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