Run most of the code as root, not the invoking user. It doesn't really
gain us anything to run as the user since an attacker can just have an setuid(0) in their egg. Running as root solves potential problems wrt signalling.
This commit is contained in:
18
auth/API
18
auth/API
@@ -31,8 +31,8 @@ The variables in the struct are as follows:
|
||||
initialized in the "init" or "setup" routines.
|
||||
|
||||
Possible values of sudo_auth.flags:
|
||||
FLAG_ROOT Whether or not the auth functions should run with
|
||||
an euid of 0 or the uid of the invoking user.
|
||||
FLAG_USER Whether or not the auth functions should run with
|
||||
the euid of the invoking user instead of 0.
|
||||
|
||||
FLAG_CONFIGURED If set then the auth method is assumed to have been
|
||||
configured successfully. All auth methods start out
|
||||
@@ -102,23 +102,23 @@ in sudo_auth.h. For instance, for a method, ``fooauth'', add:
|
||||
|
||||
#elif defined(HAVE_FOOAUTH)
|
||||
# define AUTH_STANDALONE \
|
||||
AUTH_ENTRY(FLAG_ROOT, "foo", \
|
||||
AUTH_ENTRY(0, "foo", \
|
||||
foo_init, foo_setup, foo_verify, foo_cleanup)
|
||||
|
||||
If the method doesn't need to run as root, replace FLAG_ROOT with 0.
|
||||
If you don't have a init/setup/cleanup routine, just use a NULL for that
|
||||
field.
|
||||
If the method needs to run as the user, not root, replace the first
|
||||
parameter to AUTH_ENTRY (0) with FLAG_USER. If you don't have a
|
||||
init/setup/cleanup routine, just use a NULL for that field.
|
||||
|
||||
For a normal authentication method, add it to the ``auth_switch'' in
|
||||
sudo_auth.c. If ``fooauth'' is a normal auth method, its entry
|
||||
would look like:
|
||||
|
||||
# ifdef HAVE_FOOAUTH
|
||||
AUTH_ENTRY(FLAG_ROOT, "foo", foo_init, foo_setup, foo_verify, foo_cleanup)
|
||||
AUTH_ENTRY(0, "foo", foo_init, foo_setup, foo_verify, foo_cleanup)
|
||||
# endif
|
||||
|
||||
Again, if the method doesn't need to run as root, replace FLAG_ROOT
|
||||
with 0. Likewise, if you don't have a init/setup/cleanup routine,
|
||||
Again, if the method doesn't need to run as root, replace the 0 with
|
||||
FLAG_USER. Likewise, if you don't have a init/setup/cleanup routine,
|
||||
just use a NULL for that field.
|
||||
|
||||
NOTE: You should not make a method both ``standalone'' and
|
||||
|
@@ -65,25 +65,25 @@ sudo_auth auth_switch[] = {
|
||||
AUTH_STANDALONE
|
||||
#else
|
||||
# ifndef WITHOUT_PASSWD
|
||||
AUTH_ENTRY(FLAG_ROOT, "passwd", NULL, NULL, passwd_verify, NULL)
|
||||
AUTH_ENTRY(0, "passwd", NULL, NULL, passwd_verify, NULL)
|
||||
# endif
|
||||
# if defined(HAVE_SECUREWARE) && !defined(WITHOUT_PASSWD)
|
||||
AUTH_ENTRY(FLAG_ROOT, "secureware", secureware_init, NULL, secureware_verify, NULL)
|
||||
AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, NULL)
|
||||
# endif
|
||||
# ifdef HAVE_AFS
|
||||
AUTH_ENTRY(FLAG_ROOT, "afs", NULL, NULL, afs_verify, NULL)
|
||||
AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL)
|
||||
# endif
|
||||
# ifdef HAVE_KERB4
|
||||
AUTH_ENTRY(FLAG_ROOT, "kerb4", kerb4_init, NULL, kerb4_verify, NULL)
|
||||
AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL)
|
||||
# endif
|
||||
# ifdef HAVE_KERB5
|
||||
AUTH_ENTRY(FLAG_ROOT, "kerb5", kerb5_init, NULL, kerb5_verify, NULL)
|
||||
AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, NULL)
|
||||
# endif
|
||||
# ifdef HAVE_SKEY
|
||||
AUTH_ENTRY(FLAG_ROOT, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL)
|
||||
AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL)
|
||||
# endif
|
||||
# ifdef HAVE_OPIE
|
||||
AUTH_ENTRY(FLAG_ROOT, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL)
|
||||
AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL)
|
||||
# endif
|
||||
#endif /* AUTH_STANDALONE */
|
||||
AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL)
|
||||
@@ -107,8 +107,8 @@ verify_user()
|
||||
/* Initialize auth methods and unconfigure the method if necessary. */
|
||||
for (auth = auth_switch; auth->name; auth++) {
|
||||
if (auth->init && IS_CONFIGURED(auth)) {
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
|
||||
status = (auth->init)(sudo_user.pw, &user_prompt, auth);
|
||||
if (status == AUTH_FAILURE)
|
||||
@@ -116,8 +116,8 @@ verify_user()
|
||||
else if (status == AUTH_FATAL) /* XXX log */
|
||||
exit(1); /* assume error msg already printed */
|
||||
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ verify_user()
|
||||
/* Do any per-method setup and unconfigure the method if needed */
|
||||
for (auth = auth_switch; auth->name; auth++) {
|
||||
if (auth->setup && IS_CONFIGURED(auth)) {
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
|
||||
status = (auth->setup)(sudo_user.pw, &user_prompt, auth);
|
||||
if (status == AUTH_FAILURE)
|
||||
@@ -134,8 +134,8 @@ verify_user()
|
||||
else if (status == AUTH_FATAL) /* XXX log */
|
||||
exit(1); /* assume error msg already printed */
|
||||
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,14 +154,14 @@ verify_user()
|
||||
if (!IS_CONFIGURED(auth))
|
||||
continue;
|
||||
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
|
||||
success = auth->status = (auth->verify)(sudo_user.pw, p, auth);
|
||||
(void) memset(p, 0, strlen(p));
|
||||
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
|
||||
if (auth->status != AUTH_FAILURE)
|
||||
goto cleanup;
|
||||
@@ -182,15 +182,15 @@ cleanup:
|
||||
/* Call cleanup routines. */
|
||||
for (auth = auth_switch; auth->name; auth++) {
|
||||
if (auth->cleanup && IS_CONFIGURED(auth)) {
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
|
||||
status = (auth->cleanup)(sudo_user.pw, auth);
|
||||
if (status == AUTH_FATAL) /* XXX log */
|
||||
exit(1); /* assume error msg already printed */
|
||||
|
||||
if (NEEDS_ROOT(auth))
|
||||
set_perms(PERM_USER, 0);
|
||||
if (NEEDS_USER(auth))
|
||||
set_perms(PERM_ROOT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -55,12 +55,12 @@ typedef struct sudo_auth {
|
||||
|
||||
/* Values for sudo_auth.flags. */
|
||||
/* XXX - these names are too long for my liking */
|
||||
#define FLAG_ROOT 0x01 /* functions must run as root */
|
||||
#define FLAG_USER 0x01 /* functions must run as root */
|
||||
#define FLAG_CONFIGURED 0x02 /* method configured ok */
|
||||
#define FLAG_ONEANDONLY 0x04 /* one and only auth method */
|
||||
|
||||
/* Shortcuts for using the flags above. */
|
||||
#define NEEDS_ROOT(x) ((x)->flags & FLAG_ROOT)
|
||||
#define NEEDS_USER(x) ((x)->flags & FLAG_USER)
|
||||
#define IS_CONFIGURED(x) ((x)->flags & FLAG_CONFIGURED)
|
||||
#define IS_ONEANDONLY(x) ((x)->flags & FLAG_ONEANDONLY)
|
||||
|
||||
@@ -99,27 +99,27 @@ int securid_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
|
||||
/* Some methods cannots (or should not) interoperate with any others */
|
||||
#if defined(HAVE_PAM)
|
||||
# define AUTH_STANDALONE \
|
||||
AUTH_ENTRY(FLAG_ROOT, "pam", \
|
||||
AUTH_ENTRY(0, "pam", \
|
||||
pam_init, NULL, pam_verify, pam_cleanup)
|
||||
#elif defined(HAVE_SECURID)
|
||||
# define AUTH_STANDALONE \
|
||||
AUTH_ENTRY(FLAG_ROOT, "SecurId", \
|
||||
AUTH_ENTRY(0, "SecurId",
|
||||
securid_init, securid_setup, securid_verify, NULL)
|
||||
#elif defined(HAVE_SIA)
|
||||
# define AUTH_STANDALONE \
|
||||
AUTH_ENTRY(FLAG_ROOT, "sia", \
|
||||
AUTH_ENTRY(0, "sia", \
|
||||
NULL, sia_setup, sia_verify, sia_cleanup)
|
||||
#elif defined(HAVE_DCE)
|
||||
# define AUTH_STANDALONE \
|
||||
AUTH_ENTRY(FLAG_ROOT, "dce", \
|
||||
AUTH_ENTRY(0, "dce", \
|
||||
NULL, NULL, dce_verify, NULL)
|
||||
#elif defined(HAVE_AUTHENTICATE)
|
||||
# define AUTH_STANDALONE \
|
||||
AUTH_ENTRY(FLAG_ROOT, "aixauth", \
|
||||
AUTH_ENTRY(0, "aixauth", \
|
||||
NULL, NULL, aixauth_verify, NULL)
|
||||
#elif defined(HAVE_FWTK)
|
||||
# define AUTH_STANDALONE \
|
||||
AUTH_ENTRY(FLAG_ROOT, "fwtk", fwtk_init, \
|
||||
AUTH_ENTRY(0, "fwtk", fwtk_init, \
|
||||
NULL, fwtk_verify, fwtk_cleanup)
|
||||
#endif
|
||||
|
||||
|
13
check.c
13
check.c
@@ -137,8 +137,6 @@ update_timestamp(timestampdir, timestampfile)
|
||||
char *timestampfile;
|
||||
{
|
||||
|
||||
set_perms(PERM_ROOT, 0); /* become root */
|
||||
|
||||
if (touch(timestampfile ? timestampfile : timestampdir, time(NULL)) == -1) {
|
||||
if (timestampfile) {
|
||||
int fd = open(timestampfile, O_WRONLY|O_CREAT|O_TRUNC, 0600);
|
||||
@@ -152,8 +150,6 @@ update_timestamp(timestampdir, timestampfile)
|
||||
log_error(NO_EXIT|USE_ERRNO, "Can't mkdir %s", timestampdir);
|
||||
}
|
||||
}
|
||||
|
||||
set_perms(PERM_USER, 0); /* relinquish root */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -288,8 +284,6 @@ timestamp_status(timestampdir, timestampfile, user, make_dirs)
|
||||
time_t now;
|
||||
int status = TS_ERROR; /* assume the worst */
|
||||
|
||||
set_perms(PERM_ROOT, 0); /* become root */
|
||||
|
||||
/*
|
||||
* Sanity check _PATH_SUDO_TIMEDIR and make it if it doesn't already exist.
|
||||
* We start out assuming the worst (that the dir is not sane) and
|
||||
@@ -325,10 +319,8 @@ timestamp_status(timestampdir, timestampfile, user, make_dirs)
|
||||
status = TS_MISSING;
|
||||
}
|
||||
}
|
||||
if (status == TS_ERROR) {
|
||||
set_perms(PERM_USER, 0); /* relinquish root */
|
||||
if (status == TS_ERROR)
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check the user's ticket dir. We start by downgrading
|
||||
@@ -435,7 +427,6 @@ timestamp_status(timestampdir, timestampfile, user, make_dirs)
|
||||
}
|
||||
}
|
||||
|
||||
set_perms(PERM_USER, 0); /* relinquish root */
|
||||
return(status);
|
||||
}
|
||||
|
||||
@@ -455,7 +446,6 @@ remove_timestamp(remove)
|
||||
status = timestamp_status(timestampdir, timestampfile, user_name, FALSE);
|
||||
if (status == TS_OLD || status == TS_CURRENT) {
|
||||
ts = timestampfile ? timestampfile : timestampdir;
|
||||
set_perms(PERM_ROOT, 0); /* become root */
|
||||
if (remove) {
|
||||
if (timestampfile)
|
||||
status = unlink(timestampfile);
|
||||
@@ -471,7 +461,6 @@ remove_timestamp(remove)
|
||||
(void) fprintf(stderr, "%s: can't reset %s to epoch: %s\n",
|
||||
Argv[0], ts, strerror(errno));
|
||||
}
|
||||
set_perms(PERM_USER, 0); /* relinquish root */
|
||||
}
|
||||
|
||||
(void) free(timestampdir);
|
||||
|
@@ -112,7 +112,6 @@ find_path(infile, outfile)
|
||||
path = estrdup(path);
|
||||
origpath = path;
|
||||
|
||||
/* XXX use strtok() */
|
||||
do {
|
||||
if ((n = strchr(path, ':')))
|
||||
*n = '\0';
|
||||
|
@@ -67,19 +67,12 @@ sudo_goodpath(path)
|
||||
const char *path;
|
||||
{
|
||||
struct stat sb;
|
||||
int err;
|
||||
|
||||
/* Check for brain damage */
|
||||
if (path == NULL || path[0] == '\0')
|
||||
return(NULL);
|
||||
|
||||
/* Do the stat() as root. */
|
||||
set_perms(PERM_ROOT, 0);
|
||||
err = stat(path, &sb);
|
||||
set_perms(PERM_USER, 0);
|
||||
|
||||
/* stat() failed */
|
||||
if (err)
|
||||
if (stat(path, &sb))
|
||||
return(NULL);
|
||||
|
||||
/* Make sure path describes an executable regular file. */
|
||||
|
24
logging.c
24
logging.c
@@ -161,15 +161,10 @@ do_logfile(msg)
|
||||
FILE *fp;
|
||||
mode_t oldmask;
|
||||
time_t now;
|
||||
int oldeuid = geteuid();
|
||||
int maxlen = MAXLOGFILELEN;
|
||||
|
||||
now = time((time_t) 0);
|
||||
|
||||
/* Become root if we are not already. */
|
||||
if (oldeuid)
|
||||
set_perms(PERM_ROOT, 0);
|
||||
|
||||
oldmask = umask(077);
|
||||
fp = fopen(_PATH_SUDO_LOGFILE, "a");
|
||||
(void) umask(oldmask);
|
||||
@@ -254,9 +249,6 @@ do_logfile(msg)
|
||||
(void) lock_file(fileno(fp), SUDO_UNLOCK);
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
if (oldeuid)
|
||||
set_perms(PERM_USER, 0); /* relinquish root */
|
||||
}
|
||||
#endif /* LOGGING & SLOG_FILE */
|
||||
|
||||
@@ -299,20 +291,18 @@ log_auth(status, inform_user)
|
||||
mail_auth(status, logline); /* send mail based on status */
|
||||
|
||||
/* Inform the user if they failed to authenticate. */
|
||||
if (inform_user) {
|
||||
if (inform_user && (status & VALIDATE_NOT_OK)) {
|
||||
if (status & FLAG_NO_USER)
|
||||
(void) fprintf(stderr, "%s is not in the sudoers file. %s",
|
||||
user_name, "This incident will be reported.\n");
|
||||
else if (status & FLAG_NO_HOST)
|
||||
(void) fprintf(stderr, "%s is not allowed to run sudo on %s. %s",
|
||||
user_name, user_shost, "This incident will be reported.\n");
|
||||
else if (status & VALIDATE_NOT_OK)
|
||||
else
|
||||
(void) fprintf(stderr,
|
||||
"Sorry, user %s is not allowed to execute '%s%s%s' as %s on %s.\n",
|
||||
user_name, user_cmnd, user_args ? " " : "",
|
||||
user_args ? user_args : "", user_runas, user_host);
|
||||
else
|
||||
(void) fprintf(stderr, "An unknown error has occurred.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -351,6 +341,10 @@ log_error(va_alist)
|
||||
fmt = va_arg(ap, const char *);
|
||||
#endif
|
||||
|
||||
/* Become root if we are not already to avoid user control */
|
||||
if (geteuid() != 0)
|
||||
set_perms(PERM_ROOT, 0);
|
||||
|
||||
/* Expand printf-style format + args. */
|
||||
evasprintf(&message, fmt, ap);
|
||||
va_end(ap);
|
||||
@@ -409,6 +403,9 @@ log_error(va_alist)
|
||||
free(message);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to ALERTMAIL
|
||||
*/
|
||||
#ifdef _PATH_SENDMAIL
|
||||
static void
|
||||
send_mail(line)
|
||||
@@ -481,7 +478,7 @@ send_mail(line)
|
||||
user_name, line);
|
||||
fclose(mail);
|
||||
reapchild(0);
|
||||
exit(0);
|
||||
_exit(0);
|
||||
} else {
|
||||
/* Parent, just return unless there is an error. */
|
||||
if (pid == -1) {
|
||||
@@ -510,6 +507,7 @@ mail_auth(status, line)
|
||||
{
|
||||
int mail_mask;
|
||||
|
||||
/* If any of these bits are set in status, we send mail. */
|
||||
mail_mask = VALIDATE_ERROR;
|
||||
#ifdef SEND_MAIL_WHEN_OK
|
||||
mail_mask |= VALIDATE_OK;
|
||||
|
22
parse.c
22
parse.c
@@ -124,26 +124,17 @@ sudoers_lookup(check_cmnd)
|
||||
yyin = sudoers_fp;
|
||||
yyout = stdout;
|
||||
|
||||
/*
|
||||
* Allocate space for data structures in the parser.
|
||||
*/
|
||||
/* Allocate space for data structures in the parser. */
|
||||
init_parser();
|
||||
|
||||
/*
|
||||
* Need to be root while stat'ing things in the parser.
|
||||
*/
|
||||
/* Need to be root while stat'ing things in the parser. */
|
||||
set_perms(PERM_ROOT, 0);
|
||||
error = yyparse();
|
||||
|
||||
/*
|
||||
* Don't need to keep this open...
|
||||
*/
|
||||
/* Close the sudoers file now that we are done with it. */
|
||||
(void) fclose(sudoers_fp);
|
||||
sudoers_fp = NULL;
|
||||
|
||||
/* relinquish extra privs */
|
||||
set_perms(PERM_USER, 0);
|
||||
|
||||
if (error || parse_error)
|
||||
return(VALIDATE_ERROR);
|
||||
|
||||
@@ -159,10 +150,9 @@ sudoers_lookup(check_cmnd)
|
||||
}
|
||||
|
||||
/*
|
||||
* Only check the actual command if the check_cmnd
|
||||
* flag is set. It is not set for the "validate"
|
||||
* and "list" pseudo-commands. Always check the
|
||||
* host and user.
|
||||
* Only check the actual command if the check_cmnd flag is set.
|
||||
* It is not set for the "validate" and "list" pseudo-commands.
|
||||
* Always check the host and user.
|
||||
*/
|
||||
if (check_cmnd == FALSE)
|
||||
while (top) {
|
||||
|
6
sudo.c
6
sudo.c
@@ -258,7 +258,7 @@ main(argc, argv)
|
||||
|
||||
cmnd_status = init_vars(sudo_mode);
|
||||
|
||||
set_perms(PERM_USER, sudo_mode);
|
||||
/* At this point, ruid == euid == 0 */
|
||||
|
||||
check_sudoers(); /* check mode/owner on _PATH_SUDOERS */
|
||||
|
||||
@@ -763,7 +763,6 @@ check_sudoers()
|
||||
* Fix the mode and group on sudoers file from old default.
|
||||
* Only works if filesystem is readable/writable by root.
|
||||
*/
|
||||
set_perms(PERM_ROOT, 0);
|
||||
if ((rootstat = lstat(_PATH_SUDOERS, &statbuf)) == 0 &&
|
||||
SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
|
||||
(statbuf.st_mode & 0007777) == 0400) {
|
||||
@@ -824,8 +823,7 @@ check_sudoers()
|
||||
log_error(USE_ERRNO, "can't open %s", _PATH_SUDOERS);
|
||||
}
|
||||
|
||||
set_perms(PERM_ROOT, 0);
|
||||
set_perms(PERM_USER, 0);
|
||||
set_perms(PERM_ROOT, 0); /* change back to root */
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user