BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / su / su.c
index d14ff1a..e024d81 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,7 +38,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)su.c       5.21 (Berkeley) 6/20/90";
+static char sccsid[] = "@(#)su.c       5.26 (Berkeley) 7/6/91";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -36,7 +50,7 @@ static char sccsid[] = "@(#)su.c      5.21 (Berkeley) 6/20/90";
 #include <grp.h>
 #include <string.h>
 #include <unistd.h>
 #include <grp.h>
 #include <string.h>
 #include <unistd.h>
-#include "pathnames.h"
+#include <paths.h>
 
 #ifdef KERBEROS
 #include <kerberosIV/des.h>
 
 #ifdef KERBEROS
 #include <kerberosIV/des.h>
@@ -64,7 +78,7 @@ main(argc, argv)
        enum { UNSET, YES, NO } iscsh = UNSET;
        char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
        char shellbuf[MAXPATHLEN];
        enum { UNSET, YES, NO } iscsh = UNSET;
        char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
        char shellbuf[MAXPATHLEN];
-       char *crypt(), *getpass(), *getenv(), *getlogin(), *mytty();
+       char *crypt(), *getpass(), *getenv(), *getlogin(), *ontty();
 
        np = &nargv[3];
        *np-- = NULL;
 
        np = &nargv[3];
        *np-- = NULL;
@@ -101,9 +115,15 @@ main(argc, argv)
        if (errno)
                prio = 0;
        (void)setpriority(PRIO_PROCESS, 0, -2);
        if (errno)
                prio = 0;
        (void)setpriority(PRIO_PROCESS, 0, -2);
+       openlog("su", LOG_CONS, 0);
 
        /* get current login name and shell */
 
        /* get current login name and shell */
-       if ((pwd = getpwuid(ruid = getuid())) == NULL) {
+       ruid = getuid();
+       username = getlogin();
+       if (username == NULL || (pwd = getpwnam(username)) == NULL ||
+           pwd->pw_uid != ruid)
+               pwd = getpwuid(ruid);
+       if (pwd == NULL) {
                fprintf(stderr, "su: who are you?\n");
                exit(1);
        }
                fprintf(stderr, "su: who are you?\n");
                exit(1);
        }
@@ -123,34 +143,35 @@ main(argc, argv)
                exit(1);
        }
 
                exit(1);
        }
 
-       /* only allow those in group zero to su to root. */
-       if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)))
-               for (g = gr->gr_mem;; ++g) {
-                       if (!*g) {
-                               (void)fprintf(stderr,
-                                   "su: you are not in the correct group to su %s.\n", user);
-                               exit(1);
-                       }
-                       if (!strcmp(username, *g))
-                               break;
-               }
-       openlog("su", LOG_CONS, 0);
-
        if (ruid) {
 #ifdef KERBEROS
        if (ruid) {
 #ifdef KERBEROS
-               if (!use_kerberos || kerberos(username, user, pwd->pw_uid))
+           if (!use_kerberos || kerberos(username, user, pwd->pw_uid))
 #endif
 #endif
+           {
+               /* only allow those in group zero to su to root. */
+               if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)))
+                       for (g = gr->gr_mem;; ++g) {
+                               if (!*g) {
+                                       (void)fprintf(stderr,
+                           "su: you are not in the correct group to su %s.\n",
+                                           user);
+                                       exit(1);
+                               }
+                               if (!strcmp(username, *g))
+                                       break;
+               }
                /* if target requires a password, verify it */
                if (*pwd->pw_passwd) {
                        p = getpass("Password:");
                        if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
                                fprintf(stderr, "Sorry\n");
                /* if target requires a password, verify it */
                if (*pwd->pw_passwd) {
                        p = getpass("Password:");
                        if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
                                fprintf(stderr, "Sorry\n");
-                               syslog(LOG_AUTH|LOG_CRIT,
-                                       "BAD SU %s on %s to %s", username,
-                                       mytty(), user);
+                               syslog(LOG_AUTH|LOG_WARNING,
+                                       "BAD SU %s to %s%s", username,
+                                       user, ontty());
                                exit(1);
                        }
                }
                                exit(1);
                        }
                }
+           }
        }
 
        if (asme) {
        }
 
        if (asme) {
@@ -194,7 +215,7 @@ main(argc, argv)
        if (!asme) {
                if (asthem) {
                        p = getenv("TERM");
        if (!asme) {
                if (asthem) {
                        p = getenv("TERM");
-                       cleanenv[0] = _PATH_SEARCHPATH;
+                       cleanenv[0] = _PATH_DEFPATH;
                        cleanenv[1] = NULL;
                        environ = cleanenv;
                        (void)setenv("TERM", p, 1);
                        cleanenv[1] = NULL;
                        environ = cleanenv;
                        (void)setenv("TERM", p, 1);
@@ -219,7 +240,9 @@ main(argc, argv)
        /* csh strips the first character... */
        *np = asthem ? "-su" : iscsh == YES ? "_su" : "su";
 
        /* csh strips the first character... */
        *np = asthem ? "-su" : iscsh == YES ? "_su" : "su";
 
-       syslog(LOG_NOTICE|LOG_AUTH, "%s on %s to %s", username, mytty(), user);
+       if (ruid != 0)
+               syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s",
+                   username, user, ontty());
 
        (void)setpriority(PRIO_PROCESS, 0, prio);
 
 
        (void)setpriority(PRIO_PROCESS, 0, prio);
 
@@ -236,16 +259,20 @@ chshell(sh)
 
        while ((cp = getusershell()) != NULL)
                if (!strcmp(cp, sh))
 
        while ((cp = getusershell()) != NULL)
                if (!strcmp(cp, sh))
-                       return(1);
-       return(0);
+                       return (1);
+       return (0);
 }
 
 char *
 }
 
 char *
-mytty()
+ontty()
 {
        char *p, *ttyname();
 {
        char *p, *ttyname();
+       static char buf[MAXPATHLEN + 4];
 
 
-       return((p = ttyname(STDERR_FILENO)) ? p : "UNKNOWN TTY");
+       buf[0] = 0;
+       if (p = ttyname(STDERR_FILENO))
+               sprintf(buf, " on %s", p);
+       return (buf);
 }
 
 #ifdef KERBEROS
 }
 
 #ifdef KERBEROS
@@ -262,24 +289,26 @@ kerberos(username, user, uid)
        u_long faddr;
        char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN];
        char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
        u_long faddr;
        char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN];
        char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
-       char *mytty();
+       char *ontty(), *krb_get_phost();
 
 
-       if (krb_get_lrealm(lrealm, 1) != KSUCCESS) {
-               (void)fprintf(stderr, "su: couldn't get local realm.\n");
-               return(1);
-       }
+       if (krb_get_lrealm(lrealm, 1) != KSUCCESS)
+               return (1);
        if (koktologin(username, lrealm, user) && !uid) {
                (void)fprintf(stderr, "kerberos su: not in %s's ACL.\n", user);
        if (koktologin(username, lrealm, user) && !uid) {
                (void)fprintf(stderr, "kerberos su: not in %s's ACL.\n", user);
-               return(1);
+               return (1);
        }
        (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid());
 
        (void)setenv("KRBTKFILE", krbtkfile, 1);
        }
        (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid());
 
        (void)setenv("KRBTKFILE", krbtkfile, 1);
+       (void)krb_set_tkt_string(krbtkfile);
+       /*
+        * Set real as well as effective ID to 0 for the moment,
+        * to make the kerberos library do the right thing.
+        */
        if (setuid(0) < 0) {
                perror("su: setuid");
        if (setuid(0) < 0) {
                perror("su: setuid");
-               return(1);
+               return (1);
        }
        }
-       (void)unlink(krbtkfile);
 
        /*
         * Little trick here -- if we are su'ing to root,
 
        /*
         * Little trick here -- if we are su'ing to root,
@@ -288,38 +317,40 @@ kerberos(username, user, uid)
         * we need to get a ticket for "yyy.", where yyy represents
         * the name of the person being su'd to, and the instance is null
         *
         * we need to get a ticket for "yyy.", where yyy represents
         * the name of the person being su'd to, and the instance is null
         *
-        * Also: POLICY: short ticket lifetime for root
+        * We should have a way to set the ticket lifetime,
+        * with a system default for root.
         */
        kerno = krb_get_pw_in_tkt((uid == 0 ? username : user),
                (uid == 0 ? "root" : ""), lrealm,
         */
        kerno = krb_get_pw_in_tkt((uid == 0 ? username : user),
                (uid == 0 ? "root" : ""), lrealm,
-               "krbtgt", lrealm, (uid == 0 ? 2 : DEFAULT_TKT_LIFE), 0);
+               "krbtgt", lrealm, DEFAULT_TKT_LIFE, 0);
 
        if (kerno != KSUCCESS) {
                if (kerno == KDC_PR_UNKNOWN) {
                        fprintf(stderr, "principal unknown: %s.%s@%s\n",
                                (uid == 0 ? username : user),
                                (uid == 0 ? "root" : ""), lrealm);
 
        if (kerno != KSUCCESS) {
                if (kerno == KDC_PR_UNKNOWN) {
                        fprintf(stderr, "principal unknown: %s.%s@%s\n",
                                (uid == 0 ? username : user),
                                (uid == 0 ? "root" : ""), lrealm);
-                       return(1);
+                       return (1);
                }
                }
-               (void)printf("su: unable to su: %s\n", krb_err_txt[kerno]);
+               (void)fprintf(stderr, "su: unable to su: %s\n",
+                   krb_err_txt[kerno]);
                syslog(LOG_NOTICE|LOG_AUTH,
                syslog(LOG_NOTICE|LOG_AUTH,
-                   "su: BAD Kerberos SU: %s on %s to %s: %s",
-                   username, mytty(), user, krb_err_txt[kerno]);
-               return(1);
+                   "BAD Kerberos SU: %s to %s%s: %s",
+                   username, user, ontty(), krb_err_txt[kerno]);
+               return (1);
        }
 
        if (chown(krbtkfile, uid, -1) < 0) {
                perror("su: chown:");
                (void)unlink(krbtkfile);
        }
 
        if (chown(krbtkfile, uid, -1) < 0) {
                perror("su: chown:");
                (void)unlink(krbtkfile);
-               return(1);
+               return (1);
        }
 
        (void)setpriority(PRIO_PROCESS, 0, -2);
 
        if (gethostname(hostname, sizeof(hostname)) == -1) {
        }
 
        (void)setpriority(PRIO_PROCESS, 0, -2);
 
        if (gethostname(hostname, sizeof(hostname)) == -1) {
-               perror("su: hostname");
+               perror("su: gethostname");
                dest_tkt();
                dest_tkt();
-               return(1);
+               return (1);
        }
 
        (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost));
        }
 
        (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost));
@@ -328,36 +359,40 @@ kerberos(username, user, uid)
        kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
 
        if (kerno == KDC_PR_UNKNOWN) {
        kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
 
        if (kerno == KDC_PR_UNKNOWN) {
-               (void)printf("Warning: tgt not verified.\n");
+               (void)fprintf(stderr, "Warning: TGT not verified.\n");
                syslog(LOG_NOTICE|LOG_AUTH,
                syslog(LOG_NOTICE|LOG_AUTH,
-                       "su: %s on %s to %s, TGT not verified",
-                       username, mytty(), user);
+                   "%s to %s%s, TGT not verified (%s); %s.%s not registered?",
+                   username, user, ontty(), krb_err_txt[kerno],
+                   "rcmd", savehost);
        } else if (kerno != KSUCCESS) {
        } else if (kerno != KSUCCESS) {
-               (void)printf("Unable to use TGT: %s\n", krb_err_txt[kerno]);
-               syslog(LOG_NOTICE|LOG_AUTH, "su: failed su: %s on %s to %s: %s",
-                   username, mytty(), user, krb_err_txt[kerno]);
+               (void)fprintf(stderr, "Unable to use TGT: %s\n",
+                   krb_err_txt[kerno]);
+               syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s",
+                   username, user, ontty(), krb_err_txt[kerno]);
                dest_tkt();
                dest_tkt();
-               return(1);
+               return (1);
        } else {
                if (!(hp = gethostbyname(hostname))) {
        } else {
                if (!(hp = gethostbyname(hostname))) {
-                       (void)printf("su: can't get addr of %s\n", hostname);
+                       (void)fprintf(stderr, "su: can't get addr of %s\n",
+                           hostname);
                        dest_tkt();
                        dest_tkt();
-                       return(1);
+                       return (1);
                }
                (void)bcopy((char *)hp->h_addr, (char *)&faddr, sizeof(faddr));
 
                if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,
                    &authdata, "")) != KSUCCESS) {
                }
                (void)bcopy((char *)hp->h_addr, (char *)&faddr, sizeof(faddr));
 
                if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,
                    &authdata, "")) != KSUCCESS) {
-                       (void)printf("su: unable to verify rcmd ticket: %s\n",
+                       (void)fprintf(stderr,
+                           "su: unable to verify rcmd ticket: %s\n",
                            krb_err_txt[kerno]);
                        syslog(LOG_NOTICE|LOG_AUTH,
                            krb_err_txt[kerno]);
                        syslog(LOG_NOTICE|LOG_AUTH,
-                           "su: failed su: %s on %s to %s: %s", username,
-                           mytty(), user, krb_err_txt[kerno]);
+                           "failed su: %s to %s%s: %s", username,
+                            user, ontty(), krb_err_txt[kerno]);
                        dest_tkt();
                        dest_tkt();
-                       return(1);
+                       return (1);
                }
        }
                }
        }
-       return(0);
+       return (0);
 }
 
 koktologin(name, realm, toname)
 }
 
 koktologin(name, realm, toname)
@@ -372,6 +407,6 @@ koktologin(name, realm, toname)
        (void)strcpy(kdata->pinst,
            ((strcmp(toname, "root") == 0) ? "root" : ""));
        (void)strcpy(kdata->prealm, realm);
        (void)strcpy(kdata->pinst,
            ((strcmp(toname, "root") == 0) ? "root" : ""));
        (void)strcpy(kdata->prealm, realm);
-       return(kuserok(kdata, toname));
+       return (kuserok(kdata, toname));
 }
 #endif
 }
 #endif