diff -Naur httpd-2.4.39/support/suexec.c.orig httpd-2.4.39/support/suexec.c --- httpd-2.4.39/support/suexec.c.orig 2018-05-31 01:09:00.000000000 +0600 +++ httpd-2.4.39/support/suexec.c 2019-06-13 16:58:19.943661521 +0600 @@ -269,14 +269,36 @@ environ = cleanenv; } +static int is_group_member( const char *uname, gid_t gid ) { + struct group *g; + char **members; + + g = getgrgid( gid ); + if ( g == NULL ) { + log_err("crit: cannot get membership of group %d\n", gid); + exit(109); + } + + members = g->gr_mem; + while ( *members != NULL ) { + if ( strcmp( *members, uname ) == 0 ) { + return 1; + } + } + return 0; +} + int main(int argc, char *argv[]) { int userdir = 0; /* ~userdir flag */ uid_t uid; /* user information */ + uid_t httpuid; /* http user */ gid_t gid; /* target group placeholder */ + gid_t httpgid; /* http group */ char *target_uname; /* target user name */ char *target_gname; /* target group name */ char *target_homedir; /* target home directory */ + gid_t default_gid; /* Default GID for target UID*/ char *actual_uname; /* actual user name */ char *actual_gname; /* actual group name */ char *cmd; /* command to be executed */ @@ -296,7 +318,8 @@ * Check existence/validity of the UID of the user * running this program. Error out if invalid. */ - uid = getuid(); + uid = httpuid = getuid(); + httpgid = getgid(); if ((pw = getpwuid(uid)) == NULL) { log_err("crit: invalid uid: (%lu)\n", (unsigned long)uid); exit(102); @@ -465,6 +488,7 @@ uid = pw->pw_uid; actual_uname = strdup(pw->pw_name); target_homedir = strdup(pw->pw_dir); + default_gid = pw->pw_gid; if (actual_uname == NULL || target_homedir == NULL) { log_err("failed to alloc memory\n"); exit(126); @@ -498,6 +522,14 @@ } /* + * Error out if user UID is not a member of group GID. + */ + if ((gid != default_gid) && !is_group_member(actual_uname, gid)) { + log_err("crit: user does not belong to group (%s/%d/%s)\n", actual_uname, 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, @@ -548,8 +580,10 @@ } if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { - log_err("command not in docroot (%s/%s)\n", cwd, cmd); - exit(114); + if (strncmp(cwd, SUEXEC_TRUSTED_DIR, strlen(SUEXEC_TRUSTED_DIR)) != 0) { + log_err("command not in docroot and not in trustred directory (%s/%s)\n", cwd, cmd); + exit(114); + } } /* @@ -597,16 +631,41 @@ * the name/group of the cwd or the program. */ if ((uid != dir_info.st_uid) || - (gid != dir_info.st_gid) || + ((gid != dir_info.st_gid) && (dir_info.st_gid != httpgid)) || (uid != prg_info.st_uid) || - (gid != prg_info.st_gid)) { - log_err("target uid/gid (%lu/%lu) mismatch " - "with directory (%lu/%lu) or program (%lu/%lu)\n", - (unsigned long)uid, (unsigned long)gid, - (unsigned long)dir_info.st_uid, (unsigned long)dir_info.st_gid, - (unsigned long)prg_info.st_uid, (unsigned long)prg_info.st_gid); - exit(120); - } + ((gid != prg_info.st_gid) && (prg_info.st_gid != httpgid))) { + /* <--- begin changed code ap1 suexec_standard.patch ---> + * + * This patch adds a possibility to use "shared" scripts on a + * shared webhosting box. + */ +#ifdef TRUSTED_USERS_SCRIPTS + if ((atoi(SUEXEC_TRUSTED_USER) != prg_info.st_uid) || + (atoi(SUEXEC_TRUSTED_GROUP) != prg_info.st_gid)) { + if (strncmp(cwd, SUEXEC_TRUSTED_DIR, 15) != 0) { +// (strncmp(cwd, "/etc/httpd/php-bin", 25) != 0)) { + + log_err("error: target uid/gid (%ld/%ld) mismatch " + "with directory (%ld/%ld) or program (%ld/%ld) or trusted user (%d/%d)\n", + uid, gid, + dir_info.st_uid, dir_info.st_gid, + prg_info.st_uid, prg_info.st_gid, atoi(SUEXEC_TRUSTED_USER), atoi(SUEXEC_TRUSTED_GROUP)); + exit(120); + } + } +#else + log_err("target uid/gid (%lu/%lu) mismatch " + "with directory (%lu/%lu) or program (%lu/%lu)\n", + (unsigned long)uid, (unsigned long)gid, + (unsigned long)dir_info.st_uid, (unsigned long)dir_info.st_gid, + (unsigned long)prg_info.st_uid, (unsigned long)prg_info.st_gid); + exit(120); +#endif + /* + * end changed code + */ + } + /* * Error out if the program is not executable for the user. * Otherwise, she won't find any error in the logs except for diff -Naur httpd-2.4.39/support/suexec.h.orig httpd-2.4.39/support/suexec.h --- httpd-2.4.39/support/suexec.h.orig 2011-09-23 19:38:09.000000000 +0600 +++ httpd-2.4.39/support/suexec.h 2019-06-12 14:52:18.491988334 +0600 @@ -40,6 +40,33 @@ #endif /* + * READ THIS BEFORE CONTINUING!! + * + * The patch below adds a feature which makes it possible to run "shared" + * scripts. Suppose you are a systems admin for $large hosting provider and + * you want to offer your customers some standard scripts. These scripts would + * cause a security violation based on the uid owner of the script. + * + * This patch makes it possible to "trust" a certain user/group. Look below to + * define the user/group ID. + * + * Uncomment the define to make it actually happen. + * + * patch added as ap1 suexec_standard.patch clone + */ + +#define TRUSTED_USERS_SCRIPTS + +#ifdef TRUSTED_USERS_SCRIPTS +#define SUEXEC_TRUSTED_USER "0" +#define SUEXEC_TRUSTED_GROUP "10" +#endif + +#ifndef SUEXEC_TRUSTED_DIR +#define SUEXEC_TRUSTED_DIR "/etc/httpd/sys-bin" +#endif + +/* * UID_MIN -- Define this as the lowest UID allowed to be a target user * for suEXEC. For most systems, 500 or 100 is common. */