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