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