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