source: MondoRescue/branches/3.3/mindi-busybox/loginutils/passwd.c@ 3624

Last change on this file since 3624 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 6.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5//config:config PASSWD
6//config: bool "passwd"
7//config: default y
8//config: select FEATURE_SYSLOG
9//config: help
10//config: passwd changes passwords for user and group accounts. A normal user
11//config: may only change the password for his/her own account, the super user
12//config: may change the password for any account. The administrator of a group
13//config: may change the password for the group.
14//config:
15//config: Note that Busybox binary must be setuid root for this applet to
16//config: work properly.
17//config:
18//config:config FEATURE_PASSWD_WEAK_CHECK
19//config: bool "Check new passwords for weakness"
20//config: default y
21//config: depends on PASSWD
22//config: help
23//config: With this option passwd will refuse new passwords which are "weak".
24
25//applet:/* Needs to be run by root or be suid root - needs to change /etc/{passwd,shadow}: */
26//applet:IF_PASSWD(APPLET(passwd, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
27
28//kbuild:lib-$(CONFIG_PASSWD) += passwd.o
29
30//usage:#define passwd_trivial_usage
31//usage: "[OPTIONS] [USER]"
32//usage:#define passwd_full_usage "\n\n"
33//usage: "Change USER's password (default: current user)"
34//usage: "\n"
35//usage: "\n -a ALG Encryption method"
36//usage: "\n -d Set password to ''"
37//usage: "\n -l Lock (disable) account"
38//usage: "\n -u Unlock (enable) account"
39
40#include "libbb.h"
41#include <syslog.h>
42#include <sys/resource.h> /* setrlimit */
43
44static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
45{
46 char salt[MAX_PW_SALT_LEN];
47 char *orig = (char*)"";
48 char *newp = NULL;
49 char *cp = NULL;
50 char *ret = NULL; /* failure so far */
51
52 if (myuid != 0 && pw->pw_passwd[0]) {
53 char *encrypted;
54
55 orig = bb_ask_stdin("Old password: "); /* returns ptr to static */
56 if (!orig)
57 goto err_ret;
58 encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
59 if (strcmp(encrypted, pw->pw_passwd) != 0) {
60 syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
61 bb_do_delay(LOGIN_FAIL_DELAY);
62 puts("Incorrect password");
63 goto err_ret;
64 }
65 if (ENABLE_FEATURE_CLEAN_UP)
66 free(encrypted);
67 }
68 orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
69 newp = bb_ask_stdin("New password: "); /* returns ptr to static */
70 if (!newp)
71 goto err_ret;
72 newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
73 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
74 && obscure(orig, newp, pw)
75 && myuid != 0
76 ) {
77 goto err_ret; /* non-root is not allowed to have weak passwd */
78 }
79
80 cp = bb_ask_stdin("Retype password: ");
81 if (!cp)
82 goto err_ret;
83 if (strcmp(cp, newp) != 0) {
84 puts("Passwords don't match");
85 goto err_ret;
86 }
87
88 crypt_make_pw_salt(salt, algo);
89
90 /* pw_encrypt returns malloced str */
91 ret = pw_encrypt(newp, salt, 1);
92 /* whee, success! */
93
94 err_ret:
95 nuke_str(orig);
96 if (ENABLE_FEATURE_CLEAN_UP) free(orig);
97
98 nuke_str(newp);
99 if (ENABLE_FEATURE_CLEAN_UP) free(newp);
100
101 nuke_str(cp);
102 return ret;
103}
104
105int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
106int passwd_main(int argc UNUSED_PARAM, char **argv)
107{
108 enum {
109 OPT_algo = (1 << 0), /* -a - password algorithm */
110 OPT_lock = (1 << 1), /* -l - lock account */
111 OPT_unlock = (1 << 2), /* -u - unlock account */
112 OPT_delete = (1 << 3), /* -d - delete password */
113 OPT_lud = OPT_lock | OPT_unlock | OPT_delete,
114 };
115 unsigned opt;
116 int rc;
117 const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
118 const char *filename;
119 char *myname;
120 char *name;
121 char *newp;
122 struct passwd *pw;
123 uid_t myuid;
124 struct rlimit rlimit_fsize;
125 char c;
126#if ENABLE_FEATURE_SHADOWPASSWDS
127 /* Using _r function to avoid pulling in static buffers */
128 struct spwd spw;
129 char buffer[256];
130#endif
131
132 logmode = LOGMODE_BOTH;
133 openlog(applet_name, 0, LOG_AUTH);
134 opt = getopt32(argv, "a:lud", &opt_a);
135 //argc -= optind;
136 argv += optind;
137
138 myuid = getuid();
139 /* -l, -u, -d require root priv and username argument */
140 if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
141 bb_show_usage();
142
143 /* Will complain and die if username not found */
144 myname = xstrdup(xuid2uname(myuid));
145 name = argv[0] ? argv[0] : myname;
146
147 pw = xgetpwnam(name);
148 if (myuid != 0 && pw->pw_uid != myuid) {
149 /* LOGMODE_BOTH */
150 bb_error_msg_and_die("%s can't change password for %s", myname, name);
151 }
152
153#if ENABLE_FEATURE_SHADOWPASSWDS
154 {
155 /* getspnam_r may return 0 yet set result to NULL.
156 * At least glibc 2.4 does this. Be extra paranoid here. */
157 struct spwd *result = NULL;
158 errno = 0;
159 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0
160 || !result /* no error, but no record found either */
161 || strcmp(result->sp_namp, pw->pw_name) != 0 /* paranoia */
162 ) {
163 if (errno != ENOENT) {
164 /* LOGMODE_BOTH */
165 bb_perror_msg("no record of %s in %s, using %s",
166 name, bb_path_shadow_file,
167 bb_path_passwd_file);
168 }
169 /* else: /etc/shadow does not exist,
170 * apparently we are on a shadow-less system,
171 * no surprise there */
172 } else {
173 pw->pw_passwd = result->sp_pwdp;
174 }
175 }
176#endif
177
178 /* Decide what the new password will be */
179 newp = NULL;
180 c = pw->pw_passwd[0] - '!';
181 if (!(opt & OPT_lud)) {
182 if (myuid != 0 && !c) { /* passwd starts with '!' */
183 /* LOGMODE_BOTH */
184 bb_error_msg_and_die("can't change "
185 "locked password for %s", name);
186 }
187 printf("Changing password for %s\n", name);
188 newp = new_password(pw, myuid, opt_a);
189 if (!newp) {
190 logmode = LOGMODE_STDIO;
191 bb_error_msg_and_die("password for %s is unchanged", name);
192 }
193 } else if (opt & OPT_lock) {
194 if (!c)
195 goto skip; /* passwd starts with '!' */
196 newp = xasprintf("!%s", pw->pw_passwd);
197 } else if (opt & OPT_unlock) {
198 if (c)
199 goto skip; /* not '!' */
200 /* pw->pw_passwd points to static storage,
201 * strdup'ing to avoid nasty surprizes */
202 newp = xstrdup(&pw->pw_passwd[1]);
203 } else if (opt & OPT_delete) {
204 newp = (char*)"";
205 }
206
207 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
208 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
209 bb_signals(0
210 + (1 << SIGHUP)
211 + (1 << SIGINT)
212 + (1 << SIGQUIT)
213 , SIG_IGN);
214 umask(077);
215 xsetuid(0);
216
217#if ENABLE_FEATURE_SHADOWPASSWDS
218 filename = bb_path_shadow_file;
219 rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
220 if (rc > 0)
221 /* password in /etc/shadow was updated */
222 newp = (char*) "x";
223 if (rc >= 0)
224 /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
225#endif
226 {
227 filename = bb_path_passwd_file;
228 rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
229 }
230 /* LOGMODE_BOTH */
231 if (rc < 0)
232 bb_error_msg_and_die("can't update password file %s", filename);
233 bb_error_msg("password for %s changed by %s", name, myname);
234
235 /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
236 skip:
237 if (!newp) {
238 bb_error_msg_and_die("password for %s is already %slocked",
239 name, (opt & OPT_unlock) ? "un" : "");
240 }
241
242 if (ENABLE_FEATURE_CLEAN_UP)
243 free(myname);
244 return 0;
245}
Note: See TracBrowser for help on using the repository browser.