|
|
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.