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