Annotation of /tags/mkinitrd-6_2_0/loginutils/passwd.c
Parent Directory | Revision Log
Revision 816 -
(hide annotations)
(download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 5 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/loginutils/passwd.c
File MIME type: text/plain
File size: 5591 byte(s)
Fri Apr 24 18:33:46 2009 UTC (15 years, 5 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/loginutils/passwd.c
File MIME type: text/plain
File size: 5591 byte(s)
-updated to busybox-1.13.4
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
4 | */ | ||
5 | |||
6 | niro | 816 | #include "libbb.h" |
7 | niro | 532 | #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 | niro | 816 | char *orig = (char*)""; |
18 | niro | 532 | char *newp = NULL; |
19 | char *cp = NULL; | ||
20 | char *ret = NULL; /* failure so far */ | ||
21 | |||
22 | if (myuid && pw->pw_passwd[0]) { | ||
23 | niro | 816 | char *encrypted; |
24 | |||
25 | niro | 532 | orig = bb_askpass(0, "Old password:"); /* returns ptr to static */ |
26 | if (!orig) | ||
27 | goto err_ret; | ||
28 | niro | 816 | 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 | niro | 532 | pw->pw_name); |
32 | bb_do_delay(FAIL_DELAY); | ||
33 | puts("Incorrect password"); | ||
34 | goto err_ret; | ||
35 | } | ||
36 | niro | 816 | if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); |
37 | niro | 532 | } |
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 | niro | 816 | crypt_make_salt(salt, 1, 0); /* des */ |
56 | niro | 532 | if (algo) { /* MD5 */ |
57 | strcpy(salt, "$1$"); | ||
58 | niro | 816 | crypt_make_salt(salt + 3, 4, 0); |
59 | niro | 532 | } |
60 | niro | 816 | /* pw_encrypt returns malloced str */ |
61 | ret = pw_encrypt(newp, salt, 1); | ||
62 | niro | 532 | /* 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 | niro | 816 | int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
74 | int passwd_main(int argc UNUSED_PARAM, char **argv) | ||
75 | niro | 532 | { |
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 | niro | 816 | //STATE_ALGO_des = 0x20, not needed yet |
84 | niro | 532 | }; |
85 | unsigned opt; | ||
86 | niro | 816 | int rc; |
87 | const char *opt_a = ""; | ||
88 | niro | 532 | 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 | niro | 816 | #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 | niro | 532 | |
102 | logmode = LOGMODE_BOTH; | ||
103 | openlog(applet_name, LOG_NOWAIT, LOG_AUTH); | ||
104 | niro | 816 | opt = getopt32(argv, "a:lud", &opt_a); |
105 | //argc -= optind; | ||
106 | niro | 532 | 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 | niro | 816 | /* -l, -u, -d require root priv and username argument */ |
114 | if ((opt & OPT_lud) && (myuid || !argv[0])) | ||
115 | niro | 532 | bb_show_usage(); |
116 | |||
117 | niro | 816 | /* Will complain and die if username not found */ |
118 | myname = xstrdup(bb_getpwuid(NULL, -1, myuid)); | ||
119 | name = argv[0] ? argv[0] : myname; | ||
120 | niro | 532 | |
121 | pw = getpwnam(name); | ||
122 | niro | 816 | if (!pw) |
123 | bb_error_msg_and_die("unknown user %s", name); | ||
124 | niro | 532 | 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 | niro | 816 | /* 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 | niro | 532 | /* 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 | niro | 816 | pw->pw_passwd = result->sp_pwdp; |
142 | niro | 532 | } |
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 | niro | 816 | /* pw->pw_passwd points to static storage, |
167 | * strdup'ing to avoid nasty surprizes */ | ||
168 | niro | 532 | newp = xstrdup(&pw->pw_passwd[1]); |
169 | } else if (opt & OPT_delete) { | ||
170 | niro | 816 | //newp = xstrdup(""); |
171 | newp = (char*)""; | ||
172 | niro | 532 | } |
173 | |||
174 | rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000; | ||
175 | setrlimit(RLIMIT_FSIZE, &rlimit_fsize); | ||
176 | niro | 816 | bb_signals(0 |
177 | + (1 << SIGHUP) | ||
178 | + (1 << SIGINT) | ||
179 | + (1 << SIGQUIT) | ||
180 | , SIG_IGN); | ||
181 | niro | 532 | umask(077); |
182 | xsetuid(0); | ||
183 | niro | 816 | |
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 | niro | 532 | 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 | niro | 816 | //if (ENABLE_FEATURE_CLEAN_UP) free(newp); |
200 | skip: | ||
201 | niro | 532 | 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 | } |