BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / passwd / passwd.c
index 841307f..e528b7a 100644 (file)
@@ -2,19 +2,33 @@
  * Copyright (c) 1988 The Regents of the University of California.
  * All rights reserved.
  *
  * 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
  */
 
 #ifndef lint
@@ -24,62 +38,34 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #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 */
 
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/file.h>
-#include <sys/signal.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <pwd.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <ctype.h>
-#include <string.h>
+#include <unistd.h>
 
 
-#ifdef KERBEROS
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <kerberosIV/des.h>
-#include <kerberosIV/krb.h>
-#include "kpasswd_proto.h"
+#ifdef KERBEROS
 int use_kerberos = 1;
 int use_kerberos = 1;
-#define ARGSTR "l"
-#else
-#define ARGSTR ""
 #endif
 
 #endif
 
-uid_t uid;
-
 main(argc, argv)
        int argc;
        char **argv;
 {
 main(argc, argv)
        int argc;
        char **argv;
 {
+       extern int optind;
        register int ch;
        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) {
                switch (ch) {
-               /* change local password file */
-               case 'l':
+               case 'l':               /* change local password file */
                        use_kerberos = 0;
                        break;
                        use_kerberos = 0;
                        break;
+#else
+       while ((ch = getopt(argc, argv, "")) != EOF)
+               switch (ch) {
+#endif
                default:
                case '?':
                        usage();
                default:
                case '?':
                        usage();
@@ -88,16 +74,19 @@ main(argc, argv)
 
        argc -= optind;
        argv += optind;
 
        argc -= optind;
        argv += optind;
-#endif
+
+       uname = getlogin();
 
        switch(argc) {
        case 0:
                break;
        case 1:
 #ifdef KERBEROS
 
        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
                        exit(1);
                }
 #endif
@@ -109,490 +98,17 @@ main(argc, argv)
        }
 
 #ifdef KERBEROS
        }
 
 #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
 #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
 }
 
 usage()
 {
 #ifdef KERBEROS
-       fprintf(stderr, "usage: passwd [-l] user\n");
+       (void)fprintf(stderr, "usage: passwd [-l] user\n");
 #else
 #else
-       fprintf(stderr, "usage: passwd user\n");
+       (void)fprintf(stderr, "usage: passwd user\n");
 #endif
 }
 #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 */