• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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