version 1.7, 1996/10/12 17:13:57 |
version 1.8, 1996/10/12 20:40:37 |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/time.h> |
#include <sys/time.h> |
#include <sys/resource.h> |
#include <sys/resource.h> |
#include <syslog.h> |
|
|
#include <err.h> |
|
#include <errno.h> |
|
#include <grp.h> |
|
#include <paths.h> |
|
#include <pwd.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <pwd.h> |
|
#include <grp.h> |
|
#include <string.h> |
#include <string.h> |
|
#include <syslog.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <paths.h> |
|
|
|
|
#ifdef SKEY |
|
#include <skey.h> |
|
#endif |
|
|
#ifdef KERBEROS |
#ifdef KERBEROS |
#include <kerberosIV/des.h> |
#include <kerberosIV/des.h> |
#include <kerberosIV/krb.h> |
#include <kerberosIV/krb.h> |
|
|
#define ARGSTR "-flm" |
#define ARGSTR "-flm" |
#endif |
#endif |
|
|
extern char *crypt(); |
char *ontty __P((void)); |
int chshell(); |
int chshell __P((char *)); |
|
|
int |
int |
main(argc, argv) |
main(argc, argv) |
|
|
char **argv; |
char **argv; |
{ |
{ |
extern char **environ; |
extern char **environ; |
extern int errno, optind; |
|
register struct passwd *pwd; |
register struct passwd *pwd; |
register char *p, **g; |
register char *p, **g; |
struct group *gr; |
struct group *gr; |
|
|
enum { UNSET, YES, NO } iscsh = UNSET; |
enum { UNSET, YES, NO } iscsh = UNSET; |
char *user, *shell, *avshell, *username, *cleanenv[10], **np; |
char *user, *shell, *avshell, *username, *cleanenv[10], **np; |
char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN]; |
char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN]; |
char *getpass(), *getenv(), *getlogin(), *ontty(); |
|
|
|
asme = asthem = fastlogin = 0; |
asme = asthem = fastlogin = 0; |
while ((ch = getopt(argc, argv, ARGSTR)) != EOF) |
while ((ch = getopt(argc, argv, ARGSTR)) != EOF) |
|
|
if (username == NULL || (pwd = getpwnam(username)) == NULL || |
if (username == NULL || (pwd = getpwnam(username)) == NULL || |
pwd->pw_uid != ruid) |
pwd->pw_uid != ruid) |
pwd = getpwuid(ruid); |
pwd = getpwuid(ruid); |
if (pwd == NULL) { |
if (pwd == NULL) |
fprintf(stderr, "su: who are you?\n"); |
errx(1, "who are you?"); |
exit(1); |
|
} |
|
username = strdup(pwd->pw_name); |
username = strdup(pwd->pw_name); |
if (asme) |
if (asme) |
if (pwd->pw_shell && *pwd->pw_shell) |
if (pwd->pw_shell && *pwd->pw_shell) |
|
|
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) |
fprintf(stderr, "su: unknown login %s\n", user); |
errx(1, "unknown login %s", user); |
exit(1); |
|
} |
|
|
|
if (ruid) { |
if (ruid) { |
#ifdef KERBEROS |
#ifdef KERBEROS |
|
|
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) { |
if (!*g) { |
if (!*g) |
(void)fprintf(stderr, |
errx(1, "you are not in the correct group to su %s.", user); |
"su: you are not in the correct group to su %s.\n", |
if (strcmp(username, *g) == 0) |
user); |
|
exit(1); |
|
} |
|
if (!strcmp(username, *g)) |
|
break; |
break; |
} |
} |
/* if target requires a password, verify it */ |
/* if target requires a password, verify it */ |
|
|
p = getpass("Password:"); |
p = getpass("Password:"); |
#ifdef SKEY |
#ifdef SKEY |
if (strcasecmp(p, "s/key") == 0) { |
if (strcasecmp(p, "s/key") == 0) { |
if (skey_haskey(user)) { |
if (skey_haskey(user)) |
fprintf(stderr, "Sorry, you have no s/key.\n"); |
errx(1, "Sorry, you have no s/key."); |
exit(1); |
else if (skey_authenticate(user)) |
} else { |
goto badlogin; |
if (skey_authenticate(user)) { |
|
goto badlogin; |
|
} |
|
} |
|
|
|
} else |
} else |
#endif |
#endif |
if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { |
if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { |
|
|
} |
} |
} |
} |
} |
} |
|
if (pwd->pw_expire && time(NULL) >= pwd->pw_expire) { |
|
fprintf(stderr, "Sorry - account expired\n"); |
|
syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username, |
|
user, ontty()); |
|
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) |
(void)fprintf(stderr, |
errx(1, "permission denied (shell)."); |
"su: permission denied (shell).\n"); |
|
exit(1); |
|
} |
|
} 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; |
|
|
iscsh = NO; |
iscsh = NO; |
} |
} |
|
|
if (p = rindex(shell, '/')) |
if (p = strrchr(shell, '/')) |
avshell = p+1; |
avshell = p+1; |
else |
else |
avshell = shell; |
avshell = shell; |
|
|
iscsh = strcmp(avshell, "csh") ? NO : YES; |
iscsh = strcmp(avshell, "csh") ? NO : YES; |
|
|
/* set permissions */ |
/* set permissions */ |
if (setgid(pwd->pw_gid) < 0) { |
if (setgid(pwd->pw_gid) < 0) |
perror("su: setgid"); |
err(1, "setgid"); |
exit(1); |
if (initgroups(user, pwd->pw_gid)) |
} |
err(1, "initgroups failed"); |
if (initgroups(user, pwd->pw_gid)) { |
if (setuid(pwd->pw_uid) < 0) |
(void)fprintf(stderr, "su: initgroups failed.\n"); |
err(1, "setuid"); |
exit(1); |
|
} |
|
if (setuid(pwd->pw_uid) < 0) { |
|
perror("su: setuid"); |
|
exit(1); |
|
} |
|
|
|
if (!asme) { |
if (!asme) { |
if (asthem) { |
if (asthem) { |
|
|
|
|
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) |
fprintf(stderr, "su: no directory\n"); |
errx(1, "no directory"); |
exit(1); |
|
} |
|
seteuid(0); |
seteuid(0); |
setegid(0); /* XXX use a saved gid instead? */ |
setegid(0); /* XXX use a saved gid instead? */ |
} |
} |
|
|
(void)setpriority(PRIO_PROCESS, 0, prio); |
(void)setpriority(PRIO_PROCESS, 0, prio); |
|
|
execv(shell, np); |
execv(shell, np); |
(void)fprintf(stderr, "su: %s not found.\n", shell); |
err(1, "%s", shell); |
exit(1); |
|
} |
} |
|
|
int |
int |
|
|
char *sh; |
char *sh; |
{ |
{ |
register char *cp; |
register char *cp; |
char *getusershell(); |
|
|
|
while ((cp = getusershell()) != NULL) |
while ((cp = getusershell()) != NULL) |
if (!strcmp(cp, sh)) |
if (strcmp(cp, sh) == 0) |
return (1); |
return (1); |
return (0); |
return (0); |
} |
} |
|
|
|
|
buf[0] = 0; |
buf[0] = 0; |
if (p = ttyname(STDERR_FILENO)) |
if (p = ttyname(STDERR_FILENO)) |
sprintf(buf, " on %s", p); |
snprintf(buf, sizeof(buf), " on %s", p); |
return (buf); |
return (buf); |
} |
} |
|
|
|
|
(void)fprintf(stderr, "kerberos su: not in %s's ACL.\n", user); |
(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)snprintf(krbtkfile, sizeof(krbtkfile), "%s_%s_%d", TKT_ROOT, |
|
user, getuid()); |
|
|
(void)setenv("KRBTKFILE", krbtkfile, 1); |
(void)setenv("KRBTKFILE", krbtkfile, 1); |
(void)krb_set_tkt_string(krbtkfile); |
(void)krb_set_tkt_string(krbtkfile); |
|
|
* to make the kerberos library do the right thing. |
* to make the kerberos library do the right thing. |
*/ |
*/ |
if (setuid(0) < 0) { |
if (setuid(0) < 0) { |
perror("su: setuid"); |
warn("setuid"); |
return (1); |
return (1); |
} |
} |
|
|
|
|
|
|
if (kerno != KSUCCESS) { |
if (kerno != KSUCCESS) { |
if (kerno == KDC_PR_UNKNOWN) { |
if (kerno == KDC_PR_UNKNOWN) { |
fprintf(stderr, "principal unknown: %s.%s@%s\n", |
warnx("kerberos principal unknown: %s.%s@%s", |
(uid == 0 ? username : user), |
(uid == 0 ? username : user), |
(uid == 0 ? "root" : ""), lrealm); |
(uid == 0 ? "root" : ""), lrealm); |
return (1); |
return (1); |
} |
} |
(void)fprintf(stderr, "su: unable to su: %s\n", |
warnx("unable to su: %s", krb_err_txt[kerno]); |
krb_err_txt[kerno]); |
|
syslog(LOG_NOTICE|LOG_AUTH, |
syslog(LOG_NOTICE|LOG_AUTH, |
"BAD Kerberos SU: %s to %s%s: %s", |
"BAD Kerberos SU: %s to %s%s: %s", |
username, user, ontty(), krb_err_txt[kerno]); |
username, user, ontty(), krb_err_txt[kerno]); |
|
|
} |
} |
|
|
if (chown(krbtkfile, uid, -1) < 0) { |
if (chown(krbtkfile, uid, -1) < 0) { |
perror("su: chown:"); |
warn("chown"); |
(void)unlink(krbtkfile); |
(void)unlink(krbtkfile); |
return (1); |
return (1); |
} |
} |
|
|
(void)setpriority(PRIO_PROCESS, 0, -2); |
(void)setpriority(PRIO_PROCESS, 0, -2); |
|
|
if (gethostname(hostname, sizeof(hostname)) == -1) { |
if (gethostname(hostname, sizeof(hostname)) == -1) { |
perror("su: gethostname"); |
warn("gethostname"); |
dest_tkt(); |
dest_tkt(); |
return (1); |
return (1); |
} |
} |
|
|
kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); |
kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); |
|
|
if (kerno == KDC_PR_UNKNOWN) { |
if (kerno == KDC_PR_UNKNOWN) { |
(void)fprintf(stderr, "Warning: TGT not verified.\n"); |
warnx("Warning: TGT not verified."); |
syslog(LOG_NOTICE|LOG_AUTH, |
syslog(LOG_NOTICE|LOG_AUTH, |
"%s to %s%s, TGT not verified (%s); %s.%s not registered?", |
"%s to %s%s, TGT not verified (%s); %s.%s not registered?", |
username, user, ontty(), krb_err_txt[kerno], |
username, user, ontty(), krb_err_txt[kerno], |
"rcmd", savehost); |
"rcmd", savehost); |
} else if (kerno != KSUCCESS) { |
} else if (kerno != KSUCCESS) { |
(void)fprintf(stderr, "Unable to use TGT: %s\n", |
warnx("Unable to use TGT: %s", krb_err_txt[kerno]); |
krb_err_txt[kerno]); |
|
syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s", |
syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s", |
username, user, ontty(), krb_err_txt[kerno]); |
username, user, ontty(), krb_err_txt[kerno]); |
dest_tkt(); |
dest_tkt(); |
return (1); |
return (1); |
} else { |
} else { |
if (!(hp = gethostbyname(hostname))) { |
if (!(hp = gethostbyname(hostname))) { |
(void)fprintf(stderr, "su: can't get addr of %s\n", |
warnx("can't get addr of %s", hostname); |
hostname); |
|
dest_tkt(); |
dest_tkt(); |
return (1); |
return (1); |
} |
} |
|
|
|
|
if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr, |
if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr, |
&authdata, "")) != KSUCCESS) { |
&authdata, "")) != KSUCCESS) { |
(void)fprintf(stderr, |
warnx("unable to verify rcmd ticket: %s", |
"su: unable to verify rcmd ticket: %s\n", |
krb_err_txt[kerno]); |
krb_err_txt[kerno]); |
|
syslog(LOG_NOTICE|LOG_AUTH, |
syslog(LOG_NOTICE|LOG_AUTH, |
"failed su: %s to %s%s: %s", username, |
"failed su: %s to %s%s: %s", username, |
user, ontty(), krb_err_txt[kerno]); |
user, ontty(), krb_err_txt[kerno]); |