Received: by taz.hyperreal.com (8.8.4/V2.0) id GAA24426; Mon, 10 Feb 1997 06:05:39 -0800 (PST) Received: by taz.hyperreal.com (8.8.4/V2.0) id GAA24420; Mon, 10 Feb 1997 06:05:35 -0800 (PST) Date: Mon, 10 Feb 1997 06:05:35 -0800 (PST) From: Randy Terbush Message-Id: <199702101405.GAA24420@taz.hyperreal.com> To: apache-cvs@hyperreal.com Subject: cvs commit: apache/support suexec.c Sender: apache-cvs-owner@apache.org Precedence: bulk Reply-To: new-httpd@hyperreal.com randy 97/02/10 06:05:35 Modified: src CHANGES Log: Update changes for suexec fixes. Revision Changes Path 1.155 +5 -0 apache/src/CHANGES Index: CHANGES =================================================================== RCS file: /export/home/cvs/apache/src/CHANGES,v retrieving revision 1.154 retrieving revision 1.155 diff -C3 -r1.154 -r1.155 *** CHANGES 1997/02/10 12:07:20 1.154 --- CHANGES 1997/02/10 14:03:48 1.155 *************** *** 1,5 **** --- 1,10 ---- Changes with Apache 1.2b7 + *) Several fixes for suexec wrapper. [Randy Terbush] + - Make wrapper work for files on NFS filesystem. + - Fix portability problem of MAXPATHLEN. + - Fix array overrun problem in clean_env(). + *) Removed extraneous blank line is description of mod_status chars. [Kurt Kohler] Modified: support suexec.c Log: *) Several fixes for suexec wrapper. [Randy Terbush] - Make wrapper work for files on NFS filesystem. - Fix portability problem of MAXPATHLEN. - Fix array overrun problem in clean_env(). Reviewed by: Michael Zucchi (cismpz@cis.unisa.edu.au) Revision Changes Path 1.15 +76 -66 apache/support/suexec.c Index: suexec.c =================================================================== RCS file: /export/home/cvs/apache/support/suexec.c,v retrieving revision 1.14 retrieving revision 1.15 diff -C3 -r1.14 -r1.15 *** suexec.c 1997/02/06 21:46:08 1.14 --- suexec.c 1997/02/10 14:05:34 1.15 *************** *** 81,87 **** #include #include ! #define CLEAN_ENV_BUF 256 extern char **environ; static FILE *log; --- 81,95 ---- #include #include ! #if defined(PATH_MAX) ! #define AP_MAXPATH PATH_MAX ! #elif defined(MAXPATHLEN) ! #define AP_MAXPATH MAXPATHLEN ! #else ! #define AP_MAXPATH 256 ! #endif ! ! #define AP_ENVBUF 256 extern char **environ; static FILE *log; *************** *** 173,184 **** int idx; ! if ((cleanenv = (char **)malloc(CLEAN_ENV_BUF * (sizeof(char *)))) == NULL) { log_err("failed to malloc env mem\n"); exit(120); } ! for (ep = environ; *ep; ep++) { if (!strncmp(*ep, "HTTP_", 5)) { cleanenv[cidx] = *ep; cidx++; --- 181,192 ---- int idx; ! if ((cleanenv = (char **)calloc(AP_ENVBUF, AP_ENVBUF * (sizeof(char *)))) == NULL) { log_err("failed to malloc env mem\n"); exit(120); } ! for (ep = environ; *ep && cidx < AP_ENVBUF; ep++) { if (!strncmp(*ep, "HTTP_", 5)) { cleanenv[cidx] = *ep; cidx++; *************** *** 210,217 **** char *target_gname; /* target group name */ char *prog; /* name of this program */ char *cmd; /* command to be executed */ ! char cwd[MAXPATHLEN]; /* current working directory */ ! char dwd[MAXPATHLEN]; /* docroot working directory */ struct passwd *pw; /* password entry holder */ struct group *gr; /* group entry holder */ struct stat dir_info; /* directory info holder */ --- 218,225 ---- char *target_gname; /* target group name */ char *prog; /* name of this program */ char *cmd; /* command to be executed */ ! char cwd[AP_MAXPATH]; /* current working directory */ ! char dwd[AP_MAXPATH]; /* docroot working directory */ struct passwd *pw; /* password entry holder */ struct group *gr; /* group entry holder */ struct stat dir_info; /* directory info holder */ *************** *** 289,294 **** --- 297,352 ---- } /* + * Log the transaction here to be sure we have an open log + * before we setuid(). + */ + log_err("uid: (%s/%s) gid: (%s/%s) %s\n", + target_uname, pw->pw_name, + target_gname, gr->gr_name, + cmd); + + /* + * Error out if attempt is made to execute as root or as + * a UID less than UID_MIN. Tsk tsk. + */ + if ((pw->pw_uid == 0) || + (pw->pw_uid < UID_MIN)) { + log_err("cannot run as forbidden uid (%d/%s)\n", pw->pw_uid, cmd); + exit(107); + } + + /* + * Error out if attempt is made to execute as root group + * or as a GID less than GID_MIN. Tsk tsk. + */ + if ((gr->gr_gid == 0) || + (gr->gr_gid < GID_MIN)) { + log_err("cannot run as forbidden gid (%d/%s)\n", gr->gr_gid, cmd); + exit(108); + } + + /* + * Change UID/GID here so that the following tests work over NFS. + * + * Initialize the group access list for the target user, + * and setgid() to the target group. If unsuccessful, error out. + */ + uid = pw->pw_uid; + gid = gr->gr_gid; + if (((setgid(gid)) != 0) || (initgroups(pw->pw_name,gid) != 0)) { + log_err("failed to setgid (%ld: %s/%s)\n", gid, cwd, cmd); + exit(109); + } + + /* + * setuid() to the target user. Error out on fail. + */ + if ((setuid(uid)) != 0) { + log_err("failed to setuid (%ld: %s/%s)\n", uid, cwd, cmd); + exit(110); + } + + /* * Get the current working directory, as well as the proper * document root (dependant upon whether or not it is a * ~userdir request). Error out if we cannot get either one, *************** *** 296,329 **** * Use chdir()s and getcwd()s to avoid problems with symlinked * directories. Yuck. */ ! if (getcwd(cwd, MAXPATHLEN) == NULL) { log_err("cannot get current working directory\n"); ! exit(107); } if (userdir) { if (((chdir(pw->pw_dir)) != 0) || ((chdir(USERDIR_SUFFIX)) != 0) || ! ((getcwd(dwd, MAXPATHLEN)) == NULL) || ((chdir(cwd)) != 0)) { log_err("cannot get docroot information (%s)\n", pw->pw_dir); ! exit(108); } } else { if (((chdir(DOC_ROOT)) != 0) || ! ((getcwd(dwd, MAXPATHLEN)) == NULL) || ((chdir(cwd)) != 0)) { log_err("cannot get docroot information (%s)\n", DOC_ROOT); ! exit(108); } } if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { log_err("command not in docroot (%s/%s)\n", cwd, cmd); ! exit(109); } /* --- 354,387 ---- * Use chdir()s and getcwd()s to avoid problems with symlinked * directories. Yuck. */ ! if (getcwd(cwd, AP_MAXPATH) == NULL) { log_err("cannot get current working directory\n"); ! exit(111); } if (userdir) { if (((chdir(pw->pw_dir)) != 0) || ((chdir(USERDIR_SUFFIX)) != 0) || ! ((getcwd(dwd, AP_MAXPATH)) == NULL) || ((chdir(cwd)) != 0)) { log_err("cannot get docroot information (%s)\n", pw->pw_dir); ! exit(112); } } else { if (((chdir(DOC_ROOT)) != 0) || ! ((getcwd(dwd, AP_MAXPATH)) == NULL) || ((chdir(cwd)) != 0)) { log_err("cannot get docroot information (%s)\n", DOC_ROOT); ! exit(113); } } if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { log_err("command not in docroot (%s/%s)\n", cwd, cmd); ! exit(114); } /* *************** *** 331,337 **** */ if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) { log_err("cannot stat directory: (%s)\n", cwd); ! exit(110); } /* --- 389,395 ---- */ if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) { log_err("cannot stat directory: (%s)\n", cwd); ! exit(115); } /* *************** *** 339,345 **** */ if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) { log_err("directory is writable by others: (%s)\n", cwd); ! exit(111); } /* --- 397,403 ---- */ if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) { log_err("directory is writable by others: (%s)\n", cwd); ! exit(116); } /* *************** *** 347,353 **** */ if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) { log_err("cannot stat program: (%s)\n", cmd); ! exit(112); } /* --- 405,411 ---- */ if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) { log_err("cannot stat program: (%s)\n", cmd); ! exit(117); } /* *************** *** 355,361 **** */ if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) { log_err("file is writable by others: (%s/%s)\n", cwd, cmd); ! exit(113); } /* --- 413,419 ---- */ if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) { log_err("file is writable by others: (%s/%s)\n", cwd, cmd); ! exit(118); } /* *************** *** 363,369 **** */ if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) { log_err("file is either setuid or setgid: (%s/%s)\n",cwd,cmd); ! exit(114); } /* --- 421,427 ---- */ if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) { log_err("file is either setuid or setgid: (%s/%s)\n",cwd,cmd); ! exit(119); } /* *************** *** 379,433 **** pw->pw_uid, gr->gr_gid, dir_info.st_uid, dir_info.st_gid, prg_info.st_uid, prg_info.st_gid); ! exit(115); ! } ! ! /* ! * Error out if attempt is made to execute as root or as ! * a UID less than UID_MIN. Tsk tsk. ! */ ! if ((pw->pw_uid == 0) || ! (pw->pw_uid < UID_MIN)) { ! log_err("cannot run as forbidden uid (%d/%s)\n", pw->pw_uid, cmd); ! exit(116); ! } ! ! /* ! * Error out if attempt is made to execute as root group ! * or as a GID less than GID_MIN. Tsk tsk. ! */ ! if ((gr->gr_gid == 0) || ! (gr->gr_gid < GID_MIN)) { ! log_err("cannot run as forbidden gid (%d/%s)\n", gr->gr_gid, cmd); ! exit(117); ! } ! ! /* ! * Log the transaction here to be sure we have an open log ! * before we setuid(). ! */ ! log_err("uid: (%s/%s) gid: (%s/%s) %s\n", ! target_uname, pw->pw_name, ! target_gname, gr->gr_name, ! cmd); ! ! /* ! * Initialize the group access list for the target user, ! * and setgid() to the target group. If unsuccessful, error out. ! */ ! uid = pw->pw_uid; ! gid = gr->gr_gid; ! if (((setgid(gid)) != 0) || (initgroups(pw->pw_name,gid) != 0)) { ! log_err("failed to setgid (%ld: %s/%s)\n", gid, cwd, cmd); ! exit(118); ! } ! ! /* ! * setuid() to the target user. Error out on fail. ! */ ! if ((setuid(uid)) != 0) { ! log_err("failed to setuid (%ld: %s/%s)\n", uid, cwd, cmd); ! exit(119); } clean_env(); --- 437,443 ---- pw->pw_uid, gr->gr_gid, dir_info.st_uid, dir_info.st_gid, prg_info.st_uid, prg_info.st_gid); ! exit(120); } clean_env();