Contents of /tags/mkinitrd-6_1_10/busybox/loginutils/passwd.c
Parent Directory | Revision Log
Revision 922 -
(show annotations)
(download)
Wed Oct 28 09:51:31 2009 UTC (14 years, 11 months ago) by niro
File MIME type: text/plain
File size: 5591 byte(s)
Wed Oct 28 09:51:31 2009 UTC (14 years, 11 months ago) by niro
File MIME type: text/plain
File size: 5591 byte(s)
tagged 'mkinitrd-6_1_10'
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
4 | */ |
5 | |
6 | #include "libbb.h" |
7 | #include <syslog.h> |
8 | |
9 | static void nuke_str(char *str) |
10 | { |
11 | if (str) memset(str, 0, strlen(str)); |
12 | } |
13 | |
14 | static char* new_password(const struct passwd *pw, uid_t myuid, int algo) |
15 | { |
16 | char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */ |
17 | char *orig = (char*)""; |
18 | char *newp = NULL; |
19 | char *cp = NULL; |
20 | char *ret = NULL; /* failure so far */ |
21 | |
22 | if (myuid && pw->pw_passwd[0]) { |
23 | char *encrypted; |
24 | |
25 | orig = bb_askpass(0, "Old password:"); /* returns ptr to static */ |
26 | if (!orig) |
27 | goto err_ret; |
28 | encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */ |
29 | if (strcmp(encrypted, pw->pw_passwd) != 0) { |
30 | syslog(LOG_WARNING, "incorrect password for %s", |
31 | pw->pw_name); |
32 | bb_do_delay(FAIL_DELAY); |
33 | puts("Incorrect password"); |
34 | goto err_ret; |
35 | } |
36 | if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); |
37 | } |
38 | orig = xstrdup(orig); /* or else bb_askpass() will destroy it */ |
39 | newp = bb_askpass(0, "New password:"); /* returns ptr to static */ |
40 | if (!newp) |
41 | goto err_ret; |
42 | newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */ |
43 | if (ENABLE_FEATURE_PASSWD_WEAK_CHECK |
44 | && obscure(orig, newp, pw) && myuid) |
45 | goto err_ret; /* non-root is not allowed to have weak passwd */ |
46 | |
47 | cp = bb_askpass(0, "Retype password:"); |
48 | if (!cp) |
49 | goto err_ret; |
50 | if (strcmp(cp, newp)) { |
51 | puts("Passwords don't match"); |
52 | goto err_ret; |
53 | } |
54 | |
55 | crypt_make_salt(salt, 1, 0); /* des */ |
56 | if (algo) { /* MD5 */ |
57 | strcpy(salt, "$1$"); |
58 | crypt_make_salt(salt + 3, 4, 0); |
59 | } |
60 | /* pw_encrypt returns malloced str */ |
61 | ret = pw_encrypt(newp, salt, 1); |
62 | /* whee, success! */ |
63 | |
64 | err_ret: |
65 | nuke_str(orig); |
66 | if (ENABLE_FEATURE_CLEAN_UP) free(orig); |
67 | nuke_str(newp); |
68 | if (ENABLE_FEATURE_CLEAN_UP) free(newp); |
69 | nuke_str(cp); |
70 | return ret; |
71 | } |
72 | |
73 | int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
74 | int passwd_main(int argc UNUSED_PARAM, char **argv) |
75 | { |
76 | enum { |
77 | OPT_algo = 0x1, /* -a - password algorithm */ |
78 | OPT_lock = 0x2, /* -l - lock account */ |
79 | OPT_unlock = 0x4, /* -u - unlock account */ |
80 | OPT_delete = 0x8, /* -d - delete password */ |
81 | OPT_lud = 0xe, |
82 | STATE_ALGO_md5 = 0x10, |
83 | //STATE_ALGO_des = 0x20, not needed yet |
84 | }; |
85 | unsigned opt; |
86 | int rc; |
87 | const char *opt_a = ""; |
88 | const char *filename; |
89 | char *myname; |
90 | char *name; |
91 | char *newp; |
92 | struct passwd *pw; |
93 | uid_t myuid; |
94 | struct rlimit rlimit_fsize; |
95 | char c; |
96 | #if ENABLE_FEATURE_SHADOWPASSWDS |
97 | /* Using _r function to avoid pulling in static buffers */ |
98 | struct spwd spw; |
99 | char buffer[256]; |
100 | #endif |
101 | |
102 | logmode = LOGMODE_BOTH; |
103 | openlog(applet_name, LOG_NOWAIT, LOG_AUTH); |
104 | opt = getopt32(argv, "a:lud", &opt_a); |
105 | //argc -= optind; |
106 | argv += optind; |
107 | |
108 | if (strcasecmp(opt_a, "des") != 0) /* -a */ |
109 | opt |= STATE_ALGO_md5; |
110 | //else |
111 | // opt |= STATE_ALGO_des; |
112 | myuid = getuid(); |
113 | /* -l, -u, -d require root priv and username argument */ |
114 | if ((opt & OPT_lud) && (myuid || !argv[0])) |
115 | bb_show_usage(); |
116 | |
117 | /* Will complain and die if username not found */ |
118 | myname = xstrdup(bb_getpwuid(NULL, -1, myuid)); |
119 | name = argv[0] ? argv[0] : myname; |
120 | |
121 | pw = getpwnam(name); |
122 | if (!pw) |
123 | bb_error_msg_and_die("unknown user %s", name); |
124 | if (myuid && pw->pw_uid != myuid) { |
125 | /* LOGMODE_BOTH */ |
126 | bb_error_msg_and_die("%s can't change password for %s", myname, name); |
127 | } |
128 | |
129 | #if ENABLE_FEATURE_SHADOWPASSWDS |
130 | { |
131 | /* getspnam_r may return 0 yet set result to NULL. |
132 | * At least glibc 2.4 does this. Be extra paranoid here. */ |
133 | struct spwd *result = NULL; |
134 | if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) |
135 | || !result || strcmp(result->sp_namp, pw->pw_name) != 0) { |
136 | /* LOGMODE_BOTH */ |
137 | bb_error_msg("no record of %s in %s, using %s", |
138 | name, bb_path_shadow_file, |
139 | bb_path_passwd_file); |
140 | } else { |
141 | pw->pw_passwd = result->sp_pwdp; |
142 | } |
143 | } |
144 | #endif |
145 | |
146 | /* Decide what the new password will be */ |
147 | newp = NULL; |
148 | c = pw->pw_passwd[0] - '!'; |
149 | if (!(opt & OPT_lud)) { |
150 | if (myuid && !c) { /* passwd starts with '!' */ |
151 | /* LOGMODE_BOTH */ |
152 | bb_error_msg_and_die("cannot change " |
153 | "locked password for %s", name); |
154 | } |
155 | printf("Changing password for %s\n", name); |
156 | newp = new_password(pw, myuid, opt & STATE_ALGO_md5); |
157 | if (!newp) { |
158 | logmode = LOGMODE_STDIO; |
159 | bb_error_msg_and_die("password for %s is unchanged", name); |
160 | } |
161 | } else if (opt & OPT_lock) { |
162 | if (!c) goto skip; /* passwd starts with '!' */ |
163 | newp = xasprintf("!%s", pw->pw_passwd); |
164 | } else if (opt & OPT_unlock) { |
165 | if (c) goto skip; /* not '!' */ |
166 | /* pw->pw_passwd points to static storage, |
167 | * strdup'ing to avoid nasty surprizes */ |
168 | newp = xstrdup(&pw->pw_passwd[1]); |
169 | } else if (opt & OPT_delete) { |
170 | //newp = xstrdup(""); |
171 | newp = (char*)""; |
172 | } |
173 | |
174 | rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000; |
175 | setrlimit(RLIMIT_FSIZE, &rlimit_fsize); |
176 | bb_signals(0 |
177 | + (1 << SIGHUP) |
178 | + (1 << SIGINT) |
179 | + (1 << SIGQUIT) |
180 | , SIG_IGN); |
181 | umask(077); |
182 | xsetuid(0); |
183 | |
184 | #if ENABLE_FEATURE_SHADOWPASSWDS |
185 | filename = bb_path_shadow_file; |
186 | rc = update_passwd(bb_path_shadow_file, name, newp); |
187 | if (rc == 0) /* no lines updated, no errors detected */ |
188 | #endif |
189 | { |
190 | filename = bb_path_passwd_file; |
191 | rc = update_passwd(bb_path_passwd_file, name, newp); |
192 | } |
193 | /* LOGMODE_BOTH */ |
194 | if (rc < 0) |
195 | bb_error_msg_and_die("cannot update password file %s", |
196 | filename); |
197 | bb_info_msg("Password for %s changed by %s", name, myname); |
198 | |
199 | //if (ENABLE_FEATURE_CLEAN_UP) free(newp); |
200 | skip: |
201 | if (!newp) { |
202 | bb_error_msg_and_die("password for %s is already %slocked", |
203 | name, (opt & OPT_unlock) ? "un" : ""); |
204 | } |
205 | if (ENABLE_FEATURE_CLEAN_UP) free(myname); |
206 | return 0; |
207 | } |