toybox/toys/lsb/passwd.c
<<
>>
Prefs
   1/* passwd.c - Program to update user password.
   2 *
   3 * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
   4 * Modified 2012 Jason Kyungwan Han <asura321@gmail.com>
   5 *
   6 * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/passwd.html
   7
   8USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
   9
  10config PASSWD
  11  bool "passwd"
  12  default y
  13  depends on TOYBOX_SHADOW
  14  help
  15    usage: passwd [-a ALGO] [-dlu] <account name>
  16
  17    update user's authentication tokens. Default : current user
  18
  19    -a ALGO     Encryption method (des, md5, sha256, sha512) default: des
  20    -d          Set password to ''
  21    -l          Lock (disable) account
  22    -u          Unlock (enable) account
  23
  24config PASSWD_SAD
  25  bool "Add sad password checking heuristics"
  26  default n
  27  depends on PASSWD
  28  help
  29    Password changes are checked to make sure they're at least 6 chars long,
  30    don't include the entire username (but not a subset of it), or the entire
  31    previous password (but changing password1, password2, password3 is fine).
  32    This heuristic accepts "aaaaaa" and "123456".
  33*/
  34
  35#define FOR_passwd
  36#include "toys.h"
  37
  38GLOBALS(
  39  char *algo;
  40)
  41
  42// Sad advisory heuristic, won't find password1 password2 password3...
  43static void weak_check(char *new, char *old, char *user)
  44{
  45  char *msg = 0;
  46
  47  if (strlen(new) < 6) msg = "too short";
  48  if (*new) {
  49    if (strnstr(new, user) || strnstr(user, new)) msg = "user";
  50    if (*old && (strnstr(new, old) || strnstr(old, new))) msg = "old";
  51  }
  52  if (msg) xprintf("BAD PASSWORD: %s\n",msg);
  53}
  54
  55void passwd_main(void)
  56{
  57  uid_t myuid;
  58  struct passwd *pw = 0;
  59  struct spwd *sp;
  60  char *pass, *name, *encrypted = 0, salt[MAX_SALT_LEN];
  61  int ret = -1;
  62
  63  // If we're root or not -lud, load specified user. Exit if not allowed.
  64  if (!(myuid = getuid()) || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) {
  65    if (*toys.optargs) pw = xgetpwnam(*toys.optargs);
  66    else pw = xgetpwuid(myuid);
  67  }
  68  if (!pw || (myuid && (myuid != pw->pw_uid))) error_exit("Not root");
  69
  70  // Get password from /etc/passwd or /etc/shadow
  71  // TODO: why still support non-shadow passwords...?
  72  name = pw->pw_name;
  73  if (*(pass = pw->pw_passwd)=='x' && (sp = getspnam(name))) pass = sp->sp_pwdp;
  74
  75  if (toys.optflags & FLAG_l) {
  76    if (*pass=='!') error_exit("already locked");
  77    printf("Locking '%s'\n", name);
  78    encrypted = xmprintf("!%s", pass);
  79  } else if (toys.optflags & FLAG_u) {
  80    if (*pass!='!') error_exit("already unlocked");
  81    printf("Unlocking '%s'\n", name);
  82    encrypted = pass+1;
  83  } else if (toys.optflags & FLAG_d) {
  84    printf("Deleting password for '%s'\n", name);
  85    encrypted = "";
  86  } else {
  87    if (get_salt(salt, TT.algo ? TT.algo : "des")<0)
  88      error_exit("bad -a '%s'", TT.algo);
  89
  90    printf("Changing password for %s\n", name);
  91    if (myuid) {
  92      if (*pass=='!') error_exit("'%s' locked", name);
  93
  94      if (read_password(toybuf+2048, 2048, "Old password:")) return;
  95      pass = crypt(toybuf+2048, pw->pw_passwd);
  96      if (!pass || strcmp(pass, pw->pw_passwd)) error_exit("No");
  97    }
  98
  99    if (read_password(toybuf, 2048, "New password:")) return;
 100
 101    if (CFG_PASSWD_SAD) weak_check(toybuf, toybuf+2048, name);
 102    if (read_password(toybuf+2048, 2048, "Retype password:")) return;
 103    if (strcmp(toybuf, toybuf+2048)) error_exit("Passwords do not match.");
 104
 105    encrypted = crypt(toybuf, salt);
 106  }
 107
 108  // Update the passwd
 109  ret = update_password(*pw->pw_passwd=='x' ? "/etc/shadow" : "/etc/passwd",
 110    name, encrypted);
 111
 112  if (ret) error_msg("Failure");
 113  else fprintf(stderr, "Success\n");
 114
 115  if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_l)) free(encrypted);
 116}
 117