191 lines
4.9 KiB
C
191 lines
4.9 KiB
C
/* passwd.c - Program to update user password.
|
|
*
|
|
* Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
|
|
* Modified 2012 Jason Kyungwan Han <asura321@gmail.com>
|
|
*
|
|
* http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/passwd.html
|
|
|
|
USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
|
|
|
|
config PASSWD
|
|
bool "passwd"
|
|
default y
|
|
depends on TOYBOX_SHADOW
|
|
help
|
|
usage: passwd [-a ALGO] [-dlu] <account name>
|
|
|
|
update user's authentication tokens. Default : current user
|
|
|
|
-a ALGO Encryption method (des, md5, sha256, sha512) default: des
|
|
-d Set password to ''
|
|
-l Lock (disable) account
|
|
-u Unlock (enable) account
|
|
|
|
config PASSWD_SAD
|
|
bool "Add sad password checking heuristics"
|
|
default n
|
|
depends on PASSWD
|
|
help
|
|
Password changes are checked to make sure they don't include the entire
|
|
username (but not a subset of it), and the entire previous password
|
|
(but changing password1, password2, password3 is fine). This heuristic
|
|
accepts "aaaaaa" as a password.
|
|
*/
|
|
|
|
#define FOR_passwd
|
|
#include "toys.h"
|
|
|
|
GLOBALS(
|
|
char *algo;
|
|
)
|
|
|
|
static int str_check(char *s, char *p)
|
|
{
|
|
if (strnstr(s, p) || strnstr(p, s)) return 1;
|
|
return 0;
|
|
}
|
|
|
|
// Insane heuristic won't find password1 password2 password3...?
|
|
static void strength_check(char *newp, char *oldp, char *user)
|
|
{
|
|
char *msg = NULL;
|
|
|
|
if (strlen(newp) < 6) { //Min passwd len
|
|
msg = "too short";
|
|
xprintf("BAD PASSWORD: %s\n",msg);
|
|
}
|
|
if (!newp[0]) return; //passwd is empty
|
|
|
|
if (str_check(newp, user)) {
|
|
msg = "user based password";
|
|
xprintf("BAD PASSWORD: %s\n",msg);
|
|
}
|
|
|
|
if (oldp[0] && str_check(newp, oldp)) {
|
|
msg = "based on old passwd";
|
|
xprintf("BAD PASSWORD: %s\n",msg);
|
|
}
|
|
}
|
|
|
|
static int verify_passwd(char * pwd)
|
|
{
|
|
char * pass;
|
|
|
|
if (!pwd) return 1;
|
|
if (pwd[0] == '!' || pwd[0] == '*') return 1;
|
|
|
|
pass = crypt(toybuf, pwd);
|
|
if (pass && !strcmp(pass, pwd)) return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static char *new_password(char *oldp, char *user)
|
|
{
|
|
char *newp = NULL;
|
|
|
|
if (read_password(toybuf, sizeof(toybuf), "New password:"))
|
|
return NULL; //may be due to Ctrl-C
|
|
|
|
newp = xstrdup(toybuf);
|
|
if (CFG_PASSWD_SAD) strength_check(newp, oldp, user);
|
|
if (read_password(toybuf, sizeof(toybuf), "Retype password:")) {
|
|
free(newp);
|
|
return NULL; //may be due to Ctrl-C
|
|
}
|
|
|
|
if (!strcmp(newp, toybuf)) return newp;
|
|
else error_msg("Passwords do not match.\n");
|
|
// Failure Case
|
|
free(newp);
|
|
return NULL;
|
|
}
|
|
|
|
void passwd_main(void)
|
|
{
|
|
uid_t myuid;
|
|
struct passwd *pw;
|
|
struct spwd *sp;
|
|
char *name = NULL, *pass = NULL, *encrypted = NULL, *newp = NULL,
|
|
*orig = (char *)"", salt[MAX_SALT_LEN];
|
|
int ret = -1;
|
|
|
|
myuid = getuid();
|
|
if (myuid && (toys.optflags & (FLAG_l | FLAG_u | FLAG_d)))
|
|
error_exit("Not root");
|
|
|
|
pw = xgetpwuid(myuid);
|
|
|
|
if (*toys.optargs) name = toys.optargs[0];
|
|
else name = xstrdup(pw->pw_name);
|
|
|
|
pw = xgetpwnam(name);
|
|
|
|
if (myuid && (myuid != pw->pw_uid)) error_exit("Not root");
|
|
|
|
pass = pw->pw_passwd;
|
|
if (pw->pw_passwd[0] == 'x') {
|
|
//get shadow passwd
|
|
sp = getspnam(name);
|
|
if (sp) pass = sp->sp_pwdp;
|
|
}
|
|
|
|
|
|
if (!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) {
|
|
|
|
if (!(toys.optflags & FLAG_a)) TT.algo = "des";
|
|
if (get_salt(salt, TT.algo) == -1)
|
|
error_exit("Error: Unkown encryption algorithm\n");
|
|
|
|
printf("Changing password for %s\n",name);
|
|
if (myuid && pass[0] == '!')
|
|
error_exit("Can't change, password is locked for %s",name);
|
|
if (myuid) {
|
|
//Validate user
|
|
|
|
if (read_password(toybuf, sizeof(toybuf), "Origial password:")) {
|
|
if (!toys.optargs[0]) free(name);
|
|
return;
|
|
}
|
|
orig = toybuf;
|
|
if (verify_passwd(pass)) error_exit("Authentication failed\n");
|
|
}
|
|
|
|
orig = xstrdup(orig);
|
|
|
|
// Get new password
|
|
newp = new_password(orig, name);
|
|
if (!newp) {
|
|
free(orig);
|
|
if (!toys.optargs[0]) free(name);
|
|
return; //new password is not set well.
|
|
}
|
|
|
|
encrypted = crypt(newp, salt);
|
|
free(newp);
|
|
free(orig);
|
|
} else if (toys.optflags & FLAG_l) {
|
|
if (pass[0] == '!') error_exit("password is already locked for %s",name);
|
|
printf("Locking password for %s\n",name);
|
|
encrypted = xmprintf("!%s",pass);
|
|
} else if (toys.optflags & FLAG_u) {
|
|
if (pass[0] != '!') error_exit("password is already unlocked for %s",name);
|
|
|
|
printf("Unlocking password for %s\n",name);
|
|
encrypted = xstrdup(&pass[1]);
|
|
} else if (toys.optflags & FLAG_d) {
|
|
printf("Deleting password for %s\n",name);
|
|
encrypted = xstrdup(""); //1 = "", 2 = '\0'
|
|
}
|
|
|
|
// Update the passwd
|
|
if (pw->pw_passwd[0] == 'x')
|
|
ret = update_password("/etc/shadow", name, encrypted);
|
|
else ret = update_password("/etc/passwd", name, encrypted);
|
|
|
|
if ((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) free(encrypted);
|
|
|
|
if (!toys.optargs[0]) free(name);
|
|
if (!ret) error_msg("Success");
|
|
else error_msg("Failure");
|
|
}
|