master xplshn/aruu / cmd / xsi / su.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <sys/types.h>
  5
  6#include <errno.h>
  7#include <grp.h>
  8#include <pwd.h>
  9#include <stdio.h>
 10#include <stdlib.h>
 11#include <string.h>
 12#include <unistd.h>
 13
 14#include "passwd.h"
 15#include "util.h"
 16
 17extern char **environ;
 18
 19static int lflag = 0;
 20static int pflag = 0;
 21
 22static void
 23usage(void)
 24{
 25	eprintf("usage: %s [-lp] [username]\n", argv0);
 26}
 27
 28// ?man su: run command with substitute user id
 29// ?man arguments: username
 30// ?man run a shell or command with another user id
 31int
 32main(int argc, char *argv[])
 33{
 34	char *usr, *pass;
 35	char *shell, *envshell, *term;
 36	struct passwd *pw;
 37	char *newargv[3];
 38	uid_t uid;
 39
 40	ARGBEGIN {
 41	// ?man -l: list in long format
 42	case 'l':
 43		lflag = 1;
 44		break;
 45	// ?man -p: preserve file attributes
 46	case 'p':
 47		pflag = 1;
 48		break;
 49	default:
 50		usage();
 51	} ARGEND;
 52
 53	if (argc > 1)
 54		usage();
 55	usr = argc > 0 ? argv[0] : "root";
 56
 57	errno = 0;
 58	pw = getpwnam(usr);
 59	if (!pw) {
 60		if (errno)
 61			eprintf("getpwnam: %s:", usr);
 62		else
 63			eprintf("who are you?\n");
 64	}
 65
 66	uid = getuid();
 67	if (uid) {
 68		pass = getpass("Password: ");
 69		if (!pass)
 70			eprintf("getpass:");
 71		if (pw_check(pw, pass) <= 0)
 72			exit(1);
 73	}
 74
 75	if (initgroups(usr, pw->pw_gid) < 0)
 76		eprintf("initgroups:");
 77	if (setgid(pw->pw_gid) < 0)
 78		eprintf("setgid:");
 79	if (setuid(pw->pw_uid) < 0)
 80		eprintf("setuid:");
 81
 82	shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell;
 83	if (lflag) {
 84		term = getenv("TERM");
 85		clearenv();
 86		setenv("HOME", pw->pw_dir, 1);
 87		setenv("SHELL", shell, 1);
 88		setenv("USER", pw->pw_name, 1);
 89		setenv("LOGNAME", pw->pw_name, 1);
 90		setenv("TERM", term ? term : "linux", 1);
 91		if (chdir(pw->pw_dir) < 0)
 92			eprintf("chdir %s:", pw->pw_dir);
 93		newargv[0] = shell;
 94		newargv[1] = "-l";
 95		newargv[2] = NULL;
 96	} else {
 97		if (pflag) {
 98			envshell = getenv("SHELL");
 99			if (envshell && envshell[0] != '\0')
100				shell = envshell;
101		} else {
102			setenv("HOME", pw->pw_dir, 1);
103			setenv("SHELL", shell, 1);
104			if (strcmp(pw->pw_name, "root") != 0) {
105				setenv("USER", pw->pw_name, 1);
106				setenv("LOGNAME", pw->pw_name, 1);
107			}
108		}
109		newargv[0] = shell;
110		newargv[1] = NULL;
111	}
112	execve(shell, newargv, environ);
113	weprintf("execve %s:", shell);
114	return (errno == ENOENT) ? 127 : 126;
115}