X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/1c15e88899094343f75aeba04122cd96a96b428e..af359dea2e5ab3e937b62107ecd6a51d78189ed7:/usr/src/usr.bin/passwd/passwd.c diff --git a/usr/src/usr.bin/passwd/passwd.c b/usr/src/usr.bin/passwd/passwd.c index 841307f6cb..e528b7a661 100644 --- a/usr/src/usr.bin/passwd/passwd.c +++ b/usr/src/usr.bin/passwd/passwd.c @@ -2,19 +2,33 @@ * Copyright (c) 1988 The Regents of the University of California. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted provided - * that: (1) source distributions retain this entire copyright notice and - * comment, and (2) distributions including binaries display the following - * acknowledgement: ``This product includes software developed by the - * University of California, Berkeley and its contributors'' in the - * documentation or other materials provided with the distribution and in - * all advertising materials mentioning features or use of this software. - * Neither the name of the University nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef lint @@ -24,62 +38,34 @@ char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)passwd.c 4.42 (Berkeley) 6/19/90"; +static char sccsid[] = "@(#)passwd.c 5.5 (Berkeley) 7/6/91"; #endif /* not lint */ -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include -#ifdef KERBEROS -#include -#include -#include -#include -#include -#include -#include "kpasswd_proto.h" +#ifdef KERBEROS int use_kerberos = 1; -#define ARGSTR "l" -#else -#define ARGSTR "" #endif -uid_t uid; - main(argc, argv) int argc; char **argv; { + extern int optind; register int ch; - extern int errno, optind; - extern char *optarg; - struct passwd *pw; - struct rlimit rlim; - FILE *temp_fp; - int fd; - char *fend, *np, *passwd, *temp, *tend, *uname; - char from[MAXPATHLEN], to[MAXPATHLEN]; - char *getnewpasswd(), *getlogin(); - - uid = getuid(); - uname = getlogin(); + char *uname; -#ifdef KERBEROS - while ((ch = getopt(argc, argv, ARGSTR)) != EOF) +#ifdef KERBEROS + while ((ch = getopt(argc, argv, "l")) != EOF) switch (ch) { - /* change local password file */ - case 'l': + case 'l': /* change local password file */ use_kerberos = 0; break; +#else + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { +#endif default: case '?': usage(); @@ -88,16 +74,19 @@ main(argc, argv) argc -= optind; argv += optind; -#endif + + uname = getlogin(); switch(argc) { case 0: break; case 1: #ifdef KERBEROS - if (use_kerberos && (strcmp(argv[1],uname) != 0)) { - fprintf(stderr, - "must kinit to change another's password\n"); + if (use_kerberos && strcmp(argv[1], uname)) { + (void)fprintf(stderr, "passwd: %s\n\t%s\n%s\n", +"to change another user's Kerberos password, do", +"\"kinit user; passwd; kdestroy\";", +"to change a user's local passwd, use \"passwd -l user\""); exit(1); } #endif @@ -109,490 +98,17 @@ main(argc, argv) } #ifdef KERBEROS - if (use_kerberos) { - exit(do_krb_passwd()); - /* NOTREACHED */ - } -#endif - - if (!(pw = getpwnam(uname))) { - fprintf(stderr, "passwd: unknown user %s.\n", uname); - exit(1); - } - if (uid && uid != pw->pw_uid) { - fprintf(stderr, "passwd: %s\n", strerror(EACCES)); - exit(1); - } - - (void)signal(SIGHUP, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGQUIT, SIG_IGN); - (void)signal(SIGTSTP, SIG_IGN); - - rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; - (void)setrlimit(RLIMIT_CPU, &rlim); - (void)setrlimit(RLIMIT_FSIZE, &rlim); - - (void)umask(0); - - temp = _PATH_PTMP; - if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { - if (errno == EEXIST) { - fprintf(stderr, - "passwd: password file busy -- try again later.\n"); - exit(0); - } - fprintf(stderr, "passwd: %s: %s", temp, strerror(errno)); - goto bad; - } - if (!(temp_fp = fdopen(fd, "w"))) { - fprintf(stderr, "passwd: can't write %s", temp); - goto bad; - } - passwd = _PATH_MASTERPASSWD; - if (!freopen(passwd, "r", stdin)) { - fprintf(stderr, "passwd: can't read %s", passwd); - goto bad; - } - - printf("Changing local password for %s.\n", pw->pw_name); - np = getnewpasswd(pw, temp); - - if (!copy(pw->pw_name, np, temp_fp, pw)) - goto bad; - - (void)fclose(temp_fp); - (void)fclose(stdin); - - switch(fork()) { - case 0: - break; - case -1: - fprintf(stderr, "passwd: can't fork"); - goto bad; - /* NOTREACHED */ - default: - exit(0); - /* NOTREACHED */ - } - - if (makedb(temp)) { - fprintf(stderr, "passwd: mkpasswd failed"); -bad: fprintf(stderr, "; password unchanged.\n"); - (void)unlink(temp); - exit(1); - } - - /* - * possible race; have to rename four files, and someone could slip - * in between them. LOCK_EX and rename the ``passwd.dir'' file first - * so that getpwent(3) can't slip in; the lock should never fail and - * it's unclear what to do if it does. Rename ``ptmp'' last so that - * passwd/vipw/chpass can't slip in. - */ - (void)setpriority(PRIO_PROCESS, 0, -20); - fend = strcpy(from, temp) + strlen(temp); - tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); - bcopy(".dir", fend, 5); - bcopy(".dir", tend, 5); - if ((fd = open(from, O_RDONLY, 0)) >= 0) - (void)flock(fd, LOCK_EX); - /* here we go... */ - (void)rename(from, to); - bcopy(".pag", fend, 5); - bcopy(".pag", tend, 5); - (void)rename(from, to); - bcopy(".orig", fend, 6); - (void)rename(from, _PATH_PASSWD); - (void)rename(temp, passwd); - /* done! */ - exit(0); -} - -copy(name, np, fp, pw) - char *name, *np; - FILE *fp; - struct passwd *pw; -{ - register int done; - register char *p; - char buf[1024]; - - for (done = 0; fgets(buf, sizeof(buf), stdin);) { - /* skip lines that are too big */ - if (!index(buf, '\n')) { - fprintf(stderr, "passwd: line too long.\n"); - return(0); - } - if (done) { - fprintf(fp, "%s", buf); - continue; - } - if (!(p = index(buf, ':'))) { - fprintf(stderr, "passwd: corrupted entry.\n"); - return(0); - } - *p = '\0'; - if (strcmp(buf, name)) { - *p = ':'; - fprintf(fp, "%s", buf); - continue; - } - if (!(p = index(++p, ':'))) { - fprintf(stderr, "passwd: corrupted entry.\n"); - return(0); - } - /* - * reset change time to zero; when classes are implemented, - * go and get the "offset" value for this class and reset - * the timer. - */ - fprintf(fp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", - pw->pw_name, np, pw->pw_uid, pw->pw_gid, - pw->pw_class, 0L, pw->pw_expire, pw->pw_gecos, - pw->pw_dir, pw->pw_shell); - done = 1; - } - return(1); -} - -char * -getnewpasswd(pw, temp) - register struct passwd *pw; - char *temp; -{ - register char *p, *t; - char buf[_PASSWORD_LEN+1], salt[2], *crypt(), *getpass(); - int tries = 0; - time_t time(); - - if (uid && pw->pw_passwd && - strcmp(crypt(getpass("Old password:"), pw->pw_passwd), - pw->pw_passwd)) { - (void)printf("passwd: %s.\n", strerror(EACCES)); - (void)unlink(temp); - exit(1); - } - - for (buf[0] = '\0';;) { - p = getpass("New password:"); - if (!*p) { - (void)printf("Password unchanged.\n"); - (void)unlink(temp); - exit(0); - } - if (strlen(p) <= 5 && (uid != 0 || tries++ < 2)) { - printf("Please enter a longer password.\n"); - continue; - } - for (t = p; *t && islower(*t); ++t); - if (!*t && (uid != 0 || tries++ < 2)) { - printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n"); - continue; - } - (void)strcpy(buf, p); - if (!strcmp(buf, getpass("Retype new password:"))) - break; - printf("Mismatch; try again, EOF to quit.\n"); - } - /* grab a random printable character that isn't a colon */ - (void)srandom((int)time((time_t *)NULL)); -#ifdef NEWSALT - salt[0] = '_'; - to64(&salt[1], (long)(29*25), 4); - to64(&salt[5], (long)random(), 4); -#else - to64(&salt[0], (long)random(), 2); + if (use_kerberos) + exit(krb_passwd()); #endif - return(crypt(buf, salt)); -} - -static unsigned char itoa64[] = /* 0..63 => ascii-64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -to64(s, v, n) - register char *s; - register long v; - register int n; -{ - while (--n >= 0) { - *s++ = itoa64[v&0x3f]; - v >>= 6; - } -} - -makedb(file) - char *file; -{ - union wait pstat; - pid_t pid, waitpid(); - - if (!(pid = vfork())) { - execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); - _exit(127); - } - return(waitpid(pid, &pstat, 0) == -1 ? -1 : pstat.w_status); + exit(local_passwd(uname)); } usage() { #ifdef KERBEROS - fprintf(stderr, "usage: passwd [-l] user\n"); + (void)fprintf(stderr, "usage: passwd [-l] user\n"); #else - fprintf(stderr, "usage: passwd user\n"); + (void)fprintf(stderr, "usage: passwd user\n"); #endif } - - -#ifdef KERBEROS -KTEXT_ST ticket; -long authopts = 0L; -Key_schedule random_schedule; -char realm[REALM_SZ], krbhst[MAX_HSTNM]; -static struct kpasswd_data proto_data; -static des_cblock okey; -static Key_schedule osched; -int sock; -int finish(); -#define PROTO "tcp" - -static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 }; - -do_krb_passwd() -{ - struct servent *se; - struct hostent *host; - struct sockaddr_in sin; - int rval; - char pass[_PASSWORD_LEN], password[_PASSWORD_LEN]; - fd_set readfds; - CREDENTIALS cred; - - static struct rlimit rl = { 0, 0 }; - - (void)signal(SIGHUP, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGTSTP, SIG_IGN); - - if (setrlimit(RLIMIT_CORE, &rl) < 0) { - perror("setrlimit"); - return(1); - } - - if ((se = getservbyname(SERVICE, PROTO)) == NULL) { - fprintf(stderr, "couldn't find entry for service %s/%s\n", - SERVICE, PROTO); - return(1); - } - - if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) { - fprintf(stderr, "couldn't get local Kerberos realm: %s\n", - krb_err_txt[rval]); - return(1); - } - - if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) { - fprintf(stderr, "couldn't get Kerberos host: %s\n", - krb_err_txt[rval]); - return(1); - } - - if ((host = gethostbyname(krbhst)) == NULL) { - fprintf(stderr, "couldn't get host entry for krb host %s\n", - krbhst); - return(1); - } - - sin.sin_family = host->h_addrtype; - bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length); - sin.sin_port = se->s_port; - - if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { - perror("socket"); - return(1); - } - - if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - perror("connect"); - close(sock); - return(1); - } - - rval = krb_sendauth( - authopts, /* NOT mutual */ - sock, - &ticket, /* (filled in) */ - SERVICE, - krbhst, /* instance (krbhst) */ - realm, /* dest realm */ - (u_long) getpid(), /* checksum */ - NULL, /* msg data */ - NULL, /* credentials */ - NULL, /* schedule */ - NULL, /* local addr */ - NULL, /* foreign addr */ - "KPWDV0.1" - ); - - - if (rval != KSUCCESS) { - fprintf(stderr, "Kerberos sendauth error: %s\n", - krb_err_txt[rval]); - return(1); - } - - krb_get_cred("krbtgt", realm, realm, &cred); - - printf("Changing Kerberos password for %s.%s@%s.\n", - cred.pname, cred.pinst, realm); - - if (des_read_pw_string(pass, - sizeof(pass)-1, "Old Kerberos password:", 0)) { - fprintf(stderr, - "error reading old Kerberos password\n"); - return(1); - } - - (void)des_string_to_key(pass, okey); - (void)des_key_sched(okey, osched); - (void)des_set_key(okey, osched); - - /* wait on the verification string */ - - FD_ZERO(&readfds); - FD_SET(sock, &readfds); - - rval = - select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout); - - if ((rval < 1) || !FD_ISSET(sock, &readfds)) { - if(rval == 0) { - fprintf(stderr, "timed out (aborted)\n"); - cleanup(); - return(1); - } - fprintf(stderr, "select failed (aborted)\n"); - cleanup(); - return(1); - } - - /* read verification string */ - - if (des_read(sock, &proto_data, sizeof(proto_data)) != - sizeof(proto_data)) { - fprintf(stderr, - "couldn't read verification string (aborted)\n"); - cleanup(); - return(1); - } - - (void)signal(SIGHUP, finish); - (void)signal(SIGINT, finish); - - if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) { - cleanup(); - /* don't complain loud if user just hit return */ - if (pass == NULL || (!*pass)) - return(0); - fprintf(stderr, "Sorry\n"); - return(1); - } - - (void)des_key_sched(proto_data.random_key, random_schedule); - (void)des_set_key(proto_data.random_key, random_schedule); - (void)bzero(pass, sizeof(pass)); - - if (des_read_pw_string(pass, - sizeof(pass)-1, "New Kerberos password:", 0)) { - fprintf(stderr, - "error reading new Kerberos password (aborted)\n"); - cleanup(); - return(1); - } - - if (des_read_pw_string(password, - sizeof(password)-1, "Retype new Kerberos password:", 0)) { - fprintf(stderr, - "error reading new Kerberos password (aborted)\n"); - cleanup(); - return(1); - } - - if (strcmp(password, pass) != 0) { - fprintf(stderr, "password mismatch (aborted)\n"); - cleanup(); - return(1); - } - - if (strlen(pass) == 0) - printf("using NULL password\n"); - - send_update(sock, password, SECURE_STRING); - - /* wait for ACK */ - - FD_ZERO(&readfds); - FD_SET(sock, &readfds); - - rval = - select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout); - if ((rval < 1) || !FD_ISSET(sock, &readfds)) { - if(rval == 0) { - fprintf(stderr, "timed out reading ACK (aborted)\n"); - cleanup(); - exit(1); - } - fprintf(stderr, "select failed (aborted)\n"); - cleanup(); - exit(1); - } - - recv_ack(sock); - cleanup(); - exit(0); -} - -send_update(dest, pwd, str) - int dest; - char *pwd, *str; -{ - static struct update_data ud; - strncpy(ud.secure_msg, str, _PASSWORD_LEN); - strncpy(ud.pw, pwd, sizeof(ud.pw)); - if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) { - fprintf(stderr, "couldn't write pw update (abort)\n"); - bzero(ud, sizeof(ud)); - cleanup(); - exit(1); - } -} - -recv_ack(remote) - int remote; -{ - int cc; - char buf[BUFSIZ]; - cc = des_read(remote, buf, sizeof(buf)); - if (cc <= 0) { - fprintf(stderr, "error reading acknowledgement (aborted)\n"); - cleanup(); - exit(1); - } - printf("%s", buf); -} - -cleanup() -{ - (void)bzero(&proto_data, sizeof(proto_data)); - (void)bzero(okey, sizeof(okey)); - (void)bzero(osched, sizeof(osched)); - (void)bzero(random_schedule, sizeof(random_schedule)); -} - -finish() -{ - (void)close(sock); - exit(1); -} - -#endif /* KERBEROS */