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 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
GLOBALS(char * algo;)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...?
strength_check(char * newp,char * oldp,char * user)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
verify_passwd(char * pwd)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
new_password(char * oldp,char * user)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
passwd_main(void)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