toybox/toys/pending/chsh.c
<<
>>
Prefs
   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
   7USE_CHSH(NEWTOY(chsh, "s:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
   8
   9config 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
  25GLOBALS(
  26  char *s;
  27)
  28
  29void 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