1 $NetBSD: patch-ad,v 1.1 2000/01/15 17:44:21 hubertf Exp $
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
9 +** SERVER SIDE ACCESS AUTHORIZATION MODULE
11 +** Contains the means for checking the user access
12 +** authorization for a file.
15 +** Routines in this module use dynamic allocation, but free
16 +** automatically all the memory reserved by them.
18 +** Therefore the caller never has to (and never should)
19 +** free() any object returned by these functions.
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.
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).
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.
36 +** The AA package does not free() anything else than what
37 +** it has itself allocated.
40 +** AL Ari Luotonen luotonen@dxcern.cern.ch
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 */
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 */
71 +PUBLIC time_t theTime;
75 +** Module-wide global variables
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 */
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.)
88 +** returns a string containing the error message
89 +** corresponding to internal HTAAFailReason.
91 +PUBLIC char *HTAA_statusMessage NOARGS
93 + switch (HTAAFailReason) {
97 + return "Unauthorized -- authentication failed";
98 + case HTAA_NOT_MEMBER:
99 + return "Unauthorized to access the document";
103 + return "Forbidden -- by rule";
105 + return "Forbidden -- server refuses to serve to your IP address";
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";
112 + return "Forbidden -- URL containing /../ disallowed";
114 + return "Forbidden -- /htbin feature not enabled on this server";
117 + case HTAA_NOT_FOUND:
118 + return "Not found -- file doesn't exist or is read protected";
122 + return "AA: Access should be ok but something went wrong";
124 + case HTAA_OK_GATEWAY:
125 + return "AA check bypassed (gatewaying) but something went wrong";
129 + return "Access denied -- unable to specify reason (bug)";
135 +PRIVATE char *status_name ARGS1(HTAAFailReasonType, reason)
141 + return "NO-AUTHENTICATION";
142 + case HTAA_NOT_MEMBER:
143 + return "NOT-AUTHORIZED";
147 + return "FORB-RULE";
151 + return "NO-ACL-FILE";
152 + case HTAA_NO_ENTRY:
153 + return "NO-ACL-ENTRY";
154 + case HTAA_SETUP_ERROR:
155 + return "SETUP-ERROR";
157 + return "SLASH-DOT-DOT";
159 + return "HTBIN-OFF";
162 + case HTAA_NOT_FOUND:
163 + return "NOT-FOUND";
168 + case HTAA_OK_GATEWAY:
169 + return "OK-GATEWAY";
173 + return "SERVER-BUG";
178 +/* PRIVATE check_uthorization()
179 +** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE
181 +** pathname is the physical file pathname
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).
190 +** returns HTAA_OK on success.
191 +** Otherwise the reason for failing.
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
199 +PRIVATE HTAAFailReasonType check_authorization ARGS4(CONST char *, pathname,
200 + HTAAMethod, method,
201 + HTAAScheme, scheme,
202 + char *, scheme_specifics)
204 + HTAAFailReasonType reason;
205 + GroupDef *allowed_groups;
206 + FILE *acl_file = NULL;
207 + HTAAProt *prot = NULL; /* Protection mode */
212 + CTRACE(tfp, "HTAA_checkAuthorization: Forbidden by rule\n");
213 + return HTAA_BY_RULE;
215 + CTRACE(tfp, "%s `%s' %s %s\n",
216 + "HTAA_checkAuthorization: translated path:",
217 + pathname, "method:", HTAAMethod_name(method));
220 + ** Get protection setting (set up by callbacks from rule system)
221 + ** NULL, if not protected by a "protect" rule.
223 + prot = HTAA_getCurrentProtection();
226 + ** Check ACL existence
228 + if (!(acl_file = HTAA_openAcl(pathname))) {
229 + if (prot) { /* protect rule, but no ACL */
230 + if (prot->mask_group) {
232 + ** Only mask enabled, check that
234 + GroupDefList *group_def_list =
235 + HTAA_readGroupFile(HTAssocList_lookup(prot->values,
238 + ** Authenticate if authentication info given
240 + if (scheme != HTAA_UNKNOWN && scheme != HTAA_NONE) {
241 + htaa_user = HTAA_authenticate(scheme,
244 + CTRACE(tfp, "Authentication returned: %s\n",
245 + (htaa_user ? htaa_user->username
246 + : "NOT-AUTHENTICATED"));
248 + HTAA_resolveGroupReferences(prot->mask_group, group_def_list);
249 + reason = HTAA_userAndInetInGroup(prot->mask_group,
251 + ? htaa_user->username : "",
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);
260 + CTRACE(tfp, "%s %s %s %s\n",
261 + "HTAA_checkAuthorization: request from",
263 + "accepted by only mask match (no ACL, only",
264 + "Protect rule, and only mask enabled)");
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;
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");
283 + ** Now we know that ACL exists
285 + if (!prot) { /* Not protected by "protect" rule */
286 + CTRACE(tfp, "HTAA_checkAuthorization: default protection\n");
287 + prot = HTAA_getDefaultProtection(); /* Also sets current protection */
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;
298 + ** Now we know that document is protected and ACL exists.
299 + ** Check against ACL entry.
302 + GroupDefList *group_def_list =
303 + HTAA_readGroupFile(HTAssocList_lookup(prot->values, "group"));
306 + ** Authenticate now that we know protection mode
308 + if (scheme != HTAA_UNKNOWN && scheme != HTAA_NONE) {
309 + htaa_user = HTAA_authenticate(scheme,
312 + CTRACE(tfp, "Authentication returned: %s\n",
314 + ? htaa_user->username : "NOT-AUTHENTICATED"));
317 + ** Check mask group
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 : "",
325 + if (reason != HTAA_OK) {
326 + CTRACE(tfp, "%s %s %s\n",
327 + "HTAA_checkAuthorization: access denied",
328 + "by mask, host:", HTClientHost);
332 + CTRACE(tfp, "%s %s %s %s %s\n",
333 + "HTAA_checkAuthorization: request from",
335 + "accepted by just mask group match",
336 + "(no ACL, only Protect rule, and only",
338 + /* And continue authorization checking */
342 + ** Get ACL entries; get first one first, the loop others
343 + ** Remember, allowed_groups is automatically freed by
344 + ** HTAA_getAclEntry().
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 */
355 + HTAA_resolveGroupReferences(allowed_groups, group_def_list);
356 + reason = HTAA_userAndInetInGroup(allowed_groups,
358 + ? htaa_user->username : "",
361 + if (reason == HTAA_OK) {
362 + HTAA_closeAcl(acl_file);
363 + return HTAA_OK; /* OK */
365 + allowed_groups = HTAA_getAclEntry(acl_file, pathname, method);
366 + } while (allowed_groups);
367 + HTAA_closeAcl(acl_file);
368 + return HTAA_NOT_MEMBER; /* Unauthorized */
374 +/* PUBLIC HTAA_checkAuthorization()
375 +** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE
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).
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
389 +** 403 Forbidden if there is no entry for the
390 +** requested file in the ACL.
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
400 +PUBLIC int HTAA_checkAuthorization ARGS4(CONST char *, url,
401 + CONST char *, method_name,
402 + CONST char *, scheme_name,
403 + char *, scheme_specifics)
405 + static char *pathname = NULL;
406 + char *local_copy = NULL;
407 + HTAAMethod method = HTAAMethod_enum(method_name);
408 + HTAAScheme scheme = HTAAScheme_enum(scheme_name);
410 + HTAAFailReason = HTAA_OK;
413 + ** Translate into absolute pathname, and
414 + ** check for "protect" and "defprot" rules.
416 + FREE(pathname); /* From previous call */
417 + StrAllocCopy(local_copy, url);
419 + char *keywords = strchr(local_copy, '?');
421 + *keywords = '\0'; /* Chop off keywords */
423 + HTSimplify(local_copy); /* Remove ".." etc. */
425 + /* HTSimplify will leave in a "/../" at the top, which can
426 + ** be a security hole.
428 + if (strstr(local_copy, "/../")) {
429 + CTRACE(tfp, "HTAA_checkAuthorization: %s (`%s')\n",
430 + "Illegal attempt to use /../", url);
431 + HTAAFailReason = HTAA_DOTDOT;
434 + pathname = HTTranslate(local_copy); /* Translate rules even if */
435 + /* a /htbin call to set up */
437 + if (0 == strncmp(local_copy, "/htbin/", 7)) {
439 + HTAAFailReason = HTAA_HTBIN;
441 + char *end = strchr(local_copy+7, '/');
445 + pathname=(char*)malloc(strlen(HTBinDir)+strlen(local_copy)+1);
446 + strcpy(pathname, HTBinDir);
447 + strcat(pathname, local_copy+6);
451 + if (!pathname) { /* Forbidden by rule */
452 + CTRACE(tfp, "HTAA_checkAuthorization: Forbidden by rule\n");
453 + HTAAFailReason = HTAA_BY_RULE;
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);
462 + pathname = localname;
464 + HTAAFailReason = check_authorization(pathname, method,
465 + scheme, scheme_specifics);
467 + else { /* Not local access */
468 + HTAAFailReason = HTAA_OK_GATEWAY;
469 + CTRACE(tfp, "HTAA_checkAuthorization: %s (%s access)\n",
470 + "Gatewaying -- skipping authorization check",
477 + if (htaa_logfile) {
479 + fprintf(htaa_logfile, "%24.24s %s %s %s %s %s\n",
481 + HTClientHost ? HTClientHost : "local",
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",
490 + HTClientHost ? HTClientHost : "local",
493 + status_name(HTAAFailReason),
494 + htaa_user && htaa_user->username
495 + ? htaa_user->username : "");
498 + switch (HTAAFailReason) {
501 + case HTAA_NOT_MEMBER:
507 + case HTAA_NO_ENTRY:
508 + case HTAA_SETUP_ERROR:
513 + case HTAA_NOT_FOUND:
517 + case HTAA_OK_GATEWAY:
526 +/* PRIVATE compose_scheme_specifics()
527 +** COMPOSE SCHEME-SPECIFIC PARAMETERS
528 +** TO BE SENT ALONG WITH SERVER REPLY
529 +** IN THE WWW-Authenticate: FIELD.
531 +** scheme is the authentication scheme for which
532 +** parameters are asked for.
533 +** prot protection setup structure.
536 +** returns scheme specific parameters in an
537 +** auto-freed string.
539 +PRIVATE char *compose_scheme_specifics ARGS2(HTAAScheme, scheme,
542 + static char *result = NULL;
544 + FREE(result); /* From previous call */
549 + char *realm = HTAssocList_lookup(prot->values, "server");
550 + result = (char*)malloc(60);
551 + sprintf(result, "realm=\"%s\"",
552 + (realm ? realm : "UNKNOWN"));
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");
571 +/* SERVER PUBLIC HTAA_composeAuthHeaders()
572 +** COMPOSE WWW-Authenticate: HEADER LINES
573 +** INDICATING VALID AUTHENTICATION SCHEMES
574 +** FOR THE REQUESTED DOCUMENT
576 +** No parameters, but HTAA_checkAuthorization() must
577 +** just before have failed because a wrong (or none)
578 +** authentication scheme was used.
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.
587 +PUBLIC char *HTAA_composeAuthHeaders NOARGS
589 + static char *result = NULL;
592 + char *scheme_params;
593 + HTAAProt *prot = HTAA_getCurrentProtection();
596 + CTRACE(tfp, "%s %s\n",
597 + "HTAA_composeAuthHeaders: Document not protected",
598 + "-- why was this function called??");
601 + CTRACE(tfp, "HTAA_composeAuthHeaders: for file `%s'\n",
605 + FREE(result); /* From previous call */
606 + if (!(result = (char*)malloc(4096))) /* @@ */
607 + outofmem(__FILE__, "HTAA_composeAuthHeaders");
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);
621 + strcat(result, "\r\n");
622 + } /* scheme name found */
624 + CTRACE(tfp, "HTAA_composeAuthHeaders: %s %d\n",
625 + "No name found for scheme number", scheme);
627 + } /* scheme valid for requested document */
628 + } /* for every scheme */
634 +/* PUBLIC HTAA_startLogging()
635 +** START UP ACCESS AUTHORIZATION LOGGING
637 +** fp is the open log file.
640 +PUBLIC void HTAA_startLogging ARGS1(FILE *, fp)