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