source: MondoRescue/branches/3.2/mindi-busybox/loginutils/passwd.c@ 3232

Last change on this file since 3232 was 3232, checked in by Bruno Cornec, 10 years ago
  • Update mindi-busybox to 1.21.1
File size: 6.0 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
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)"
10//usage: "\n"
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"
15
16#include "libbb.h"
17#include <syslog.h>
18#include <sys/resource.h> /* setrlimit */
19
20static void nuke_str(char *str)
21{
22 if (str) memset(str, 0, strlen(str));
23}
24
25static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
26{
27 char salt[MAX_PW_SALT_LEN];
28 char *orig = (char*)"";
29 char *newp = NULL;
30 char *cp = NULL;
31 char *ret = NULL; /* failure so far */
32
33 if (myuid != 0 && pw->pw_passwd[0]) {
34 char *encrypted;
35
36 orig = bb_ask_stdin("Old password: "); /* returns ptr to static */
37 if (!orig)
38 goto err_ret;
39 encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
40 if (strcmp(encrypted, pw->pw_passwd) != 0) {
41 syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
42 bb_do_delay(LOGIN_FAIL_DELAY);
43 puts("Incorrect password");
44 goto err_ret;
45 }
46 if (ENABLE_FEATURE_CLEAN_UP)
47 free(encrypted);
48 }
49 orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
50 newp = bb_ask_stdin("New password: "); /* returns ptr to static */
51 if (!newp)
52 goto err_ret;
53 newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
54 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
55 && obscure(orig, newp, pw)
56 && myuid != 0
57 ) {
58 goto err_ret; /* non-root is not allowed to have weak passwd */
59 }
60
61 cp = bb_ask_stdin("Retype password: ");
62 if (!cp)
63 goto err_ret;
64 if (strcmp(cp, newp) != 0) {
65 puts("Passwords don't match");
66 goto err_ret;
67 }
68
69 crypt_make_pw_salt(salt, algo);
70
71 /* pw_encrypt returns malloced str */
72 ret = pw_encrypt(newp, salt, 1);
73 /* whee, success! */
74
75 err_ret:
76 nuke_str(orig);
77 if (ENABLE_FEATURE_CLEAN_UP) free(orig);
78
79 nuke_str(newp);
80 if (ENABLE_FEATURE_CLEAN_UP) free(newp);
81
82 nuke_str(cp);
83 return ret;
84}
85
86int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
87int passwd_main(int argc UNUSED_PARAM, char **argv)
88{
89 enum {
90 OPT_algo = (1 << 0), /* -a - password algorithm */
91 OPT_lock = (1 << 1), /* -l - lock account */
92 OPT_unlock = (1 << 2), /* -u - unlock account */
93 OPT_delete = (1 << 3), /* -d - delete password */
94 OPT_lud = OPT_lock | OPT_unlock | OPT_delete,
95 };
96 unsigned opt;
97 int rc;
98 const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
99 const char *filename;
100 char *myname;
101 char *name;
102 char *newp;
103 struct passwd *pw;
104 uid_t myuid;
105 struct rlimit rlimit_fsize;
106 char c;
107#if ENABLE_FEATURE_SHADOWPASSWDS
108 /* Using _r function to avoid pulling in static buffers */
109 struct spwd spw;
110 char buffer[256];
111#endif
112
113 logmode = LOGMODE_BOTH;
114 openlog(applet_name, 0, LOG_AUTH);
115 opt = getopt32(argv, "a:lud", &opt_a);
116 //argc -= optind;
117 argv += optind;
118
119 myuid = getuid();
120 /* -l, -u, -d require root priv and username argument */
121 if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
122 bb_show_usage();
123
124 /* Will complain and die if username not found */
125 myname = xstrdup(xuid2uname(myuid));
126 name = argv[0] ? argv[0] : myname;
127
128 pw = xgetpwnam(name);
129 if (myuid != 0 && pw->pw_uid != myuid) {
130 /* LOGMODE_BOTH */
131 bb_error_msg_and_die("%s can't change password for %s", myname, name);
132 }
133
134#if ENABLE_FEATURE_SHADOWPASSWDS
135 {
136 /* getspnam_r may return 0 yet set result to NULL.
137 * At least glibc 2.4 does this. Be extra paranoid here. */
138 struct spwd *result = NULL;
139 errno = 0;
140 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0
141 || !result /* no error, but no record found either */
142 || strcmp(result->sp_namp, pw->pw_name) != 0 /* paranoia */
143 ) {
144 if (errno != ENOENT) {
145 /* LOGMODE_BOTH */
146 bb_perror_msg("no record of %s in %s, using %s",
147 name, bb_path_shadow_file,
148 bb_path_passwd_file);
149 }
150 /* else: /etc/shadow does not exist,
151 * apparently we are on a shadow-less system,
152 * no surprise there */
153 } else {
154 pw->pw_passwd = result->sp_pwdp;
155 }
156 }
157#endif
158
159 /* Decide what the new password will be */
160 newp = NULL;
161 c = pw->pw_passwd[0] - '!';
162 if (!(opt & OPT_lud)) {
163 if (myuid != 0 && !c) { /* passwd starts with '!' */
164 /* LOGMODE_BOTH */
165 bb_error_msg_and_die("can't change "
166 "locked password for %s", name);
167 }
168 printf("Changing password for %s\n", name);
169 newp = new_password(pw, myuid, opt_a);
170 if (!newp) {
171 logmode = LOGMODE_STDIO;
172 bb_error_msg_and_die("password for %s is unchanged", name);
173 }
174 } else if (opt & OPT_lock) {
175 if (!c)
176 goto skip; /* passwd starts with '!' */
177 newp = xasprintf("!%s", pw->pw_passwd);
178 } else if (opt & OPT_unlock) {
179 if (c)
180 goto skip; /* not '!' */
181 /* pw->pw_passwd points to static storage,
182 * strdup'ing to avoid nasty surprizes */
183 newp = xstrdup(&pw->pw_passwd[1]);
184 } else if (opt & OPT_delete) {
185 newp = (char*)"";
186 }
187
188 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
189 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
190 bb_signals(0
191 + (1 << SIGHUP)
192 + (1 << SIGINT)
193 + (1 << SIGQUIT)
194 , SIG_IGN);
195 umask(077);
196 xsetuid(0);
197
198#if ENABLE_FEATURE_SHADOWPASSWDS
199 filename = bb_path_shadow_file;
200 rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
201 if (rc > 0)
202 /* password in /etc/shadow was updated */
203 newp = (char*) "x";
204 if (rc >= 0)
205 /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
206#endif
207 {
208 filename = bb_path_passwd_file;
209 rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
210 }
211 /* LOGMODE_BOTH */
212 if (rc < 0)
213 bb_error_msg_and_die("can't update password file %s", filename);
214 bb_info_msg("Password for %s changed by %s", name, myname);
215
216 /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
217 skip:
218 if (!newp) {
219 bb_error_msg_and_die("password for %s is already %slocked",
220 name, (opt & OPT_unlock) ? "un" : "");
221 }
222
223 if (ENABLE_FEATURE_CLEAN_UP)
224 free(myname);
225 return 0;
226}
Note: See TracBrowser for help on using the repository browser.