122347Spst/* opiesu.c: main body of code for the su(1m) program
222347Spst
329964Sache%%% portions-copyright-cmetz-96
492906SmarkmPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights
522347SpstReserved. The Inner Net License Version 2 applies to these portions of
622347Spstthe software.
722347SpstYou should have received a copy of the license with this software. If
822347Spstyou didn't get a copy, you may request one from <license@inner.net>.
922347Spst
1022347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan
1122347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned
1222347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
1322347SpstLicense Agreement applies to this software.
1422347Spst
1522347Spst	History:
1622347Spst
1792906Smarkm	Modified by cmetz for OPIE 2.4. Check euid on startup. Use
1892906Smarkm		opiestrncpy().
1959118Skris	Modified by cmetz for OPIE 2.32. Set up TERM and PATH correctly.
2029964Sache	Modified by cmetz for OPIE 2.31. Fix sulog(). Replaced Getlogin() with
2129964Sache		currentuser. Fixed fencepost error in month printed by sulog().
2222347Spst	Modified by cmetz for OPIE 2.3. Limit the length of TERM on full login.
2322347Spst		Use HAVE_SULOG instead of DOSULOG.
2422347Spst        Modified by cmetz for OPIE 2.2. Don't try to clear non-blocking I/O.
2522347Spst                Use opiereadpass(). Minor speedup. Removed termios manipulation
2622347Spst                -- that's opiereadpass()'s job. Change opiereadpass() calls
2722347Spst                to add echo arg. Removed useless strings (I don't think that
2822347Spst                removing the ucb copyright one is a problem -- please let me
2922347Spst                know if I'm wrong). Use FUNCTION declaration et al. Ifdef
3022347Spst                around some headers. Make everything static. Removed
3122347Spst                closelog() prototype. Use the same catchexit() trickery as
3222347Spst                opielogin.
3322347Spst        Modified at NRL for OPIE 2.2. Changed opiestrip_crlf to
3422347Spst                opiestripcrlf.
3522347Spst        Modified at NRL for OPIE 2.1. Added struct group declaration.
3622347Spst	        Added Solaris(+others?) sulog capability. Symbol changes
3722347Spst		for autoconf. Removed des_crypt.h. File renamed to
3822347Spst		opiesu.c. Symbol+misc changes for autoconf. Added bletch
3922347Spst		for setpriority.
4022347Spst        Modified at NRL for OPIE 2.02. Added SU_STAR_CHECK (turning a bug
4122347Spst                into a feature ;). Fixed Solaris shadow password problem
4222347Spst                introduced in OPIE 2.01 (the shadow password structure is
4322347Spst                spwd, not spasswd).
4422347Spst        Modified at NRL for OPIE 2.01. Changed password lookup handling
4522347Spst                to use a static structure to avoid problems with drain-
4622347Spst                bamaged shadow password packages. Always log failures.
4722347Spst                Make sure to close syslog by function to avoid problems
4822347Spst                with drain bamaged syslog implementations. Log a few
4922347Spst                interesting errors.
5022347Spst	Modified at NRL for OPIE 2.0.
5122347Spst	Modified at Bellcore for the S/Key Version 1 software distribution.
5222347Spst	Originally from BSD.
5322347Spst*/
5422347Spst
5522347Spst/*
5622347Spst * Copyright (c) 1980 Regents of the University of California.
5722347Spst * All rights reserved.  The Berkeley software License Agreement
5822347Spst * specifies the terms and conditions for redistribution.
5922347Spst */
6022347Spst
6122347Spst#include "opie_cfg.h"
6222347Spst
6322347Spst#include <stdio.h>
6422347Spst#if HAVE_PWD_H
6522347Spst#include <pwd.h>
6622347Spst#endif /* HAVE_PWD_H */
6722347Spst#include <grp.h>
6822347Spst#include <syslog.h>
6922347Spst#include <sys/types.h>
7022347Spst#if HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H
7122347Spst#if TIME_WITH_SYS_TIME
7222347Spst# include <sys/time.h>
7322347Spst# include <time.h>
7422347Spst#else /* TIME_WITH_SYS_TIME */
7522347Spst#if HAVE_SYS_TIME_H
7622347Spst#include <sys/time.h>
7722347Spst#else /* HAVE_SYS_TIME_H */
7822347Spst#include <time.h>
7922347Spst#endif /* HAVE_SYS_TIME_H */
8022347Spst#endif /* TIME_WITH_SYS_TIME */
8122347Spst#include <sys/resource.h>
8222347Spst#else /* HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H */
8322347Spst#if TM_IN_SYS_TIME
8422347Spst#include <sys/time.h>
8522347Spst#else /* TM_IN_SYS_TIME */
8622347Spst#include <time.h>
8722347Spst#endif /* TM_IN_SYS_TIME */
8822347Spst#endif /* HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H */
8922347Spst#if HAVE_STDLIB_H
9022347Spst#include <stdlib.h>
9122347Spst#endif /* HAVE_STDLIB_H */
9222347Spst#if HAVE_UNISTD_H
9322347Spst#include <unistd.h>
9422347Spst#endif /* HAVE_UNISTD_H */
9522347Spst#if HAVE_STRING_H
9622347Spst#include <string.h>
9722347Spst#endif /* HAVE_STRING_H */
9822347Spst#include <errno.h>
9922347Spst
10022347Spst#include "opie.h"
10122347Spst
10222347Spststatic char userbuf[16] = "USER=";
10322347Spststatic char homebuf[128] = "HOME=";
10422347Spststatic char shellbuf[128] = "SHELL=";
10559118Skrisstatic char pathbuf[sizeof("PATH") + sizeof(DEFAULT_PATH) - 1] = "PATH=";
10622347Spststatic char termbuf[32] = "TERM=";
10722347Spststatic char *cleanenv[] = {userbuf, homebuf, shellbuf, pathbuf, 0, 0};
10822347Spststatic char *user = "root";
10922347Spststatic char *shell = "/bin/sh";
11022347Spststatic int fulllogin;
11129964Sache#if 0
11222347Spststatic int fastlogin;
11329964Sache#else /* 0 */
11429964Sachestatic int force = 0;
11529964Sache#endif /* 0 */
11622347Spst
11729964Sachestatic char currentuser[65];
11829964Sache
11922347Spstextern char **environ;
12022347Spststatic struct passwd thisuser, nouser;
12122347Spst
12222347Spst#if HAVE_SHADOW_H
12322347Spst#include <shadow.h>
12422347Spst#endif /* HAVE_SHADOW_H */
12522347Spst
12622347Spst#if HAVE_CRYPT_H
12722347Spst#include <crypt.h>
12822347Spst#endif /* HAVE_CRYPT_H */
12922347Spst
13022347Spststatic VOIDRET catchexit FUNCTION_NOARGS
13122347Spst{
13222347Spst  int i;
13322347Spst  closelog();
13422347Spst  for (i = sysconf(_SC_OPEN_MAX); i > 2; i--)
13522347Spst    close(i);
13622347Spst}
13722347Spst
13822347Spst/* We allow the malloc()s to potentially leak data out because we can
13922347Spstonly call this routine about four times in the lifetime of this process
14022347Spstand the kernel will free all heap memory when we exit or exec. */
14122347Spststatic int lookupuser FUNCTION((name), char *name)
14222347Spst{
14322347Spst  struct passwd *pwd;
14422347Spst#if HAVE_SHADOW
14522347Spst  struct spwd *spwd;
14622347Spst#endif /* HAVE_SHADOW */
14722347Spst
14822347Spst  memcpy(&thisuser, &nouser, sizeof(thisuser));
14922347Spst
15022347Spst  if (!(pwd = getpwnam(name)))
15122347Spst    return -1;
15222347Spst
15322347Spst  thisuser.pw_uid = pwd->pw_uid;
15422347Spst  thisuser.pw_gid = pwd->pw_gid;
15522347Spst
15622347Spst  if (!(thisuser.pw_name = malloc(strlen(pwd->pw_name) + 1)))
15722347Spst    goto lookupuserbad;
15822347Spst  strcpy(thisuser.pw_name, pwd->pw_name);
15922347Spst
16022347Spst  if (!(thisuser.pw_dir = malloc(strlen(pwd->pw_dir) + 1)))
16122347Spst    goto lookupuserbad;
16222347Spst  strcpy(thisuser.pw_dir, pwd->pw_dir);
16322347Spst
16422347Spst  if (!(thisuser.pw_shell = malloc(strlen(pwd->pw_shell) + 1)))
16522347Spst    goto lookupuserbad;
16622347Spst  strcpy(thisuser.pw_shell, pwd->pw_shell);
16722347Spst
16822347Spst#if HAVE_SHADOW
16922347Spst  if (!(spwd = getspnam(name)))
17022347Spst	goto lookupuserbad;
17122347Spst
17222347Spst  pwd->pw_passwd = spwd->sp_pwdp;
17322347Spst
17422347Spst  endspent();
17522347Spst#endif /* HAVE_SHADOW */
17622347Spst
17722347Spst  if (!(thisuser.pw_passwd = malloc(strlen(pwd->pw_passwd) + 1)))
17822347Spst    goto lookupuserbad;
17922347Spst  strcpy(thisuser.pw_passwd, pwd->pw_passwd);
18022347Spst
18122347Spst  endpwent();
18222347Spst
18322347Spst#if SU_STAR_CHECK
18422347Spst  return ((thisuser.pw_passwd[0] == '*') || (thisuser.pw_passwd[0] == '#'));
18522347Spst#else /* SU_STAR_CHECK */
18622347Spst  return 0;
18722347Spst#endif /* SU_STAR_CHECK */
18822347Spst
18922347Spstlookupuserbad:
19022347Spst  memcpy(&thisuser, &nouser, sizeof(thisuser));
19122347Spst  return -1;
19222347Spst}
19322347Spst
19422347Spststatic VOIDRET lsetenv FUNCTION((ename, eval, buf), char *ename AND char *eval AND char *buf)
19522347Spst{
19622347Spst  register char *cp, *dp;
19722347Spst  register char **ep = environ;
19822347Spst
19922347Spst  /* this assumes an environment variable "ename" already exists */
20022347Spst  while (dp = *ep++) {
20122347Spst    for (cp = ename; *cp == *dp && *cp; cp++, dp++)
20222347Spst      continue;
20322347Spst    if (*cp == 0 && (*dp == '=' || *dp == 0)) {
20422347Spst      strcat(buf, eval);
20522347Spst      *--ep = buf;
20622347Spst      return;
20722347Spst    }
20822347Spst  }
20922347Spst}
21022347Spst
21122347Spst#if HAVE_SULOG
21222347Spststatic int sulog FUNCTION((status, who), int status AND char *who)
21322347Spst{
21422347Spst  char *from;
21522347Spst  char *ttynam;
21622347Spst  struct tm *tm;
21722347Spst  FILE *f;
21822347Spst  time_t now;
21922347Spst
22022347Spst  if (who)
22122347Spst    from = who;
22222347Spst  else
22329964Sache    from = currentuser;
22422347Spst
22522347Spst  if (!strncmp(ttynam = ttyname(2), "/dev/", 5))
22622347Spst    ttynam += 5;
22722347Spst
22822347Spst  now = time(NULL);
22922347Spst  tm = localtime(&now);
23022347Spst
23122347Spst  if (!(f = fopen("/var/adm/sulog", "a"))) {
23222347Spst    fprintf(stderr, "Can't update su log!\n");
23322347Spst    exit(1);
23422347Spst  }
23522347Spst
23622347Spst  fprintf(f, "SU %02d/%02d %02d:%02d %c %s %s-%s\n",
23729964Sache	  tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
23829964Sache	  status ? '+' : '-', ttynam, from, user);
23922347Spst  fclose(f);
24022347Spst}
24122347Spst#endif /* HAVE_SULOG */
24222347Spst
24322347Spstint main FUNCTION((argc, argv),	int argc AND char *argv[])
24422347Spst{
24529964Sache  char *p;
24622347Spst  struct opie opie;
24722347Spst  int i;
24822347Spst  char pbuf[256];
24922347Spst  char opieprompt[80];
25022347Spst  int console = 0;
25129964Sache  char *argvbuf;
25222347Spst
25322347Spst  for (i = sysconf(_SC_OPEN_MAX); i > 2; i--)
25422347Spst    close(i);
25522347Spst
25629964Sache  openlog("su", LOG_ODELAY, LOG_AUTH);
25729964Sache  atexit(catchexit);
25822347Spst
25929964Sache  {
26029964Sache  int argvsize = 0;
26129964Sache  for (i = 0; i < argc; argvsize += strlen(argv[i++]));
26229964Sache  argvsize += argc;
26329964Sache  if (!(argvbuf = malloc(argvsize))) {
26429964Sache    syslog(LOG_ERR, "can't allocate memory to store command line");
26529964Sache    exit(1);
26629964Sache  };
26729964Sache  for (i = 0, *argvbuf = 0; i < argc;) {
26829964Sache    strcat(argvbuf, argv[i]);
26929964Sache    if (++i < argc)
27029964Sache      strcat(argvbuf, " ");
27129964Sache  };
27229964Sache  };
27329964Sache
27459118Skris  strcat(pathbuf, DEFAULT_PATH);
27529964Sache
27622347Spstagain:
27722347Spst  if (argc > 1 && strcmp(argv[1], "-f") == 0) {
27829964Sache#if 0
27922347Spst    fastlogin++;
28029964Sache#else /* 0 */
28129964Sache#if INSECURE_OVERRIDE
28229964Sache    force = 1;
28329964Sache#else /* INSECURE_OVERRIDE */
28429964Sache    fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
28529964Sache#endif /* INSECURE_OVERRIDE */
28629964Sache#endif /* 0 */
28722347Spst    argc--, argv++;
28822347Spst    goto again;
28922347Spst  }
29022347Spst  if (argc > 1 && strcmp(argv[1], "-c") == 0) {
29122347Spst    console++;
29222347Spst    argc--, argv++;
29322347Spst    goto again;
29422347Spst  }
29522347Spst  if (argc > 1 && strcmp(argv[1], "-") == 0) {
29622347Spst    fulllogin++;
29722347Spst    argc--;
29822347Spst    argv++;
29922347Spst    goto again;
30022347Spst  }
30122347Spst  if (argc > 1 && argv[1][0] != '-') {
30222347Spst    user = argv[1];
30322347Spst    argc--;
30422347Spst    argv++;
30522347Spst  }
30622347Spst
30792906Smarkm
30822347Spst  {
30922347Spst  struct passwd *pwd;
31029964Sache  char *p = getlogin();
31129964Sache  char buf[32];
31222347Spst
31322347Spst  if ((pwd = getpwuid(getuid())) == NULL) {
31429964Sache    syslog(LOG_CRIT, "'%s' failed for unknown uid %d on %s", argvbuf, getuid(), ttyname(2));
31522347Spst#if HAVE_SULOG
31622347Spst    sulog(0, "unknown");
31722347Spst#endif /* HAVE_SULOG */
31822347Spst    exit(1);
31922347Spst  }
32092906Smarkm  opiestrncpy(buf, pwd->pw_name, sizeof(buf));
32122347Spst
32229964Sache  if (!p)
32329964Sache    p = "unknown";
32429964Sache
32592906Smarkm  opiestrncpy(currentuser, p, 31);
32629964Sache
32729964Sache  if (p && *p && strcmp(currentuser, buf)) {
32829964Sache    strcat(currentuser, "(");
32929964Sache    strcat(currentuser, buf);
33029964Sache    strcat(currentuser, ")");
33129964Sache  };
33229964Sache
33322347Spst  if (lookupuser(user)) {
33429964Sache    syslog(LOG_CRIT, "'%s' failed for %s on %s", argvbuf, currentuser, ttyname(2));
33522347Spst#if HAVE_SULOG
33622347Spst    sulog(0, NULL);
33722347Spst#endif /* HAVE_SULOG */
33822347Spst    fprintf(stderr, "Unknown user: %s\n", user);
33922347Spst    exit(1);
34022347Spst  }
34122347Spst
34292906Smarkm  if (geteuid()) {
34392906Smarkm    syslog(LOG_CRIT, "'%s' failed for %s on %s: not running with superuser priveleges", argvbuf, currentuser, ttyname(2));
34492906Smarkm#if HAVE_SULOG
34592906Smarkm    sulog(0, NULL);
34692906Smarkm#endif /* HAVE_SULOG */
34792906Smarkm    fprintf(stderr, "You do not have permission to su %s\n", user);
34892906Smarkm    exit(1);
34992906Smarkm  };
35092906Smarkm
35122347Spst/* Implement the BSD "wheel group" su restriction. */
35222347Spst#if DOWHEEL
35322347Spst  /* Only allow those in group zero to su to root? */
35422347Spst  if (thisuser.pw_uid == 0) {
35522347Spst    struct group *gr;
35622347Spst    if ((gr = getgrgid(0)) != NULL) {
35722347Spst      for (i = 0; gr->gr_mem[i] != NULL; i++)
35822347Spst	if (strcmp(buf, gr->gr_mem[i]) == 0)
35922347Spst	  goto userok;
36022347Spst      fprintf(stderr, "You do not have permission to su %s\n", user);
36122347Spst      exit(1);
36222347Spst    }
36322347Spstuserok:
36422347Spst    ;
36522347Spst#if HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H
36622347Spst    setpriority(PRIO_PROCESS, 0, -2);
36722347Spst#endif /* HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H */
36822347Spst  }
36922347Spst#endif	/* DOWHEEL */
37029964Sache  };
37122347Spst
37222347Spst  if (!thisuser.pw_passwd[0] || getuid() == 0)
37322347Spst    goto ok;
37422347Spst
37522347Spst  if (console) {
37622347Spst    if (!opiealways(thisuser.pw_dir)) {
37722347Spst      fprintf(stderr, "That account requires OTP responses.\n");
37822347Spst      exit(1);
37922347Spst    };
38022347Spst    /* Get user's secret password */
38122347Spst    fprintf(stderr, "Reminder - Only use this method from the console; NEVER from remote. If you\n");
38222347Spst    fprintf(stderr, "are using telnet, xterm, or a dial-in, type ^C now or exit with no password.\n");
38322347Spst    fprintf(stderr, "Then run su without the -c parameter.\n");
38422347Spst    if (opieinsecure()) {
38522347Spst      fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
38629964Sache#if INSECURE_OVERRIDE
38729964Sache    if (force)
38829964Sache      fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
38929964Sache    else
39029964Sache#endif /* INSECURE_OVERRIDE */
39122347Spst      exit(1);
39222347Spst    };
39322347Spst#if NEW_PROMPTS
39422347Spst    printf("%s's system password: ", thisuser.pw_name);
39522347Spst    if (!opiereadpass(pbuf, sizeof(pbuf), 0))
39622347Spst      goto error;
39722347Spst#endif /* NEW_PROMPTS */
39822347Spst  } else {
39922347Spst    /* Attempt an OTP challenge */
40022347Spst    i = opiechallenge(&opie, user, opieprompt);
40122347Spst    printf("%s\n", opieprompt);
40222347Spst#if NEW_PROMPTS
40322347Spst    printf("%s's response: ", thisuser.pw_name);
40422347Spst    if (!opiereadpass(pbuf, sizeof(pbuf), 1))
40522347Spst      goto error;
40622347Spst#else /* NEW_PROMPTS */
40722347Spst    printf("(OTP response required)\n");
40822347Spst#endif /* NEW_PROMPTS */
40922347Spst    fflush(stdout);
41022347Spst  };
41122347Spst#if !NEW_PROMPTS
41222347Spst  printf("%s's password: ", thisuser.pw_name);
41322347Spst  if (!opiereadpass(pbuf, sizeof(pbuf), 0))
41422347Spst    goto error;
41522347Spst#endif /* !NEW_PROMPTS */
41622347Spst
41722347Spst#if !NEW_PROMPTS
41822347Spst  if (!pbuf[0] && !console) {
41922347Spst    /* Null line entered; turn echoing back on and read again */
42022347Spst    printf(" (echo on)\n%s's password: ", thisuser.pw_name);
42122347Spst    if (!opiereadpass(pbuf, sizeof(pbuf), 1))
42222347Spst      goto error;
42322347Spst  }
42422347Spst#endif /* !NEW_PROMPTS */
42522347Spst
42622347Spst  if (console) {
42722347Spst    /* Try regular password check, if allowed */
42822347Spst    if (!strcmp(crypt(pbuf, thisuser.pw_passwd), thisuser.pw_passwd))
42922347Spst      goto ok;
43022347Spst  } else {
43122347Spst    int i = opiegetsequence(&opie);
43222347Spst    if (!opieverify(&opie, pbuf)) {
43322347Spst      /* OPIE authentication succeeded */
43422347Spst      if (i < 5)
43522347Spst	fprintf(stderr, "Warning: Change %s's OTP secret pass phrase NOW!\n", user);
43622347Spst      else
43722347Spst	if (i < 10)
43822347Spst	  fprintf(stderr, "Warning: Change %s's OTP secret pass phrase soon.\n", user);
43922347Spst      goto ok;
44022347Spst    };
44122347Spst  };
44222347Spsterror:
44329964Sache  if (!console)
44429964Sache    opieverify(&opie, "");
44522347Spst  fprintf(stderr, "Sorry\n");
44629964Sache  syslog(LOG_CRIT, "'%s' failed for %s on %s", argvbuf, currentuser, ttyname(2));
44722347Spst#if HAVE_SULOG
44822347Spst  sulog(0, NULL);
44922347Spst#endif /* HAVE_SULOG */
45022347Spst  exit(2);
45122347Spst
45222347Spstok:
45329964Sache  syslog(LOG_NOTICE, "'%s' by %s on %s", argvbuf, currentuser, ttyname(2));
45422347Spst#if HAVE_SULOG
45522347Spst  sulog(1, NULL);
45622347Spst#endif /* HAVE_SULOG */
45722347Spst
45822347Spst  if (setgid(thisuser.pw_gid) < 0) {
45922347Spst    perror("su: setgid");
46022347Spst    exit(3);
46122347Spst  }
46222347Spst  if (initgroups(user, thisuser.pw_gid)) {
46322347Spst    fprintf(stderr, "su: initgroups failed (errno=%d)\n", errno);
46422347Spst    exit(4);
46522347Spst  }
46622347Spst  if (setuid(thisuser.pw_uid) < 0) {
46722347Spst    perror("su: setuid");
46822347Spst    exit(5);
46922347Spst  }
47022347Spst  if (thisuser.pw_shell && *thisuser.pw_shell)
47122347Spst    shell = thisuser.pw_shell;
47222347Spst  if (fulllogin) {
47359118Skris    if ((p = getenv("TERM")) && (strlen(termbuf) + strlen(p) - 1 < sizeof(termbuf))) {
47459118Skris      strcat(termbuf, p);
47522347Spst      cleanenv[4] = termbuf;
47622347Spst    }
47722347Spst    environ = cleanenv;
47822347Spst  }
47922347Spst  if (fulllogin || strcmp(user, "root") != 0)
48022347Spst    lsetenv("USER", thisuser.pw_name, userbuf);
48122347Spst  lsetenv("SHELL", shell, shellbuf);
48222347Spst  lsetenv("HOME", thisuser.pw_dir, homebuf);
48322347Spst
48422347Spst#if HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H
48522347Spst  setpriority(PRIO_PROCESS, 0, 0);
48622347Spst#endif /* HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H */
48722347Spst
48829964Sache#if 0
48922347Spst  if (fastlogin) {
49022347Spst    *argv-- = "-f";
49122347Spst    *argv = "su";
49222347Spst  } else
49329964Sache#endif /* 0 */
49422347Spst    if (fulllogin) {
49522347Spst      if (chdir(thisuser.pw_dir) < 0) {
49622347Spst	fprintf(stderr, "No directory\n");
49722347Spst	exit(6);
49822347Spst      }
49922347Spst      *argv = "-su";
50022347Spst    } else {
50122347Spst      *argv = "su";
50222347Spst    }
50322347Spst
50422347Spst  catchexit();
50522347Spst
50622347Spst#if DEBUG
50722347Spst  syslog(LOG_DEBUG, "execing %s", shell);
50822347Spst#endif /* DEBUG */
50922347Spst  execv(shell, argv);
51022347Spst  fprintf(stderr, "No shell\n");
51122347Spst  exit(7);
51222347Spst}
513