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