summaryrefslogtreecommitdiffstats
path: root/src/su.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/su.c')
-rw-r--r--src/su.c115
1 files changed, 71 insertions, 44 deletions
diff --git a/src/su.c b/src/su.c
index 6cd82fc..80c0859 100644
--- a/src/su.c
+++ b/src/su.c
@@ -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,