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