Commit | Line | Data |
---|---|---|
d9898ee8 | 1 | /* |
ac40fd9e | 2 | ** Copyright 1998 - 2008 Double Precision, Inc. See COPYING for |
d9898ee8 | 3 | ** distribution information. |
4 | */ | |
5 | ||
6 | #if HAVE_CONFIG_H | |
7 | #include "courier_auth_config.h" | |
8 | #endif | |
9 | #include <stdio.h> | |
10 | #include <stdlib.h> | |
11 | #include <string.h> | |
12 | #include <errno.h> | |
13 | #include "courierauthsasl.h" | |
14 | #include "cramlib.h" | |
15 | #include "courierauthdebug.h" | |
d9898ee8 | 16 | #include "libhmac/hmac.h" |
17 | #include "cramlib.h" | |
18 | ||
19 | static int nybble(int c) | |
20 | { | |
21 | if (c >= '0' && c <= '9') return (c-'0'); | |
22 | if (c >= 'a' && c <= 'f') return (c-'a'+10); | |
23 | if (c >= 'A' && c <= 'F') return (c-'A'+10); | |
24 | return (-1); | |
25 | } | |
26 | ||
27 | static int do_auth_verify_cram(struct hmac_hashinfo *hash, | |
28 | const char *challenge, const char *response, | |
29 | const char *hashsecret) | |
30 | { | |
31 | unsigned char *context; | |
32 | unsigned i; | |
33 | ||
34 | if (strlen(hashsecret) != hash->hh_L*4 || | |
35 | strlen(response) != hash->hh_L*2) | |
36 | return (-1); | |
37 | ||
38 | if ((context=malloc(hash->hh_L*3)) == 0) return (-1); | |
39 | ||
40 | for (i=0; i<hash->hh_L*2; i++) | |
41 | { | |
42 | int a=nybble(hashsecret[i*2]), b=nybble(hashsecret[i*2+1]); | |
43 | ||
44 | if (a < 0 || b < 0) | |
45 | { | |
46 | free(context); | |
47 | return (-1); | |
48 | } | |
49 | context[i]= a*16 + b; | |
50 | } | |
51 | ||
52 | hmac_hashtext(hash, challenge, strlen(challenge), | |
53 | context, context+hash->hh_L, | |
54 | context+hash->hh_L*2); | |
55 | ||
56 | for (i=0; i<hash->hh_L; i++) | |
57 | { | |
58 | int a=nybble(response[i*2]), b=nybble(response[i*2+1]); | |
59 | ||
60 | if ( (unsigned char)(a*16+b) != | |
61 | context[hash->hh_L*2+i]) | |
62 | { | |
63 | free(context); | |
64 | return (-1); | |
65 | } | |
66 | } | |
67 | free(context); | |
68 | return (0); | |
69 | } | |
70 | ||
71 | int auth_verify_cram(struct hmac_hashinfo *hash, | |
72 | const char *challenge, const char *response, | |
73 | const char *hashsecret) | |
74 | { | |
75 | int rc; | |
76 | ||
77 | rc = do_auth_verify_cram(hash, challenge, response, hashsecret); | |
78 | DPRINTF(rc ? "cram validation failed" : "cram validation succeeded"); | |
79 | return rc; | |
80 | } | |
81 | ||
b0322a85 CE |
82 | static int do_auth_get_cram(const char *authtype, char *authdata, |
83 | struct cram_callback_info *craminfo, int logerr) | |
d9898ee8 | 84 | { |
85 | int i; | |
86 | int challenge_l; | |
87 | int response_l; | |
88 | ||
89 | if (strncmp(authtype, "cram-", 5) || | |
90 | (craminfo->challenge=strtok(authdata, "\n")) == 0 || | |
91 | (craminfo->response=strtok(0, "\n")) == 0) | |
92 | { | |
b0322a85 CE |
93 | if (logerr) |
94 | { | |
95 | DPRINTF("Unsupported authentication type: %s", authtype); | |
96 | } | |
d9898ee8 | 97 | errno=EPERM; |
98 | return (-1); | |
99 | } | |
100 | ||
101 | for (i=0; hmac_list[i]; i++) | |
102 | if (strcmp(hmac_list[i]->hh_name, authtype+5) == 0) | |
103 | break; | |
104 | ||
b0322a85 CE |
105 | if (logerr) |
106 | { | |
107 | DPRINTF("cram: challenge=%s, response=%s", craminfo->challenge, | |
108 | craminfo->response); | |
109 | } | |
d9898ee8 | 110 | |
111 | if (hmac_list[i] == 0 | |
112 | || (challenge_l=authsasl_frombase64(craminfo->challenge)) < 0 | |
113 | || (response_l=authsasl_frombase64(craminfo->response)) < 0) | |
114 | { | |
b0322a85 CE |
115 | if (logerr) |
116 | { | |
117 | DPRINTF("cram: invalid base64 encoding, or unknown method: %s", | |
118 | authtype); | |
119 | } | |
d9898ee8 | 120 | errno=EACCES; |
121 | return (-1); | |
122 | } | |
123 | craminfo->h=hmac_list[i]; | |
124 | ||
125 | for (i=response_l; i > 0; ) | |
126 | { | |
127 | if (craminfo->response[i-1] == ' ') | |
128 | break; | |
129 | --i; | |
130 | } | |
131 | ||
132 | if (i == 0) | |
133 | { | |
b0322a85 CE |
134 | if (logerr) |
135 | { | |
136 | DPRINTF("cram: invalid base64 encoding"); | |
137 | } | |
d9898ee8 | 138 | errno=EACCES; |
139 | return (-1); | |
140 | } | |
141 | craminfo->response[i-1]=0; | |
142 | craminfo->user = craminfo->response; | |
143 | craminfo->response += i; | |
144 | response_l -= i; | |
145 | ||
146 | /* Since base64decoded data is always lesser in size (at least), | |
147 | ** we can do the following: | |
148 | */ | |
149 | craminfo->challenge[challenge_l]=0; | |
150 | craminfo->response[response_l]=0; | |
151 | ||
b0322a85 CE |
152 | if (logerr) |
153 | { | |
154 | /* we rely on DPRINTF doing a "safe" print here */ | |
155 | DPRINTF("cram: decoded challenge/response, username '%s'", | |
156 | craminfo->user); | |
157 | } | |
d9898ee8 | 158 | return (0); |
159 | } | |
160 | ||
161 | int auth_cram_callback(struct authinfo *a, void *vp) | |
162 | { | |
163 | struct cram_callback_info *cci=(struct cram_callback_info *)vp; | |
164 | unsigned char *hashbuf; | |
165 | unsigned char *p; | |
166 | unsigned i; | |
167 | static const char hex[]="0123456789abcdef"; | |
168 | int rc; | |
169 | ||
170 | if (!a->clearpasswd) | |
171 | return (-1); | |
172 | ||
173 | /* | |
174 | hmac->hh_L*2 will be the size of the binary hash. | |
175 | ||
176 | hmac->hh_L*4+1 will therefore be size of the binary hash, | |
177 | as a hexadecimal string. | |
178 | */ | |
179 | ||
180 | if ((hashbuf=malloc(cci->h->hh_L*6+1)) == 0) | |
181 | return (1); | |
182 | ||
183 | hmac_hashkey(cci->h, a->clearpasswd, strlen(a->clearpasswd), | |
184 | hashbuf, hashbuf+cci->h->hh_L); | |
185 | ||
186 | p=hashbuf+cci->h->hh_L*2; | |
187 | ||
188 | for (i=0; i<cci->h->hh_L*2; i++) | |
189 | { | |
190 | char c; | |
191 | ||
192 | c = hex[ (hashbuf[i] >> 4) & 0x0F]; | |
193 | *p++=c; | |
194 | ||
195 | c = hex[ hashbuf[i] & 0x0F]; | |
196 | *p++=c; | |
197 | ||
198 | *p=0; | |
199 | } | |
200 | ||
201 | rc=auth_verify_cram(cci->h, cci->challenge, cci->response, | |
202 | (const char *)hashbuf+cci->h->hh_L*2); | |
203 | free(hashbuf); | |
204 | ||
205 | if (rc) return (rc); | |
206 | ||
207 | return (*cci->callback_func)(a, cci->callback_arg); | |
208 | } | |
b0322a85 CE |
209 | |
210 | int auth_get_cram(const char *authtype, char *authdata, | |
211 | struct cram_callback_info *craminfo) | |
212 | { | |
213 | return do_auth_get_cram(authtype, authdata, craminfo, 1); | |
214 | } | |
215 | ||
216 | int auth_get_cram_silent(const char *authtype, char *authdata, | |
217 | struct cram_callback_info *craminfo) | |
218 | { | |
219 | return do_auth_get_cram(authtype, authdata, craminfo, 0); | |
220 | } |