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