Annotation of libwww/Library/src/HTAABrow.c, revision 2.49
2.15 frystyk 1: /* HTAABrow.c
2.32 frystyk 2: ** BROWSER SIDE ACCESS AUTHORIZATION MODULE
2.15 frystyk 3: **
2.19 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.15 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.49 ! kahan 6: ** @(#) $Id: HTAABrow.c,v 1.3 1998/10/08 18:13:49 cvs Exp $
2.1 luotonen 7: **
2.32 frystyk 8: ** Contains code for parsing challenges and creating credentials for
2.36 frystyk 9: ** basic authentication schemes. See also the HTAAUtil module
2.32 frystyk 10: ** for how to handle other authentication schemes. You don't have to use
11: ** this code at all.
2.1 luotonen 12: **
13: ** AUTHORS:
14: ** AL Ari Luotonen luotonen@dxcern.cern.ch
2.32 frystyk 15: ** HFN Henrik Frystyk
2.1 luotonen 16: **
17: ** HISTORY:
2.5 luotonen 18: ** Oct 17 AL Made corrections suggested by marca:
19: ** Added if (!realm->username) return NULL;
20: ** Changed some ""s to NULLs.
2.33 frystyk 21: ** Now doing HT_CALLOC() to init uuencode source;
2.5 luotonen 22: ** otherwise HTUU_encode() reads uninitialized memory
23: ** every now and then (not a real bug but not pretty).
24: ** Corrected the formula for uuencode destination size.
2.32 frystyk 25: ** Feb 96 HFN Rewritten to make it scheme independent and based on
26: ** callback functions and an info structure
2.1 luotonen 27: */
28:
2.17 frystyk 29: /* Library include files */
2.27 frystyk 30: #include "WWWLib.h"
31: #include "HTAAUtil.h"
32: #include "HTAABrow.h" /* Implemented here */
2.1 luotonen 33:
2.36 frystyk 34: #define BASIC_AUTH "basic"
2.44 frystyk 35: #define DIGEST_AUTH "digest"
2.36 frystyk 36:
2.32 frystyk 37: typedef struct _HTBasic { /* Basic challenge and credentials */
38: char * uid;
39: char * pw;
2.38 frystyk 40: BOOL retry; /* Should we ask the user again? */
2.40 frystyk 41: BOOL proxy; /* Proxy authentication */
2.32 frystyk 42: } HTBasic;
43:
2.44 frystyk 44: typedef struct _HTDigest { /* Digest challenge and credentials */
45: char * uid;
46: char * pw;
47: char * nounce;
48: char * opaque;
49: BOOL stale;
50: BOOL retry; /* Should we ask the user again? */
51: BOOL proxy; /* Proxy authentication */
52: int references; /* Number of pointers to this object */
53: } HTDigest;
54:
2.36 frystyk 55: /* ------------------------------------------------------------------------- */
56:
2.32 frystyk 57: /*
58: ** Create a protection template for the files
59: ** in the same directory as the given file
60: ** Returns a template matching docname, and other files in that directory.
61: **
62: ** E.g. /foo/bar/x.html => /foo/bar/ *
63: ** ^
64: ** Space only to prevent it from
65: ** being a comment marker here,
66: ** there really isn't any space.
2.1 luotonen 67: */
2.33 frystyk 68: PRIVATE char * make_template (const char * docname)
2.1 luotonen 69: {
2.39 frystyk 70: char * tmplate = NULL;
2.32 frystyk 71: if (docname) {
2.39 frystyk 72: char * host = HTParse(docname, "", PARSE_ACCESS|PARSE_HOST|PARSE_PUNCTUATION);
73: char * path = HTParse(docname, "", PARSE_PATH|PARSE_PUNCTUATION);
74: char * slash = strrchr(path, '/');
75: if (slash) {
2.47 frystyk 76: #if 0
2.39 frystyk 77: if (*(slash+1)) {
78: strcpy(slash, "*");
79: StrAllocCat(host, path);
80: } else
2.43 frystyk 81: StrAllocCat(host, "/*");
2.47 frystyk 82: #else
2.49 ! kahan 83: if (*(slash+1)) {
! 84: strcpy(slash + 1, "*");
2.47 frystyk 85: StrAllocCat(host, path);
2.49 ! kahan 86: } else {
! 87: StrAllocCat(host, path);
! 88: StrAllocCat(host, "*");
! 89: }
2.47 frystyk 90: #endif
2.39 frystyk 91: }
92: HT_FREE(path);
93: tmplate = host;
94: } else
95: StrAllocCopy(tmplate, "*");
2.32 frystyk 96: if (AUTH_TRACE)
97: HTTrace("Template.... Made template `%s' for file `%s'\n",
2.39 frystyk 98: tmplate, docname ? docname : "<null>");
2.32 frystyk 99: return tmplate;
2.1 luotonen 100: }
101:
2.44 frystyk 102: /* ------------------------------------------------------------------------- */
103: /* Basic Authentication */
104: /* ------------------------------------------------------------------------- */
105:
106: /*
107: ** Prompt the user for username and password.
108: ** Returns YES if user name was typed in, else NO
109: */
110: PRIVATE int prompt_user (HTRequest * request, const char * realm,
111: HTBasic * basic)
112: {
113: HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
114: if (request && cbf) {
115: HTAlertPar * reply = HTAlert_newReply();
116: int msg = basic->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
117: BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
118: basic->uid, (char *) realm, reply);
119: if (res) {
120: HT_FREE(basic->uid);
121: HT_FREE(basic->pw);
122: basic->uid = HTAlert_replyMessage(reply);
123: basic->pw = HTAlert_replySecret(reply);
124: }
125: HTAlert_deleteReply(reply);
126: return res ? HT_OK : HT_ERROR;
127: }
128: return HT_OK;
129: }
130:
131: PRIVATE HTBasic * HTBasic_new()
132: {
133: HTBasic * me = NULL;
134: if ((me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic))) == NULL)
135: HT_OUTOFMEM("HTBasic_new");
136: me->retry = YES; /* Ask the first time through */
137: return me;
138: }
139:
140: /* HTBasic_delete
141: ** --------------
142: ** Deletes a "basic" information object
143: */
144: PUBLIC int HTBasic_delete (void * context)
145: {
146: HTBasic * basic = (HTBasic *) context;
147: if (basic) {
148: HT_FREE(basic->uid);
149: HT_FREE(basic->pw);
150: HT_FREE(basic);
151: return YES;
152: }
153: return NO;
154: }
155:
2.32 frystyk 156: /*
157: ** Make basic authentication scheme credentials and register this
158: ** information in the request object as credentials. They will then
159: ** be included in the request header. An example is
160: **
161: ** "Basic AkRDIhEF8sdEgs72F73bfaS=="
162: **
2.40 frystyk 163: ** The function can both create normal and proxy credentials
2.36 frystyk 164: ** Returns HT_OK or HT_ERROR
2.32 frystyk 165: */
2.36 frystyk 166: PRIVATE BOOL basic_credentials (HTRequest * request, HTBasic * basic)
2.32 frystyk 167: {
168: if (request && basic) {
169: char * cleartext = NULL;
170: char * cipher = NULL;
171: int cl_len = strlen(basic->uid ? basic->uid : "") +
2.42 frystyk 172: strlen(basic->pw ? basic->pw : "") + 5;
2.37 frystyk 173: int ci_len = 4 * (((cl_len+2)/3) + 1);
174: if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
2.32 frystyk 175: HT_OUTOFMEM("basic_credentials");
176: *cleartext = '\0';
177: if (basic->uid) strcpy(cleartext, basic->uid);
178: strcat(cleartext, ":");
179: if (basic->pw) strcat(cleartext, basic->pw);
2.37 frystyk 180: if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
2.32 frystyk 181: HT_OUTOFMEM("basic_credentials");
2.37 frystyk 182: HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
2.1 luotonen 183:
2.32 frystyk 184: /* Create the credentials and assign them to the request object */
185: {
2.37 frystyk 186: int cr_len = strlen("basic") + ci_len + 3;
2.32 frystyk 187: char * cookie = (char *) HT_MALLOC(cr_len+1);
188: if (!cookie) HT_OUTOFMEM("basic_credentials");
189: strcpy(cookie, "Basic ");
190: strcat(cookie, cipher);
2.37 frystyk 191: if (AUTH_TRACE) HTTrace("Basic Cookie `%s\'\n", cookie);
2.40 frystyk 192:
193: /* Check whether it is proxy or normal credentials */
194: if (basic->proxy)
195: HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
196: else
197: HTRequest_addCredentials(request, "Authorization", cookie);
198:
2.32 frystyk 199: HT_FREE(cookie);
2.1 luotonen 200: }
2.32 frystyk 201: HT_FREE(cleartext);
202: HT_FREE(cipher);
2.36 frystyk 203: return HT_OK;
2.32 frystyk 204: }
2.36 frystyk 205: return HT_ERROR;
2.1 luotonen 206: }
207:
2.32 frystyk 208: /* HTBasic_generate
209: ** ----------------
210: ** This function generates "basic" credentials for the challenge found in
211: ** the authentication information base for this request. The result is
212: ** stored as an association list in the request object.
213: ** This is a callback function for the AA handler.
214: */
2.45 frystyk 215: PUBLIC int HTBasic_generate (HTRequest * request, void * context, int mode)
2.32 frystyk 216: {
2.36 frystyk 217: HTBasic * basic = (HTBasic *) context;
2.45 frystyk 218: BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO;
2.36 frystyk 219: if (request) {
220: const char * realm = HTRequest_realm(request);
221:
2.40 frystyk 222: /*
2.46 frystyk 223: ** If we were asked to explicitly ask the user again
224: */
225: if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH)
226: basic->retry = YES;
227:
228: /*
2.40 frystyk 229: ** If we don't have a basic context then add a new one to the tree.
2.42 frystyk 230: ** We use different trees for normal and proxy authentication
2.40 frystyk 231: */
2.36 frystyk 232: if (!basic) {
2.42 frystyk 233: if (proxy) {
234: char * url = HTRequest_proxy(request);
235: basic = HTBasic_new();
236: basic->proxy = YES;
237: HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
238: } else {
239: char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
240: basic = HTBasic_new();
241: HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
242: HT_FREE(url);
243: }
2.36 frystyk 244: }
245:
2.32 frystyk 246: /*
2.36 frystyk 247: ** If we have a set of credentials (or the user provides a new set)
248: ** then store it in the request object as the credentials
2.32 frystyk 249: */
2.39 frystyk 250: if ((basic->retry && prompt_user(request, realm, basic) == HT_OK) ||
251: (!basic->retry && basic->uid)) {
2.38 frystyk 252: basic->retry = NO;
2.36 frystyk 253: return basic_credentials(request, basic);
2.48 frystyk 254: } else {
255: char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
256: HTAA_deleteNode(proxy, BASIC_AUTH, realm, url);
257: HT_FREE(url);
2.37 frystyk 258: return HT_ERROR;
2.48 frystyk 259: }
2.1 luotonen 260: }
2.36 frystyk 261: return HT_OK;
2.1 luotonen 262: }
263:
2.32 frystyk 264: /* HTBasic_parse
265: ** -------------
266: ** This function parses the contents of a "basic" challenge
267: ** and stores the challenge in our authentication information datebase.
268: ** We also store the realm in the request object which will help finding
269: ** the right set of credentials to generate.
270: ** The function is a callback function for the AA handler.
271: */
2.45 frystyk 272: PUBLIC int HTBasic_parse (HTRequest * request, HTResponse * response,
273: void * context, int status)
2.32 frystyk 274: {
2.45 frystyk 275: HTAssocList * challenge = HTResponse_challenge(response);
2.38 frystyk 276: HTBasic * basic = NULL;
2.40 frystyk 277: BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
2.36 frystyk 278: if (request && challenge) {
279: char * p = HTAssocList_findObject(challenge, BASIC_AUTH);
280: char * realm = HTNextField(&p);
281: char * rm = HTNextField(&p);
2.38 frystyk 282:
2.32 frystyk 283: /*
2.36 frystyk 284: ** If valid challenge then make a template for the resource and
285: ** store this information in our authentication URL Tree
2.32 frystyk 286: */
2.36 frystyk 287: if (realm && !strcasecomp(realm, "realm") && rm) {
288: if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", rm);
289: HTRequest_setRealm(request, rm);
2.40 frystyk 290:
291: /*
292: ** If we are in proxy mode then add the proxy - not the final URL
293: */
294: if (proxy) {
295: char * url = HTRequest_proxy(request);
2.42 frystyk 296: if (AUTH_TRACE) HTTrace("Basic Parse. Proxy authentication\n");
2.40 frystyk 297: basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
298: url, NULL);
2.49 ! kahan 299: /* if the previous authentication failed, then try again */
! 300: if (HTRequest_AAretrys (request) > 1
! 301: && status == HT_NO_ACCESS && basic)
! 302: basic->retry = YES;
2.40 frystyk 303: } else {
304: char * url = HTAnchor_address((HTAnchor *)
305: HTRequest_anchor(request));
306: char * tmplate = make_template(url);
307: basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
308: tmplate, NULL);
2.49 ! kahan 309: /* if the previous authentication failed, then try again */
! 310: if (HTRequest_AAretrys (request) > 1
! 311: && status == HT_NO_ACCESS && basic)
! 312: basic->retry = YES;
2.40 frystyk 313: HT_FREE(url);
314: HT_FREE(tmplate);
315: }
2.1 luotonen 316: }
2.38 frystyk 317:
318: /*
319: ** For some reason the authentication failed so we have to ask the user
320: ** if we should try again. It may be because the user typed the wrong
321: ** user name and password
322: */
2.49 ! kahan 323: if (basic && basic->retry) {
2.38 frystyk 324: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
2.40 frystyk 325:
326: /*
2.42 frystyk 327: ** Do we haev a method registered for prompting the user whether
328: ** we should retry
2.40 frystyk 329: */
2.38 frystyk 330: if (prompt) {
2.40 frystyk 331: int code = proxy ?
332: HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
333: if ((*prompt)(request, HT_A_CONFIRM, code,
2.38 frystyk 334: NULL, NULL, NULL) != YES)
335: return HT_ERROR;
336: basic->retry = YES;
337: }
338: }
2.36 frystyk 339: return HT_OK;
2.1 luotonen 340: }
2.36 frystyk 341: if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
2.38 frystyk 342: return HT_ERROR;
2.7 luotonen 343: }
2.44 frystyk 344:
345: /* ------------------------------------------------------------------------- */
346: /* Digest Authentication */
347: /* ------------------------------------------------------------------------- */
348:
349: /*
350: ** Prompt the user for username and password.
351: ** Returns YES if user name was typed in, else NO
352: */
353: PRIVATE int prompt_digest_user (HTRequest * request, const char * realm,
354: HTDigest * digest)
355: {
356: HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
357: if (request && cbf) {
358: HTAlertPar * reply = HTAlert_newReply();
359: int msg = digest->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
360: BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
361: digest->uid, (char *) realm, reply);
362: if (res) {
363: HT_FREE(digest->uid);
364: HT_FREE(digest->pw);
365: digest->uid = HTAlert_replyMessage(reply);
366: digest->pw = HTAlert_replySecret(reply);
367: }
368: HTAlert_deleteReply(reply);
369: return res ? HT_OK : HT_ERROR;
370: }
371: return HT_OK;
372: }
373:
374: PRIVATE HTDigest * HTDigest_new()
375: {
376: HTDigest * me = NULL;
377: if ((me = (HTDigest *) HT_CALLOC(1, sizeof(HTDigest))) == NULL)
378: HT_OUTOFMEM("HTDigest_new");
379: me->retry = YES; /* Ask the first time through */
380: return me;
381: }
382:
383: /* HTDigest_delete
384: ** --------------
385: ** Deletes a "digest" information object
386: ** A single object may be registered multiple places in the URL tree.
387: ** We keep a simple reference count on the object so that we know
388: ** when to delete the object.
389: */
390: PUBLIC int HTDigest_delete (void * context)
391: {
392: HTDigest * digest = (HTDigest *) context;
393: if (digest) {
394: if (digest->references <= 0) {
395: HT_FREE(digest->uid);
396: HT_FREE(digest->pw);
397: HT_FREE(digest->nounce);
398: HT_FREE(digest->opaque);
399: HT_FREE(digest);
400: } else
401: digest->references--;
402: return YES;
403: }
404: return NO;
405: }
406:
407: /*
408: ** Make digest authentication scheme credentials and register this
409: ** information in the request object as credentials. They will then
410: ** be included in the request header.
411: ** The function can both create normal and proxy credentials
412: ** Returns HT_OK or HT_ERROR
413: */
414: PRIVATE BOOL digest_credentials (HTRequest * request, HTDigest * digest)
415: {
416: if (request && digest) {
417:
418: /* THIS IS CURRENTLY FOR BASIC AUTH. CHANGE THIS TO DIGEST */
419:
420: char * cleartext = NULL;
421: char * cipher = NULL;
422: int cl_len = strlen(digest->uid ? digest->uid : "") +
423: strlen(digest->pw ? digest->pw : "") + 5;
424: int ci_len = 4 * (((cl_len+2)/3) + 1);
425: if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
426: HT_OUTOFMEM("digest_credentials");
427: *cleartext = '\0';
428: if (digest->uid) strcpy(cleartext, digest->uid);
429: strcat(cleartext, ":");
430: if (digest->pw) strcat(cleartext, digest->pw);
431: if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
432: HT_OUTOFMEM("digest_credentials");
433: HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
434:
435: /* Create the credentials and assign them to the request object */
436: {
437: int cr_len = strlen("digest") + ci_len + 3;
438: char * cookie = (char *) HT_MALLOC(cr_len+1);
439: if (!cookie) HT_OUTOFMEM("digest_credentials");
440: strcpy(cookie, "Digest ");
441: strcat(cookie, cipher);
442: if (AUTH_TRACE) HTTrace("Digest Cookie `%s\'\n", cookie);
443:
444: /* Check whether it is proxy or normal credentials */
445: if (digest->proxy)
446: HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
447: else
448: HTRequest_addCredentials(request, "Authorization", cookie);
449:
450: HT_FREE(cookie);
451: }
452: HT_FREE(cleartext);
453: HT_FREE(cipher);
454: return HT_OK;
455: }
456: return HT_ERROR;
457: }
458:
459: /* HTDigest_generate
460: ** ----------------
461: ** This function generates "digest" credentials for the challenge found in
462: ** the authentication information base for this request. The result is
463: ** stored as an association list in the request object.
464: ** This is a callback function for the AA handler.
465: */
2.45 frystyk 466: PUBLIC int HTDigest_generate (HTRequest * request, void * context, int mode)
2.44 frystyk 467: {
468: HTDigest * digest = (HTDigest *) context;
2.45 frystyk 469: BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO;
2.44 frystyk 470: if (request) {
471: const char * realm = HTRequest_realm(request);
2.46 frystyk 472:
473: /*
474: ** If we were asked to explicitly ask the user again
475: */
476: if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH)
477: digest->retry = YES;
2.44 frystyk 478:
479: /*
480: ** If we don't have a digest context then add a new one to the tree.
481: ** We use different trees for normal and proxy authentication
482: */
483: if (!digest) {
484: if (proxy) {
485: char * url = HTRequest_proxy(request);
486: digest = HTDigest_new();
487: digest->proxy = YES;
488: HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
489: } else {
490: char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
491: digest = HTDigest_new();
492: HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
493: HT_FREE(url);
494: }
495: }
496:
497: /*
498: ** If we have a set of credentials (or the user provides a new set)
499: ** then store it in the request object as the credentials
500: */
501: if ((digest->retry &&
502: prompt_digest_user(request, realm, digest) == HT_OK) ||
503: (!digest->retry && digest->uid)) {
504: digest->retry = NO;
505: return digest_credentials(request, digest);
506: } else
507: return HT_ERROR;
508: }
509: return HT_OK;
510: }
511:
512: /* HTDigest_parse
513: ** -------------
514: ** This function parses the contents of a "digest" challenge
515: ** and stores the challenge in our authentication information datebase.
516: ** We also store the realm in the request object which will help finding
517: ** the right set of credentials to generate.
518: ** The function is a callback function for the AA handler.
519: */
2.45 frystyk 520: PUBLIC int HTDigest_parse (HTRequest * request, HTResponse * response,
521: void * context, int status)
2.44 frystyk 522: {
2.45 frystyk 523: HTAssocList * challenge = HTResponse_challenge(response);
2.44 frystyk 524: HTDigest * digest = NULL;
525: BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
526: if (request && challenge) {
527: char * p = HTAssocList_findObject(challenge, DIGEST_AUTH);
528: char * realm = HTNextField(&p);
529: char * value = HTNextField(&p);
530: char * token = NULL;
531: char * uris = NULL;
532: BOOL found = NO;
533:
534: /*
535: ** Search for the realm and see if we have an entry for it. If not
536: ** then create a new entry.
537: */
538: if (realm && !strcasecomp(realm, "realm") && value) {
539: if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", value);
540: HTRequest_setRealm(request, value);
541: digest = (HTDigest *)
542: HTAA_updateNode(proxy, DIGEST_AUTH, value, NULL, NULL);
543: }
544: if (!digest)
545: digest = HTDigest_new();
546: else
547: found = YES;
548:
549: /*
550: ** Search through the set of parameters in the digest header.
551: ** If valid challenge then make a template for the resource and
552: ** store this information in our authentication URL Tree
553: */
554: while ((token = HTNextField(&p))) {
555: if (!strcasecomp(token, "domain")) {
556: if ((value = HTNextField(&p)))
557: uris = value;
558: } else if (!strcasecomp(token, "nounce")) {
559: if ((value = HTNextField(&p)))
560: StrAllocCopy(digest->nounce, value);
561: } else if (!strcasecomp(token, "opaque")) {
562: if ((value = HTNextField(&p)))
563: StrAllocCopy(digest->opaque, value);
564: } else if (!strcasecomp(token, "stale")) {
565: if ((value = HTNextField(&p)) && !strcasecomp(value, "true"))
566: digest->stale = YES;
567: } else if (!strcasecomp(token, "algorithm")) {
568: if ((value = HTNextField(&p)) && strcasecomp(value, "md5")) {
569: /*
570: ** We only support MD5 for the moment
571: */
572: if (AUTH_TRACE) HTTrace("Digest Parse Unknown algorithm `%s\'\n", value);
573: HTDigest_delete(digest);
574: return HT_ERROR;
575: }
576: }
577: }
578:
579: /*
580: ** Now as we have parsed the full digest header we update the URL tree
581: ** with the new information. If we didn't get a "domain" token then
582: ** add the node using a template. If we have multiple URIs in the
583: ** domain token then add a digest node at each URI.
584: */
585: if (!uris) {
586: if (proxy) {
587: char * location = HTRequest_proxy(request);
588: if (AUTH_TRACE) HTTrace("Digest Parse Proxy authentication\n");
589: HTAA_updateNode(proxy, DIGEST_AUTH, realm, location, digest);
590: } else {
591: char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
592: char * tmplate = make_template(url);
593: HTAA_updateNode(proxy, DIGEST_AUTH, realm, tmplate, digest);
594: HT_FREE(url);
595: HT_FREE(tmplate);
596: }
597: } else {
598:
599: /*
600: ** ADD THE DIGEST FOR EACH URL IN THE LIST AND INCREMENT THE
601: ** REFERENCE COUNT IN THE DIGEST BY ONE
602: */
603:
604: }
605:
606: /*
607: ** For some reason the authentication failed so we have to ask the user
608: ** if we should try again. It may be because the user typed the wrong
609: ** user name and password
610: */
611: if (found) {
612: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
613:
614: /*
615: ** Do we have a method registered for prompting the user whether
616: ** we should retry
617: */
618: if (prompt) {
619: int code = proxy ?
620: HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
621: if ((*prompt)(request, HT_A_CONFIRM, code,
622: NULL, NULL, NULL) != YES)
623: return HT_ERROR;
624: digest->retry = YES;
625: }
626: }
627: return HT_OK;
628: }
629: if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
630: return HT_ERROR;
631: }
632:
Webmaster