1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 //usage:#define passwd_trivial_usage
7 //usage: "[OPTIONS] [USER]"
8 //usage:#define passwd_full_usage "\n\n"
9 //usage: "Change USER's password (default: current user)"
11 //usage: "\n -a ALG Encryption method"
12 //usage: "\n -d Set password to ''"
13 //usage: "\n -l Lock (disable) account"
14 //usage: "\n -u Unlock (enable) account"
19 static void nuke_str(char *str)
21 if (str) memset(str, 0, strlen(str));
24 static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
26 char salt[MAX_PW_SALT_LEN];
27 char *orig = (char*)"";
30 char *ret = NULL; /* failure so far */
32 if (myuid != 0 && pw->pw_passwd[0]) {
35 orig = bb_ask_stdin("Old password: "); /* returns ptr to static */
38 encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
39 if (strcmp(encrypted, pw->pw_passwd) != 0) {
40 syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
41 bb_do_delay(LOGIN_FAIL_DELAY);
42 puts("Incorrect password");
45 if (ENABLE_FEATURE_CLEAN_UP)
48 orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
49 newp = bb_ask_stdin("New password: "); /* returns ptr to static */
52 newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
53 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
54 && obscure(orig, newp, pw)
57 goto err_ret; /* non-root is not allowed to have weak passwd */
60 cp = bb_ask_stdin("Retype password: ");
63 if (strcmp(cp, newp) != 0) {
64 puts("Passwords don't match");
68 crypt_make_pw_salt(salt, algo);
70 /* pw_encrypt returns malloced str */
71 ret = pw_encrypt(newp, salt, 1);
76 if (ENABLE_FEATURE_CLEAN_UP) free(orig);
79 if (ENABLE_FEATURE_CLEAN_UP) free(newp);
85 int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
86 int passwd_main(int argc UNUSED_PARAM, char **argv)
89 OPT_algo = (1 << 0), /* -a - password algorithm */
90 OPT_lock = (1 << 1), /* -l - lock account */
91 OPT_unlock = (1 << 2), /* -u - unlock account */
92 OPT_delete = (1 << 3), /* -d - delete password */
93 OPT_lud = OPT_lock | OPT_unlock | OPT_delete,
97 const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
104 struct rlimit rlimit_fsize;
106 #if ENABLE_FEATURE_SHADOWPASSWDS
107 /* Using _r function to avoid pulling in static buffers */
112 logmode = LOGMODE_BOTH;
113 openlog(applet_name, 0, LOG_AUTH);
114 opt = getopt32(argv, "a:lud", &opt_a);
119 /* -l, -u, -d require root priv and username argument */
120 if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
123 /* Will complain and die if username not found */
124 myname = xstrdup(xuid2uname(myuid));
125 name = argv[0] ? argv[0] : myname;
127 pw = xgetpwnam(name);
128 if (myuid != 0 && pw->pw_uid != myuid) {
130 bb_error_msg_and_die("%s can't change password for %s", myname, name);
133 #if ENABLE_FEATURE_SHADOWPASSWDS
135 /* getspnam_r may return 0 yet set result to NULL.
136 * At least glibc 2.4 does this. Be extra paranoid here. */
137 struct spwd *result = NULL;
139 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0
140 || !result /* no error, but no record found either */
141 || strcmp(result->sp_namp, pw->pw_name) != 0 /* paranoia */
143 if (errno != ENOENT) {
145 bb_perror_msg("no record of %s in %s, using %s",
146 name, bb_path_shadow_file,
147 bb_path_passwd_file);
149 /* else: /etc/shadow does not exist,
150 * apparently we are on a shadow-less system,
151 * no surprise there */
153 pw->pw_passwd = result->sp_pwdp;
158 /* Decide what the new password will be */
160 c = pw->pw_passwd[0] - '!';
161 if (!(opt & OPT_lud)) {
162 if (myuid != 0 && !c) { /* passwd starts with '!' */
164 bb_error_msg_and_die("can't change "
165 "locked password for %s", name);
167 printf("Changing password for %s\n", name);
168 newp = new_password(pw, myuid, opt_a);
170 logmode = LOGMODE_STDIO;
171 bb_error_msg_and_die("password for %s is unchanged", name);
173 } else if (opt & OPT_lock) {
175 goto skip; /* passwd starts with '!' */
176 newp = xasprintf("!%s", pw->pw_passwd);
177 } else if (opt & OPT_unlock) {
179 goto skip; /* not '!' */
180 /* pw->pw_passwd points to static storage,
181 * strdup'ing to avoid nasty surprizes */
182 newp = xstrdup(&pw->pw_passwd[1]);
183 } else if (opt & OPT_delete) {
187 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
188 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
197 #if ENABLE_FEATURE_SHADOWPASSWDS
198 filename = bb_path_shadow_file;
199 rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
201 /* password in /etc/shadow was updated */
204 /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
207 filename = bb_path_passwd_file;
208 rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
212 bb_error_msg_and_die("can't update password file %s", filename);
213 bb_info_msg("Password for %s changed by %s", name, myname);
215 /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
218 bb_error_msg_and_die("password for %s is already %slocked",
219 name, (opt & OPT_unlock) ? "un" : "");
222 if (ENABLE_FEATURE_CLEAN_UP)