1#include <stdlib.h> 2#include <stdio.h> 3#include <string.h> 4#include <unistd.h> 5#include <sys/types.h> 6#include <sys/stat.h> 7#include <fcntl.h> 8#include <dirent.h> 9#include <assert.h> 10#include <string.h> 11#include <errno.h> 12 13/* Make sure assertions are not compiled out. */ 14#undef NDEBUG 15 16extern char **environ; 17 18static char * wrapperDir = WRAPPER_DIR; 19 20int main(int argc, char * * argv) 21{ 22 char self[PATH_MAX]; 23 24 int len = readlink("/proc/self/exe", self, sizeof(self) - 1); 25 assert (len > 0); 26 self[len] = 0; 27 28 /* Make sure that we are being executed from the right location, 29 i.e., `wrapperDir'. This is to prevent someone from 30 creating hard link `X' from some other location, along with a 31 false `X.real' file, to allow arbitrary programs from being 32 executed setuid. */ 33 assert ((strncmp(self, wrapperDir, strlen(wrapperDir)) == 0) && 34 (self[strlen(wrapperDir)] == '/')); 35 36 /* Make *really* *really* sure that we were executed as `self', 37 and not, say, as some other setuid program. That is, our 38 effective uid/gid should match the uid/gid of `self'. */ 39 //printf("%d %d\n", geteuid(), getegid()); 40 41 struct stat st; 42 assert (lstat(self, &st) != -1); 43 44 //printf("%d %d\n", st.st_uid, st.st_gid); 45 46 assert ((st.st_mode & S_ISUID) == 0 || 47 (st.st_uid == geteuid())); 48 49 assert ((st.st_mode & S_ISGID) == 0 || 50 st.st_gid == getegid()); 51 52 /* And, of course, we shouldn't be writable. */ 53 assert (!(st.st_mode & (S_IWGRP | S_IWOTH))); 54 55 56 /* Read the path of the real (wrapped) program from <self>.real. */ 57 char realFN[PATH_MAX + 10]; 58 int realFNSize = snprintf (realFN, sizeof(realFN), "%s.real", self); 59 assert (realFNSize < sizeof(realFN)); 60 61 int fdSelf = open(realFN, O_RDONLY); 62 assert (fdSelf != -1); 63 64 char real[PATH_MAX]; 65 len = read(fdSelf, real, PATH_MAX); 66 assert (len != -1); 67 assert (len < sizeof (real)); 68 assert (len > 0); 69 real[len] = 0; 70 71 close(fdSelf); 72 73 //printf("real = %s, len = %d\n", real, len); 74 75 execve(real, argv, environ); 76 77 fprintf(stderr, "%s: cannot run `%s': %s\n", 78 argv[0], real, strerror(errno)); 79 80 exit(1); 81}