1/* passwd.c - Program to update user password.
2 *
3 * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
4 * Modified 2012 Jason Kyungwan Han <asura321@gmail.com>
5 *
6 * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/passwd.html
7
8USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
9
10config PASSWD
11  bool "passwd"
12  default y
13  depends on TOYBOX_SHADOW
14  help
15    usage: passwd [-a ALGO] [-dlu] <account name>
16
17    update user's authentication tokens. Default : current user
18
19    -a ALGO	Encryption method (des, md5, sha256, sha512) default: des
20    -d		Set password to ''
21    -l		Lock (disable) account
22    -u		Unlock (enable) account
23
24config PASSWD_SAD
25  bool "Add sad password checking heuristics"
26  default n
27  depends on PASSWD
28  help
29    Password changes are checked to make sure they don't include the entire
30    username (but not a subset of it), and the entire previous password
31    (but changing password1, password2, password3 is fine). This heuristic
32    accepts "aaaaaa" as a password.
33*/
34
35#define FOR_passwd
36#include "toys.h"
37
38GLOBALS(
39  char *algo;
40)
41
42static int str_check(char *s, char *p)
43{
44  if (strnstr(s, p) || strnstr(p, s)) return 1;
45  return 0;
46}
47
48// Insane heuristic won't find password1 password2 password3...?
49static void strength_check(char *newp, char *oldp, char *user)
50{
51  char *msg = NULL;
52
53  if (strlen(newp) < 6) { //Min passwd len
54    msg = "too short";
55    xprintf("BAD PASSWORD: %s\n",msg);
56  }
57  if (!newp[0]) return; //passwd is empty
58
59  if (str_check(newp, user)) {
60    msg = "user based password";
61    xprintf("BAD PASSWORD: %s\n",msg);
62  }
63
64  if (oldp[0] && str_check(newp, oldp)) {
65    msg = "based on old passwd";
66    xprintf("BAD PASSWORD: %s\n",msg);
67  }
68}
69
70static int verify_passwd(char * pwd)
71{
72  char * pass;
73
74  if (!pwd) return 1;
75  if (pwd[0] == '!' || pwd[0] == '*') return 1;
76
77  pass = crypt(toybuf, pwd);
78  if (pass  && !strcmp(pass, pwd)) return 0;
79
80  return 1;
81}
82
83static char *new_password(char *oldp, char *user)
84{
85  char *newp = NULL;
86
87  if (read_password(toybuf, sizeof(toybuf), "New password:"))
88    return NULL; //may be due to Ctrl-C
89
90  newp = xstrdup(toybuf);
91  if (CFG_PASSWD_SAD) strength_check(newp, oldp, user);
92  if (read_password(toybuf, sizeof(toybuf), "Retype password:")) {
93    free(newp);
94    return NULL; //may be due to Ctrl-C
95  }
96
97  if (!strcmp(newp, toybuf)) return newp;
98  else error_msg("Passwords do not match.\n");
99  // Failure Case
100  free(newp);
101  return NULL;
102}
103
104void passwd_main(void)
105{
106  uid_t myuid;
107  struct passwd *pw;
108  struct spwd *sp;
109  char *name = NULL, *pass = NULL, *encrypted = NULL, *newp = NULL,
110       *orig = (char *)"", salt[MAX_SALT_LEN];
111  int ret = -1;
112
113  myuid = getuid();
114  if (myuid && (toys.optflags & (FLAG_l | FLAG_u | FLAG_d)))
115    error_exit("Not root");
116
117  pw = xgetpwuid(myuid);
118
119  if (*toys.optargs) name = toys.optargs[0];
120  else name = xstrdup(pw->pw_name);
121
122  pw = xgetpwnam(name);
123
124  if (myuid && (myuid != pw->pw_uid)) error_exit("Not root");
125
126  pass = pw->pw_passwd;
127  if (pw->pw_passwd[0] == 'x') {
128    //get shadow passwd
129    sp = getspnam(name);
130    if (sp) pass = sp->sp_pwdp;
131  }
132
133
134  if (!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) {
135
136    if (!(toys.optflags & FLAG_a)) TT.algo = "des";
137    if (get_salt(salt, TT.algo) == -1)
138      error_exit("Error: Unkown encryption algorithm\n");
139
140    printf("Changing password for %s\n",name);
141    if (myuid && pass[0] == '!')
142      error_exit("Can't change, password is locked for %s",name);
143    if (myuid) {
144      //Validate user
145
146      if (read_password(toybuf, sizeof(toybuf), "Origial password:")) {
147        if (!toys.optargs[0]) free(name);
148        return;
149      }
150      orig = toybuf;
151      if (verify_passwd(pass)) error_exit("Authentication failed\n");
152    }
153
154    orig = xstrdup(orig);
155
156    // Get new password
157    newp = new_password(orig, name);
158    if (!newp) {
159      free(orig);
160      if (!toys.optargs[0]) free(name);
161      return; //new password is not set well.
162    }
163
164    encrypted = crypt(newp, salt);
165    free(newp);
166    free(orig);
167  } else if (toys.optflags & FLAG_l) {
168    if (pass[0] == '!') error_exit("password is already locked for %s",name);
169    printf("Locking password for %s\n",name);
170    encrypted = xmprintf("!%s",pass);
171  } else if (toys.optflags & FLAG_u) {
172    if (pass[0] != '!') error_exit("password is already unlocked for %s",name);
173
174    printf("Unlocking password for %s\n",name);
175    encrypted = xstrdup(&pass[1]);
176  } else if (toys.optflags & FLAG_d) {
177    printf("Deleting password for %s\n",name);
178    encrypted = xstrdup(""); //1 = "", 2 = '\0'
179  }
180
181  // Update the passwd
182  if (pw->pw_passwd[0] == 'x')
183    ret = update_password("/etc/shadow", name, encrypted);
184  else ret = update_password("/etc/passwd", name, encrypted);
185
186  if ((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) free(encrypted);
187
188  if (!toys.optargs[0]) free(name);
189  if (!ret) error_msg("Success");
190  else error_msg("Failure");
191}
192