📄 suexec.c
字号:
exit(101); } target_uname = argv[1]; target_gname = argv[2]; cmd = argv[3]; /* * Check to see if the user running this program * is the user allowed to do so as defined in * suexec.h. If not the allowed user, error out. */#ifdef _OSD_POSIX /* User name comparisons are case insensitive on BS2000/OSD */ if (strcasecmp(AP_HTTPD_USER, pw->pw_name)) { log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER); exit(103); }#else /*_OSD_POSIX*/ if (strcmp(AP_HTTPD_USER, pw->pw_name)) { log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER); exit(103); }#endif /*_OSD_POSIX*/ /* * Check for a leading '/' (absolute path) in the command to be executed, * or attempts to back up out of the current directory, * to protect against attacks. If any are * found, error out. Naughty naughty crackers. */ if ((cmd[0] == '/') || (!strncmp(cmd, "../", 3)) || (strstr(cmd, "/../") != NULL)) { log_err("invalid command (%s)\n", cmd); exit(104); } /* * Check to see if this is a ~userdir request. If * so, set the flag, and remove the '~' from the * target username. */ if (!strncmp("~", target_uname, 1)) { target_uname++; userdir = 1; } /* * Error out if the target username is invalid. */ if (strspn(target_uname, "1234567890") != strlen(target_uname)) { if ((pw = getpwnam(target_uname)) == NULL) { log_err("invalid target user name: (%s)\n", target_uname); exit(105); } } else { if ((pw = getpwuid(atoi(target_uname))) == NULL) { log_err("invalid target user id: (%s)\n", target_uname); exit(121); } } /* * Error out if the target group name is invalid. */ if (strspn(target_gname, "1234567890") != strlen(target_gname)) { if ((gr = getgrnam(target_gname)) == NULL) { log_err("invalid target group name: (%s)\n", target_gname); exit(106); } gid = gr->gr_gid; actual_gname = strdup(gr->gr_name); } else { gid = atoi(target_gname); actual_gname = strdup(target_gname); }#ifdef _OSD_POSIX /* * Initialize BS2000 user environment */ { pid_t pid; int status; switch (pid = ufork(target_uname)) { case -1: /* Error */ log_err("failed to setup bs2000 environment for user %s: %s\n", target_uname, strerror(errno)); exit(150); case 0: /* Child */ break; default: /* Father */ while (pid != waitpid(pid, &status, 0)) ; /* @@@ FIXME: should we deal with STOP signals as well? */ if (WIFSIGNALED(status)) { kill (getpid(), WTERMSIG(status)); } exit(WEXITSTATUS(status)); } }#endif /*_OSD_POSIX*/ /* * Save these for later since initgroups will hose the struct */ uid = pw->pw_uid; actual_uname = strdup(pw->pw_name); target_homedir = strdup(pw->pw_dir); /* * Log the transaction here to be sure we have an open log * before we setuid(). */ log_err("uid: (%s/%s) gid: (%s/%s) cmd: %s\n", target_uname, actual_uname, target_gname, actual_gname, cmd); /* * Error out if attempt is made to execute as root or as * a UID less than AP_UID_MIN. Tsk tsk. */ if ((uid == 0) || (uid < AP_UID_MIN)) { log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd); exit(107); } /* * Error out if attempt is made to execute as root group * or as a GID less than AP_GID_MIN. Tsk tsk. */ if ((gid == 0) || (gid < AP_GID_MIN)) { log_err("cannot run as forbidden gid (%d/%s)\n", 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. */ if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) { log_err("failed to setgid (%ld: %s)\n", gid, cmd); exit(109); } /* * setuid() to the target user. Error out on fail. */ if ((setuid(uid)) != 0) { log_err("failed to setuid (%ld: %s)\n", uid, 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, * or if the current working directory is not in the docroot. * 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(target_homedir)) != 0) || ((chdir(AP_USERDIR_SUFFIX)) != 0) || ((getcwd(dwd, AP_MAXPATH)) == NULL) || ((chdir(cwd)) != 0)) { log_err("cannot get docroot information (%s)\n", target_homedir); exit(112); } } else { if (((chdir(AP_DOC_ROOT)) != 0) || ((getcwd(dwd, AP_MAXPATH)) == NULL) || ((chdir(cwd)) != 0)) { log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT); exit(113); } } if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { log_err("command not in docroot (%s/%s)\n", cwd, cmd); exit(114); } /* * Stat the cwd and verify it is a directory, or error out. */ if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) { log_err("cannot stat directory: (%s)\n", cwd); exit(115); } /* * Error out if cwd is writable by others. */ 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); } /* * Error out if we cannot stat the program. */ if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) { log_err("cannot stat program: (%s)\n", cmd); exit(117); } /* * Error out if the program is writable by others. */ 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); } /* * Error out if the file is setuid or setgid. */ 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); } /* * Error out if the target name/group is different from * the name/group of the cwd or the program. */ if ((uid != dir_info.st_uid) || (gid != dir_info.st_gid) || (uid != prg_info.st_uid) || (gid != prg_info.st_gid)) { log_err("target uid/gid (%ld/%ld) mismatch " "with directory (%ld/%ld) or program (%ld/%ld)\n", uid, gid, dir_info.st_uid, dir_info.st_gid, prg_info.st_uid, prg_info.st_gid); exit(120); } /* * Error out if the program is not executable for the user. * Otherwise, she won't find any error in the logs except for * "[error] Premature end of script headers: ..." */ if (!(prg_info.st_mode & S_IXUSR)) { log_err("file has no execute permission: (%s/%s)\n", cwd, cmd); exit(121); }#ifdef AP_SUEXEC_UMASK /* * umask() uses inverse logic; bits are CLEAR for allowed access. */ if ((~AP_SUEXEC_UMASK) & 0022) { log_err("notice: AP_SUEXEC_UMASK of %03o allows " "write permission to group and/or other\n", AP_SUEXEC_UMASK); } umask(AP_SUEXEC_UMASK);#endif /* AP_SUEXEC_UMASK */ /* * Be sure to close the log file so the CGI can't * mess with it. If the exec fails, it will be reopened * automatically when log_err is called. Note that the log * might not actually be open if AP_LOG_EXEC isn't defined. * However, the "log" cell isn't ifdef'd so let's be defensive * and assume someone might have done something with it * outside an ifdef'd AP_LOG_EXEC block. */ if (log != NULL) { fclose(log); log = NULL; } /* * Execute the command, replacing our image with its own. */#ifdef NEED_HASHBANG_EMUL /* We need the #! emulation when we want to execute scripts */ { extern char **environ; ap_execve(cmd, &argv[3], environ); }#else /*NEED_HASHBANG_EMUL*/ execv(cmd, &argv[3]);#endif /*NEED_HASHBANG_EMUL*/ /* * (I can't help myself...sorry.) * * Uh oh. Still here. Where's the kaboom? There was supposed to be an * EARTH-shattering kaboom! * * Oh well, log the failure and error out. */ log_err("(%d)%s: exec failed (%s)\n", errno, strerror(errno), cmd); exit(255);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -