From 5fd3f5e07cd61589d913b1ddc9db4c0fb084c02a Mon Sep 17 00:00:00 2001 From: Andrew McNab Date: Thu, 26 May 2005 21:14:21 +0000 Subject: [PATCH] Patch gridmapdir code into gsexec --- org.gridsite.core/CHANGES | 4 + org.gridsite.core/doc/httpd-fileserver.conf | 4 +- org.gridsite.core/doc/httpd-webserver.conf | 4 +- org.gridsite.core/src/Makefile | 2 +- org.gridsite.core/src/grst_x509.c | 2 +- org.gridsite.core/src/gsexec.c | 370 ++++++++++++++++++++++++++-- org.gridsite.core/src/gsexec.h | 33 ++- 7 files changed, 392 insertions(+), 27 deletions(-) diff --git a/org.gridsite.core/CHANGES b/org.gridsite.core/CHANGES index 9b86237..a9a305e 100644 --- a/org.gridsite.core/CHANGES +++ b/org.gridsite.core/CHANGES @@ -1,3 +1,7 @@ +* Thu May 26 2005 Andrew McNab +- Include gsexec, a drop-in replacement for suexec, + which can do suexec execution of CGI programs or + pool-account mapping based on client DN. * Tue May 24 2005 Andrew McNab - ==== GridSite version 1.1.9 ==== * Mon Apr 25 2005 Andrew McNab diff --git a/org.gridsite.core/doc/httpd-fileserver.conf b/org.gridsite.core/doc/httpd-fileserver.conf index 9bd51e2..192d9e3 100644 --- a/org.gridsite.core/doc/httpd-fileserver.conf +++ b/org.gridsite.core/doc/httpd-fileserver.conf @@ -123,6 +123,8 @@ Listen 80 # Secured and possibly authenticated HTTPS on port 443 ###################################################################### Listen 443 +SSLSessionCache dbm:/var/cache/mod_ssl/scache +SSLSessionCacheTimeout 300 SSLEngine on @@ -130,8 +132,6 @@ SSLCertificateFile /etc/grid-security/hostcert.pem SSLCertificateKeyFile /etc/grid-security/hostkey.pem SSLCACertificatePath /etc/grid-security/certificates #SSLCARevocationPath YOUR CRL DIRECTORY WOULD GO HERE -SSLSessionCache dbm:/var/cache/mod_ssl/scache -SSLSessionCacheTimeout 300 SSLVerifyClient optional SSLVerifyDepth 10 SSLOptions +ExportCertData +StdEnvVars diff --git a/org.gridsite.core/doc/httpd-webserver.conf b/org.gridsite.core/doc/httpd-webserver.conf index da332a0..e2e03ff 100644 --- a/org.gridsite.core/doc/httpd-webserver.conf +++ b/org.gridsite.core/doc/httpd-webserver.conf @@ -153,6 +153,8 @@ ScriptAlias /real-gridsite-admin.cgi /usr/sbin/real-gridsite-admin.cgi # Secured and possibly authenticated HTTPS on port 443 ###################################################################### Listen 443 +SSLSessionCache dbm:/var/cache/mod_ssl/scache +SSLSessionCacheTimeout 300 SSLEngine on @@ -160,8 +162,6 @@ SSLCertificateFile /etc/grid-security/hostcert.pem SSLCertificateKeyFile /etc/grid-security/hostkey.pem SSLCACertificatePath /etc/grid-security/certificates #SSLCARevocationPath YOUR CRL DIRECTORY WOULD GO HERE -SSLSessionCache dbm:/var/cache/mod_ssl/scache -SSLSessionCacheTimeout 300 SSLVerifyClient optional SSLVerifyDepth 10 SSLOptions +ExportCertData +StdEnvVars diff --git a/org.gridsite.core/src/Makefile b/org.gridsite.core/src/Makefile index bd14ba4..234cd8a 100644 --- a/org.gridsite.core/src/Makefile +++ b/org.gridsite.core/src/Makefile @@ -136,7 +136,7 @@ libgridsite_globus.a: libgridsite.a endif -gsexec: gsexec.c +gsexec: gsexec.c gsexec.h gcc -DVERSION=\"$(PATCH_VERSION)\" -I/usr/include/httpd \ -I/usr/include/apr-0 \ -o gsexec gsexec.c diff --git a/org.gridsite.core/src/grst_x509.c b/org.gridsite.core/src/grst_x509.c index ec2b385..942dd7e 100644 --- a/org.gridsite.core/src/grst_x509.c +++ b/org.gridsite.core/src/grst_x509.c @@ -1412,7 +1412,7 @@ int GRSTx509CacheProxy(char *proxydir, char *delegation_id, return GRST_RET_FAILED; } - fprintf(stderr, "\n\n\n\n PROXYCHAIN = \n %s", proxychain); +// fprintf(stderr, "\n\n\n\n PROXYCHAIN = \n %s", proxychain); if (GRSTx509StringToChain(&certstack, proxychain) != GRST_RET_OK) return GRST_RET_FAILED; diff --git a/org.gridsite.core/src/gsexec.c b/org.gridsite.core/src/gsexec.c index a9abf9f..eeec524 100644 --- a/org.gridsite.core/src/gsexec.c +++ b/org.gridsite.core/src/gsexec.c @@ -245,10 +245,280 @@ static void clean_env(void) environ = cleanenv; } +/* Pool account functions */ + + +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** +Function: mapdir_otherlink +Description: + find another link in map directory to the same inode as firstlink + and change the modification time of firstlink to now (so that we + always know when this pair was last used) + +Parameters: + firstlink, the filename of the link we already know + +Returns: + a pointer to the other link's filename (without path) or NULL if none + found (this is malloc'd and will need freeing) + +******************************************************************************/ +static char *mapdir_otherlink(char *mapdir, char *firstlink) +{ + int ret; + char *firstlinkpath, *otherlinkdup, *otherlinkpath; + struct dirent *mapdirentry; + DIR *mapdirstream; + struct stat statbuf; + ino_t firstinode; + + firstlinkpath = malloc(strlen(mapdir) + 2 + strlen(firstlink)); + sprintf(firstlinkpath, "%s/%s", mapdir, firstlink); + ret = stat(firstlinkpath, &statbuf); + free(firstlinkpath); + if (ret != 0) return NULL; + if (statbuf.st_nlink != 2) return NULL; + + firstinode = statbuf.st_ino; /* save for comparisons */ + + mapdirstream = opendir(mapdir); + + if (mapdirstream != NULL) + { + while ((mapdirentry = readdir(mapdirstream)) != NULL) + { + if (strcmp(mapdirentry->d_name, firstlink) == 0) continue; + + otherlinkpath = malloc(strlen(mapdir) + 2 + + strlen(mapdirentry->d_name)); + sprintf(otherlinkpath, "%s/%s", mapdir, + mapdirentry->d_name); + + ret = stat(otherlinkpath, &statbuf); + if ((ret == 0) && (statbuf.st_ino == firstinode)) + { + utime(otherlinkpath, (struct utimbuf *) NULL); + free(otherlinkpath); + otherlinkdup = strdup(mapdirentry->d_name); + closedir(mapdirstream); + return otherlinkdup; + } + else free(otherlinkpath); + } + + closedir(mapdirstream); + } + + return NULL; +} + +/****************************************************************************** +Function: mapdir_urlencode +Description: + Convert string to URL encoded and return pointer to the encoded + version, obtained through malloc. Calling routine must free + this. Here "URL encoded" means anything other than an isalnum() + goes to %HH where HH is its ascii value in hex; also A-Z => a-z + This name is suitable for filenames since no / or spaces. + +Parameters: + rawstring, the string to be converted + +Returns: + a pointer to the encoded string or NULL if the malloc failed + +******************************************************************************/ +static char *mapdir_urlencode(char *rawstring) +{ + int encodedchar = 0, rawchar = 0; + char * encodedstring; + + encodedstring = (char *) malloc(3 * strlen(rawstring) + 1); + + if (encodedstring == NULL) return (char *) NULL; + + while (rawstring[rawchar] != '\0') + { + if (isalnum(rawstring[rawchar])) + { + encodedstring[encodedchar] = tolower(rawstring[rawchar]); + ++rawchar; + ++encodedchar; + } + else + { + sprintf(&encodedstring[encodedchar], "%%%02x", + rawstring[rawchar]); + ++rawchar; + encodedchar = encodedchar + 3; + } + } + + encodedstring[encodedchar] = '\0'; + + return encodedstring; +} + +/****************************************************************************** +Function: mapdir_newlease +Description: + Search for an unleased local username to give to the X.509 DN or + directory key corresponding to encodedfilename, and then lease it. + +Parameters: + encodedfilename, URL-encoded X.509 DN or directory key to associate + with an unlease pool username + +Returns: + no return value +******************************************************************************/ + +void mapdir_newlease(char *mapdir, char *encodedkey) +{ + int ret; + char *userfilename, *encodedfilename; + struct dirent *mapdirentry; + DIR *mapdirstream; + struct stat statbuf; + + encodedfilename = malloc(strlen(mapdir) + (size_t) 2 + + strlen(encodedkey)); + sprintf(encodedfilename, "%s/%s", mapdir, encodedkey); + + mapdirstream = opendir(mapdir); + + while ((mapdirentry = readdir(mapdirstream)) != NULL) + { + /* we dont want any files that dont look like acceptable usernames */ + if ((*(mapdirentry->d_name) == '%') || + (strcmp(mapdirentry->d_name, "root") == 0)) continue; + else if (*(mapdirentry->d_name) == '.') continue; + else if (index(mapdirentry->d_name, '~') != NULL) continue; + + userfilename = malloc(strlen(mapdir) + (size_t) 2 + + strlen(mapdirentry->d_name)); + sprintf(userfilename, "%s/%s", mapdir, mapdirentry->d_name); + stat(userfilename, &statbuf); + + if (statbuf.st_nlink == 1) /* this one isnt leased yet */ + { + ret = link(userfilename, encodedfilename); + free(userfilename); + if (ret != 0) + { + /* link failed: this is probably because a VERY lucky + other process has obtained a lease for encodedfilename + while we were faffing around */ + closedir(mapdirstream); + free(encodedfilename); + return; + } + + stat(encodedfilename, &statbuf); + if (statbuf.st_nlink > 2) + { + /* two keys have grabbed the same username: back off */ + unlink(encodedfilename); + continue; + } + + closedir(mapdirstream); + free(encodedfilename); + return; /* link worked ok, so return */ + } + else free(userfilename); /* already in use, try next one */ + } + + closedir(mapdirstream); + free(encodedfilename); + return; /* no unleased names left: give up */ +} + +/****************************************************************************** +Function: gridmapdir_userid +Description: + This is equivalent to globus_gss_assist_gridmap but for the dynamic + user ids in the gridmapdir: maps a globusID to a local unix user id, + either one already leased, or calls gridmapdir_newlease() to obtain + a new lease. This is called by globus_gss_assist_gridmap if the + local user id in the static gridmap file begins . (for a dynamic id) + +Parameters: + globusidp, globus client name who requested authentication + usernameprefix, prefix of the local usernames which would + be acceptable (or "\0" ) + *userid returned userid name for local system. + +Returns: + + 0 on success + !=0 on failure + +******************************************************************************/ + + + int GRSTexecGetMapping(char **target_uname, char **target_gname, - char *map_x509dn) + char *mapdir, char *key) { - return 1; + char *encodedkey; + + if (key[0] != '/') return 1; /* must be a proper X.509 DN or path */ + + encodedkey = mapdir_urlencode(key); +log_err("encodedkey=%s\n", encodedkey); + *target_uname = mapdir_otherlink(mapdir, encodedkey); +log_err("*target_uname=%s\n", *target_uname); + + if (*target_uname == NULL) /* maybe no lease yet */ + { + mapdir_newlease(mapdir, encodedkey); + /* try making a lease */ + + *target_uname = mapdir_otherlink(mapdir, encodedkey); + /* check if there is a now a lease - possibly made by someone else */ + + if (*target_uname == NULL) + { + free(encodedkey); + return 1; /* still no good */ + } + } + + free(encodedkey); + +// nasty hack for now +*target_gname = strdup(*target_uname); + + return 0; +} + +void internal_server_error(void) +{ + /* use this when its probably an httpd.conf configuration error */ + + puts("Status: 500 Internal Server Error\n" + "Content-Type: text/html\n\n" + "500 Internal Server Error\n" + "

Internal Server Error

"); +} + +void forbidden_error(void) +{ + /* use this when unix file permissions/ownerships are probably wrong */ + + puts("Status: 403 Forbidden\n" + "Content-Type: text/html\n\n" + "403 Forbidden\n" + "

Forbidden

"); } int main(int argc, char *argv[]) @@ -256,6 +526,8 @@ int main(int argc, char *argv[]) int userdir = 0; /* ~userdir flag */ uid_t uid; /* user information */ gid_t gid; /* target group placeholder */ + uid_t httpd_uid; /* uid for AP_HTTPD_USER */ + gid_t httpd_gid; /* uid for AP_HTTPD_GROUP */ char *mapping_type; /* suexec / X509DN / directory */ char *map_x509dn; /* DN to use as pool acct. key */ char *map_directory; /* directory as pool acct. key */ @@ -286,6 +558,17 @@ int main(int argc, char *argv[]) uid = getuid(); if ((pw = getpwuid(uid)) == NULL) { log_err("crit: invalid uid: (%ld)\n", uid); + internal_server_error(); + exit(102); + } + /* + * Check existence/validity of the GID of the user + * running this program. Error out if invalid. + */ + gid = getgid(); + if ((gr = getgrgid(gid)) == NULL) { + log_err("crit: invalid gid: (%ld)\n", gid); + internal_server_error(); exit(102); } /* @@ -334,10 +617,12 @@ int main(int argc, char *argv[]) */ if (argc < 4) { log_err("too few arguments\n"); + internal_server_error(); exit(101); } mapping_type = getenv("GRST_EXEC_MAPPING"); +log_err("mapping_type=%s\n",mapping_type); if ((mapping_type == NULL) || (mapping_type[0] == '\0') || (strcasecmp(mapping_type, "suexec") == 0)) @@ -348,18 +633,22 @@ int main(int argc, char *argv[]) } else if (strcasecmp(mapping_type, "X509DN") == 0) { +log_err("X509DN mapping type\n"); map_x509dn = getenv("SSL_CLIENT_S_DN"); if (map_x509dn == NULL) { log_err("No SSL_CLIENT_S_DN despite X509DN mapping\n"); + internal_server_error(); exit(151); } - if (GRSTexecGetMapping(&target_uname, &target_gname, map_x509dn) + if (GRSTexecGetMapping(&target_uname, &target_gname, + GRST_EXECMAPDIR, map_x509dn) != 0) { log_err("GRSTexecGetMapping() failed mapping \"%s\"\n", map_x509dn); + internal_server_error(); exit(152); } } @@ -369,20 +658,24 @@ int main(int argc, char *argv[]) if (map_directory == NULL) { log_err("No GRST_EXEC_MAP_DIR despite directory mapping\n"); + internal_server_error(); exit(153); } - if (GRSTexecGetMapping(&target_uname, &target_gname, map_directory) + if (GRSTexecGetMapping(&target_uname, &target_gname, + GRST_EXECMAPDIR, map_directory) != 0) { log_err("GRSTexecGetMapping() failed mapping \"%s\"\n", map_directory); + internal_server_error(); exit(154); } } else { log_err("mapping type \"%s\" not recognised\n", mapping_type); + internal_server_error(); exit(155); } @@ -397,15 +690,33 @@ int main(int argc, char *argv[]) /* 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); + internal_server_error(); + exit(103); + } + /* User name comparisons are case insensitive on BS2000/OSD */ + if (strcasecmp(AP_HTTPD_GROUP, gr->gr_name)) { + log_err("group mismatch (%s instead of %s)\n", gr->gr_name, AP_HTTPD_GROUP); + internal_server_error(); 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); + internal_server_error(); + exit(103); + } + if (strcmp(AP_HTTPD_GROUP, gr->gr_name)) { + log_err("group mismatch (%s instead of %s)\n", gr->gr_name, AP_HTTPD_GROUP); + internal_server_error(); exit(103); } #endif /*_OSD_POSIX*/ + /* Since they match (via name) save these for later */ + + httpd_uid = uid; + httpd_gid = gid; + /* * Check for a leading '/' (absolute path) in the command to be executed, * or attempts to back up out of the current directory, @@ -415,6 +726,7 @@ int main(int argc, char *argv[]) if ((cmd[0] == '/') || (!strncmp(cmd, "../", 3)) || (strstr(cmd, "/../") != NULL)) { log_err("invalid command (%s)\n", cmd); + internal_server_error(); exit(104); } @@ -434,12 +746,14 @@ int main(int argc, char *argv[]) if (strspn(target_uname, "1234567890") != strlen(target_uname)) { if ((pw = getpwnam(target_uname)) == NULL) { log_err("invalid target user name: (%s)\n", target_uname); + internal_server_error(); exit(105); } } else { if ((pw = getpwuid(atoi(target_uname))) == NULL) { log_err("invalid target user id: (%s)\n", target_uname); + internal_server_error(); exit(121); } } @@ -450,6 +764,7 @@ int main(int argc, char *argv[]) if (strspn(target_gname, "1234567890") != strlen(target_gname)) { if ((gr = getgrnam(target_gname)) == NULL) { log_err("invalid target group name: (%s)\n", target_gname); + internal_server_error(); exit(106); } gid = gr->gr_gid; @@ -472,6 +787,7 @@ int main(int argc, char *argv[]) case -1: /* Error */ log_err("failed to setup bs2000 environment for user %s: %s\n", target_uname, strerror(errno)); + internal_server_error(); exit(150); case 0: /* Child */ break; @@ -482,6 +798,7 @@ int main(int argc, char *argv[]) if (WIFSIGNALED(status)) { kill (getpid(), WTERMSIG(status)); } + internal_server_error(); exit(WEXITSTATUS(status)); } } @@ -509,6 +826,7 @@ int main(int argc, char *argv[]) */ if ((uid == 0) || (uid < AP_UID_MIN)) { log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd); + internal_server_error(); exit(107); } @@ -518,6 +836,7 @@ int main(int argc, char *argv[]) */ if ((gid == 0) || (gid < AP_GID_MIN)) { log_err("cannot run as forbidden gid (%d/%s)\n", gid, cmd); + internal_server_error(); exit(108); } @@ -529,6 +848,7 @@ int main(int argc, char *argv[]) */ if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) { log_err("failed to setgid (%ld: %s)\n", gid, cmd); + internal_server_error(); exit(109); } @@ -537,6 +857,7 @@ int main(int argc, char *argv[]) */ if ((setuid(uid)) != 0) { log_err("failed to setuid (%ld: %s)\n", uid, cmd); + internal_server_error(); exit(110); } @@ -550,15 +871,18 @@ int main(int argc, char *argv[]) */ if (getcwd(cwd, AP_MAXPATH) == NULL) { log_err("cannot get current working directory\n"); + internal_server_error(); exit(111); } +#if 0 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); + internal_server_error(); exit(112); } } @@ -567,20 +891,24 @@ int main(int argc, char *argv[]) ((getcwd(dwd, AP_MAXPATH)) == NULL) || ((chdir(cwd)) != 0)) { log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT); + internal_server_error(); exit(113); } } if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { log_err("command not in docroot (%s/%s)\n", cwd, cmd); + internal_server_error(); exit(114); } +#endif /* * 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); + internal_server_error(); exit(115); } @@ -589,6 +917,7 @@ int main(int argc, char *argv[]) */ if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) { log_err("directory is writable by others: (%s)\n", cwd); + forbidden_error(); exit(116); } @@ -597,14 +926,16 @@ int main(int argc, char *argv[]) */ if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) { log_err("cannot stat program: (%s)\n", cmd); + forbidden_error(); exit(117); } /* * Error out if the program is writable by others. */ - if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) { + if (prg_info.st_mode & S_IWOTH) { log_err("file is writable by others: (%s/%s)\n", cwd, cmd); + forbidden_error(); exit(118); } @@ -613,24 +944,33 @@ int main(int argc, char *argv[]) */ 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); + forbidden_error(); exit(119); } /* * Error out if the target name/group is different from - * the name/group of the cwd or the program. + * the name/group of the cwd or the program AND the name/group + * of the cwd and program are not the AP_HTTPD_USER/AP_HTTPD_GROUP + * AND the name/group of the cwd and program are not root */ - 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, + if (((uid != dir_info.st_uid) && (httpd_uid != dir_info.st_uid) + && (0 != dir_info.st_uid)) || + ((gid != dir_info.st_gid) && (httpd_gid != dir_info.st_gid) + && (0 != dir_info.st_gid)) || + ((uid != prg_info.st_uid) && (httpd_uid != prg_info.st_uid) + && (0 != prg_info.st_uid)) || + ((gid != prg_info.st_gid) && (httpd_gid != prg_info.st_gid) + && (0 != prg_info.st_gid))) + { + log_err("target (%ld/%ld) or %s (%ld/%ld) or root (0/0) uid/gid " + "mismatch with directory (%ld/%ld) or program (%ld/%ld)\n", + uid, gid, AP_HTTPD_USER, httpd_uid, httpd_gid, dir_info.st_uid, dir_info.st_gid, prg_info.st_uid, prg_info.st_gid); + forbidden_error(); 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 @@ -638,6 +978,7 @@ int main(int argc, char *argv[]) */ if (!(prg_info.st_mode & S_IXUSR)) { log_err("file has no execute permission: (%s/%s)\n", cwd, cmd); + forbidden_error(); exit(121); } @@ -689,5 +1030,6 @@ int main(int argc, char *argv[]) * Oh well, log the failure and error out. */ log_err("(%d)%s: exec failed (%s)\n", errno, strerror(errno), cmd); + internal_server_error(); exit(255); } diff --git a/org.gridsite.core/src/gsexec.h b/org.gridsite.core/src/gsexec.h index e76a3bb..b777421 100644 --- a/org.gridsite.core/src/gsexec.h +++ b/org.gridsite.core/src/gsexec.h @@ -34,24 +34,37 @@ * this program. */ #ifndef AP_HTTPD_USER -#define AP_HTTPD_USER "www" +#define AP_HTTPD_USER "apache" +#endif + +/* + * HTTPD_GROUP -- Define as the group under which Apache normally + * runs. This is the only user allowed to execute + * this program. + */ +#ifndef AP_HTTPD_GROUP +#define AP_HTTPD_GROUP "apache" #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. + * for suEXEC. For most systems, 500 or 100 is common, but + * 99 will include user nobody on RedHat Linux systems. */ -#ifndef AP_UID_MIN -#define AP_UID_MIN 100 +#ifdef AP_UID_MIN +#undef AP_UID_MIN #endif +#define AP_UID_MIN 99 /* * GID_MIN -- Define this as the lowest GID allowed to be a target group - * for suEXEC. For most systems, 100 is common. + * for suEXEC. For most systems, 100 is common, but 99 will + * include group nobody on RedHat Linux systems. */ -#ifndef AP_GID_MIN -#define AP_GID_MIN 100 +#ifdef AP_GID_MIN +#undef AP_GID_MIN #endif +#define AP_GID_MIN 99 /* * USERDIR_SUFFIX -- Define to be the subdirectory under users' @@ -104,4 +117,10 @@ #define AP_SAFE_PATH "/usr/local/bin:/usr/bin:/bin" #endif +/* + * GRST_EXECMAPDIR -- Location of the gridmapdir-style directory of lock files + * + */ +#define GRST_EXECMAPDIR "/var/www/execmapdir" + #endif /* _SUEXEC_H */ -- 1.8.2.3