1*cf5a6c84SAndroid Build Coastguard Worker /* chsh.c - Change login shell.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2021 Michael Christensen
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/chsh.html
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker USE_CHSH(NEWTOY(chsh, ">1R:s:a", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker config CHSH
10*cf5a6c84SAndroid Build Coastguard Worker bool "chsh"
11*cf5a6c84SAndroid Build Coastguard Worker default n
12*cf5a6c84SAndroid Build Coastguard Worker help
13*cf5a6c84SAndroid Build Coastguard Worker usage: chsh [-s SHELL] [-R CHROOT_DIR] [USER]
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker Change user's login shell.
16*cf5a6c84SAndroid Build Coastguard Worker
17*cf5a6c84SAndroid Build Coastguard Worker -s Use SHELL instead of prompting
18*cf5a6c84SAndroid Build Coastguard Worker -R Act on CHROOT_DIR instead of host
19*cf5a6c84SAndroid Build Coastguard Worker
20*cf5a6c84SAndroid Build Coastguard Worker Non-root users can only change their own shell to one listed in /etc/shells.
21*cf5a6c84SAndroid Build Coastguard Worker */
22*cf5a6c84SAndroid Build Coastguard Worker
23*cf5a6c84SAndroid Build Coastguard Worker #define FOR_chsh
24*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
25*cf5a6c84SAndroid Build Coastguard Worker
26*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
27*cf5a6c84SAndroid Build Coastguard Worker char *s, *R;
28*cf5a6c84SAndroid Build Coastguard Worker )
29*cf5a6c84SAndroid Build Coastguard Worker
chsh_main()30*cf5a6c84SAndroid Build Coastguard Worker void chsh_main()
31*cf5a6c84SAndroid Build Coastguard Worker {
32*cf5a6c84SAndroid Build Coastguard Worker FILE *file;
33*cf5a6c84SAndroid Build Coastguard Worker char *user, *line, *shell, *encrypted;
34*cf5a6c84SAndroid Build Coastguard Worker struct passwd *passwd_info;
35*cf5a6c84SAndroid Build Coastguard Worker struct spwd *shadow_info;
36*cf5a6c84SAndroid Build Coastguard Worker
37*cf5a6c84SAndroid Build Coastguard Worker // Get uid user information, may be discarded later
38*cf5a6c84SAndroid Build Coastguard Worker
39*cf5a6c84SAndroid Build Coastguard Worker if ((user = *toys.optargs)) {
40*cf5a6c84SAndroid Build Coastguard Worker if (strcmp((passwd_info = xgetpwnam(user))->pw_name, user))
41*cf5a6c84SAndroid Build Coastguard Worker if (geteuid()) errno = EPERM, error_exit(0);
42*cf5a6c84SAndroid Build Coastguard Worker } else user = (passwd_info = xgetpwuid(getuid()))->pw_name;
43*cf5a6c84SAndroid Build Coastguard Worker
44*cf5a6c84SAndroid Build Coastguard Worker // Get a password, encrypt it, wipe it, and check it
45*cf5a6c84SAndroid Build Coastguard Worker if (mlock(toybuf, sizeof(toybuf))) perror_exit("mlock");
46*cf5a6c84SAndroid Build Coastguard Worker if (!(shadow_info = getspnam(passwd_info->pw_name))) perror_exit("getspnam");
47*cf5a6c84SAndroid Build Coastguard Worker if (read_password(toybuf, sizeof(toybuf), "Password: ")) *toybuf = 0;
48*cf5a6c84SAndroid Build Coastguard Worker if (!(encrypted = crypt(toybuf, shadow_info->sp_pwdp))) perror_exit("crypt");
49*cf5a6c84SAndroid Build Coastguard Worker memset(toybuf, 0, sizeof(toybuf));
50*cf5a6c84SAndroid Build Coastguard Worker munlock(toybuf, sizeof(toybuf)); // prevents memset from "optimizing" away.
51*cf5a6c84SAndroid Build Coastguard Worker if (strcmp(encrypted, shadow_info->sp_pwdp)) perror_exit("Bad password");
52*cf5a6c84SAndroid Build Coastguard Worker
53*cf5a6c84SAndroid Build Coastguard Worker // Get new shell (either -s or interactive)
54*cf5a6c84SAndroid Build Coastguard Worker file = xfopen("/etc/shells", "r");
55*cf5a6c84SAndroid Build Coastguard Worker if (toys.optflags) shell = TT.s;
56*cf5a6c84SAndroid Build Coastguard Worker else {
57*cf5a6c84SAndroid Build Coastguard Worker xprintf("Login shell for %s [%s]:", user, passwd_info->pw_shell);
58*cf5a6c84SAndroid Build Coastguard Worker if (!(shell = xgetline(stdin))) xexit();
59*cf5a6c84SAndroid Build Coastguard Worker if (!*shell) xexit();
60*cf5a6c84SAndroid Build Coastguard Worker }
61*cf5a6c84SAndroid Build Coastguard Worker
62*cf5a6c84SAndroid Build Coastguard Worker // Verify supplied shell in /etc/shells, or get default shell
63*cf5a6c84SAndroid Build Coastguard Worker if (*shell) while ((line = xgetline(file)) && strcmp(shell, line)) free(line);
64*cf5a6c84SAndroid Build Coastguard Worker else do line = xgetline(file); while (line && *line != '/');
65*cf5a6c84SAndroid Build Coastguard Worker if (!line) error_exit("Shell not found in '/etc/shells'");
66*cf5a6c84SAndroid Build Coastguard Worker
67*cf5a6c84SAndroid Build Coastguard Worker // Update /etc/passwd
68*cf5a6c84SAndroid Build Coastguard Worker if (!update_password("/etc/passwd", user, line,6)) perror_exit("/etc/passwd");
69*cf5a6c84SAndroid Build Coastguard Worker }
70