|
2250
|
1 /* ================================================================= |
|
|
2 * |
|
|
3 * auth.c |
|
|
4 * |
|
|
5 * Handles basic authentication. |
|
|
6 * |
|
|
7 * ================================================================= |
|
|
8 * ####ECOSGPLCOPYRIGHTBEGIN#### |
|
|
9 * ------------------------------------------- |
|
|
10 * This file is part of eCos, the Embedded Configurable Operating |
|
|
11 * System. |
|
|
12 * Copyright (C) 2005 eCosCentric Ltd. |
|
|
13 * |
|
|
14 * eCos is free software; you can redistribute it and/or modify it |
|
|
15 * under the terms of the GNU General Public License as published by |
|
|
16 * the Free Software Foundation; either version 2 or (at your option) |
|
|
17 * any later version. |
|
|
18 * |
|
|
19 * eCos is distributed in the hope that it will be useful, but |
|
|
20 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
|
22 * General Public License for more details. |
|
|
23 * |
|
|
24 * You should have received a copy of the GNU General Public License |
|
|
25 * along with eCos; if not, write to the Free Software Foundation, |
|
|
26 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|
|
27 * |
|
|
28 * As a special exception, if other files instantiate templates or |
|
|
29 * use macros or inline functions from this file, or you compile this |
|
|
30 * file and link it with other works to produce a work based on this |
|
|
31 * file, this file does not by itself cause the resulting work to be |
|
|
32 * covered by the GNU General Public License. However the source code |
|
|
33 * for this file must still be made available in accordance with |
|
|
34 * section (3) of the GNU General Public License. |
|
|
35 * |
|
|
36 * This exception does not invalidate any other reasons why a work |
|
|
37 * based on this file might be covered by the GNU General Public |
|
|
38 * License. |
|
|
39 * |
|
|
40 * ------------------------------------------- |
|
|
41 * ####ECOSGPLCOPYRIGHTEND#### |
|
|
42 * ================================================================= |
|
|
43 * #####DESCRIPTIONBEGIN#### |
|
|
44 * |
|
|
45 * Author(s): Anthony Tonizzo (atonizzo@gmail.com) |
|
|
46 * Contributors: |
|
|
47 * Date: 2006-06-12 |
|
|
48 * Purpose: |
|
|
49 * Description: |
|
|
50 * |
|
|
51 * ####DESCRIPTIONEND#### |
|
|
52 * |
|
|
53 * ================================================================= |
|
|
54 */ |
|
|
55 #include <pkgconf/hal.h> |
|
|
56 #include <pkgconf/kernel.h> |
|
|
57 #include <cyg/kernel/kapi.h> // Kernel API. |
|
|
58 #include <cyg/hal/hal_tables.h> |
|
|
59 |
|
|
60 #include <stdio.h> |
|
|
61 |
|
|
62 #include <network.h> |
|
|
63 #include <string.h> |
|
|
64 |
|
|
65 #include <cyg/athttpd/http.h> |
|
|
66 #include <cyg/athttpd/md5.h> |
|
|
67 |
|
2265
|
68 // This is a string that contains the domain that is currently authorized. |
|
2250
|
69 cyg_uint8 *cyg_httpd_current_authName; |
|
|
70 |
|
|
71 CYG_HAL_TABLE_BEGIN(cyg_httpd_auth_table, httpd_auth_table ); |
|
|
72 CYG_HAL_TABLE_END(cyg_httpd_auth_table_end, httpd_auth_table ); |
|
|
73 |
|
|
74 __externC cyg_httpd_auth_table_entry cyg_httpd_auth_table[]; |
|
|
75 __externC cyg_httpd_auth_table_entry cyg_httpd_auth_table_end[]; |
|
|
76 |
|
|
77 // Variables used for authorization. |
|
|
78 char cyg_httpd_md5_nonce[33]; |
|
|
79 char cyg_httpd_md5_digest[33]; |
|
|
80 char cyg_httpd_md5_response[33]; |
|
|
81 char cyg_httpd_md5_cnonce[33]; |
|
|
82 char cyg_httpd_md5_noncecount[9]; |
|
|
83 char cyg_httpd_md5_ha2[HASHHEXLEN+1] = {'\0'}; |
|
|
84 char cyg_httpd_md5_ha1[HASHHEXLEN+1]; |
|
|
85 |
|
|
86 char b64string[] = |
|
2265
|
87 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|
2250
|
88 |
|
|
89 cyg_httpd_auth_table_entry* |
|
|
90 cyg_httpd_auth_entry_from_path(char *authPath) |
|
|
91 { |
|
|
92 cyg_httpd_auth_table_entry *entry = cyg_httpd_auth_table; |
|
|
93 if (strcmp(authPath, "/") != 0) |
|
|
94 while (entry != cyg_httpd_auth_table_end) |
|
|
95 { |
|
|
96 if (strncmp(entry->auth_dirname, |
|
|
97 authPath, |
|
|
98 strlen(entry->auth_dirname)) == 0) |
|
|
99 return entry; |
|
|
100 entry++; |
|
|
101 } |
|
|
102 else |
|
|
103 while (entry != cyg_httpd_auth_table_end) |
|
|
104 { |
|
|
105 if (strcmp(entry->auth_dirname, authPath) == 0) |
|
|
106 return entry; |
|
|
107 entry++; |
|
|
108 } |
|
|
109 |
|
|
110 return (cyg_httpd_auth_table_entry *)0; |
|
|
111 } |
|
|
112 |
|
|
113 cyg_httpd_auth_table_entry* |
|
|
114 cyg_httpd_auth_entry_from_domain(char *authDomain) |
|
|
115 { |
|
|
116 cyg_httpd_auth_table_entry *entry = cyg_httpd_auth_table; |
|
|
117 while (entry != cyg_httpd_auth_table_end) |
|
|
118 { |
|
|
119 if (!strncmp((const char*)authDomain, |
|
|
120 entry->auth_domainname, |
|
|
121 strlen(entry->auth_domainname))) |
|
|
122 return entry; |
|
|
123 entry++; |
|
|
124 } |
|
|
125 |
|
|
126 return (cyg_httpd_auth_table_entry *)0; |
|
|
127 } |
|
|
128 |
|
|
129 cyg_int32 |
|
|
130 cyg_httpd_base64_encode(char* to, char* from, cyg_uint32 len ) |
|
|
131 { |
|
2265
|
132 char *fromp = from; |
|
|
133 char *top = to; |
|
|
134 char cbyte; |
|
|
135 char obyte; |
|
|
136 cyg_int8 end[3]; |
|
2250
|
137 |
|
2265
|
138 for (; len >= 3; len -= 3) |
|
2250
|
139 { |
|
2265
|
140 cbyte = *fromp++; |
|
|
141 *top++ = b64string[(int)(cbyte >> 2)]; |
|
|
142 obyte = (cbyte << 4) & 0x30; |
|
2250
|
143 |
|
2265
|
144 cbyte = *fromp++; |
|
|
145 obyte |= (cbyte >> 4); |
|
|
146 *top++ = b64string[(cyg_int32)obyte]; |
|
|
147 obyte = (cbyte << 2) & 0x3C; |
|
2250
|
148 |
|
2265
|
149 cbyte = *fromp++; |
|
|
150 obyte |= (cbyte >> 6); |
|
|
151 *top++ = b64string[(cyg_int32)obyte]; |
|
|
152 *top++ = b64string[(cyg_int32)(cbyte & 0x3F)]; |
|
|
153 } |
|
2250
|
154 |
|
2265
|
155 if (len) |
|
2250
|
156 { |
|
2265
|
157 end[0] = *fromp++; |
|
|
158 if (--len ) |
|
2250
|
159 end[1] = *fromp++; |
|
|
160 else |
|
|
161 end[1] = 0; |
|
2265
|
162 end[2] = 0; |
|
2250
|
163 |
|
2265
|
164 cbyte = end[0]; |
|
|
165 *top++ = b64string[(cyg_int32)(cbyte >> 2)]; |
|
|
166 obyte = (cbyte << 4) & 0x30; |
|
2250
|
167 |
|
2265
|
168 cbyte = end[1]; |
|
|
169 obyte |= (cbyte >> 4); |
|
|
170 *top++ = b64string[(cyg_int32)obyte]; |
|
|
171 obyte = (cbyte << 2) & 0x3C; |
|
2250
|
172 |
|
2265
|
173 if (len ) |
|
2250
|
174 *top++ = b64string[(cyg_int32)obyte]; |
|
2265
|
175 else |
|
2250
|
176 *top++ = '='; |
|
2265
|
177 *top++ = '='; |
|
|
178 } |
|
|
179 *top = 0; |
|
|
180 return top - to; |
|
2250
|
181 } |
|
|
182 |
|
|
183 cyg_int32 |
|
|
184 cyg_httpd_base64_decode(char* to, char* from, cyg_uint32 len ) |
|
|
185 { |
|
|
186 char *fromp = from; |
|
|
187 char *top = to; |
|
|
188 char *p; |
|
|
189 char cbyte; |
|
|
190 char obyte; |
|
|
191 cyg_int32 padding = 0; |
|
|
192 |
|
2265
|
193 for (; len >= 4; len -= 4) |
|
2250
|
194 { |
|
|
195 if ((cbyte = *fromp++) == '=') |
|
|
196 cbyte = 0; |
|
2265
|
197 else |
|
2250
|
198 { |
|
|
199 if (badchar(cbyte, p ) ) |
|
|
200 return -1; |
|
|
201 cbyte = (p - b64string); |
|
|
202 } |
|
|
203 obyte = cbyte << 2; |
|
|
204 |
|
|
205 if ((cbyte = *fromp++) == '=') |
|
|
206 cbyte = 0; |
|
2265
|
207 else |
|
2250
|
208 { |
|
2265
|
209 if (badchar(cbyte, p)) |
|
2250
|
210 return -1; |
|
|
211 cbyte = p - b64string; |
|
2265
|
212 } |
|
2250
|
213 obyte |= cbyte >> 4; |
|
|
214 *top++ = obyte; |
|
|
215 |
|
|
216 obyte = cbyte << 4; |
|
|
217 if ((cbyte = *fromp++) == '=') |
|
|
218 { |
|
|
219 cbyte = 0; |
|
|
220 padding++; |
|
|
221 } |
|
2265
|
222 else |
|
2250
|
223 { |
|
|
224 padding = 0; |
|
|
225 if (badchar(cbyte, p)) |
|
|
226 return -1; |
|
|
227 cbyte = p - b64string; |
|
|
228 } |
|
|
229 obyte |= cbyte >> 2; |
|
|
230 *top++ = obyte; |
|
|
231 |
|
|
232 obyte = cbyte << 6; |
|
|
233 if ((cbyte = *fromp++) == '=') |
|
|
234 { |
|
|
235 cbyte = 0; |
|
|
236 padding++; |
|
|
237 } |
|
|
238 else |
|
|
239 { |
|
|
240 padding = 0; |
|
|
241 if (badchar(cbyte, p)) |
|
|
242 return -1; |
|
|
243 cbyte = p - b64string; |
|
|
244 } |
|
|
245 obyte |= cbyte; |
|
|
246 *top++ = obyte; |
|
|
247 } |
|
|
248 |
|
|
249 *top = 0; |
|
|
250 if (len) |
|
|
251 return -1; |
|
|
252 return (top - to) - padding; |
|
|
253 } |
|
|
254 |
|
|
255 cyg_httpd_auth_table_entry* |
|
|
256 cyg_httpd_verify_auth(char* username, char* password) |
|
|
257 { |
|
|
258 if ((strcmp(httpstate.needs_auth->auth_username, username) == 0) && |
|
|
259 (strcmp(httpstate.needs_auth->auth_password, password) == 0)) |
|
|
260 return httpstate.needs_auth; |
|
|
261 else |
|
|
262 return (cyg_httpd_auth_table_entry*)0; |
|
|
263 } |
|
|
264 |
|
|
265 // The following code is a slightly modified version of those available at the |
|
|
266 // end of RFC1270. |
|
|
267 void cyg_httpd_cvthex(HASH Bin, HASHHEX Hex) |
|
|
268 { |
|
|
269 unsigned short i; |
|
|
270 unsigned char j; |
|
|
271 |
|
|
272 for (i = 0; i < HASHLEN; i++) |
|
|
273 { |
|
|
274 j = (Bin[i] >> 4) & 0xf; |
|
|
275 if (j <= 9) |
|
|
276 Hex[i*2] = (j + '0'); |
|
|
277 else |
|
|
278 Hex[i*2] = (j + 'a' - 10); |
|
|
279 j = Bin[i] & 0xf; |
|
|
280 if (j <= 9) |
|
|
281 Hex[i*2+1] = (j + '0'); |
|
|
282 else |
|
|
283 Hex[i*2+1] = (j + 'a' - 10); |
|
|
284 }; |
|
|
285 Hex[HASHHEXLEN] = '\0'; |
|
|
286 }; |
|
|
287 |
|
|
288 // Calculate H(A1) as per spec. |
|
|
289 void |
|
|
290 cyg_httpd_digest_calc_HA1( char *pszAlg, |
|
|
291 char *pszUserName, |
|
|
292 char *pszRealm, |
|
|
293 char *pszPassword, |
|
|
294 char *pszNonce, |
|
|
295 char *pszCNonce, |
|
|
296 HASHHEX SessionKey ) |
|
|
297 { |
|
|
298 MD5_CTX Md5Ctx; |
|
|
299 HASH HA1; |
|
|
300 |
|
|
301 MD5Init(&Md5Ctx); |
|
|
302 MD5Update(&Md5Ctx, (unsigned char*)pszUserName, strlen(pszUserName)); |
|
|
303 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
304 MD5Update(&Md5Ctx, (unsigned char*)pszRealm, strlen(pszRealm)); |
|
|
305 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
306 MD5Update(&Md5Ctx, (unsigned char*)pszPassword, strlen(pszPassword)); |
|
|
307 MD5Final((unsigned char*)HA1, &Md5Ctx); |
|
|
308 if (strcmp(pszAlg, "md5-sess") == 0) |
|
|
309 { |
|
|
310 MD5Init(&Md5Ctx); |
|
|
311 MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHLEN); |
|
|
312 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
313 MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce)); |
|
|
314 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
315 MD5Update(&Md5Ctx, (unsigned char*)pszCNonce, strlen(pszCNonce)); |
|
|
316 MD5Final((unsigned char*)HA1, &Md5Ctx); |
|
|
317 }; |
|
|
318 cyg_httpd_cvthex(HA1, SessionKey); |
|
|
319 }; |
|
|
320 |
|
|
321 // Calculate request-digest/response-digest as per HTTP Digest spec. |
|
|
322 void |
|
|
323 cyg_httpd_digest_calc_response(HASHHEX HA1, |
|
|
324 char *pszNonce, |
|
|
325 char *pszNonceCount, |
|
|
326 char *pszCNonce, |
|
|
327 char *pszQop, |
|
|
328 char *pszMethod, |
|
|
329 char *pszDigestUri, |
|
|
330 HASHHEX HEntity, |
|
|
331 HASHHEX Response) |
|
|
332 { |
|
|
333 MD5_CTX Md5Ctx; |
|
|
334 HASH HA2; |
|
|
335 HASH RespHash; |
|
|
336 HASHHEX HA2Hex; |
|
|
337 |
|
|
338 // Calculate H(A2). |
|
|
339 MD5Init(&Md5Ctx); |
|
|
340 MD5Update(&Md5Ctx, (unsigned char*)pszMethod, strlen(pszMethod)); |
|
|
341 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
342 MD5Update(&Md5Ctx, (unsigned char*)pszDigestUri, strlen(pszDigestUri)); |
|
|
343 if (strcmp(pszQop, "auth-int") == 0) { |
|
|
344 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
345 MD5Update(&Md5Ctx, (unsigned char*)HEntity, HASHHEXLEN); |
|
|
346 }; |
|
|
347 MD5Final((unsigned char*)HA2, &Md5Ctx); |
|
|
348 cyg_httpd_cvthex(HA2, HA2Hex); |
|
|
349 |
|
|
350 // calculate response |
|
|
351 MD5Init(&Md5Ctx); |
|
|
352 MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHHEXLEN); |
|
|
353 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
354 MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce)); |
|
|
355 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
356 if (*pszQop) |
|
|
357 { |
|
|
358 MD5Update(&Md5Ctx, (unsigned char*)pszNonceCount, strlen(pszNonceCount)); |
|
|
359 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
360 MD5Update(&Md5Ctx, (unsigned char*)pszCNonce, strlen(pszCNonce)); |
|
|
361 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
362 MD5Update(&Md5Ctx, (unsigned char*)pszQop, strlen(pszQop)); |
|
|
363 MD5Update(&Md5Ctx, (unsigned char*)":", 1); |
|
|
364 }; |
|
|
365 MD5Update(&Md5Ctx, (unsigned char*)HA2Hex, HASHHEXLEN); |
|
|
366 MD5Final((unsigned char*)RespHash, &Md5Ctx); |
|
|
367 cyg_httpd_cvthex(RespHash, Response); |
|
|
368 }; |
|
|
369 |
|
|
370 cyg_httpd_auth_table_entry* |
|
|
371 cyg_httpd_is_authenticated(char* fname) |
|
|
372 { |
|
|
373 // Let's check if the directory access needs authorization. The |
|
|
374 // authentication is done on the directory name. |
|
|
375 cyg_httpd_auth_table_entry* entry = |
|
|
376 cyg_httpd_auth_entry_from_path(fname); |
|
|
377 if (entry != 0) |
|
|
378 { |
|
|
379 if (entry->auth_mode == CYG_HTTPD_AUTH_BASIC) |
|
|
380 { |
|
|
381 cyg_httpd_base64_decode(cyg_httpd_md5_response, |
|
|
382 cyg_httpd_md5_digest, |
|
|
383 strlen(cyg_httpd_md5_digest)); |
|
|
384 char *extension = rindex(cyg_httpd_md5_response, ':'); |
|
|
385 if (extension == NULL) |
|
|
386 { |
|
|
387 return (httpstate.needs_auth = entry); |
|
|
388 } |
|
|
389 else |
|
|
390 { |
|
|
391 *extension = '\0'; // Crypto now has the username. |
|
|
392 |
|
|
393 // In the case of a 'Basic" authentication, the HTTP header |
|
|
394 // did not return to us the domain name that we sent when we |
|
|
395 // challenged the request: The only things that are returned |
|
|
396 // are the username:password duo. In this case I will just |
|
|
397 // compare the entry's username/password to those read from |
|
|
398 // the header. |
|
|
399 if ((strcmp(entry->auth_username, |
|
|
400 cyg_httpd_md5_response) != 0) || |
|
|
401 (strcmp(entry->auth_password, |
|
|
402 ++extension) != 0)) |
|
|
403 return (httpstate.needs_auth = entry); |
|
|
404 } |
|
|
405 } |
|
|
406 else |
|
|
407 { |
|
|
408 char *cyg_httpd_md5_method; |
|
|
409 |
|
|
410 switch (httpstate.method) |
|
|
411 { |
|
|
412 case CYG_HTTPD_METHOD_GET: |
|
|
413 cyg_httpd_md5_method = "GET"; |
|
|
414 break; |
|
|
415 case CYG_HTTPD_METHOD_POST: |
|
|
416 cyg_httpd_md5_method = "POST"; |
|
|
417 break; |
|
|
418 default: |
|
|
419 cyg_httpd_md5_method = "HEAD"; |
|
|
420 break; |
|
|
421 } |
|
|
422 cyg_httpd_digest_calc_HA1(CYG_HTTPD_MD5_AUTH_NAME, |
|
|
423 entry->auth_username, |
|
|
424 entry->auth_domainname, |
|
|
425 entry->auth_password, |
|
|
426 cyg_httpd_md5_nonce, |
|
|
427 cyg_httpd_md5_cnonce, |
|
|
428 cyg_httpd_md5_ha1); |
|
|
429 cyg_httpd_digest_calc_response(cyg_httpd_md5_ha1, |
|
|
430 cyg_httpd_md5_nonce, |
|
|
431 cyg_httpd_md5_noncecount, |
|
|
432 cyg_httpd_md5_cnonce, |
|
|
433 CYG_HTTPD_MD5_AUTH_QOP, |
|
|
434 cyg_httpd_md5_method, |
|
|
435 httpstate.url, |
|
|
436 cyg_httpd_md5_ha2, |
|
|
437 cyg_httpd_md5_digest); |
|
|
438 if (strcmp(cyg_httpd_md5_response, cyg_httpd_md5_digest) != 0) |
|
|
439 return (httpstate.needs_auth = entry); |
|
|
440 } |
|
|
441 } |
|
|
442 // No need for authentication... |
|
|
443 return (cyg_httpd_auth_table_entry*)0; |
|
|
444 } |
|
|
445 |
|
|
446 char* |
|
|
447 cyg_httpd_digest_data(char *dest, char *src) |
|
|
448 { |
|
|
449 int exit = 0; |
|
|
450 while (exit == 0) |
|
|
451 { |
|
|
452 switch (*src ) |
|
|
453 { |
|
|
454 case '\r': |
|
|
455 case '\n': |
|
|
456 *dest = '\0'; |
|
|
457 exit = 1; |
|
|
458 break; |
|
|
459 case ' ': |
|
|
460 src++; |
|
|
461 *dest = '\0'; |
|
|
462 exit = 1; |
|
|
463 break; |
|
|
464 case '"': |
|
|
465 case ',': |
|
|
466 src++; |
|
|
467 break; |
|
|
468 default: |
|
|
469 *dest++ = *src++; |
|
|
470 } |
|
|
471 } |
|
|
472 return src; |
|
|
473 } |
|
|
474 |
|
|
475 // Skips through fields we do not need. |
|
|
476 char* |
|
|
477 cyg_httpd_digest_skip(char *p) |
|
|
478 { |
|
|
479 if (*p == '"') |
|
|
480 { |
|
|
481 p++; |
|
|
482 while ((*p != '"') && (*p != '\n')) |
|
|
483 p++; |
|
|
484 p++; |
|
|
485 if (*p == ',') |
|
|
486 p++; |
|
|
487 if (*p == ' ') |
|
|
488 p++; |
|
|
489 if (*p == '\n') |
|
|
490 p++; |
|
|
491 } |
|
|
492 else |
|
|
493 { |
|
|
494 while ((*p != ' ') && (*p != '\n')) |
|
|
495 p++; |
|
|
496 if (*p == ',') |
|
|
497 p++; |
|
|
498 if (*p == ' ') |
|
|
499 p++; |
|
|
500 if (*p == '\n') |
|
|
501 p++; |
|
|
502 } |
|
|
503 return p; |
|
|
504 } |