* src/su.c (save_caller_context): Extract from main() the code
used to save the caller's context.
This commit is contained in:
		@@ -1,3 +1,8 @@
 | 
			
		||||
2011-06-12  Nicolas François  <nicolas.francois@centraliens.net>
 | 
			
		||||
 | 
			
		||||
	* src/su.c (save_caller_context): Extract from main() the code
 | 
			
		||||
	used to save the caller's context.
 | 
			
		||||
 | 
			
		||||
2011-06-10  Nicolas François  <nicolas.francois@centraliens.net>
 | 
			
		||||
 | 
			
		||||
	* src/su.c: Group some of the environment processing blocks. The
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										207
									
								
								src/su.c
									
									
									
									
									
								
							
							
						
						
									
										207
									
								
								src/su.c
									
									
									
									
									
								
							@@ -75,10 +75,20 @@
 | 
			
		||||
 * Global variables
 | 
			
		||||
 */
 | 
			
		||||
const char *Prog;
 | 
			
		||||
const char *caller_tty = NULL;	/* Name of tty SU is run from */
 | 
			
		||||
bool caller_is_root = false;
 | 
			
		||||
uid_t caller_uid;
 | 
			
		||||
#ifndef USE_PAM
 | 
			
		||||
int caller_on_console = 0;
 | 
			
		||||
#ifdef SU_ACCESS
 | 
			
		||||
char *caller_pass;
 | 
			
		||||
#endif
 | 
			
		||||
#endif				/* !USE_PAM */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* not needed by sulog.c anymore */
 | 
			
		||||
static char name[BUFSIZ];
 | 
			
		||||
static char oldname[BUFSIZ];
 | 
			
		||||
static char caller_name[BUFSIZ];
 | 
			
		||||
 | 
			
		||||
/* If nonzero, change some environment vars to indicate the user su'd to. */
 | 
			
		||||
static bool change_environment;
 | 
			
		||||
@@ -110,6 +120,7 @@ static RETSIGTYPE die (int);
 | 
			
		||||
static bool iswheel (const char *);
 | 
			
		||||
#endif				/* !USE_PAM */
 | 
			
		||||
static struct passwd * check_perms (void);
 | 
			
		||||
static void save_caller_context (char **argv);
 | 
			
		||||
 | 
			
		||||
#ifndef USE_PAM
 | 
			
		||||
/*
 | 
			
		||||
@@ -178,12 +189,12 @@ static bool restricted_shell (const char *shellstr)
 | 
			
		||||
 | 
			
		||||
static void su_failure (const char *tty, bool su_to_root)
 | 
			
		||||
{
 | 
			
		||||
	sulog (tty, false, oldname, name);	/* log failed attempt */
 | 
			
		||||
	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,
 | 
			
		||||
		         ('\0' != oldname[0]) ? oldname : "???",
 | 
			
		||||
		         ('\0' != caller_name[0]) ? caller_name : "???",
 | 
			
		||||
		         ('\0' != name[0]) ? name : "???"));
 | 
			
		||||
	}
 | 
			
		||||
	closelog ();
 | 
			
		||||
@@ -440,10 +451,10 @@ static struct passwd * check_perms (void)
 | 
			
		||||
	 * to Chris Evans <lady0110@sable.ox.ac.uk>.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (!amroot) {
 | 
			
		||||
	if (!caller_is_root) {
 | 
			
		||||
		if (   (0 == pw->pw_uid)
 | 
			
		||||
		    && getdef_bool ("SU_WHEEL_ONLY")
 | 
			
		||||
		    && !iswheel (oldname)) {
 | 
			
		||||
		    && !iswheel (caller_name)) {
 | 
			
		||||
			fprintf (stderr,
 | 
			
		||||
			         _("You are not authorized to su %s\n"),
 | 
			
		||||
			         name);
 | 
			
		||||
@@ -457,7 +468,7 @@ static struct passwd * check_perms (void)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch (check_su_auth (oldname, name, 0 == pw->pw_uid)) {
 | 
			
		||||
		switch (check_su_auth (caller_name, name, 0 == pw->pw_uid)) {
 | 
			
		||||
		case 0:	/* normal su, require target user's password */
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:	/* require no password */
 | 
			
		||||
@@ -465,7 +476,7 @@ static struct passwd * check_perms (void)
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:	/* require own password */
 | 
			
		||||
			puts (_("(Enter your own password)"));
 | 
			
		||||
			pw->pw_passwd = oldpass;
 | 
			
		||||
			pw->pw_passwd = caller_pass;
 | 
			
		||||
			break;
 | 
			
		||||
		default:	/* access denied (-1) or unexpected value */
 | 
			
		||||
			fprintf (stderr,
 | 
			
		||||
@@ -486,12 +497,12 @@ static struct passwd * check_perms (void)
 | 
			
		||||
		         pam_strerror (pamh, ret)));
 | 
			
		||||
		fprintf (stderr, _("%s: %s\n"), Prog, pam_strerror (pamh, ret));
 | 
			
		||||
		(void) pam_end (pamh, ret);
 | 
			
		||||
		su_failure (tty, 0 == pw->pw_uid);
 | 
			
		||||
		su_failure (caller_tty, 0 == pw->pw_uid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = pam_acct_mgmt (pamh, 0);
 | 
			
		||||
	if (PAM_SUCCESS != ret) {
 | 
			
		||||
		if (amroot) {
 | 
			
		||||
		if (caller_is_root) {
 | 
			
		||||
			fprintf (stderr,
 | 
			
		||||
			         _("%s: %s\n(Ignored)\n"),
 | 
			
		||||
			         Prog, pam_strerror (pamh, ret));
 | 
			
		||||
@@ -504,7 +515,7 @@ static struct passwd * check_perms (void)
 | 
			
		||||
				         _("%s: %s\n"),
 | 
			
		||||
				         Prog, pam_strerror (pamh, ret));
 | 
			
		||||
				(void) pam_end (pamh, ret);
 | 
			
		||||
				su_failure (tty, 0 == pw->pw_uid);
 | 
			
		||||
				su_failure (caller_tty, 0 == pw->pw_uid);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			SYSLOG ((LOG_ERR, "pam_acct_mgmt: %s",
 | 
			
		||||
@@ -513,7 +524,7 @@ static struct passwd * check_perms (void)
 | 
			
		||||
			         _("%s: %s\n"),
 | 
			
		||||
			         Prog, pam_strerror (pamh, ret));
 | 
			
		||||
			(void) pam_end (pamh, ret);
 | 
			
		||||
			su_failure (tty, 0 == pw->pw_uid);
 | 
			
		||||
			su_failure (caller_tty, 0 == pw->pw_uid);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#else				/* !USE_PAM */
 | 
			
		||||
@@ -528,12 +539,12 @@ static struct passwd * check_perms (void)
 | 
			
		||||
	 * The first character of an administrator defined method is an '@'
 | 
			
		||||
	 * character.
 | 
			
		||||
	 */
 | 
			
		||||
	if (   !amroot
 | 
			
		||||
	if (   !caller_is_root
 | 
			
		||||
	    && (pw_auth (pw->pw_passwd, name, PW_SU, (char *) 0) != 0)) {
 | 
			
		||||
		SYSLOG (((pw->pw_uid != 0)? LOG_NOTICE : LOG_WARN,
 | 
			
		||||
		         "Authentication failed for %s", name));
 | 
			
		||||
		fprintf(stderr, _("%s: Authentication failure\n"), Prog);
 | 
			
		||||
		su_failure (tty, 0 == pw->pw_uid);
 | 
			
		||||
		su_failure (caller_tty, 0 == pw->pw_uid);
 | 
			
		||||
	}
 | 
			
		||||
	(void) signal (SIGQUIT, oldsig);
 | 
			
		||||
 | 
			
		||||
@@ -542,7 +553,7 @@ static struct passwd * check_perms (void)
 | 
			
		||||
	 * expired accounts, but normal users can't become a user with an
 | 
			
		||||
	 * expired password.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((!amroot) && (NULL != spwd)) {
 | 
			
		||||
	if ((!caller_is_root) && (NULL != spwd)) {
 | 
			
		||||
		(void) expire (pw, spwd);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -552,15 +563,15 @@ static struct passwd * check_perms (void)
 | 
			
		||||
	 * there is a "SU" entry in the /etc/porttime file denying access to
 | 
			
		||||
	 * the account.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!amroot) {
 | 
			
		||||
	if (!caller_is_root) {
 | 
			
		||||
		if (!isttytime (name, "SU", time ((time_t *) 0))) {
 | 
			
		||||
			SYSLOG (((0 != pw->pw_uid) ? LOG_WARN : LOG_CRIT,
 | 
			
		||||
			         "SU by %s to restricted account %s",
 | 
			
		||||
			         oldname, name));
 | 
			
		||||
			         caller_name, name));
 | 
			
		||||
			fprintf (stderr,
 | 
			
		||||
			         _("%s: You are not authorized to su at that time\n"),
 | 
			
		||||
			         Prog);
 | 
			
		||||
			su_failure (tty, 0 == pw->pw_uid);
 | 
			
		||||
			su_failure (caller_tty, 0 == pw->pw_uid);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif				/* !USE_PAM */
 | 
			
		||||
@@ -583,6 +594,80 @@ static struct passwd * check_perms (void)
 | 
			
		||||
	return pw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * save_caller_context - save information from the call context
 | 
			
		||||
 *
 | 
			
		||||
 *	Save the program's name (Prog), caller's UID (caller_uid /
 | 
			
		||||
 *	caller_is_root), name (caller_name), and password (caller_pass),
 | 
			
		||||
 *	the TTY (ttyp), and whether su was called from a console
 | 
			
		||||
 *	(is_console) for further processing and before they might change.
 | 
			
		||||
 */
 | 
			
		||||
static void save_caller_context (char **argv)
 | 
			
		||||
{
 | 
			
		||||
	struct passwd *pw = NULL;
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get the program name. The program name is used as a prefix to
 | 
			
		||||
	 * most error messages.
 | 
			
		||||
	 */
 | 
			
		||||
	Prog = Basename (argv[0]);
 | 
			
		||||
 | 
			
		||||
	caller_uid = getuid ();
 | 
			
		||||
	caller_is_root = (caller_uid == 0);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get the tty name. Entries will be logged indicating that the user
 | 
			
		||||
	 * tried to change to the named new user from the current terminal.
 | 
			
		||||
	 */
 | 
			
		||||
	caller_tty = ttyname (0);
 | 
			
		||||
	if ((isatty (0) != 0) && (NULL != caller_tty)) {
 | 
			
		||||
#ifndef USE_PAM
 | 
			
		||||
		caller_on_console = console (caller_tty);
 | 
			
		||||
#endif
 | 
			
		||||
	} else {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Be more paranoid, like su from SimplePAMApps.  --marekm
 | 
			
		||||
		 */
 | 
			
		||||
		if (!caller_is_root) {
 | 
			
		||||
			fprintf (stderr,
 | 
			
		||||
			         _("%s: must be run from a terminal\n"),
 | 
			
		||||
			         Prog);
 | 
			
		||||
			exit (1);
 | 
			
		||||
		}
 | 
			
		||||
		caller_tty = "???";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get the user's real name. The current UID is used to determine
 | 
			
		||||
	 * who has executed su. That user ID must exist.
 | 
			
		||||
	 */
 | 
			
		||||
	pw = get_my_pwent ();
 | 
			
		||||
	if (NULL == pw) {
 | 
			
		||||
		fprintf (stderr,
 | 
			
		||||
		         _("%s: Cannot determine your user name.\n"),
 | 
			
		||||
		         Prog);
 | 
			
		||||
		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
 | 
			
		||||
		         (unsigned long) caller_uid));
 | 
			
		||||
		su_failure (caller_tty, true); // FIXME: at this time I do not know the target UID
 | 
			
		||||
	}
 | 
			
		||||
	STRFCPY (caller_name, pw->pw_name);
 | 
			
		||||
 | 
			
		||||
#ifndef USE_PAM
 | 
			
		||||
#ifdef SU_ACCESS
 | 
			
		||||
	/*
 | 
			
		||||
	 * Sort out the password of user calling su, in case needed later
 | 
			
		||||
	 * -- chris
 | 
			
		||||
	 */
 | 
			
		||||
	if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
 | 
			
		||||
		struct spwd *spwd = getspnam (caller_name);
 | 
			
		||||
		if (NULL != spwd) {
 | 
			
		||||
			pw->pw_passwd = spwd->sp_pwdp;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	caller_pass = xstrdup (pw->pw_passwd);
 | 
			
		||||
#endif				/* SU_ACCESS */
 | 
			
		||||
#endif				/* !USE_PAM */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * su - switch user id
 | 
			
		||||
 *
 | 
			
		||||
@@ -596,11 +681,8 @@ static struct passwd * check_perms (void)
 | 
			
		||||
int main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	const char *cp;
 | 
			
		||||
	const char *tty = NULL;	/* Name of tty SU is run from        */
 | 
			
		||||
	bool doshell = false;
 | 
			
		||||
	bool fakelogin = false;
 | 
			
		||||
	bool amroot = false;
 | 
			
		||||
	uid_t my_uid;
 | 
			
		||||
	struct passwd *pw = NULL;
 | 
			
		||||
	char *shellstr = NULL;
 | 
			
		||||
	char *command = NULL;
 | 
			
		||||
@@ -611,11 +693,7 @@ int main (int argc, char **argv)
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	RETSIGTYPE (*oldsig) (int);
 | 
			
		||||
	int is_console = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef SU_ACCESS
 | 
			
		||||
	char *oldpass;
 | 
			
		||||
#endif
 | 
			
		||||
#endif				/* !USE_PAM */
 | 
			
		||||
 | 
			
		||||
	(void) setlocale (LC_ALL, "");
 | 
			
		||||
@@ -624,11 +702,7 @@ int main (int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	change_environment = true;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get the program name. The program name is used as a prefix to
 | 
			
		||||
	 * most error messages.
 | 
			
		||||
	 */
 | 
			
		||||
	Prog = Basename (argv[0]);
 | 
			
		||||
	save_caller_context (argv);
 | 
			
		||||
 | 
			
		||||
	OPENLOG ("su");
 | 
			
		||||
 | 
			
		||||
@@ -692,31 +766,6 @@ int main (int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	initenv ();
 | 
			
		||||
 | 
			
		||||
	my_uid = getuid ();
 | 
			
		||||
	amroot = (my_uid == 0);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get the tty name. Entries will be logged indicating that the user
 | 
			
		||||
	 * tried to change to the named new user from the current terminal.
 | 
			
		||||
	 */
 | 
			
		||||
	tty = ttyname (0);
 | 
			
		||||
	if ((isatty (0) != 0) && (NULL != tty)) {
 | 
			
		||||
#ifndef USE_PAM
 | 
			
		||||
		is_console = console (tty);
 | 
			
		||||
#endif
 | 
			
		||||
	} else {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Be more paranoid, like su from SimplePAMApps.  --marekm
 | 
			
		||||
		 */
 | 
			
		||||
		if (!amroot) {
 | 
			
		||||
			fprintf (stderr,
 | 
			
		||||
			         _("%s: must be run from a terminal\n"),
 | 
			
		||||
			         Prog);
 | 
			
		||||
			exit (1);
 | 
			
		||||
		}
 | 
			
		||||
		tty = "???";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The next argument must be either a user ID, or some flag to a
 | 
			
		||||
	 * subshell. Pretty sticky since you can't have an argument which
 | 
			
		||||
@@ -737,7 +786,7 @@ int main (int argc, char **argv)
 | 
			
		||||
			root_pw = getpwuid (0);
 | 
			
		||||
			if (NULL == root_pw) {
 | 
			
		||||
				SYSLOG ((LOG_CRIT, "There is no UID 0 user."));
 | 
			
		||||
				su_failure (tty, true);
 | 
			
		||||
				su_failure (caller_tty, true);
 | 
			
		||||
			}
 | 
			
		||||
			(void) strcpy (name, root_pw->pw_name);
 | 
			
		||||
		}
 | 
			
		||||
@@ -748,37 +797,7 @@ int main (int argc, char **argv)
 | 
			
		||||
		doshell = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get the user's real name. The current UID is used to determine
 | 
			
		||||
	 * who has executed su. That user ID must exist.
 | 
			
		||||
	 */
 | 
			
		||||
	pw = get_my_pwent ();
 | 
			
		||||
	if (NULL == pw) {
 | 
			
		||||
		fprintf (stderr,
 | 
			
		||||
		         _("%s: Cannot determine your user name.\n"),
 | 
			
		||||
		         Prog);
 | 
			
		||||
		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
 | 
			
		||||
		         (unsigned long) my_uid));
 | 
			
		||||
		su_failure (tty, true); // FIXME: at this time I do not know the target UID
 | 
			
		||||
	}
 | 
			
		||||
	STRFCPY (oldname, pw->pw_name);
 | 
			
		||||
 | 
			
		||||
#ifndef USE_PAM
 | 
			
		||||
#ifdef SU_ACCESS
 | 
			
		||||
	/*
 | 
			
		||||
	 * Sort out the password of user calling su, in case needed later
 | 
			
		||||
	 * -- chris
 | 
			
		||||
	 */
 | 
			
		||||
	if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
 | 
			
		||||
		struct spwd *spwd = getspnam (oldname);
 | 
			
		||||
		if (NULL != spwd) {
 | 
			
		||||
			pw->pw_passwd = spwd->sp_pwdp;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	oldpass = xstrdup (pw->pw_passwd);
 | 
			
		||||
#endif				/* SU_ACCESS */
 | 
			
		||||
 | 
			
		||||
#else				/* USE_PAM */
 | 
			
		||||
#ifdef USE_PAM
 | 
			
		||||
	ret = pam_start ("su", name, &conv, &pamh);
 | 
			
		||||
	if (PAM_SUCCESS != ret) {
 | 
			
		||||
		SYSLOG ((LOG_ERR, "pam_start: error %d", ret);
 | 
			
		||||
@@ -788,9 +807,9 @@ int main (int argc, char **argv)
 | 
			
		||||
		exit (1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = pam_set_item (pamh, PAM_TTY, (const void *) tty);
 | 
			
		||||
	ret = pam_set_item (pamh, PAM_TTY, (const void *) caller_tty);
 | 
			
		||||
	if (PAM_SUCCESS == ret) {
 | 
			
		||||
		ret = pam_set_item (pamh, PAM_RUSER, (const void *) oldname);
 | 
			
		||||
		ret = pam_set_item (pamh, PAM_RUSER, (const void *) caller_name);
 | 
			
		||||
	}
 | 
			
		||||
	if (PAM_SUCCESS != ret) {
 | 
			
		||||
		SYSLOG ((LOG_ERR, "pam_set_item: %s",
 | 
			
		||||
@@ -815,7 +834,7 @@ int main (int argc, char **argv)
 | 
			
		||||
	 * restricted shell, the environment must be changed and the shell
 | 
			
		||||
	 * must be the one specified in /etc/passwd.
 | 
			
		||||
	 */
 | 
			
		||||
	if (   !amroot
 | 
			
		||||
	if (   !caller_is_root
 | 
			
		||||
	    && restricted_shell (pw->pw_shell)) {
 | 
			
		||||
		shellstr = NULL;
 | 
			
		||||
		change_environment = true;
 | 
			
		||||
@@ -910,13 +929,13 @@ int main (int argc, char **argv)
 | 
			
		||||
		addenv ("IFS= \t\n", NULL);	/* ... instead, set a safe IFS */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sulog (tty, true, oldname, name);	/* save SU information */
 | 
			
		||||
	sulog (caller_tty, true, caller_name, name);	/* save SU information */
 | 
			
		||||
	endpwent ();
 | 
			
		||||
	endspent ();
 | 
			
		||||
#ifdef USE_SYSLOG
 | 
			
		||||
	if (getdef_bool ("SYSLOG_SU_ENAB")) {
 | 
			
		||||
		SYSLOG ((LOG_INFO, "+ %s %s:%s", tty,
 | 
			
		||||
		         ('\0' != oldname[0]) ? oldname : "???",
 | 
			
		||||
		SYSLOG ((LOG_INFO, "+ %s %s:%s", caller_tty,
 | 
			
		||||
		         ('\0' != caller_name[0]) ? caller_name : "???",
 | 
			
		||||
		         ('\0' != name[0]) ? name : "???"));
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -978,11 +997,11 @@ int main (int argc, char **argv)
 | 
			
		||||
	environ = newenvp;	/* make new environment active */
 | 
			
		||||
 | 
			
		||||
	/* no limits if su from root (unless su must fake login's behavior) */
 | 
			
		||||
	if (!amroot || fakelogin) {
 | 
			
		||||
	if (!caller_is_root || fakelogin) {
 | 
			
		||||
		setup_limits (pw);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (setup_uid_gid (pw, is_console) != 0) {
 | 
			
		||||
	if (setup_uid_gid (pw, caller_on_console) != 0) {
 | 
			
		||||
		exit (1);
 | 
			
		||||
	}
 | 
			
		||||
#endif				/* !USE_PAM */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user