Imported upstream version 0.59.3
[hcoop/debian/courier-authlib.git] / authsaslcram.c
1 /* $Id: authsaslcram.c,v 1.6 2006/06/01 10:47:32 mrsam Exp $ */
2
3 /*
4 ** Copyright 1998 - 2006 Double Precision, Inc. See COPYING for
5 ** distribution information.
6 */
7
8 #include "courier_auth_config.h"
9 #include "random128/random128.h"
10 #include "courierauthsasl.h"
11 #include <stdlib.h>
12 #include <string.h>
13 #if HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <errno.h>
19
20 extern char *strdupdefdomain(const char *userid, const char *s1,
21 const char *s2, const char *s3);
22
23 int authsasl_cram(const char *method, const char *initresponse,
24 char *(*getresp)(const char *, void *),
25 void *callback_arg,
26 char **authtype,
27 char **authdata)
28 {
29 const char *randtoken;
30 char hostnamebuf[256];
31 char *challenge;
32 char *challenge_base64;
33 char *response;
34 char *chrsp;
35 char *q, *r, *s, *t;
36 int plen;
37
38 if (initresponse && *initresponse)
39 {
40 if (write(2, "authsasl_cram: invalid request.\n", 32) < 0)
41 ; /* ignore gcc warning */
42 return (AUTHSASL_ERROR);
43 }
44
45 randtoken=random128();
46 hostnamebuf[0]=0;
47 if (gethostname(hostnamebuf, sizeof(hostnamebuf)-1))
48 strcpy(hostnamebuf, "cram");
49
50 challenge=malloc(strlen(randtoken)+strlen(hostnamebuf)
51 +sizeof("<@>"));
52 if (!challenge)
53 {
54 perror("malloc");
55 return (AUTHSASL_ERROR);
56 }
57 strcat(strcat(strcat(strcat(strcpy(challenge, "<"),
58 randtoken), "@"), hostnamebuf), ">");
59
60 challenge_base64=authsasl_tobase64(challenge, -1);
61 free(challenge);
62 if (!challenge_base64)
63 {
64 perror("malloc");
65 return (AUTHSASL_ERROR);
66 }
67
68 response=getresp(challenge_base64, callback_arg);
69 if (!response)
70 {
71 free(challenge_base64);
72 return (AUTHSASL_ERROR);
73 }
74
75 if (*response == '*')
76 {
77 free(challenge_base64);
78 free(response);
79 return (AUTHSASL_ABORTED);
80 }
81
82 /* If DEFDOMAIN is set, pick apart the response and reassemble
83 * it, potentially with a default domain appended to the username */
84 q=getenv("DEFDOMAIN");
85 if (q && q[0])
86 {
87 r = 0;
88 if ( (plen = authsasl_frombase64(response)) > 0 &&
89 (response[plen]=0, (s = strchr(response, ' ')) != 0) &&
90 (*s++ = 0, (t = strdupdefdomain(response, " ", s, "")) != 0) )
91 {
92 r = authsasl_tobase64(t, -1);
93 free(t);
94 }
95 free(response);
96 if ((response = r) == 0)
97 {
98 free(challenge_base64);
99 return (AUTHSASL_ERROR);
100 }
101 }
102
103 chrsp=malloc(strlen(challenge_base64)+strlen(response)+3);
104 if (!chrsp)
105 {
106 free(challenge_base64);
107 free(response);
108 perror("malloc");
109 return (AUTHSASL_ERROR);
110 }
111
112 strcat(strcat(strcat(strcpy(chrsp, challenge_base64), "\n"),
113 response), "\n");
114 free(challenge_base64);
115 free(response);
116
117 if ( (*authtype=malloc(strlen(method)+1)) == 0)
118 {
119 free(chrsp);
120 perror("malloc");
121 return (AUTHSASL_ERROR);
122 }
123 strcpy( *authtype, method );
124 *authdata=chrsp;
125
126 for (chrsp= *authtype; *chrsp; chrsp++)
127 *chrsp= tolower( (int)(unsigned char)*chrsp );
128
129 return (AUTHSASL_OK);
130 }