Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 1 | /* passwd.c - Program to update user password. |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 2 | * |
| 3 | * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com> |
| 4 | * Modified 2012 Jason Kyungwan Han <asura321@gmail.com> |
| 5 | * |
Rob Landley | f91b7c8 | 2012-08-25 18:08:51 -0500 | [diff] [blame] | 6 | * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/passwd.html |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 7 | |
| 8 | USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) |
| 9 | |
| 10 | config PASSWD |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 11 | bool "passwd" |
| 12 | default y |
Isaac Dunham | 46ddf0e | 2014-11-19 16:38:46 -0600 | [diff] [blame^] | 13 | depends on TOYBOX_SHADOW |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 14 | help |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 15 | usage: passwd [-a ALGO] [-dlu] <account name> |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 16 | |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 17 | update user's authentication tokens. Default : current user |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 18 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 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 |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 23 | */ |
| 24 | |
Rob Landley | c0e56ed | 2012-10-08 00:02:30 -0500 | [diff] [blame] | 25 | #define FOR_passwd |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 26 | #include "toys.h" |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 27 | |
Rob Landley | c0e56ed | 2012-10-08 00:02:30 -0500 | [diff] [blame] | 28 | GLOBALS( |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 29 | char *algo; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 30 | ) |
| 31 | |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 32 | #ifndef _GNU_SOURCE |
| 33 | char *strcasestr(const char *haystack, const char *needle); |
| 34 | #endif |
| 35 | |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 36 | static int str_check(char *s, char *p) |
| 37 | { |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 38 | if (strcasestr(s, p) || strcasestr(p, s)) return 1; |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 39 | return 0; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | static void strength_check(char *newp, char *oldp, char *user) |
| 43 | { |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 44 | char *msg = NULL; |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 45 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 46 | if (strlen(newp) < 6) { //Min passwd len |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 47 | msg = "too short"; |
| 48 | xprintf("BAD PASSWORD: %s\n",msg); |
| 49 | } |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 50 | if (!newp[0]) return; //passwd is empty |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 51 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 52 | if (str_check(newp, user)) { |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 53 | msg = "user based password"; |
| 54 | xprintf("BAD PASSWORD: %s\n",msg); |
| 55 | } |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 56 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 57 | if (oldp[0] && str_check(newp, oldp)) { |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 58 | msg = "based on old passwd"; |
| 59 | xprintf("BAD PASSWORD: %s\n",msg); |
| 60 | } |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | static int verify_passwd(char * pwd) |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 64 | { |
| 65 | char * pass; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 66 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 67 | if (!pwd) return 1; |
| 68 | if (pwd[0] == '!' || pwd[0] == '*') return 1; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 69 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 70 | pass = crypt(toybuf, pwd); |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 71 | if (pass && !strcmp(pass, pwd)) return 0; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 72 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 73 | return 1; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 74 | } |
| 75 | |
| 76 | static char *new_password(char *oldp, char *user) |
| 77 | { |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 78 | char *newp = NULL; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 79 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 80 | if (read_password(toybuf, sizeof(toybuf), "New password:")) |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 81 | return NULL; //may be due to Ctrl-C |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 82 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 83 | newp = xstrdup(toybuf); |
| 84 | strength_check(newp, oldp, user); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 85 | if (read_password(toybuf, sizeof(toybuf), "Retype password:")) { |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 86 | free(newp); |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 87 | return NULL; //may be due to Ctrl-C |
| 88 | } |
| 89 | |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 90 | if (!strcmp(newp, toybuf)) return newp; |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 91 | else error_msg("Passwords do not match.\n"); |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 92 | // Failure Case |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 93 | free(newp); |
| 94 | return NULL; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 95 | } |
| 96 | |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 97 | void passwd_main(void) |
| 98 | { |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 99 | uid_t myuid; |
| 100 | struct passwd *pw; |
| 101 | struct spwd *sp; |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 102 | char *name = NULL, *pass = NULL, *encrypted = NULL, *newp = NULL, |
| 103 | *orig = (char *)"", salt[MAX_SALT_LEN]; |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 104 | int ret = -1; |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 105 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 106 | myuid = getuid(); |
Rob Landley | 5ec4ab3 | 2013-11-28 21:06:15 -0600 | [diff] [blame] | 107 | if (myuid && (toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) |
| 108 | error_exit("Not root"); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 109 | |
Rob Landley | 5ec4ab3 | 2013-11-28 21:06:15 -0600 | [diff] [blame] | 110 | pw = xgetpwuid(myuid); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 111 | |
Rob Landley | 5ec4ab3 | 2013-11-28 21:06:15 -0600 | [diff] [blame] | 112 | if (*toys.optargs) name = toys.optargs[0]; |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 113 | else name = xstrdup(pw->pw_name); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 114 | |
Rob Landley | 5ec4ab3 | 2013-11-28 21:06:15 -0600 | [diff] [blame] | 115 | pw = xgetpwnam(name); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 116 | |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 117 | if (myuid && (myuid != pw->pw_uid)) |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 118 | error_exit("You need to be root to change '%s' password\n", name); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 119 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 120 | pass = pw->pw_passwd; |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 121 | if (pw->pw_passwd[0] == 'x') { |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 122 | //get shadow passwd |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 123 | sp = getspnam(name); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 124 | if (sp) pass = sp->sp_pwdp; |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 128 | if (!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) { |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 129 | |
| 130 | if (!(toys.optflags & FLAG_a)) TT.algo = "des"; |
| 131 | if (get_salt(salt, TT.algo) == -1) |
| 132 | error_exit("Error: Unkown encryption algorithm\n"); |
| 133 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 134 | printf("Changing password for %s\n",name); |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 135 | if (myuid && pass[0] == '!') |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 136 | error_exit("Can't change, password is locked for %s",name); |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 137 | if (myuid) { |
| 138 | //Validate user |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 139 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 140 | if (read_password(toybuf, sizeof(toybuf), "Origial password:")) { |
| 141 | if (!toys.optargs[0]) free(name); |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 142 | return; |
| 143 | } |
| 144 | orig = toybuf; |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 145 | if (verify_passwd(pass)) error_exit("Authentication failed\n"); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 146 | } |
| 147 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 148 | orig = xstrdup(orig); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 149 | |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 150 | // Get new password |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 151 | newp = new_password(orig, name); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 152 | if (!newp) { |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 153 | free(orig); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 154 | if (!toys.optargs[0]) free(name); |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 155 | return; //new password is not set well. |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 156 | } |
| 157 | |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 158 | encrypted = crypt(newp, salt); |
| 159 | free(newp); |
| 160 | free(orig); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 161 | } else if (toys.optflags & FLAG_l) { |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 162 | if (pass[0] == '!') error_exit("password is already locked for %s",name); |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 163 | printf("Locking password for %s\n",name); |
Rob Landley | 59d85e2 | 2014-01-16 09:26:50 -0600 | [diff] [blame] | 164 | encrypted = xmprintf("!%s",pass); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 165 | } else if (toys.optflags & FLAG_u) { |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 166 | if (pass[0] != '!') error_exit("password is already unlocked for %s",name); |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 167 | |
| 168 | printf("Unlocking password for %s\n",name); |
| 169 | encrypted = xstrdup(&pass[1]); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 170 | } else if (toys.optflags & FLAG_d) { |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 171 | printf("Deleting password for %s\n",name); |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 172 | encrypted = xstrdup(""); //1 = "", 2 = '\0' |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 173 | } |
| 174 | |
Rob Landley | d0f7935 | 2013-10-16 19:30:17 -0500 | [diff] [blame] | 175 | // Update the passwd |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 176 | if (pw->pw_passwd[0] == 'x') |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 177 | ret = update_password("/etc/shadow", name, encrypted); |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 178 | else ret = update_password("/etc/passwd", name, encrypted); |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 179 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 180 | if ((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) free(encrypted); |
Rob Landley | 7aa651a | 2012-11-13 17:14:08 -0600 | [diff] [blame] | 181 | |
Rob Landley | d364e14 | 2013-08-18 14:01:46 -0500 | [diff] [blame] | 182 | if (!toys.optargs[0]) free(name); |
| 183 | if (!ret) error_msg("Success"); |
| 184 | else error_msg("Failure"); |
Rob Landley | 2c917f5 | 2012-07-17 08:54:47 -0500 | [diff] [blame] | 185 | } |