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