struct passwd* getpwnam (const char* name) { struct passwd* result; if (__getpwnam_r (name, &passwd, buf, 1024, &result) != 0) return NULL; return result; }
int mtev_security_usergroup(const char *user, const char *group, mtev_boolean effective) { static long pwnam_buflen = 0; static long grnam_buflen = 0; uid_t uid = 0; gid_t gid = 0; if(pwnam_buflen == 0) #ifdef _SC_GETPW_R_SIZE_MAX pwnam_buflen = sysconf(_SC_GETPW_R_SIZE_MAX); #else pwnam_buflen = 100; /* This shouldn't be used, so size is not important. */ #endif if(grnam_buflen == 0) #ifdef _SC_GETGR_R_SIZE_MAX grnam_buflen = sysconf(_SC_GETGR_R_SIZE_MAX); #else grnam_buflen = 100; #endif if(user) { if(isuinteger(user)) uid = atoi(user); else { struct passwd *pw, _pw; char *buf; if(NULL == (buf = alloca(pwnam_buflen))) BAIL("alloca failed\n"); if(NULL == (pw = __getpwnam_r(user, &_pw, buf, pwnam_buflen))) BAIL("Cannot find user '%s'\n", user); uid = pw->pw_uid; } } if(group) { if(isuinteger(group)) gid = atoi(group); else { struct group *gr, _gr; char *buf; if(NULL == (buf = alloca(grnam_buflen))) BAIL("alloca failed\n"); if(NULL == (gr = __getgrnam_r(group, &_gr, buf, grnam_buflen))) BAIL("Cannot find group '%s'\n", group); gid = gr->gr_gid; } } if(!user && !group) return 0; #if defined(CAP_SUPPORTED) && defined(HAVE_SETPPRIV) if(!effective && getpflags(PRIV_AWARE)) { int rv; priv_set_t *set; set = priv_allocset(); priv_addset(set, "proc_setid"); rv = setppriv(PRIV_ON, PRIV_EFFECTIVE, set); priv_freeset(set); if(rv) BAIL("setppriv(proc_setid) failed"); } #endif if(group) { if(!effective && gid == 0) BAIL("Cannot use this function to setgid(0)\n"); if((effective ? setegid(gid) : setgid(gid)) != 0) BAIL("setgid(%d) failed: %s\n", (int)gid, strerror(errno)); } if(user) { if(!effective && uid == 0) BAIL("Cannot use this function to setuid(0)\n"); if((effective ? seteuid(uid) : setuid(uid)) != 0) BAIL("setgid(%d) failed: %s\n", (int)gid, strerror(errno)); if(!effective) { #if defined(CAP_SUPPORTED) && defined(HAVE_SETPPRIV) if(getpflags(PRIV_AWARE)) { int rv; priv_set_t *set; set = priv_allocset(); priv_addset(set, "proc_setid"); rv = setppriv(PRIV_OFF, PRIV_EFFECTIVE, set); if(rv) BAIL("setppriv(off, effective, proc_setid) failed"); getppriv(PRIV_EFFECTIVE, set); rv = setppriv(PRIV_SET, PRIV_PERMITTED, set); if(rv) BAIL("setppriv(effective -> permitted) failed"); priv_freeset(set); } #endif if(setuid(0) == 0) BAIL("setuid(0) worked, and it shouldn't have.\n"); if(setgid(0) == 0) BAIL("setgid(0) worked, and it shouldn't have.\n"); } } return 0; }