1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#include "libbb.h"
41#include <syslog.h>
42
43static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
44{
45 char salt[MAX_PW_SALT_LEN];
46 char *orig = NULL;
47 char *newp = NULL;
48 char *cp = NULL;
49 char *ret = NULL;
50
51 if (myuid != 0 && pw->pw_passwd[0]) {
52 char *encrypted;
53
54 orig = bb_ask_noecho_stdin("Old password: ");
55 if (!orig)
56 goto err_ret;
57 encrypted = pw_encrypt(orig, pw->pw_passwd, 1);
58 if (strcmp(encrypted, pw->pw_passwd) != 0) {
59 syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
60 pause_after_failed_login();
61 puts("Incorrect password");
62 goto err_ret;
63 }
64 if (ENABLE_FEATURE_CLEAN_UP)
65 free(encrypted);
66 }
67 newp = bb_ask_noecho_stdin("New password: ");
68 if (!newp)
69 goto err_ret;
70 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
71 && obscure(orig, newp, pw)
72 && myuid != 0
73 ) {
74 goto err_ret;
75 }
76
77 cp = bb_ask_noecho_stdin("Retype password: ");
78 if (!cp)
79 goto err_ret;
80 if (strcmp(cp, newp) != 0) {
81 puts("Passwords don't match");
82 goto err_ret;
83 }
84
85 crypt_make_pw_salt(salt, algo);
86
87
88 ret = pw_encrypt(newp, salt, 1);
89
90
91 err_ret:
92 nuke_str(orig);
93 if (ENABLE_FEATURE_CLEAN_UP) free(orig);
94
95 nuke_str(newp);
96 if (ENABLE_FEATURE_CLEAN_UP) free(newp);
97
98 nuke_str(cp);
99 if (ENABLE_FEATURE_CLEAN_UP) free(cp);
100 return ret;
101}
102
103int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
104int passwd_main(int argc UNUSED_PARAM, char **argv)
105{
106 enum {
107 OPT_algo = (1 << 0),
108 OPT_lock = (1 << 1),
109 OPT_unlock = (1 << 2),
110 OPT_delete = (1 << 3),
111 OPT_lud = OPT_lock | OPT_unlock | OPT_delete,
112 };
113 unsigned opt;
114 int rc;
115 const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
116 const char *filename;
117 char *myname;
118 char *name;
119 char *newp;
120 struct passwd *pw;
121 uid_t myuid;
122 struct rlimit rlimit_fsize;
123 char c;
124#if ENABLE_FEATURE_SHADOWPASSWDS
125
126 struct spwd spw;
127 char buffer[256];
128#endif
129
130 logmode = LOGMODE_BOTH;
131 openlog(applet_name, 0, LOG_AUTH);
132 opt = getopt32(argv, "a:lud", &opt_a);
133
134 argv += optind;
135
136 myuid = getuid();
137
138 if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
139 bb_show_usage();
140
141
142 myname = xstrdup(xuid2uname(myuid));
143 name = argv[0] ? argv[0] : myname;
144
145 pw = xgetpwnam(name);
146 if (myuid != 0 && pw->pw_uid != myuid) {
147
148 bb_error_msg_and_die("%s can't change password for %s", myname, name);
149 }
150
151#if ENABLE_FEATURE_SHADOWPASSWDS
152 {
153
154
155 struct spwd *result = NULL;
156 errno = 0;
157 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0
158 || !result
159 || strcmp(result->sp_namp, pw->pw_name) != 0
160 ) {
161 if (errno != ENOENT) {
162
163 bb_perror_msg("no record of %s in %s, using %s",
164 name, bb_path_shadow_file,
165 bb_path_passwd_file);
166 }
167
168
169
170 } else {
171 pw->pw_passwd = result->sp_pwdp;
172 }
173 }
174#endif
175
176
177 newp = NULL;
178 c = pw->pw_passwd[0] - '!';
179 if (!(opt & OPT_lud)) {
180 if (myuid != 0 && !c) {
181
182 bb_error_msg_and_die("can't change "
183 "locked password for %s", name);
184 }
185 printf("Changing password for %s\n", name);
186 newp = new_password(pw, myuid, opt_a);
187 if (!newp) {
188 logmode = LOGMODE_STDIO;
189 bb_error_msg_and_die("password for %s is unchanged", name);
190 }
191 } else if (opt & OPT_lock) {
192 if (!c)
193 goto skip;
194 newp = xasprintf("!%s", pw->pw_passwd);
195 } else if (opt & OPT_unlock) {
196 if (c)
197 goto skip;
198
199
200 newp = xstrdup(&pw->pw_passwd[1]);
201 } else if (opt & OPT_delete) {
202 newp = (char*)"";
203 }
204
205 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
206 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
207 bb_signals(0
208 + (1 << SIGHUP)
209 + (1 << SIGINT)
210 + (1 << SIGQUIT)
211 , SIG_IGN);
212 umask(077);
213 xsetuid(0);
214
215#if ENABLE_FEATURE_SHADOWPASSWDS
216 filename = bb_path_shadow_file;
217 rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
218 if (rc > 0)
219
220 newp = (char*) "x";
221 if (rc >= 0)
222
223#endif
224 {
225 filename = bb_path_passwd_file;
226 rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
227 }
228
229 if (rc < 0)
230 bb_error_msg_and_die("can't update password file %s", filename);
231 bb_info_msg("password for %s changed by %s", name, myname);
232
233
234 skip:
235 if (!newp) {
236 bb_error_msg_and_die("password for %s is already %slocked",
237 name, (opt & OPT_unlock) ? "un" : "");
238 }
239
240 if (ENABLE_FEATURE_CLEAN_UP)
241 free(myname);
242 return 0;
243}
244