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