New upstream version 4.15.1
This commit is contained in:
@@ -45,6 +45,10 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
#include "alloc.h"
|
||||
#include "attr.h"
|
||||
#include "cast.h"
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "pwauth.h"
|
||||
@@ -55,11 +59,14 @@
|
||||
/*@-exitarg@*/
|
||||
#include "exitcodes.h"
|
||||
#include "shadowlog.h"
|
||||
#include "string/sprintf.h"
|
||||
#include "string/strtcpy.h"
|
||||
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
const char *Prog;
|
||||
static const char Prog[] = "su";
|
||||
static /*@observer@*/const char *caller_tty = NULL; /* Name of tty SU is run from */
|
||||
static bool caller_is_root = false;
|
||||
static uid_t caller_uid;
|
||||
@@ -95,8 +102,8 @@ static pid_t pid_child = 0;
|
||||
* External identifiers
|
||||
*/
|
||||
|
||||
extern char **newenvp; /* libmisc/env.c */
|
||||
extern size_t newenvc; /* libmisc/env.c */
|
||||
extern char **newenvp; /* lib/env.c */
|
||||
extern size_t newenvc; /* lib/env.c */
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
@@ -104,15 +111,16 @@ static void execve_shell (const char *shellname,
|
||||
char *args[],
|
||||
char *const envp[]);
|
||||
#ifdef USE_PAM
|
||||
static void kill_child (int unused(s));
|
||||
static void kill_child (MAYBE_UNUSED int s);
|
||||
static void prepare_pam_close_session (void);
|
||||
#else /* !USE_PAM */
|
||||
static void die (int);
|
||||
static bool iswheel (const char *);
|
||||
#endif /* !USE_PAM */
|
||||
static bool restricted_shell (const char *shellname);
|
||||
static /*@noreturn@*/void su_failure (const char *tty, bool su_to_root);
|
||||
NORETURN static void su_failure (const char *tty, bool su_to_root);
|
||||
static /*@only@*/struct passwd * check_perms (void);
|
||||
static /*@only@*/struct passwd * do_check_perms (void);
|
||||
#ifdef USE_PAM
|
||||
static void check_perms_pam (const struct passwd *pw);
|
||||
#else /* !USE_PAM */
|
||||
@@ -157,13 +165,13 @@ static bool iswheel (const char *username)
|
||||
return is_on_list (grp->gr_mem, username);
|
||||
}
|
||||
#else /* USE_PAM */
|
||||
static void kill_child (int unused(s))
|
||||
static void kill_child (MAYBE_UNUSED int s)
|
||||
{
|
||||
if (0 != pid_child) {
|
||||
(void) kill (-pid_child, SIGKILL);
|
||||
(void) write (STDERR_FILENO, kill_msg, strlen (kill_msg));
|
||||
(void) write_full(STDERR_FILENO, kill_msg, strlen(kill_msg));
|
||||
} else {
|
||||
(void) write (STDERR_FILENO, wait_msg, strlen (wait_msg));
|
||||
(void) write_full(STDERR_FILENO, wait_msg, strlen(wait_msg));
|
||||
}
|
||||
_exit (255);
|
||||
}
|
||||
@@ -185,10 +193,11 @@ static bool restricted_shell (const char *shellname)
|
||||
return true;
|
||||
}
|
||||
|
||||
static /*@noreturn@*/void su_failure (const char *tty, bool su_to_root)
|
||||
NORETURN
|
||||
static void
|
||||
su_failure (const char *tty, bool su_to_root)
|
||||
{
|
||||
sulog (tty, false, caller_name, name); /* log failed attempt */
|
||||
#ifdef USE_SYSLOG
|
||||
if (getdef_bool ("SYSLOG_SU_ENAB")) {
|
||||
SYSLOG ((su_to_root ? LOG_NOTICE : LOG_INFO,
|
||||
"- %s %s:%s", tty,
|
||||
@@ -196,7 +205,6 @@ static /*@noreturn@*/void su_failure (const char *tty, bool su_to_root)
|
||||
('\0' != name[0]) ? name : "???"));
|
||||
}
|
||||
closelog ();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_AUDIT
|
||||
audit_fd = audit_open ();
|
||||
@@ -225,7 +233,7 @@ static void execve_shell (const char *shellname,
|
||||
char *const envp[])
|
||||
{
|
||||
int err;
|
||||
(void) execve (shellname, (char **) args, envp);
|
||||
(void) execve (shellname, args, envp);
|
||||
err = errno;
|
||||
|
||||
if (access (shellname, R_OK|X_OK) == 0) {
|
||||
@@ -238,7 +246,7 @@ static void execve_shell (const char *shellname,
|
||||
while (NULL != args[n_args]) {
|
||||
n_args++;
|
||||
}
|
||||
targs = (char **) xmalloc ((n_args + 3) * sizeof (args[0]));
|
||||
targs = XMALLOC(n_args + 3, char *);
|
||||
targs[0] = "sh";
|
||||
targs[1] = "-";
|
||||
targs[2] = xstrdup (shellname);
|
||||
@@ -382,8 +390,8 @@ static void prepare_pam_close_session (void)
|
||||
stderr);
|
||||
(void) kill (-pid_child, caught);
|
||||
|
||||
snprintf (kill_msg, sizeof kill_msg, _(" ...killed.\n"));
|
||||
snprintf (wait_msg, sizeof wait_msg, _(" ...waiting for child to terminate.\n"));
|
||||
SNPRINTF(kill_msg, _(" ...killed.\n"));
|
||||
SNPRINTF(wait_msg, _(" ...waiting for child to terminate.\n"));
|
||||
|
||||
/* Any signals other than SIGCHLD and SIGALRM will no longer have any effect,
|
||||
* so it's time to block all of them. */
|
||||
@@ -430,6 +438,7 @@ static void prepare_pam_close_session (void)
|
||||
/*
|
||||
* usage - print command line syntax and exit
|
||||
*/
|
||||
NORETURN
|
||||
static void usage (int status)
|
||||
{
|
||||
(void)
|
||||
@@ -501,7 +510,8 @@ static void check_perms_nopam (const struct passwd *pw)
|
||||
}
|
||||
|
||||
if (strcmp (pw->pw_passwd, "") == 0) {
|
||||
char *prevent_no_auth = getdef_str("PREVENT_NO_AUTH");
|
||||
const char *prevent_no_auth = getdef_str("PREVENT_NO_AUTH");
|
||||
|
||||
if (prevent_no_auth == NULL) {
|
||||
prevent_no_auth = "superuser";
|
||||
}
|
||||
@@ -577,7 +587,7 @@ static void check_perms_nopam (const struct passwd *pw)
|
||||
* The first character of an administrator defined method is an '@'
|
||||
* character.
|
||||
*/
|
||||
if (pw_auth (password, name, PW_SU, (char *) 0) != 0) {
|
||||
if (pw_auth (password, name, PW_SU, NULL) != 0) {
|
||||
SYSLOG (((pw->pw_uid != 0)? LOG_NOTICE : LOG_WARN,
|
||||
"Authentication failed for %s", name));
|
||||
fprintf(stderr, _("%s: Authentication failure\n"), Prog);
|
||||
@@ -600,7 +610,7 @@ static void check_perms_nopam (const struct passwd *pw)
|
||||
* there is a "SU" entry in the /etc/porttime file denying access to
|
||||
* the account.
|
||||
*/
|
||||
if (!isttytime (name, "SU", time ((time_t *) 0))) {
|
||||
if (!isttytime (name, "SU", time (NULL))) {
|
||||
SYSLOG (((0 != pw->pw_uid) ? LOG_WARN : LOG_CRIT,
|
||||
"SU by %s to restricted account %s",
|
||||
caller_name, name));
|
||||
@@ -615,14 +625,30 @@ static void check_perms_nopam (const struct passwd *pw)
|
||||
/*
|
||||
* check_perms - check permissions to switch to the user 'name'
|
||||
*
|
||||
* In case of subsystem login, the user is first authenticated in the
|
||||
* caller's root subsystem, and then in the user's target subsystem.
|
||||
* The user is authenticated in all subsystems iterately.
|
||||
*/
|
||||
static /*@only@*/struct passwd * check_perms (void)
|
||||
{
|
||||
struct passwd *pw = NULL;
|
||||
|
||||
while (pw == NULL)
|
||||
pw = do_check_perms();
|
||||
return pw;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_check_perms - check permissions to switch to the user 'name'
|
||||
*
|
||||
* The user is authenticated in current subsystem, if any. Returns
|
||||
* NULL if permissions have to be checked in next subsystem, in
|
||||
* which case the subsystem has already been entered.
|
||||
*/
|
||||
static /*@only@*/struct passwd * do_check_perms (void)
|
||||
{
|
||||
#ifdef USE_PAM
|
||||
const char *tmp_name;
|
||||
int ret;
|
||||
int ret;
|
||||
const char *tmp_name;
|
||||
const void *item;
|
||||
#endif /* !USE_PAM */
|
||||
/*
|
||||
* The password file entries for the user is gotten and the account
|
||||
@@ -642,7 +668,7 @@ static /*@only@*/struct passwd * check_perms (void)
|
||||
#ifdef USE_PAM
|
||||
check_perms_pam (pw);
|
||||
/* PAM authentication can request a change of account */
|
||||
ret = pam_get_item(pamh, PAM_USER, (const void **) &tmp_name);
|
||||
ret = pam_get_item(pamh, PAM_USER, &item);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
SYSLOG((LOG_ERR, "pam_get_item: internal PAM error\n"));
|
||||
(void) fprintf (stderr,
|
||||
@@ -651,12 +677,18 @@ static /*@only@*/struct passwd * check_perms (void)
|
||||
(void) pam_end (pamh, ret);
|
||||
su_failure (caller_tty, 0 == pw->pw_uid);
|
||||
}
|
||||
tmp_name = item;
|
||||
if (strcmp (name, tmp_name) != 0) {
|
||||
SYSLOG ((LOG_INFO,
|
||||
"Change user from '%s' to '%s' as requested by PAM",
|
||||
name, tmp_name));
|
||||
strncpy (name, tmp_name, sizeof(name) - 1);
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
if (STRTCPY(name, tmp_name) == -1) {
|
||||
fprintf (stderr, _("Overlong user name '%s'\n"),
|
||||
tmp_name);
|
||||
SYSLOG ((LOG_NOTICE, "Overlong user name '%s'",
|
||||
tmp_name));
|
||||
su_failure (caller_tty, true);
|
||||
}
|
||||
pw = xgetpwnam (name);
|
||||
if (NULL == pw) {
|
||||
(void) fprintf (stderr,
|
||||
@@ -684,7 +716,7 @@ static /*@only@*/struct passwd * check_perms (void)
|
||||
endpwent (); /* close the old password databases */
|
||||
endspent ();
|
||||
pw_free (pw);
|
||||
return check_perms (); /* authenticate in the subsystem */
|
||||
return NULL; /* authenticate in the subsystem */
|
||||
}
|
||||
|
||||
return pw;
|
||||
@@ -706,11 +738,6 @@ static void save_caller_context (char **argv)
|
||||
const char *password = NULL;
|
||||
#endif /* SU_ACCESS */
|
||||
#endif /* !USE_PAM */
|
||||
/*
|
||||
* Get the program name. The program name is used as a prefix to
|
||||
* most error messages.
|
||||
*/
|
||||
Prog = Basename (argv[0]);
|
||||
log_set_progname(Prog);
|
||||
log_set_logfd(stderr);
|
||||
|
||||
@@ -752,7 +779,7 @@ static void save_caller_context (char **argv)
|
||||
(unsigned long) caller_uid));
|
||||
su_failure (caller_tty, true); /* unknown target UID*/
|
||||
}
|
||||
STRFCPY (caller_name, pw->pw_name);
|
||||
STRTCPY(caller_name, pw->pw_name);
|
||||
|
||||
#ifndef USE_PAM
|
||||
#ifdef SU_ACCESS
|
||||
@@ -808,7 +835,7 @@ static void process_flags (int argc, char **argv)
|
||||
case 'm':
|
||||
case 'p':
|
||||
/* This will only have an effect if the target
|
||||
* user do not have a restricted shell, or if
|
||||
* user does not have a restricted shell, or if
|
||||
* su is called by root.
|
||||
*/
|
||||
change_environment = false;
|
||||
@@ -827,7 +854,7 @@ static void process_flags (int argc, char **argv)
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
STRFCPY (name, argv[optind++]); /* use this login id */
|
||||
STRTCPY(name, argv[optind++]); /* use this login id */
|
||||
}
|
||||
if ('\0' == name[0]) { /* use default user */
|
||||
struct passwd *root_pw = getpwnam ("root");
|
||||
@@ -980,20 +1007,22 @@ int main (int argc, char **argv)
|
||||
int ret;
|
||||
#endif /* USE_PAM */
|
||||
|
||||
check_fds ();
|
||||
|
||||
(void) setlocale (LC_ALL, "");
|
||||
(void) bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
(void) textdomain (PACKAGE);
|
||||
|
||||
save_caller_context (argv);
|
||||
|
||||
OPENLOG ("su");
|
||||
OPENLOG (Prog);
|
||||
|
||||
process_flags (argc, argv);
|
||||
|
||||
initenv ();
|
||||
|
||||
#ifdef USE_PAM
|
||||
ret = pam_start ("su", name, &conv, &pamh);
|
||||
ret = pam_start (Prog, name, &conv, &pamh);
|
||||
if (PAM_SUCCESS != ret) {
|
||||
SYSLOG ((LOG_ERR, "pam_start: error %d", ret);
|
||||
fprintf (stderr,
|
||||
@@ -1002,9 +1031,9 @@ int main (int argc, char **argv)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
ret = pam_set_item (pamh, PAM_TTY, (const void *) caller_tty);
|
||||
ret = pam_set_item (pamh, PAM_TTY, caller_tty);
|
||||
if (PAM_SUCCESS == ret) {
|
||||
ret = pam_set_item (pamh, PAM_RUSER, (const void *) caller_name);
|
||||
ret = pam_set_item (pamh, PAM_RUSER, caller_name);
|
||||
}
|
||||
if (PAM_SUCCESS != ret) {
|
||||
SYSLOG ((LOG_ERR, "pam_set_item: %s",
|
||||
@@ -1017,7 +1046,7 @@ int main (int argc, char **argv)
|
||||
|
||||
pw = check_perms ();
|
||||
|
||||
/* If the user do not want to change the environment,
|
||||
/* If the user does not want to change the environment,
|
||||
* use the current SHELL.
|
||||
* (unless another shell is required by the command line)
|
||||
*/
|
||||
@@ -1050,13 +1079,11 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
sulog (caller_tty, true, caller_name, name); /* save SU information */
|
||||
#ifdef USE_SYSLOG
|
||||
if (getdef_bool ("SYSLOG_SU_ENAB")) {
|
||||
SYSLOG ((LOG_INFO, "+ %s %s:%s", caller_tty,
|
||||
('\0' != caller_name[0]) ? caller_name : "???",
|
||||
('\0' != name[0]) ? name : "???"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
/* set primary group id and supplementary groups */
|
||||
@@ -1135,7 +1162,7 @@ int main (int argc, char **argv)
|
||||
int fd = open ("/dev/tty", O_RDWR);
|
||||
|
||||
if (fd >= 0) {
|
||||
err = ioctl (fd, TIOCNOTTY, (char *) 0);
|
||||
err = ioctl (fd, TIOCNOTTY, (char *) NULL);
|
||||
(void) close (fd);
|
||||
} else if (ENXIO == errno) {
|
||||
/* There are no controlling terminal already */
|
||||
@@ -1178,7 +1205,7 @@ int main (int argc, char **argv)
|
||||
cp = Basename (shellstr);
|
||||
}
|
||||
|
||||
arg0 = xmalloc (strlen (cp) + 2);
|
||||
arg0 = XMALLOC(strlen(cp) + 2, char);
|
||||
arg0[0] = '-';
|
||||
strcpy (arg0 + 1, cp);
|
||||
cp = arg0;
|
||||
@@ -1199,7 +1226,7 @@ int main (int argc, char **argv)
|
||||
* Use the shell and create an argv
|
||||
* with the rest of the command line included.
|
||||
*/
|
||||
argv[-1] = cp;
|
||||
argv[-1] = const_cast(char *, cp);
|
||||
execve_shell (shellstr, &argv[-1], environ);
|
||||
err = errno;
|
||||
(void) fprintf (stderr,
|
||||
|
||||
Reference in New Issue
Block a user