1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)passwd.c 4.42 (Berkeley) 06/19/90"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/file.h> 20 #include <sys/signal.h> 21 #include <sys/time.h> 22 #include <sys/resource.h> 23 #include <sys/wait.h> 24 #include <errno.h> 25 #include <pwd.h> 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <string.h> 29 30 #ifdef KERBEROS 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <netdb.h> 35 #include <kerberosIV/des.h> 36 #include <kerberosIV/krb.h> 37 #include "kpasswd_proto.h" 38 int use_kerberos = 1; 39 #define ARGSTR "l" 40 #else 41 #define ARGSTR "" 42 #endif 43 44 uid_t uid; 45 46 main(argc, argv) 47 int argc; 48 char **argv; 49 { 50 register int ch; 51 extern int errno, optind; 52 extern char *optarg; 53 struct passwd *pw; 54 struct rlimit rlim; 55 FILE *temp_fp; 56 int fd; 57 char *fend, *np, *passwd, *temp, *tend, *uname; 58 char from[MAXPATHLEN], to[MAXPATHLEN]; 59 char *getnewpasswd(), *getlogin(); 60 61 uid = getuid(); 62 uname = getlogin(); 63 64 #ifdef KERBEROS 65 while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 66 switch (ch) { 67 /* change local password file */ 68 case 'l': 69 use_kerberos = 0; 70 break; 71 default: 72 case '?': 73 usage(); 74 exit(1); 75 } 76 77 argc -= optind; 78 argv += optind; 79 #endif 80 81 switch(argc) { 82 case 0: 83 break; 84 case 1: 85 #ifdef KERBEROS 86 if (use_kerberos && (strcmp(argv[1],uname) != 0)) { 87 fprintf(stderr, 88 "must kinit to change another's password\n"); 89 exit(1); 90 } 91 #endif 92 uname = argv[0]; 93 break; 94 default: 95 usage(); 96 exit(1); 97 } 98 99 #ifdef KERBEROS 100 if (use_kerberos) { 101 exit(do_krb_passwd()); 102 /* NOTREACHED */ 103 } 104 #endif 105 106 if (!(pw = getpwnam(uname))) { 107 fprintf(stderr, "passwd: unknown user %s.\n", uname); 108 exit(1); 109 } 110 if (uid && uid != pw->pw_uid) { 111 fprintf(stderr, "passwd: %s\n", strerror(EACCES)); 112 exit(1); 113 } 114 115 (void)signal(SIGHUP, SIG_IGN); 116 (void)signal(SIGINT, SIG_IGN); 117 (void)signal(SIGQUIT, SIG_IGN); 118 (void)signal(SIGTSTP, SIG_IGN); 119 120 rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 121 (void)setrlimit(RLIMIT_CPU, &rlim); 122 (void)setrlimit(RLIMIT_FSIZE, &rlim); 123 124 (void)umask(0); 125 126 temp = _PATH_PTMP; 127 if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { 128 if (errno == EEXIST) { 129 fprintf(stderr, 130 "passwd: password file busy -- try again later.\n"); 131 exit(0); 132 } 133 fprintf(stderr, "passwd: %s: %s", temp, strerror(errno)); 134 goto bad; 135 } 136 if (!(temp_fp = fdopen(fd, "w"))) { 137 fprintf(stderr, "passwd: can't write %s", temp); 138 goto bad; 139 } 140 passwd = _PATH_MASTERPASSWD; 141 if (!freopen(passwd, "r", stdin)) { 142 fprintf(stderr, "passwd: can't read %s", passwd); 143 goto bad; 144 } 145 146 printf("Changing local password for %s.\n", pw->pw_name); 147 np = getnewpasswd(pw, temp); 148 149 if (!copy(pw->pw_name, np, temp_fp, pw)) 150 goto bad; 151 152 (void)fclose(temp_fp); 153 (void)fclose(stdin); 154 155 switch(fork()) { 156 case 0: 157 break; 158 case -1: 159 fprintf(stderr, "passwd: can't fork"); 160 goto bad; 161 /* NOTREACHED */ 162 default: 163 exit(0); 164 /* NOTREACHED */ 165 } 166 167 if (makedb(temp)) { 168 fprintf(stderr, "passwd: mkpasswd failed"); 169 bad: fprintf(stderr, "; password unchanged.\n"); 170 (void)unlink(temp); 171 exit(1); 172 } 173 174 /* 175 * possible race; have to rename four files, and someone could slip 176 * in between them. LOCK_EX and rename the ``passwd.dir'' file first 177 * so that getpwent(3) can't slip in; the lock should never fail and 178 * it's unclear what to do if it does. Rename ``ptmp'' last so that 179 * passwd/vipw/chpass can't slip in. 180 */ 181 (void)setpriority(PRIO_PROCESS, 0, -20); 182 fend = strcpy(from, temp) + strlen(temp); 183 tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); 184 bcopy(".dir", fend, 5); 185 bcopy(".dir", tend, 5); 186 if ((fd = open(from, O_RDONLY, 0)) >= 0) 187 (void)flock(fd, LOCK_EX); 188 /* here we go... */ 189 (void)rename(from, to); 190 bcopy(".pag", fend, 5); 191 bcopy(".pag", tend, 5); 192 (void)rename(from, to); 193 bcopy(".orig", fend, 6); 194 (void)rename(from, _PATH_PASSWD); 195 (void)rename(temp, passwd); 196 /* done! */ 197 exit(0); 198 } 199 200 copy(name, np, fp, pw) 201 char *name, *np; 202 FILE *fp; 203 struct passwd *pw; 204 { 205 register int done; 206 register char *p; 207 char buf[1024]; 208 209 for (done = 0; fgets(buf, sizeof(buf), stdin);) { 210 /* skip lines that are too big */ 211 if (!index(buf, '\n')) { 212 fprintf(stderr, "passwd: line too long.\n"); 213 return(0); 214 } 215 if (done) { 216 fprintf(fp, "%s", buf); 217 continue; 218 } 219 if (!(p = index(buf, ':'))) { 220 fprintf(stderr, "passwd: corrupted entry.\n"); 221 return(0); 222 } 223 *p = '\0'; 224 if (strcmp(buf, name)) { 225 *p = ':'; 226 fprintf(fp, "%s", buf); 227 continue; 228 } 229 if (!(p = index(++p, ':'))) { 230 fprintf(stderr, "passwd: corrupted entry.\n"); 231 return(0); 232 } 233 /* 234 * reset change time to zero; when classes are implemented, 235 * go and get the "offset" value for this class and reset 236 * the timer. 237 */ 238 fprintf(fp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", 239 pw->pw_name, np, pw->pw_uid, pw->pw_gid, 240 pw->pw_class, 0L, pw->pw_expire, pw->pw_gecos, 241 pw->pw_dir, pw->pw_shell); 242 done = 1; 243 } 244 return(1); 245 } 246 247 char * 248 getnewpasswd(pw, temp) 249 register struct passwd *pw; 250 char *temp; 251 { 252 register char *p, *t; 253 char buf[_PASSWORD_LEN+1], salt[2], *crypt(), *getpass(); 254 int tries = 0; 255 time_t time(); 256 257 if (uid && pw->pw_passwd && 258 strcmp(crypt(getpass("Old password:"), pw->pw_passwd), 259 pw->pw_passwd)) { 260 (void)printf("passwd: %s.\n", strerror(EACCES)); 261 (void)unlink(temp); 262 exit(1); 263 } 264 265 for (buf[0] = '\0';;) { 266 p = getpass("New password:"); 267 if (!*p) { 268 (void)printf("Password unchanged.\n"); 269 (void)unlink(temp); 270 exit(0); 271 } 272 if (strlen(p) <= 5 && (uid != 0 || tries++ < 2)) { 273 printf("Please enter a longer password.\n"); 274 continue; 275 } 276 for (t = p; *t && islower(*t); ++t); 277 if (!*t && (uid != 0 || tries++ < 2)) { 278 printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n"); 279 continue; 280 } 281 (void)strcpy(buf, p); 282 if (!strcmp(buf, getpass("Retype new password:"))) 283 break; 284 printf("Mismatch; try again, EOF to quit.\n"); 285 } 286 /* grab a random printable character that isn't a colon */ 287 (void)srandom((int)time((time_t *)NULL)); 288 #ifdef NEWSALT 289 salt[0] = '_'; 290 to64(&salt[1], (long)(29*25), 4); 291 to64(&salt[5], (long)random(), 4); 292 #else 293 to64(&salt[0], (long)random(), 2); 294 #endif 295 return(crypt(buf, salt)); 296 } 297 298 static unsigned char itoa64[] = /* 0..63 => ascii-64 */ 299 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 300 301 to64(s, v, n) 302 register char *s; 303 register long v; 304 register int n; 305 { 306 while (--n >= 0) { 307 *s++ = itoa64[v&0x3f]; 308 v >>= 6; 309 } 310 } 311 312 makedb(file) 313 char *file; 314 { 315 union wait pstat; 316 pid_t pid, waitpid(); 317 318 if (!(pid = vfork())) { 319 execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); 320 _exit(127); 321 } 322 return(waitpid(pid, &pstat, 0) == -1 ? -1 : pstat.w_status); 323 } 324 325 usage() 326 { 327 #ifdef KERBEROS 328 fprintf(stderr, "usage: passwd [-l] user\n"); 329 #else 330 fprintf(stderr, "usage: passwd user\n"); 331 #endif 332 } 333 334 335 #ifdef KERBEROS 336 KTEXT_ST ticket; 337 long authopts = 0L; 338 Key_schedule random_schedule; 339 char realm[REALM_SZ], krbhst[MAX_HSTNM]; 340 static struct kpasswd_data proto_data; 341 static des_cblock okey; 342 static Key_schedule osched; 343 int sock; 344 int finish(); 345 #define PROTO "tcp" 346 347 static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 }; 348 349 do_krb_passwd() 350 { 351 struct servent *se; 352 struct hostent *host; 353 struct sockaddr_in sin; 354 int rval; 355 char pass[_PASSWORD_LEN], password[_PASSWORD_LEN]; 356 fd_set readfds; 357 CREDENTIALS cred; 358 359 static struct rlimit rl = { 0, 0 }; 360 361 (void)signal(SIGHUP, SIG_IGN); 362 (void)signal(SIGINT, SIG_IGN); 363 (void)signal(SIGTSTP, SIG_IGN); 364 365 if (setrlimit(RLIMIT_CORE, &rl) < 0) { 366 perror("setrlimit"); 367 return(1); 368 } 369 370 if ((se = getservbyname(SERVICE, PROTO)) == NULL) { 371 fprintf(stderr, "couldn't find entry for service %s/%s\n", 372 SERVICE, PROTO); 373 return(1); 374 } 375 376 if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) { 377 fprintf(stderr, "couldn't get local Kerberos realm: %s\n", 378 krb_err_txt[rval]); 379 return(1); 380 } 381 382 if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) { 383 fprintf(stderr, "couldn't get Kerberos host: %s\n", 384 krb_err_txt[rval]); 385 return(1); 386 } 387 388 if ((host = gethostbyname(krbhst)) == NULL) { 389 fprintf(stderr, "couldn't get host entry for krb host %s\n", 390 krbhst); 391 return(1); 392 } 393 394 sin.sin_family = host->h_addrtype; 395 bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length); 396 sin.sin_port = se->s_port; 397 398 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 399 perror("socket"); 400 return(1); 401 } 402 403 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { 404 perror("connect"); 405 close(sock); 406 return(1); 407 } 408 409 rval = krb_sendauth( 410 authopts, /* NOT mutual */ 411 sock, 412 &ticket, /* (filled in) */ 413 SERVICE, 414 krbhst, /* instance (krbhst) */ 415 realm, /* dest realm */ 416 (u_long) getpid(), /* checksum */ 417 NULL, /* msg data */ 418 NULL, /* credentials */ 419 NULL, /* schedule */ 420 NULL, /* local addr */ 421 NULL, /* foreign addr */ 422 "KPWDV0.1" 423 ); 424 425 426 if (rval != KSUCCESS) { 427 fprintf(stderr, "Kerberos sendauth error: %s\n", 428 krb_err_txt[rval]); 429 return(1); 430 } 431 432 krb_get_cred("krbtgt", realm, realm, &cred); 433 434 printf("Changing Kerberos password for %s.%s@%s.\n", 435 cred.pname, cred.pinst, realm); 436 437 if (des_read_pw_string(pass, 438 sizeof(pass)-1, "Old Kerberos password:", 0)) { 439 fprintf(stderr, 440 "error reading old Kerberos password\n"); 441 return(1); 442 } 443 444 (void)des_string_to_key(pass, okey); 445 (void)des_key_sched(okey, osched); 446 (void)des_set_key(okey, osched); 447 448 /* wait on the verification string */ 449 450 FD_ZERO(&readfds); 451 FD_SET(sock, &readfds); 452 453 rval = 454 select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout); 455 456 if ((rval < 1) || !FD_ISSET(sock, &readfds)) { 457 if(rval == 0) { 458 fprintf(stderr, "timed out (aborted)\n"); 459 cleanup(); 460 return(1); 461 } 462 fprintf(stderr, "select failed (aborted)\n"); 463 cleanup(); 464 return(1); 465 } 466 467 /* read verification string */ 468 469 if (des_read(sock, &proto_data, sizeof(proto_data)) != 470 sizeof(proto_data)) { 471 fprintf(stderr, 472 "couldn't read verification string (aborted)\n"); 473 cleanup(); 474 return(1); 475 } 476 477 (void)signal(SIGHUP, finish); 478 (void)signal(SIGINT, finish); 479 480 if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) { 481 cleanup(); 482 /* don't complain loud if user just hit return */ 483 if (pass == NULL || (!*pass)) 484 return(0); 485 fprintf(stderr, "Sorry\n"); 486 return(1); 487 } 488 489 (void)des_key_sched(proto_data.random_key, random_schedule); 490 (void)des_set_key(proto_data.random_key, random_schedule); 491 (void)bzero(pass, sizeof(pass)); 492 493 if (des_read_pw_string(pass, 494 sizeof(pass)-1, "New Kerberos password:", 0)) { 495 fprintf(stderr, 496 "error reading new Kerberos password (aborted)\n"); 497 cleanup(); 498 return(1); 499 } 500 501 if (des_read_pw_string(password, 502 sizeof(password)-1, "Retype new Kerberos password:", 0)) { 503 fprintf(stderr, 504 "error reading new Kerberos password (aborted)\n"); 505 cleanup(); 506 return(1); 507 } 508 509 if (strcmp(password, pass) != 0) { 510 fprintf(stderr, "password mismatch (aborted)\n"); 511 cleanup(); 512 return(1); 513 } 514 515 if (strlen(pass) == 0) 516 printf("using NULL password\n"); 517 518 send_update(sock, password, SECURE_STRING); 519 520 /* wait for ACK */ 521 522 FD_ZERO(&readfds); 523 FD_SET(sock, &readfds); 524 525 rval = 526 select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout); 527 if ((rval < 1) || !FD_ISSET(sock, &readfds)) { 528 if(rval == 0) { 529 fprintf(stderr, "timed out reading ACK (aborted)\n"); 530 cleanup(); 531 exit(1); 532 } 533 fprintf(stderr, "select failed (aborted)\n"); 534 cleanup(); 535 exit(1); 536 } 537 538 recv_ack(sock); 539 cleanup(); 540 exit(0); 541 } 542 543 send_update(dest, pwd, str) 544 int dest; 545 char *pwd, *str; 546 { 547 static struct update_data ud; 548 strncpy(ud.secure_msg, str, _PASSWORD_LEN); 549 strncpy(ud.pw, pwd, sizeof(ud.pw)); 550 if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) { 551 fprintf(stderr, "couldn't write pw update (abort)\n"); 552 bzero(ud, sizeof(ud)); 553 cleanup(); 554 exit(1); 555 } 556 } 557 558 recv_ack(remote) 559 int remote; 560 { 561 int cc; 562 char buf[BUFSIZ]; 563 cc = des_read(remote, buf, sizeof(buf)); 564 if (cc <= 0) { 565 fprintf(stderr, "error reading acknowledgement (aborted)\n"); 566 cleanup(); 567 exit(1); 568 } 569 printf("%s", buf); 570 } 571 572 cleanup() 573 { 574 (void)bzero(&proto_data, sizeof(proto_data)); 575 (void)bzero(okey, sizeof(okey)); 576 (void)bzero(osched, sizeof(osched)); 577 (void)bzero(random_schedule, sizeof(random_schedule)); 578 } 579 580 finish() 581 { 582 (void)close(sock); 583 exit(1); 584 } 585 586 #endif /* KERBEROS */ 587