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