die("setgroups");
}
if (getgroups(0, NULL) != 0) {
- die_fmt("failed to drop all groups");
+ die_fmt("failed to drop all supplementary groups");
}
/* Dropping groups may require privileges, do that first. */
if (ppoll(fds, nfds, NULL /* no timeout */, &sigset_old) == -1) {
if (errno == EAGAIN || errno == EINTR) {
continue;
- } else {
- perror("poll");
}
+ perror("poll");
break;
}
/* Handle errors first. (Data available before the error occurred
- * might be skipped, but shouldn't matter here.) */
+ * might be dropped, but shouldn't matter here.) */
if (fds[0].revents & (POLLERR | POLLNVAL)) {
fprintf(stderr, "poll: error on master: %d\n", fds[0].revents);
break;
if (pid == -1) {
die("fork child");
} else if (pid == 0) {
+ /* Drop the privileges just now so that the other user doesn't get
+ * access to the master TTY or the session leader (which might
+ * have additional privileges). */
drop_privileges_or_die(uid, gid);
dup2_or_die(pty_slave, STDIN_FILENO);
}
const char *home = passwd->pw_dir;
+ // Ignore errors here as we don't want to die on non-existent home
+ // directories to allow running as any user (think "/nonexistent"
+ // as home) and an error message will be annoying to ignore when
+ // running this command in scripts.
+ chdir(home);
+
char envp_user[strlen("USER=") + strlen(user) + 1];
char envp_home[strlen("HOME=") + strlen(home) + 1];
char envp_term[strlen("TERM=") + strlen(term) + 1];
die("tcsetattr restore");
}
- /* Wait until we got the status code from our child. poll() might also
+ /* Wait until we got the status code from our child. poll() might already
* exit after POLLHUP while we haven't collected the child yet. */
if (sigprocmask(SIG_BLOCK, &sigset, &sigset_old) != 0) {
die("sigprocmask block sigchld loop");