Annotation of libwww/Library/src/HTAABrow.c, revision 2.13
2.1 luotonen 1:
2: /* MODULE HTAABrow.c
3: ** BROWSER SIDE ACCESS AUTHORIZATION MODULE
4: **
5: ** Containts the code for keeping track on server hostnames,
6: ** port numbers, scheme names, usernames, passwords
7: ** (and servers' public keys).
8: **
9: ** IMPORTANT:
10: ** Routines in this module use dynamic allocation, but free
11: ** automatically all the memory reserved by them.
12: **
13: ** Therefore the caller never has to (and never should)
14: ** free() any object returned by these functions.
15: **
16: ** Therefore also all the strings returned by this package
17: ** are only valid until the next call to the same function
18: ** is made. This approach is selected, because of the nature
19: ** of access authorization: no string returned by the package
20: ** needs to be valid longer than until the next call.
21: **
22: ** This also makes it easy to plug the AA package in:
23: ** you don't have to ponder whether to free() something
24: ** here or is it done somewhere else (because it is always
25: ** done somewhere else).
26: **
27: ** The strings that the package needs to store are copied
28: ** so the original strings given as parameters to AA
29: ** functions may be freed or modified with no side effects.
30: **
31: ** The AA package does not free() anything else than what
32: ** it has itself allocated.
33: **
34: ** AUTHORS:
35: ** AL Ari Luotonen luotonen@dxcern.cern.ch
36: **
37: ** HISTORY:
2.5 luotonen 38: ** Oct 17 AL Made corrections suggested by marca:
39: ** Added if (!realm->username) return NULL;
40: ** Changed some ""s to NULLs.
41: ** Now doing calloc() to init uuencode source;
42: ** otherwise HTUU_encode() reads uninitialized memory
43: ** every now and then (not a real bug but not pretty).
44: ** Corrected the formula for uuencode destination size.
2.1 luotonen 45: ** BUGS:
46: **
47: **
48: */
49:
50: #include <string.h> /* strchr() */
51:
52: #include "HTUtils.h"
53: #include "HTString.h"
54: #include "HTParse.h" /* URL parsing function */
55: #include "HTList.h" /* HTList object */
56: #include "HTAlert.h" /* HTConfirm(), HTPrompt() */
57: #include "HTAAUtil.h" /* AA common to both sides */
2.2 luotonen 58: #include "HTAssoc.h" /* Assoc list */
2.1 luotonen 59: #include "HTAABrow.h" /* Implemented here */
60: #include "HTUU.h" /* Uuencoding and uudecoding */
2.7 luotonen 61: #include "HTAccess.h" /* HTRequest structure */
2.1 luotonen 62:
63:
64: /*
65: ** Module-wide global variables
66: */
67:
68: PRIVATE HTList *server_table = NULL; /* Browser's info about servers */
2.7 luotonen 69:
2.1 luotonen 70:
71: /**************************** HTAAServer ***********************************/
72:
73:
74: /* PRIVATE HTAAServer_new()
75: ** ALLOCATE A NEW NODE TO HOLD SERVER INFO
76: ** AND ADD IT TO THE LIST OF SERVERS
77: ** ON ENTRY:
78: ** hostname is the name of the host that the server
79: ** is running in.
80: ** portnumber is the portnumber which the server listens.
81: **
82: ** ON EXIT:
83: ** returns the newly-allocated node with all the strings
84: ** duplicated.
85: ** Strings will be automatically freed by
86: ** the function HTAAServer_delete(), which also
87: ** frees the node itself.
88: */
89: PRIVATE HTAAServer *HTAAServer_new ARGS2(CONST char*, hostname,
90: int, portnumber)
91: {
92: HTAAServer *server;
93:
94: if (!(server = (HTAAServer *)malloc(sizeof(HTAAServer))))
95: outofmem(__FILE__, "HTAAServer_new");
96:
97: server->hostname = NULL;
98: server->portnumber = (portnumber > 0 ? portnumber : 80);
99: server->setups = HTList_new();
2.4 luotonen 100: server->realms = HTList_new();
2.1 luotonen 101:
102: if (hostname) StrAllocCopy(server->hostname, hostname);
103:
104: if (!server_table) server_table = HTList_new();
105:
106: HTList_addObject(server_table, (void*)server);
107:
108: return server;
109: }
110:
111:
112: /* PRIVATE HTAAServer_delete()
113: **
114: ** DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE,
115: ** AND FREE THE MEMORY USED BY IT.
116: **
117: ** ON ENTRY:
118: ** killme points to the HTAAServer to be freed.
119: **
120: ** ON EXIT:
121: ** returns nothing.
122: */
123: #ifdef NOT_NEEDED_IT_SEEMS
124: PRIVATE void HTAASetup_delete(); /* Forward */
125: PRIVATE void HTAAServer_delete ARGS1(HTAAServer *, killme)
126: {
127: if (killme) {
2.4 luotonen 128: HTList *cur1 = killme->setups;
129: HTList *cur2 = killme->realms;
2.1 luotonen 130: HTAASetup *setup;
2.4 luotonen 131: HTAARealm *realm;
2.1 luotonen 132:
2.4 luotonen 133: while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur1)))
2.1 luotonen 134: HTAASetup_delete(setup);
135: HTList_delete(killme->setups);
136:
2.4 luotonen 137: while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur2)))
138: ; /* This sould free() the realm */
139: HTList_delete(killme->realms);
140:
2.1 luotonen 141: FREE(killme->hostname);
142:
143: HTList_removeObject(server_table, (void*)killme);
144:
145: free(killme);
146: }
147: }
148: #endif /*NOT_NEEDED_IT_SEEMS*/
149:
150:
151: /* PRIVATE HTAAServer_lookup()
152: ** LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
153: ** ON ENTRY:
154: ** hostname obvious.
155: ** portnumber if non-positive defaults to 80.
156: **
157: ** Looks up the server in the module-global server_table.
158: **
159: ** ON EXIT:
160: ** returns pointer to a HTAAServer structure
161: ** representing the looked-up server.
162: ** NULL, if not found.
163: */
164: PRIVATE HTAAServer *HTAAServer_lookup ARGS2(CONST char *, hostname,
165: int, portnumber)
166: {
167: if (hostname) {
168: HTList *cur = server_table;
169: HTAAServer *server;
170:
171: if (portnumber <= 0) portnumber = 80;
172:
173: while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
174: if (server->portnumber == portnumber &&
175: 0==strcmp(server->hostname, hostname))
176: return server;
177: }
178: }
179: return NULL; /* NULL parameter, or not found */
180: }
181:
182:
183:
184:
185: /*************************** HTAASetup *******************************/
186:
187:
188: /* PRIVATE HTAASetup_lookup()
189: ** FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
190: ** IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
191: **
192: ** ON ENTRY:
193: ** hostname is the name of the server host machine.
194: ** portnumber is the port that the server is running in.
195: ** docname is the (URL-)pathname of the document we
196: ** are trying to access.
197: **
198: ** This function goes through the information known about
199: ** all the setups of the server, and finds out if the given
200: ** filename resides in one of the protected directories.
201: **
202: ** ON EXIT:
203: ** returns NULL if no match.
204: ** Otherwise, a HTAASetup structure representing
205: ** the protected server setup on the corresponding
206: ** document tree.
207: **
208: */
209: PRIVATE HTAASetup *HTAASetup_lookup ARGS3(CONST char *, hostname,
210: int, portnumber,
211: CONST char *, docname)
212: {
213: HTAAServer *server;
214: HTAASetup *setup;
215:
216: if (portnumber <= 0) portnumber = 80;
217:
218: if (hostname && docname && *hostname && *docname &&
219: NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
220:
221: HTList *cur = server->setups;
222:
223: if (TRACE) fprintf(stderr, "%s (%s:%d:%s)\n",
224: "HTAASetup_lookup: resolving setup for",
225: hostname, portnumber, docname);
226:
227: while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
2.13 ! frystyk 228: if (HTAA_templateMatch(setup->tmplate, docname)) {
2.1 luotonen 229: if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
230: "HTAASetup_lookup:", docname,
2.13 ! frystyk 231: "matched template", setup->tmplate);
2.1 luotonen 232: return setup;
233: }
234: else if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
235: "HTAASetup_lookup:", docname,
2.13 ! frystyk 236: "did NOT match template", setup->tmplate);
2.1 luotonen 237: } /* while setups remain */
238: } /* if valid parameters and server found */
239:
240: if (TRACE) fprintf(stderr, "%s `%s' %s\n",
241: "HTAASetup_lookup: No template matched",
242: (docname ? docname : "(null)"),
243: "(so probably not protected)");
244:
245: return NULL; /* NULL in parameters, or not found */
246: }
247:
248:
249:
250:
251: /* PRIVATE HTAASetup_new()
252: ** CREATE A NEW SETUP NODE
253: ** ON ENTRY:
254: ** server is a pointer to a HTAAServer structure
255: ** to which this setup belongs.
256: ** template documents matching this template
257: ** are protected according to this setup.
2.2 luotonen 258: ** valid_schemes a list containing all valid authentication
259: ** schemes for this setup.
2.1 luotonen 260: ** If NULL, all schemes are disallowed.
2.2 luotonen 261: ** scheme_specifics is an array of assoc lists, which
262: ** contain scheme specific parameters given
263: ** by server in Authenticate: fields.
2.1 luotonen 264: ** If NULL, all scheme specifics are
265: ** set to NULL.
266: ** ON EXIT:
267: ** returns a new HTAASetup node, and also adds it as
268: ** part of the HTAAServer given as parameter.
269: */
270: PRIVATE HTAASetup *HTAASetup_new ARGS4(HTAAServer *, server,
2.13 ! frystyk 271: char *, tmplate,
2.2 luotonen 272: HTList *, valid_schemes,
273: HTAssocList **, scheme_specifics)
2.1 luotonen 274: {
275: HTAASetup *setup;
276:
2.13 ! frystyk 277: if (!server || !tmplate || !*tmplate) return NULL;
2.1 luotonen 278:
279: if (!(setup = (HTAASetup*)malloc(sizeof(HTAASetup))))
280: outofmem(__FILE__, "HTAASetup_new");
281:
2.7 luotonen 282: setup->reprompt = NO;
2.1 luotonen 283: setup->server = server;
2.13 ! frystyk 284: setup->tmplate = NULL;
! 285: if (tmplate) StrAllocCopy(setup->tmplate, tmplate);
2.2 luotonen 286: setup->valid_schemes = valid_schemes;
287: setup->scheme_specifics = scheme_specifics;
2.1 luotonen 288:
2.2 luotonen 289: HTList_addObject(server->setups, (void*)setup);
2.1 luotonen 290:
291: return setup;
292: }
293:
294:
295:
296: /* PRIVATE HTAASetup_delete()
297: ** FREE A HTAASetup STRUCTURE
298: ** ON ENTRY:
299: ** killme is a pointer to the structure to free().
300: **
301: ** ON EXIT:
302: ** returns nothing.
303: */
304: #ifdef NOT_NEEDED_IT_SEEMS
305: PRIVATE void HTAASetup_delete ARGS1(HTAASetup *, killme)
306: {
2.2 luotonen 307: int scheme;
2.1 luotonen 308:
309: if (killme) {
2.13 ! frystyk 310: if (killme->tmplate) free(killme->tmplate);
2.2 luotonen 311: if (killme->valid_schemes)
312: HTList_delete(killme->valid_schemes);
313: for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++)
314: if (killme->scheme_specifics[scheme])
315: HTAssocList_delete(killme->scheme_specifics[scheme]);
2.1 luotonen 316: free(killme);
317: }
318: }
319: #endif /*NOT_NEEDED_IT_SEEMS*/
320:
321:
322:
323: /* PRIVATE HTAASetup_updateSpecifics()
324: * COPY SCHEME SPECIFIC PARAMETERS
325: ** TO HTAASetup STRUCTURE
326: ** ON ENTRY:
327: ** setup destination setup structure.
328: ** specifics string array containing scheme
329: ** specific parameters for each scheme.
330: ** If NULL, all the scheme specific
331: ** parameters are set to NULL.
332: **
333: ** ON EXIT:
334: ** returns nothing.
335: */
2.2 luotonen 336: PRIVATE void HTAASetup_updateSpecifics ARGS2(HTAASetup *, setup,
337: HTAssocList **, specifics)
2.1 luotonen 338: {
2.2 luotonen 339: int scheme;
2.1 luotonen 340:
2.2 luotonen 341: if (setup) {
342: if (setup->scheme_specifics) {
343: for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
344: if (setup->scheme_specifics[scheme])
345: HTAssocList_delete(setup->scheme_specifics[scheme]);
346: }
347: free(setup->scheme_specifics);
348: }
349: setup->scheme_specifics = specifics;
2.1 luotonen 350: }
351: }
352:
353:
354:
355:
356: /*************************** HTAARealm **********************************/
357:
358: /* PRIVATE HTAARealm_lookup()
359: ** LOOKUP HTAARealm STRUCTURE BY REALM NAME
360: ** ON ENTRY:
2.4 luotonen 361: ** realm_table a list of realm objects.
2.1 luotonen 362: ** realmname is the name of realm to look for.
363: **
364: ** ON EXIT:
365: ** returns the realm. NULL, if not found.
366: */
2.4 luotonen 367: PRIVATE HTAARealm *HTAARealm_lookup ARGS2(HTList *, realm_table,
368: CONST char *, realmname)
2.1 luotonen 369: {
370: if (realm_table && realmname) {
371: HTList *cur = realm_table;
372: HTAARealm *realm;
373:
374: while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
375: if (0==strcmp(realm->realmname, realmname))
376: return realm;
377: }
378: }
379: return NULL; /* No table, NULL param, or not found */
380: }
381:
382:
383:
384: /* PRIVATE HTAARealm_new()
385: ** CREATE A NODE CONTAINING USERNAME AND
386: ** PASSWORD USED FOR THE GIVEN REALM.
387: ** IF REALM ALREADY EXISTS, CHANGE
388: ** USERNAME/PASSWORD.
389: ** ON ENTRY:
2.4 luotonen 390: ** realm_table a list of realms to where to add
391: ** the new one, too.
2.1 luotonen 392: ** realmname is the name of the password domain.
393: ** username and
394: ** password are what you can expect them to be.
395: **
396: ** ON EXIT:
397: ** returns the created realm.
398: */
2.4 luotonen 399: PRIVATE HTAARealm *HTAARealm_new ARGS4(HTList *, realm_table,
400: CONST char *, realmname,
2.1 luotonen 401: CONST char *, username,
402: CONST char *, password)
403: {
404: HTAARealm *realm;
405:
2.4 luotonen 406: realm = HTAARealm_lookup(realm_table, realmname);
2.1 luotonen 407:
408: if (!realm) {
409: if (!(realm = (HTAARealm*)malloc(sizeof(HTAARealm))))
410: outofmem(__FILE__, "HTAARealm_new");
411: realm->realmname = NULL;
412: realm->username = NULL;
413: realm->password = NULL;
414: StrAllocCopy(realm->realmname, realmname);
2.4 luotonen 415: if (realm_table) HTList_addObject(realm_table, (void*)realm);
2.1 luotonen 416: }
417: if (username) StrAllocCopy(realm->username, username);
418: if (password) StrAllocCopy(realm->password, password);
419:
420: return realm;
421: }
422:
423:
424:
425:
426: /***************** Basic and Pubkey Authentication ************************/
427:
2.7 luotonen 428: /* PRIVATE compose_Basic_auth()
2.1 luotonen 429: **
2.7 luotonen 430: ** COMPOSE Basic SCHEME AUTHENTICATION STRING
2.1 luotonen 431: **
432: ** ON ENTRY:
2.7 luotonen 433: ** req request, where
434: ** req->scheme == HTAA_BASIC
435: ** req->realm contains username and password.
2.1 luotonen 436: **
437: ** ON EXIT:
438: ** returns a newly composed authorization string,
2.5 luotonen 439: ** NULL, if something fails.
2.1 luotonen 440: ** NOTE:
441: ** Like throughout the entire AA package, no string or structure
442: ** returned by AA package needs to (or should) be freed.
443: **
444: */
2.7 luotonen 445: PRIVATE char *compose_Basic_auth ARGS1(HTRequest *, req)
2.1 luotonen 446: {
447: static char *result = NULL; /* Uuencoded presentation, the result */
448: char *cleartext = NULL; /* Cleartext presentation */
449: int len;
450:
451: FREE(result); /* From previous call */
452:
2.7 luotonen 453: if (!req || req->scheme != HTAA_BASIC || !req->setup ||
454: !req->setup->server)
2.5 luotonen 455: return NULL;
2.1 luotonen 456:
2.7 luotonen 457: if (!req->realm) {
458: char *realmname;
2.1 luotonen 459:
2.7 luotonen 460: if (!req->setup || !req->setup->scheme_specifics ||
461: !(realmname =
462: HTAssocList_lookup(req->setup->scheme_specifics[HTAA_BASIC],
463: "realm")))
464: return NULL;
465:
466: req->realm = HTAARealm_lookup(req->setup->server->realms, realmname);
467: if (!req->realm) {
468: req->realm = HTAARealm_new(req->setup->server->realms,
469: realmname, NULL, NULL);
470: return NULL;
2.1 luotonen 471: }
472: }
473:
2.7 luotonen 474: len = strlen(req->realm->username ? req->realm->username : "") +
475: strlen(req->realm->password ? req->realm->password : "") + 3;
2.1 luotonen 476:
2.5 luotonen 477: if (!(cleartext = (char*)calloc(len, 1)))
2.7 luotonen 478: outofmem(__FILE__, "compose_Basic_auth");
2.1 luotonen 479:
2.7 luotonen 480: if (req->realm->username) strcpy(cleartext, req->realm->username);
2.3 luotonen 481: else *cleartext = (char)0;
2.1 luotonen 482:
483: strcat(cleartext, ":");
484:
2.7 luotonen 485: if (req->realm->password) strcat(cleartext, req->realm->password);
486:
487: if (!(result = (char*)malloc(4 * ((len+2)/3) + 1)))
488: outofmem(__FILE__, "compose_Basic_auth");
489: HTUU_encode((unsigned char *)cleartext, strlen(cleartext), result);
490: free(cleartext);
2.1 luotonen 491:
492: return result;
493: }
494:
495:
496:
497: /* BROWSER PRIVATE HTAA_selectScheme()
498: ** SELECT THE AUTHENTICATION SCHEME TO USE
499: ** ON ENTRY:
500: ** setup is the server setup structure which can
501: ** be used to make the decision about the
502: ** used scheme.
503: **
504: ** When new authentication methods are added to library
505: ** this function makes the decision about which one to
506: ** use at a given time. This can be done by inspecting
507: ** environment variables etc.
508: **
2.2 luotonen 509: ** Currently only searches for the first valid scheme,
510: ** and if nothing found suggests Basic scheme;
511: **
2.1 luotonen 512: ** ON EXIT:
513: ** returns the authentication scheme to use.
514: */
515: PRIVATE HTAAScheme HTAA_selectScheme ARGS1(HTAASetup *, setup)
516: {
2.13 ! frystyk 517: int scheme;
2.2 luotonen 518: if (setup && setup->valid_schemes) {
2.13 ! frystyk 519: for (scheme = (HTAAScheme) HTAA_BASIC;
! 520: scheme < (HTAAScheme) HTAA_MAX_SCHEMES;
! 521: scheme++)
! 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.
674: ** req->retry_callback
675: ** function to call when username and password
676: ** have been entered.
2.1 luotonen 677: ** ON EXIT:
2.7 luotonen 678: **
679: ** returns nothing.
680: ** Calls (*req->retry_callback)(req).
681: **
682: */
683: PUBLIC void HTPasswordDialog ARGS1(HTRequest *, req)
2.1 luotonen 684: {
2.7 luotonen 685: if (!req || !req->setup || !req->realm || !req->dialog_msg ||
686: !req->retry_callback) {
687: HTAlert("HTPasswordDialog() called with an illegal parameter");
688: return;
689: }
690: if (req->setup->reprompt &&
691: NO == HTConfirm("Authorization failed. Retry?")) {
692: return;
693: } /* HTConfirm(...) == NO */
694: else { /* re-ask username+password (if misspelled) */
695: char *username = req->realm->username;
696: char *password = NULL;
2.1 luotonen 697:
2.7 luotonen 698: HTPromptUsernameAndPassword(req->dialog_msg, &username, &password);
2.1 luotonen 699:
2.7 luotonen 700: if (req->realm->username) free(req->realm->username);
701: if (req->realm->password) free(req->realm->password);
702: req->realm->username = username;
703: req->realm->password = password;
2.1 luotonen 704:
2.7 luotonen 705: if (!req->realm->username)
706: return; /* Suggested by marca; thanks! */
707: else
708: (*req->retry_callback)(req); /* Callback */
709: }
710: }
2.1 luotonen 711:
712:
713:
2.7 luotonen 714: /* BROWSER PUBLIC HTAA_retryWithAuth()
715: **
716: ** RETRY THE SERVER WITH AUTHORIZATION (OR IF
717: ** ALREADY RETRIED, WITH A DIFFERENT USERNAME
718: ** AND/OR PASSWORD (IF MISSPELLED)) OR CANCEL
719: ** ON ENTRY:
720: ** req request.
721: ** req->valid_schemes
722: ** This function should only be called when
723: ** server has replied with a 401 (Unauthorized)
724: ** status code, and req structure has been filled
725: ** up according to server reply, especially the
726: ** req->valid_shemes list must have been set up
727: ** according to WWW-Authenticate: headers.
728: ** ON EXIT:
729: ** On GUI clients pops up a username/password dialog box
730: ** with "Ok" and "Cancel".
731: ** "Ok" button press should do a callback
732: **
733: ** HTLoadHTTP(req);
734: **
735: ** This actually done by function HTPasswordDialog(),
736: ** which GUI clients redefine.
737: **
738: ** returns YES, if dialog box was popped up.
739: ** NO, on failure.
740: */
741: PUBLIC BOOL HTAA_retryWithAuth ARGS2(HTRequest *, req,
742: HTRetryCallbackType, callback)
743: {
744: int len;
745: char *realmname;
2.9 luotonen 746: char *arg = NULL;
2.1 luotonen 747:
2.9 luotonen 748: if (!req || !req->anchor ||
2.7 luotonen 749: !req->valid_schemes || HTList_count(req->valid_schemes) == 0) {
750: req->setup = NULL;
2.1 luotonen 751: return NO;
752: }
753:
2.9 luotonen 754: arg = HTAnchor_physical(req->anchor);
755:
2.7 luotonen 756: if (req->setup && req->setup->server) {
2.1 luotonen 757: /* So we have already tried with authorization. */
758: /* Either we don't have access or username or */
759: /* password was misspelled. */
760:
761: /* Update scheme-specific parameters */
762: /* (in case they have expired by chance). */
2.7 luotonen 763: HTAASetup_updateSpecifics(req->setup, req->scheme_specifics);
764: req->scheme = HTAA_selectScheme(req->setup);
765: req->setup->reprompt = YES;
766: }
2.1 luotonen 767: else { /* current_setup == NULL, i.e. we have a */
768: /* first connection to a protected server or */
769: /* the server serves a wider set of documents */
770: /* than we expected so far. */
771:
2.7 luotonen 772: static char *hostname;
773: static char *docname;
774: int portnumber;
775: char *colon;
776: HTAAServer *server;
777:
778: FREE(hostname); /* From previous call */
779: FREE(docname); /* - " - */
780:
2.9 luotonen 781: docname = HTParse(arg, "", PARSE_PATH);
782: hostname = HTParse(arg, "", PARSE_HOST);
2.7 luotonen 783: if (hostname &&
784: NULL != (colon = strchr(hostname, ':'))) {
785: *(colon++) = '\0'; /* Chop off port number */
786: portnumber = atoi(colon);
787: }
788: else portnumber = 80;
789:
790: if (TRACE) fprintf(stderr,
791: "HTAA_retryWithAuth: first retry of %s:%d/%s\n",
792: hostname, portnumber, docname);
793:
794: if (!(server = HTAAServer_lookup(hostname, portnumber))) {
795: server = HTAAServer_new(hostname, portnumber);
796: }
797: else {
798: HTAlert("Access without authorization denied -- retrying");
2.1 luotonen 799: }
800:
2.7 luotonen 801: if (!req->prot_template)
802: req->prot_template = HTAA_makeProtectionTemplate(docname);
803: req->setup = HTAASetup_new(server,
804: req->prot_template,
805: req->valid_schemes,
806: req->scheme_specifics);
807: req->setup->reprompt = NO;
808: req->scheme = HTAA_selectScheme(req->setup);
809:
2.1 luotonen 810: } /* else current_setup == NULL */
811:
2.7 luotonen 812: realmname = HTAssocList_lookup(req->setup->scheme_specifics[req->scheme],
813: "realm");
814: if (!realmname)
815: return NO;
816:
817: req->realm = HTAARealm_lookup(req->setup->server->realms, realmname);
818: if (!req->realm)
819: req->realm = HTAARealm_new(req->setup->server->realms,
820: realmname, NULL, NULL);
821:
822: len = strlen(realmname) + 100;
823: if (req->setup->server->hostname)
824: len += strlen(req->setup->server->hostname);
2.11 frystyk 825:
826: FREE(req->dialog_msg); /* Free from previous call, Henrik 14/03-94 */
2.7 luotonen 827: if (!(req->dialog_msg = (char*)malloc(len)))
828: outofmem(__FILE__, "HTAA_retryWithAuth");
829: if (!req->realm->username)
830: sprintf(req->dialog_msg, "%s %s at %s",
831: "Document is protected. Enter username for",
832: req->realm->realmname,
833: req->setup->server->hostname
834: ? req->setup->server->hostname : "??");
835: else sprintf(req->dialog_msg, "%s %s at %s",
836: "Authorization failed. Enter username for",
837: req->realm->realmname,
838: req->setup->server->hostname
839: ? req->setup->server->hostname : "??");
840:
841: req->retry_callback = callback; /* Set callback function */
842: HTPasswordDialog(req);
843: return YES;
2.11 frystyk 844: }
845:
846:
847: /* PUPLIC HTAA_cleanup()
848: **
849: ** Free the memory used by the entries concerning Access Authorization
850: ** in the request structure and put all pointers to NULL
851: ** Henrik 14/03-94.
852: **
853: ** ON ENTRY:
854: ** req the request structure
855: **
856: ** ON EXIT:
857: ** returns nothing.
858: */
859: PUBLIC void HTAACleanup ARGS1(HTRequest *, req)
860: {
861: if (req) {
862: FREE(req->authorization);
863: FREE(req->prot_template);
864: FREE(req->dialog_msg);
2.12 frystyk 865: #ifdef OLD_CODE
866: /* Should not be freed as they have become a part of a static
867: memory */
2.11 frystyk 868: if (req->valid_schemes) {
869: HTList_delete(req->valid_schemes);
870: req->valid_schemes = NULL;
871: }
872: if (req->scheme_specifics) {
873: int cnt;
874: for (cnt=0; cnt<HTAA_MAX_SCHEMES; cnt++) {
875: if (req->scheme_specifics[cnt])
876: HTAssocList_delete(req->scheme_specifics[cnt]);
877: }
878: FREE(req->scheme_specifics);
879: }
2.12 frystyk 880: #endif /* OLD_CODE */
2.11 frystyk 881: }
882: return;
2.1 luotonen 883: }
2.7 luotonen 884:
885:
2.1 luotonen 886:
Webmaster