Home | History | Annotate | Download | only in newrole
      1 /************************************************************************
      2  *
      3  * newrole
      4  *
      5  * SYNOPSIS:
      6  *
      7  * This program allows a user to change their SELinux RBAC role and/or
      8  * SELinux TE type (domain) in a manner similar to the way the traditional
      9  * UNIX su program allows a user to change their identity.
     10  *
     11  * USAGE:
     12  *
     13  * newrole [ -r role ] [ -t type ] [ -l level ] [ -V ] [ -- args ]
     14  *
     15  * BUILD OPTIONS:
     16  *
     17  * option USE_PAM:
     18  *
     19  * Set the USE_PAM constant if you want to authenticate users via PAM.
     20  * If USE_PAM is not set, users will be authenticated via direct
     21  * access to the shadow password file.
     22  *
     23  * If you decide to use PAM must be told how to handle newrole.  A
     24  * good rule-of-thumb might be to tell PAM to handle newrole in the
     25  * same way it handles su, except that you should remove the pam_rootok.so
     26  * entry so that even root must re-authenticate to change roles.
     27  *
     28  * If you choose not to use PAM, make sure you have a shadow passwd file
     29  * in /etc/shadow.  You can use a symlink if your shadow passwd file
     30  * lives in another directory.  Example:
     31  *   su
     32  *   cd /etc
     33  *   ln -s /etc/auth/shadow shadow
     34  *
     35  * If you decide not to use PAM, you will also have to make newrole
     36  * setuid root, so that it can read the shadow passwd file.
     37  *
     38  *
     39  * Authors:
     40  *      Anthony Colatrella
     41  *	Tim Fraser
     42  *	Steve Grubb <sgrubb (at) redhat.com>
     43  *	Darrel Goeddel <DGoeddel (at) trustedcs.com>
     44  *	Michael Thompson <mcthomps (at) us.ibm.com>
     45  *	Dan Walsh <dwalsh (at) redhat.com>
     46  *
     47  *************************************************************************/
     48 
     49 #define _GNU_SOURCE
     50 
     51 #if defined(AUDIT_LOG_PRIV) && !defined(USE_AUDIT)
     52 #error AUDIT_LOG_PRIV needs the USE_AUDIT option
     53 #endif
     54 #if defined(NAMESPACE_PRIV) && !defined(USE_PAM)
     55 #error NAMESPACE_PRIV needs the USE_PAM option
     56 #endif
     57 
     58 #include <stdio.h>
     59 #include <stdlib.h>		/* for malloc(), realloc(), free() */
     60 #include <pwd.h>		/* for getpwuid() */
     61 #include <ctype.h>
     62 #include <sys/types.h>		/* to make getuid() and getpwuid() happy */
     63 #include <sys/wait.h>		/* for wait() */
     64 #include <getopt.h>		/* for getopt_long() form of getopt() */
     65 #include <fcntl.h>
     66 #include <string.h>
     67 #include <errno.h>
     68 #include <selinux/selinux.h>	/* for is_selinux_enabled() */
     69 #include <selinux/context.h>	/* for context-mangling functions */
     70 #include <selinux/get_default_type.h>
     71 #include <selinux/get_context_list.h>	/* for SELINUX_DEFAULTUSER */
     72 #include <signal.h>
     73 #include <unistd.h>		/* for getuid(), exit(), getopt() */
     74 #ifdef USE_AUDIT
     75 #include <libaudit.h>
     76 #endif
     77 #if defined(AUDIT_LOG_PRIV) || defined(NAMESPACE_PRIV)
     78 #include <sys/prctl.h>
     79 #include <cap-ng.h>
     80 #endif
     81 #ifdef USE_NLS
     82 #include <locale.h>		/* for setlocale() */
     83 #include <libintl.h>		/* for gettext() */
     84 #define _(msgid) gettext (msgid)
     85 #else
     86 #define _(msgid) (msgid)
     87 #endif
     88 #ifndef PACKAGE
     89 #define PACKAGE "policycoreutils"	/* the name of this package lang translation */
     90 #endif
     91 
     92 #define TRUE 1
     93 #define FALSE 0
     94 
     95 /* USAGE_STRING describes the command-line args of this program. */
     96 #define USAGE_STRING "USAGE: newrole [ -r role ] [ -t type ] [ -l level ] [ -p ] [ -V ] [ -- args ]"
     97 
     98 #ifdef USE_PAM
     99 #define PAM_SERVICE_CONFIG "/etc/selinux/newrole_pam.conf";
    100 #endif
    101 
    102 #define DEFAULT_PATH "/usr/bin:/bin"
    103 #define DEFAULT_CONTEXT_SIZE 255	/* first guess at context size */
    104 
    105 extern char **environ;
    106 
    107 /**
    108  * Construct from the current range and specified desired level a resulting
    109  * range. If the specified level is a range, return that. If it is not, then
    110  * construct a range with level as the sensitivity and clearance of the current
    111  * context.
    112  *
    113  * newlevel - the level specified on the command line
    114  * range    - the range in the current context
    115  *
    116  * Returns malloc'd memory
    117  */
    118 static char *build_new_range(char *newlevel, const char *range)
    119 {
    120 	char *newrangep = NULL;
    121 	const char *tmpptr;
    122 	size_t len;
    123 
    124 	/* a missing or empty string */
    125 	if (!range || !strlen(range) || !newlevel || !strlen(newlevel))
    126 		return NULL;
    127 
    128 	/* if the newlevel is actually a range - just use that */
    129 	if (strchr(newlevel, '-')) {
    130 		newrangep = strdup(newlevel);
    131 		return newrangep;
    132 	}
    133 
    134 	/* look for MLS range in current context */
    135 	tmpptr = strchr(range, '-');
    136 	if (tmpptr) {
    137 		/* we are inserting into a ranged MLS context */
    138 		len = strlen(newlevel) + 1 + strlen(tmpptr + 1) + 1;
    139 		newrangep = (char *)malloc(len);
    140 		if (!newrangep)
    141 			return NULL;
    142 		snprintf(newrangep, len, "%s-%s", newlevel, tmpptr + 1);
    143 	} else {
    144 		/* we are inserting into a currently non-ranged MLS context */
    145 		if (!strcmp(newlevel, range)) {
    146 			newrangep = strdup(range);
    147 		} else {
    148 			len = strlen(newlevel) + 1 + strlen(range) + 1;
    149 			newrangep = (char *)malloc(len);
    150 			if (!newrangep)
    151 				return NULL;
    152 			snprintf(newrangep, len, "%s-%s", newlevel, range);
    153 		}
    154 	}
    155 
    156 	return newrangep;
    157 }
    158 
    159 #ifdef USE_PAM
    160 
    161 /************************************************************************
    162  *
    163  * All PAM code goes in this section.
    164  *
    165  ************************************************************************/
    166 #include <security/pam_appl.h>	/* for PAM functions */
    167 #include <security/pam_misc.h>	/* for misc_conv PAM utility function */
    168 
    169 const char *service_name = "newrole";
    170 
    171 /* authenticate_via_pam()
    172  *
    173  * in:     pw - struct containing data from our user's line in
    174  *                         the passwd file.
    175  * out:    nothing
    176  * return: value   condition
    177  *         -----   ---------
    178  *           1     PAM thinks that the user authenticated themselves properly
    179  *           0     otherwise
    180  *
    181  * This function uses PAM to authenticate the user running this
    182  * program.  This is the only function in this program that makes PAM
    183  * calls.
    184  */
    185 int authenticate_via_pam(const char *ttyn, pam_handle_t * pam_handle)
    186 {
    187 
    188 	int result = 0;		/* set to 0 (not authenticated) by default */
    189 	int pam_rc;		/* pam return code */
    190 	const char *tty_name;
    191 
    192 	if (ttyn) {
    193 		if (strncmp(ttyn, "/dev/", 5) == 0)
    194 			tty_name = ttyn + 5;
    195 		else
    196 			tty_name = ttyn;
    197 
    198 		pam_rc = pam_set_item(pam_handle, PAM_TTY, tty_name);
    199 		if (pam_rc != PAM_SUCCESS) {
    200 			fprintf(stderr, _("failed to set PAM_TTY\n"));
    201 			goto out;
    202 		}
    203 	}
    204 
    205 	/* Ask PAM to authenticate the user running this program */
    206 	pam_rc = pam_authenticate(pam_handle, 0);
    207 	if (pam_rc != PAM_SUCCESS) {
    208 		goto out;
    209 	}
    210 
    211 	/* Ask PAM to verify acct_mgmt */
    212 	pam_rc = pam_acct_mgmt(pam_handle, 0);
    213 	if (pam_rc == PAM_SUCCESS) {
    214 		result = 1;	/* user authenticated OK! */
    215 	}
    216 
    217       out:
    218 	return result;
    219 }				/* authenticate_via_pam() */
    220 
    221 #include "hashtab.h"
    222 
    223 static int free_hashtab_entry(hashtab_key_t key, hashtab_datum_t d,
    224 			      void *args __attribute__ ((unused)))
    225 {
    226 	free(key);
    227 	free(d);
    228 	return 0;
    229 }
    230 
    231 static unsigned int reqsymhash(hashtab_t h, const_hashtab_key_t key)
    232 {
    233 	char *p, *keyp;
    234 	size_t size;
    235 	unsigned int val;
    236 
    237 	val = 0;
    238 	keyp = (char *)key;
    239 	size = strlen(keyp);
    240 	for (p = keyp; ((size_t) (p - keyp)) < size; p++)
    241 		val =
    242 		    (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
    243 	return val & (h->size - 1);
    244 }
    245 
    246 static int reqsymcmp(hashtab_t h
    247 		     __attribute__ ((unused)), const_hashtab_key_t key1,
    248 		     const_hashtab_key_t key2)
    249 {
    250 	return strcmp(key1, key2);
    251 }
    252 
    253 static hashtab_t app_service_names = NULL;
    254 #define PAM_SERVICE_SLOTS 64
    255 
    256 static int process_pam_config(FILE * cfg)
    257 {
    258 	const char *config_file_path = PAM_SERVICE_CONFIG;
    259 	char *line_buf = NULL;
    260 	unsigned long lineno = 0;
    261 	size_t len = 0;
    262 	char *app = NULL;
    263 	char *service = NULL;
    264 	int ret;
    265 
    266 	while (getline(&line_buf, &len, cfg) > 0) {
    267 		char *buffer = line_buf;
    268 		lineno++;
    269 		while (isspace(*buffer))
    270 			buffer++;
    271 		if (buffer[0] == '#')
    272 			continue;
    273 		if (buffer[0] == '\n' || buffer[0] == '\0')
    274 			continue;
    275 
    276 		app = service = NULL;
    277 		ret = sscanf(buffer, "%ms %ms\n", &app, &service);
    278 		if (ret < 2 || !app || !service)
    279 			goto err;
    280 
    281 		ret = hashtab_insert(app_service_names, app, service);
    282 		if (ret == HASHTAB_OVERFLOW) {
    283 			fprintf(stderr,
    284 				_
    285 				("newrole: service name configuration hashtable overflow\n"));
    286 			goto err;
    287 		}
    288 	}
    289 
    290 	free(line_buf);
    291 	return 0;
    292       err:
    293 	free(app);
    294 	free(service);
    295 	fprintf(stderr, _("newrole:  %s:  error on line %lu.\n"),
    296 		config_file_path, lineno);
    297 	free(line_buf);
    298 	return -1;
    299 }
    300 
    301 /*
    302  *  Read config file ignoring comment lines.
    303  *  Files specified one per line executable with a corresponding
    304  *  pam service name.
    305  */
    306 static int read_pam_config(void)
    307 {
    308 	const char *config_file_path = PAM_SERVICE_CONFIG;
    309 	FILE *cfg = NULL;
    310 	cfg = fopen(config_file_path, "r");
    311 	if (!cfg)
    312 		return 0;	/* This configuration is optional. */
    313 	app_service_names =
    314 	    hashtab_create(reqsymhash, reqsymcmp, PAM_SERVICE_SLOTS);
    315 	if (!app_service_names)
    316 		goto err;
    317 	if (process_pam_config(cfg))
    318 		goto err;
    319 	fclose(cfg);
    320 	return 0;
    321       err:
    322 	fclose(cfg);
    323 	return -1;
    324 }
    325 
    326 #else				/* else !USE_PAM */
    327 
    328 /************************************************************************
    329  *
    330  * All shadow passwd code goes in this section.
    331  *
    332  ************************************************************************/
    333 #include <shadow.h>		/* for shadow passwd functions */
    334 #include <string.h>		/* for strlen(), memset() */
    335 
    336 #define PASSWORD_PROMPT _("Password:")	/* prompt for getpass() */
    337 
    338 /* authenticate_via_shadow_passwd()
    339  *
    340  * in:     uname - the calling user's user name
    341  * out:    nothing
    342  * return: value   condition
    343  *         -----   ---------
    344  *           1     user authenticated themselves properly according to the
    345  *                 shadow passwd file.
    346  *           0     otherwise
    347  *
    348  * This function uses the shadow passwd file to thenticate the user running
    349  * this program.
    350  */
    351 int authenticate_via_shadow_passwd(const char *uname)
    352 {
    353 	struct spwd *p_shadow_line;
    354 	char *unencrypted_password_s;
    355 	char *encrypted_password_s;
    356 
    357 	setspent();
    358 	p_shadow_line = getspnam(uname);
    359 	endspent();
    360 	if (!(p_shadow_line)) {
    361 		fprintf(stderr, _("Cannot find your entry in the shadow "
    362 				  "passwd file.\n"));
    363 		return 0;
    364 	}
    365 
    366 	/* Ask user to input unencrypted password */
    367 	if (!(unencrypted_password_s = getpass(PASSWORD_PROMPT))) {
    368 		fprintf(stderr, _("getpass cannot open /dev/tty\n"));
    369 		return 0;
    370 	}
    371 
    372 	/* Use crypt() to encrypt user's input password. */
    373 	encrypted_password_s = crypt(unencrypted_password_s,
    374 				     p_shadow_line->sp_pwdp);
    375 	memset(unencrypted_password_s, 0, strlen(unencrypted_password_s));
    376 	return (!strcmp(encrypted_password_s, p_shadow_line->sp_pwdp));
    377 }
    378 #endif				/* if/else USE_PAM */
    379 
    380 /**
    381  * This function checks to see if the shell is known in /etc/shells.
    382  * If so, it returns 1. On error or illegal shell, it returns 0.
    383  */
    384 static int verify_shell(const char *shell_name)
    385 {
    386 	int found = 0;
    387 	const char *buf;
    388 
    389 	if (!(shell_name && shell_name[0]))
    390 		return found;
    391 
    392 	while ((buf = getusershell()) != NULL) {
    393 		/* ignore comments */
    394 		if (*buf == '#')
    395 			continue;
    396 
    397 		/* check the shell skipping newline char */
    398 		if (!strcmp(shell_name, buf)) {
    399 			found = 1;
    400 			break;
    401 		}
    402 	}
    403 	endusershell();
    404 	return found;
    405 }
    406 
    407 /**
    408  * Determine the Linux user identity to re-authenticate.
    409  * If supported and set, use the login uid, as this should be more stable.
    410  * Otherwise, use the real uid.
    411  *
    412  * This function assigns malloc'd memory into the pw_copy struct.
    413  * Returns zero on success, non-zero otherwise
    414  */
    415 static int extract_pw_data(struct passwd *pw_copy)
    416 {
    417 	uid_t uid;
    418 	struct passwd *pw;
    419 
    420 #ifdef USE_AUDIT
    421 	uid = audit_getloginuid();
    422 	if (uid == (uid_t) - 1)
    423 		uid = getuid();
    424 #else
    425 	uid = getuid();
    426 #endif
    427 
    428 	setpwent();
    429 	pw = getpwuid(uid);
    430 	endpwent();
    431 	if (!(pw && pw->pw_name && pw->pw_name[0] && pw->pw_shell
    432 	      && pw->pw_shell[0] && pw->pw_dir && pw->pw_dir[0])) {
    433 		fprintf(stderr,
    434 			_("cannot find valid entry in the passwd file.\n"));
    435 		return -1;
    436 	}
    437 
    438 	*pw_copy = *pw;
    439 	pw = pw_copy;
    440 	pw->pw_name = strdup(pw->pw_name);
    441 	pw->pw_dir = strdup(pw->pw_dir);
    442 	pw->pw_shell = strdup(pw->pw_shell);
    443 
    444 	if (!(pw->pw_name && pw->pw_dir && pw->pw_shell)) {
    445 		fprintf(stderr, _("Out of memory!\n"));
    446 		goto out_free;
    447 	}
    448 
    449 	if (verify_shell(pw->pw_shell) == 0) {
    450 		fprintf(stderr, _("Error!  Shell is not valid.\n"));
    451 		goto out_free;
    452 	}
    453 	return 0;
    454 
    455       out_free:
    456 	free(pw->pw_name);
    457 	free(pw->pw_dir);
    458 	free(pw->pw_shell);
    459 	pw->pw_name = NULL;
    460 	pw->pw_dir = NULL;
    461 	pw->pw_shell = NULL;
    462 	return -1;
    463 }
    464 
    465 /**
    466  * Either restore the original environment, or set up a minimal one.
    467  *
    468  * The minimal environment contains:
    469  * TERM, DISPLAY and XAUTHORITY - if they are set, preserve values
    470  * HOME, SHELL, USER and LOGNAME - set to contents of /etc/passwd
    471  * PATH - set to default value DEFAULT_PATH
    472  *
    473  * Returns zero on success, non-zero otherwise
    474  */
    475 static int restore_environment(int preserve_environment,
    476 			       char **old_environ, const struct passwd *pw)
    477 {
    478 	char const *term_env;
    479 	char const *display_env;
    480 	char const *xauthority_env;
    481 	char *term = NULL;	/* temporary container */
    482 	char *display = NULL;	/* temporary container */
    483 	char *xauthority = NULL;	/* temporary container */
    484 	int rc;
    485 
    486 	environ = old_environ;
    487 
    488 	if (preserve_environment)
    489 		return 0;
    490 
    491 	term_env = getenv("TERM");
    492 	display_env = getenv("DISPLAY");
    493 	xauthority_env = getenv("XAUTHORITY");
    494 
    495 	/* Save the variable values we want */
    496 	if (term_env)
    497 		term = strdup(term_env);
    498 	if (display_env)
    499 		display = strdup(display_env);
    500 	if (xauthority_env)
    501 		xauthority = strdup(xauthority_env);
    502 	if ((term_env && !term) || (display_env && !display) ||
    503 	    (xauthority_env && !xauthority)) {
    504 		rc = -1;
    505 		goto out;
    506 	}
    507 
    508 	/* Construct a new environment */
    509 	if ((rc = clearenv())) {
    510 		fprintf(stderr, _("Unable to clear environment\n"));
    511 		goto out;
    512 	}
    513 
    514 	/* Restore that which we saved */
    515 	if (term)
    516 		rc |= setenv("TERM", term, 1);
    517 	if (display)
    518 		rc |= setenv("DISPLAY", display, 1);
    519 	if (xauthority)
    520 		rc |= setenv("XAUTHORITY", xauthority, 1);
    521 	rc |= setenv("HOME", pw->pw_dir, 1);
    522 	rc |= setenv("SHELL", pw->pw_shell, 1);
    523 	rc |= setenv("USER", pw->pw_name, 1);
    524 	rc |= setenv("LOGNAME", pw->pw_name, 1);
    525 	rc |= setenv("PATH", DEFAULT_PATH, 1);
    526       out:
    527 	free(term);
    528 	free(display);
    529 	free(xauthority);
    530 	return rc;
    531 }
    532 
    533 /**
    534  * This function will drop the capabilities so that we are left
    535  * only with access to the audit system. If the user is root, we leave
    536  * the capabilities alone since they already should have access to the
    537  * audit netlink socket.
    538  *
    539  * Returns zero on success, non-zero otherwise
    540  */
    541 #if defined(AUDIT_LOG_PRIV) && !defined(NAMESPACE_PRIV)
    542 static int drop_capabilities(int full)
    543 {
    544 	uid_t uid = getuid();
    545 	if (!uid) return 0;
    546 
    547 	capng_setpid(getpid());
    548 	capng_clear(CAPNG_SELECT_CAPS);
    549 
    550 	if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
    551 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
    552 		return -1;
    553 	}
    554 
    555 	/* Change uid */
    556 	if (setresuid(uid, uid, uid)) {
    557 		fprintf(stderr, _("Error changing uid, aborting.\n"));
    558 		return -1;
    559 	}
    560 
    561 	if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
    562 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
    563 		return -1;
    564 	}
    565 
    566 	if (! full)
    567 		capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_AUDIT_WRITE);
    568 	return capng_apply(CAPNG_SELECT_CAPS);
    569 }
    570 #elif defined(NAMESPACE_PRIV)
    571 /**
    572  * This function will drop the capabilities so that we are left
    573  * only with access to the audit system and the ability to raise
    574  * CAP_SYS_ADMIN, CAP_DAC_OVERRIDE, CAP_FOWNER and CAP_CHOWN,
    575  * before invoking pam_namespace.  These capabilities are needed
    576  * for performing bind mounts/unmounts and to create potential new
    577  * instance directories with appropriate DAC attributes. If the
    578  * user is root, we leave the capabilities alone since they already
    579  * should have access to the audit netlink socket and should have
    580  * the ability to create/mount/unmount instance directories.
    581  *
    582  * Returns zero on success, non-zero otherwise
    583  */
    584 static int drop_capabilities(int full)
    585 {
    586 	uid_t uid = getuid();
    587 	if (!uid) return 0;
    588 
    589 	capng_setpid(getpid());
    590 	capng_clear(CAPNG_SELECT_CAPS);
    591 
    592 	if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
    593 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
    594 		return -1;
    595 	}
    596 
    597 	/* Change uid */
    598 	if (setresuid(uid, uid, uid)) {
    599 		fprintf(stderr, _("Error changing uid, aborting.\n"));
    600 		return -1;
    601 	}
    602 
    603 	if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
    604 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
    605 		return -1;
    606 	}
    607 
    608 	if (! full)
    609 		capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_SYS_ADMIN , CAP_FOWNER , CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_AUDIT_WRITE, -1);
    610 
    611 	return capng_apply(CAPNG_SELECT_CAPS);
    612 }
    613 
    614 #else
    615 static inline int drop_capabilities(__attribute__ ((__unused__)) int full)
    616 {
    617 	return 0;
    618 }
    619 #endif
    620 
    621 #ifdef NAMESPACE_PRIV
    622 /**
    623  * This function will set the uid values to be that of caller's uid, and
    624  * will drop any privilages which maybe have been raised.
    625  */
    626 static int transition_to_caller_uid()
    627 {
    628 	uid_t uid = getuid();
    629 
    630 	if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
    631 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
    632 		return -1;
    633 	}
    634 
    635 	if (setresuid(uid, uid, uid)) {
    636 		fprintf(stderr, _("Error changing uid, aborting.\n"));
    637 		return -1;
    638 	}
    639 	return 0;
    640 }
    641 #endif
    642 
    643 #ifdef AUDIT_LOG_PRIV
    644 /* Send audit message */
    645 static
    646 int send_audit_message(int success, security_context_t old_context,
    647 		       security_context_t new_context, const char *ttyn)
    648 {
    649 	char *msg = NULL;
    650 	int rc;
    651 	int audit_fd = audit_open();
    652 
    653 	if (audit_fd < 0) {
    654 		fprintf(stderr, _("Error connecting to audit system.\n"));
    655 		return -1;
    656 	}
    657 	if (asprintf(&msg, "newrole: old-context=%s new-context=%s",
    658 		     old_context ? old_context : "?",
    659 		     new_context ? new_context : "?") < 0) {
    660 		fprintf(stderr, _("Error allocating memory.\n"));
    661 		rc = -1;
    662 		goto out;
    663 	}
    664 	rc = audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
    665 				    msg, NULL, NULL, ttyn, success);
    666 	if (rc <= 0) {
    667 		fprintf(stderr, _("Error sending audit message.\n"));
    668 		rc = -1;
    669 		goto out;
    670 	}
    671 	rc = 0;
    672       out:
    673 	free(msg);
    674 	close(audit_fd);
    675 	return rc;
    676 }
    677 #else
    678 static inline
    679     int send_audit_message(int success __attribute__ ((unused)),
    680 			   security_context_t old_context
    681 			   __attribute__ ((unused)),
    682 			   security_context_t new_context
    683 			   __attribute__ ((unused)), const char *ttyn
    684 			   __attribute__ ((unused)))
    685 {
    686 	return 0;
    687 }
    688 #endif
    689 
    690 /**
    691  * This function attempts to relabel the tty. If this function fails, then
    692  * the fd is closed, the contexts are free'd and -1 is returned. On success,
    693  * a valid fd is returned and tty_context and new_tty_context are set.
    694  *
    695  * This function will not fail if it can not relabel the tty when selinux is
    696  * in permissive mode.
    697  */
    698 static int relabel_tty(const char *ttyn, security_context_t new_context,
    699 		       security_context_t * tty_context,
    700 		       security_context_t * new_tty_context)
    701 {
    702 	int fd, rc;
    703 	int enforcing = security_getenforce();
    704 	security_context_t tty_con = NULL;
    705 	security_context_t new_tty_con = NULL;
    706 
    707 	if (!ttyn)
    708 		return 0;
    709 
    710 	if (enforcing < 0) {
    711 		fprintf(stderr, _("Could not determine enforcing mode.\n"));
    712 		return -1;
    713 	}
    714 
    715 	/* Re-open TTY descriptor */
    716 	fd = open(ttyn, O_RDWR | O_NONBLOCK);
    717 	if (fd < 0) {
    718 		fprintf(stderr, _("Error!  Could not open %s.\n"), ttyn);
    719 		return fd;
    720 	}
    721 	/* this craziness is to make sure we cann't block on open and deadlock */
    722 	rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
    723 	if (rc) {
    724 		fprintf(stderr, _("Error!  Could not clear O_NONBLOCK on %s\n"), ttyn);
    725 		close(fd);
    726 		return rc;
    727 	}
    728 
    729 	if (fgetfilecon(fd, &tty_con) < 0) {
    730 		fprintf(stderr, _("%s!  Could not get current context "
    731 				  "for %s, not relabeling tty.\n"),
    732 			enforcing ? "Error" : "Warning", ttyn);
    733 		if (enforcing)
    734 			goto close_fd;
    735 	}
    736 
    737 	if (tty_con &&
    738 	    (security_compute_relabel(new_context, tty_con,
    739 				      string_to_security_class("chr_file"), &new_tty_con) < 0)) {
    740 		fprintf(stderr, _("%s!  Could not get new context for %s, "
    741 				  "not relabeling tty.\n"),
    742 			enforcing ? "Error" : "Warning", ttyn);
    743 		if (enforcing)
    744 			goto close_fd;
    745 	}
    746 
    747 	if (new_tty_con)
    748 		if (fsetfilecon(fd, new_tty_con) < 0) {
    749 			fprintf(stderr,
    750 				_("%s!  Could not set new context for %s\n"),
    751 				enforcing ? "Error" : "Warning", ttyn);
    752 			freecon(new_tty_con);
    753 			new_tty_con = NULL;
    754 			if (enforcing)
    755 				goto close_fd;
    756 		}
    757 
    758 	*tty_context = tty_con;
    759 	*new_tty_context = new_tty_con;
    760 	return fd;
    761 
    762       close_fd:
    763 	freecon(tty_con);
    764 	close(fd);
    765 	return -1;
    766 }
    767 
    768 /**
    769  * This function attempts to revert the relabeling done to the tty.
    770  * fd   - referencing the opened ttyn
    771  * ttyn - name of tty to restore
    772  * tty_context     - original context of the tty
    773  * new_tty_context - context tty was relabeled to
    774  *
    775  * Returns zero on success, non-zero otherwise
    776  */
    777 static int restore_tty_label(int fd, const char *ttyn,
    778 			     security_context_t tty_context,
    779 			     security_context_t new_tty_context)
    780 {
    781 	int rc = 0;
    782 	security_context_t chk_tty_context = NULL;
    783 
    784 	if (!ttyn)
    785 		goto skip_relabel;
    786 
    787 	if (!new_tty_context)
    788 		goto skip_relabel;
    789 
    790 	/* Verify that the tty still has the context set by newrole. */
    791 	if ((rc = fgetfilecon(fd, &chk_tty_context)) < 0) {
    792 		fprintf(stderr, "Could not fgetfilecon %s.\n", ttyn);
    793 		goto skip_relabel;
    794 	}
    795 
    796 	if ((rc = strcmp(chk_tty_context, new_tty_context))) {
    797 		fprintf(stderr, _("%s changed labels.\n"), ttyn);
    798 		goto skip_relabel;
    799 	}
    800 
    801 	if ((rc = fsetfilecon(fd, tty_context)) < 0)
    802 		fprintf(stderr,
    803 			_("Warning! Could not restore context for %s\n"), ttyn);
    804       skip_relabel:
    805 	freecon(chk_tty_context);
    806 	return rc;
    807 }
    808 
    809 /**
    810  * Parses and validates the provided command line options and
    811  * constructs a new context based on our old context and the
    812  * arguments specified on the command line. On success
    813  * new_context will be set to valid values, otherwise its value
    814  * is left unchanged.
    815  *
    816  * Returns zero on success, non-zero otherwise.
    817  */
    818 static int parse_command_line_arguments(int argc, char **argv, char *ttyn,
    819 					security_context_t old_context,
    820 					security_context_t * new_context,
    821 					int *preserve_environment)
    822 {
    823 	int flag_index;		/* flag index in argv[] */
    824 	int clflag;		/* holds codes for command line flags */
    825 	char *role_s = NULL;	/* role spec'd by user in argv[] */
    826 	char *type_s = NULL;	/* type spec'd by user in argv[] */
    827 	char *type_ptr = NULL;	/* stores malloc'd data from get_default_type */
    828 	char *level_s = NULL;	/* level spec'd by user in argv[] */
    829 	char *range_ptr = NULL;
    830 	security_context_t new_con = NULL;
    831 	security_context_t tty_con = NULL;
    832 	context_t context = NULL;	/* manipulatable form of new_context */
    833 	const struct option long_options[] = {
    834 		{"role", 1, 0, 'r'},
    835 		{"type", 1, 0, 't'},
    836 		{"level", 1, 0, 'l'},
    837 		{"preserve-environment", 0, 0, 'p'},
    838 		{"version", 0, 0, 'V'},
    839 		{NULL, 0, 0, 0}
    840 	};
    841 
    842 	*preserve_environment = 0;
    843 	while (1) {
    844 		clflag = getopt_long(argc, argv, "r:t:l:pV", long_options,
    845 				     &flag_index);
    846 		if (clflag == -1)
    847 			break;
    848 
    849 		switch (clflag) {
    850 		case 'V':
    851 			printf("newrole: %s version %s\n", PACKAGE, VERSION);
    852 			exit(0);
    853 			break;
    854 		case 'p':
    855 			*preserve_environment = 1;
    856 			break;
    857 		case 'r':
    858 			if (role_s) {
    859 				fprintf(stderr,
    860 					_("Error: multiple roles specified\n"));
    861 				return -1;
    862 			}
    863 			role_s = optarg;
    864 			break;
    865 		case 't':
    866 			if (type_s) {
    867 				fprintf(stderr,
    868 					_("Error: multiple types specified\n"));
    869 				return -1;
    870 			}
    871 			type_s = optarg;
    872 			break;
    873 		case 'l':
    874 			if (!is_selinux_mls_enabled()) {
    875 				fprintf(stderr, _("Sorry, -l may be used with "
    876 						  "SELinux MLS support.\n"));
    877 				return -1;
    878 			}
    879 			if (level_s) {
    880 				fprintf(stderr, _("Error: multiple levels "
    881 						  "specified\n"));
    882 				return -1;
    883 			}
    884 			if (ttyn) {
    885 				if (fgetfilecon(STDIN_FILENO, &tty_con) >= 0) {
    886 					if (selinux_check_securetty_context
    887 					    (tty_con) < 0) {
    888 						fprintf(stderr,
    889 							_
    890 							("Error: you are not allowed to change levels on a non secure terminal \n"));
    891 						freecon(tty_con);
    892 						return -1;
    893 					}
    894 					freecon(tty_con);
    895 				}
    896 			}
    897 
    898 			level_s = optarg;
    899 			break;
    900 		default:
    901 			fprintf(stderr, "%s\n", USAGE_STRING);
    902 			return -1;
    903 		}
    904 	}
    905 
    906 	/* Verify that the combination of command-line arguments are viable */
    907 	if (!(role_s || type_s || level_s)) {
    908 		fprintf(stderr, "%s\n", USAGE_STRING);
    909 		return -1;
    910 	}
    911 
    912 	/* Fill in a default type if one hasn't been specified. */
    913 	if (role_s && !type_s) {
    914 		/* get_default_type() returns malloc'd memory */
    915 		if (get_default_type(role_s, &type_ptr)) {
    916 			fprintf(stderr, _("Couldn't get default type.\n"));
    917 			send_audit_message(0, old_context, new_con, ttyn);
    918 			return -1;
    919 		}
    920 		type_s = type_ptr;
    921 	}
    922 
    923 	/* Create a temporary new context structure we extract and modify */
    924 	context = context_new(old_context);
    925 	if (!context) {
    926 		fprintf(stderr, _("failed to get new context.\n"));
    927 		goto err_free;
    928 	}
    929 
    930 	/* Modify the temporary new context */
    931 	if (role_s)
    932 		if (context_role_set(context, role_s)) {
    933 			fprintf(stderr, _("failed to set new role %s\n"),
    934 				role_s);
    935 			goto err_free;
    936 		}
    937 
    938 	if (type_s)
    939 		if (context_type_set(context, type_s)) {
    940 			fprintf(stderr, _("failed to set new type %s\n"),
    941 				type_s);
    942 			goto err_free;
    943 		}
    944 
    945 	if (level_s) {
    946 		range_ptr =
    947 		    build_new_range(level_s, context_range_get(context));
    948 		if (!range_ptr) {
    949 			fprintf(stderr,
    950 				_("failed to build new range with level %s\n"),
    951 				level_s);
    952 			goto err_free;
    953 		}
    954 		if (context_range_set(context, range_ptr)) {
    955 			fprintf(stderr, _("failed to set new range %s\n"),
    956 				range_ptr);
    957 			goto err_free;
    958 		}
    959 	}
    960 
    961 	/* Construct the final new context */
    962 	if (!(new_con = context_str(context))) {
    963 		fprintf(stderr, _("failed to convert new context to string\n"));
    964 		goto err_free;
    965 	}
    966 
    967 	if (security_check_context(new_con) < 0) {
    968 		fprintf(stderr, _("%s is not a valid context\n"), new_con);
    969 		send_audit_message(0, old_context, new_con, ttyn);
    970 		goto err_free;
    971 	}
    972 
    973 	*new_context = strdup(new_con);
    974 	if (!*new_context) {
    975 		fprintf(stderr, _("Unable to allocate memory for new_context"));
    976 		goto err_free;
    977 	}
    978 
    979 	free(type_ptr);
    980 	free(range_ptr);
    981 	context_free(context);
    982 	return 0;
    983 
    984       err_free:
    985 	free(type_ptr);
    986 	free(range_ptr);
    987 	/* Don't free new_con, context_free(context) handles this */
    988 	context_free(context);
    989 	return -1;
    990 }
    991 
    992 /**
    993  * Take care of any signal setup
    994  */
    995 static int set_signal_handles(void)
    996 {
    997 	sigset_t empty;
    998 
    999 	/* Empty the signal mask in case someone is blocking a signal */
   1000 	if (sigemptyset(&empty)) {
   1001 		fprintf(stderr, _("Unable to obtain empty signal set\n"));
   1002 		return -1;
   1003 	}
   1004 
   1005 	(void)sigprocmask(SIG_SETMASK, &empty, NULL);
   1006 
   1007 	/* Terminate on SIGHUP. */
   1008 	if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
   1009 		fprintf(stderr, _("Unable to set SIGHUP handler\n"));
   1010 		return -1;
   1011 	}
   1012 
   1013 	return 0;
   1014 }
   1015 
   1016 /************************************************************************
   1017  *
   1018  * All code used for both PAM and shadow passwd goes in this section.
   1019  *
   1020  ************************************************************************/
   1021 
   1022 int main(int argc, char *argv[])
   1023 {
   1024 	security_context_t new_context = NULL;	/* target security context */
   1025 	security_context_t old_context = NULL;	/* original securiy context */
   1026 	security_context_t tty_context = NULL;	/* current context of tty */
   1027 	security_context_t new_tty_context = NULL;	/* new context of tty */
   1028 
   1029 	struct passwd pw;	/* struct derived from passwd file line */
   1030 	char *ttyn = NULL;	/* tty path */
   1031 
   1032 	char **old_environ;
   1033 	int preserve_environment;
   1034 
   1035 	int fd;
   1036 	pid_t childPid = 0;
   1037 	char *shell_argv0 = NULL;
   1038 	int rc;
   1039 
   1040 #ifdef USE_PAM
   1041 	int pam_status;		/* pam return code */
   1042 	pam_handle_t *pam_handle;	/* opaque handle used by all PAM functions */
   1043 
   1044 	/* This is a jump table of functions for PAM to use when it wants to *
   1045 	 * communicate with the user.  We'll be using misc_conv(), which is  *
   1046 	 * provided for us via pam_misc.h.                                   */
   1047 	struct pam_conv pam_conversation = {
   1048 		misc_conv,
   1049 		NULL
   1050 	};
   1051 #endif
   1052 
   1053 	/*
   1054 	 * Step 0: Setup
   1055 	 *
   1056 	 * Do some intial setup, including dropping capabilities, checking
   1057 	 * if it makes sense to continue to run newrole, and setting up
   1058 	 * a scrubbed environment.
   1059 	 */
   1060 	if (drop_capabilities(FALSE)) {
   1061 		perror(_("Sorry, newrole failed to drop capabilities\n"));
   1062 		return -1;
   1063 	}
   1064 	if (set_signal_handles())
   1065 		return -1;
   1066 
   1067 #ifdef USE_NLS
   1068 	setlocale(LC_ALL, "");
   1069 	bindtextdomain(PACKAGE, LOCALEDIR);
   1070 	textdomain(PACKAGE);
   1071 #endif
   1072 
   1073 	old_environ = environ;
   1074 	environ = NULL;
   1075 
   1076 	if (!is_selinux_enabled()) {
   1077 		fprintf(stderr, _("Sorry, newrole may be used only on "
   1078 				  "a SELinux kernel.\n"));
   1079 		return -1;
   1080 	}
   1081 
   1082 	if (security_getenforce() < 0) {
   1083 		fprintf(stderr, _("Could not determine enforcing mode.\n"));
   1084 		return -1;
   1085 	}
   1086 
   1087 	/*
   1088 	 * Step 1: Parse command line and valid arguments
   1089 	 *
   1090 	 * old_context and ttyn are required for audit logging,
   1091 	 * context validation and pam
   1092 	 */
   1093 	if (getprevcon(&old_context)) {
   1094 		fprintf(stderr, _("failed to get old_context.\n"));
   1095 		return -1;
   1096 	}
   1097 
   1098 	ttyn = ttyname(STDIN_FILENO);
   1099 	if (!ttyn || *ttyn == '\0') {
   1100 		fprintf(stderr,
   1101 			_("Warning!  Could not retrieve tty information.\n"));
   1102 	}
   1103 
   1104 	if (parse_command_line_arguments(argc, argv, ttyn, old_context,
   1105 					 &new_context, &preserve_environment))
   1106 		return -1;
   1107 
   1108 	/*
   1109 	 * Step 2:  Authenticate the user.
   1110 	 *
   1111 	 * Re-authenticate the user running this program.
   1112 	 * This is just to help confirm user intent (vs. invocation by
   1113 	 * malicious software), not to authorize the operation (which is covered
   1114 	 * by policy).  Trusted path mechanism would be preferred.
   1115 	 */
   1116 	memset(&pw, 0, sizeof(pw));
   1117 	if (extract_pw_data(&pw))
   1118 		goto err_free;
   1119 
   1120 #ifdef USE_PAM
   1121 	if (read_pam_config()) {
   1122 		fprintf(stderr,
   1123 			_("error on reading PAM service configuration.\n"));
   1124 		goto err_free;
   1125 	}
   1126 
   1127 	if (app_service_names != NULL && optind < argc) {
   1128 		if (strcmp(argv[optind], "-c") == 0 && optind < (argc - 1)) {
   1129 			/*
   1130 			 * Check for a separate pam service name for the
   1131 			 * command when invoked by newrole.
   1132 			 */
   1133 			char *cmd = NULL;
   1134 			rc = sscanf(argv[optind + 1], "%ms", &cmd);
   1135 			if (rc != EOF && cmd) {
   1136 				char *app_service_name =
   1137 				    (char *)hashtab_search(app_service_names,
   1138 							   cmd);
   1139 				free(cmd);
   1140 				if (app_service_name != NULL)
   1141 					service_name = app_service_name;
   1142 			}
   1143 		}
   1144 	}
   1145 
   1146 	pam_status = pam_start(service_name, pw.pw_name, &pam_conversation,
   1147 			       &pam_handle);
   1148 	if (pam_status != PAM_SUCCESS) {
   1149 		fprintf(stderr, _("failed to initialize PAM\n"));
   1150 		goto err_free;
   1151 	}
   1152 
   1153 	if (!authenticate_via_pam(ttyn, pam_handle))
   1154 #else
   1155 	if (!authenticate_via_shadow_passwd(pw.pw_name))
   1156 #endif
   1157 	{
   1158 		fprintf(stderr, _("newrole: incorrect password for %s\n"),
   1159 			pw.pw_name);
   1160 		send_audit_message(0, old_context, new_context, ttyn);
   1161 		goto err_close_pam;
   1162 	}
   1163 
   1164 	/*
   1165 	 * Step 3:  Handle relabeling of the tty.
   1166 	 *
   1167 	 * Once we authenticate the user, we know that we want to proceed with
   1168 	 * the action. Prior to this point, no changes are made the to system.
   1169 	 */
   1170 	fd = relabel_tty(ttyn, new_context, &tty_context, &new_tty_context);
   1171 	if (fd < 0)
   1172 		goto err_close_pam;
   1173 
   1174 	/*
   1175 	 * Step 4: Fork
   1176 	 *
   1177 	 * Fork, allowing parent to clean up after shell has executed.
   1178 	 * Child: reopen stdin, stdout, stderr and exec shell
   1179 	 * Parnet: wait for child to die and restore tty's context
   1180 	 */
   1181 	childPid = fork();
   1182 	if (childPid < 0) {
   1183 		/* fork failed, no child to worry about */
   1184 		int errsv = errno;
   1185 		fprintf(stderr, _("newrole: failure forking: %s"),
   1186 			strerror(errsv));
   1187 		if (restore_tty_label(fd, ttyn, tty_context, new_tty_context))
   1188 			fprintf(stderr, _("Unable to restore tty label...\n"));
   1189 		if (close(fd))
   1190 			fprintf(stderr, _("Failed to close tty properly\n"));
   1191 		goto err_close_pam;
   1192 	} else if (childPid) {
   1193 		/* PARENT
   1194 		 * It doesn't make senes to exit early on errors at this point,
   1195 		 * since we are doing cleanup which needs to be done.
   1196 		 * We can exit with a bad rc though
   1197 		 */
   1198 		pid_t pid;
   1199 		int exit_code = 0;
   1200 		int status;
   1201 
   1202 		do {
   1203 			pid = wait(&status);
   1204 		} while (pid < 0 && errno == EINTR);
   1205 
   1206 		/* Preserve child exit status, unless there is another error. */
   1207 		if (WIFEXITED(status))
   1208 			exit_code = WEXITSTATUS(status);
   1209 
   1210 		if (restore_tty_label(fd, ttyn, tty_context, new_tty_context)) {
   1211 			fprintf(stderr, _("Unable to restore tty label...\n"));
   1212 			exit_code = -1;
   1213 		}
   1214 		freecon(tty_context);
   1215 		freecon(new_tty_context);
   1216 		if (close(fd)) {
   1217 			fprintf(stderr, _("Failed to close tty properly\n"));
   1218 			exit_code = -1;
   1219 		}
   1220 #ifdef USE_PAM
   1221 #ifdef NAMESPACE_PRIV
   1222 		pam_status = pam_close_session(pam_handle, 0);
   1223 		if (pam_status != PAM_SUCCESS) {
   1224 			fprintf(stderr, "pam_close_session failed with %s\n",
   1225 				pam_strerror(pam_handle, pam_status));
   1226 			exit_code = -1;
   1227 		}
   1228 #endif
   1229 		rc = pam_end(pam_handle, pam_status);
   1230 		if (rc != PAM_SUCCESS) {
   1231 			fprintf(stderr, "pam_end failed with %s\n",
   1232 				pam_strerror(pam_handle, rc));
   1233 			exit_code = -1;
   1234 		}
   1235 		hashtab_map(app_service_names, free_hashtab_entry, NULL);
   1236 		hashtab_destroy(app_service_names);
   1237 #endif
   1238 		free(pw.pw_name);
   1239 		free(pw.pw_dir);
   1240 		free(pw.pw_shell);
   1241 		free(shell_argv0);
   1242 		return exit_code;
   1243 	}
   1244 
   1245 	/* CHILD */
   1246 	/* Close the tty and reopen descriptors 0 through 2 */
   1247 	if (ttyn) {
   1248 		if (close(fd) || close(0) || close(1) || close(2)) {
   1249 			fprintf(stderr, _("Could not close descriptors.\n"));
   1250 			goto err_close_pam;
   1251 		}
   1252 		fd = open(ttyn, O_RDWR | O_NONBLOCK);
   1253 		if (fd != 0)
   1254 			goto err_close_pam;
   1255 		rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
   1256 		if (rc)
   1257 			goto err_close_pam;
   1258 
   1259 		fd = open(ttyn, O_RDWR | O_NONBLOCK);
   1260 		if (fd != 1)
   1261 			goto err_close_pam;
   1262 		rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
   1263 		if (rc)
   1264 			goto err_close_pam;
   1265 
   1266 		fd = open(ttyn, O_RDWR | O_NONBLOCK);
   1267 		if (fd != 2)
   1268 			goto err_close_pam;
   1269 		rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
   1270 		if (rc)
   1271 			goto err_close_pam;
   1272 
   1273 	}
   1274 	/*
   1275 	 * Step 5:  Execute a new shell with the new context in `new_context'.
   1276 	 *
   1277 	 * Establish context, namesapce and any options for the new shell
   1278 	 */
   1279 	if (optind < 1)
   1280 		optind = 1;
   1281 
   1282 	/* This is ugly, but use newrole's argv for the exec'd shells argv */
   1283 	if (asprintf(&shell_argv0, "-%s", pw.pw_shell) < 0) {
   1284 		fprintf(stderr, _("Error allocating shell's argv0.\n"));
   1285 		shell_argv0 = NULL;
   1286 		goto err_close_pam;
   1287 	}
   1288 	argv[optind - 1] = shell_argv0;
   1289 
   1290 	if (setexeccon(new_context)) {
   1291 		fprintf(stderr, _("Could not set exec context to %s.\n"),
   1292 			new_context);
   1293 		goto err_close_pam;
   1294 	}
   1295 #ifdef NAMESPACE_PRIV
   1296 	/* Ask PAM to setup session for user running this program */
   1297 	pam_status = pam_open_session(pam_handle, 0);
   1298 	if (pam_status != PAM_SUCCESS) {
   1299 		fprintf(stderr, "pam_open_session failed with %s\n",
   1300 			pam_strerror(pam_handle, pam_status));
   1301 		goto err_close_pam;
   1302 	}
   1303 #endif
   1304 
   1305 	if (send_audit_message(1, old_context, new_context, ttyn)) {
   1306 		fprintf(stderr, _("Failed to send audit message"));
   1307 		goto err_close_pam_session;
   1308 	}
   1309 	freecon(old_context); old_context=NULL;
   1310 	freecon(new_context); new_context=NULL;
   1311 
   1312 #ifdef NAMESPACE_PRIV
   1313 	if (transition_to_caller_uid()) {
   1314 		fprintf(stderr, _("Failed to transition to namespace\n"));
   1315 		goto err_close_pam_session;
   1316 	}
   1317 #endif
   1318 
   1319 	if (drop_capabilities(TRUE)) {
   1320 		fprintf(stderr, _("Failed to drop capabilities %m\n"));
   1321 		goto err_close_pam_session;
   1322 	}
   1323 	/* Handle environment changes */
   1324 	if (restore_environment(preserve_environment, old_environ, &pw)) {
   1325 		fprintf(stderr, _("Unable to restore the environment, "
   1326 				  "aborting\n"));
   1327 		goto err_close_pam_session;
   1328 	}
   1329 	execv(pw.pw_shell, argv + optind - 1);
   1330 
   1331 	/*
   1332 	 * Error path cleanup
   1333 	 *
   1334 	 * If we reach here, then we failed to exec the new shell.
   1335 	 */
   1336 	perror(_("failed to exec shell\n"));
   1337       err_close_pam_session:
   1338 #ifdef NAMESPACE_PRIV
   1339 	pam_status = pam_close_session(pam_handle, 0);
   1340 	if (pam_status != PAM_SUCCESS)
   1341 		fprintf(stderr, "pam_close_session failed with %s\n",
   1342 			pam_strerror(pam_handle, pam_status));
   1343 #endif
   1344       err_close_pam:
   1345 #ifdef USE_PAM
   1346 	rc = pam_end(pam_handle, pam_status);
   1347 	if (rc != PAM_SUCCESS)
   1348 		fprintf(stderr, "pam_end failed with %s\n",
   1349 			pam_strerror(pam_handle, rc));
   1350 #endif
   1351       err_free:
   1352 	freecon(tty_context);
   1353 	freecon(new_tty_context);
   1354 	freecon(old_context);
   1355 	freecon(new_context);
   1356 	free(pw.pw_name);
   1357 	free(pw.pw_dir);
   1358 	free(pw.pw_shell);
   1359 	free(shell_argv0);
   1360 #ifdef USE_PAM
   1361 	if (app_service_names) {
   1362 		hashtab_map(app_service_names, free_hashtab_entry, NULL);
   1363 		hashtab_destroy(app_service_names);
   1364 	}
   1365 #endif
   1366 	return -1;
   1367 }				/* main() */
   1368