This is http_access.c in view mode; [Download] [Up]
/************************************************************************ * NCSA HTTPd Server * Software Development Group * National Center for Supercomputing Applications * University of Illinois at Urbana-Champaign * 605 E. Springfield, Champaign, IL 61820 * httpd@ncsa.uiuc.edu * * Copyright (C) 1995, Board of Trustees of the University of Illinois * ************************************************************************ * * http_access.c,v 1.67 1995/11/03 21:56:54 blong Exp * ************************************************************************ * * http_access: Security options etc. * * Based on NCSA HTTPd 1.3 by Rob McCool * * 03-12-95 blong * Added patch to fix ALLOW_THEN_DENY * * 10-02-95 blong * Added patch by Maurizio Codogno (mau@beatles.cselt.stet.it) to * allow or deny hosts using a LOCAL keyword which matches all hosts * without a dot in their name */ #include "config.h" #include "portability.h" #include <stdio.h> #ifndef NO_STDLIB_H # include <stdlib.h> #endif /* NO_STDLIB_H */ #include <string.h> #include <sys/stat.h> #include <ctype.h> #include <errno.h> #include "constants.h" #include "http_access.h" #include "http_request.h" #include "http_config.h" #include "http_auth.h" #include "http_mime.h" #include "http_log.h" #include "util.h" #ifdef DIGEST_AUTH int client_accepts_digest; int assume_digest_support; #endif /* DIGEST_AUTH */ /* * Modified this bad boy so he wouldn't * match things like "allow csa.ncsa.uiuc.edu" and * a ncsa.uiuc.edu. SSG 7/10/95 */ int in_domain(char *domain, char *what) { int dl=strlen(domain); int wl=strlen(what); if(((wl-dl) >= 0) && !strcmp(domain,&what[wl-dl])) { if (((wl - dl) > 0) && (*domain != '.') && (what[wl-dl-1] != '.')) return 0; /* only a partial match - SSG */ return 1; } else { return 0; } } int in_ip(char *domain, char *what) { return(!strncmp(domain,what,strlen(domain))); } /* find_allow() * Hunts down list of allowed hosts and returns 1 if allowed, 0 if not * As soon as it finds an allow that matches, it returns 1 */ int find_allow(per_request *reqInfo, int x) { register int y; /* If no allows are specified, then allow */ if(sec[x].num_allow[reqInfo->method] == 0) return FA_ALLOW; for(y=0;y<sec[x].num_allow[reqInfo->method];y++) { if(!strcmp("all",sec[x].allow[reqInfo->method][y])) return FA_ALLOW; #ifdef LOCALHACK if((!strcmp("LOCAL",sec[x].allow[reqInfo->method][y])) && reqInfo->remote_host && (ind(reqInfo->remote_host,'.') == -1)) { reqInfo->bSatisfiedDomain = TRUE; return FA_ALLOW; } #endif /* LOCALHACK */ if(in_ip(sec[x].allow[reqInfo->method][y],reqInfo->remote_ip)) { reqInfo->bSatisfiedDomain = TRUE; return FA_ALLOW; } /* If we haven't done a lookup, and the DNS type is Minimum, then * we do a lookup now */ if (!reqInfo->dns_host_lookup && (reqInfo->hostInfo->dns_mode == DNS_MIN)) get_remote_host_min(reqInfo); if(reqInfo->remote_host) { if(in_domain(sec[x].allow[reqInfo->method][y],reqInfo->remote_host)) { reqInfo->bSatisfiedDomain = TRUE; return FA_ALLOW; } } } /* Default is to deny */ return FA_DENY; } /* find_deny() * Hunts down list of denied hosts and returns 0 if denied, 1 if not * As soon as it finds a deny that matches, it returns 0 */ int find_deny(per_request *reqInfo, int x) { register int y; /* If there aren't any denies, then it is allowed */ if(sec[x].num_deny[reqInfo->method] == 0) return FA_ALLOW; for(y=0;y<sec[x].num_deny[reqInfo->method];y++) { if(!strcmp("all",sec[x].deny[reqInfo->method][y])) { reqInfo->bSatisfiedDomain = FALSE; return FA_DENY; } #ifdef LOCALHACK if((!strcmp("LOCAL",sec[x].allow[reqInfo->method][y])) && reqInfo->remote_host && (ind(reqInfo->remote_host,'.') == -1)) { reqInfo->bSatisfiedDomain = FALSE; return FA_DENY; } #endif /* LOCALHACK */ if(in_ip(sec[x].deny[reqInfo->method][y],reqInfo->remote_ip)) { reqInfo->bSatisfiedDomain = FALSE; return FA_DENY; } if (!reqInfo->dns_host_lookup && (reqInfo->hostInfo->dns_mode == DNS_MIN)) get_remote_host_min(reqInfo); if(reqInfo->remote_host) { if(in_domain(sec[x].deny[reqInfo->method][y],reqInfo->remote_host)) { reqInfo->bSatisfiedDomain = FALSE; return FA_DENY; } } } /* Default is to allow */ reqInfo->bSatisfiedDomain = TRUE; return FA_ALLOW; } void check_dir_access(per_request *reqInfo,int x, int *allow, int *allow_options) { if(sec[x].auth_name[0]) reqInfo->auth_name = sec[x].auth_name; if(sec[x].auth_pwfile[0]) { reqInfo->auth_pwfile = sec[x].auth_pwfile; reqInfo->auth_pwfile_type = sec[x].auth_pwfile_type; } if(sec[x].auth_grpfile[0]) { reqInfo->auth_grpfile = sec[x].auth_grpfile; reqInfo->auth_grpfile_type = sec[x].auth_grpfile_type; } #ifdef DIGEST_AUTH if(sec[x].auth_digestfile[0]) { reqInfo->auth_digestfile = sec[x].auth_digestfile; reqInfo->auth_digestfile_type = sec[x].auth_digestfile_type; } #endif /* DIGEST_AUTH */ if (sec[x].auth_type[0]) strcpy(reqInfo->auth_type,sec[x].auth_type); *allow=0; if(sec[x].order[reqInfo->method] == ALLOW_THEN_DENY) { *allow = find_allow(reqInfo,x); *allow = find_deny(reqInfo,x); } else if(sec[x].order[reqInfo->method] == DENY_THEN_ALLOW) { *allow = find_deny(reqInfo,x); *allow = find_allow(reqInfo,x); } else *allow = find_allow(reqInfo,x) && !find_deny(reqInfo,x); if(sec[x].num_auth[reqInfo->method]) *allow_options=x; } void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, char *allow_options) { int will_allow, need_auth, num_dirs; char opts[MAX_STRING_LEN], override[MAX_STRING_LEN]; char path[MAX_STRING_LEN], d[MAX_STRING_LEN]; char errstr[MAX_STRING_LEN]; register int x,y,z,n; if(S_ISDIR(finfo->st_mode)) strncpy_dir(path,reqInfo->filename,MAX_STRING_LEN); else lim_strcpy(path,reqInfo->filename,MAX_STRING_LEN); no2slash(path); num_dirs = count_dirs(path); will_allow = 1; need_auth = -1; user[0] = '\0'; groupname[0] = '\0'; reset_mime_vars(); for(x=0;x<num_dirs;x++) { opts[x] = OPT_ALL; override[x] = OR_ALL; } /* assume not domain restricted */ reqInfo->bSatisfiedDomain = 0; n=num_dirs-1; for(x=0;x<num_sec;x++) { if(is_matchexp(sec[x].d)) { if(!strcmp_match(path,sec[x].d)) { for(y=0;y<num_dirs;y++) { if(!(sec[x].opts & OPT_UNSET)) opts[y] = sec[x].opts; override[y] = sec[x].override; } } check_dir_access(reqInfo,x,&will_allow,&need_auth); } else if(!strncmp(path,sec[x].d,strlen(sec[x].d))) { for(y=count_dirs(sec[x].d) - 1;y<num_dirs;y++) { if(!(sec[x].opts & OPT_UNSET)) opts[y] = sec[x].opts; override[y] = sec[x].override; } check_dir_access(reqInfo,x,&will_allow,&need_auth); } } if((override[n]) || (!(opts[n] & OPT_SYM_LINKS)) || (opts[n] & OPT_SYM_OWNER)) { for(x=0;x<num_dirs;x++) { y = num_sec; make_dirstr(path,x+1,d); if((!(opts[x] & OPT_SYM_LINKS)) || (opts[x] & OPT_SYM_OWNER)) { struct stat lfi,fi; if(lstat(d,&lfi) != 0) { sprintf(errstr,"httpd: can't lstat %s, errno = %d",d, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=0; *allow_options = OPT_NONE; return; } if(!(S_ISDIR(lfi.st_mode))) { if(opts[x] & OPT_SYM_OWNER) { if(stat(d,&fi) != 0) { sprintf(errstr,"httpd: can't stat %s, errno = %d",d, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=0; *allow_options = OPT_NONE; return; } if(fi.st_uid != lfi.st_uid) goto bong; } else { bong: sprintf(errstr,"httpd: will not follow link %s",d); log_error(errstr,reqInfo->hostInfo->error_log); *allow=0; *allow_options = OPT_NONE; return; } } } if(override[x]) { parse_htaccess(reqInfo,d,override[x]); if(num_sec != y) { for(z=count_dirs(sec[y].d) - 1;z<num_dirs;z++) { if(!(sec[y].opts & OPT_UNSET)) opts[z] = sec[y].opts; override[z] = sec[y].override; } if (sec[y].num_auth[reqInfo->method] > 0 || sec[y].num_allow[reqInfo->method] > 0) check_dir_access(reqInfo,y,&will_allow,&need_auth); } } } } if((!(S_ISDIR(finfo->st_mode))) && ((!(opts[n] & OPT_SYM_LINKS)) || (opts[n] & OPT_SYM_OWNER))) { struct stat fi,lfi; if(lstat(path,&fi)!=0) { sprintf(errstr,"httpd: can't lstat %s, errno = %d",path, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=0; *allow_options = OPT_NONE; return; } if(!(S_ISREG(fi.st_mode))) { if(opts[n] & OPT_SYM_OWNER) { if(stat(path,&lfi)!=0) { sprintf(errstr,"httpd: can't stat %s, errno = %d",path, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=0; *allow_options = OPT_NONE; return; } if(fi.st_uid != lfi.st_uid) goto gong; } else { gong: sprintf(errstr,"httpd: will not follow link %s",path); log_error(errstr,reqInfo->hostInfo->error_log); *allow=0; *allow_options = OPT_NONE; return; } } } *allow = will_allow; if(will_allow) { *allow_options = opts[num_dirs-1]; if ((need_auth >= 0) && !sec[need_auth].bSatisfy) { reqInfo->bSatisfiedDomain = 0; check_auth(reqInfo,&sec[need_auth], auth_line); } } else if (need_auth >= 0 && sec[need_auth].bSatisfy) { check_auth(reqInfo,&sec[need_auth], auth_line); *allow_options = opts[num_dirs-1]; *allow = 1; } else *allow_options = 0; } void kill_security() { register int x,y,m; for(x=0;x<num_sec;x++) { /*free(sec[x].d);*/ for(m=0;m<METHODS;m++) { for(y=0;y<sec[x].num_allow[m];y++) free(sec[x].allow[m][y]); for(y=0;y<sec[x].num_deny[m];y++) free(sec[x].deny[m][y]); for(y=0;y<sec[x].num_auth[m];y++) free(sec[x].auth[m][y]); } /* if(sec[x].auth_type) free(sec[x].auth_type); if(sec[x].auth_name) free(sec[x].auth_name); if(sec[x].auth_pwfile) free(sec[x].auth_pwfile); if(sec[x].auth_grpfile) free(sec[x].auth_grpfile); #ifdef DIGEST_AUTH if(sec[x].auth_digestfile) free(sec[x].auth_digestfile); #endif*/ /* DIGEST_AUTH */ } } /* This function should reset the security data structure to contain only the information given in the access configuration file. It should be called after any transactions */ void reset_security() { register int x,y,m; for(x=num_sec_config;x<num_sec;x++) { /*free(sec[x].d);*/ for(m=0;m<METHODS;m++) { for(y=0;y<sec[x].num_allow[m];y++) free(sec[x].allow[m][y]); for(y=0;y<sec[x].num_deny[m];y++) free(sec[x].deny[m][y]); for(y=0;y<sec[x].num_auth[m];y++) free(sec[x].auth[m][y]); } /* if(sec[x].auth_type) free(sec[x].auth_type); if(sec[x].auth_name) free(sec[x].auth_name); if(sec[x].auth_pwfile) free(sec[x].auth_pwfile); if(sec[x].auth_grpfile) free(sec[x].auth_grpfile); #ifdef DIGEST_AUTH if(sec[x].auth_digestfile) free(sec[x].auth_digestfile); #endif*/ /* DIGEST_AUTH */ } num_sec = num_sec_config; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.