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@redhat.com>
43  *	Darrel Goeddel <DGoeddel@trustedcs.com>
44  *	Michael Thompson <mcthomps@us.ibm.com>
45  *	Dan Walsh <dwalsh@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  */
build_new_range(char * newlevel,const char * range)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  */
authenticate_via_pam(const char * ttyn,pam_handle_t * pam_handle)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 
free_hashtab_entry(hashtab_key_t key,hashtab_datum_t d,void * args)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 
reqsymhash(hashtab_t h,const_hashtab_key_t key)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 
reqsymcmp(hashtab_t h,const_hashtab_key_t key1,const_hashtab_key_t key2)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 
process_pam_config(FILE * cfg)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  */
read_pam_config(void)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  */
authenticate_via_shadow_passwd(const char * uname)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  */
verify_shell(const char * shell_name)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  */
extract_pw_data(struct passwd * pw_copy)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  */
restore_environment(int preserve_environment,char ** old_environ,const struct passwd * pw)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)
drop_capabilities(int full)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  */
drop_capabilities(int full)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
drop_capabilities(int full)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  */
transition_to_caller_uid()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
send_audit_message(int success,security_context_t old_context,security_context_t new_context,const char * ttyn)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
send_audit_message(int success,security_context_t old_context,security_context_t new_context,const char * ttyn)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  */
relabel_tty(const char * ttyn,security_context_t new_context,security_context_t * tty_context,security_context_t * new_tty_context)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  */
restore_tty_label(int fd,const char * ttyn,security_context_t tty_context,security_context_t new_tty_context)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  */
parse_command_line_arguments(int argc,char ** argv,char * ttyn,security_context_t old_context,security_context_t * new_context,int * preserve_environment)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  */
set_signal_handles(void)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 
main(int argc,char * argv[])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