source: MondoRescue/branches/3.2/mindi-busybox/loginutils/passwd.c@ 3232

Last change on this file since 3232 was 3232, checked in by Bruno Cornec, 10 years ago
  • Update mindi-busybox to 1.21.1
File size: 6.0 KB
RevLine 
[821]1/* vi: set sw=4 ts=4: */
[1765]2/*
[2725]3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
[1765]4 */
[3232]5
6//usage:#define passwd_trivial_usage
7//usage: "[OPTIONS] [USER]"
8//usage:#define passwd_full_usage "\n\n"
9//usage: "Change USER's password (default: current user)"
10//usage: "\n"
11//usage: "\n -a ALG Encryption method"
12//usage: "\n -d Set password to ''"
13//usage: "\n -l Lock (disable) account"
14//usage: "\n -u Unlock (enable) account"
15
[1765]16#include "libbb.h"
[821]17#include <syslog.h>
[3232]18#include <sys/resource.h> /* setrlimit */
[821]19
[1765]20static void nuke_str(char *str)
[821]21{
[1765]22 if (str) memset(str, 0, strlen(str));
[821]23}
24
[3232]25static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
[821]26{
[3232]27 char salt[MAX_PW_SALT_LEN];
[1765]28 char *orig = (char*)"";
29 char *newp = NULL;
30 char *cp = NULL;
31 char *ret = NULL; /* failure so far */
[821]32
[3232]33 if (myuid != 0 && pw->pw_passwd[0]) {
[2725]34 char *encrypted;
35
36 orig = bb_ask_stdin("Old password: "); /* returns ptr to static */
[1765]37 if (!orig)
38 goto err_ret;
[2725]39 encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
40 if (strcmp(encrypted, pw->pw_passwd) != 0) {
[3232]41 syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
42 bb_do_delay(LOGIN_FAIL_DELAY);
[1765]43 puts("Incorrect password");
44 goto err_ret;
45 }
[3232]46 if (ENABLE_FEATURE_CLEAN_UP)
47 free(encrypted);
[821]48 }
[2725]49 orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
50 newp = bb_ask_stdin("New password: "); /* returns ptr to static */
[1765]51 if (!newp)
52 goto err_ret;
[2725]53 newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
[1765]54 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
[3232]55 && obscure(orig, newp, pw)
56 && myuid != 0
57 ) {
[1765]58 goto err_ret; /* non-root is not allowed to have weak passwd */
[3232]59 }
[821]60
[2725]61 cp = bb_ask_stdin("Retype password: ");
[1765]62 if (!cp)
63 goto err_ret;
[3232]64 if (strcmp(cp, newp) != 0) {
[1765]65 puts("Passwords don't match");
66 goto err_ret;
[821]67 }
68
[3232]69 crypt_make_pw_salt(salt, algo);
70
[2725]71 /* pw_encrypt returns malloced str */
72 ret = pw_encrypt(newp, salt, 1);
[1765]73 /* whee, success! */
[821]74
[1765]75 err_ret:
76 nuke_str(orig);
77 if (ENABLE_FEATURE_CLEAN_UP) free(orig);
[3232]78
[1765]79 nuke_str(newp);
80 if (ENABLE_FEATURE_CLEAN_UP) free(newp);
[3232]81
[1765]82 nuke_str(cp);
83 return ret;
[821]84}
85
[2725]86int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
87int passwd_main(int argc UNUSED_PARAM, char **argv)
[821]88{
[1765]89 enum {
[3232]90 OPT_algo = (1 << 0), /* -a - password algorithm */
91 OPT_lock = (1 << 1), /* -l - lock account */
92 OPT_unlock = (1 << 2), /* -u - unlock account */
93 OPT_delete = (1 << 3), /* -d - delete password */
94 OPT_lud = OPT_lock | OPT_unlock | OPT_delete,
[1765]95 };
96 unsigned opt;
97 int rc;
[3232]98 const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
[1765]99 const char *filename;
100 char *myname;
[821]101 char *name;
[1765]102 char *newp;
103 struct passwd *pw;
104 uid_t myuid;
105 struct rlimit rlimit_fsize;
106 char c;
[821]107#if ENABLE_FEATURE_SHADOWPASSWDS
[1765]108 /* Using _r function to avoid pulling in static buffers */
109 struct spwd spw;
110 char buffer[256];
[821]111#endif
[1765]112
113 logmode = LOGMODE_BOTH;
[2725]114 openlog(applet_name, 0, LOG_AUTH);
[1765]115 opt = getopt32(argv, "a:lud", &opt_a);
116 //argc -= optind;
117 argv += optind;
118
119 myuid = getuid();
120 /* -l, -u, -d require root priv and username argument */
[3232]121 if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
[821]122 bb_show_usage();
[1765]123
124 /* Will complain and die if username not found */
[2725]125 myname = xstrdup(xuid2uname(myuid));
[1765]126 name = argv[0] ? argv[0] : myname;
127
[2725]128 pw = xgetpwnam(name);
[3232]129 if (myuid != 0 && pw->pw_uid != myuid) {
[1765]130 /* LOGMODE_BOTH */
131 bb_error_msg_and_die("%s can't change password for %s", myname, name);
[821]132 }
[1765]133
[821]134#if ENABLE_FEATURE_SHADOWPASSWDS
[2725]135 {
136 /* getspnam_r may return 0 yet set result to NULL.
137 * At least glibc 2.4 does this. Be extra paranoid here. */
138 struct spwd *result = NULL;
139 errno = 0;
140 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0
141 || !result /* no error, but no record found either */
142 || strcmp(result->sp_namp, pw->pw_name) != 0 /* paranoia */
143 ) {
144 if (errno != ENOENT) {
145 /* LOGMODE_BOTH */
146 bb_perror_msg("no record of %s in %s, using %s",
147 name, bb_path_shadow_file,
148 bb_path_passwd_file);
149 }
150 /* else: /etc/shadow does not exist,
151 * apparently we are on a shadow-less system,
152 * no surprise there */
153 } else {
154 pw->pw_passwd = result->sp_pwdp;
155 }
[821]156 }
157#endif
158
[1765]159 /* Decide what the new password will be */
160 newp = NULL;
161 c = pw->pw_passwd[0] - '!';
162 if (!(opt & OPT_lud)) {
[3232]163 if (myuid != 0 && !c) { /* passwd starts with '!' */
[1765]164 /* LOGMODE_BOTH */
[2725]165 bb_error_msg_and_die("can't change "
[1765]166 "locked password for %s", name);
[821]167 }
168 printf("Changing password for %s\n", name);
[3232]169 newp = new_password(pw, myuid, opt_a);
[1765]170 if (!newp) {
171 logmode = LOGMODE_STDIO;
172 bb_error_msg_and_die("password for %s is unchanged", name);
[821]173 }
[1765]174 } else if (opt & OPT_lock) {
[3232]175 if (!c)
176 goto skip; /* passwd starts with '!' */
[1765]177 newp = xasprintf("!%s", pw->pw_passwd);
178 } else if (opt & OPT_unlock) {
[3232]179 if (c)
180 goto skip; /* not '!' */
[2725]181 /* pw->pw_passwd points to static storage,
[1765]182 * strdup'ing to avoid nasty surprizes */
183 newp = xstrdup(&pw->pw_passwd[1]);
184 } else if (opt & OPT_delete) {
185 newp = (char*)"";
[821]186 }
[1765]187
188 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
189 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
[2725]190 bb_signals(0
191 + (1 << SIGHUP)
192 + (1 << SIGINT)
193 + (1 << SIGQUIT)
194 , SIG_IGN);
[821]195 umask(077);
196 xsetuid(0);
197
[1765]198#if ENABLE_FEATURE_SHADOWPASSWDS
199 filename = bb_path_shadow_file;
[2725]200 rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
[3232]201 if (rc > 0)
202 /* password in /etc/shadow was updated */
203 newp = (char*) "x";
204 if (rc >= 0)
205 /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
[1765]206#endif
[821]207 {
[1765]208 filename = bb_path_passwd_file;
[2725]209 rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
[821]210 }
[1765]211 /* LOGMODE_BOTH */
212 if (rc < 0)
[3232]213 bb_error_msg_and_die("can't update password file %s", filename);
[1765]214 bb_info_msg("Password for %s changed by %s", name, myname);
[821]215
[3232]216 /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
[1765]217 skip:
218 if (!newp) {
219 bb_error_msg_and_die("password for %s is already %slocked",
220 name, (opt & OPT_unlock) ? "un" : "");
[821]221 }
[3232]222
223 if (ENABLE_FEATURE_CLEAN_UP)
224 free(myname);
[821]225 return 0;
226}
Note: See TracBrowser for help on using the repository browser.