Mercurial > hg > toybox
comparison toys/passwd.c @ 626:77d94b36aff0
Add passwd by Kyungwan Han.
author | Rob Landley <rob@landley.net> |
---|---|
date | Tue, 17 Jul 2012 08:54:47 -0500 |
parents | |
children | 9aeea680acc7 |
comparison
equal
deleted
inserted
replaced
625:1a368546afd9 | 626:77d94b36aff0 |
---|---|
1 /* vi: set sw=4 ts=4: | |
2 * | |
3 * passwd.c - Program to upadte user password. | |
4 * | |
5 * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com> | |
6 * Modified 2012 Jason Kyungwan Han <asura321@gmail.com> | |
7 * | |
8 * Not in SUSv4. | |
9 | |
10 USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) | |
11 | |
12 config PASSWD | |
13 bool "passwd" | |
14 default y | |
15 help | |
16 usage: passwd [-a ALGO] [-d] [-l] [-u] <account name> | |
17 | |
18 update user’s authentication tokens. Default : current user | |
19 | |
20 -a ALGO Encryption method (des, md5, sha256, sha512) default: des | |
21 -d Set password to '' | |
22 -l Lock (disable) account | |
23 -u Unlock (enable) account | |
24 | |
25 */ | |
26 | |
27 #include "toys.h" | |
28 #include <time.h> | |
29 | |
30 | |
31 DEFINE_GLOBALS( | |
32 char *algo; | |
33 ) | |
34 | |
35 #define TT this.passwd | |
36 | |
37 #define FLAG_u (1 << 0) | |
38 #define FLAG_l (1 << 1) | |
39 #define FLAG_d (1 << 2) | |
40 #define FLAG_a (1 << 3) | |
41 | |
42 #define MAX_SALT_LEN 20 //3 for id, 16 for key, 1 for '\0' | |
43 #define URANDOM_PATH "/dev/urandom" | |
44 | |
45 #ifndef _GNU_SOURCE | |
46 char *strcasestr(const char *haystack, const char *needle); | |
47 #endif | |
48 | |
49 unsigned int random_number_generator(int fd) | |
50 { | |
51 unsigned int randnum; | |
52 xreadall(fd, &randnum, sizeof(randnum)); | |
53 return randnum; | |
54 } | |
55 | |
56 | |
57 | |
58 char inttoc(int i) | |
59 { | |
60 // salt value uses 64 chracters in "./0-9a-zA-Z" | |
61 const char character_set[]="./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
62 i &= 0x3f; // masking for using 10 bits only | |
63 return character_set[i]; | |
64 } | |
65 | |
66 int get_salt(char *salt) | |
67 { | |
68 int i, salt_length = 0; | |
69 int randfd; | |
70 if(!strncmp(TT.algo,"des",3)){ | |
71 // 2 bytes salt value is used in des | |
72 salt_length = 2; | |
73 } else { | |
74 *salt++ = '$'; | |
75 if(!strncmp(TT.algo,"md5",3)){ | |
76 *salt++ = '1'; | |
77 // 8 bytes salt value is used in md5 | |
78 salt_length = 8; | |
79 } else if(!strncmp(TT.algo,"sha256",6)){ | |
80 *salt++ = '5'; | |
81 // 16 bytes salt value is used in sha256 | |
82 salt_length = 16; | |
83 } else if(!strncmp(TT.algo,"sha512",6)){ | |
84 *salt++ = '6'; | |
85 // 16 bytes salt value is used in sha512 | |
86 salt_length = 16; | |
87 } else return 1; | |
88 | |
89 *salt++ = '$'; | |
90 } | |
91 | |
92 randfd = xopen(URANDOM_PATH, O_RDONLY); | |
93 for(i=0; i<salt_length; i++) | |
94 salt[i] = inttoc(random_number_generator(randfd)); | |
95 salt[salt_length+1] = '\0'; | |
96 xclose(randfd); | |
97 | |
98 return 0; | |
99 } | |
100 | |
101 static int str_check(char *s, char *p) | |
102 { | |
103 if((strcasestr(s, p) != NULL) || (strcasestr(p, s) != NULL)) | |
104 return 1; | |
105 return 0; | |
106 } | |
107 | |
108 static void strength_check(char *newp, char *oldp, char *user) | |
109 { | |
110 char *msg = NULL; | |
111 if(strlen(newp) < 6) { //Min passwd len | |
112 msg = "too short"; | |
113 xprintf("BAD PASSWORD: %s\n",msg); | |
114 } | |
115 if(!newp[0]) | |
116 return; //passwd is empty | |
117 | |
118 if(str_check(newp, user)) { | |
119 msg = "user based password"; | |
120 xprintf("BAD PASSWORD: %s\n",msg); | |
121 } | |
122 | |
123 if(oldp[0] && str_check(newp, oldp)) { | |
124 msg = "based on old passwd"; | |
125 xprintf("BAD PASSWORD: %s\n",msg); | |
126 } | |
127 } | |
128 | |
129 static int verify_passwd(char * pwd) | |
130 { | |
131 char * pass; | |
132 | |
133 if (!pwd) return 1; | |
134 if (pwd[0] == '!' || pwd[0] == '*') return 1; | |
135 | |
136 pass = crypt(toybuf, pwd); | |
137 if (pass != NULL && strcmp(pass, pwd)==0) | |
138 return 0; | |
139 | |
140 return 1; | |
141 } | |
142 | |
143 static char *new_password(char *oldp, char *user) | |
144 { | |
145 char *newp = NULL; | |
146 | |
147 if(read_passwd(toybuf, sizeof(toybuf), "New password:")) | |
148 return NULL; //may be due to Ctrl-C | |
149 | |
150 newp = xstrdup(toybuf); | |
151 strength_check(newp, oldp, user); | |
152 if(read_passwd(toybuf, sizeof(toybuf), "Retype password:")) { | |
153 free(newp); | |
154 return NULL; //may be due to Ctrl-C | |
155 } | |
156 | |
157 if(strcmp(newp, toybuf) == 0) | |
158 return newp; | |
159 else error_msg("Passwords do not match.\n"); | |
160 /*Failure Case */ | |
161 free(newp); | |
162 return NULL; | |
163 } | |
164 | |
165 | |
166 void passwd_main(void) | |
167 { | |
168 uid_t myuid; | |
169 struct passwd *pw; | |
170 struct spwd *sp; | |
171 char *name = NULL; | |
172 char *pass = NULL, *encrypted = NULL, *newp = NULL; | |
173 char *orig = (char *)""; | |
174 char salt[MAX_SALT_LEN]; | |
175 int ret = -1; | |
176 | |
177 myuid = getuid(); | |
178 if((myuid != 0) && (toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) | |
179 error_exit("You need to be root to do these actions\n"); | |
180 | |
181 pw = getpwuid(myuid); | |
182 | |
183 if(!pw) | |
184 error_exit("Unknown uid '%u'",myuid); | |
185 | |
186 if(toys.optargs[0]) | |
187 name = toys.optargs[0]; | |
188 else | |
189 name = xstrdup(pw->pw_name); | |
190 | |
191 pw = getpwnam(name); | |
192 if(!pw) error_exit("Unknown user '%s'",name); | |
193 | |
194 if(myuid != 0 && (myuid != pw->pw_uid)) | |
195 error_exit("You need to be root to change '%s' password\n", name); | |
196 | |
197 pass = pw->pw_passwd; | |
198 if(pw->pw_passwd[0] == 'x') { | |
199 /*get shadow passwd */ | |
200 sp = getspnam(name); | |
201 if(sp) | |
202 pass = sp->sp_pwdp; | |
203 } | |
204 | |
205 | |
206 if(!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) { | |
207 printf("Changing password for %s\n",name); | |
208 if(pass[0] == '!') | |
209 error_exit("Can't change, password is locked for %s",name); | |
210 if(myuid != 0) { | |
211 /*Validate user */ | |
212 | |
213 if(read_passwd(toybuf, sizeof(toybuf), "Origial password:")) { | |
214 if(!toys.optargs[0]) free(name); | |
215 return; | |
216 } | |
217 orig = toybuf; | |
218 if(verify_passwd(pass)) | |
219 error_exit("Authentication failed\n"); | |
220 } | |
221 | |
222 orig = xstrdup(orig); | |
223 | |
224 /*Get new password */ | |
225 newp = new_password(orig, name); | |
226 if(!newp) { | |
227 free(orig); | |
228 if(!toys.optargs[0]) free(name); | |
229 return; //new password is not set well. | |
230 } | |
231 | |
232 /*Encrypt the passwd */ | |
233 if(!(toys.optflags & FLAG_a)) TT.algo = "des"; | |
234 | |
235 if(get_salt(salt)) | |
236 error_exit("Error: Unkown encryption algorithm\n"); | |
237 | |
238 encrypted = crypt(newp, salt); | |
239 free(newp); | |
240 free(orig); | |
241 } | |
242 else if(toys.optflags & FLAG_l) { | |
243 if(pass[0] == '!') | |
244 error_exit("password is already locked for %s",name); | |
245 printf("Locking password for %s\n",name); | |
246 encrypted = xmsprintf("!%s",pass); | |
247 } | |
248 else if(toys.optflags & FLAG_u) { | |
249 if(pass[0] != '!') | |
250 error_exit("password is already unlocked for %s",name); | |
251 | |
252 printf("Unlocking password for %s\n",name); | |
253 encrypted = xstrdup(&pass[1]); | |
254 } | |
255 else if(toys.optflags & FLAG_d) { | |
256 printf("Deleting password for %s\n",name); | |
257 encrypted = (char*)xzalloc(sizeof(char)*2); //1 = "", 2 = '\0' | |
258 } | |
259 | |
260 /*Update the passwd */ | |
261 if(pw->pw_passwd[0] == 'x') | |
262 ret = update_passwd("/etc/shadow", name, encrypted); | |
263 else | |
264 ret = update_passwd("/etc/passwd", name, encrypted); | |
265 | |
266 if((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) | |
267 free(encrypted); | |
268 | |
269 if(!toys.optargs[0]) free(name); | |
270 if(!ret) | |
271 error_msg("Success"); | |
272 else | |
273 error_msg("Failure"); | |
274 } |