/* * Checks to see if actual access to the URL is permitted or not * stats the URI first, if failure returns FORBIDDEN, if allowed then * checks to see if it is a file, dir or LINK (TEST), and accordingly does more */ static int can_access(request_rec * r) { int rc; char *doc_root = (char *)DOCUMENT_ROOT(r); struct stat buf; char path[MAX_STRING_LEN]; afsassert(r->uri); afsassert(doc_root); if (r->filename) { afslog(10, ("%s: Found r->filename:%s", module_name, r->filename)); sprintf(path, "%s", r->filename); } else { afslog(10, ("%s: Composing path from doc_root:%s and r->uri:%s", module_name, doc_root, r->uri)); sprintf(path, "%s/%s", doc_root, r->uri); afslog(10, ("%s: Path:%s", module_name, path)); } rc = stat(path, &buf); if (rc == -1) { afslog(2, ("%s: pid:%d\tpath:%s\tstat error:%s", module_name, getpid(), path, strerror(errno))); /* * if the requested method is an HTTP PUT and the file does not * exist then well, we'll get a stat error but we shouldn't return * an error - we should try and open the file in append mode and then * see if we get a permission denied error */ if ((strncmp(r->method, "PUT", 3) == 0) && (errno == ENOENT)) { FILE *f = fopen(path, "a"); if (f == NULL) { if (errno == EACCES) { afslog(2, ("%s: Either AFS acls or other permissions forbid write" " access to file %s for user %s", module_name, path, r->connection->user ? r->connection-> user : "******")); return FORBIDDEN; } else { log_reason ("afs_module: Error checking file for PUT method", r->uri, r); return SERVER_ERROR; } } } else if (errno == ENOTDIR) { /* * maybe the special case of CGI PATH_INFO to be translated to * PATH_TRANSLATED - check each component of this path * and stat it to see what portion of the url is actually * the path and discard the rest for our purposes. */ rc = remove_path_info(r, path, &buf); afslog(10, ("%s:remove_path_info returned %d path:%s", module_name, rc, path)); if (rc) return rc; } else { return sort_stat_error(r); } } /* * If we get here then we have something - either a file or a directory */ else { if (S_IFREG == (buf.st_mode & S_IFMT)) { /* regular file */ FILE *f; char permissions[] = { 'r', '\0', '\0', '\0' }; /* room for +, etc... */ if ((strncmp(r->method, "PUT", 3) == 0)) { strcpy(permissions, "a"); } if (!(f = fopen(path, permissions))) { if (errno == EACCES) { afslog(2, ("%s: Either AFS acls or other permissions" " forbid access to file %s for user %s", module_name, path, r->connection->user ? r->connection-> user : "******")); return FORBIDDEN; } else { char error[ERRSTRLEN]; sprintf(error, "%s: Error checking file %s for permissions:%s", module_name, path, strerror(errno)); log_reason(error, r->uri, r); return SERVER_ERROR; } } fclose(f); return OK; } if (S_IFDIR == (buf.st_mode & S_IFMT)) { /* path is a directory */ if (r->uri[strlen(r->uri) - 1] != '/') { /* if we don't have a trailing slash, return REDIRECT */ char *ifile; if (r->args != NULL) { ifile = PSTRCAT(r->pool, escape_uri(r->pool, r->uri), "/", "?", r->args, NULL); } else { ifile = PSTRCAT(r->pool, escape_uri(r->pool, r->uri), "/", NULL); } TABLE_SET(r->headers_out, "Location", ifile); return REDIRECT; } else { DIR *d; if (!(d = opendir(path))) { if (errno == EACCES) { afslog(2, ("%s: Error accessing dir %s - %s", module_name, path, strerror(errno))); return FORBIDDEN; } else { char error[ERRSTRLEN]; sprintf(error, "%s: opendir failed with Error:%s", module_name, strerror(errno)); log_reason(error, r, r->uri); return SERVER_ERROR; } } closedir(d); return OK; } } } }
void send_node(per_request *reqInfo) { struct stat finfo; register x = 0; int allow; char allow_options; int ErrReturn = 0; exit_callback = NULL; /* It is no longer necessary to move all but one of the trailing slashes * to the path_info string, since all multiple slashes are now compressed * to one as a security precaution. */ if(stat(reqInfo->filename,&finfo) == -1) { ErrReturn = extract_path_info(reqInfo,&finfo); } evaluate_access(reqInfo,&finfo,&allow,&allow_options); if (ErrReturn) { if(ErrReturn == ENOENT) { log_reason(reqInfo,"file does not exist",reqInfo->filename); die(reqInfo,SC_NOT_FOUND,reqInfo->url); /* Check for AFS/NFS problems, and send back an unavailable message instead * Larry Schwimmer ([email protected]) */ } else if ((ErrReturn == ETIMEDOUT) || (ErrReturn == ENODEV)) { log_reason(reqInfo, "file temporarily unavailable", reqInfo->filename); die(reqInfo,SC_SERVICE_UNAVAIL,reqInfo->url); } else { log_reason(reqInfo,"(3) file permissions deny server access", reqInfo->filename); die(reqInfo,SC_FORBIDDEN,reqInfo->url); } } if(!allow) { log_reason(reqInfo,"client denied by server configuration", reqInfo->filename); die(reqInfo,SC_FORBIDDEN,reqInfo->url); } if (S_ISDIR(finfo.st_mode)) { send_dir(reqInfo,&finfo,allow_options); } else if (S_ISREG(finfo.st_mode)) { x = strlen(reqInfo->filename); /* Remove the trailing slash if its not a directory */ if (reqInfo->filename[x-1] == '/') { if (reqInfo->path_info[0] == '\0') { reqInfo->path_info[0] = '/'; reqInfo->path_info[1] = '\0'; } reqInfo->filename[x-1] = '\0'; } probe_content_type(reqInfo,reqInfo->filename); if (!strcmp(reqInfo->outh_content_type, CGI_MAGIC_TYPE)) send_cgi(reqInfo,&finfo,allow_options); #ifdef IMAGEMAP_SUPPORT else if (!strcmp(reqInfo->outh_content_type, IMAGEMAP_MAGIC_TYPE)) send_imagemap(reqInfo,&finfo,allow_options); #endif /* IMAGEMAP_SUPPORT */ #ifdef FCGI_SUPPORT else if (!strcmp(reqInfo->outh_content_type, FCGI_MAGIC_TYPE)) FastCgiHandler(reqInfo); #endif /* FCGI_SUPPORT */ else send_file(reqInfo,&finfo,allow_options); } else { log_reason(reqInfo,"improper file type",reqInfo->filename); /* device driver or pipe, no permission */ die(reqInfo,SC_FORBIDDEN,reqInfo->url); } }
/* NCSA Imagemap files use: method URL coord1 coord2 * CERN Imagemap files use: method (coord1) (coord2) URL * This version of imagemap will probably work with either in the same file, * as long as a full line is in one format or the other. */ int send_imagemap(per_request* reqInfo, struct stat* fi, char allow_options) { char *input, *def, *szPoint, *url, *type; double testpoint[2], pointarray[MAXVERTS][2]; int i, j, k; int error_num = 0; FILE *fp; char *t; double dist, mindist = -1; int sawpoint = 0; int sawparen = 0; int Found = 0; input = newString(HUGE_STRING_LEN,STR_TMP); def = newString(MAX_STRING_LEN,STR_TMP); szPoint = newString(MAX_STRING_LEN,STR_TMP); type = newString(MAX_STRING_LEN,STR_TMP); url = newString(MAX_STRING_LEN,STR_TMP); def[0] = '\0'; strcpy(szPoint, reqInfo->args); if(!(t = strchr(szPoint,','))) { error_num = IMAP_ERR_INCORRECT_ARGS; goto imagemap_error; } *t++ = '\0'; testpoint[X] = (double) atoi(szPoint); testpoint[Y] = (double) atoi(t); if(!(fp=FOpen(reqInfo->filename,"r"))){ log_reason(reqInfo, "File permissions deny server access", reqInfo->filename); freeString(input); freeString(def); freeString(szPoint); freeString(url); freeString(type); die(reqInfo, SC_FORBIDDEN, reqInfo->url); } while (!Found && fgets(input,HUGE_STRING_LEN,fp)) { char num[10]; /* Skip lines with # as comments and blank lines */ if((input[0] == '#') || (!input[0])) continue; type[0] = '\0';url[0] = '\0'; /* Copy the shape keyword into type */ for(i=0;!isspace(input[i]) && (input[i]);i++) type[i] = input[i]; type[i] = '\0'; /* Forward to next word */ while(isspace(input[i])) ++i; /* If no coordinates, must be url for default, or NCSA format */ if (input[i] != '(') { for(j=0;input[i] && !isspace(input[i]);++i,++j) url[j] = input[i]; url[j] = '\0'; } /* Handle default keyword */ if(!strcmp(type,"default") && !sawpoint) { strcpy(def,url); continue; } /* Looking for Coordinates */ k=0; while (input[i]) { /* Move over spaces and commas */ while (isspace(input[i]) || input[i] == ',') i++; /* Under CERN, coordinates are in parenthesis */ if (input[i] == '(') { sawparen = 1; while (isspace(input[++i])); } /* Copy digits into num array */ j = 0; while (isdigit(input[i])) num[j++] = input[i++]; num[j] = '\0'; if (!j) break; pointarray[k][X] = (double) atoi(num); /* Skip to next digit */ while (isspace(input[i]) || input[i] == ',') i++; /* Copy other number into num */ j = 0; while (isdigit(input[i])) num[j++] = input[i++]; num[j] = '\0'; if (!j && !sawparen && k > 0) { pointarray[k++][Y] = -127; break; } if (j) pointarray[k++][Y] = (double) atoi(num); else { error_num = IMAP_ERR_INCORRECT_COORDS; FClose(fp); goto imagemap_error; } /* End of parenthesis for coordinates under CERN */ if (input[i] == ')') { i++; sawparen = 0; } else if (sawparen) { error_num = IMAP_ERR_CERN_MISSING_RIGHT_PAREN; FClose(fp); goto imagemap_error; } } if (url[0] == '\0' && input[i]) { while (isspace(input[i])) i++; for (j = 0; input[i] && !isspace(input[i]); ++i, ++j) url[j] = input[i]; url[j] = '\0'; } pointarray[k][X] = -1; if(!strncmp(type, "poly", 4)) if(pointinpoly(testpoint,pointarray)) Found = 1; if(!strncmp(type, "circ", 4)) if(pointincircle(testpoint,pointarray)) Found = 1; if(!strncmp(type, "rect", 4)) if(pointinrect(testpoint,pointarray)) Found = 1; if(!strcmp(type,"point")) { /* Don't need to take square root. */ dist = ((testpoint[X] - pointarray[0][X]) * (testpoint[X] - pointarray[0][X])) + ((testpoint[Y] - pointarray[0][Y]) * (testpoint[Y] - pointarray[0][Y])); /* If this is the first point, or the nearest, set the default. */ if ((! sawpoint) || (dist < mindist)) { mindist = dist; strcpy(def,url); } sawpoint++; } } if(Found) { sendmesg(reqInfo, url, fp); goto imagemap_ok; } else { if(def[0]) { sendmesg(reqInfo, def, fp); goto imagemap_ok; } } /* No reason to log each of these as an "error" */ /* log_reason(reqInfo, "No default defined in imagemap.", reqInfo->filename); */ FClose(fp); freeString(input); freeString(def); freeString(szPoint); freeString(url); freeString(type); die(reqInfo, SC_NO_CONTENT, reqInfo->url); return 0; imagemap_ok: FClose(fp); freeString(input); freeString(def); freeString(szPoint); freeString(url); freeString(type); return 1; imagemap_error: freeString(input); freeString(def); freeString(szPoint); freeString(url); freeString(type); log_reason(reqInfo,imagemap_errors[error_num-1],reqInfo->filename); die(reqInfo,SC_BAD_IMAGEMAP,imagemap_errors[error_num-1]); return -1; }
void send_file(per_request *reqInfo, struct stat *fi, char allow_options) { FILE *f; #ifdef BLACKOUT_CODE int isblack = FALSE; #endif /* BLACKOUT_CODE */ if ((reqInfo->method != M_GET) && (reqInfo->method != M_HEAD)) { sprintf(error_msg,"%s to non-script",methods[reqInfo->method]); die(reqInfo,SC_NOT_IMPLEMENTED,error_msg); } set_content_type(reqInfo,reqInfo->filename); if((allow_options & OPT_INCLUDES) && (!reqInfo->outh_content_encoding[0])) { #ifdef XBITHACK if((fi->st_mode & S_IXUSR) || (!strcmp(reqInfo->outh_content_type,INCLUDES_MAGIC_TYPE))) { #else if(!strcmp(reqInfo->outh_content_type,INCLUDES_MAGIC_TYPE)) { #endif /* XBITHACK */ reqInfo->bytes_sent = 0; send_parsed_file(reqInfo, allow_options & OPT_INCNOEXEC); log_transaction(reqInfo); return; } } if (reqInfo->path_info[0]) { strcat(reqInfo->filename,reqInfo->path_info); strcat(reqInfo->url,reqInfo->path_info); sprintf(error_msg,"No file matching URL: %s",reqInfo->url); log_reason(reqInfo, error_msg, reqInfo->filename); die(reqInfo,SC_NOT_FOUND,reqInfo->url); } if(!(f=FOpen(reqInfo->filename,"r"))) { if (errno == EACCES) { log_reason(reqInfo,"(1) file permissions deny server access", reqInfo->filename); /* we've already established that it exists */ die(reqInfo,SC_FORBIDDEN,reqInfo->url); } else { /* We know an error occured, of an unexpected variety. * This could be due to no more file descriptors. We have this * child exit after this stage so that errors of state are * swept under the carpet. */ standalone = 0; sprintf(error_msg,"File Open error, errno=%d",errno); log_reason(reqInfo,error_msg,reqInfo->filename); die(reqInfo,SC_SERVER_ERROR,error_msg); } } reqInfo->bytes_sent = 0; #ifdef BLACKOUT_CODE if (!strcmp(reqInfo->outh_content_type,BLACKOUT_MAGIC_TYPE)) { isblack = TRUE; strcpy(reqInfo->outh_content_type,"text/html"); } #endif /* BLACKOUT_CODE */ if(reqInfo->http_version != P_HTTP_0_9) { /* No length dependent headers since black is parsed */ #ifdef BLACKOUT_CODE if (isblack == FALSE) { #endif /* BLACKOUT_CODE */ #ifdef CONTENT_MD5 reqInfo->outh_content_md5 = (unsigned char *)md5digest(f); #endif /* CONTENT_MD5 */ set_content_length(reqInfo,fi->st_size); if (set_last_modified(reqInfo,fi->st_mtime)) { FClose(f); return; } } if (reqInfo->http_version != P_HTTP_0_9) { send_http_header(reqInfo); } #ifdef BLACKOUT_CODE } #endif /* BLACKOUT_CODE */ if(reqInfo->method != M_HEAD) { #ifdef BLACKOUT_CODE if (isblack == TRUE) send_fp_black(reqInfo,f,NULL); else #endif /* BLACKOUT_CODE */ send_fp(reqInfo,f,NULL); } log_transaction(reqInfo); FClose(f); } void send_dir(per_request *reqInfo,struct stat *finfo, char allow_options) { char *name_ptr, *end_ptr; char *ifile, *temp_name; ifile = newString(HUGE_STRING_LEN,STR_TMP); temp_name = newString(HUGE_STRING_LEN,STR_TMP); /* Path Alias (pa) array should now have the trailing slash */ /* if (pa[0] != '/') { */ if ((reqInfo->filename[strlen(reqInfo->filename) - 1] != '/') && (reqInfo->path_info[0] != '/')) { strcpy_dir(ifile,reqInfo->url); construct_url(temp_name,reqInfo->hostInfo,ifile); escape_url(temp_name); die(reqInfo,SC_REDIRECT_PERM,temp_name); } /* Don't allow PATH_INFO to directory indexes as a compromise for error messages for files which don't exist */ if ((reqInfo->path_info[0] != '\0') || (strlen(reqInfo->path_info) > 1)) { strcat(reqInfo->filename,reqInfo->path_info); strcat(reqInfo->url,reqInfo->path_info); sprintf(error_msg,"No file matching URL: %s",reqInfo->url); log_reason(reqInfo, error_msg, reqInfo->filename); freeString(temp_name); freeString(ifile); die(reqInfo,SC_NOT_FOUND,reqInfo->url); } strncpy(temp_name, reqInfo->hostInfo->index_names, HUGE_STRING_LEN-1); end_ptr = name_ptr = temp_name; while (*name_ptr) { while (*name_ptr && isspace (*name_ptr)) ++name_ptr; end_ptr = name_ptr; if (strchr(end_ptr, ' ') ) { end_ptr = strchr(name_ptr, ' '); *end_ptr = '\0'; end_ptr++; } else end_ptr += strlen(end_ptr); make_full_path(reqInfo->filename,name_ptr,ifile); if(stat(ifile,finfo) == -1) { if(! *end_ptr && (allow_options & OPT_INDEXES)) { if (reqInfo->path_info[0]) { strcat(reqInfo->filename,reqInfo->path_info); strcat(reqInfo->url,reqInfo->path_info); log_reason(reqInfo,"file does not exist",reqInfo->filename); freeString(ifile); freeString(temp_name); die(reqInfo,SC_NOT_FOUND,reqInfo->url); } if ((reqInfo->method != M_GET) && (reqInfo->method != M_HEAD)) { sprintf(error_msg,"%s to non-script",methods[reqInfo->method]); freeString(ifile); freeString(temp_name); die(reqInfo,SC_NOT_IMPLEMENTED,error_msg); } index_directory(reqInfo); freeString(ifile); freeString(temp_name); return; } else if (! *end_ptr) { log_reason(reqInfo,"(2) file permissions deny server access", reqInfo->filename); freeString(ifile); freeString(temp_name); die(reqInfo,SC_FORBIDDEN,reqInfo->url); } } else { strcpy(reqInfo->filename,ifile); probe_content_type(reqInfo,reqInfo->filename); if(!strcmp(reqInfo->outh_content_type,CGI_MAGIC_TYPE)) send_cgi(reqInfo,finfo,allow_options); else send_file(reqInfo,finfo,allow_options); freeString(ifile); freeString(temp_name); return; } name_ptr = end_ptr; } }