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