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 
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 
str_check(char * s,char * p)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 
strength_check(char * newp,char * oldp,char * user)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 
verify_passwd(char * pwd)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 
new_password(char * oldp,char * user)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 
passwd_main(void)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