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