dgaudet 97/06/26 19:21:25
Modified: src Tag: APACHE_1_2_X http_request.c mod_cern_meta.c mod_dir.c Log: Ugh I messed up the security fixes commit. Revision Changes Path No revision No revision 1.50.2.1 +41 -4 apache/src/http_request.c Index: http_request.c =================================================================== RCS file: /export/home/cvs/apache/src/http_request.c,v retrieving revision 1.50 retrieving revision 1.50.2.1 diff -C3 -r1.50 -r1.50.2.1 *** http_request.c 1997/05/14 19:22:52 1.50 --- http_request.c 1997/06/27 02:21:21 1.50.2.1 *************** *** 85,90 **** --- 85,108 ---- * they change, all the way down. */ + + /* + * We don't want people able to serve up pipes, or unix sockets, or other + * scary things. Note that symlink tests are performed later. + */ + static int check_safe_file(request_rec *r) + { + if (r->finfo.st_mode == 0 /* doesn't exist */ + || S_ISDIR (r->finfo.st_mode) + || S_ISREG (r->finfo.st_mode) + || S_ISLNK (r->finfo.st_mode)) { + return OK; + } + log_reason("object is not a file, directory or symlink", r->filename, r); + return HTTP_FORBIDDEN; + } + + int check_symlinks (char *d, int opts) { struct stat lfi, fi; *************** *** 310,320 **** if (res != OK) { return res; } ! if (test_filename[strlen(test_filename)-1] == '/') --num_dirs; ! if (S_ISDIR (r->finfo.st_mode)) ++num_dirs; for (i = 1; i <= num_dirs; ++i) { core_dir_config *core_dir = --- 328,344 ---- if (res != OK) { return res; } ! ! if ((res = check_safe_file(r))) { ! return res; ! } ! if (test_filename[strlen(test_filename)-1] == '/') --num_dirs; ! if (S_ISDIR (r->finfo.st_mode)) { ! ++num_dirs; ! } for (i = 1; i <= num_dirs; ++i) { core_dir_config *core_dir = *************** *** 399,406 **** r->per_dir_config = per_dir_defaults; ! if ((res = check_symlinks (r->filename, allow_options(r)))) ! { log_reason("Symbolic link not allowed", r->filename, r); return res; } --- 423,438 ---- r->per_dir_config = per_dir_defaults; ! /* Symlink permissions are determined by the parent. If the request is for ! * a directory then applying the symlink test here would use the ! * permissions of the directory as opposed to its parent. Consider a ! * symlink pointing to a dir with a .htaccess disallowing symlinks. If you ! * access /symlink (or /symlink/) you would get a 403 without this S_ISDIR ! * test. But if you accessed /symlink/index.html, for example, you would ! * *not* get the 403. ! */ ! if (!S_ISDIR (r->finfo.st_mode) ! && (res = check_symlinks (r->filename, allow_options(r)))) { log_reason("Symbolic link not allowed", r->filename, r); return res; } *************** *** 667,672 **** --- 699,709 ---- rnew->filename = make_full_path (rnew->pool, fdir, new_file); if (stat (rnew->filename, &rnew->finfo) < 0) { rnew->finfo.st_mode = 0; + } + + if ((res = check_safe_file(rnew))) { + rnew->status = res; + return rnew; } rnew->per_dir_config = r->per_dir_config; 1.10.2.1 +14 -20 apache/src/mod_cern_meta.c Index: mod_cern_meta.c =================================================================== RCS file: /export/home/cvs/apache/src/mod_cern_meta.c,v retrieving revision 1.10 retrieving revision 1.10.2.1 diff -C3 -r1.10 -r1.10.2.1 *** mod_cern_meta.c 1997/03/07 14:15:39 1.10 --- mod_cern_meta.c 1997/06/27 02:21:22 1.10.2.1 *************** *** 131,136 **** --- 131,137 ---- #include <sys/stat.h> #include "util_script.h" #include "http_log.h" + #include "http_request.h" #define DEFAULT_METADIR ".web" #define DEFAULT_METASUFFIX ".meta" *************** *** 238,247 **** char *last_slash; char *real_file; char *scrap_book; - struct stat meta_stat; FILE *f; cern_meta_config *cmc ; int rv; cmc = get_module_config (r->server->module_config, &cern_meta_module); --- 239,248 ---- char *last_slash; char *real_file; char *scrap_book; FILE *f; cern_meta_config *cmc ; int rv; + request_rec *rr; cmc = get_module_config (r->server->module_config, &cern_meta_module); *************** *** 276,305 **** metafilename = pstrcat(r->pool, "/", scrap_book, "/", cmc->metadir, "/", real_file, cmc->metasuffix, NULL); ! /* ! * stat can legitimately fail for a bewildering number of reasons, ! * only one of which implies the file isn't there. A hardened ! * version of this module should test for all conditions, but later... */ ! if (stat(metafilename, &meta_stat) == -1) { ! /* stat failed, possibly file missing */ return DECLINED; ! }; ! ! /* ! * this check is to be found in other Jan/96 Apache code, I've ! * not been able to find any corroboration in the man pages but ! * I've been wrong before so I'll put it in anyway. Never ! * admit to being clueless... ! */ ! if ( meta_stat.st_mode == 0 ) { ! /* stat failed, definately file missing */ ! return DECLINED; ! }; f = pfopen (r->pool, metafilename, "r"); - if (f == NULL) { log_reason("meta file permissions deny server access", metafilename, r); return FORBIDDEN; }; --- 277,299 ---- metafilename = pstrcat(r->pool, "/", scrap_book, "/", cmc->metadir, "/", real_file, cmc->metasuffix, NULL); ! /* XXX: it sucks to require this subrequest to complete, because this ! * means people must leave their meta files accessible to the world. ! * A better solution might be a "safe open" feature of pfopen to avoid ! * pipes, symlinks, and crap like that. */ ! rr = sub_req_lookup_file (metafilename, r); ! if (rr->status != HTTP_OK) { ! destroy_sub_req (rr); return DECLINED; ! } ! destroy_sub_req (rr); f = pfopen (r->pool, metafilename, "r"); if (f == NULL) { + if (errno == ENOENT) { + return DECLINED; + } log_reason("meta file permissions deny server access", metafilename, r); return FORBIDDEN; }; 1.26.2.1 +19 -0 apache/src/mod_dir.c Index: mod_dir.c =================================================================== RCS file: /export/home/cvs/apache/src/mod_dir.c,v retrieving revision 1.26 retrieving revision 1.26.2.1 diff -C3 -r1.26 -r1.26.2.1 *** mod_dir.c 1997/05/13 04:01:50 1.26 --- mod_dir.c 1997/06/27 02:21:22 1.26.2.1 *************** *** 164,174 **** --- 164,180 ---- } const char *add_header(cmd_parms *cmd, void *d, char *name) { + if (strchr (name, '/')) { + return "HeaderName cannot contain a /"; + } push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name); return NULL; } const char *add_readme(cmd_parms *cmd, void *d, char *name) { + if (strchr (name, '/')) { + return "ReadmeName cannot contain a /"; + } push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name); return NULL; } *************** *** 408,414 **** --- 414,422 ---- FILE *f; struct stat finfo; int plaintext=0; + request_rec *rr; + /* XXX: this is a load of crap, it needs to do a full sub_req_lookup_uri */ fn = make_full_path(r->pool, name, readme_fname); fn = pstrcat(r->pool, fn, ".html", NULL); if(stat(fn,&finfo) == -1) { *************** *** 421,426 **** --- 429,442 ---- rputs("<PRE>\n", r); } else if (rule) rputs("<HR>\n", r); + /* XXX: when the above is rewritten properly, this necessary security + * check will be redundant. -djg */ + rr = sub_req_lookup_file (fn, r); + if (rr->status != HTTP_OK) { + destroy_sub_req (rr); + return 0; + } + destroy_sub_req (rr); if(!(f = pfopen(r->pool,fn,"r"))) return 0; if (!plaintext) *************** *** 462,467 **** --- 478,486 ---- FILE *thefile = NULL; int x,y,n,p; + if (r->status != HTTP_OK) { + return NULL; + } if (r->content_type && !strcmp(r->content_type,"text/html") && !r->content_encoding) { if(!(thefile = pfopen(r->pool, r->filename,"r"))) return NULL;