HTAABrow.c
上传用户:zlh9724
上传日期:2007-01-04
资源大小:1991k
文件大小:23k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /*       HTAABrow.c
  2. ** BROWSER SIDE ACCESS AUTHORIZATION MODULE
  3. **
  4. ** (c) COPYRIGHT MIT 1995.
  5. ** Please first read the full copyright statement in the file COPYRIGH.
  6. **
  7. ** Containts the code for keeping track on server hostnames,
  8. ** port numbers, scheme names, usernames, passwords
  9. ** (and servers' public keys).
  10. **
  11. ** IMPORTANT:
  12. ** Routines in this module use dynamic allocation, but free
  13. ** automatically all the memory reserved by them.
  14. **
  15. ** Therefore the caller never has to (and never should)
  16. ** free() any object returned by these functions.
  17. **
  18. ** Therefore also all the strings returned by this package
  19. ** are only valid until the next call to the same function
  20. ** is made. This approach is selected, because of the nature
  21. ** of access authorization: no string returned by the package
  22. ** needs to be valid longer than until the next call.
  23. **
  24. ** This also makes it easy to plug the AA package in:
  25. ** you don't have to ponder whether to free() something
  26. ** here or is it done somewhere else (because it is always
  27. ** done somewhere else).
  28. **
  29. ** The strings that the package needs to store are copied
  30. ** so the original strings given as parameters to AA
  31. ** functions may be freed or modified with no side effects.
  32. **
  33. ** The AA package does not free() anything else than what
  34. ** it has itself allocated.
  35. **
  36. ** AUTHORS:
  37. ** AL Ari Luotonen luotonen@dxcern.cern.ch
  38. **
  39. ** HISTORY:
  40. ** Oct 17 AL Made corrections suggested by marca:
  41. ** Added  if (!realm->username) return NULL;
  42. ** Changed some ""s to NULLs.
  43. ** Now doing calloc() to init uuencode source;
  44. ** otherwise HTUU_encode() reads uninitialized memory
  45. ** every now and then (not a real bug but not pretty).
  46. ** Corrected the formula for uuencode destination size.
  47. ** BUGS:
  48. **
  49. **
  50. */
  51. /* Library include files */
  52. #include "WWWLib.h"
  53. #include "HTReqMan.h" /* @@@@ */
  54. #include "HTAAUtil.h"
  55. #include "HTAABrow.h"  /* Implemented here */
  56. PRIVATE HTList *server_table = NULL; /* Browser's info about servers      */
  57. /**************************** HTAAServer ***********************************/
  58. /* PRIVATE HTAAServer_new()
  59. ** ALLOCATE A NEW NODE TO HOLD SERVER INFO
  60. ** AND ADD IT TO THE LIST OF SERVERS
  61. ** ON ENTRY:
  62. ** hostname is the name of the host that the server
  63. ** is running in.
  64. ** portnumber is the portnumber which the server listens.
  65. **
  66. ** ON EXIT:
  67. ** returns the newly-allocated node with all the strings
  68. ** duplicated.
  69. ** Strings will be automatically freed by
  70. ** the function HTAAServer_delete(), which also
  71. ** frees the node itself.
  72. */
  73. PRIVATE HTAAServer *HTAAServer_new (CONST char * hostname, int portnumber)
  74. {
  75.     HTAAServer *server;
  76.     if ((server = (HTAAServer *) HT_MALLOC(sizeof(HTAAServer))) == NULL)
  77.         HT_OUTOFMEM("HTAAServer_new");
  78.     server->hostname = NULL;
  79.     server->portnumber = (portnumber > 0 ? portnumber : 80);
  80.     server->setups = HTList_new();
  81.     server->realms = HTList_new();
  82.     if (hostname) StrAllocCopy(server->hostname, hostname);
  83.     if (!server_table) server_table = HTList_new();
  84.     
  85.     HTList_addObject(server_table, (void*)server);
  86.     return server;
  87. }
  88. /* PRIVATE HTAAServer_lookup()
  89. ** LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
  90. ** ON ENTRY:
  91. ** hostname obvious.
  92. ** portnumber if non-positive defaults to 80.
  93. **
  94. ** Looks up the server in the module-global server_table.
  95. **
  96. ** ON EXIT:
  97. ** returns pointer to a HTAAServer structure
  98. ** representing the looked-up server.
  99. ** NULL, if not found.
  100. */
  101. PRIVATE HTAAServer *HTAAServer_lookup (CONST char * hostname, int portnumber)
  102. {
  103.     if (hostname) {
  104. HTList *cur = server_table;
  105. HTAAServer *server;
  106. if (portnumber <= 0) portnumber = 80;
  107. while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
  108.     if (server->portnumber == portnumber  &&
  109. 0==strcmp(server->hostname, hostname))
  110. return server;
  111. }
  112.     }
  113.     return NULL; /* NULL parameter, or not found */
  114. }
  115. /*************************** HTAASetup *******************************/    
  116. /* PRIVATE HTAASetup_lookup()
  117. ** FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
  118. ** IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
  119. **
  120. ** ON ENTRY:
  121. ** hostname is the name of the server host machine.
  122. ** portnumber is the port that the server is running in.
  123. ** docname is the (URL-)pathname of the document we
  124. ** are trying to access.
  125. **
  126. **  This function goes through the information known about
  127. ** all the setups of the server, and finds out if the given
  128. ** filename resides in one of the protected directories.
  129. **
  130. ** ON EXIT:
  131. ** returns NULL if no match.
  132. ** Otherwise, a HTAASetup structure representing
  133. ** the protected server setup on the corresponding
  134. ** document tree.
  135. **
  136. */
  137. PRIVATE HTAASetup *HTAASetup_lookup (CONST char * hostname,
  138.      int   portnumber,
  139.      CONST char * docname)
  140. {
  141.     HTAAServer *server;
  142.     HTAASetup *setup;
  143.     if (portnumber <= 0) portnumber = 80;
  144.     if (hostname && docname && *hostname && *docname &&
  145. NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
  146. HTList *cur = server->setups;
  147. if (PROT_TRACE)
  148.     TTYPrint(TDEST, "Access Auth. resolving setup for (%s:%d:%s)n",
  149.     hostname, portnumber, docname);
  150. while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
  151.     if (HTAA_templateMatch(setup->tmplate, docname)) {
  152. if (PROT_TRACE)
  153.     TTYPrint(TDEST, "Access Auth. `%s' matched template `%s'n",
  154.     docname, setup->tmplate);
  155. return setup;
  156.     }
  157.     else if (PROT_TRACE)
  158. TTYPrint(TDEST,"%s `%s' %s `%s'n","HTAASetup_lookup:", docname,
  159. "did NOT match template", setup->tmplate);
  160. } /* while setups remain */
  161.     } /* if valid parameters and server found */
  162.     if (PROT_TRACE)
  163. TTYPrint(TDEST, "Access Auth. `%s' (so probably not protected)n",
  164. (docname ? docname : "(null)"));
  165.     return NULL;  /* NULL in parameters, or not found */
  166. }
  167. /* PRIVATE HTAASetup_new()
  168. ** CREATE A NEW SETUP NODE
  169. ** ON ENTRY:
  170. ** server is a pointer to a HTAAServer structure
  171. ** to which this setup belongs.
  172. ** template documents matching this template
  173. ** are protected according to this setup.
  174. ** valid_schemes a list containing all valid authentication
  175. ** schemes for this setup.
  176. ** If NULL, all schemes are disallowed.
  177. ** scheme_specifics is an array of assoc lists, which
  178. ** contain scheme specific parameters given
  179. ** by server in Authenticate: fields.
  180. ** If NULL, all scheme specifics are
  181. ** set to NULL.
  182. ** ON EXIT:
  183. ** returns a new HTAASetup node, and also adds it as
  184. ** part of the HTAAServer given as parameter.
  185. */
  186. PRIVATE HTAASetup *HTAASetup_new (HTAAServer * server,
  187.   char * tmplate,
  188.   HTList * valid_schemes,
  189.   HTAssocList **scheme_specifics)
  190. {
  191.     HTAASetup *setup;
  192.     if (!server || !tmplate || !*tmplate) return NULL;
  193.     if ((setup = (HTAASetup *) HT_MALLOC(sizeof(HTAASetup))) == NULL)
  194.         HT_OUTOFMEM("HTAASetup_new");
  195.     setup->reprompt = NO;
  196.     setup->server = server;
  197.     setup->tmplate = NULL;
  198.     if (tmplate) StrAllocCopy(setup->tmplate, tmplate);
  199.     setup->valid_schemes = valid_schemes;
  200.     setup->scheme_specifics = scheme_specifics;
  201.     HTList_addObject(server->setups, (void*)setup);
  202.     return setup;
  203. }
  204. /* PRIVATE HTAASetup_delete()
  205. ** FREE A HTAASetup STRUCTURE
  206. ** ON ENTRY:
  207. ** killme is a pointer to the structure to free;
  208. **
  209. ** ON EXIT:
  210. ** returns nothing.
  211. */
  212. #ifdef NOT_NEEDED_IT_SEEMS
  213. PRIVATE void HTAASetup_delete (HTAASetup * killme)
  214. {
  215.     int scheme;
  216.     if (killme) {
  217. if (killme->tmplate) HT_FREE(killme->tmplate);
  218. if (killme->valid_schemes)
  219.     HTList_delete(killme->valid_schemes);
  220. for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++)
  221.     if (killme->scheme_specifics[scheme])
  222. HTAssocList_delete(killme->scheme_specifics[scheme]);
  223. HT_FREE(killme);
  224.     }
  225. }
  226. #endif /*NOT_NEEDED_IT_SEEMS*/
  227. /* PRIVATE HTAASetup_updateSpecifics()
  228. * COPY SCHEME SPECIFIC PARAMETERS
  229. ** TO HTAASetup STRUCTURE
  230. ** ON ENTRY:
  231. ** setup destination setup structure.
  232. ** specifics string array containing scheme
  233. ** specific parameters for each scheme.
  234. ** If NULL, all the scheme specific
  235. ** parameters are set to NULL.
  236. **
  237. ** ON EXIT:
  238. ** returns nothing.
  239. */
  240. PRIVATE void HTAASetup_updateSpecifics (HTAASetup * setup,
  241. HTAssocList ** specifics)
  242. {
  243.     int scheme;
  244.     if (setup) {
  245. if (setup->scheme_specifics) {
  246.     for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
  247. if (setup->scheme_specifics[scheme])
  248.     HTAssocList_delete(setup->scheme_specifics[scheme]);
  249.     }
  250.     HT_FREE(setup->scheme_specifics);
  251. }
  252. setup->scheme_specifics = specifics;
  253.     }
  254. }
  255. /*************************** HTAARealm **********************************/
  256. /* PRIVATE  HTAARealm_lookup()
  257. ** LOOKUP HTAARealm STRUCTURE BY REALM NAME
  258. ** ON ENTRY:
  259. ** realm_table a list of realm objects.
  260. ** realmname is the name of realm to look for.
  261. **
  262. ** ON EXIT:
  263. ** returns the realm.  NULL, if not found.
  264. */
  265. PRIVATE HTAARealm *HTAARealm_lookup (HTList * realm_table,
  266.      CONST char * realmname)
  267. {
  268.     if (realm_table && realmname) {
  269. HTList *cur = realm_table;
  270. HTAARealm *realm;
  271. while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
  272.     if (0==strcmp(realm->realmname, realmname))
  273. return realm;
  274. }
  275.     }
  276.     return NULL; /* No table, NULL param, or not found */
  277. }
  278. /* PRIVATE HTAARealm_new()
  279. ** CREATE A NODE CONTAINING USERNAME AND
  280. ** PASSWORD USED FOR THE GIVEN REALM.
  281. ** IF REALM ALREADY EXISTS, CHANGE
  282. ** USERNAME/PASSWORD.
  283. ** ON ENTRY:
  284. ** realm_table a list of realms to where to add
  285. ** the new one, too.
  286. ** realmname is the name of the password domain.
  287. ** username and
  288. ** password are what you can expect them to be.
  289. **
  290. ** ON EXIT:
  291. ** returns the created realm.
  292. */
  293. PRIVATE HTAARealm *HTAARealm_new (HTList * realm_table,
  294.   CONST char * realmname,
  295.   CONST char * username,
  296.   CONST char * password)
  297. {
  298.     HTAARealm *realm;
  299.     realm = HTAARealm_lookup(realm_table, realmname);
  300.     if (!realm) {
  301. if ((realm = (HTAARealm *) HT_MALLOC(sizeof(HTAARealm))) == NULL)
  302.     HT_OUTOFMEM("HTAARealm_new");
  303. realm->realmname = NULL;
  304. realm->username = NULL;
  305. realm->password = NULL;
  306. StrAllocCopy(realm->realmname, realmname);
  307. if (realm_table) HTList_addObject(realm_table, (void*)realm);
  308.     }
  309.     if (username) StrAllocCopy(realm->username, username);
  310.     if (password) StrAllocCopy(realm->password, password);
  311.     return realm;
  312. }
  313. /***************** Basic and Pubkey Authentication ************************/
  314. /* PRIVATE compose_Basic_auth()
  315. **
  316. ** COMPOSE Basic SCHEME AUTHENTICATION STRING
  317. **
  318. ** ON ENTRY:
  319. ** req request, where
  320. ** req->scheme == HTAA_BASIC
  321. ** req->realm contains username and password.
  322. **
  323. ** ON EXIT:
  324. ** returns a newly composed authorization string,
  325. ** NULL, if something fails.
  326. ** NOTE:
  327. ** Like throughout the entire AA package, no string or structure
  328. ** returned by AA package needs to (or should) be freed.
  329. **
  330. */
  331. PRIVATE char *compose_Basic_auth (HTRequest * req)
  332. {
  333.     static char *result = NULL; /* Uuencoded presentation, the result */
  334.     char *cleartext = NULL; /* Cleartext presentation */
  335.     int len;
  336.     HT_FREE(result); /* from previous call */
  337.     if (!req || req->scheme != HTAA_BASIC || !req->setup ||
  338. !req->setup->server)
  339. return NULL;
  340.     if (!req->realm) {
  341. char *realmname;
  342. if (!req->setup || !req->setup->scheme_specifics ||
  343.     !(realmname =
  344.       HTAssocList_lookup(req->setup->scheme_specifics[HTAA_BASIC],
  345.  "realm")))
  346.     return NULL;
  347. req->realm = HTAARealm_lookup(req->setup->server->realms, realmname);
  348. if (!req->realm) {
  349.     req->realm = HTAARealm_new(req->setup->server->realms,
  350.        realmname, NULL, NULL);
  351.     return NULL;
  352. }
  353.     }
  354.     len = strlen(req->realm->username ? req->realm->username : "") +
  355.   strlen(req->realm->password ? req->realm->password : "") + 3;
  356.     if ((cleartext = (char *) HT_CALLOC(len, 1)) == NULL)
  357.         HT_OUTOFMEM("compose_Basic_auth");
  358.     if (req->realm->username) strcpy(cleartext, req->realm->username);
  359.     else *cleartext = (char)0;
  360.     strcat(cleartext, ":");
  361.     if (req->realm->password) strcat(cleartext, req->realm->password);
  362.     if ((result = (char *) HT_MALLOC(4 * ((len+2)/3) + 1)) == NULL)
  363.         HT_OUTOFMEM("compose_Basic_auth");
  364.     HTUU_encode((unsigned char *)cleartext, strlen(cleartext), result);
  365.     HT_FREE(cleartext);
  366.     return result;
  367. }
  368. /* BROWSER PRIVATE HTAA_selectScheme()
  369. ** SELECT THE AUTHENTICATION SCHEME TO USE
  370. ** ON ENTRY:
  371. ** setup is the server setup structure which can
  372. ** be used to make the decision about the
  373. ** used scheme.
  374. **
  375. ** When new authentication methods are added to library
  376. ** this function makes the decision about which one to
  377. ** use at a given time.  This can be done by inspecting
  378. ** environment variables etc.
  379. **
  380. ** Currently only searches for the first valid scheme,
  381. ** and if nothing found suggests Basic scheme;
  382. **
  383. ** ON EXIT:
  384. ** returns the authentication scheme to use.
  385. */
  386. PRIVATE HTAAScheme HTAA_selectScheme (HTAASetup * setup)
  387. {
  388.     HTAAScheme scheme;
  389.     if (setup && setup->valid_schemes) {
  390. for (scheme = HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++)
  391.     if (-1 < HTList_indexOf(setup->valid_schemes, (void *) scheme))
  392. return (HTAAScheme) scheme;
  393.     }
  394.     return HTAA_NONE;
  395. }
  396. /* BROWSER PUBLIC HTAA_composeAuth()
  397. **
  398. ** COMPOSE Authorization: HEADER LINE CONTENTS
  399. ** IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
  400. **
  401. ** ON ENTRY:
  402. ** req request, which contains
  403. ** req->setup protection setup info on browser.
  404. ** req->scheme selected authentication scheme.
  405. ** req->realm for Basic scheme the username and password.
  406. **
  407. ** ON EXIT:
  408. ** returns NO, if no authorization seems to be needed, and
  409. ** req->authorization is NULL.
  410. ** YES, if it has composed Authorization field,
  411. ** in which case the result is in req->authorization,
  412. ** e.g.
  413. **
  414. **    "Basic AkRDIhEF8sdEgs72F73bfaS=="
  415. */
  416. PUBLIC BOOL HTAA_composeAuth (HTRequest * req)
  417. {
  418.     char *auth_string = NULL;
  419.     static char *docname;
  420.     static char *hostname;
  421.     int portnumber;
  422.     char *colon;
  423.     char *gate = NULL; /* Obsolite? */
  424.     char *arg = NULL;
  425.     HT_FREE(hostname); /* From previous call */
  426.     HT_FREE(docname); /* - " -       */
  427.     if (!req  ||  !req->anchor)
  428. return NO;
  429.     arg = HTAnchor_physical(req->anchor);
  430.     docname = HTParse(arg, "", PARSE_PATH);
  431.     hostname = HTParse((gate ? gate : arg), "", PARSE_HOST);
  432.     if (hostname &&
  433. NULL != (colon = strchr(hostname, ':'))) {
  434. *(colon++) = ''; /* Chop off port number */
  435. portnumber = atoi(colon);
  436.     }
  437.     else portnumber = 80;
  438.     if (PROT_TRACE)
  439. TTYPrint(TDEST, "Access Auth. composing authorization for %s:%d/%sn",
  440. hostname, portnumber, docname);
  441. #ifdef OLD_CODE
  442.     if (current_portnumber != portnumber ||
  443. !current_hostname || !current_docname ||
  444. !hostname         || !docname         ||
  445. 0 != strcmp(current_hostname, hostname) ||
  446. 0 != strcmp(current_docname, docname)) {
  447. retry = NO;
  448. current_portnumber = portnumber;
  449. if (hostname) StrAllocCopy(current_hostname, hostname);
  450. else HT_FREE(current_hostname);
  451. if (docname) StrAllocCopy(current_docname, docname);
  452. else HT_FREE(current_docname);
  453.     }
  454.     else retry = YES;
  455. #endif /*OLD_CODE*/
  456.     if (!req->setup)
  457. req->setup = HTAASetup_lookup(hostname, portnumber, docname);
  458.     if (!req->setup)
  459. return NO;
  460.     if (req->scheme == HTAA_NONE || req->scheme == HTAA_UNKNOWN)
  461. req->scheme = HTAA_selectScheme(req->setup);
  462.     switch (req->scheme) {
  463.       case HTAA_BASIC:
  464. auth_string = compose_Basic_auth(req);
  465. break;
  466.       case HTAA_PUBKEY:
  467.       case HTAA_KERBEROS_V4:
  468. /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
  469.       default:
  470. {
  471.     char msg[100];
  472.     sprintf(msg, "%s %s `%s'",
  473.     "This client doesn't know how to compose authentication",
  474.     "information for scheme", HTAAScheme_name(req->scheme));
  475.     HTRequest_addError(req, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
  476.        msg, 0, "HTLoadHTTP");
  477.     auth_string = NULL;
  478. }
  479.     } /* switch scheme */
  480.     req->setup->reprompt = NO;
  481.     /* Added by marca. */
  482.     if (!auth_string)
  483. return NO;
  484.     
  485.     HT_FREE(req->authorization); /* Free from previous call, Henrik 14/03-94 */
  486.     if ((req->authorization = (char *) HT_MALLOC(sizeof(char) * (strlen(auth_string)+40))) == NULL)
  487.         HT_OUTOFMEM("HTAA_composeAuth");
  488.     strcpy(req->authorization, HTAAScheme_name(req->scheme));
  489.     strcat(req->authorization, " ");
  490.     strcat(req->authorization, auth_string);
  491.     return YES;
  492. }
  493. /* BROWSER OVERLOADED HTPasswordDialog()
  494. **
  495. ** PROMPT USERNAME AND PASSWORD, AND MAKE A
  496. ** CALLBACK TO FUNCTION HTLoadHTTP().
  497. **
  498. ** This function must be redifined by GUI clients, which
  499. ** call HTLoadHTTP(req) when user presses "Ok".
  500. **
  501. ** ON ENTRY:
  502. ** req request.
  503. ** req->dialog_msg prompting message.
  504. ** req->setup information about protections of this request.
  505. ** req->realm structure describing one password realm.
  506. ** This function should only be called when
  507. ** server has replied with a 401 (Unauthorized)
  508. ** status code, and req structure has been filled
  509. ** up according to server reply, especially the
  510. ** req->valid_shemes list must have been set up
  511. ** according to WWW-Authenticate: headers.
  512. ** ON EXIT:
  513. **
  514. ** returns YES or NO
  515. **
  516. */
  517. PUBLIC BOOL HTPasswordDialog (HTRequest * req)
  518. {
  519.     HTAlertCallback *cbf = HTAlert_find(HT_A_USER_PW);
  520.     if (!req || !req->setup || !req->realm || !req->dialog_msg) {
  521. if (PROT_TRACE)
  522.     TTYPrint(TDEST, "Access...... called with an illegal parameter");
  523. return NO;
  524.     }
  525.     if (cbf) {
  526. HTAlertPar * reply = HTAlert_newReply();
  527. HT_FREE(req->realm->username);
  528. HT_FREE(req->realm->password);
  529. if (((*cbf)(req, HT_A_USER_PW, HT_MSG_NULL, NULL,
  530.     req->realm->realmname, reply))) {
  531.     req->realm->username = HTAlert_replyMessage(reply);
  532.     req->realm->password = HTAlert_replySecret(reply);
  533. }
  534. HTAlert_deleteReply(reply);
  535. /* Suggested by marca; thanks! */
  536. return req->realm->username ? YES : NO;
  537.     }
  538.     return NO;
  539. }
  540. /* BROWSER PUBLIC HTAA_retryWithAuth()
  541. **
  542. ** RETRY THE SERVER WITH AUTHORIZATION (OR IF
  543. ** ALREADY RETRIED, WITH A DIFFERENT USERNAME
  544. ** AND/OR PASSWORD (IF MISSPELLED)) OR CANCEL
  545. ** ON ENTRY:
  546. ** req request.
  547. ** req->valid_schemes
  548. ** This function should only be called when
  549. ** server has replied with a 401 (Unauthorized)
  550. ** status code, and req structure has been filled
  551. ** up according to server reply, especially the
  552. ** req->valid_shemes list must have been set up
  553. ** according to WWW-Authenticate: headers.
  554. ** ON EXIT:
  555. ** On GUI clients pops up a username/password dialog box
  556. ** with "Ok" and "Cancel".
  557. ** "Ok" button press should do a callback
  558. **
  559. ** HTLoadHTTP(req);
  560. **
  561. ** This actually done by function HTPasswordDialog(),
  562. ** which GUI clients redefine.
  563. **
  564. ** returns YES, if dialog box was popped up.
  565. ** NO, on failure.
  566. */
  567. PUBLIC BOOL HTAA_retryWithAuth (HTRequest * req)
  568. {
  569.     int len;
  570.     char *realmname;
  571.     char *arg = NULL;
  572.     if (!req || !req->anchor ||
  573. !req->valid_schemes || HTList_count(req->valid_schemes) == 0) {
  574. req->setup = NULL;
  575. return NO;
  576.     }
  577.     arg = HTAnchor_physical(req->anchor);
  578.     if (req->setup && req->setup->server) {
  579. /* So we have already tried with authorization. */
  580. /* Either we don't have access or username or */
  581. /* password was misspelled. */
  582.     
  583. /* Update scheme-specific parameters */
  584. /* (in case they have expired by chance). */
  585. HTAASetup_updateSpecifics(req->setup, req->scheme_specifics);
  586. req->scheme = HTAA_selectScheme(req->setup);
  587. req->setup->reprompt = YES;
  588.     }
  589.     else { /* current_setup == NULL, i.e. we have a  */
  590.    /* first connection to a protected server or  */
  591.    /* the server serves a wider set of documents */
  592.    /* than we expected so far.                   */
  593. static char *hostname;
  594. static char *docname;
  595. int portnumber;
  596. char *colon;
  597. HTAAServer *server;
  598. HT_FREE(hostname); /* From previous call */
  599. HT_FREE(docname); /* - " -       */
  600. docname = HTParse(arg, "", PARSE_PATH);
  601. hostname = HTParse(arg, "", PARSE_HOST);
  602. if (hostname &&
  603.     NULL != (colon = strchr(hostname, ':'))) {
  604.     *(colon++) = ''; /* Chop off port number */
  605.     portnumber = atoi(colon);
  606. }
  607. else portnumber = 80;
  608. if (PROT_TRACE)
  609.     TTYPrint(TDEST, "HTAA_retryWithAuth: first retry of %s:%d/%sn",
  610.     hostname, portnumber, docname);
  611. if (!(server = HTAAServer_lookup(hostname, portnumber))) {
  612.     server = HTAAServer_new(hostname, portnumber);
  613. }
  614. #if 0
  615. else 
  616.     HTAlert(req, "Access without authorization denied -- retrying");
  617. }
  618. #endif
  619. if (!req->prot_template)
  620.     req->prot_template = HTAA_makeProtectionTemplate(docname);
  621. req->setup = HTAASetup_new(server, 
  622.    req->prot_template,
  623.    req->valid_schemes,
  624.    req->scheme_specifics);
  625. req->setup->reprompt = NO;
  626. req->scheme = HTAA_selectScheme(req->setup);
  627.     } /* else current_setup == NULL */
  628.     realmname = HTAssocList_lookup(req->setup->scheme_specifics[req->scheme],
  629.    "realm");
  630.     if (!realmname)
  631. return NO;
  632.     req->realm = HTAARealm_lookup(req->setup->server->realms, realmname);
  633.     if (!req->realm)
  634. req->realm = HTAARealm_new(req->setup->server->realms,
  635.    realmname, NULL, NULL);
  636.     len = strlen(realmname) + 100;
  637.     if (req->setup->server->hostname)
  638. len += strlen(req->setup->server->hostname);
  639.     HT_FREE(req->dialog_msg);  /* Free from previous call, Henrik 14/03-94 */
  640.     if ((req->dialog_msg = (char *) HT_MALLOC(len)) == NULL)
  641.         HT_OUTOFMEM("HTAA_retryWithAuth");
  642.     if (!req->realm->username)
  643. sprintf(req->dialog_msg, "n%s %s at %s",
  644. "Document is protected. Enter username for",
  645. req->realm->realmname,
  646. req->setup->server->hostname
  647. ? req->setup->server->hostname : "??");
  648.     else sprintf(req->dialog_msg, "n%s %s at %s",
  649.  "Authorization failed. Enter username for",
  650.  req->realm->realmname,
  651.  req->setup->server->hostname
  652.  ? req->setup->server->hostname : "??");
  653.     return (HTPasswordDialog(req));
  654. }
  655. /*
  656. ** Setup HTTP access authentication
  657. */
  658. PUBLIC BOOL HTAA_authentication (HTRequest * request)
  659. {
  660.     HTAAScheme scheme;
  661.     HTList *valid_schemes = HTList_new();
  662.     HTAssocList **scheme_specifics = NULL;
  663.     char *tmplate = NULL;
  664.     if (request->WWWAAScheme) {
  665. if ((scheme = HTAAScheme_enum(request->WWWAAScheme)) != HTAA_UNKNOWN) {
  666.     HTList_addObject(valid_schemes, (void *) scheme);
  667.     if (!scheme_specifics) {
  668. int i;
  669. scheme_specifics = (HTAssocList**) HT_MALLOC(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
  670. if (!scheme_specifics)
  671.     outofmem(__FILE__, "HTTPAuthentication");
  672. for (i=0; i < HTAA_MAX_SCHEMES; i++)
  673.     scheme_specifics[i] = NULL;
  674.     }
  675.     scheme_specifics[scheme] = HTAA_parseArgList(request->WWWAARealm);
  676. } else if (PROT_TRACE) {
  677.     HTRequest_addError(request, ERR_INFO, NO, HTERR_UNKNOWN_AA,
  678.        (void *) request->WWWAAScheme, 0, "HTTPAuthentication");
  679.     return NO;
  680. }
  681.     }
  682.     if (request->WWWprotection) {
  683. if (PROT_TRACE)
  684.     TTYPrint(TDEST, "Protection template set to `%s'n",
  685.     request->WWWprotection);
  686. StrAllocCopy(tmplate, request->WWWprotection);
  687.     }
  688.     request->valid_schemes = valid_schemes;
  689.     request->scheme_specifics = scheme_specifics;
  690.     request->prot_template = tmplate;
  691.     return YES;
  692. }