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 don't include the entire
  30    username (but not a subset of it), and the entire previous password
  31    (but changing password1, password2, password3 is fine). This heuristic
  32    accepts "aaaaaa" as a password.
  33*/
  34
  35#define FOR_passwd
  36#include "toys.h"
  37
  38GLOBALS(
  39  char *algo;
  40)
  41
  42static int str_check(char *s, char *p)
  43{
  44  if (strnstr(s, p) || strnstr(p, s)) return 1;
  45  return 0;
  46}
  47
  48// Insane heuristic won't find password1 password2 password3...?
  49static void strength_check(char *newp, char *oldp, char *user)
  50{
  51  char *msg = NULL;
  52
  53  if (strlen(newp) < 6) { //Min passwd len
  54    msg = "too short";
  55    xprintf("BAD PASSWORD: %s\n",msg);
  56  }
  57  if (!newp[0]) return; //passwd is empty
  58
  59  if (str_check(newp, user)) {
  60    msg = "user based password";
  61    xprintf("BAD PASSWORD: %s\n",msg);
  62  }
  63
  64  if (oldp[0] && str_check(newp, oldp)) {
  65    msg = "based on old passwd";
  66    xprintf("BAD PASSWORD: %s\n",msg);
  67  }
  68}
  69
  70static int verify_passwd(char * pwd)
  71{
  72  char * pass;
  73
  74  if (!pwd) return 1;
  75  if (pwd[0] == '!' || pwd[0] == '*') return 1;
  76
  77  pass = crypt(toybuf, pwd);
  78  if (pass  && !strcmp(pass, pwd)) return 0;
  79
  80  return 1;
  81}
  82
  83static char *new_password(char *oldp, char *user)
  84{
  85  char *newp = NULL;
  86
  87  if (read_password(toybuf, sizeof(toybuf), "New password:"))
  88    return NULL; //may be due to Ctrl-C
  89
  90  newp = xstrdup(toybuf);
  91  if (CFG_PASSWD_SAD) strength_check(newp, oldp, user);
  92  if (read_password(toybuf, sizeof(toybuf), "Retype password:")) {
  93    free(newp);
  94    return NULL; //may be due to Ctrl-C
  95  }
  96
  97  if (!strcmp(newp, toybuf)) return newp;
  98  else error_msg("Passwords do not match.\n");
  99  // Failure Case
 100  free(newp);
 101  return NULL;
 102}
 103
 104void passwd_main(void)
 105{
 106  uid_t myuid;
 107  struct passwd *pw;
 108  struct spwd *sp;
 109  char *name = NULL, *pass = NULL, *encrypted = NULL, *newp = NULL,
 110       *orig = (char *)"", salt[MAX_SALT_LEN];
 111  int ret = -1;
 112
 113  myuid = getuid();
 114  if (myuid && (toys.optflags & (FLAG_l | FLAG_u | FLAG_d)))
 115    error_exit("Not root");
 116
 117  pw = xgetpwuid(myuid);
 118
 119  if (*toys.optargs) name = toys.optargs[0];
 120  else name = xstrdup(pw->pw_name);
 121
 122  pw = xgetpwnam(name);
 123
 124  if (myuid && (myuid != pw->pw_uid)) error_exit("Not root");
 125
 126  pass = pw->pw_passwd;
 127  if (pw->pw_passwd[0] == 'x') {
 128    //get shadow passwd
 129    sp = getspnam(name);
 130    if (sp) pass = sp->sp_pwdp;
 131  }
 132
 133
 134  if (!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) {
 135    
 136    if (!(toys.optflags & FLAG_a)) TT.algo = "des";
 137    if (get_salt(salt, TT.algo) == -1)
 138      error_exit("Error: Unkown encryption algorithm\n");
 139
 140    printf("Changing password for %s\n",name);
 141    if (myuid && pass[0] == '!')
 142      error_exit("Can't change, password is locked for %s",name);
 143    if (myuid) {
 144      //Validate user 
 145
 146      if (read_password(toybuf, sizeof(toybuf), "Origial password:")) {
 147        if (!toys.optargs[0]) free(name);
 148        return;
 149      }
 150      orig = toybuf;
 151      if (verify_passwd(pass)) error_exit("Authentication failed\n");
 152    }
 153
 154    orig = xstrdup(orig);
 155
 156    // Get new password
 157    newp = new_password(orig, name);
 158    if (!newp) {
 159      free(orig);
 160      if (!toys.optargs[0]) free(name);
 161      return; //new password is not set well.
 162    }
 163
 164    encrypted = crypt(newp, salt);
 165    free(newp);
 166    free(orig);
 167  } else if (toys.optflags & FLAG_l) {
 168    if (pass[0] == '!') error_exit("password is already locked for %s",name);
 169    printf("Locking password for %s\n",name);
 170    encrypted = xmprintf("!%s",pass);
 171  } else if (toys.optflags & FLAG_u) {
 172    if (pass[0] != '!') error_exit("password is already unlocked for %s",name);
 173
 174    printf("Unlocking password for %s\n",name);
 175    encrypted = xstrdup(&pass[1]);
 176  } else if (toys.optflags & FLAG_d) {
 177    printf("Deleting password for %s\n",name);
 178    encrypted = xstrdup(""); //1 = "", 2 = '\0'
 179  }
 180
 181  // Update the passwd
 182  if (pw->pw_passwd[0] == 'x')
 183    ret = update_password("/etc/shadow", name, encrypted);
 184  else ret = update_password("/etc/passwd", name, encrypted);
 185
 186  if ((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) free(encrypted);
 187
 188  if (!toys.optargs[0]) free(name);
 189  if (!ret) error_msg("Success");
 190  else error_msg("Failure");
 191}
 192