Annotation of libwww/Library/src/HTAABrow.c, revision 2.6
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 */
61:
62:
63:
64: /*
65: ** Local datatype definitions
66: **
67: ** HTAAServer contains all the information about one server.
68: */
69: typedef struct {
70:
71: char * hostname; /* Host's name */
72: int portnumber; /* Port number */
73: HTList * setups; /* List of protection setups */
74: /* on this server; i.e. valid */
75: /* authentication schemes and */
76: /* templates when to use them. */
77: /* This is actually a list of */
78: /* HTAASetup objects. */
2.4 luotonen 79: HTList * realms; /* Information about passwords */
2.1 luotonen 80: } HTAAServer;
81:
82:
83: /*
84: ** HTAASetup contains information about one server's one
85: ** protected tree of documents.
86: */
87: typedef struct {
88: HTAAServer *server; /* Which server serves this tree */
89: char * template; /* Template for this tree */
2.2 luotonen 90: HTList * valid_schemes; /* Valid authentic.schemes */
91: HTAssocList**scheme_specifics;/* Scheme specific params */
2.1 luotonen 92: BOOL retry; /* Failed last time -- reprompt (or whatever)*/
93: } HTAASetup;
94:
95:
96: /*
97: ** Information about usernames and passwords in
98: ** Basic and Pubkey authentication schemes;
99: */
100: typedef struct {
101: char * realmname; /* Password domain name */
102: char * username; /* Username in that domain */
103: char * password; /* Corresponding password */
104: } HTAARealm;
105:
106:
107:
108: /*
109: ** Module-wide global variables
110: */
111:
112: PRIVATE HTList *server_table = NULL; /* Browser's info about servers */
113: PRIVATE char *secret_key = NULL; /* Browser's latest secret key */
114: PRIVATE HTAASetup *current_setup= NULL; /* The server setup we are currently */
115: /* talking to */
116: PRIVATE char *current_hostname = NULL; /* The server's name and portnumber */
117: PRIVATE int current_portnumber = 80; /* where we are currently trying to */
118: /* connect. */
119: PRIVATE char *current_docname = NULL; /* The document's name we are */
120: /* trying to access. */
2.5 luotonen 121: PRIVATE char *HTAAForwardAuth = NULL; /* Authorization: line to forward */
122: /* (used by gateway httpds) */
123:
124:
125: /*** HTAAForwardAuth for enabling gateway-httpds to forward Authorization ***/
126:
127: PUBLIC void HTAAForwardAuth_set ARGS2(CONST char *, scheme_name,
128: CONST char *, scheme_specifics)
129: {
130: int len = 20 + (scheme_name ? strlen(scheme_name) : 0)
131: + (scheme_specifics ? strlen(scheme_specifics) : 0);
2.1 luotonen 132:
2.5 luotonen 133: FREE(HTAAForwardAuth);
134: if (!(HTAAForwardAuth = (char*)malloc(len)))
135: outofmem(__FILE__, "HTAAForwardAuth_set");
2.1 luotonen 136:
2.5 luotonen 137: strcpy(HTAAForwardAuth, "Authorization: ");
138: if (scheme_name) {
139: strcat(HTAAForwardAuth, scheme_name);
140: strcat(HTAAForwardAuth, " ");
141: if (scheme_specifics) {
142: strcat(HTAAForwardAuth, scheme_specifics);
143: }
144: }
145: }
2.1 luotonen 146:
147:
2.5 luotonen 148: PUBLIC void HTAAForwardAuth_reset NOARGS
149: {
150: FREE(HTAAForwardAuth);
151: }
152:
2.1 luotonen 153:
154: /**************************** HTAAServer ***********************************/
155:
156:
157: /* PRIVATE HTAAServer_new()
158: ** ALLOCATE A NEW NODE TO HOLD SERVER INFO
159: ** AND ADD IT TO THE LIST OF SERVERS
160: ** ON ENTRY:
161: ** hostname is the name of the host that the server
162: ** is running in.
163: ** portnumber is the portnumber which the server listens.
164: **
165: ** ON EXIT:
166: ** returns the newly-allocated node with all the strings
167: ** duplicated.
168: ** Strings will be automatically freed by
169: ** the function HTAAServer_delete(), which also
170: ** frees the node itself.
171: */
172: PRIVATE HTAAServer *HTAAServer_new ARGS2(CONST char*, hostname,
173: int, portnumber)
174: {
175: HTAAServer *server;
176:
177: if (!(server = (HTAAServer *)malloc(sizeof(HTAAServer))))
178: outofmem(__FILE__, "HTAAServer_new");
179:
180: server->hostname = NULL;
181: server->portnumber = (portnumber > 0 ? portnumber : 80);
182: server->setups = HTList_new();
2.4 luotonen 183: server->realms = HTList_new();
2.1 luotonen 184:
185: if (hostname) StrAllocCopy(server->hostname, hostname);
186:
187: if (!server_table) server_table = HTList_new();
188:
189: HTList_addObject(server_table, (void*)server);
190:
191: return server;
192: }
193:
194:
195: /* PRIVATE HTAAServer_delete()
196: **
197: ** DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE,
198: ** AND FREE THE MEMORY USED BY IT.
199: **
200: ** ON ENTRY:
201: ** killme points to the HTAAServer to be freed.
202: **
203: ** ON EXIT:
204: ** returns nothing.
205: */
206: #ifdef NOT_NEEDED_IT_SEEMS
207: PRIVATE void HTAASetup_delete(); /* Forward */
208: PRIVATE void HTAAServer_delete ARGS1(HTAAServer *, killme)
209: {
210: if (killme) {
2.4 luotonen 211: HTList *cur1 = killme->setups;
212: HTList *cur2 = killme->realms;
2.1 luotonen 213: HTAASetup *setup;
2.4 luotonen 214: HTAARealm *realm;
2.1 luotonen 215:
2.4 luotonen 216: while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur1)))
2.1 luotonen 217: HTAASetup_delete(setup);
218: HTList_delete(killme->setups);
219:
2.4 luotonen 220: while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur2)))
221: ; /* This sould free() the realm */
222: HTList_delete(killme->realms);
223:
2.1 luotonen 224: FREE(killme->hostname);
225:
226: HTList_removeObject(server_table, (void*)killme);
227:
228: free(killme);
229: }
230: }
231: #endif /*NOT_NEEDED_IT_SEEMS*/
232:
233:
234: /* PRIVATE HTAAServer_lookup()
235: ** LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
236: ** ON ENTRY:
237: ** hostname obvious.
238: ** portnumber if non-positive defaults to 80.
239: **
240: ** Looks up the server in the module-global server_table.
241: **
242: ** ON EXIT:
243: ** returns pointer to a HTAAServer structure
244: ** representing the looked-up server.
245: ** NULL, if not found.
246: */
247: PRIVATE HTAAServer *HTAAServer_lookup ARGS2(CONST char *, hostname,
248: int, portnumber)
249: {
250: if (hostname) {
251: HTList *cur = server_table;
252: HTAAServer *server;
253:
254: if (portnumber <= 0) portnumber = 80;
255:
256: while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
257: if (server->portnumber == portnumber &&
258: 0==strcmp(server->hostname, hostname))
259: return server;
260: }
261: }
262: return NULL; /* NULL parameter, or not found */
263: }
264:
265:
266:
267:
268: /*************************** HTAASetup *******************************/
269:
270:
271: /* PRIVATE HTAASetup_lookup()
272: ** FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
273: ** IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
274: **
275: ** ON ENTRY:
276: ** hostname is the name of the server host machine.
277: ** portnumber is the port that the server is running in.
278: ** docname is the (URL-)pathname of the document we
279: ** are trying to access.
280: **
281: ** This function goes through the information known about
282: ** all the setups of the server, and finds out if the given
283: ** filename resides in one of the protected directories.
284: **
285: ** ON EXIT:
286: ** returns NULL if no match.
287: ** Otherwise, a HTAASetup structure representing
288: ** the protected server setup on the corresponding
289: ** document tree.
290: **
291: */
292: PRIVATE HTAASetup *HTAASetup_lookup ARGS3(CONST char *, hostname,
293: int, portnumber,
294: CONST char *, docname)
295: {
296: HTAAServer *server;
297: HTAASetup *setup;
298:
299: if (portnumber <= 0) portnumber = 80;
300:
301: if (hostname && docname && *hostname && *docname &&
302: NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
303:
304: HTList *cur = server->setups;
305:
306: if (TRACE) fprintf(stderr, "%s (%s:%d:%s)\n",
307: "HTAASetup_lookup: resolving setup for",
308: hostname, portnumber, docname);
309:
310: while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
311: if (HTAA_templateMatch(setup->template, docname)) {
312: if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
313: "HTAASetup_lookup:", docname,
314: "matched template", setup->template);
315: return setup;
316: }
317: else if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
318: "HTAASetup_lookup:", docname,
319: "did NOT match template", setup->template);
320: } /* while setups remain */
321: } /* if valid parameters and server found */
322:
323: if (TRACE) fprintf(stderr, "%s `%s' %s\n",
324: "HTAASetup_lookup: No template matched",
325: (docname ? docname : "(null)"),
326: "(so probably not protected)");
327:
328: return NULL; /* NULL in parameters, or not found */
329: }
330:
331:
332:
333:
334: /* PRIVATE HTAASetup_new()
335: ** CREATE A NEW SETUP NODE
336: ** ON ENTRY:
337: ** server is a pointer to a HTAAServer structure
338: ** to which this setup belongs.
339: ** template documents matching this template
340: ** are protected according to this setup.
2.2 luotonen 341: ** valid_schemes a list containing all valid authentication
342: ** schemes for this setup.
2.1 luotonen 343: ** If NULL, all schemes are disallowed.
2.2 luotonen 344: ** scheme_specifics is an array of assoc lists, which
345: ** contain scheme specific parameters given
346: ** by server in Authenticate: fields.
2.1 luotonen 347: ** If NULL, all scheme specifics are
348: ** set to NULL.
349: ** ON EXIT:
350: ** returns a new HTAASetup node, and also adds it as
351: ** part of the HTAAServer given as parameter.
352: */
353: PRIVATE HTAASetup *HTAASetup_new ARGS4(HTAAServer *, server,
354: char *, template,
2.2 luotonen 355: HTList *, valid_schemes,
356: HTAssocList **, scheme_specifics)
2.1 luotonen 357: {
358: HTAASetup *setup;
359:
360: if (!server || !template || !*template) return NULL;
361:
362: if (!(setup = (HTAASetup*)malloc(sizeof(HTAASetup))))
363: outofmem(__FILE__, "HTAASetup_new");
364:
365: setup->retry = NO;
366: setup->server = server;
367: setup->template = NULL;
2.2 luotonen 368: if (template) StrAllocCopy(setup->template, template);
369: setup->valid_schemes = valid_schemes;
370: setup->scheme_specifics = scheme_specifics;
2.1 luotonen 371:
2.2 luotonen 372: HTList_addObject(server->setups, (void*)setup);
2.1 luotonen 373:
374: return setup;
375: }
376:
377:
378:
379: /* PRIVATE HTAASetup_delete()
380: ** FREE A HTAASetup STRUCTURE
381: ** ON ENTRY:
382: ** killme is a pointer to the structure to free().
383: **
384: ** ON EXIT:
385: ** returns nothing.
386: */
387: #ifdef NOT_NEEDED_IT_SEEMS
388: PRIVATE void HTAASetup_delete ARGS1(HTAASetup *, killme)
389: {
2.2 luotonen 390: int scheme;
2.1 luotonen 391:
392: if (killme) {
2.2 luotonen 393: if (killme->template) free(killme->template);
394: if (killme->valid_schemes)
395: HTList_delete(killme->valid_schemes);
396: for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++)
397: if (killme->scheme_specifics[scheme])
398: HTAssocList_delete(killme->scheme_specifics[scheme]);
2.1 luotonen 399: free(killme);
400: }
401: }
402: #endif /*NOT_NEEDED_IT_SEEMS*/
403:
404:
405:
406: /* PRIVATE HTAASetup_updateSpecifics()
407: * COPY SCHEME SPECIFIC PARAMETERS
408: ** TO HTAASetup STRUCTURE
409: ** ON ENTRY:
410: ** setup destination setup structure.
411: ** specifics string array containing scheme
412: ** specific parameters for each scheme.
413: ** If NULL, all the scheme specific
414: ** parameters are set to NULL.
415: **
416: ** ON EXIT:
417: ** returns nothing.
418: */
2.2 luotonen 419: PRIVATE void HTAASetup_updateSpecifics ARGS2(HTAASetup *, setup,
420: HTAssocList **, specifics)
2.1 luotonen 421: {
2.2 luotonen 422: int scheme;
2.1 luotonen 423:
2.2 luotonen 424: if (setup) {
425: if (setup->scheme_specifics) {
426: for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
427: if (setup->scheme_specifics[scheme])
428: HTAssocList_delete(setup->scheme_specifics[scheme]);
429: }
430: free(setup->scheme_specifics);
431: }
432: setup->scheme_specifics = specifics;
2.1 luotonen 433: }
434: }
435:
436:
437:
438:
439: /*************************** HTAARealm **********************************/
440:
441: /* PRIVATE HTAARealm_lookup()
442: ** LOOKUP HTAARealm STRUCTURE BY REALM NAME
443: ** ON ENTRY:
2.4 luotonen 444: ** realm_table a list of realm objects.
2.1 luotonen 445: ** realmname is the name of realm to look for.
446: **
447: ** ON EXIT:
448: ** returns the realm. NULL, if not found.
449: */
2.4 luotonen 450: PRIVATE HTAARealm *HTAARealm_lookup ARGS2(HTList *, realm_table,
451: CONST char *, realmname)
2.1 luotonen 452: {
453: if (realm_table && realmname) {
454: HTList *cur = realm_table;
455: HTAARealm *realm;
456:
457: while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
458: if (0==strcmp(realm->realmname, realmname))
459: return realm;
460: }
461: }
462: return NULL; /* No table, NULL param, or not found */
463: }
464:
465:
466:
467: /* PRIVATE HTAARealm_new()
468: ** CREATE A NODE CONTAINING USERNAME AND
469: ** PASSWORD USED FOR THE GIVEN REALM.
470: ** IF REALM ALREADY EXISTS, CHANGE
471: ** USERNAME/PASSWORD.
472: ** ON ENTRY:
2.4 luotonen 473: ** realm_table a list of realms to where to add
474: ** the new one, too.
2.1 luotonen 475: ** realmname is the name of the password domain.
476: ** username and
477: ** password are what you can expect them to be.
478: **
479: ** ON EXIT:
480: ** returns the created realm.
481: */
2.4 luotonen 482: PRIVATE HTAARealm *HTAARealm_new ARGS4(HTList *, realm_table,
483: CONST char *, realmname,
2.1 luotonen 484: CONST char *, username,
485: CONST char *, password)
486: {
487: HTAARealm *realm;
488:
2.4 luotonen 489: realm = HTAARealm_lookup(realm_table, realmname);
2.1 luotonen 490:
491: if (!realm) {
492: if (!(realm = (HTAARealm*)malloc(sizeof(HTAARealm))))
493: outofmem(__FILE__, "HTAARealm_new");
494: realm->realmname = NULL;
495: realm->username = NULL;
496: realm->password = NULL;
497: StrAllocCopy(realm->realmname, realmname);
2.4 luotonen 498: if (realm_table) HTList_addObject(realm_table, (void*)realm);
2.1 luotonen 499: }
500: if (username) StrAllocCopy(realm->username, username);
501: if (password) StrAllocCopy(realm->password, password);
502:
503: return realm;
504: }
505:
506:
507:
508:
509: /***************** Basic and Pubkey Authentication ************************/
510:
511: /* PRIVATE compose_auth_string()
512: **
513: ** COMPOSE Basic OR Pubkey AUTHENTICATION STRING;
514: ** PROMPTS FOR USERNAME AND PASSWORD IF NEEDED
515: **
516: ** ON ENTRY:
517: ** scheme is either HTAA_BASIC or HTAA_PUBKEY.
518: ** realmname is the password domain name.
519: **
520: ** ON EXIT:
521: ** returns a newly composed authorization string,
522: ** (with, of course, a newly generated secret
523: ** key and fresh timestamp, if Pubkey-scheme
524: ** is being used).
2.5 luotonen 525: ** NULL, if something fails.
2.1 luotonen 526: ** NOTE:
527: ** Like throughout the entire AA package, no string or structure
528: ** returned by AA package needs to (or should) be freed.
529: **
530: */
531: PRIVATE char *compose_auth_string ARGS2(HTAAScheme, scheme,
532: HTAASetup *, setup)
533: {
534: static char *result = NULL; /* Uuencoded presentation, the result */
535: char *cleartext = NULL; /* Cleartext presentation */
536: char *ciphertext = NULL; /* Encrypted presentation */
537: int len;
538: char *username;
539: char *password;
540: char *realmname;
541: HTAARealm *realm;
542: char *inet_addr = "0.0.0.0"; /* Change... @@@@ */
543: char *timestamp = "42"; /* ... these @@@@ */
544:
545:
546: FREE(result); /* From previous call */
547:
2.2 luotonen 548: if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) || !setup ||
2.4 luotonen 549: !setup->scheme_specifics || !setup->scheme_specifics[scheme] ||
550: !setup->server || !setup->server->realms)
2.5 luotonen 551: return NULL;
2.1 luotonen 552:
2.2 luotonen 553: realmname = HTAssocList_lookup(setup->scheme_specifics[scheme], "realm");
2.5 luotonen 554: if (!realmname) return NULL;
2.1 luotonen 555:
2.4 luotonen 556: realm = HTAARealm_lookup(setup->server->realms, realmname);
2.1 luotonen 557: if (!realm || setup->retry) {
2.2 luotonen 558: char msg[100];
559:
2.1 luotonen 560: if (!realm) {
561: if (TRACE) fprintf(stderr, "%s `%s' %s\n",
562: "compose_auth_string: realm:", realmname,
563: "not found -- creating");
2.4 luotonen 564: realm = HTAARealm_new(setup->server->realms, realmname, NULL,NULL);
565: sprintf(msg,
2.5 luotonen 566: "Document is protected. Enter username for %s at %s",
2.4 luotonen 567: realm->realmname,
568: setup->server->hostname ? setup->server->hostname : "??");
2.1 luotonen 569: }
570: else {
2.5 luotonen 571: sprintf(msg,"Enter username for %s at %s", realm->realmname,
2.4 luotonen 572: setup->server->hostname ? setup->server->hostname : "??");
2.1 luotonen 573: }
2.5 luotonen 574:
575: username = realm->username;
576: password = NULL;
577: HTPromptUsernameAndPassword(msg, &username, &password);
578:
579: FREE(realm->username);
2.1 luotonen 580: FREE(realm->password);
2.5 luotonen 581: realm->username = username;
2.1 luotonen 582: realm->password = password;
2.5 luotonen 583:
584: if (!realm->username)
585: return NULL; /* Suggested by marca; thanks! */
2.1 luotonen 586: }
587:
588: len = strlen(realm->username ? realm->username : "") +
589: strlen(realm->password ? realm->password : "") + 3;
590:
591: if (scheme == HTAA_PUBKEY) {
592: #ifdef PUBKEY
593: /* Generate new secret key */
594: StrAllocCopy(secret_key, HTAA_generateRandomKey());
595: #endif
596: /* Room for secret key, timestamp and inet address */
597: len += strlen(secret_key ? secret_key : "") + 30;
598: }
599: else
600: FREE(secret_key);
601:
2.5 luotonen 602: if (!(cleartext = (char*)calloc(len, 1)))
2.1 luotonen 603: outofmem(__FILE__, "compose_auth_string");
604:
605: if (realm->username) strcpy(cleartext, realm->username);
2.3 luotonen 606: else *cleartext = (char)0;
2.1 luotonen 607:
608: strcat(cleartext, ":");
609:
610: if (realm->password) strcat(cleartext, realm->password);
611:
612: if (scheme == HTAA_PUBKEY) {
613: strcat(cleartext, ":");
614: strcat(cleartext, inet_addr);
615: strcat(cleartext, ":");
616: strcat(cleartext, timestamp);
617: strcat(cleartext, ":");
618: if (secret_key) strcat(cleartext, secret_key);
619:
620: if (!((ciphertext = (char*)malloc(2*len)) &&
621: (result = (char*)malloc(3*len))))
622: outofmem(__FILE__, "compose_auth_string");
623: #ifdef PUBKEY
624: HTPK_encrypt(cleartext, ciphertext, server->public_key);
2.6 ! luotonen 625: HTUU_encode((unsigned char *)ciphertext, strlen(ciphertext), result);
2.1 luotonen 626: #endif
627: free(cleartext);
628: free(ciphertext);
629: }
630: else { /* scheme == HTAA_BASIC */
2.5 luotonen 631: if (!(result = (char*)malloc(4 * ((len+2)/3) + 1)))
2.1 luotonen 632: outofmem(__FILE__, "compose_auth_string");
2.6 ! luotonen 633: HTUU_encode((unsigned char *)cleartext, strlen(cleartext), result);
2.1 luotonen 634: free(cleartext);
635: }
636: return result;
637: }
638:
639:
640:
641: /* BROWSER PRIVATE HTAA_selectScheme()
642: ** SELECT THE AUTHENTICATION SCHEME TO USE
643: ** ON ENTRY:
644: ** setup is the server setup structure which can
645: ** be used to make the decision about the
646: ** used scheme.
647: **
648: ** When new authentication methods are added to library
649: ** this function makes the decision about which one to
650: ** use at a given time. This can be done by inspecting
651: ** environment variables etc.
652: **
2.2 luotonen 653: ** Currently only searches for the first valid scheme,
654: ** and if nothing found suggests Basic scheme;
655: **
2.1 luotonen 656: ** ON EXIT:
657: ** returns the authentication scheme to use.
658: */
659: PRIVATE HTAAScheme HTAA_selectScheme ARGS1(HTAASetup *, setup)
660: {
2.2 luotonen 661: HTAAScheme scheme;
662:
663: if (setup && setup->valid_schemes) {
664: for (scheme=HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++)
665: if (-1 < HTList_indexOf(setup->valid_schemes, (void*)scheme))
666: return scheme;
667: }
2.1 luotonen 668: return HTAA_BASIC;
669: }
670:
671:
672:
673:
674: /* BROWSER PUBLIC HTAA_composeAuth()
675: **
676: ** SELECT THE AUTHENTICATION SCHEME AND
677: ** COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE
678: ** IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
679: **
680: ** ON ENTRY:
681: ** hostname is the hostname of the server.
682: ** portnumber is the portnumber in which the server runs.
683: ** docname is the pathname of the document (as in URL)
684: **
685: ** ON EXIT:
686: ** returns NULL, if no authorization seems to be needed, or
687: ** if it is the entire Authorization: line, e.g.
688: **
689: ** "Authorization: Basic username:password"
690: **
691: ** As usual, this string is automatically freed.
692: */
693: PUBLIC char *HTAA_composeAuth ARGS3(CONST char *, hostname,
694: CONST int, portnumber,
695: CONST char *, docname)
696: {
697: static char *result = NULL;
698: char *auth_string;
699: BOOL retry;
700: HTAAScheme scheme;
701:
2.5 luotonen 702: /*
703: ** Make gateway httpds pass authorization field as it was received.
704: ** (This still doesn't really work because Authenticate: headers
705: ** from remote server are not forwarded to client yet so it cannot
706: ** really know that it should send authorization; I will not
707: ** implement it yet because I feel we will soon change radically
708: ** the way requests are represented to allow multithreading
709: ** on server-side. Life is hard.)
710: */
711: if (HTAAForwardAuth) {
712: if (TRACE) fprintf(stderr, "HTAA_composeAuth: %s\n",
713: "Forwarding received authorization");
714: StrAllocCopy(result, HTAAForwardAuth);
715: HTAAForwardAuth_reset(); /* Just a precaution */
716: return result;
717: }
718:
2.1 luotonen 719: FREE(result); /* From previous call */
720:
721: if (TRACE)
722: fprintf(stderr,
723: "Composing Authorization for %s:%d/%s\n",
724: hostname, portnumber, docname);
725:
726: if (current_portnumber != portnumber ||
727: !current_hostname || !current_docname ||
728: !hostname || !docname ||
729: 0 != strcmp(current_hostname, hostname) ||
730: 0 != strcmp(current_docname, docname)) {
731:
732: retry = NO;
733:
734: current_portnumber = portnumber;
735:
736: if (hostname) StrAllocCopy(current_hostname, hostname);
737: else FREE(current_hostname);
738:
739: if (docname) StrAllocCopy(current_docname, docname);
740: else FREE(current_docname);
741: }
742: else retry = YES;
743:
744: if (!current_setup || !retry)
745: current_setup = HTAASetup_lookup(hostname, portnumber, docname);
746:
747: if (!current_setup)
748: return NULL;
749:
750:
751: switch (scheme = HTAA_selectScheme(current_setup)) {
752: case HTAA_BASIC:
753: case HTAA_PUBKEY:
754: auth_string = compose_auth_string(scheme, current_setup);
755: break;
756: case HTAA_KERBEROS_V4:
757: /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
758: default:
759: {
760: char msg[100];
761: sprintf(msg, "%s %s `%s'",
762: "This client doesn't know how to compose authentication",
763: "information for scheme", HTAAScheme_name(scheme));
764: HTAlert(msg);
2.5 luotonen 765: auth_string = NULL;
2.1 luotonen 766: }
767: } /* switch scheme */
768:
769: current_setup->retry = NO;
770:
2.5 luotonen 771: /* Added by marca. */
772: if (!auth_string)
773: return NULL;
774:
2.1 luotonen 775: if (!(result = (char*)malloc(sizeof(char) * (strlen(auth_string)+40))))
776: outofmem(__FILE__, "HTAA_composeAuth");
777: strcpy(result, "Authorization: ");
778: strcat(result, HTAAScheme_name(scheme));
779: strcat(result, " ");
780: strcat(result, auth_string);
781: return result;
782: }
783:
784:
785:
2.5 luotonen 786:
2.1 luotonen 787: /* BROWSER PUBLIC HTAA_shouldRetryWithAuth()
788: **
789: ** DETERMINES IF WE SHOULD RETRY THE SERVER
790: ** WITH AUTHORIZATION
791: ** (OR IF ALREADY RETRIED, WITH A DIFFERENT
792: ** USERNAME AND/OR PASSWORD (IF MISSPELLED))
793: ** ON ENTRY:
794: ** start_of_headers is the first block already read from socket,
795: ** but status line skipped; i.e. points to the
796: ** start of the header section.
797: ** length is the remaining length of the first block.
798: ** soc is the socket to read the rest of server reply.
799: **
800: ** This function should only be called when
801: ** server has replied with a 401 (Unauthorized)
802: ** status code.
803: ** ON EXIT:
804: ** returns YES, if connection should be retried.
805: ** The node containing all the necessary
806: ** information is
807: ** * either constructed if it does not exist
808: ** * or password is reset to NULL to indicate
809: ** that username and password should be
810: ** reprompted when composing Authorization:
811: ** field (in function HTAA_composeAuth()).
812: ** NO, otherwise.
813: */
814: PUBLIC BOOL HTAA_shouldRetryWithAuth ARGS3(char *, start_of_headers,
815: int, length,
816: int, soc)
817: {
818: HTAAScheme scheme;
819: char *line;
820: int num_schemes = 0;
2.2 luotonen 821: HTList *valid_schemes = HTList_new();
822: HTAssocList **scheme_specifics = NULL;
2.1 luotonen 823: char *template = NULL;
824:
825:
826: /* Read server reply header lines */
827:
828: if (TRACE)
829: fprintf(stderr, "Server reply header lines:\n");
830:
831: HTAA_setupReader(start_of_headers, length, soc);
2.3 luotonen 832: while (NULL != (line = HTAA_getUnfoldedLine()) && *line != (char)0) {
2.1 luotonen 833:
834: if (TRACE) fprintf(stderr, "%s\n", line);
835:
836: if (strchr(line, ':')) { /* Valid header line */
837:
838: char *p = line;
839: char *fieldname = HTNextField(&p);
840: char *arg1 = HTNextField(&p);
841: char *args = p;
842:
843: if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
844: if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
2.2 luotonen 845: HTList_addObject(valid_schemes, (void*)scheme);
846: if (!scheme_specifics) {
847: int i;
848: scheme_specifics = (HTAssocList**)
849: malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
850: if (!scheme_specifics)
851: outofmem(__FILE__, "HTAA_shouldRetryWithAuth");
852: for (i=0; i < HTAA_MAX_SCHEMES; i++)
853: scheme_specifics[i] = NULL;
854: }
2.1 luotonen 855: scheme_specifics[scheme] = HTAA_parseArgList(args);
856: num_schemes++;
857: }
858: else if (TRACE) {
859: fprintf(stderr, "Unknown scheme `%s' %s\n",
860: (arg1 ? arg1 : "(null)"),
861: "in WWW-Authenticate: field");
862: }
863: }
864:
865: else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
866: if (TRACE)
867: fprintf(stderr, "Protection template set to `%s'\n", arg1);
868: StrAllocCopy(template, arg1);
869: }
870:
871: } /* if a valid header line */
872: else if (TRACE) {
873: fprintf(stderr, "Invalid header line `%s' ignored\n", line);
874: } /* else invalid header line */
875: } /* while header lines remain */
876:
877:
878: /* So should we retry with authorization */
879:
880: if (num_schemes == 0) { /* No authentication valid */
881: current_setup = NULL;
882: return NO;
883: }
884:
885: if (current_setup && current_setup->server) {
886: /* So we have already tried with authorization. */
887: /* Either we don't have access or username or */
888: /* password was misspelled. */
889:
890: /* Update scheme-specific parameters */
891: /* (in case they have expired by chance). */
892: HTAASetup_updateSpecifics(current_setup, scheme_specifics);
893:
894: if (NO == HTConfirm("Authorization failed. Retry?")) {
895: current_setup = NULL;
896: return NO;
897: } /* HTConfirm(...) == NO */
898: else { /* re-ask username+password (if misspelled) */
899: current_setup->retry = YES;
900: return YES;
901: } /* HTConfirm(...) == YES */
902: } /* if current_setup != NULL */
903:
904: else { /* current_setup == NULL, i.e. we have a */
905: /* first connection to a protected server or */
906: /* the server serves a wider set of documents */
907: /* than we expected so far. */
908:
909: HTAAServer *server = HTAAServer_lookup(current_hostname,
910: current_portnumber);
911: if (!server) {
912: server = HTAAServer_new(current_hostname,
913: current_portnumber);
914: }
915: if (!template)
916: template = HTAA_makeProtectionTemplate(current_docname);
917: current_setup = HTAASetup_new(server,
918: template,
919: valid_schemes,
920: scheme_specifics);
921:
922: HTAlert("Access without authorization denied -- retrying");
923: return YES;
924: } /* else current_setup == NULL */
925:
926: /* Never reached */
927: }
928:
Webmaster