home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / lynx-2.4 / WWW / Library / Implementation / HTAAServ.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-28  |  17.8 KB  |  680 lines

  1.  
  2. /* MODULE                            HTAAServ.c
  3. **        SERVER SIDE ACCESS AUTHORIZATION MODULE
  4. **
  5. **    Contains the means for checking the user access
  6. **    authorization for a file.
  7. **
  8. ** IMPORTANT:
  9. **    Routines in this module use dynamic allocation, but free
  10. **    automatically all the memory reserved by them.
  11. **
  12. **    Therefore the caller never has to (and never should)
  13. **    free() any object returned by these functions.
  14. **
  15. **    Therefore also all the strings returned by this package
  16. **    are only valid until the next call to the same function
  17. **    is made. This approach is selected, because of the nature
  18. **    of access authorization: no string returned by the package
  19. **    needs to be valid longer than until the next call.
  20. **
  21. **    This also makes it easy to plug the AA package in:
  22. **    you don't have to ponder whether to free() something
  23. **    here or is it done somewhere else (because it is always
  24. **    done somewhere else).
  25. **
  26. **    The strings that the package needs to store are copied
  27. **    so the original strings given as parameters to AA
  28. **    functions may be freed or modified with no side effects.
  29. **
  30. **    The AA package does not free() anything else than what
  31. **    it has itself allocated.
  32. **
  33. ** AUTHORS:
  34. **    AL    Ari Luotonen    luotonen@dxcern.cern.ch
  35. **
  36. ** HISTORY:
  37. **
  38. **
  39. ** BUGS:
  40. **
  41. **
  42. */
  43.  
  44. #include "HTUtils.h"
  45.  
  46. /*#include <stdio.h> included by HTUtils.h -- FM *//* FILE */
  47. #include <string.h>        /* strchr() */
  48.  
  49. #include "HTString.h"
  50. #include "HTAccess.h"        /* HTSecure            */
  51. #include "HTFile.h"        /* HTLocalName            */
  52. #include "HTRules.h"        /*                 */
  53. #include "HTParse.h"        /* URL parsing function        */
  54. #include "HTList.h"        /* HTList object        */
  55.  
  56. #include "HTAAUtil.h"        /* AA common parts        */
  57. #include "HTAuth.h"        /* Authentication        */
  58. #include "HTACL.h"        /* Access Control List        */
  59. #include "HTGroup.h"        /* Group handling        */
  60. #include "HTAAProt.h"        /* Protection file parsing    */
  61. #include "HTAAServ.h"        /* Implemented here        */
  62.  
  63. #include "LYLeaks.h"
  64.  
  65. /*
  66. ** Global variables
  67. */
  68. PUBLIC time_t theTime;
  69.  
  70.  
  71. /*
  72. ** Module-wide global variables
  73. */
  74. PRIVATE FILE *  htaa_logfile        = NULL;         /* Log file          */
  75. PRIVATE HTAAUser *htaa_user = NULL;            /* Authenticated user */
  76. PRIVATE HTAAFailReasonType HTAAFailReason = HTAA_OK;    /* AA fail reason     */
  77.  
  78.  
  79.  
  80. /* SERVER PUBLIC                    HTAA_statusMessage()
  81. **        RETURN A STRING EXPLAINING ACCESS
  82. **        AUTHORIZATION FAILURE
  83. **        (Can be used in server reply status line
  84. **         with 401/403 replies.)
  85. ** ON EXIT:
  86. **    returns    a string containing the error message
  87. **        corresponding to internal HTAAFailReason.
  88. */
  89. PUBLIC char *HTAA_statusMessage NOARGS
  90. {
  91.     switch (HTAAFailReason) {
  92.  
  93.     /* 401 cases */
  94.       case HTAA_NO_AUTH:
  95.     return "Unauthorized -- authentication failed";
  96.     break;
  97.       case HTAA_NOT_MEMBER:
  98.     return "Unauthorized to access the document";
  99.     break;
  100.  
  101.     /* 403 cases */
  102.       case HTAA_BY_RULE:
  103.     return "Forbidden -- by rule";
  104.     break;
  105.       case HTAA_IP_MASK:
  106.     return "Forbidden -- server refuses to serve to your IP address";
  107.     break;
  108.       case HTAA_NO_ACL:
  109.       case HTAA_NO_ENTRY:
  110.     return "Forbidden -- access to file is never allowed";
  111.     break;
  112.       case HTAA_SETUP_ERROR:
  113.     return "Forbidden -- server protection setup error";
  114.     break;
  115.       case HTAA_DOTDOT:
  116.     return "Forbidden -- URL containing /../ disallowed";
  117.     break;
  118.       case HTAA_HTBIN:
  119.     return "Forbidden -- /htbin feature not enabled on this server";
  120.     break;
  121.  
  122.     /* 404 cases */
  123.       case HTAA_NOT_FOUND:
  124.     return "Not found -- file doesn't exist or is read protected";
  125.     break;
  126.  
  127.     /* Success */
  128.       case HTAA_OK:
  129.     return "AA: Access should be ok but something went wrong"; 
  130.     break;
  131.  
  132.       case HTAA_OK_GATEWAY:
  133.     return "AA check bypassed (gatewaying) but something went wrong";
  134.     break;
  135.  
  136.     /* Others */
  137.       default:
  138.     return "Access denied -- unable to specify reason (bug)";
  139.  
  140.     } /* switch */
  141. }
  142.  
  143.  
  144.  
  145. PRIVATE char *status_name ARGS1(HTAAFailReasonType, reason)
  146. {
  147.     switch (HTAAFailReason) {
  148.  
  149.     /* 401 cases */
  150.       case HTAA_NO_AUTH:
  151.     return "NO-AUTHENTICATION";
  152.     break;
  153.       case HTAA_NOT_MEMBER:
  154.     return "NOT-AUTHORIZED";
  155.     break;
  156.  
  157.     /* 403 cases */
  158.       case HTAA_BY_RULE:
  159.     return "FORB-RULE";
  160.     break;
  161.       case HTAA_IP_MASK:
  162.     return "FORB-IP";
  163.     break;
  164.       case HTAA_NO_ACL:
  165.     return "NO-ACL-FILE";
  166.     break;
  167.       case HTAA_NO_ENTRY:
  168.     return "NO-ACL-ENTRY";
  169.     break;
  170.       case HTAA_SETUP_ERROR:
  171.     return "SETUP-ERROR";
  172.     break;
  173.       case HTAA_DOTDOT:
  174.     return "SLASH-DOT-DOT";
  175.     break;
  176.       case HTAA_HTBIN:
  177.     return "HTBIN-OFF";
  178.     break;
  179.  
  180.     /* 404 cases */
  181.       case HTAA_NOT_FOUND:
  182.     return "NOT-FOUND";
  183.     break;
  184.  
  185.     /* Success */
  186.       case HTAA_OK:
  187.     return "OK";
  188.     break;
  189.       case HTAA_OK_GATEWAY:
  190.     return "OK-GATEWAY";
  191.     break;
  192.  
  193.     /* Others */
  194.       default:
  195.     return "SERVER-BUG";
  196.     } /* switch */
  197. }
  198.  
  199.     
  200.  
  201.  
  202.  
  203.  
  204. /* PRIVATE                        check_uthorization()
  205. **        CHECK IF USER IS AUTHORIZED TO ACCESS A FILE
  206. ** ON ENTRY:
  207. **    pathname    is the physical file pathname
  208. **            to access.
  209. **    method        method, e.g. METHOD_GET, METHOD_PUT, ...
  210. **    scheme        authentication scheme.
  211. **    scheme_specifics authentication string (or other
  212. **            scheme specific parameters, like
  213. **            Kerberos-ticket).
  214. **
  215. ** ON EXIT:
  216. **    returns        HTAA_OK on success.
  217. **            Otherwise the reason for failing.
  218. ** NOTE:
  219. **    This function does not check whether the file
  220. **    exists or not -- so the status  404 Not found
  221. **    must be returned from somewhere else (this is
  222. **    to avoid unnecessary overhead of opening the
  223. **    file twice).
  224. */
  225. PRIVATE HTAAFailReasonType check_authorization ARGS4(CONST char *,  pathname,
  226.                              HTAAMethod,    method,
  227.                              HTAAScheme,    scheme,
  228.                              char *, scheme_specifics)
  229. {
  230.     HTAAFailReasonType reason;
  231.     GroupDef *allowed_groups;
  232.     FILE *acl_file = NULL;
  233.     HTAAProt *prot = NULL;    /* Protection mode */
  234.  
  235.     htaa_user = NULL;
  236.  
  237.     if (!pathname) {
  238.     if (TRACE) fprintf(stderr,
  239.                "HTAA_checkAuthorization: Forbidden by rule\n");
  240.     return HTAA_BY_RULE;
  241.     }
  242.     if (TRACE) fprintf(stderr, "%s `%s' %s %s\n",
  243.                "HTAA_checkAuthorization: translated path:",
  244.                pathname, "method:", HTAAMethod_name(method));
  245.  
  246.     /*
  247.     ** Get protection setting (set up by callbacks from rule system)
  248.     ** NULL, if not protected by a "protect" rule.
  249.     */
  250.     prot = HTAA_getCurrentProtection();
  251.  
  252.     /*
  253.     ** Check ACL existence
  254.     */
  255.     if (!(acl_file = HTAA_openAcl(pathname))) {
  256.     if (prot) { /* protect rule, but no ACL */
  257.         if (prot->mask_group) {
  258.         /*
  259.         ** Only mask enabled, check that
  260.         */
  261.         GroupDefList *group_def_list =
  262.             HTAA_readGroupFile(HTAssocList_lookup(prot->values,
  263.                               "group"));
  264.         /*
  265.         ** Authenticate if authentication info given
  266.         */
  267.         if (scheme != HTAA_UNKNOWN  &&  scheme != HTAA_NONE) {
  268.             htaa_user = HTAA_authenticate(scheme,
  269.                           scheme_specifics,
  270.                           prot);
  271.             if (TRACE) fprintf(stderr, "Authentication returned: %s\n",
  272.                        (htaa_user ? htaa_user->username
  273.                               : "NOT-AUTHENTICATED"));
  274.         }
  275.         HTAA_resolveGroupReferences(prot->mask_group, group_def_list);
  276.         reason = HTAA_userAndInetInGroup(prot->mask_group,
  277.                          htaa_user
  278.                           ? htaa_user->username : "",
  279.                          HTClientHost,
  280.                          NULL);
  281.         if (TRACE) {
  282.             if (reason != HTAA_OK)
  283.             fprintf(stderr, "%s %s %s %s\n",
  284.                 "HTAA_checkAuthorization: access denied",
  285.                 "by mask (no ACL, only Protect rule)",
  286.                 "host", HTClientHost);
  287.             else fprintf(stderr, "%s %s %s %s\n",
  288.                  "HTAA_checkAuthorization: request from",
  289.                  HTClientHost, 
  290.                  "accepted by only mask match (no ACL, only",
  291.                  "Protect rule, and only mask enabled)");
  292.         }
  293.         return reason;
  294.         }
  295.         else {    /* 403 Forbidden */
  296.         if (TRACE) fprintf(stderr, "%s %s\n",
  297.                    "HTAA_checkAuthorization: Protected, but",
  298.                    "no mask group nor ACL -- forbidden");
  299.         return HTAA_NO_ACL;
  300.         }
  301.     }
  302.     else { /* No protect rule and no ACL => OK 200 */
  303.         if (TRACE) fprintf(stderr, "HTAA_checkAuthorization: %s\n",
  304.                    "no protect rule nor ACL -- ok\n");
  305.         return HTAA_OK;
  306.     }
  307.     }
  308.  
  309.     /*
  310.     ** Now we know that ACL exists
  311.     */
  312.     if (!prot) {        /* Not protected by "protect" rule */
  313.     if (TRACE) fprintf(stderr,
  314.                "HTAA_checkAuthorization: default protection\n");
  315.     prot = HTAA_getDefaultProtection();   /* Also sets current protection */
  316.  
  317.     if (!prot) {        /* @@ Default protection not set ?? */
  318.         if (TRACE) fprintf(stderr, "%s %s\n",
  319.                    "HTAA_checkAuthorization: default protection",
  320.                    "not set (internal server error)!!");
  321.         return HTAA_SETUP_ERROR;
  322.     }
  323.     }
  324.  
  325.     /*
  326.     ** Now we know that document is protected and ACL exists.
  327.     ** Check against ACL entry.
  328.     */
  329.     {
  330.     GroupDefList *group_def_list =
  331.         HTAA_readGroupFile(HTAssocList_lookup(prot->values, "group"));
  332.  
  333.     /*
  334.     ** Authenticate now that we know protection mode
  335.     */
  336.     if (scheme != HTAA_UNKNOWN  &&  scheme != HTAA_NONE) {
  337.         htaa_user = HTAA_authenticate(scheme,
  338.                       scheme_specifics,
  339.                       prot);
  340.         if (TRACE) fprintf(stderr, "Authentication returned: %s\n",
  341.                    (htaa_user
  342.                 ? htaa_user->username : "NOT-AUTHENTICATED"));
  343.     }
  344.     /* 
  345.     ** Check mask group
  346.     */
  347.     if (prot->mask_group) {
  348.         HTAA_resolveGroupReferences(prot->mask_group, group_def_list);
  349.         reason=HTAA_userAndInetInGroup(prot->mask_group,
  350.                        htaa_user ? htaa_user->username : "",
  351.                        HTClientHost,
  352.                        NULL);
  353.         if (reason != HTAA_OK) {
  354.         if (TRACE) fprintf(stderr, "%s %s %s\n",
  355.                    "HTAA_checkAuthorization: access denied",
  356.                    "by mask, host:", HTClientHost);
  357.         return reason;
  358.         }
  359.         else {
  360.         if (TRACE) fprintf(stderr, "%s %s %s %s %s\n",
  361.                    "HTAA_checkAuthorization: request from",
  362.                    HTClientHost, 
  363.                    "accepted by just mask group match",
  364.                    "(no ACL, only Protect rule, and only",
  365.                    "mask enabled)");
  366.         /* And continue authorization checking */
  367.         }
  368.     }
  369.     /*
  370.         ** Get ACL entries; get first one first, the loop others
  371.     ** Remember, allowed_groups is automatically freed by
  372.     ** HTAA_getAclEntry().
  373.     */
  374.     allowed_groups = HTAA_getAclEntry(acl_file, pathname, method);
  375.     if (!allowed_groups) {
  376.         if (TRACE) fprintf(stderr, "%s `%s' %s\n",
  377.                    "No entry for file", pathname, "in ACL");
  378.         HTAA_closeAcl(acl_file);
  379.         return HTAA_NO_ENTRY;    /* Forbidden -- no entry in the ACL */
  380.     }
  381.     else {
  382.         do {
  383.         HTAA_resolveGroupReferences(allowed_groups, group_def_list);
  384.         reason = HTAA_userAndInetInGroup(allowed_groups,
  385.                          htaa_user
  386.                          ? htaa_user->username : "",
  387.                          HTClientHost,
  388.                          NULL);
  389.         if (reason == HTAA_OK) {
  390.             HTAA_closeAcl(acl_file);
  391.             return HTAA_OK;    /* OK */
  392.         }
  393.         allowed_groups = HTAA_getAclEntry(acl_file, pathname, method);
  394.         } while (allowed_groups);
  395.         HTAA_closeAcl(acl_file);
  396.         return HTAA_NOT_MEMBER;    /* Unauthorized */
  397.     }
  398.     }
  399. }
  400.  
  401.  
  402.  
  403. /* PUBLIC                          HTAA_checkAuthorization()
  404. **        CHECK IF USER IS AUTHORIZED TO ACCESS A FILE
  405. ** ON ENTRY:
  406. **    url        is the document to be accessed.
  407. **    method_name    name of the method, e.g. "GET"
  408. **    scheme_name    authentication scheme name.
  409. **    scheme_specifics authentication string (or other
  410. **            scheme specific parameters, like
  411. **            Kerberos-ticket).
  412. **
  413. ** ON EXIT:
  414. **    returns    status codes uniform with those of HTTP:
  415. **      200 OK       if file access is ok.
  416. **      401 Unauthorized if user is not authorized to
  417. **               access the file.
  418. **      403 Forbidden       if there is no entry for the
  419. **               requested file in the ACL.
  420. **
  421. ** NOTE:
  422. **    This function does not check whether the file
  423. **    exists or not -- so the status  404 Not found
  424. **    must be returned from somewhere else (this is
  425. **    to avoid unnecessary overhead of opening the
  426. **    file twice).
  427. **
  428. */
  429. PUBLIC int HTAA_checkAuthorization ARGS4(CONST char *,    url,
  430.                      CONST char *,    method_name,
  431.                      CONST char *,    scheme_name,
  432.                                          char *,    scheme_specifics)
  433. {
  434.     static char *pathname = NULL;
  435.     char *local_copy = NULL;
  436.     HTAAMethod method = HTAAMethod_enum(method_name);
  437.     HTAAScheme scheme = HTAAScheme_enum(scheme_name);
  438.  
  439.     HTAAFailReason = HTAA_OK;
  440.  
  441.     /*
  442.     ** Translate into absolute pathname, and
  443.     ** check for "protect" and "defprot" rules.
  444.     */
  445.     FREE(pathname);        /* From previous call    */
  446.     StrAllocCopy(local_copy, url);
  447.     {
  448.     char *keywords = strchr(local_copy, '?');
  449.     if (keywords) *keywords = (char)0;    /* Chop off keywords */
  450.     }
  451.     HTSimplify(local_copy);    /* Remove ".." etc. */
  452.  
  453.     /* HTSimplify will leave in a "/../" at the top, which can
  454.     ** be a security hole.
  455.     */
  456.     if (strstr(local_copy, "/../")) {
  457.     if (TRACE) fprintf(stderr, "HTAA_checkAuthorization: %s (`%s')\n",
  458.                "Illegal attempt to use /../", url);
  459.     HTAAFailReason = HTAA_DOTDOT;
  460.     }
  461.     else {
  462.     pathname = HTTranslate(local_copy); /* Translate rules even if */
  463.                                         /* a /htbin call to set up */
  464.                                         /* protections.           */
  465.     if (0 == strncmp(local_copy, "/htbin/", 7)) {
  466.         if (!HTBinDir)
  467.         HTAAFailReason = HTAA_HTBIN;
  468.         else {
  469.         char *end = strchr(local_copy+7, '/');
  470.         if (end)
  471.             *end = (char)0;
  472.         FREE(pathname);
  473.         pathname=(char*)malloc(strlen(HTBinDir)+strlen(local_copy)+1);
  474.         strcpy(pathname, HTBinDir);
  475.         strcat(pathname, local_copy+6);
  476.         }
  477.     }
  478.  
  479.     if (!pathname) {        /* Forbidden by rule */
  480.         if (TRACE) fprintf(stderr,
  481.                    "HTAA_checkAuthorization: Forbidden by rule\n");
  482.         HTAAFailReason = HTAA_BY_RULE;
  483.     }
  484.     else if (HTAAFailReason != HTAA_HTBIN) {
  485.         /* pathname != NULL */
  486.         char *access = HTParse(pathname, "", PARSE_ACCESS);
  487.         if (!*access || 0 == strcmp(access,"file")) { /*Local file, do AA*/
  488.         if (!HTSecure && 0 != strncmp(local_copy, "/htbin/", 7)) {
  489.             char *localname = HTLocalName(pathname);
  490.             free(pathname);
  491.             pathname = localname;
  492.         }
  493.         HTAAFailReason = check_authorization(pathname, method,
  494.                              scheme, scheme_specifics);
  495.         }
  496.         else {  /* Not local access */
  497.         HTAAFailReason = HTAA_OK_GATEWAY;
  498.         fprintf(stderr, "HTAA_checkAuthorization: %s (%s access)\n",
  499.             "Gatewaying -- skipping authorization check",
  500.             access);
  501.         }
  502.     } /* pathname */
  503.     }
  504.     FREE(local_copy);
  505.  
  506.     if (htaa_logfile) {
  507.     time(&theTime);
  508.     fprintf(htaa_logfile, "%24.24s %s %s %s %s %s\n",
  509.         ctime(&theTime),
  510.         HTClientHost ? HTClientHost : "local",
  511.         method_name,
  512.         url,
  513.         status_name(HTAAFailReason),
  514.         htaa_user && htaa_user->username
  515.         ? htaa_user->username : "");
  516.     fflush(htaa_logfile);    /* Actually update it on disk */
  517.     if (TRACE) fprintf(stderr, "Log: %24.24s %s %s %s %s %s\n",
  518.                ctime(&theTime),
  519.                HTClientHost ? HTClientHost : "local",
  520.                method_name,
  521.                url,
  522.                status_name(HTAAFailReason),
  523.                htaa_user && htaa_user->username
  524.                ? htaa_user->username : "");
  525.     }
  526.  
  527.     switch (HTAAFailReason) {
  528.  
  529.       case HTAA_NO_AUTH:
  530.       case HTAA_NOT_MEMBER:
  531.     return 401;
  532.     break;
  533.  
  534.       case HTAA_BY_RULE:
  535.       case HTAA_IP_MASK:
  536.       case HTAA_NO_ACL:
  537.       case HTAA_NO_ENTRY:
  538.       case HTAA_SETUP_ERROR:
  539.       case HTAA_DOTDOT:
  540.       case HTAA_HTBIN:
  541.     return 403;
  542.     break;
  543.  
  544.       case HTAA_NOT_FOUND:
  545.     return 404;
  546.     break;
  547.  
  548.       case HTAA_OK:
  549.       case HTAA_OK_GATEWAY:
  550.     return 200;
  551.     break;
  552.  
  553.       default:
  554.     return 500;
  555.     } /* switch */
  556. }
  557.  
  558.  
  559.  
  560.  
  561.  
  562. /* PRIVATE                    compose_scheme_specifics()
  563. **        COMPOSE SCHEME-SPECIFIC PARAMETERS
  564. **        TO BE SENT ALONG WITH SERVER REPLY
  565. **        IN THE WWW-Authenticate: FIELD.
  566. ** ON ENTRY:
  567. **    scheme        is the authentication scheme for which
  568. **            parameters are asked for.
  569. **    prot        protection setup structure.
  570. **
  571. ** ON EXIT:
  572. **    returns        scheme specific parameters in an
  573. **            auto-freed string.
  574. */
  575. PRIVATE char *compose_scheme_specifics ARGS2(HTAAScheme,    scheme,
  576.                          HTAAProt *,    prot)
  577. {
  578.     static char *result = NULL;
  579.  
  580.     FREE(result);    /* From previous call */
  581.  
  582.     switch (scheme) {
  583.       case HTAA_BASIC:
  584.     {
  585.         char *realm = HTAssocList_lookup(prot->values, "server");
  586.         result = (char*)malloc(60);
  587.         sprintf(result, "realm=\"%s\"",
  588.             (realm ? realm : "UNKNOWN"));
  589.         return result;
  590.     }
  591.     break;
  592.  
  593.       case HTAA_PUBKEY:
  594.     {
  595.         char *realm = HTAssocList_lookup(prot->values, "server");
  596.         result = (char*)malloc(200);
  597.         sprintf(result, "realm=\"%s\", key=\"%s\"",
  598.             (realm ? realm : "UNKNOWN"),
  599.             "PUBKEY-NOT-IMPLEMENTED");
  600.         return result;
  601.     }
  602.     break;
  603.       default:
  604.     return NULL;
  605.     }
  606. }
  607.  
  608.  
  609. /* SERVER PUBLIC                    HTAA_composeAuthHeaders()
  610. **        COMPOSE WWW-Authenticate: HEADER LINES
  611. **        INDICATING VALID AUTHENTICATION SCHEMES
  612. **        FOR THE REQUESTED DOCUMENT
  613. ** ON ENTRY:
  614. **    No parameters, but HTAA_checkAuthorization() must
  615. **    just before have failed because a wrong (or none)
  616. **    authentication scheme was used.
  617. **
  618. ** ON EXIT:
  619. **    returns    a buffer containing all the WWW-Authenticate:
  620. **        fields including CRLFs (this buffer is auto-freed).
  621. **        NULL, if authentication won't help in accessing
  622. **        the requested document.
  623. **
  624. */
  625. PUBLIC char *HTAA_composeAuthHeaders NOARGS
  626. {
  627.     static char *result = NULL;
  628.     HTAAScheme scheme;
  629.     char *scheme_name;
  630.     char *scheme_params;
  631.     HTAAProt *prot = HTAA_getCurrentProtection();
  632.  
  633.     if (!prot) {
  634.     if (TRACE) fprintf(stderr, "%s %s\n",
  635.                "HTAA_composeAuthHeaders: Document not protected",
  636.                "-- why was this function called??");
  637.     return NULL;
  638.     }
  639.     else if (TRACE) fprintf(stderr, "HTAA_composeAuthHeaders: for file `%s'\n",
  640.                 prot->filename);
  641.  
  642.     FREE(result);    /* From previous call */
  643.     if (!(result = (char*)malloc(4096)))    /* @@ */
  644.     outofmem(__FILE__, "HTAA_composeAuthHeaders");
  645.     *result = (char)0;
  646.  
  647.     for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
  648.     if (-1 < HTList_indexOf(prot->valid_schemes, (void*)scheme)) {
  649.         if ((scheme_name = HTAAScheme_name(scheme))) {
  650.         scheme_params = compose_scheme_specifics(scheme,prot);
  651.         strcat(result, "WWW-Authenticate: ");
  652.         strcat(result, scheme_name);
  653.         if (scheme_params) {
  654.             strcat(result, " ");
  655.             strcat(result, scheme_params);
  656.         }
  657.         strcat(result, "\r\n");
  658.         } /* scheme name found */
  659.         else if (TRACE) fprintf(stderr, "HTAA_composeAuthHeaders: %s %d\n",
  660.                     "No name found for scheme number", scheme);
  661.     } /* scheme valid for requested document */
  662.     } /* for every scheme */
  663.     
  664.     return result;
  665. }
  666.  
  667.  
  668.  
  669. /* PUBLIC                        HTAA_startLogging()
  670. **        START UP ACCESS AUTHORIZATION LOGGING
  671. ** ON ENTRY:
  672. **    fp    is the open log file.
  673. **
  674. */
  675. PUBLIC void HTAA_startLogging ARGS1(FILE *, fp)
  676. {
  677.     htaa_logfile = fp;
  678. }
  679.  
  680.