2002-06-23 04:24:25 +00:00
|
|
|
/* vi: set sw=4 ts=4: */
|
2006-07-12 07:56:04 +00:00
|
|
|
/*
|
2010-08-16 18:14:46 +00:00
|
|
|
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
2006-07-12 07:56:04 +00:00
|
|
|
*/
|
2011-04-01 20:56:30 +00:00
|
|
|
|
|
|
|
//usage:#define passwd_trivial_usage
|
|
|
|
//usage: "[OPTIONS] [USER]"
|
|
|
|
//usage:#define passwd_full_usage "\n\n"
|
2011-05-13 01:31:45 +00:00
|
|
|
//usage: "Change USER's password (default: current user)"
|
|
|
|
//usage: "\n"
|
2011-05-13 01:19:01 +00:00
|
|
|
//usage: "\n -a ALG Encryption method"
|
2011-05-13 01:31:45 +00:00
|
|
|
//usage: "\n -d Set password to ''"
|
2011-04-01 20:56:30 +00:00
|
|
|
//usage: "\n -l Lock (disable) account"
|
2011-05-13 01:31:45 +00:00
|
|
|
//usage: "\n -u Unlock (enable) account"
|
2011-04-01 20:56:30 +00:00
|
|
|
|
2007-05-26 19:00:18 +00:00
|
|
|
#include "libbb.h"
|
2006-08-03 15:41:12 +00:00
|
|
|
#include <syslog.h>
|
2012-07-06 03:19:09 +00:00
|
|
|
#include <sys/resource.h> /* setrlimit */
|
2002-06-23 04:24:25 +00:00
|
|
|
|
2011-05-13 01:19:01 +00:00
|
|
|
static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
|
2006-11-30 16:41:15 +00:00
|
|
|
{
|
2011-05-13 01:19:01 +00:00
|
|
|
char salt[MAX_PW_SALT_LEN];
|
2007-01-29 22:51:44 +00:00
|
|
|
char *orig = (char*)"";
|
2006-11-30 16:41:15 +00:00
|
|
|
char *newp = NULL;
|
|
|
|
char *cp = NULL;
|
|
|
|
char *ret = NULL; /* failure so far */
|
|
|
|
|
2011-05-13 01:19:01 +00:00
|
|
|
if (myuid != 0 && pw->pw_passwd[0]) {
|
2008-06-12 16:56:52 +00:00
|
|
|
char *encrypted;
|
|
|
|
|
2009-11-02 18:18:49 +00:00
|
|
|
orig = bb_ask_stdin("Old password: "); /* returns ptr to static */
|
2006-11-30 16:41:15 +00:00
|
|
|
if (!orig)
|
|
|
|
goto err_ret;
|
2008-06-12 16:56:52 +00:00
|
|
|
encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
|
|
|
|
if (strcmp(encrypted, pw->pw_passwd) != 0) {
|
2011-05-13 01:19:01 +00:00
|
|
|
syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
|
2011-03-08 20:07:05 +00:00
|
|
|
bb_do_delay(LOGIN_FAIL_DELAY);
|
2006-11-30 16:41:15 +00:00
|
|
|
puts("Incorrect password");
|
|
|
|
goto err_ret;
|
|
|
|
}
|
2011-05-13 01:19:01 +00:00
|
|
|
if (ENABLE_FEATURE_CLEAN_UP)
|
|
|
|
free(encrypted);
|
2006-11-30 16:41:15 +00:00
|
|
|
}
|
2008-12-03 18:48:39 +00:00
|
|
|
orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
|
2009-11-02 18:18:49 +00:00
|
|
|
newp = bb_ask_stdin("New password: "); /* returns ptr to static */
|
2006-11-30 16:41:15 +00:00
|
|
|
if (!newp)
|
|
|
|
goto err_ret;
|
2008-12-03 18:48:39 +00:00
|
|
|
newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
|
2006-12-19 00:33:53 +00:00
|
|
|
if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
|
2011-05-13 01:19:01 +00:00
|
|
|
&& obscure(orig, newp, pw)
|
|
|
|
&& myuid != 0
|
|
|
|
) {
|
2006-12-12 18:11:58 +00:00
|
|
|
goto err_ret; /* non-root is not allowed to have weak passwd */
|
2011-05-13 01:19:01 +00:00
|
|
|
}
|
2006-11-30 16:41:15 +00:00
|
|
|
|
2009-11-02 18:18:49 +00:00
|
|
|
cp = bb_ask_stdin("Retype password: ");
|
2006-11-30 16:41:15 +00:00
|
|
|
if (!cp)
|
|
|
|
goto err_ret;
|
2011-05-13 01:19:01 +00:00
|
|
|
if (strcmp(cp, newp) != 0) {
|
2006-12-01 21:34:20 +00:00
|
|
|
puts("Passwords don't match");
|
2006-11-30 16:41:15 +00:00
|
|
|
goto err_ret;
|
|
|
|
}
|
|
|
|
|
2011-05-13 01:19:01 +00:00
|
|
|
crypt_make_pw_salt(salt, algo);
|
|
|
|
|
2008-06-12 16:56:52 +00:00
|
|
|
/* pw_encrypt returns malloced str */
|
|
|
|
ret = pw_encrypt(newp, salt, 1);
|
2006-11-30 16:41:15 +00:00
|
|
|
/* whee, success! */
|
|
|
|
|
|
|
|
err_ret:
|
|
|
|
nuke_str(orig);
|
|
|
|
if (ENABLE_FEATURE_CLEAN_UP) free(orig);
|
2011-05-13 01:19:01 +00:00
|
|
|
|
2006-11-30 16:41:15 +00:00
|
|
|
nuke_str(newp);
|
|
|
|
if (ENABLE_FEATURE_CLEAN_UP) free(newp);
|
2011-05-13 01:19:01 +00:00
|
|
|
|
2006-11-30 16:41:15 +00:00
|
|
|
nuke_str(cp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-10-11 10:05:36 +00:00
|
|
|
int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
2008-07-05 09:18:54 +00:00
|
|
|
int passwd_main(int argc UNUSED_PARAM, char **argv)
|
2002-06-23 04:24:25 +00:00
|
|
|
{
|
2006-09-23 12:30:03 +00:00
|
|
|
enum {
|
2011-05-13 01:19:01 +00:00
|
|
|
OPT_algo = (1 << 0), /* -a - password algorithm */
|
|
|
|
OPT_lock = (1 << 1), /* -l - lock account */
|
|
|
|
OPT_unlock = (1 << 2), /* -u - unlock account */
|
|
|
|
OPT_delete = (1 << 3), /* -d - delete password */
|
|
|
|
OPT_lud = OPT_lock | OPT_unlock | OPT_delete,
|
2006-09-23 12:30:03 +00:00
|
|
|
};
|
2006-10-03 21:00:06 +00:00
|
|
|
unsigned opt;
|
2007-07-20 21:28:41 +00:00
|
|
|
int rc;
|
2012-01-08 15:44:37 +00:00
|
|
|
const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
|
2006-11-30 16:41:15 +00:00
|
|
|
const char *filename;
|
2002-06-23 04:24:25 +00:00
|
|
|
char *myname;
|
2006-11-30 16:41:15 +00:00
|
|
|
char *name;
|
2006-12-01 21:34:20 +00:00
|
|
|
char *newp;
|
|
|
|
struct passwd *pw;
|
2006-11-30 16:41:15 +00:00
|
|
|
uid_t myuid;
|
2006-12-01 21:34:20 +00:00
|
|
|
struct rlimit rlimit_fsize;
|
|
|
|
char c;
|
2007-03-13 13:01:14 +00:00
|
|
|
#if ENABLE_FEATURE_SHADOWPASSWDS
|
|
|
|
/* Using _r function to avoid pulling in static buffers */
|
|
|
|
struct spwd spw;
|
|
|
|
char buffer[256];
|
|
|
|
#endif
|
|
|
|
|
2006-12-01 21:34:20 +00:00
|
|
|
logmode = LOGMODE_BOTH;
|
2009-03-11 15:59:49 +00:00
|
|
|
openlog(applet_name, 0, LOG_AUTH);
|
2007-08-18 15:32:12 +00:00
|
|
|
opt = getopt32(argv, "a:lud", &opt_a);
|
2007-07-27 11:20:10 +00:00
|
|
|
//argc -= optind;
|
2006-09-23 12:30:03 +00:00
|
|
|
argv += optind;
|
2006-11-30 16:41:15 +00:00
|
|
|
|
|
|
|
myuid = getuid();
|
2007-07-27 11:20:10 +00:00
|
|
|
/* -l, -u, -d require root priv and username argument */
|
2011-05-13 01:19:01 +00:00
|
|
|
if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
|
2003-03-19 09:13:01 +00:00
|
|
|
bb_show_usage();
|
2006-09-23 12:30:03 +00:00
|
|
|
|
2007-07-27 11:20:10 +00:00
|
|
|
/* Will complain and die if username not found */
|
2008-12-02 22:56:59 +00:00
|
|
|
myname = xstrdup(xuid2uname(myuid));
|
2007-07-27 11:20:10 +00:00
|
|
|
name = argv[0] ? argv[0] : myname;
|
2006-09-23 12:30:03 +00:00
|
|
|
|
2008-12-03 19:05:55 +00:00
|
|
|
pw = xgetpwnam(name);
|
2011-05-13 01:19:01 +00:00
|
|
|
if (myuid != 0 && pw->pw_uid != myuid) {
|
2006-12-01 21:34:20 +00:00
|
|
|
/* LOGMODE_BOTH */
|
|
|
|
bb_error_msg_and_die("%s can't change password for %s", myname, name);
|
2002-06-23 04:24:25 +00:00
|
|
|
}
|
2006-11-30 16:41:15 +00:00
|
|
|
|
2006-12-30 14:46:51 +00:00
|
|
|
#if ENABLE_FEATURE_SHADOWPASSWDS
|
2007-10-29 19:25:45 +00:00
|
|
|
{
|
|
|
|
/* getspnam_r may return 0 yet set result to NULL.
|
|
|
|
* At least glibc 2.4 does this. Be extra paranoid here. */
|
|
|
|
struct spwd *result = NULL;
|
2010-01-09 21:21:55 +00:00
|
|
|
errno = 0;
|
|
|
|
if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0
|
|
|
|
|| !result /* no error, but no record found either */
|
|
|
|
|| strcmp(result->sp_namp, pw->pw_name) != 0 /* paranoia */
|
|
|
|
) {
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
/* LOGMODE_BOTH */
|
|
|
|
bb_perror_msg("no record of %s in %s, using %s",
|
2007-10-29 19:25:45 +00:00
|
|
|
name, bb_path_shadow_file,
|
|
|
|
bb_path_passwd_file);
|
2010-01-09 21:21:55 +00:00
|
|
|
}
|
|
|
|
/* else: /etc/shadow does not exist,
|
|
|
|
* apparently we are on a shadow-less system,
|
|
|
|
* no surprise there */
|
2007-10-29 19:25:45 +00:00
|
|
|
} else {
|
|
|
|
pw->pw_passwd = result->sp_pwdp;
|
|
|
|
}
|
2006-11-30 16:41:15 +00:00
|
|
|
}
|
2006-12-30 14:46:51 +00:00
|
|
|
#endif
|
2002-06-23 04:24:25 +00:00
|
|
|
|
2006-11-30 16:41:15 +00:00
|
|
|
/* Decide what the new password will be */
|
2006-12-01 21:34:20 +00:00
|
|
|
newp = NULL;
|
|
|
|
c = pw->pw_passwd[0] - '!';
|
2006-09-23 12:30:03 +00:00
|
|
|
if (!(opt & OPT_lud)) {
|
2011-05-13 01:19:01 +00:00
|
|
|
if (myuid != 0 && !c) { /* passwd starts with '!' */
|
2006-12-01 21:34:20 +00:00
|
|
|
/* LOGMODE_BOTH */
|
2009-11-13 08:08:27 +00:00
|
|
|
bb_error_msg_and_die("can't change "
|
2006-12-01 21:34:20 +00:00
|
|
|
"locked password for %s", name);
|
2002-06-23 04:24:25 +00:00
|
|
|
}
|
|
|
|
printf("Changing password for %s\n", name);
|
2011-05-13 01:19:01 +00:00
|
|
|
newp = new_password(pw, myuid, opt_a);
|
2006-11-30 16:41:15 +00:00
|
|
|
if (!newp) {
|
2006-12-01 21:34:20 +00:00
|
|
|
logmode = LOGMODE_STDIO;
|
|
|
|
bb_error_msg_and_die("password for %s is unchanged", name);
|
2002-06-23 04:24:25 +00:00
|
|
|
}
|
2006-09-23 12:30:03 +00:00
|
|
|
} else if (opt & OPT_lock) {
|
2011-05-13 01:19:01 +00:00
|
|
|
if (!c)
|
|
|
|
goto skip; /* passwd starts with '!' */
|
2006-12-01 21:34:20 +00:00
|
|
|
newp = xasprintf("!%s", pw->pw_passwd);
|
2006-09-23 12:30:03 +00:00
|
|
|
} else if (opt & OPT_unlock) {
|
2011-05-13 01:19:01 +00:00
|
|
|
if (c)
|
|
|
|
goto skip; /* not '!' */
|
2007-10-29 19:25:45 +00:00
|
|
|
/* pw->pw_passwd points to static storage,
|
2007-07-27 11:20:10 +00:00
|
|
|
* strdup'ing to avoid nasty surprizes */
|
2006-12-01 21:34:20 +00:00
|
|
|
newp = xstrdup(&pw->pw_passwd[1]);
|
2006-09-23 12:30:03 +00:00
|
|
|
} else if (opt & OPT_delete) {
|
2011-05-13 01:19:01 +00:00
|
|
|
newp = (char*)"";
|
2002-06-23 04:24:25 +00:00
|
|
|
}
|
2006-11-30 16:41:15 +00:00
|
|
|
|
2006-12-01 21:34:20 +00:00
|
|
|
rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
|
|
|
|
setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
|
2008-02-16 22:58:56 +00:00
|
|
|
bb_signals(0
|
|
|
|
+ (1 << SIGHUP)
|
|
|
|
+ (1 << SIGINT)
|
|
|
|
+ (1 << SIGQUIT)
|
|
|
|
, SIG_IGN);
|
2002-06-23 04:24:25 +00:00
|
|
|
umask(077);
|
2006-07-16 08:06:34 +00:00
|
|
|
xsetuid(0);
|
2007-07-27 11:22:34 +00:00
|
|
|
|
|
|
|
#if ENABLE_FEATURE_SHADOWPASSWDS
|
|
|
|
filename = bb_path_shadow_file;
|
2009-04-14 00:51:05 +00:00
|
|
|
rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
|
2011-04-04 22:18:33 +00:00
|
|
|
if (rc > 0)
|
|
|
|
/* password in /etc/shadow was updated */
|
2011-05-13 01:19:01 +00:00
|
|
|
newp = (char*) "x";
|
2011-04-04 22:18:33 +00:00
|
|
|
if (rc >= 0)
|
|
|
|
/* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
|
2007-07-27 11:22:34 +00:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
filename = bb_path_passwd_file;
|
2009-04-14 00:51:05 +00:00
|
|
|
rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
|
2007-07-27 11:22:34 +00:00
|
|
|
}
|
|
|
|
/* LOGMODE_BOTH */
|
2007-07-20 21:28:41 +00:00
|
|
|
if (rc < 0)
|
2011-05-13 01:19:01 +00:00
|
|
|
bb_error_msg_and_die("can't update password file %s", filename);
|
2006-12-01 21:34:20 +00:00
|
|
|
bb_info_msg("Password for %s changed by %s", name, myname);
|
2002-06-23 04:24:25 +00:00
|
|
|
|
2011-05-13 01:19:01 +00:00
|
|
|
/*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
|
2007-07-27 11:20:10 +00:00
|
|
|
skip:
|
2006-12-01 21:34:20 +00:00
|
|
|
if (!newp) {
|
|
|
|
bb_error_msg_and_die("password for %s is already %slocked",
|
|
|
|
name, (opt & OPT_unlock) ? "un" : "");
|
|
|
|
}
|
2011-05-13 01:19:01 +00:00
|
|
|
|
|
|
|
if (ENABLE_FEATURE_CLEAN_UP)
|
|
|
|
free(myname);
|
2002-06-23 04:24:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|