10f66f451Sopenharmony_ci/* passwd.c - Program to update user password.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
40f66f451Sopenharmony_ci * Modified 2012 Jason Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci *
60f66f451Sopenharmony_ci * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/passwd.html
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciUSE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciconfig PASSWD
110f66f451Sopenharmony_ci  bool "passwd"
120f66f451Sopenharmony_ci  default y
130f66f451Sopenharmony_ci  depends on TOYBOX_SHADOW
140f66f451Sopenharmony_ci  help
150f66f451Sopenharmony_ci    usage: passwd [-a ALGO] [-dlu] [USER]
160f66f451Sopenharmony_ci
170f66f451Sopenharmony_ci    Update user's authentication tokens. Defaults to current user.
180f66f451Sopenharmony_ci
190f66f451Sopenharmony_ci    -a ALGO	Encryption method (des, md5, sha256, sha512) default: des
200f66f451Sopenharmony_ci    -d		Set password to ''
210f66f451Sopenharmony_ci    -l		Lock (disable) account
220f66f451Sopenharmony_ci    -u		Unlock (enable) account
230f66f451Sopenharmony_ci
240f66f451Sopenharmony_ciconfig PASSWD_SAD
250f66f451Sopenharmony_ci  bool "Add sad password checking heuristics"
260f66f451Sopenharmony_ci  default n
270f66f451Sopenharmony_ci  depends on PASSWD
280f66f451Sopenharmony_ci  help
290f66f451Sopenharmony_ci    Password changes are checked to make sure they're at least 6 chars long,
300f66f451Sopenharmony_ci    don't include the entire username (but not a subset of it), or the entire
310f66f451Sopenharmony_ci    previous password (but changing password1, password2, password3 is fine).
320f66f451Sopenharmony_ci    This heuristic accepts "aaaaaa" and "123456".
330f66f451Sopenharmony_ci*/
340f66f451Sopenharmony_ci
350f66f451Sopenharmony_ci#define FOR_passwd
360f66f451Sopenharmony_ci#include "toys.h"
370f66f451Sopenharmony_ci
380f66f451Sopenharmony_ciGLOBALS(
390f66f451Sopenharmony_ci  char *a;
400f66f451Sopenharmony_ci)
410f66f451Sopenharmony_ci
420f66f451Sopenharmony_ci// Sad advisory heuristic, won't find password1 password2 password3...
430f66f451Sopenharmony_cistatic void weak_check(char *new, char *old, char *user)
440f66f451Sopenharmony_ci{
450f66f451Sopenharmony_ci  char *msg = 0;
460f66f451Sopenharmony_ci
470f66f451Sopenharmony_ci  if (strlen(new) < 6) msg = "too short";
480f66f451Sopenharmony_ci  if (*new) {
490f66f451Sopenharmony_ci    if (strcasestr(new, user) || strcasestr(user, new)) msg = "user";
500f66f451Sopenharmony_ci    if (*old && (strcasestr(new, old) || strcasestr(old, new))) msg = "old";
510f66f451Sopenharmony_ci  }
520f66f451Sopenharmony_ci  if (msg) xprintf("BAD PASSWORD: %s\n",msg);
530f66f451Sopenharmony_ci}
540f66f451Sopenharmony_ci
550f66f451Sopenharmony_civoid passwd_main(void)
560f66f451Sopenharmony_ci{
570f66f451Sopenharmony_ci  uid_t myuid;
580f66f451Sopenharmony_ci  struct passwd *pw = 0;
590f66f451Sopenharmony_ci  struct spwd *sp;
600f66f451Sopenharmony_ci  char *pass, *name, *encrypted = 0, salt[MAX_SALT_LEN];
610f66f451Sopenharmony_ci  int ret = -1;
620f66f451Sopenharmony_ci
630f66f451Sopenharmony_ci  // If we're root or not -lud, load specified user. Exit if not allowed.
640f66f451Sopenharmony_ci  if (!(myuid = getuid()) || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) {
650f66f451Sopenharmony_ci    if (*toys.optargs) pw = xgetpwnam(*toys.optargs);
660f66f451Sopenharmony_ci    else pw = xgetpwuid(myuid);
670f66f451Sopenharmony_ci  }
680f66f451Sopenharmony_ci  if (!pw || (myuid && (myuid != pw->pw_uid))) error_exit("Not root");
690f66f451Sopenharmony_ci
700f66f451Sopenharmony_ci  // Get password from /etc/passwd or /etc/shadow
710f66f451Sopenharmony_ci  // TODO: why still support non-shadow passwords...?
720f66f451Sopenharmony_ci  name = pw->pw_name;
730f66f451Sopenharmony_ci  if (*(pass = pw->pw_passwd)=='x' && (sp = getspnam(name))) pass = sp->sp_pwdp;
740f66f451Sopenharmony_ci
750f66f451Sopenharmony_ci  if (toys.optflags & FLAG_l) {
760f66f451Sopenharmony_ci    if (*pass=='!') error_exit("already locked");
770f66f451Sopenharmony_ci    printf("Locking '%s'\n", name);
780f66f451Sopenharmony_ci    encrypted = xmprintf("!%s", pass);
790f66f451Sopenharmony_ci  } else if (toys.optflags & FLAG_u) {
800f66f451Sopenharmony_ci    if (*pass!='!') error_exit("already unlocked");
810f66f451Sopenharmony_ci    printf("Unlocking '%s'\n", name);
820f66f451Sopenharmony_ci    encrypted = pass+1;
830f66f451Sopenharmony_ci  } else if (toys.optflags & FLAG_d) {
840f66f451Sopenharmony_ci    printf("Deleting password for '%s'\n", name);
850f66f451Sopenharmony_ci    encrypted = "";
860f66f451Sopenharmony_ci  } else {
870f66f451Sopenharmony_ci    if (get_salt(salt, TT.a ? TT.a : "des")<0) error_exit("bad -a '%s'", TT.a);
880f66f451Sopenharmony_ci
890f66f451Sopenharmony_ci    printf("Changing password for %s\n", name);
900f66f451Sopenharmony_ci    if (myuid) {
910f66f451Sopenharmony_ci      if (*pass=='!') error_exit("'%s' locked", name);
920f66f451Sopenharmony_ci
930f66f451Sopenharmony_ci      if (read_password(toybuf+2048, 2048, "Old password:")) return;
940f66f451Sopenharmony_ci      pass = crypt(toybuf+2048, pw->pw_passwd);
950f66f451Sopenharmony_ci      if (!pass || strcmp(pass, pw->pw_passwd)) error_exit("No");
960f66f451Sopenharmony_ci    }
970f66f451Sopenharmony_ci
980f66f451Sopenharmony_ci    if (read_password(toybuf, 2048, "New password:")) return;
990f66f451Sopenharmony_ci
1000f66f451Sopenharmony_ci    if (CFG_PASSWD_SAD) weak_check(toybuf, toybuf+2048, name);
1010f66f451Sopenharmony_ci    if (read_password(toybuf+2048, 2048, "Retype password:")) return;
1020f66f451Sopenharmony_ci    if (strcmp(toybuf, toybuf+2048)) error_exit("Passwords do not match.");
1030f66f451Sopenharmony_ci
1040f66f451Sopenharmony_ci    encrypted = crypt(toybuf, salt);
1050f66f451Sopenharmony_ci  }
1060f66f451Sopenharmony_ci
1070f66f451Sopenharmony_ci  // Update the passwd
1080f66f451Sopenharmony_ci  ret = update_password(*pw->pw_passwd=='x' ? "/etc/shadow" : "/etc/passwd",
1090f66f451Sopenharmony_ci    name, encrypted);
1100f66f451Sopenharmony_ci
1110f66f451Sopenharmony_ci  if (ret) error_msg("Failure");
1120f66f451Sopenharmony_ci  else fprintf(stderr, "Success\n");
1130f66f451Sopenharmony_ci
1140f66f451Sopenharmony_ci  if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_l)) free(encrypted);
1150f66f451Sopenharmony_ci}
116