• 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] [USER]
16 
17     Update user's authentication tokens. Defaults to 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're at least 6 chars long,
30     don't include the entire username (but not a subset of it), or the entire
31     previous password (but changing password1, password2, password3 is fine).
32     This heuristic accepts "aaaaaa" and "123456".
33 */
34 
35 #define FOR_passwd
36 #include "toys.h"
37 
GLOBALS(char * a;)38 GLOBALS(
39   char *a;
40 )
41 
42 // Sad advisory heuristic, won't find password1 password2 password3...
43 static void weak_check(char *new, char *old, char *user)
44 {
45   char *msg = 0;
46 
47   if (strlen(new) < 6) msg = "too short";
48   if (*new) {
49     if (strcasestr(new, user) || strcasestr(user, new)) msg = "user";
50     if (*old && (strcasestr(new, old) || strcasestr(old, new))) msg = "old";
51   }
52   if (msg) xprintf("BAD PASSWORD: %s\n",msg);
53 }
54 
passwd_main(void)55 void passwd_main(void)
56 {
57   uid_t myuid;
58   struct passwd *pw = 0;
59   struct spwd *sp;
60   char *pass, *name, *encrypted = 0, salt[MAX_SALT_LEN];
61   int ret = -1;
62 
63   // If we're root or not -lud, load specified user. Exit if not allowed.
64   if (!(myuid = getuid()) || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) {
65     if (*toys.optargs) pw = xgetpwnam(*toys.optargs);
66     else pw = xgetpwuid(myuid);
67   }
68   if (!pw || (myuid && (myuid != pw->pw_uid))) error_exit("Not root");
69 
70   // Get password from /etc/passwd or /etc/shadow
71   // TODO: why still support non-shadow passwords...?
72   name = pw->pw_name;
73   if (*(pass = pw->pw_passwd)=='x' && (sp = getspnam(name))) pass = sp->sp_pwdp;
74 
75   if (toys.optflags & FLAG_l) {
76     if (*pass=='!') error_exit("already locked");
77     printf("Locking '%s'\n", name);
78     encrypted = xmprintf("!%s", pass);
79   } else if (toys.optflags & FLAG_u) {
80     if (*pass!='!') error_exit("already unlocked");
81     printf("Unlocking '%s'\n", name);
82     encrypted = pass+1;
83   } else if (toys.optflags & FLAG_d) {
84     printf("Deleting password for '%s'\n", name);
85     encrypted = "";
86   } else {
87     if (get_salt(salt, TT.a ? TT.a : "des")<0) error_exit("bad -a '%s'", TT.a);
88 
89     printf("Changing password for %s\n", name);
90     if (myuid) {
91       if (*pass=='!') error_exit("'%s' locked", name);
92 
93       if (read_password(toybuf+2048, 2048, "Old password:")) return;
94       pass = crypt(toybuf+2048, pw->pw_passwd);
95       if (!pass || strcmp(pass, pw->pw_passwd)) error_exit("No");
96     }
97 
98     if (read_password(toybuf, 2048, "New password:")) return;
99 
100     if (CFG_PASSWD_SAD) weak_check(toybuf, toybuf+2048, name);
101     if (read_password(toybuf+2048, 2048, "Retype password:")) return;
102     if (strcmp(toybuf, toybuf+2048)) error_exit("Passwords do not match.");
103 
104     encrypted = crypt(toybuf, salt);
105   }
106 
107   // Update the passwd
108   ret = update_password(*pw->pw_passwd=='x' ? "/etc/shadow" : "/etc/passwd",
109     name, encrypted);
110 
111   if (ret) error_msg("Failure");
112   else fprintf(stderr, "Success\n");
113 
114   if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_l)) free(encrypted);
115 }
116