xref: /aosp_15_r20/external/toybox/toys/lsb/passwd.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1 /* passwd.c - update user password.
2  *
3  * Copyright 2012 Ashwini Kumar <[email protected]>
4  * Modified 2012 Jason Kyungwan Han <[email protected]>
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 n
13   help
14     usage: passwd [-a ALGO] [-dlu] [USER]
15 
16     Update user's login password. Defaults to current user.
17 
18     -a ALGO	Encryption method (des, md5, sha256, sha512) default: md5
19     -d		Set password to ''
20     -l		Lock (disable) account
21     -u		Unlock (enable) account
22 
23 config PASSWD_SAD
24   bool "Add sad password checking heuristics"
25   default n
26   depends on PASSWD
27   help
28     Password changes are checked to make sure they're at least 6 chars long,
29     don't include the entire username (but not a subset of it), or the entire
30     previous password (but changing password1, password2, password3 is fine).
31     This heuristic accepts "aaaaaa" and "123456".
32 */
33 
34 #define FOR_passwd
35 #include "toys.h"
36 
GLOBALS(char * a;)37 GLOBALS(
38   char *a;
39 )
40 
41 // Sad advisory heuristic, won't find password1 password2 password3...
42 static void weak_check(char *new, char *old, char *user)
43 {
44   char *msg = 0;
45 
46   if (strlen(new) < 6) msg = "too short";
47   if (*new) {
48     if (strcasestr(new, user) || strcasestr(user, new)) msg = "user";
49     if (*old && (strcasestr(new, old) || strcasestr(old, new))) msg = "old";
50   }
51   if (msg) xprintf("BAD PASSWORD: %s\n",msg);
52 }
53 
passwd_main(void)54 void passwd_main(void)
55 {
56   uid_t myuid = getuid();
57   struct passwd *pw = 0;
58   struct spwd *sp;
59   char *pass, *name, *encrypted = 0, salt[32];
60 
61   // If we're root or not -lud, load specified user. Exit if not allowed.
62   if (!myuid || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) {
63     if (*toys.optargs) pw = xgetpwnam(*toys.optargs);
64     else pw = xgetpwuid(myuid);
65   }
66   if (!pw || (myuid && myuid != pw->pw_uid)) error_exit("Not root");
67 
68   // Get password from /etc/passwd or /etc/shadow
69   // TODO: why still support non-shadow passwords...?
70   name = pw->pw_name;
71   if (*(pass = pw->pw_passwd)=='x' && (sp = getspnam(name))) pass = sp->sp_pwdp;
72 
73   if (FLAG(l)) {
74     if (*pass=='!') error_exit("already locked");
75     printf("Locking '%s'\n", name);
76     encrypted = xmprintf("!%s", pass);
77   } else if (FLAG(u)) {
78     if (*pass!='!') error_exit("already unlocked");
79     printf("Unlocking '%s'\n", name);
80     encrypted = pass+1;
81   } else if (FLAG(d)) {
82     printf("Deleting password for '%s'\n", name);
83     *(encrypted = toybuf) = 0;
84   } else {
85     if (!TT.a) TT.a = "des";
86     if (get_salt(salt, TT.a, 1)<0) error_exit("bad -a '%s'", TT.a);
87 
88     printf("Changing password for %s\n", name);
89     if (myuid) {
90       if (*pass=='!') error_exit("'%s' locked", name);
91 
92       if (read_password(toybuf+2048, 2048, "Old password:")) return;
93       pass = crypt(toybuf+2048, pw->pw_passwd);
94       if (!pass || strcmp(pass, pw->pw_passwd)) error_exit("No");
95     }
96 
97     if (read_password(toybuf, 2048, "New password:")) return;
98 
99     if (CFG_PASSWD_SAD) weak_check(toybuf, toybuf+2048, name);
100     if (read_password(toybuf+2048, 2048, "Retype password:")) return;
101     if (strcmp(toybuf, toybuf+2048)) error_exit("Passwords do not match.");
102 
103     encrypted = crypt(toybuf, salt);
104   }
105 
106   // Update the passwd
107   if (update_password(*pw->pw_passwd=='x' ? "/etc/shadow" : "/etc/passwd",
108     name, encrypted, 1)) error_msg("Failure");
109   else fprintf(stderr, "Success\n");
110 
111   memset(toybuf, 0, sizeof(toybuf));
112   memset(encrypted, 0, strlen(encrypted));
113   free(encrypted);
114 }
115