2002-06-23 09:54:25 +05:30
|
|
|
/* vi: set sw=4 ts=4: */
|
2006-07-12 13:26:04 +05:30
|
|
|
/*
|
2010-08-16 23:44:46 +05:30
|
|
|
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
2006-07-12 13:26:04 +05:30
|
|
|
*/
|
2015-10-19 04:50:36 +05:30
|
|
|
//config:config PASSWD
|
2017-07-19 01:31:24 +05:30
|
|
|
//config: bool "passwd (21 kb)"
|
2015-10-19 04:50:36 +05:30
|
|
|
//config: default y
|
|
|
|
//config: select FEATURE_SYSLOG
|
|
|
|
//config: help
|
2017-07-21 13:20:55 +05:30
|
|
|
//config: passwd changes passwords for user and group accounts. A normal user
|
|
|
|
//config: may only change the password for his/her own account, the super user
|
|
|
|
//config: may change the password for any account. The administrator of a group
|
|
|
|
//config: may change the password for the group.
|
2015-10-19 04:50:36 +05:30
|
|
|
//config:
|
2017-07-21 13:20:55 +05:30
|
|
|
//config: Note that Busybox binary must be setuid root for this applet to
|
|
|
|
//config: work properly.
|
2015-10-19 04:50:36 +05:30
|
|
|
//config:
|
|
|
|
//config:config FEATURE_PASSWD_WEAK_CHECK
|
|
|
|
//config: bool "Check new passwords for weakness"
|
|
|
|
//config: default y
|
|
|
|
//config: depends on PASSWD
|
|
|
|
//config: help
|
2017-07-21 13:20:55 +05:30
|
|
|
//config: With this option passwd will refuse new passwords which are "weak".
|
2015-10-19 04:50:36 +05:30
|
|
|
|
|
|
|
//applet:/* Needs to be run by root or be suid root - needs to change /etc/{passwd,shadow}: */
|
|
|
|
//applet:IF_PASSWD(APPLET(passwd, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
|
|
|
|
|
|
|
|
//kbuild:lib-$(CONFIG_PASSWD) += passwd.o
|
2011-04-02 02:26:30 +05:30
|
|
|
|
|
|
|
//usage:#define passwd_trivial_usage
|
|
|
|
//usage: "[OPTIONS] [USER]"
|
|
|
|
//usage:#define passwd_full_usage "\n\n"
|
2011-05-13 07:01:45 +05:30
|
|
|
//usage: "Change USER's password (default: current user)"
|
|
|
|
//usage: "\n"
|
2017-01-21 00:17:49 +05:30
|
|
|
//usage: "\n -a ALG "CRYPT_METHODS_HELP_STR
|
2011-05-13 07:01:45 +05:30
|
|
|
//usage: "\n -d Set password to ''"
|
2011-04-02 02:26:30 +05:30
|
|
|
//usage: "\n -l Lock (disable) account"
|
2011-05-13 07:01:45 +05:30
|
|
|
//usage: "\n -u Unlock (enable) account"
|
2011-04-02 02:26:30 +05:30
|
|
|
|
2007-05-27 00:30:18 +05:30
|
|
|
#include "libbb.h"
|
2006-08-03 21:11:12 +05:30
|
|
|
#include <syslog.h>
|
2012-07-06 08:49:09 +05:30
|
|
|
#include <sys/resource.h> /* setrlimit */
|
2002-06-23 09:54:25 +05:30
|
|
|
|
2011-05-13 06:49:01 +05:30
|
|
|
static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
|
2006-11-30 22:11:15 +05:30
|
|
|
{
|
2011-05-13 06:49:01 +05:30
|
|
|
char salt[MAX_PW_SALT_LEN];
|
2007-01-30 04:21:44 +05:30
|
|
|
char *orig = (char*)"";
|
2006-11-30 22:11:15 +05:30
|
|
|
char *newp = NULL;
|
|
|
|
char *cp = NULL;
|
|
|
|
char *ret = NULL; /* failure so far */
|
|
|
|
|
2011-05-13 06:49:01 +05:30
|
|
|
if (myuid != 0 && pw->pw_passwd[0]) {
|
2008-06-12 22:26:52 +05:30
|
|
|
char *encrypted;
|
|
|
|
|
2009-11-02 23:48:49 +05:30
|
|
|
orig = bb_ask_stdin("Old password: "); /* returns ptr to static */
|
2006-11-30 22:11:15 +05:30
|
|
|
if (!orig)
|
|
|
|
goto err_ret;
|
2008-06-12 22:26:52 +05:30
|
|
|
encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
|
|
|
|
if (strcmp(encrypted, pw->pw_passwd) != 0) {
|
2011-05-13 06:49:01 +05:30
|
|
|
syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
|
2011-03-09 01:37:05 +05:30
|
|
|
bb_do_delay(LOGIN_FAIL_DELAY);
|
2006-11-30 22:11:15 +05:30
|
|
|
puts("Incorrect password");
|
|
|
|
goto err_ret;
|
|
|
|
}
|
2011-05-13 06:49:01 +05:30
|
|
|
if (ENABLE_FEATURE_CLEAN_UP)
|
|
|
|
free(encrypted);
|
2006-11-30 22:11:15 +05:30
|
|
|
}
|
2008-12-04 00:18:39 +05:30
|
|
|
orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
|
2009-11-02 23:48:49 +05:30
|
|
|
newp = bb_ask_stdin("New password: "); /* returns ptr to static */
|
2006-11-30 22:11:15 +05:30
|
|
|
if (!newp)
|
|
|
|
goto err_ret;
|
2008-12-04 00:18:39 +05:30
|
|
|
newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
|
2006-12-19 06:03:53 +05:30
|
|
|
if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
|
2011-05-13 06:49:01 +05:30
|
|
|
&& obscure(orig, newp, pw)
|
|
|
|
&& myuid != 0
|
|
|
|
) {
|
2006-12-12 23:41:58 +05:30
|
|
|
goto err_ret; /* non-root is not allowed to have weak passwd */
|
2011-05-13 06:49:01 +05:30
|
|
|
}
|
2006-11-30 22:11:15 +05:30
|
|
|
|
2009-11-02 23:48:49 +05:30
|
|
|
cp = bb_ask_stdin("Retype password: ");
|
2006-11-30 22:11:15 +05:30
|
|
|
if (!cp)
|
|
|
|
goto err_ret;
|
2011-05-13 06:49:01 +05:30
|
|
|
if (strcmp(cp, newp) != 0) {
|
2006-12-02 03:04:20 +05:30
|
|
|
puts("Passwords don't match");
|
2006-11-30 22:11:15 +05:30
|
|
|
goto err_ret;
|
|
|
|
}
|
|
|
|
|
2011-05-13 06:49:01 +05:30
|
|
|
crypt_make_pw_salt(salt, algo);
|
|
|
|
|
2008-06-12 22:26:52 +05:30
|
|
|
/* pw_encrypt returns malloced str */
|
|
|
|
ret = pw_encrypt(newp, salt, 1);
|
2006-11-30 22:11:15 +05:30
|
|
|
/* whee, success! */
|
|
|
|
|
|
|
|
err_ret:
|
|
|
|
nuke_str(orig);
|
|
|
|
if (ENABLE_FEATURE_CLEAN_UP) free(orig);
|
2011-05-13 06:49:01 +05:30
|
|
|
|
2006-11-30 22:11:15 +05:30
|
|
|
nuke_str(newp);
|
|
|
|
if (ENABLE_FEATURE_CLEAN_UP) free(newp);
|
2011-05-13 06:49:01 +05:30
|
|
|
|
2006-11-30 22:11:15 +05:30
|
|
|
nuke_str(cp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-10-11 15:35:36 +05:30
|
|
|
int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
2008-07-05 14:48:54 +05:30
|
|
|
int passwd_main(int argc UNUSED_PARAM, char **argv)
|
2002-06-23 09:54:25 +05:30
|
|
|
{
|
2006-09-23 18:00:03 +05:30
|
|
|
enum {
|
2011-05-13 06:49:01 +05:30
|
|
|
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 18:00:03 +05:30
|
|
|
};
|
2006-10-04 02:30:06 +05:30
|
|
|
unsigned opt;
|
2007-07-21 02:58:41 +05:30
|
|
|
int rc;
|
2012-01-08 21:14:37 +05:30
|
|
|
const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
|
2006-11-30 22:11:15 +05:30
|
|
|
const char *filename;
|
2002-06-23 09:54:25 +05:30
|
|
|
char *myname;
|
2006-11-30 22:11:15 +05:30
|
|
|
char *name;
|
2006-12-02 03:04:20 +05:30
|
|
|
char *newp;
|
|
|
|
struct passwd *pw;
|
2006-11-30 22:11:15 +05:30
|
|
|
uid_t myuid;
|
2006-12-02 03:04:20 +05:30
|
|
|
struct rlimit rlimit_fsize;
|
|
|
|
char c;
|
2007-03-13 18:31:14 +05:30
|
|
|
#if ENABLE_FEATURE_SHADOWPASSWDS
|
|
|
|
/* Using _r function to avoid pulling in static buffers */
|
|
|
|
struct spwd spw;
|
|
|
|
char buffer[256];
|
|
|
|
#endif
|
|
|
|
|
2006-12-02 03:04:20 +05:30
|
|
|
logmode = LOGMODE_BOTH;
|
2009-03-11 21:29:49 +05:30
|
|
|
openlog(applet_name, 0, LOG_AUTH);
|
2007-08-18 21:02:12 +05:30
|
|
|
opt = getopt32(argv, "a:lud", &opt_a);
|
2007-07-27 16:50:10 +05:30
|
|
|
//argc -= optind;
|
2006-09-23 18:00:03 +05:30
|
|
|
argv += optind;
|
2006-11-30 22:11:15 +05:30
|
|
|
|
|
|
|
myuid = getuid();
|
2007-07-27 16:50:10 +05:30
|
|
|
/* -l, -u, -d require root priv and username argument */
|
2011-05-13 06:49:01 +05:30
|
|
|
if ((opt & OPT_lud) && (myuid != 0 || !argv[0]))
|
2003-03-19 14:43:01 +05:30
|
|
|
bb_show_usage();
|
2006-09-23 18:00:03 +05:30
|
|
|
|
2007-07-27 16:50:10 +05:30
|
|
|
/* Will complain and die if username not found */
|
2008-12-03 04:26:59 +05:30
|
|
|
myname = xstrdup(xuid2uname(myuid));
|
2007-07-27 16:50:10 +05:30
|
|
|
name = argv[0] ? argv[0] : myname;
|
2006-09-23 18:00:03 +05:30
|
|
|
|
2008-12-04 00:35:55 +05:30
|
|
|
pw = xgetpwnam(name);
|
2011-05-13 06:49:01 +05:30
|
|
|
if (myuid != 0 && pw->pw_uid != myuid) {
|
2006-12-02 03:04:20 +05:30
|
|
|
/* LOGMODE_BOTH */
|
|
|
|
bb_error_msg_and_die("%s can't change password for %s", myname, name);
|
2002-06-23 09:54:25 +05:30
|
|
|
}
|
2006-11-30 22:11:15 +05:30
|
|
|
|
2006-12-30 20:16:51 +05:30
|
|
|
#if ENABLE_FEATURE_SHADOWPASSWDS
|
2007-10-30 00:55:45 +05:30
|
|
|
{
|
|
|
|
/* 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-10 02:51:55 +05:30
|
|
|
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-30 00:55:45 +05:30
|
|
|
name, bb_path_shadow_file,
|
|
|
|
bb_path_passwd_file);
|
2010-01-10 02:51:55 +05:30
|
|
|
}
|
|
|
|
/* else: /etc/shadow does not exist,
|
|
|
|
* apparently we are on a shadow-less system,
|
|
|
|
* no surprise there */
|
2007-10-30 00:55:45 +05:30
|
|
|
} else {
|
|
|
|
pw->pw_passwd = result->sp_pwdp;
|
|
|
|
}
|
2006-11-30 22:11:15 +05:30
|
|
|
}
|
2006-12-30 20:16:51 +05:30
|
|
|
#endif
|
2002-06-23 09:54:25 +05:30
|
|
|
|
2006-11-30 22:11:15 +05:30
|
|
|
/* Decide what the new password will be */
|
2006-12-02 03:04:20 +05:30
|
|
|
newp = NULL;
|
|
|
|
c = pw->pw_passwd[0] - '!';
|
2006-09-23 18:00:03 +05:30
|
|
|
if (!(opt & OPT_lud)) {
|
2011-05-13 06:49:01 +05:30
|
|
|
if (myuid != 0 && !c) { /* passwd starts with '!' */
|
2006-12-02 03:04:20 +05:30
|
|
|
/* LOGMODE_BOTH */
|
2009-11-13 13:38:27 +05:30
|
|
|
bb_error_msg_and_die("can't change "
|
2006-12-02 03:04:20 +05:30
|
|
|
"locked password for %s", name);
|
2002-06-23 09:54:25 +05:30
|
|
|
}
|
|
|
|
printf("Changing password for %s\n", name);
|
2011-05-13 06:49:01 +05:30
|
|
|
newp = new_password(pw, myuid, opt_a);
|
2006-11-30 22:11:15 +05:30
|
|
|
if (!newp) {
|
2006-12-02 03:04:20 +05:30
|
|
|
logmode = LOGMODE_STDIO;
|
|
|
|
bb_error_msg_and_die("password for %s is unchanged", name);
|
2002-06-23 09:54:25 +05:30
|
|
|
}
|
2006-09-23 18:00:03 +05:30
|
|
|
} else if (opt & OPT_lock) {
|
2011-05-13 06:49:01 +05:30
|
|
|
if (!c)
|
|
|
|
goto skip; /* passwd starts with '!' */
|
2006-12-02 03:04:20 +05:30
|
|
|
newp = xasprintf("!%s", pw->pw_passwd);
|
2006-09-23 18:00:03 +05:30
|
|
|
} else if (opt & OPT_unlock) {
|
2011-05-13 06:49:01 +05:30
|
|
|
if (c)
|
|
|
|
goto skip; /* not '!' */
|
2007-10-30 00:55:45 +05:30
|
|
|
/* pw->pw_passwd points to static storage,
|
2007-07-27 16:50:10 +05:30
|
|
|
* strdup'ing to avoid nasty surprizes */
|
2006-12-02 03:04:20 +05:30
|
|
|
newp = xstrdup(&pw->pw_passwd[1]);
|
2006-09-23 18:00:03 +05:30
|
|
|
} else if (opt & OPT_delete) {
|
2011-05-13 06:49:01 +05:30
|
|
|
newp = (char*)"";
|
2002-06-23 09:54:25 +05:30
|
|
|
}
|
2006-11-30 22:11:15 +05:30
|
|
|
|
2006-12-02 03:04:20 +05:30
|
|
|
rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
|
|
|
|
setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
|
2008-02-17 04:28:56 +05:30
|
|
|
bb_signals(0
|
|
|
|
+ (1 << SIGHUP)
|
|
|
|
+ (1 << SIGINT)
|
|
|
|
+ (1 << SIGQUIT)
|
|
|
|
, SIG_IGN);
|
2002-06-23 09:54:25 +05:30
|
|
|
umask(077);
|
2006-07-16 13:36:34 +05:30
|
|
|
xsetuid(0);
|
2007-07-27 16:52:34 +05:30
|
|
|
|
|
|
|
#if ENABLE_FEATURE_SHADOWPASSWDS
|
|
|
|
filename = bb_path_shadow_file;
|
2009-04-14 06:21:05 +05:30
|
|
|
rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
|
2011-04-05 03:48:33 +05:30
|
|
|
if (rc > 0)
|
|
|
|
/* password in /etc/shadow was updated */
|
2011-05-13 06:49:01 +05:30
|
|
|
newp = (char*) "x";
|
2011-04-05 03:48:33 +05:30
|
|
|
if (rc >= 0)
|
|
|
|
/* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
|
2007-07-27 16:52:34 +05:30
|
|
|
#endif
|
|
|
|
{
|
|
|
|
filename = bb_path_passwd_file;
|
2009-04-14 06:21:05 +05:30
|
|
|
rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
|
2007-07-27 16:52:34 +05:30
|
|
|
}
|
|
|
|
/* LOGMODE_BOTH */
|
2007-07-21 02:58:41 +05:30
|
|
|
if (rc < 0)
|
2011-05-13 06:49:01 +05:30
|
|
|
bb_error_msg_and_die("can't update password file %s", filename);
|
2016-03-30 19:50:28 +05:30
|
|
|
bb_error_msg("password for %s changed by %s", name, myname);
|
2002-06-23 09:54:25 +05:30
|
|
|
|
2011-05-13 06:49:01 +05:30
|
|
|
/*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
|
2007-07-27 16:50:10 +05:30
|
|
|
skip:
|
2006-12-02 03:04:20 +05:30
|
|
|
if (!newp) {
|
|
|
|
bb_error_msg_and_die("password for %s is already %slocked",
|
|
|
|
name, (opt & OPT_unlock) ? "un" : "");
|
|
|
|
}
|
2011-05-13 06:49:01 +05:30
|
|
|
|
|
|
|
if (ENABLE_FEATURE_CLEAN_UP)
|
|
|
|
free(myname);
|
2002-06-23 09:54:25 +05:30
|
|
|
return 0;
|
|
|
|
}
|