#include #include #include #include #include #include #include #include #include #include "pw_check.h" #include "unused.h" #define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL) static char *c_flag = NULL; static char *s_flag = NULL; static char p_flag; static int hide_input(int fd, int flag) { struct termios term; if (tcgetattr(fd, &term) < 0) return 1; if (flag) term.c_lflag &= ~ECHOFLAGS; else term.c_lflag |= ECHOFLAGS; if (tcsetattr(fd, TCSAFLUSH, &term) < 0) return 1; return 0; } static void su(const struct passwd *pw) { char *shell = s_flag; if (s_flag == NULL) shell = (pw->pw_shell[0] == '\0') ? "/bin/sh" : pw->pw_shell; if (!p_flag) { setenv("HOME", pw->pw_dir, 1); setenv("SHELL", shell, 1); setenv("USER", pw->pw_name, 1); setenv("LOGNAME", pw->pw_name, 1); setenv("PATH", "/bin", 1); } if (c_flag) execlp(shell, shell, "-c", c_flag, NULL); else execlp(shell, shell, "-l", NULL); } static int password(const struct passwd *pw) { static char psswd[512]; printf("Password: "); fflush(stdout); if (hide_input(STDIN_FILENO, 1)) { fprintf(stderr, "\nsu: %s\n", strerror(errno)); return 1; } off_t ret = 0; if ((ret = read(STDIN_FILENO, psswd, sizeof(psswd))) <= 0) { fprintf(stderr, "\nsu: %s\n", strerror(errno)); return 1; } putchar('\n'); psswd[ret - 1] = '\0'; if (pw_check("su", pw, psswd)) { memset(psswd, '\0', sizeof(psswd)); return 1; } memset(psswd, '\0', sizeof(psswd)); return 0; } static void endwin(int sig) { UNUSED(sig); hide_input(STDIN_FILENO, 0); exit(1); } int main(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "c:s:p")) != -1) { switch (opt) { case 'c': c_flag = optarg; break; case 's': s_flag = optarg; break; case 'p': p_flag = 1; break; default: puts("su [cps] [user Default: root]\n\t-c CMD Command to pass to \'sh -c\'\n\t-s SHELL Shell to use instead of user's default\n\t-p Do not set new env"); return 0; } } argc -= optind; argv += optind; char *user = "root"; if (argv[0]) user = argv[0]; struct passwd *pw = getpwnam(user); if (!pw) { fprintf(stderr, "su: Incorrent username\n"); return 1; } signal(SIGINT, endwin); if (getuid() != 0) { int ret = password(pw); hide_input(STDIN_FILENO, 0); if (ret) return 1; } /* Start */ if (setgid(pw->pw_gid) < 0) { fprintf(stderr, "su: %s\n", strerror(errno)); return 1; } if (setuid(pw->pw_uid) < 0) { fprintf(stderr, "su: %s\n", strerror(errno)); return 1; } su(pw); return 0; }