[BACK]Return to su.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / su

Diff for /src/usr.bin/su/su.c between version 1.35 and 1.36

version 1.35, 2000/12/02 22:44:49 version 1.36, 2001/05/29 21:40:36
Line 59 
Line 59 
 #include <string.h>  #include <string.h>
 #include <syslog.h>  #include <syslog.h>
 #include <unistd.h>  #include <unistd.h>
 #include <fcntl.h>  #ifdef __STDC__
   #include <stdarg.h>
 #ifdef  SKEY  
 #include <skey.h>  
 #endif  
   
 #ifdef KERBEROS  
 #include <des.h>  
 #include <kerberosIV/krb.h>  
 #include <netdb.h>  
   
 int kerberos __P((char *username, char *user, int uid));  
   
 #define ARGSTR  "-Kc:flm"  
   
 int use_kerberos = 1;  
 char krbtkfile[MAXPATHLEN];  
 char lrealm[REALM_SZ];  
 int ksettkfile(char *);  
 #else  #else
 #define ARGSTR  "-c:flm"  #include <varargs.h>
 #endif  #endif
   #include <bsd_auth.h>
   
   #define ARGSTR  "-a:c:fKlm"
   
 char   *ontty __P((void));  char   *ontty __P((void));
 int     chshell __P((char *));  int     chshell __P((char *));
   void    usage __P((void));
   void    auth_err __P((auth_session_t *, int, const char *, ...));
   void    auth_errx __P((auth_session_t *, int, const char *, ...));
   
 int  int
 main(argc, argv)  main(argc, argv)
Line 91 
Line 80 
         char **argv;          char **argv;
 {  {
         extern char **environ;          extern char **environ;
         register struct passwd *pwd;          enum { UNSET, YES, NO } iscsh;
         register char *p, **g;          struct passwd *pwd;
         struct group *gr;          struct group *gr;
         uid_t ruid;          uid_t ruid;
         login_cap_t *lc;          login_cap_t *lc;
         int asme, ch, asthem, fastlogin, prio;          auth_session_t *as;
         enum { UNSET, YES, NO } iscsh;          int asme, asthem, authok, ch, fastlogin, prio;
         char *user, *shell, *avshell, *username, *class, **np;          char *class, *style, *p, **g;
           char *user, *shell, *avshell, *username, **np, *fullname;
         char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];          char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
   
         iscsh = UNSET;          iscsh = UNSET;
         shell = class = NULL;          class = shell = style = NULL;
         asme = asthem = fastlogin = 0;          asme = asthem = fastlogin = 0;
         while ((ch = getopt(argc, argv, ARGSTR)) != -1)          while ((ch = getopt(argc, argv, ARGSTR)) != -1)
                 switch((char)ch) {                  switch(ch) {
 #ifdef KERBEROS                  case 'a':
                 case 'K':                          if (style)
                         use_kerberos = 0;                                  usage();
                           style = optarg;
                         break;                          break;
 #endif  
                 case 'c':                  case 'c':
                           if (class)
                                   usage();
                         class = optarg;                          class = optarg;
                         break;                          break;
                 case 'f':                  case 'f':
                         fastlogin = 1;                          fastlogin = 1;
                         break;                          break;
                   case 'K':
                           if (style)
                                   usage();
                           style = "passwd";
                           break;
                 case '-':                  case '-':
                 case 'l':                  case 'l':
                         asme = 0;                          asme = 0;
Line 128 
Line 125 
                         break;                          break;
                 case '?':                  case '?':
                 default:                  default:
                         (void)fprintf(stderr,                          usage();
                             "usage: su [%s] [login [shell arguments]]\n",  
                             ARGSTR);  
                         exit(1);  
                 }                  }
         argv += optind;          argv += optind;
   
Line 142 
Line 136 
         (void)setpriority(PRIO_PROCESS, 0, -2);          (void)setpriority(PRIO_PROCESS, 0, -2);
         openlog("su", LOG_CONS, 0);          openlog("su", LOG_CONS, 0);
   
           if ((as = auth_open()) == NULL) {
                   syslog(LOG_ERR, "auth_open: %m");
                   err(1, "unable to begin authentication");
           }
   
         /* get current login name and shell */          /* get current login name and shell */
         ruid = getuid();          ruid = getuid();
         username = getlogin();          username = getlogin();
Line 149 
Line 148 
             pwd->pw_uid != ruid)              pwd->pw_uid != ruid)
                 pwd = getpwuid(ruid);                  pwd = getpwuid(ruid);
         if (pwd == NULL)          if (pwd == NULL)
                 errx(1, "who are you?");                  auth_errx(as, 1, "who are you?");
         if ((username = strdup(pwd->pw_name)) == NULL)          if ((username = strdup(pwd->pw_name)) == NULL)
                 err(1, "can't allocate memory");                  auth_err(as, 1, "can't allocate memory");
         if (asme) {          if (asme) {
                 if (pwd->pw_shell && *pwd->pw_shell) {                  if (pwd->pw_shell && *pwd->pw_shell) {
                         shell = strncpy(shellbuf, pwd->pw_shell, sizeof(shellbuf) - 1);                          strlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
                         shellbuf[sizeof(shellbuf) - 1] = '\0';                          shell = shellbuf;
                 } else {                  } else {
                         shell = _PATH_BSHELL;                          shell = _PATH_BSHELL;
                         iscsh = NO;                          iscsh = NO;
Line 164 
Line 163 
   
         /* get target login information, default to root */          /* get target login information, default to root */
         user = *argv ? *argv : "root";          user = *argv ? *argv : "root";
         np = *argv ? argv : argv-1;          np = *argv ? argv : argv - 1;
   
         if ((pwd = getpwnam(user)) == NULL)          if ((pwd = getpwnam(user)) == NULL)
                 errx(1, "unknown login %s", user);                  auth_errx(as, 1, "unknown login %s", user);
         if ((user = strdup(pwd->pw_name)) == NULL)          if ((user = strdup(pwd->pw_name)) == NULL)
                 err(1, "can't allocate memory");                  auth_err(as, 1, "can't allocate memory");
   
         /* If the user specified a login class and we are root, use it */          /* If the user specified a login class and we are root, use it */
         if (ruid && class)          if (ruid && class)
                 errx(1, "only the superuser may specify a login class");                  auth_errx(as, 1, "only the superuser may specify a login class");
         if (class)          if (class)
                 pwd->pw_class = class;                  pwd->pw_class = class;
         if ((lc = login_getclass(pwd->pw_class)) == NULL)          if ((lc = login_getclass(pwd->pw_class)) == NULL)
                 errx(1, "no such login class: %s",                  auth_errx(as, 1, "no such login class: %s",
                     class ? class : LOGIN_DEFCLASS);                      class ? class : LOGIN_DEFCLASS);
   
 #if KERBEROS  
         if (ksettkfile(user))  
                 use_kerberos = 0;  
 #endif  
   
         if (ruid) {          if (ruid) {
 #ifdef KERBEROS                  /*
             if (!use_kerberos || kerberos(username, user, pwd->pw_uid))                   * If we are trying to become root and the default style
 #endif                   * is being used, don't bother to look it up (we might be
             {                   * be su'ing up to fix /etc/login.conf)
                 /* only allow those in group zero to su to root. */                   */
                   if ((pwd->pw_uid || !style || strcmp(style, LOGIN_DEFSTYLE)) &&
                       (style = login_getstyle(lc, style, "auth-su")) == NULL)
                           auth_errx(as, 1, "invalid authentication type");
                   if (pwd->pw_uid || strcmp(user, "root") != 0)
                           fullname = user;
                   else {
                           if ((fullname =
                               malloc(strlen(username) + 6)) == NULL)
                                   auth_err(as, 1, NULL);
                           (void)sprintf(fullname, "%s.root", username);
                   }
                   /*
                    * Let the authentication program know whether they are
                    * in group wheel or not (if trying to become super user)
                    */
                 if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))                  if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))
                     && gr->gr_mem && *(gr->gr_mem))                      && gr->gr_mem && *(gr->gr_mem)) {
                         for (g = gr->gr_mem;; ++g) {                          for (g = gr->gr_mem; *g; ++g) {
                                 if (!*g)                                  if (strcmp(username, *g) == 0) {
                                         errx(1, "you are not in the correct group to su %s.", user);                                          auth_setoption(as, "wheel", "yes");
                                 if (strcmp(username, *g) == 0)  
                                         break;                                          break;
                 }                                  }
                 /* if target requires a password, verify it */  
                 if (*pwd->pw_passwd) {  
                         p = getpass("Password:");  
 #ifdef SKEY  
                         if (strcasecmp(p, "s/key") == 0) {  
                                 if (skey_authenticate(user))  
                                         goto badlogin;  
                         } else  
 #endif  
                         if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {  
 badlogin:  
                                 fprintf(stderr, "Sorry\n");  
                                 syslog(LOG_AUTH|LOG_WARNING,  
                                         "BAD SU %s to %s%s", username,  
                                         user, ontty());  
                                 exit(1);  
                         }                          }
                           if (!*g)
                                   auth_setoption(as, "wheel", "no");
                 }                  }
             }  
             if (pwd->pw_expire && time(NULL) >= pwd->pw_expire) {                  auth_verify(as, style, fullname, lc->lc_class, NULL);
                     fprintf(stderr, "Sorry - account expired\n");                  authok = auth_getstate(as);
                     syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username,                  if ((authok & AUTH_ALLOW) == 0) {
                             user, ontty());                          if ((p = auth_getvalue(as, "errormsg")) != NULL)
                     exit(1);                                  fprintf(stderr, "%s\n", p);
             }                          fprintf(stderr, "Sorry\n");
                           syslog(LOG_AUTH|LOG_WARNING,
                                   "BAD SU %s to %s%s", username, user, ontty());
                           auth_close(as);
                           exit(1);
                   }
         }          }
   
         if (asme) {          if (asme) {
                 /* if asme and non-standard target shell, must be root */                  /* if asme and non-standard target shell, must be root */
                 if (!chshell(pwd->pw_shell) && ruid)                  if (!chshell(pwd->pw_shell) && ruid)
                         errx(1, "permission denied (shell).");                          auth_errx(as, 1, "permission denied (shell).");
         } else if (pwd->pw_shell && *pwd->pw_shell) {          } else if (pwd->pw_shell && *pwd->pw_shell) {
                 shell = pwd->pw_shell;                  shell = pwd->pw_shell;
                 iscsh = UNSET;                  iscsh = UNSET;
Line 251 
Line 250 
                 if (asthem) {                  if (asthem) {
                         p = getenv("TERM");                          p = getenv("TERM");
                         if ((environ = calloc(1, sizeof (char *))) == NULL)                          if ((environ = calloc(1, sizeof (char *))) == NULL)
                                 errx(1, "calloc");                                  auth_errx(as, 1, "calloc");
                         if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH))                          if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH))
                                 err(1, "unable to set user context");                                  auth_err(as, 1, "unable to set user context");
                         if (p) {                          if (p && setenv("TERM", p, 1) == -1)
                                 if (setenv("TERM", p, 1) == -1)                                  auth_err(as, 1, "unable to set environment");
                                         err(1, "unable to set environment");  
                         }  
   
                         seteuid(pwd->pw_uid);                          seteuid(pwd->pw_uid);
                         setegid(pwd->pw_gid);                          setegid(pwd->pw_gid);
                         if (chdir(pwd->pw_dir) < 0)                          if (chdir(pwd->pw_dir) < 0)
                                 err(1, "%s", pwd->pw_dir);                                  auth_err(as, 1, "%s", pwd->pw_dir);
                         seteuid(0);                          seteuid(0);
                         setegid(0);     /* XXX use a saved gid instead? */                          setegid(0);     /* XXX use a saved gid instead? */
                 } else if (pwd->pw_uid == 0) {                  } else if (pwd->pw_uid == 0) {
                         /* XXX - this seems questionable to me */  
                         if (setusercontext(lc,                          if (setusercontext(lc,
                             pwd, pwd->pw_uid, LOGIN_SETPATH|LOGIN_SETUMASK))                              pwd, pwd->pw_uid, LOGIN_SETPATH|LOGIN_SETUMASK))
                                 err(1, "unable to set user context");                                  auth_err(as, 1, "unable to set user context");
                 }                  }
                 if (asthem || pwd->pw_uid) {                  if (asthem || pwd->pw_uid) {
                         if (setenv("LOGNAME", pwd->pw_name, 1) == -1 ||                          if (setenv("LOGNAME", pwd->pw_name, 1) == -1 ||
                             setenv("USER", pwd->pw_name, 1) == -1)                              setenv("USER", pwd->pw_name, 1) == -1)
                                 err(1, "unable to set environment");                                  auth_err(as, 1, "unable to set environment");
                 }                  }
                 if (setenv("HOME", pwd->pw_dir, 1) == -1 ||                  if (setenv("HOME", pwd->pw_dir, 1) == -1 ||
                     setenv("SHELL", shell, 1) == -1)                      setenv("SHELL", shell, 1) == -1)
                         err(1, "unable to set environment");                          auth_err(as, 1, "unable to set environment");
         }          }
   
 #ifdef KERBEROS  
         if (*krbtkfile) {  
                 if (setenv("KRBTKFILE", krbtkfile, 1) == -1)  
                         err(1, "unable to set environment");  
         }  
 #endif  
   
         if (iscsh == YES) {          if (iscsh == YES) {
                 if (fastlogin)                  if (fastlogin)
                         *np-- = "-f";                          *np-- = "-f";
Line 297 
Line 286 
   
         if (asthem) {          if (asthem) {
                 avshellbuf[0] = '-';                  avshellbuf[0] = '-';
                 strncpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 2);                  strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1);
                 avshellbuf[sizeof(avshellbuf) - 1] = '\0';  
                 avshell = avshellbuf;                  avshell = avshellbuf;
         } else if (iscsh == YES) {          } else if (iscsh == YES) {
                 /* csh strips the first character... */                  /* csh strips the first character... */
                 avshellbuf[0] = '_';                  avshellbuf[0] = '_';
                 strncpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 2);                  strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1);
                 avshellbuf[sizeof(avshellbuf) - 1] = '\0';  
                 avshell = avshellbuf;                  avshell = avshellbuf;
         }          }
   
Line 318 
Line 305 
         if (setusercontext(lc, pwd, pwd->pw_uid,          if (setusercontext(lc, pwd, pwd->pw_uid,
             (asthem ? (LOGIN_SETPRIORITY | LOGIN_SETUMASK) : 0) |              (asthem ? (LOGIN_SETPRIORITY | LOGIN_SETUMASK) : 0) |
             LOGIN_SETRESOURCES | LOGIN_SETGROUP | LOGIN_SETUSER))              LOGIN_SETRESOURCES | LOGIN_SETGROUP | LOGIN_SETUSER))
                 err(1, "unable to set user context");                  auth_err(as, 1, "unable to set user context");
           if (pwd->pw_uid && auth_approval(as, lc, pwd->pw_name, "su") <= 0)
                   auth_err(as, 1, "approval failure");
           auth_close(as);
   
         execv(shell, np);          execv(shell, np);
         err(1, "%s", shell);          err(1, "%s", shell);
Line 328 
Line 318 
 chshell(sh)  chshell(sh)
         char *sh;          char *sh;
 {  {
         register char *cp;          char *cp;
   
         while ((cp = getusershell()) != NULL)          while ((cp = getusershell()) != NULL)
                 if (strcmp(cp, sh) == 0)                  if (strcmp(cp, sh) == 0)
Line 339 
Line 329 
 char *  char *
 ontty()  ontty()
 {  {
         char *p, *ttyname();  
         static char buf[MAXPATHLEN + 4];          static char buf[MAXPATHLEN + 4];
           char *p;
   
         buf[0] = 0;          buf[0] = 0;
         if ((p = ttyname(STDERR_FILENO)))          if ((p = ttyname(STDERR_FILENO)))
Line 348 
Line 338 
         return (buf);          return (buf);
 }  }
   
 #ifdef KERBEROS  void
 int koktologin __P((char *, char *, char *));  usage()
   
 int  
 kerberos(username, user, uid)  
         char *username, *user;  
         int uid;  
 {  {
         KTEXT_ST ticket;          extern char *__progname;
         AUTH_DAT authdata;  
         struct hostent *hp;  
         int kerno, fd;  
         in_addr_t faddr;  
         char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];  
         char *ontty(), *krb_get_phost();  
   
         /* Don't bother with Kerberos if there is no srvtab file */          (void)fprintf(stderr, "usage: %s [%s] [-a auth-type] %s ",
         if ((fd = open(KEYFILE, O_RDONLY, 0)) < 0)              "[-c login-class] [login [argument ...]]\n", __progname, ARGSTR);
                 return (1);          exit(1);
         close(fd);  
   
         if (koktologin(username, lrealm, user) && !uid) {  
                 (void)fprintf(stderr, "kerberos su: not in %s's ACL.\n", user);  
                 return (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) {  
                 warn("setuid");  
                 return (1);  
         }  
   
         /*  
          * Little trick here -- if we are su'ing to root,  
          * we need to get a ticket for "xxx.root", where xxx represents  
          * the name of the person su'ing.  Otherwise (non-root case),  
          * 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  
          */  
   
         printf("%s%s@%s's ", (uid == 0 ? username : user),  
                (uid == 0 ? ".root" : ""), lrealm);  
         fflush(stdout);  
         kerno = krb_get_pw_in_tkt((uid == 0 ? username : user),  
                 (uid == 0 ? "root" : ""), lrealm,  
                 "krbtgt", lrealm, DEFAULT_TKT_LIFE, 0);  
   
         if (kerno != KSUCCESS) {  
                 if (kerno == KDC_PR_UNKNOWN) {  
                         warnx("kerberos principal unknown: %s.%s@%s",  
                                 (uid == 0 ? username : user),  
                                 (uid == 0 ? "root" : ""), lrealm);  
                         return (1);  
                 }  
                 warnx("unable to su: %s", krb_err_txt[kerno]);  
                 syslog(LOG_NOTICE|LOG_AUTH,  
                     "BAD Kerberos SU: %s to %s%s: %s",  
                     username, user, ontty(), krb_err_txt[kerno]);  
                 return (1);  
         }  
   
         /*  
          * Set the owner of the ticket file to root but bail if someone  
          * has nefariously swapped a link in place of the file.  
          */  
         fd = open(krbtkfile, O_RDWR|O_NOFOLLOW, 0);  
         if (fd == -1) {  
                 warn("unable to open ticket file");  
                 (void)unlink(krbtkfile);  
                 return (1);  
         }  
         if (fchown(fd, uid, -1) < 0) {  
                 warn("fchown");  
                 (void)unlink(krbtkfile);  
                 return (1);  
         }  
         close(fd);  
   
         (void)setpriority(PRIO_PROCESS, 0, -2);  
   
         if (gethostname(hostname, sizeof(hostname)) == -1) {  
                 warn("gethostname");  
                 dest_tkt();  
                 return (1);  
         }  
   
         (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost) - 1);  
         savehost[sizeof(savehost) - 1] = '\0';  
   
         kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);  
   
         if (kerno == KDC_PR_UNKNOWN) {  
                 warnx("Warning: TGT not verified.");  
                 syslog(LOG_NOTICE|LOG_AUTH,  
                     "%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) {  
                 warnx("Unable to use TGT: %s", 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();  
                 return (1);  
         } else {  
                 if (!(hp = gethostbyname(hostname))) {  
                         warnx("can't get addr of %s", hostname);  
                         dest_tkt();  
                         return (1);  
                 }  
                 (void)memcpy((void *)&faddr, (void *)hp->h_addr, sizeof(faddr));  
   
                 if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,  
                     &authdata, "")) != KSUCCESS) {  
                         warnx("unable to verify rcmd ticket: %s",  
                               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();  
                         return (1);  
                 }  
         }  
         return (0);  
 }  }
   
 int  void
 koktologin(name, realm, toname)  #ifdef __STDC__
         char *name, *realm, *toname;  auth_err(auth_session_t *as, int eval, const char *fmt, ...)
   #else
   auth_err(va_alist)
           va_dcl
   #endif
 {  {
         register AUTH_DAT *kdata;          va_list ap;
         AUTH_DAT kdata_st;  #ifdef __STDC__
           va_start(ap, fmt);
   #else
           auth_session_t *as;
           int eval;
           const char *fmt;
   
         memset((void *)&kdata_st, 0, sizeof(kdata_st));          va_start(ap);
         kdata = &kdata_st;          as = va_arg(ap, auth_session_t *);
           eval = va_arg(ap, int);
         (void)strncpy(kdata->pname, name, sizeof(kdata->pname) - 1);          fmt = va_arg(ap, const char *);
         kdata->pname[sizeof(kdata->pname) - 1] = '\0';  #endif
           verr(eval, fmt, ap);
         (void)strncpy(kdata->pinst,          auth_close(as);
             ((strcmp(toname, "root") == 0) ? "root" : ""), sizeof(kdata->pinst) - 1);          va_end(ap);
         kdata->pinst[sizeof(kdata->pinst) -1] = '\0';  
   
         (void)strncpy(kdata->prealm, realm, sizeof(kdata->prealm) - 1);  
         kdata->prealm[sizeof(kdata->prealm) -1] = '\0';  
   
         return (kuserok(kdata, toname));  
 }  }
   
 int  void
 ksettkfile(user)  #ifdef __STDC__
         char *user;  auth_errx(auth_session_t *as, int eval, const char *fmt, ...)
   #else
   auth_errx(va_alist)
           va_dcl
   #endif
 {  {
         if (krb_get_lrealm(lrealm, 1) != KSUCCESS)          va_list ap;
                 return (1);  #ifdef __STDC__
         (void)snprintf(krbtkfile, sizeof(krbtkfile), "%s_%s_%u", TKT_ROOT,          va_start(ap, fmt);
                 user, getuid());  #else
         return (0);          auth_session_t *as;
 }          int eval;
           const char *fmt;
   
           va_start(ap);
           as = va_arg(ap, auth_session_t *);
           eval = va_arg(ap, int);
           fmt = va_arg(ap, const char *);
 #endif  #endif
           verrx(eval, fmt, ap);
           auth_close(as);
           va_end(ap);
   }

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.36