Annotation of libwww/Library/src/HTAABrow.c, revision 2.31
2.15 frystyk 1: /* HTAABrow.c
2.1 luotonen 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.1 luotonen 6: **
7: ** Containts the code for keeping track on server hostnames,
8: ** port numbers, scheme names, usernames, passwords
9: ** (and servers' public keys).
10: **
11: ** IMPORTANT:
12: ** Routines in this module use dynamic allocation, but free
13: ** automatically all the memory reserved by them.
14: **
15: ** Therefore the caller never has to (and never should)
16: ** free() any object returned by these functions.
17: **
18: ** Therefore also all the strings returned by this package
19: ** are only valid until the next call to the same function
20: ** is made. This approach is selected, because of the nature
21: ** of access authorization: no string returned by the package
22: ** needs to be valid longer than until the next call.
23: **
24: ** This also makes it easy to plug the AA package in:
25: ** you don't have to ponder whether to free() something
26: ** here or is it done somewhere else (because it is always
27: ** done somewhere else).
28: **
29: ** The strings that the package needs to store are copied
30: ** so the original strings given as parameters to AA
31: ** functions may be freed or modified with no side effects.
32: **
33: ** The AA package does not free() anything else than what
34: ** it has itself allocated.
35: **
36: ** AUTHORS:
37: ** AL Ari Luotonen luotonen@dxcern.cern.ch
38: **
39: ** HISTORY:
2.5 luotonen 40: ** Oct 17 AL Made corrections suggested by marca:
41: ** Added if (!realm->username) return NULL;
42: ** Changed some ""s to NULLs.
43: ** Now doing calloc() to init uuencode source;
44: ** otherwise HTUU_encode() reads uninitialized memory
45: ** every now and then (not a real bug but not pretty).
46: ** Corrected the formula for uuencode destination size.
2.1 luotonen 47: ** BUGS:
48: **
49: **
50: */
51:
2.17 frystyk 52: /* Library include files */
2.27 frystyk 53: #include "WWWLib.h"
54: #include "HTReqMan.h" /* @@@@ */
55: #include "HTAAUtil.h"
56: #include "HTAABrow.h" /* Implemented here */
2.1 luotonen 57:
58: PRIVATE HTList *server_table = NULL; /* Browser's info about servers */
2.7 luotonen 59:
2.1 luotonen 60: /**************************** HTAAServer ***********************************/
61:
62:
63: /* PRIVATE HTAAServer_new()
64: ** ALLOCATE A NEW NODE TO HOLD SERVER INFO
65: ** AND ADD IT TO THE LIST OF SERVERS
66: ** ON ENTRY:
67: ** hostname is the name of the host that the server
68: ** is running in.
69: ** portnumber is the portnumber which the server listens.
70: **
71: ** ON EXIT:
72: ** returns the newly-allocated node with all the strings
73: ** duplicated.
74: ** Strings will be automatically freed by
75: ** the function HTAAServer_delete(), which also
76: ** frees the node itself.
77: */
2.27 frystyk 78: PRIVATE HTAAServer *HTAAServer_new (CONST char * hostname, int portnumber)
2.1 luotonen 79: {
80: HTAAServer *server;
81:
2.30 frystyk 82: if ((server = (HTAAServer *) HT_MALLOC(sizeof(HTAAServer))) == NULL)
83: HT_OUTOFMEM("HTAAServer_new");
2.1 luotonen 84:
85: server->hostname = NULL;
86: server->portnumber = (portnumber > 0 ? portnumber : 80);
87: server->setups = HTList_new();
2.4 luotonen 88: server->realms = HTList_new();
2.1 luotonen 89:
90: if (hostname) StrAllocCopy(server->hostname, hostname);
91:
92: if (!server_table) server_table = HTList_new();
93:
94: HTList_addObject(server_table, (void*)server);
95:
96: return server;
97: }
98:
99:
100: /* PRIVATE HTAAServer_lookup()
101: ** LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
102: ** ON ENTRY:
103: ** hostname obvious.
104: ** portnumber if non-positive defaults to 80.
105: **
106: ** Looks up the server in the module-global server_table.
107: **
108: ** ON EXIT:
109: ** returns pointer to a HTAAServer structure
110: ** representing the looked-up server.
111: ** NULL, if not found.
112: */
2.27 frystyk 113: PRIVATE HTAAServer *HTAAServer_lookup (CONST char * hostname, int portnumber)
2.1 luotonen 114: {
115: if (hostname) {
116: HTList *cur = server_table;
117: HTAAServer *server;
118:
119: if (portnumber <= 0) portnumber = 80;
120:
121: while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
122: if (server->portnumber == portnumber &&
123: 0==strcmp(server->hostname, hostname))
124: return server;
125: }
126: }
127: return NULL; /* NULL parameter, or not found */
128: }
129:
130:
131:
132:
133: /*************************** HTAASetup *******************************/
134:
135:
136: /* PRIVATE HTAASetup_lookup()
137: ** FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
138: ** IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
139: **
140: ** ON ENTRY:
141: ** hostname is the name of the server host machine.
142: ** portnumber is the port that the server is running in.
143: ** docname is the (URL-)pathname of the document we
144: ** are trying to access.
145: **
146: ** This function goes through the information known about
147: ** all the setups of the server, and finds out if the given
148: ** filename resides in one of the protected directories.
149: **
150: ** ON EXIT:
151: ** returns NULL if no match.
152: ** Otherwise, a HTAASetup structure representing
153: ** the protected server setup on the corresponding
154: ** document tree.
155: **
156: */
2.27 frystyk 157: PRIVATE HTAASetup *HTAASetup_lookup (CONST char * hostname,
158: int portnumber,
159: CONST char * docname)
2.1 luotonen 160: {
161: HTAAServer *server;
162: HTAASetup *setup;
163:
164: if (portnumber <= 0) portnumber = 80;
165:
166: if (hostname && docname && *hostname && *docname &&
167: NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
168:
169: HTList *cur = server->setups;
170:
2.24 frystyk 171: if (PROT_TRACE)
2.31 ! eric 172: HTTrace("Access Auth. resolving setup for (%s:%d:%s)\n",
2.21 frystyk 173: hostname, portnumber, docname);
2.1 luotonen 174:
175: while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
2.13 frystyk 176: if (HTAA_templateMatch(setup->tmplate, docname)) {
2.24 frystyk 177: if (PROT_TRACE)
2.31 ! eric 178: HTTrace("Access Auth. `%s' matched template `%s'\n",
2.21 frystyk 179: docname, setup->tmplate);
2.1 luotonen 180: return setup;
181: }
2.24 frystyk 182: else if (PROT_TRACE)
2.31 ! eric 183: HTTrace("%s `%s' %s `%s'\n","HTAASetup_lookup:", docname,
2.24 frystyk 184: "did NOT match template", setup->tmplate);
2.1 luotonen 185: } /* while setups remain */
186: } /* if valid parameters and server found */
187:
2.24 frystyk 188: if (PROT_TRACE)
2.31 ! eric 189: HTTrace("Access Auth. `%s' (so probably not protected)\n",
2.21 frystyk 190: (docname ? docname : "(null)"));
191: return NULL; /* NULL in parameters, or not found */
2.1 luotonen 192: }
193:
194:
195:
196:
197: /* PRIVATE HTAASetup_new()
198: ** CREATE A NEW SETUP NODE
199: ** ON ENTRY:
200: ** server is a pointer to a HTAAServer structure
201: ** to which this setup belongs.
202: ** template documents matching this template
203: ** are protected according to this setup.
2.2 luotonen 204: ** valid_schemes a list containing all valid authentication
205: ** schemes for this setup.
2.1 luotonen 206: ** If NULL, all schemes are disallowed.
2.2 luotonen 207: ** scheme_specifics is an array of assoc lists, which
208: ** contain scheme specific parameters given
209: ** by server in Authenticate: fields.
2.1 luotonen 210: ** If NULL, all scheme specifics are
211: ** set to NULL.
212: ** ON EXIT:
213: ** returns a new HTAASetup node, and also adds it as
214: ** part of the HTAAServer given as parameter.
215: */
2.27 frystyk 216: PRIVATE HTAASetup *HTAASetup_new (HTAAServer * server,
217: char * tmplate,
218: HTList * valid_schemes,
219: HTAssocList **scheme_specifics)
2.1 luotonen 220: {
221: HTAASetup *setup;
222:
2.13 frystyk 223: if (!server || !tmplate || !*tmplate) return NULL;
2.1 luotonen 224:
2.30 frystyk 225: if ((setup = (HTAASetup *) HT_MALLOC(sizeof(HTAASetup))) == NULL)
226: HT_OUTOFMEM("HTAASetup_new");
2.1 luotonen 227:
2.7 luotonen 228: setup->reprompt = NO;
2.1 luotonen 229: setup->server = server;
2.13 frystyk 230: setup->tmplate = NULL;
231: if (tmplate) StrAllocCopy(setup->tmplate, tmplate);
2.2 luotonen 232: setup->valid_schemes = valid_schemes;
233: setup->scheme_specifics = scheme_specifics;
2.1 luotonen 234:
2.2 luotonen 235: HTList_addObject(server->setups, (void*)setup);
2.1 luotonen 236:
237: return setup;
238: }
239:
240:
241:
242: /* PRIVATE HTAASetup_delete()
243: ** FREE A HTAASetup STRUCTURE
244: ** ON ENTRY:
2.30 frystyk 245: ** killme is a pointer to the structure to free;
2.1 luotonen 246: **
247: ** ON EXIT:
248: ** returns nothing.
249: */
250: #ifdef NOT_NEEDED_IT_SEEMS
2.27 frystyk 251: PRIVATE void HTAASetup_delete (HTAASetup * killme)
2.1 luotonen 252: {
2.2 luotonen 253: int scheme;
2.1 luotonen 254:
255: if (killme) {
2.30 frystyk 256: if (killme->tmplate) HT_FREE(killme->tmplate);
2.2 luotonen 257: if (killme->valid_schemes)
258: HTList_delete(killme->valid_schemes);
259: for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++)
260: if (killme->scheme_specifics[scheme])
261: HTAssocList_delete(killme->scheme_specifics[scheme]);
2.30 frystyk 262: HT_FREE(killme);
2.1 luotonen 263: }
264: }
265: #endif /*NOT_NEEDED_IT_SEEMS*/
266:
267:
268:
269: /* PRIVATE HTAASetup_updateSpecifics()
270: * COPY SCHEME SPECIFIC PARAMETERS
271: ** TO HTAASetup STRUCTURE
272: ** ON ENTRY:
273: ** setup destination setup structure.
274: ** specifics string array containing scheme
275: ** specific parameters for each scheme.
276: ** If NULL, all the scheme specific
277: ** parameters are set to NULL.
278: **
279: ** ON EXIT:
280: ** returns nothing.
281: */
2.27 frystyk 282: PRIVATE void HTAASetup_updateSpecifics (HTAASetup * setup,
283: HTAssocList ** specifics)
2.1 luotonen 284: {
2.2 luotonen 285: int scheme;
2.1 luotonen 286:
2.2 luotonen 287: if (setup) {
288: if (setup->scheme_specifics) {
289: for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
290: if (setup->scheme_specifics[scheme])
291: HTAssocList_delete(setup->scheme_specifics[scheme]);
292: }
2.30 frystyk 293: HT_FREE(setup->scheme_specifics);
2.2 luotonen 294: }
295: setup->scheme_specifics = specifics;
2.1 luotonen 296: }
297: }
298:
299:
300:
301:
302: /*************************** HTAARealm **********************************/
303:
304: /* PRIVATE HTAARealm_lookup()
305: ** LOOKUP HTAARealm STRUCTURE BY REALM NAME
306: ** ON ENTRY:
2.4 luotonen 307: ** realm_table a list of realm objects.
2.1 luotonen 308: ** realmname is the name of realm to look for.
309: **
310: ** ON EXIT:
311: ** returns the realm. NULL, if not found.
312: */
2.27 frystyk 313: PRIVATE HTAARealm *HTAARealm_lookup (HTList * realm_table,
314: CONST char * realmname)
2.1 luotonen 315: {
316: if (realm_table && realmname) {
317: HTList *cur = realm_table;
318: HTAARealm *realm;
319:
320: while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
321: if (0==strcmp(realm->realmname, realmname))
322: return realm;
323: }
324: }
325: return NULL; /* No table, NULL param, or not found */
326: }
327:
328:
329:
330: /* PRIVATE HTAARealm_new()
331: ** CREATE A NODE CONTAINING USERNAME AND
332: ** PASSWORD USED FOR THE GIVEN REALM.
333: ** IF REALM ALREADY EXISTS, CHANGE
334: ** USERNAME/PASSWORD.
335: ** ON ENTRY:
2.4 luotonen 336: ** realm_table a list of realms to where to add
337: ** the new one, too.
2.1 luotonen 338: ** realmname is the name of the password domain.
339: ** username and
340: ** password are what you can expect them to be.
341: **
342: ** ON EXIT:
343: ** returns the created realm.
344: */
2.27 frystyk 345: PRIVATE HTAARealm *HTAARealm_new (HTList * realm_table,
346: CONST char * realmname,
347: CONST char * username,
348: CONST char * password)
2.1 luotonen 349: {
350: HTAARealm *realm;
351:
2.4 luotonen 352: realm = HTAARealm_lookup(realm_table, realmname);
2.1 luotonen 353:
354: if (!realm) {
2.30 frystyk 355: if ((realm = (HTAARealm *) HT_MALLOC(sizeof(HTAARealm))) == NULL)
356: HT_OUTOFMEM("HTAARealm_new");
2.1 luotonen 357: realm->realmname = NULL;
358: realm->username = NULL;
359: realm->password = NULL;
360: StrAllocCopy(realm->realmname, realmname);
2.4 luotonen 361: if (realm_table) HTList_addObject(realm_table, (void*)realm);
2.1 luotonen 362: }
363: if (username) StrAllocCopy(realm->username, username);
364: if (password) StrAllocCopy(realm->password, password);
365:
366: return realm;
367: }
368:
369:
370:
371:
372: /***************** Basic and Pubkey Authentication ************************/
373:
2.7 luotonen 374: /* PRIVATE compose_Basic_auth()
2.1 luotonen 375: **
2.7 luotonen 376: ** COMPOSE Basic SCHEME AUTHENTICATION STRING
2.1 luotonen 377: **
378: ** ON ENTRY:
2.7 luotonen 379: ** req request, where
380: ** req->scheme == HTAA_BASIC
381: ** req->realm contains username and password.
2.1 luotonen 382: **
383: ** ON EXIT:
384: ** returns a newly composed authorization string,
2.5 luotonen 385: ** NULL, if something fails.
2.1 luotonen 386: ** NOTE:
387: ** Like throughout the entire AA package, no string or structure
388: ** returned by AA package needs to (or should) be freed.
389: **
390: */
2.27 frystyk 391: PRIVATE char *compose_Basic_auth (HTRequest * req)
2.1 luotonen 392: {
393: static char *result = NULL; /* Uuencoded presentation, the result */
394: char *cleartext = NULL; /* Cleartext presentation */
395: int len;
396:
2.30 frystyk 397: HT_FREE(result); /* from previous call */
2.1 luotonen 398:
2.7 luotonen 399: if (!req || req->scheme != HTAA_BASIC || !req->setup ||
400: !req->setup->server)
2.5 luotonen 401: return NULL;
2.1 luotonen 402:
2.7 luotonen 403: if (!req->realm) {
404: char *realmname;
2.1 luotonen 405:
2.7 luotonen 406: if (!req->setup || !req->setup->scheme_specifics ||
407: !(realmname =
408: HTAssocList_lookup(req->setup->scheme_specifics[HTAA_BASIC],
409: "realm")))
410: return NULL;
411:
412: req->realm = HTAARealm_lookup(req->setup->server->realms, realmname);
413: if (!req->realm) {
414: req->realm = HTAARealm_new(req->setup->server->realms,
415: realmname, NULL, NULL);
416: return NULL;
2.1 luotonen 417: }
418: }
419:
2.7 luotonen 420: len = strlen(req->realm->username ? req->realm->username : "") +
421: strlen(req->realm->password ? req->realm->password : "") + 3;
2.1 luotonen 422:
2.30 frystyk 423: if ((cleartext = (char *) HT_CALLOC(len, 1)) == NULL)
424: HT_OUTOFMEM("compose_Basic_auth");
2.1 luotonen 425:
2.7 luotonen 426: if (req->realm->username) strcpy(cleartext, req->realm->username);
2.3 luotonen 427: else *cleartext = (char)0;
2.1 luotonen 428:
429: strcat(cleartext, ":");
430:
2.7 luotonen 431: if (req->realm->password) strcat(cleartext, req->realm->password);
432:
2.30 frystyk 433: if ((result = (char *) HT_MALLOC(4 * ((len+2)/3) + 1)) == NULL)
434: HT_OUTOFMEM("compose_Basic_auth");
2.7 luotonen 435: HTUU_encode((unsigned char *)cleartext, strlen(cleartext), result);
2.30 frystyk 436: HT_FREE(cleartext);
2.1 luotonen 437:
438: return result;
439: }
440:
441:
442:
443: /* BROWSER PRIVATE HTAA_selectScheme()
444: ** SELECT THE AUTHENTICATION SCHEME TO USE
445: ** ON ENTRY:
446: ** setup is the server setup structure which can
447: ** be used to make the decision about the
448: ** used scheme.
449: **
450: ** When new authentication methods are added to library
451: ** this function makes the decision about which one to
452: ** use at a given time. This can be done by inspecting
453: ** environment variables etc.
454: **
2.2 luotonen 455: ** Currently only searches for the first valid scheme,
456: ** and if nothing found suggests Basic scheme;
457: **
2.1 luotonen 458: ** ON EXIT:
459: ** returns the authentication scheme to use.
460: */
2.27 frystyk 461: PRIVATE HTAAScheme HTAA_selectScheme (HTAASetup * setup)
2.1 luotonen 462: {
2.14 frystyk 463: HTAAScheme scheme;
2.2 luotonen 464: if (setup && setup->valid_schemes) {
2.14 frystyk 465: for (scheme = HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++)
2.13 frystyk 466: if (-1 < HTList_indexOf(setup->valid_schemes, (void *) scheme))
467: return (HTAAScheme) scheme;
2.2 luotonen 468: }
2.7 luotonen 469: return HTAA_NONE;
2.1 luotonen 470: }
471:
472:
473:
474:
475: /* BROWSER PUBLIC HTAA_composeAuth()
476: **
2.7 luotonen 477: ** COMPOSE Authorization: HEADER LINE CONTENTS
2.1 luotonen 478: ** IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
479: **
480: ** ON ENTRY:
2.7 luotonen 481: ** req request, which contains
482: ** req->setup protection setup info on browser.
483: ** req->scheme selected authentication scheme.
484: ** req->realm for Basic scheme the username and password.
485: **
486: ** ON EXIT:
487: ** returns NO, if no authorization seems to be needed, and
488: ** req->authorization is NULL.
489: ** YES, if it has composed Authorization field,
490: ** in which case the result is in req->authorization,
491: ** e.g.
492: **
493: ** "Basic AkRDIhEF8sdEgs72F73bfaS=="
494: */
2.27 frystyk 495: PUBLIC BOOL HTAA_composeAuth (HTRequest * req)
2.7 luotonen 496: {
497: char *auth_string = NULL;
498: static char *docname;
499: static char *hostname;
500: int portnumber;
501: char *colon;
502: char *gate = NULL; /* Obsolite? */
2.9 luotonen 503: char *arg = NULL;
2.7 luotonen 504:
2.30 frystyk 505: HT_FREE(hostname); /* From previous call */
506: HT_FREE(docname); /* - " - */
2.5 luotonen 507:
2.9 luotonen 508: if (!req || !req->anchor)
2.7 luotonen 509: return NO;
2.1 luotonen 510:
2.9 luotonen 511: arg = HTAnchor_physical(req->anchor);
512: docname = HTParse(arg, "", PARSE_PATH);
513: hostname = HTParse((gate ? gate : arg), "", PARSE_HOST);
2.7 luotonen 514: if (hostname &&
515: NULL != (colon = strchr(hostname, ':'))) {
516: *(colon++) = '\0'; /* Chop off port number */
517: portnumber = atoi(colon);
518: }
519: else portnumber = 80;
520:
2.24 frystyk 521: if (PROT_TRACE)
2.31 ! eric 522: HTTrace("Access Auth. composing authorization for %s:%d/%s\n",
2.21 frystyk 523: hostname, portnumber, docname);
2.1 luotonen 524:
2.7 luotonen 525: #ifdef OLD_CODE
2.1 luotonen 526: if (current_portnumber != portnumber ||
527: !current_hostname || !current_docname ||
528: !hostname || !docname ||
529: 0 != strcmp(current_hostname, hostname) ||
530: 0 != strcmp(current_docname, docname)) {
531:
532: retry = NO;
533:
534: current_portnumber = portnumber;
535:
536: if (hostname) StrAllocCopy(current_hostname, hostname);
2.30 frystyk 537: else HT_FREE(current_hostname);
2.1 luotonen 538:
539: if (docname) StrAllocCopy(current_docname, docname);
2.30 frystyk 540: else HT_FREE(current_docname);
2.1 luotonen 541: }
542: else retry = YES;
2.7 luotonen 543: #endif /*OLD_CODE*/
2.1 luotonen 544:
2.7 luotonen 545: if (!req->setup)
546: req->setup = HTAASetup_lookup(hostname, portnumber, docname);
547: if (!req->setup)
548: return NO;
2.1 luotonen 549:
2.12 frystyk 550: if (req->scheme == HTAA_NONE || req->scheme == HTAA_UNKNOWN)
2.7 luotonen 551: req->scheme = HTAA_selectScheme(req->setup);
2.1 luotonen 552:
2.7 luotonen 553: switch (req->scheme) {
2.1 luotonen 554: case HTAA_BASIC:
2.7 luotonen 555: auth_string = compose_Basic_auth(req);
556: break;
2.1 luotonen 557: case HTAA_PUBKEY:
558: case HTAA_KERBEROS_V4:
559: /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
560: default:
561: {
562: char msg[100];
563: sprintf(msg, "%s %s `%s'",
564: "This client doesn't know how to compose authentication",
2.7 luotonen 565: "information for scheme", HTAAScheme_name(req->scheme));
2.27 frystyk 566: HTRequest_addError(req, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
567: msg, 0, "HTLoadHTTP");
2.5 luotonen 568: auth_string = NULL;
2.1 luotonen 569: }
570: } /* switch scheme */
571:
2.7 luotonen 572: req->setup->reprompt = NO;
2.1 luotonen 573:
2.5 luotonen 574: /* Added by marca. */
575: if (!auth_string)
2.7 luotonen 576: return NO;
2.5 luotonen 577:
2.30 frystyk 578: HT_FREE(req->authorization); /* Free from previous call, Henrik 14/03-94 */
579: if ((req->authorization = (char *) HT_MALLOC(sizeof(char) * (strlen(auth_string)+40))) == NULL)
580: HT_OUTOFMEM("HTAA_composeAuth");
2.1 luotonen 581:
2.7 luotonen 582: strcpy(req->authorization, HTAAScheme_name(req->scheme));
583: strcat(req->authorization, " ");
584: strcat(req->authorization, auth_string);
2.1 luotonen 585:
2.7 luotonen 586: return YES;
587: }
2.1 luotonen 588:
2.5 luotonen 589:
2.7 luotonen 590: /* BROWSER OVERLOADED HTPasswordDialog()
591: **
592: ** PROMPT USERNAME AND PASSWORD, AND MAKE A
593: ** CALLBACK TO FUNCTION HTLoadHTTP().
2.1 luotonen 594: **
2.7 luotonen 595: ** This function must be redifined by GUI clients, which
596: ** call HTLoadHTTP(req) when user presses "Ok".
2.1 luotonen 597: **
2.7 luotonen 598: ** ON ENTRY:
599: ** req request.
600: ** req->dialog_msg prompting message.
601: ** req->setup information about protections of this request.
602: ** req->realm structure describing one password realm.
2.1 luotonen 603: ** This function should only be called when
604: ** server has replied with a 401 (Unauthorized)
2.7 luotonen 605: ** status code, and req structure has been filled
606: ** up according to server reply, especially the
607: ** req->valid_shemes list must have been set up
608: ** according to WWW-Authenticate: headers.
2.1 luotonen 609: ** ON EXIT:
2.7 luotonen 610: **
2.14 frystyk 611: ** returns YES or NO
2.7 luotonen 612: **
613: */
2.27 frystyk 614: PUBLIC BOOL HTPasswordDialog (HTRequest * req)
2.1 luotonen 615: {
2.27 frystyk 616: HTAlertCallback *cbf = HTAlert_find(HT_A_USER_PW);
2.14 frystyk 617: if (!req || !req->setup || !req->realm || !req->dialog_msg) {
2.22 frystyk 618: if (PROT_TRACE)
2.31 ! eric 619: HTTrace("Access...... called with an illegal parameter");
2.14 frystyk 620: return NO;
2.7 luotonen 621: }
2.27 frystyk 622: if (cbf) {
623: HTAlertPar * reply = HTAlert_newReply();
2.30 frystyk 624: HT_FREE(req->realm->username);
625: HT_FREE(req->realm->password);
2.27 frystyk 626: if (((*cbf)(req, HT_A_USER_PW, HT_MSG_NULL, NULL,
627: req->realm->realmname, reply))) {
628: req->realm->username = HTAlert_replyMessage(reply);
629: req->realm->password = HTAlert_replySecret(reply);
630: }
2.28 frystyk 631: HTAlert_deleteReply(reply);
2.27 frystyk 632: /* Suggested by marca; thanks! */
633: return req->realm->username ? YES : NO;
2.7 luotonen 634: }
2.14 frystyk 635: return NO;
2.7 luotonen 636: }
2.1 luotonen 637:
638:
639:
2.7 luotonen 640: /* BROWSER PUBLIC HTAA_retryWithAuth()
641: **
642: ** RETRY THE SERVER WITH AUTHORIZATION (OR IF
643: ** ALREADY RETRIED, WITH A DIFFERENT USERNAME
644: ** AND/OR PASSWORD (IF MISSPELLED)) OR CANCEL
645: ** ON ENTRY:
646: ** req request.
647: ** req->valid_schemes
648: ** This function should only be called when
649: ** server has replied with a 401 (Unauthorized)
650: ** status code, and req structure has been filled
651: ** up according to server reply, especially the
652: ** req->valid_shemes list must have been set up
653: ** according to WWW-Authenticate: headers.
654: ** ON EXIT:
655: ** On GUI clients pops up a username/password dialog box
656: ** with "Ok" and "Cancel".
657: ** "Ok" button press should do a callback
658: **
659: ** HTLoadHTTP(req);
660: **
661: ** This actually done by function HTPasswordDialog(),
662: ** which GUI clients redefine.
663: **
664: ** returns YES, if dialog box was popped up.
665: ** NO, on failure.
666: */
2.27 frystyk 667: PUBLIC BOOL HTAA_retryWithAuth (HTRequest * req)
2.7 luotonen 668: {
669: int len;
670: char *realmname;
2.9 luotonen 671: char *arg = NULL;
2.1 luotonen 672:
2.9 luotonen 673: if (!req || !req->anchor ||
2.7 luotonen 674: !req->valid_schemes || HTList_count(req->valid_schemes) == 0) {
675: req->setup = NULL;
2.1 luotonen 676: return NO;
677: }
678:
2.9 luotonen 679: arg = HTAnchor_physical(req->anchor);
680:
2.7 luotonen 681: if (req->setup && req->setup->server) {
2.1 luotonen 682: /* So we have already tried with authorization. */
683: /* Either we don't have access or username or */
684: /* password was misspelled. */
685:
686: /* Update scheme-specific parameters */
687: /* (in case they have expired by chance). */
2.7 luotonen 688: HTAASetup_updateSpecifics(req->setup, req->scheme_specifics);
689: req->scheme = HTAA_selectScheme(req->setup);
690: req->setup->reprompt = YES;
691: }
2.1 luotonen 692: else { /* current_setup == NULL, i.e. we have a */
693: /* first connection to a protected server or */
694: /* the server serves a wider set of documents */
695: /* than we expected so far. */
696:
2.7 luotonen 697: static char *hostname;
698: static char *docname;
699: int portnumber;
700: char *colon;
701: HTAAServer *server;
702:
2.30 frystyk 703: HT_FREE(hostname); /* From previous call */
704: HT_FREE(docname); /* - " - */
2.7 luotonen 705:
2.9 luotonen 706: docname = HTParse(arg, "", PARSE_PATH);
707: hostname = HTParse(arg, "", PARSE_HOST);
2.7 luotonen 708: if (hostname &&
709: NULL != (colon = strchr(hostname, ':'))) {
710: *(colon++) = '\0'; /* Chop off port number */
711: portnumber = atoi(colon);
712: }
713: else portnumber = 80;
714:
2.24 frystyk 715: if (PROT_TRACE)
2.31 ! eric 716: HTTrace("HTAA_retryWithAuth: first retry of %s:%d/%s\n",
2.24 frystyk 717: hostname, portnumber, docname);
2.7 luotonen 718:
719: if (!(server = HTAAServer_lookup(hostname, portnumber))) {
720: server = HTAAServer_new(hostname, portnumber);
721: }
2.27 frystyk 722: #if 0
723: else
2.22 frystyk 724: HTAlert(req, "Access without authorization denied -- retrying");
2.1 luotonen 725: }
2.27 frystyk 726: #endif
2.1 luotonen 727:
2.7 luotonen 728: if (!req->prot_template)
729: req->prot_template = HTAA_makeProtectionTemplate(docname);
730: req->setup = HTAASetup_new(server,
731: req->prot_template,
732: req->valid_schemes,
733: req->scheme_specifics);
734: req->setup->reprompt = NO;
735: req->scheme = HTAA_selectScheme(req->setup);
736:
2.1 luotonen 737: } /* else current_setup == NULL */
738:
2.7 luotonen 739: realmname = HTAssocList_lookup(req->setup->scheme_specifics[req->scheme],
740: "realm");
741: if (!realmname)
742: return NO;
743:
744: req->realm = HTAARealm_lookup(req->setup->server->realms, realmname);
745: if (!req->realm)
746: req->realm = HTAARealm_new(req->setup->server->realms,
747: realmname, NULL, NULL);
748:
749: len = strlen(realmname) + 100;
750: if (req->setup->server->hostname)
751: len += strlen(req->setup->server->hostname);
2.11 frystyk 752:
2.30 frystyk 753: HT_FREE(req->dialog_msg); /* Free from previous call, Henrik 14/03-94 */
754: if ((req->dialog_msg = (char *) HT_MALLOC(len)) == NULL)
755: HT_OUTOFMEM("HTAA_retryWithAuth");
2.7 luotonen 756: if (!req->realm->username)
2.20 frystyk 757: sprintf(req->dialog_msg, "\n%s %s at %s",
2.7 luotonen 758: "Document is protected. Enter username for",
759: req->realm->realmname,
760: req->setup->server->hostname
761: ? req->setup->server->hostname : "??");
2.20 frystyk 762: else sprintf(req->dialog_msg, "\n%s %s at %s",
2.7 luotonen 763: "Authorization failed. Enter username for",
764: req->realm->realmname,
765: req->setup->server->hostname
766: ? req->setup->server->hostname : "??");
2.14 frystyk 767: return (HTPasswordDialog(req));
2.11 frystyk 768: }
769:
2.29 frystyk 770: /*
771: ** Setup HTTP access authentication
772: */
773: PUBLIC BOOL HTAA_authentication (HTRequest * request)
774: {
775: HTAAScheme scheme;
776: HTList *valid_schemes = HTList_new();
777: HTAssocList **scheme_specifics = NULL;
778: char *tmplate = NULL;
779:
780: if (request->WWWAAScheme) {
781: if ((scheme = HTAAScheme_enum(request->WWWAAScheme)) != HTAA_UNKNOWN) {
782: HTList_addObject(valid_schemes, (void *) scheme);
783: if (!scheme_specifics) {
784: int i;
2.30 frystyk 785: scheme_specifics = (HTAssocList**) HT_MALLOC(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
2.29 frystyk 786: if (!scheme_specifics)
787: outofmem(__FILE__, "HTTPAuthentication");
788: for (i=0; i < HTAA_MAX_SCHEMES; i++)
789: scheme_specifics[i] = NULL;
790: }
791: scheme_specifics[scheme] = HTAA_parseArgList(request->WWWAARealm);
792: } else if (PROT_TRACE) {
793: HTRequest_addError(request, ERR_INFO, NO, HTERR_UNKNOWN_AA,
794: (void *) request->WWWAAScheme, 0, "HTTPAuthentication");
795: return NO;
796: }
797: }
798: if (request->WWWprotection) {
799: if (PROT_TRACE)
2.31 ! eric 800: HTTrace("Protection template set to `%s'\n",
2.29 frystyk 801: request->WWWprotection);
802: StrAllocCopy(tmplate, request->WWWprotection);
803: }
804: request->valid_schemes = valid_schemes;
805: request->scheme_specifics = scheme_specifics;
806: request->prot_template = tmplate;
807: return YES;
808: }
Webmaster