* Copyright (c) 1988 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not 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.
"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)su.c 5.16 (Berkeley) %G%";
#include <sys/resource.h>
extern int errno
, optind
;
register struct passwd
*pwd
;
int asme
, ch
, fulllogin
, fastlogin
, prio
;
enum { UNSET
, YES
, NO
} iscsh
= UNSET
;
char *user
, *shell
, *username
, *cleanenv
[2], *nargv
[4], **np
;
char shellbuf
[MAXPATHLEN
];
char *crypt(), *getpass(), *getenv(), *getlogin(), *mytty();
asme
= fulllogin
= fastlogin
= 0;
while ((ch
= getopt(argc
, argv
, ARGSTR
)) != EOF
)
(void)fprintf(stderr
, "usage: su [%s] [login]\n",
prio
= getpriority(PRIO_PROCESS
, 0);
(void)setpriority(PRIO_PROCESS
, 0, -2);
/* get current login name and shell */
if ((pwd
= getpwuid(ruid
= getuid())) == NULL
) {
fprintf(stderr
, "su: who are you?\n");
username
= strdup(pwd
->pw_name
);
if (pwd
->pw_shell
&& *pwd
->pw_shell
)
shell
= strcpy(shellbuf
, pwd
->pw_shell
);
/* get target login information, default to root */
user
= *argv
? *argv
: "root";
if ((pwd
= getpwnam(user
)) == NULL
) {
fprintf(stderr
, "su: unknown login %s\n", user
);
/* 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
) {
"su: you are not in the correct group to su %s.\n", user
);
if (!strcmp(username
, *g
))
openlog("su", LOG_CONS
, 0);
if (!use_kerberos
|| kerberos(username
, user
, pwd
->pw_uid
))
/* if target requires a password, verify it */
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", username
,
/* if asme and non-standard target shell, must be root */
if (!chshell(pwd
->pw_shell
) && ruid
) {
(void)fprintf(stderr
, "su: permission denied.\n");
} else if (pwd
->pw_shell
&& *pwd
->pw_shell
) {
/* if we're forking a csh, we want to slightly muck the args */
if (p
= rindex(shell
, '/'))
iscsh
= strcmp(p
, "csh") ? NO
: YES
;
if (setgid(pwd
->pw_gid
) < 0) {
if (initgroups(user
, pwd
->pw_gid
)) {
(void)fprintf(stderr
, "su: initgroups failed.\n");
if (setuid(pwd
->pw_uid
) < 0) {
cleanenv
[0] = _PATH_SEARCHPATH
;
(void)setenv("TERM", p
, 1);
if (chdir(pwd
->pw_dir
) < 0) {
fprintf(stderr
, "su: no directory\n");
if (fulllogin
|| pwd
->pw_uid
)
(void)setenv("USER", pwd
->pw_name
, 1);
(void)setenv("HOME", pwd
->pw_dir
, 1);
(void)setenv("SHELL", shell
, 1);
/* csh strips the first character... */
*np
= fulllogin
? "-su" : iscsh
== YES
? "_su" : "su";
syslog(LOG_NOTICE
|LOG_AUTH
, "%s on %s", username
, mytty());
(void)setpriority(PRIO_PROCESS
, 0, prio
);
(void)fprintf(stderr
, "su: %s not found.\n", shell
);
while ((cp
= getusershell()) != NULL
)
return((p
= ttyname(STDERR_FILENO
)) ? p
: "UNKNOWN TTY");
kerberos(username
, user
, uid
)
extern char *krb_err_txt
[];
char lrealm
[REALM_SZ
], krbtkfile
[MAXPATHLEN
], pw_buf
[_PASSWORD_LEN
];
char hostname
[MAXHOSTNAMELEN
], savehost
[MAXHOSTNAMELEN
];
if (krb_get_lrealm(lrealm
, 1) != KSUCCESS
) {
(void)fprintf(stderr
, "su: couldn't get local realm.\n");
if (koktologin(username
, lrealm
, user
) && !uid
) {
(void)fprintf(stderr
, "kerberos su: not in %s's ACL.\n", user
);
(void)sprintf(krbtkfile
, "%s_%s_%d", TKT_ROOT
, user
, getuid());
if (read_pw_string(pw_buf
, sizeof(pw_buf
) - 1,
"Kerberos password: ", 0)) {
(void)fprintf(stderr
, "su: error reading password.\n");
(void)setenv("KRBTKFILE", krbtkfile
, 1);
/* short lifetime for root tickets */
/* POLICY: short ticket lifetime for root */
kerno
= krb_get_pw_in_tkt(username
, (uid
== 0 ? "root" : ""), lrealm
,
"krbtgt", lrealm
, (uid
== 0 ? 2 : DEFAULT_TKT_LIFE
), pw_buf
);
bzero(pw_buf
, sizeof(pw_buf
));
if (kerno
== KDC_PR_UNKNOWN
)
(void)printf("su: unable to su: %s\n", krb_err_txt
[kerno
]);
syslog(LOG_NOTICE
|LOG_AUTH
,
"su: BAD Kerberos SU: %s on %s: %s", username
, mytty(),
if (chown(krbtkfile
, uid
, -1) < 0) {
(void)setpriority(PRIO_PROCESS
, 0, -2);
if (gethostname(hostname
, sizeof(hostname
)) == -1) {
(void)strncpy(savehost
, krb_get_phost(hostname
), sizeof(savehost
));
savehost
[sizeof(savehost
) - 1] = '\0';
kerno
= krb_mk_req(&ticket
, "rcmd", savehost
, lrealm
, 33);
if (kerno
== KDC_PR_UNKNOWN
) {
(void)printf("Warning: tgt not verified.\n");
syslog(LOG_NOTICE
|LOG_AUTH
, "su: %s on %s, tgt not verified",
} 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: %s",
username
, mytty(), krb_err_txt
[kerno
]);
if (!(hp
= gethostbyname(hostname
))) {
(void)printf("su: can't get addr of %s\n", hostname
);
(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",
syslog(LOG_NOTICE
|LOG_AUTH
,
"su: failed su: %s on %s: %s", username
,
mytty(), krb_err_txt
[kerno
]);
koktologin(name
, realm
, toname
)
char *name
, *realm
, *toname
;
register AUTH_DAT
*kdata
;
bzero((caddr_t
) kdata
, sizeof(*kdata
));
(void)strcpy(kdata
->pname
, name
);
(void)strcpy(kdata
->pinst
,
((strcmp(toname
, "root") == 0) ? "root" : ""));
(void)strcpy(kdata
->prealm
, realm
);
return(kuserok(kdata
, toname
));