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