/* Change the ownership and access permission of the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ int grantpt (int fd) { int retval = -1; #ifdef PATH_MAX char _buf[PATH_MAX]; #else char _buf[512]; #endif char *buf = _buf; struct stat64 st; if (__glibc_unlikely (pts_name (fd, &buf, sizeof (_buf), &st))) { int save_errno = errno; /* Check, if the file descriptor is valid. pts_name returns the wrong errno number, so we cannot use that. */ if (__libc_fcntl (fd, F_GETFD) == -1 && errno == EBADF) return -1; /* If the filedescriptor is no TTY, grantpt has to set errno to EINVAL. */ if (save_errno == ENOTTY) __set_errno (EINVAL); else __set_errno (save_errno); return -1; } /* Make sure that we own the device. */ uid_t uid = __getuid (); if (st.st_uid != uid) { if (__chown (buf, uid, st.st_gid) < 0) goto helper; } static int tty_gid = -1; if (__glibc_unlikely (tty_gid == -1)) { char *grtmpbuf; struct group grbuf; size_t grbuflen = __sysconf (_SC_GETGR_R_SIZE_MAX); struct group *p; /* Get the group ID of the special `tty' group. */ if (grbuflen == (size_t) -1L) /* `sysconf' does not support _SC_GETGR_R_SIZE_MAX. Try a moderate value. */ grbuflen = 1024; grtmpbuf = (char *) __alloca (grbuflen); __getgrnam_r (TTY_GROUP, &grbuf, grtmpbuf, grbuflen, &p); if (p != NULL) tty_gid = p->gr_gid; } gid_t gid = tty_gid == -1 ? __getgid () : tty_gid; /* Make sure the group of the device is that special group. */ if (st.st_gid != gid) { if (__chown (buf, uid, gid) < 0) goto helper; } /* Make sure the permission mode is set to readable and writable by the owner, and writable by the group. */ if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP)) { if (__chmod (buf, S_IRUSR|S_IWUSR|S_IWGRP) < 0) goto helper; } retval = 0; goto cleanup; /* We have to use the helper program if it is available. */ helper:; #ifdef HAVE_PT_CHOWN pid_t pid = __fork (); if (pid == -1) goto cleanup; else if (pid == 0) { /* Disable core dumps. */ struct rlimit rl = { 0, 0 }; __setrlimit (RLIMIT_CORE, &rl); /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */ if (fd != PTY_FILENO) if (__dup2 (fd, PTY_FILENO) < 0) _exit (FAIL_EBADF); # ifdef CLOSE_ALL_FDS CLOSE_ALL_FDS (); # endif execle (_PATH_PT_CHOWN, basename (_PATH_PT_CHOWN), NULL, NULL); _exit (FAIL_EXEC); } else { int w; if (__waitpid (pid, &w, 0) == -1) goto cleanup; if (!WIFEXITED (w)) __set_errno (ENOEXEC); else switch (WEXITSTATUS (w)) { case 0: retval = 0; break; case FAIL_EBADF: __set_errno (EBADF); break; case FAIL_EINVAL: __set_errno (EINVAL); break; case FAIL_EACCES: __set_errno (EACCES); break; case FAIL_EXEC: __set_errno (ENOEXEC); break; case FAIL_ENOMEM: __set_errno (ENOMEM); break; default: assert(! "getpt: internal error: invalid exit code from pt_chown"); } } #endif cleanup: if (buf != _buf) free (buf); return retval; }
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; }