Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/loginutils/passwd.c
- Timestamp:
- Nov 4, 2007, 3:16:40 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.5/mindi-busybox/loginutils/passwd.c
r821 r1765 1 1 /* vi: set sw=4 ts=4: */ 2 #include <fcntl.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <signal.h> 6 #include <sys/stat.h> 7 #include <sys/types.h> 8 #include <unistd.h> 9 #include <utime.h> 2 /* 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 4 */ 5 6 #include "libbb.h" 10 7 #include <syslog.h> 11 #include <time.h> 12 #include <sys/resource.h> 13 #include <errno.h> 14 15 #include "busybox.h" 16 17 static char crypt_passwd[128]; 18 19 static int create_backup(const char *backup, FILE * fp); 20 static int new_password(const struct passwd *pw, int amroot, int algo); 21 static void set_filesize_limit(int blocks); 22 23 24 static int get_algo(char *a) 8 9 10 static void nuke_str(char *str) 25 11 { 26 int x = 1; /* standard: MD5 */ 27 28 if (strcasecmp(a, "des") == 0) 29 x = 0; 30 return x; 12 if (str) memset(str, 0, strlen(str)); 31 13 } 32 14 33 34 static int update_passwd(const struct passwd *pw, const char *crypt_pw) 15 static char* new_password(const struct passwd *pw, uid_t myuid, int algo) 35 16 { 36 char filename[1024]; 37 char buf[1025]; 38 char buffer[80]; 39 char username[32]; 40 char *pw_rest; 41 int mask; 42 int continued; 43 FILE *fp; 44 FILE *out_fp; 45 struct stat sb; 46 struct flock lock; 47 48 #if ENABLE_FEATURE_SHADOWPASSWDS 49 if (access(bb_path_shadow_file, F_OK) == 0) { 50 snprintf(filename, sizeof filename, "%s", bb_path_shadow_file); 51 } else 52 #endif 53 { 54 snprintf(filename, sizeof filename, "%s", bb_path_passwd_file); 55 } 56 57 if (((fp = fopen(filename, "r+")) == 0) || (fstat(fileno(fp), &sb))) { 58 /* return 0; */ 59 return 1; 60 } 61 62 /* Lock the password file before updating */ 63 lock.l_type = F_WRLCK; 64 lock.l_whence = SEEK_SET; 65 lock.l_start = 0; 66 lock.l_len = 0; 67 if (fcntl(fileno(fp), F_SETLK, &lock) < 0) { 68 fprintf(stderr, "%s: %s\n", filename, strerror(errno)); 69 return 1; 70 } 71 lock.l_type = F_UNLCK; 72 73 snprintf(buf, sizeof buf, "%s-", filename); 74 if (create_backup(buf, fp)) { 75 fcntl(fileno(fp), F_SETLK, &lock); 76 fclose(fp); 77 return 1; 78 } 79 snprintf(buf, sizeof buf, "%s+", filename); 80 mask = umask(0777); 81 out_fp = fopen(buf, "w"); 82 umask(mask); 83 if ((!out_fp) || (fchmod(fileno(out_fp), sb.st_mode & 0777)) 84 || (fchown(fileno(out_fp), sb.st_uid, sb.st_gid))) { 85 fcntl(fileno(fp), F_SETLK, &lock); 86 fclose(fp); 87 fclose(out_fp); 88 return 1; 89 } 90 91 continued = 0; 92 snprintf(username, sizeof username, "%s:", pw->pw_name); 93 rewind(fp); 94 while (!feof(fp)) { 95 fgets(buffer, sizeof buffer, fp); 96 if (!continued) { /* Check to see if we're updating this line. */ 97 if (strncmp(username, buffer, strlen(username)) == 0) { 98 /* we have a match. */ 99 pw_rest = strchr(buffer, ':'); 100 *pw_rest++ = '\0'; 101 pw_rest = strchr(pw_rest, ':'); 102 fprintf(out_fp, "%s:%s%s", buffer, crypt_pw, pw_rest); 103 } else { 104 fputs(buffer, out_fp); 105 } 106 } else { 107 fputs(buffer, out_fp); 17 char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */ 18 char *orig = (char*)""; 19 char *newp = NULL; 20 char *cipher = NULL; 21 char *cp = NULL; 22 char *ret = NULL; /* failure so far */ 23 24 if (myuid && pw->pw_passwd[0]) { 25 orig = bb_askpass(0, "Old password:"); /* returns ptr to static */ 26 if (!orig) 27 goto err_ret; 28 cipher = pw_encrypt(orig, pw->pw_passwd); /* returns ptr to static */ 29 if (strcmp(cipher, pw->pw_passwd) != 0) { 30 syslog(LOG_WARNING, "incorrect password for '%s'", 31 pw->pw_name); 32 bb_do_delay(FAIL_DELAY); 33 puts("Incorrect password"); 34 goto err_ret; 108 35 } 109 if (buffer[strlen(buffer) - 1] == '\n') { 110 continued = 0; 111 } else { 112 continued = 1; 113 } 114 memset(buffer, 0, sizeof buffer); 115 } 116 117 if (fflush(out_fp) || fsync(fileno(out_fp)) || fclose(out_fp)) { 118 unlink(buf); 119 fcntl(fileno(fp), F_SETLK, &lock); 120 fclose(fp); 121 return 1; 122 } 123 if (rename(buf, filename) < 0) { 124 fcntl(fileno(fp), F_SETLK, &lock); 125 fclose(fp); 126 return 1; 127 } else { 128 fcntl(fileno(fp), F_SETLK, &lock); 129 fclose(fp); 130 return 0; 131 } 36 } 37 orig = xstrdup(orig); /* or else bb_askpass() will destroy it */ 38 newp = bb_askpass(0, "New password:"); /* returns ptr to static */ 39 if (!newp) 40 goto err_ret; 41 newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */ 42 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK 43 && obscure(orig, newp, pw) && myuid) 44 goto err_ret; /* non-root is not allowed to have weak passwd */ 45 46 cp = bb_askpass(0, "Retype password:"); 47 if (!cp) 48 goto err_ret; 49 if (strcmp(cp, newp)) { 50 puts("Passwords don't match"); 51 goto err_ret; 52 } 53 54 crypt_make_salt(salt, 1, 0); /* des */ 55 if (algo) { /* MD5 */ 56 strcpy(salt, "$1$"); 57 crypt_make_salt(salt + 3, 4, 0); 58 } 59 /* pw_encrypt returns ptr to static */ 60 ret = xstrdup(pw_encrypt(newp, salt)); 61 /* whee, success! */ 62 63 err_ret: 64 nuke_str(orig); 65 if (ENABLE_FEATURE_CLEAN_UP) free(orig); 66 nuke_str(newp); 67 if (ENABLE_FEATURE_CLEAN_UP) free(newp); 68 nuke_str(cipher); 69 nuke_str(cp); 70 return ret; 132 71 } 133 72 134 73 int passwd_main(int argc, char **argv); 135 74 int passwd_main(int argc, char **argv) 136 75 { 137 int amroot; 138 char *cp; 139 char *np; 76 enum { 77 OPT_algo = 0x1, /* -a - password algorithm */ 78 OPT_lock = 0x2, /* -l - lock account */ 79 OPT_unlock = 0x4, /* -u - unlock account */ 80 OPT_delete = 0x8, /* -d - delete password */ 81 OPT_lud = 0xe, 82 STATE_ALGO_md5 = 0x10, 83 //STATE_ALGO_des = 0x20, not needed yet 84 }; 85 unsigned opt; 86 int rc; 87 const char *opt_a = ""; 88 const char *filename; 89 char *myname; 140 90 char *name; 141 char *myname; 142 int flag; 143 int algo = 1; /* -a - password algorithm */ 144 int lflg = 0; /* -l - lock account */ 145 int uflg = 0; /* -u - unlock account */ 146 int dflg = 0; /* -d - delete password */ 147 const struct passwd *pw; 91 char *newp; 92 struct passwd *pw; 93 uid_t myuid; 94 struct rlimit rlimit_fsize; 95 char c; 148 96 149 97 #if ENABLE_FEATURE_SHADOWPASSWDS 150 const struct spwd *sp; 98 /* Using _r function to avoid pulling in static buffers */ 99 struct spwd spw; 100 struct spwd *result; 101 char buffer[256]; 151 102 #endif 152 amroot = (getuid() == 0); 153 openlog("passwd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); 154 while ((flag = getopt(argc, argv, "a:dlu")) != EOF) { 155 switch (flag) { 156 case 'a': 157 algo = get_algo(optarg); 158 break; 159 case 'd': 160 dflg++; 161 break; 162 case 'l': 163 lflg++; 164 break; 165 case 'u': 166 uflg++; 167 break; 168 default: 169 bb_show_usage(); 170 } 171 } 172 myname = (char *) bb_xstrdup(bb_getpwuid(NULL, getuid(), -1)); 173 /* exits on error */ 174 if (optind < argc) { 175 name = argv[optind]; 103 104 logmode = LOGMODE_BOTH; 105 openlog(applet_name, LOG_NOWAIT, LOG_AUTH); 106 opt = getopt32(argv, "a:lud", &opt_a); 107 //argc -= optind; 108 argv += optind; 109 110 if (strcasecmp(opt_a, "des") != 0) /* -a */ 111 opt |= STATE_ALGO_md5; 112 //else 113 // opt |= STATE_ALGO_des; 114 myuid = getuid(); 115 /* -l, -u, -d require root priv and username argument */ 116 if ((opt & OPT_lud) && (myuid || !argv[0])) 117 bb_show_usage(); 118 119 /* Will complain and die if username not found */ 120 myname = xstrdup(bb_getpwuid(NULL, -1, myuid)); 121 name = argv[0] ? argv[0] : myname; 122 123 pw = getpwnam(name); 124 if (!pw) bb_error_msg_and_die("unknown user %s", name); 125 if (myuid && pw->pw_uid != myuid) { 126 /* LOGMODE_BOTH */ 127 bb_error_msg_and_die("%s can't change password for %s", myname, name); 128 } 129 130 #if ENABLE_FEATURE_SHADOWPASSWDS 131 /* getspnam_r() can lie! Even if user isn't in shadow, it can 132 * return success (pwd field was seen set to "!" in this case) */ 133 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) 134 || LONE_CHAR(spw.sp_pwdp, '!')) { 135 /* LOGMODE_BOTH */ 136 bb_error_msg("no record of %s in %s, using %s", 137 name, bb_path_shadow_file, 138 bb_path_passwd_file); 176 139 } else { 177 name = myname; 178 } 179 if ((lflg || uflg || dflg) && (optind >= argc || !amroot)) { 180 bb_show_usage(); 181 } 182 pw = getpwnam(name); 183 if (!pw) { 184 bb_error_msg_and_die("Unknown user %s\n", name); 185 } 186 if (!amroot && pw->pw_uid != getuid()) { 187 syslog(LOG_WARNING, "can't change pwd for `%s'", name); 188 bb_error_msg_and_die("Permission denied.\n"); 189 } 190 #if ENABLE_FEATURE_SHADOWPASSWDS 191 sp = getspnam(name); 192 if (!sp) { 193 sp = (struct spwd *) pwd_to_spwd(pw); 194 } 195 cp = sp->sp_pwdp; 196 np = sp->sp_namp; 197 #else 198 cp = pw->pw_passwd; 199 np = name; 140 pw->pw_passwd = spw.sp_pwdp; 141 } 200 142 #endif 201 143 202 safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd)); 203 if (!(dflg || lflg || uflg)) { 204 if (!amroot) { 205 if (cp[0] == '!') { 206 syslog(LOG_WARNING, "password locked for `%s'", np); 207 bb_error_msg_and_die( "The password for `%s' cannot be changed.\n", np); 208 } 144 /* Decide what the new password will be */ 145 newp = NULL; 146 c = pw->pw_passwd[0] - '!'; 147 if (!(opt & OPT_lud)) { 148 if (myuid && !c) { /* passwd starts with '!' */ 149 /* LOGMODE_BOTH */ 150 bb_error_msg_and_die("cannot change " 151 "locked password for %s", name); 209 152 } 210 153 printf("Changing password for %s\n", name); 211 if (new_password(pw, amroot, algo)) { 212 bb_error_msg_and_die( "The password for %s is unchanged.\n", name); 154 newp = new_password(pw, myuid, opt & STATE_ALGO_md5); 155 if (!newp) { 156 logmode = LOGMODE_STDIO; 157 bb_error_msg_and_die("password for %s is unchanged", name); 213 158 } 214 } else if (lflg) { 215 if (crypt_passwd[0] != '!') { 216 memmove(&crypt_passwd[1], crypt_passwd, 217 sizeof crypt_passwd - 1); 218 crypt_passwd[sizeof crypt_passwd - 1] = '\0'; 219 crypt_passwd[0] = '!'; 220 } 221 } else if (uflg) { 222 if (crypt_passwd[0] == '!') { 223 memmove(crypt_passwd, &crypt_passwd[1], 224 sizeof crypt_passwd - 1); 225 } 226 } else if (dflg) { 227 crypt_passwd[0] = '\0'; 228 } 229 set_filesize_limit(30000); 159 } else if (opt & OPT_lock) { 160 if (!c) goto skip; /* passwd starts with '!' */ 161 newp = xasprintf("!%s", pw->pw_passwd); 162 } else if (opt & OPT_unlock) { 163 if (c) goto skip; /* not '!' */ 164 /* pw->pw_passwd pints to static storage, 165 * strdup'ing to avoid nasty surprizes */ 166 newp = xstrdup(&pw->pw_passwd[1]); 167 } else if (opt & OPT_delete) { 168 //newp = xstrdup(""); 169 newp = (char*)""; 170 } 171 172 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000; 173 setrlimit(RLIMIT_FSIZE, &rlimit_fsize); 230 174 signal(SIGHUP, SIG_IGN); 231 175 signal(SIGINT, SIG_IGN); … … 233 177 umask(077); 234 178 xsetuid(0); 235 if (!update_passwd(pw, crypt_passwd)) { 236 syslog(LOG_INFO, "password for `%s' changed by user `%s'", name, 237 myname); 238 printf("Password changed.\n"); 239 } else { 240 syslog(LOG_WARNING, "an error occurred updating the password file"); 241 bb_error_msg_and_die("An error occurred updating the password file.\n"); 242 } 243 return (0); 244 } 245 246 247 248 static int create_backup(const char *backup, FILE * fp) 249 { 250 struct stat sb; 251 struct utimbuf ub; 252 FILE *bkfp; 253 int c, mask; 254 255 if (fstat(fileno(fp), &sb)) 256 /* return -1; */ 257 return 1; 258 259 mask = umask(077); 260 bkfp = fopen(backup, "w"); 261 umask(mask); 262 if (!bkfp) 263 /* return -1; */ 264 return 1; 265 266 /* TODO: faster copy, not one-char-at-a-time. --marekm */ 267 rewind(fp); 268 while ((c = getc(fp)) != EOF) { 269 if (putc(c, bkfp) == EOF) 270 break; 271 } 272 if (c != EOF || fflush(bkfp)) { 273 fclose(bkfp); 274 /* return -1; */ 275 return 1; 276 } 277 if (fclose(bkfp)) 278 /* return -1; */ 279 return 1; 280 281 ub.actime = sb.st_atime; 282 ub.modtime = sb.st_mtime; 283 utime(backup, &ub); 179 180 #if ENABLE_FEATURE_SHADOWPASSWDS 181 filename = bb_path_shadow_file; 182 rc = update_passwd(bb_path_shadow_file, name, newp); 183 if (rc == 0) /* no lines updated, no errors detected */ 184 #endif 185 { 186 filename = bb_path_passwd_file; 187 rc = update_passwd(bb_path_passwd_file, name, newp); 188 } 189 /* LOGMODE_BOTH */ 190 if (rc < 0) 191 bb_error_msg_and_die("cannot update password file %s", 192 filename); 193 bb_info_msg("Password for %s changed by %s", name, myname); 194 195 //if (ENABLE_FEATURE_CLEAN_UP) free(newp); 196 skip: 197 if (!newp) { 198 bb_error_msg_and_die("password for %s is already %slocked", 199 name, (opt & OPT_unlock) ? "un" : ""); 200 } 201 if (ENABLE_FEATURE_CLEAN_UP) free(myname); 284 202 return 0; 285 203 } 286 287 static int i64c(int i)288 {289 if (i <= 0)290 return ('.');291 if (i == 1)292 return ('/');293 if (i >= 2 && i < 12)294 return ('0' - 2 + i);295 if (i >= 12 && i < 38)296 return ('A' - 12 + i);297 if (i >= 38 && i < 63)298 return ('a' - 38 + i);299 return ('z');300 }301 302 static char *crypt_make_salt(void)303 {304 time_t now;305 static unsigned long x;306 static char result[3];307 308 time(&now);309 x += now + getpid() + clock();310 result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);311 result[1] = i64c(((x >> 12) ^ x) & 077);312 result[2] = '\0';313 return result;314 }315 316 317 static int new_password(const struct passwd *pw, int amroot, int algo)318 {319 char *clear;320 char *cipher;321 char *cp;322 char salt[12]; /* "$N$XXXXXXXX" or "XX" */323 char orig[200];324 char pass[200];325 326 if (!amroot && crypt_passwd[0]) {327 if (!(clear = bb_askpass(0, "Old password:"))) {328 /* return -1; */329 return 1;330 }331 cipher = pw_encrypt(clear, crypt_passwd);332 if (strcmp(cipher, crypt_passwd) != 0) {333 syslog(LOG_WARNING, "incorrect password for `%s'",334 pw->pw_name);335 bb_do_delay(FAIL_DELAY);336 fprintf(stderr, "Incorrect password.\n");337 /* return -1; */338 return 1;339 }340 safe_strncpy(orig, clear, sizeof(orig));341 memset(clear, 0, strlen(clear));342 memset(cipher, 0, strlen(cipher));343 } else {344 orig[0] = '\0';345 }346 if (! (cp=bb_askpass(0, "Enter the new password (minimum of 5, maximum of 8 characters)\n"347 "Please use a combination of upper and lower case letters and numbers.\n"348 "Enter new password: ")))349 {350 memset(orig, 0, sizeof orig);351 /* return -1; */352 return 1;353 }354 safe_strncpy(pass, cp, sizeof(pass));355 memset(cp, 0, strlen(cp));356 /* if (!obscure(orig, pass, pw)) { */357 if (obscure(orig, pass, pw)) {358 if (amroot) {359 printf("\nWarning: weak password (continuing).\n");360 } else {361 /* return -1; */362 return 1;363 }364 }365 if (!(cp = bb_askpass(0, "Re-enter new password: "))) {366 memset(orig, 0, sizeof orig);367 /* return -1; */368 return 1;369 }370 if (strcmp(cp, pass)) {371 fprintf(stderr, "Passwords do not match.\n");372 /* return -1; */373 return 1;374 }375 memset(cp, 0, strlen(cp));376 memset(orig, 0, sizeof(orig));377 memset(salt, 0, sizeof(salt));378 379 if (algo == 1) {380 strcpy(salt, "$1$");381 strcat(salt, crypt_make_salt());382 strcat(salt, crypt_make_salt());383 strcat(salt, crypt_make_salt());384 }385 386 strcat(salt, crypt_make_salt());387 cp = pw_encrypt(pass, salt);388 389 memset(pass, 0, sizeof pass);390 safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));391 return 0;392 }393 394 static void set_filesize_limit(int blocks)395 {396 struct rlimit rlimit_fsize;397 398 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;399 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);400 }
Note:
See TracChangeset
for help on using the changeset viewer.