#include #include #include #include #include #include #include #define MAXPGPATH 1024 int DebugLvl = 2; #ifndef S_IRUSR /* XXX [TRH] should be in a header */ #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #define S_IXUSR S_IEXEC #define S_IRGRP ((S_IRUSR)>>3) #define S_IWGRP ((S_IWUSR)>>3) #define S_IXGRP ((S_IXUSR)>>3) #define S_IROTH ((S_IRUSR)>>6) #define S_IWOTH ((S_IWUSR)>>6) #define S_IXOTH ((S_IXUSR)>>6) #endif static int ValidateBinary(char *path); int main(int argc, char* argv[]) { int s = ValidateBinary(argv[1]); printf("ValidateBinary() = %d\n", s); } /* * ValidateBinary -- validate "path" as a POSTMASTER/POSTGRES executable file * * returns 0 if the file is found and no error is encountered. * -1 if the regular file "path" does not exist or cannot be executed. * -2 if the file is otherwise valid but cannot be read. */ static int ValidateBinary(char *path) { struct stat buf; uid_t euid; struct group *gp; struct passwd *pwp; int i; int is_r = 0; int is_x = 0; int in_grp = 0; /* * Ensure that the file exists and is a regular file. * * XXX if you have a broken system where stat() looks at the symlink * instead of the underlying file, you lose. */ if (strlen(path) >= MAXPGPATH) { if (DebugLvl > 1) fprintf(stderr, "ValidateBinary: pathname \"%s\" is too long\n", path); return -1; } if (stat(path, &buf) < 0) { if (DebugLvl > 1) fprintf(stderr, "ValidateBinary: can't stat \"%s\"\n", path); return -1; } if (!(buf.st_mode & S_IFREG)) { if (DebugLvl > 1) fprintf(stderr, "ValidateBinary: \"%s\" is not a regular file\n", path); return -1; } /* * Ensure that we are using an authorized backend. * * XXX I'm open to suggestions here. I would like to enforce ownership * of binaries by user "postgres" but people seem to like to run as * users other than "postgres"... */ /* * Ensure that the file is both executable and readable (required for * dynamic loading). * * We use the effective uid here because the backend will not have * executed setuid() by the time it calls this routine. */ euid = geteuid(); if (euid == buf.st_uid) { is_r = buf.st_mode & S_IRUSR; is_x = buf.st_mode & S_IXUSR; if (DebugLvl > 1 && !(is_r && is_x)) fprintf(stderr, "ValidateBinary: \"%s\" is not user read/execute\n", path); return is_x ? (is_r ? 0 : -2) : -1; } pwp = getpwuid(euid); if (pwp) { if (pwp->pw_gid == buf.st_gid) ++in_grp; else if (pwp->pw_name && (gp = getgrgid(buf.st_gid))) { for (i = 0; gp->gr_mem[i]; ++i) { if (!strcmp(gp->gr_mem[i], pwp->pw_name)) { ++in_grp; break; } } } if (in_grp) { is_r = buf.st_mode & S_IRGRP; is_x = buf.st_mode & S_IXGRP; if (DebugLvl > 1 && !(is_r && is_x)) fprintf(stderr, "ValidateBinary: \"%s\" is not group read/execute\n", path); return is_x ? (is_r ? 0 : -2) : -1; } } is_r = buf.st_mode & S_IROTH; is_x = buf.st_mode & S_IXOTH; if (DebugLvl > 1 && !(is_r && is_x)) fprintf(stderr, "ValidateBinary: \"%s\" is not other read/execute\n", path); return is_x ? (is_r ? 0 : -2) : -1; }