/* python-setuid.c - Wrapper for execution of Python setuid scripts * Copyright (C) 2003 Domenico Andreoli * * python-setuid.c is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * python-setuid.c is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Prua; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define PYTHON "/usr/bin/python" #define FULLPATH "/usr/libexec/nagios/check_qmailq.py" #ifndef PYTHON #error "This wrapper requires PYTHON macro be defined to specify which Python interpreter is to be used." #endif #ifndef FULLPATH #error "This wrapper requires FULLPATH macro be defined to specify which Python script is to be wrapped." #endif #include #include #include #include #include #include #include #include #if defined(__STDC__) && defined(__sgi) #define environ _environ #endif static char python[] = PYTHON; static char fullpath[] = FULLPATH; static char def_IFS[] = "IFS= \t\n"; static char def_CDPATH[] = "CDPATH=."; static char def_ENV[] = "ENV=:"; static char def_PATH[] = "PATH=/usr/bin:/bin"; /* :/usr/bin/local"; */ static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); exit(1); } /* * This function changes all environment variables that start with LD_ * into variables that start with XD_. This is important since we * don't want the script that is executed to use any funny shared * libraries. * * If IFS is set in the environment, set it to space,tab,newline. * If CDPATH is set in the environment, set it to ".". * Set PATH to a reasonable default. */ static void clean_environ(void) { char **p; extern char **environ; for(p = environ; *p; p++) { if(strncmp(*p, "LD_", 3) == 0) **p = 'X'; else if(strncmp(*p, "_RLD", 4) == 0) **p = 'X'; else if(strncmp(*p, "PYTHON", 6) == 0) **p = 'X'; else if(strncmp(*p, "IFS=", 4) == 0) *p = def_IFS; else if(strncmp(*p, "CDPATH=", 7) == 0) *p = def_CDPATH; else if(strncmp(*p, "ENV=", 4) == 0) *p = def_ENV; } putenv(def_PATH); } int main(int argc, char *argv[]) { int i; char **args, **a; struct stat statb; struct rlimit rlim; const gid_t egid = getegid(); const uid_t euid = geteuid(); args = (char**) malloc((argc+3) * sizeof(char*)); if(args == NULL) die("%s: malloc: %s\n", argv[0], strerror(errno)); a = args; *(a++) = python; if(euid != getuid() || egid != getgid()) { if(fullpath[0] != '/') die("%s: not a full path name: %s\n", argv[0], fullpath); if(stat(fullpath, &statb) < 0) die("%s: stat: %s\n", argv[0], strerror(errno)); if(statb.st_uid != 0 && statb.st_uid != euid) die("%s: wrong owner: %s\n", argv[0], fullpath); clean_environ(); umask(077); rlim.rlim_cur = 0; rlim.rlim_max = 0; if(setrlimit(RLIMIT_CORE, &rlim) < 0) die("%s: setrlimit: %s\n", argv[0], strerror(errno)); #ifdef PYTHON_VERSION /* the -E switch has been added in version 2.2 */ if(strcmp(PYTHON_VERSION, "2.2") >= 0) { /* this should be superfluous given the castrated environment */ *(a++) = "-E"; } #endif } *(a++) = fullpath; for(i = 1; argv[i] != NULL; i++) *(a++) = argv[i]; *a = NULL; execv(python, args); die("%s: unable to execute %s: %s\n", argv[0], fullpath, strerror(errno)); return 1; }