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