Home | History | Annotate | Download | only in lsb
      1 /* passwd.c - Program to update user password.
      2  *
      3  * Copyright 2012 Ashwini Kumar <ak.ashwini (at) gmail.com>
      4  * Modified 2012 Jason Kyungwan Han <asura321 (at) gmail.com>
      5  *
      6  * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/passwd.html
      7 
      8 USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
      9 
     10 config 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 
     24 config 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 
     38 GLOBALS(
     39   char *algo;
     40 )
     41 
     42 static 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...?
     49 static 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 
     70 static 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 
     83 static 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 
    104 void 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