Contents of /trunk/mkinitrd-magellan/busybox/loginutils/passwd.c
Parent Directory | Revision Log
Revision 984 -
(show annotations)
(download)
Sun May 30 11:32:42 2010 UTC (14 years, 4 months ago) by niro
File MIME type: text/plain
File size: 5758 byte(s)
Sun May 30 11:32:42 2010 UTC (14 years, 4 months 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 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
4 | */ |
5 | #include "libbb.h" |
6 | #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 | char *orig = (char*)""; |
17 | char *newp = NULL; |
18 | char *cp = NULL; |
19 | char *ret = NULL; /* failure so far */ |
20 | |
21 | if (myuid && pw->pw_passwd[0]) { |
22 | char *encrypted; |
23 | |
24 | orig = bb_ask_stdin("Old password: "); /* returns ptr to static */ |
25 | if (!orig) |
26 | goto err_ret; |
27 | 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 | pw->pw_name); |
31 | bb_do_delay(FAIL_DELAY); |
32 | puts("Incorrect password"); |
33 | goto err_ret; |
34 | } |
35 | if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); |
36 | } |
37 | orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */ |
38 | newp = bb_ask_stdin("New password: "); /* returns ptr to static */ |
39 | if (!newp) |
40 | goto err_ret; |
41 | newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */ |
42 | 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 | cp = bb_ask_stdin("Retype password: "); |
47 | if (!cp) |
48 | goto err_ret; |
49 | if (strcmp(cp, newp)) { |
50 | puts("Passwords don't match"); |
51 | goto err_ret; |
52 | } |
53 | |
54 | crypt_make_salt(salt, 1, 0); /* des */ |
55 | if (algo) { /* MD5 */ |
56 | strcpy(salt, "$1$"); |
57 | crypt_make_salt(salt + 3, 4, 0); |
58 | } |
59 | /* pw_encrypt returns malloced str */ |
60 | ret = pw_encrypt(newp, salt, 1); |
61 | /* 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 | int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
73 | int passwd_main(int argc UNUSED_PARAM, char **argv) |
74 | { |
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 | //STATE_ALGO_des = 0x20, not needed yet |
83 | }; |
84 | unsigned opt; |
85 | int rc; |
86 | const char *opt_a = ""; |
87 | 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 | #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 | |
101 | logmode = LOGMODE_BOTH; |
102 | openlog(applet_name, 0, LOG_AUTH); |
103 | opt = getopt32(argv, "a:lud", &opt_a); |
104 | //argc -= optind; |
105 | 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 | /* -l, -u, -d require root priv and username argument */ |
113 | if ((opt & OPT_lud) && (myuid || !argv[0])) |
114 | bb_show_usage(); |
115 | |
116 | /* Will complain and die if username not found */ |
117 | myname = xstrdup(xuid2uname(myuid)); |
118 | name = argv[0] ? argv[0] : myname; |
119 | |
120 | pw = xgetpwnam(name); |
121 | 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 | /* 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 | 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 | name, bb_path_shadow_file, |
140 | bb_path_passwd_file); |
141 | } |
142 | /* else: /etc/shadow does not exist, |
143 | * apparently we are on a shadow-less system, |
144 | * no surprise there */ |
145 | } else { |
146 | pw->pw_passwd = result->sp_pwdp; |
147 | } |
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 | bb_error_msg_and_die("can't change " |
158 | "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 | /* pw->pw_passwd points to static storage, |
172 | * strdup'ing to avoid nasty surprizes */ |
173 | newp = xstrdup(&pw->pw_passwd[1]); |
174 | } else if (opt & OPT_delete) { |
175 | //newp = xstrdup(""); |
176 | newp = (char*)""; |
177 | } |
178 | |
179 | rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000; |
180 | setrlimit(RLIMIT_FSIZE, &rlimit_fsize); |
181 | bb_signals(0 |
182 | + (1 << SIGHUP) |
183 | + (1 << SIGINT) |
184 | + (1 << SIGQUIT) |
185 | , SIG_IGN); |
186 | umask(077); |
187 | xsetuid(0); |
188 | |
189 | #if ENABLE_FEATURE_SHADOWPASSWDS |
190 | filename = bb_path_shadow_file; |
191 | rc = update_passwd(bb_path_shadow_file, name, newp, NULL); |
192 | if (rc == 0) /* no lines updated, no errors detected */ |
193 | #endif |
194 | { |
195 | filename = bb_path_passwd_file; |
196 | rc = update_passwd(bb_path_passwd_file, name, newp, NULL); |
197 | } |
198 | /* LOGMODE_BOTH */ |
199 | if (rc < 0) |
200 | bb_error_msg_and_die("can't update password file %s", |
201 | filename); |
202 | bb_info_msg("Password for %s changed by %s", name, myname); |
203 | |
204 | //if (ENABLE_FEATURE_CLEAN_UP) free(newp); |
205 | skip: |
206 | 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 | } |