• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) || (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,hashtab_key_t key)231 static unsigned int reqsymhash(hashtab_t h, 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,hashtab_key_t key1,hashtab_key_t key2)246 static int reqsymcmp(hashtab_t h
247 		     __attribute__ ((unused)), hashtab_key_t key1,
248 		     hashtab_key_t key2)
249 {
250 	char *keyp1, *keyp2;
251 
252 	keyp1 = (char *)key1;
253 	keyp2 = (char *)key2;
254 	return strcmp(keyp1, keyp2);
255 }
256 
257 static hashtab_t app_service_names = NULL;
258 #define PAM_SERVICE_SLOTS 64
259 
process_pam_config(FILE * cfg)260 static int process_pam_config(FILE * cfg)
261 {
262 	const char *config_file_path = PAM_SERVICE_CONFIG;
263 	char *line_buf = NULL;
264 	unsigned long lineno = 0;
265 	size_t len = 0;
266 	char *app = NULL;
267 	char *service = NULL;
268 	int ret;
269 
270 	while (getline(&line_buf, &len, cfg) > 0) {
271 		char *buffer = line_buf;
272 		lineno++;
273 		while (isspace(*buffer))
274 			buffer++;
275 		if (buffer[0] == '#')
276 			continue;
277 		if (buffer[0] == '\n' || buffer[0] == '\0')
278 			continue;
279 
280 		app = service = NULL;
281 		ret = sscanf(buffer, "%ms %ms\n", &app, &service);
282 		if (ret < 2 || !app || !service)
283 			goto err;
284 
285 		ret = hashtab_insert(app_service_names, app, service);
286 		if (ret == HASHTAB_OVERFLOW) {
287 			fprintf(stderr,
288 				_
289 				("newrole: service name configuration hashtable overflow\n"));
290 			goto err;
291 		}
292 	}
293 
294 	free(line_buf);
295 	return 0;
296       err:
297 	free(app);
298 	free(service);
299 	fprintf(stderr, _("newrole:  %s:  error on line %lu.\n"),
300 		config_file_path, lineno);
301 	free(line_buf);
302 	return -1;
303 }
304 
305 /*
306  *  Read config file ignoring comment lines.
307  *  Files specified one per line executable with a corresponding
308  *  pam service name.
309  */
read_pam_config(void)310 static int read_pam_config(void)
311 {
312 	const char *config_file_path = PAM_SERVICE_CONFIG;
313 	FILE *cfg = NULL;
314 	cfg = fopen(config_file_path, "r");
315 	if (!cfg)
316 		return 0;	/* This configuration is optional. */
317 	app_service_names =
318 	    hashtab_create(reqsymhash, reqsymcmp, PAM_SERVICE_SLOTS);
319 	if (!app_service_names)
320 		goto err;
321 	if (process_pam_config(cfg))
322 		goto err;
323 	fclose(cfg);
324 	return 0;
325       err:
326 	fclose(cfg);
327 	return -1;
328 }
329 
330 #else				/* else !USE_PAM */
331 
332 /************************************************************************
333  *
334  * All shadow passwd code goes in this section.
335  *
336  ************************************************************************/
337 #include <shadow.h>		/* for shadow passwd functions */
338 #include <string.h>		/* for strlen(), memset() */
339 
340 #define PASSWORD_PROMPT _("Password:")	/* prompt for getpass() */
341 
342 /* authenticate_via_shadow_passwd()
343  *
344  * in:     uname - the calling user's user name
345  * out:    nothing
346  * return: value   condition
347  *         -----   ---------
348  *           1     user authenticated themselves properly according to the
349  *                 shadow passwd file.
350  *           0     otherwise
351  *
352  * This function uses the shadow passwd file to thenticate the user running
353  * this program.
354  */
authenticate_via_shadow_passwd(const char * uname)355 int authenticate_via_shadow_passwd(const char *uname)
356 {
357 	struct spwd *p_shadow_line;
358 	char *unencrypted_password_s;
359 	char *encrypted_password_s;
360 
361 	setspent();
362 	p_shadow_line = getspnam(uname);
363 	endspent();
364 	if (!(p_shadow_line)) {
365 		fprintf(stderr, _("Cannot find your entry in the shadow "
366 				  "passwd file.\n"));
367 		return 0;
368 	}
369 
370 	/* Ask user to input unencrypted password */
371 	if (!(unencrypted_password_s = getpass(PASSWORD_PROMPT))) {
372 		fprintf(stderr, _("getpass cannot open /dev/tty\n"));
373 		return 0;
374 	}
375 
376 	/* Use crypt() to encrypt user's input password. */
377 	encrypted_password_s = crypt(unencrypted_password_s,
378 				     p_shadow_line->sp_pwdp);
379 	memset(unencrypted_password_s, 0, strlen(unencrypted_password_s));
380 	return (!strcmp(encrypted_password_s, p_shadow_line->sp_pwdp));
381 }
382 #endif				/* if/else USE_PAM */
383 
384 /**
385  * This function checks to see if the shell is known in /etc/shells.
386  * If so, it returns 1. On error or illegal shell, it returns 0.
387  */
verify_shell(const char * shell_name)388 static int verify_shell(const char *shell_name)
389 {
390 	int found = 0;
391 	const char *buf;
392 
393 	if (!(shell_name && shell_name[0]))
394 		return found;
395 
396 	while ((buf = getusershell()) != NULL) {
397 		/* ignore comments */
398 		if (*buf == '#')
399 			continue;
400 
401 		/* check the shell skipping newline char */
402 		if (!strcmp(shell_name, buf)) {
403 			found = 1;
404 			break;
405 		}
406 	}
407 	endusershell();
408 	return found;
409 }
410 
411 /**
412  * Determine the Linux user identity to re-authenticate.
413  * If supported and set, use the login uid, as this should be more stable.
414  * Otherwise, use the real uid.
415  *
416  * This function assigns malloc'd memory into the pw_copy struct.
417  * Returns zero on success, non-zero otherwise
418  */
extract_pw_data(struct passwd * pw_copy)419 int extract_pw_data(struct passwd *pw_copy)
420 {
421 	uid_t uid;
422 	struct passwd *pw;
423 
424 #ifdef USE_AUDIT
425 	uid = audit_getloginuid();
426 	if (uid == (uid_t) - 1)
427 		uid = getuid();
428 #else
429 	uid = getuid();
430 #endif
431 
432 	setpwent();
433 	pw = getpwuid(uid);
434 	endpwent();
435 	if (!(pw && pw->pw_name && pw->pw_name[0] && pw->pw_shell
436 	      && pw->pw_shell[0] && pw->pw_dir && pw->pw_dir[0])) {
437 		fprintf(stderr,
438 			_("cannot find valid entry in the passwd file.\n"));
439 		return -1;
440 	}
441 
442 	*pw_copy = *pw;
443 	pw = pw_copy;
444 	pw->pw_name = strdup(pw->pw_name);
445 	pw->pw_dir = strdup(pw->pw_dir);
446 	pw->pw_shell = strdup(pw->pw_shell);
447 
448 	if (!(pw->pw_name && pw->pw_dir && pw->pw_shell)) {
449 		fprintf(stderr, _("Out of memory!\n"));
450 		goto out_free;
451 	}
452 
453 	if (verify_shell(pw->pw_shell) == 0) {
454 		fprintf(stderr, _("Error!  Shell is not valid.\n"));
455 		goto out_free;
456 	}
457 	return 0;
458 
459       out_free:
460 	free(pw->pw_name);
461 	free(pw->pw_dir);
462 	free(pw->pw_shell);
463 	return -1;
464 }
465 
466 /**
467  * Either restore the original environment, or set up a minimal one.
468  *
469  * The minimal environment contains:
470  * TERM, DISPLAY and XAUTHORITY - if they are set, preserve values
471  * HOME, SHELL, USER and LOGNAME - set to contents of /etc/passwd
472  * PATH - set to default value DEFAULT_PATH
473  *
474  * Returns zero on success, non-zero otherwise
475  */
restore_environment(int preserve_environment,char ** old_environ,const struct passwd * pw)476 static int restore_environment(int preserve_environment,
477 			       char **old_environ, const struct passwd *pw)
478 {
479 	char const *term_env;
480 	char const *display_env;
481 	char const *xauthority_env;
482 	char *term = NULL;	/* temporary container */
483 	char *display = NULL;	/* temporary container */
484 	char *xauthority = NULL;	/* temporary container */
485 	int rc;
486 
487 	environ = old_environ;
488 
489 	if (preserve_environment)
490 		return 0;
491 
492 	term_env = getenv("TERM");
493 	display_env = getenv("DISPLAY");
494 	xauthority_env = getenv("XAUTHORITY");
495 
496 	/* Save the variable values we want */
497 	if (term_env)
498 		term = strdup(term_env);
499 	if (display_env)
500 		display = strdup(display_env);
501 	if (xauthority_env)
502 		xauthority = strdup(xauthority_env);
503 	if ((term_env && !term) || (display_env && !display) ||
504 	    (xauthority_env && !xauthority)) {
505 		rc = -1;
506 		goto out;
507 	}
508 
509 	/* Construct a new environment */
510 	if ((rc = clearenv())) {
511 		fprintf(stderr, _("Unable to clear environment\n"));
512 		goto out;
513 	}
514 
515 	/* Restore that which we saved */
516 	if (term)
517 		rc |= setenv("TERM", term, 1);
518 	if (display)
519 		rc |= setenv("DISPLAY", display, 1);
520 	if (xauthority)
521 		rc |= setenv("XAUTHORITY", xauthority, 1);
522 	rc |= setenv("HOME", pw->pw_dir, 1);
523 	rc |= setenv("SHELL", pw->pw_shell, 1);
524 	rc |= setenv("USER", pw->pw_name, 1);
525 	rc |= setenv("LOGNAME", pw->pw_name, 1);
526 	rc |= setenv("PATH", DEFAULT_PATH, 1);
527       out:
528 	free(term);
529 	free(display);
530 	free(xauthority);
531 	return rc;
532 }
533 
534 /**
535  * This function will drop the capabilities so that we are left
536  * only with access to the audit system. If the user is root, we leave
537  * the capabilities alone since they already should have access to the
538  * audit netlink socket.
539  *
540  * Returns zero on success, non-zero otherwise
541  */
542 #if defined(AUDIT_LOG_PRIV) && !defined(NAMESPACE_PRIV)
drop_capabilities(int full)543 static int drop_capabilities(int full)
544 {
545 	uid_t uid = getuid();
546 	if (!uid) return 0;
547 
548 	capng_setpid(getpid());
549 	capng_clear(CAPNG_SELECT_CAPS);
550 
551 	if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
552 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
553 		return -1;
554 	}
555 
556 	/* Change uid */
557 	if (setresuid(uid, uid, uid)) {
558 		fprintf(stderr, _("Error changing uid, aborting.\n"));
559 		return -1;
560 	}
561 
562 	if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
563 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
564 		return -1;
565 	}
566 
567 	if (! full)
568 		capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_AUDIT_WRITE);
569 	return capng_apply(CAPNG_SELECT_CAPS);
570 }
571 #elif defined(NAMESPACE_PRIV)
572 /**
573  * This function will drop the capabilities so that we are left
574  * only with access to the audit system and the ability to raise
575  * CAP_SYS_ADMIN, CAP_DAC_OVERRIDE, CAP_FOWNER and CAP_CHOWN,
576  * before invoking pam_namespace.  These capabilities are needed
577  * for performing bind mounts/unmounts and to create potential new
578  * instance directories with appropriate DAC attributes. If the
579  * user is root, we leave the capabilities alone since they already
580  * should have access to the audit netlink socket and should have
581  * the ability to create/mount/unmount instance directories.
582  *
583  * Returns zero on success, non-zero otherwise
584  */
drop_capabilities(int full)585 static int drop_capabilities(int full)
586 {
587 	uid_t uid = getuid();
588 	if (!uid) return 0;
589 
590 	capng_setpid(getpid());
591 	capng_clear(CAPNG_SELECT_CAPS);
592 
593 	if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
594 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
595 		return -1;
596 	}
597 
598 	/* Change uid */
599 	if (setresuid(uid, uid, uid)) {
600 		fprintf(stderr, _("Error changing uid, aborting.\n"));
601 		return -1;
602 	}
603 
604 	if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
605 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
606 		return -1;
607 	}
608 
609 	if (! full)
610 		capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_SYS_ADMIN , CAP_FOWNER , CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_AUDIT_WRITE, -1);
611 
612 	return capng_apply(CAPNG_SELECT_CAPS);
613 }
614 
615 #else
drop_capabilities(int full)616 static inline int drop_capabilities(__attribute__ ((__unused__)) int full)
617 {
618 	return 0;
619 }
620 #endif
621 
622 #ifdef NAMESPACE_PRIV
623 /**
624  * This function will set the uid values to be that of caller's uid, and
625  * will drop any privilages which maybe have been raised.
626  */
transition_to_caller_uid()627 static int transition_to_caller_uid()
628 {
629 	uid_t uid = getuid();
630 
631 	if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
632 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
633 		return -1;
634 	}
635 
636 	if (setresuid(uid, uid, uid)) {
637 		fprintf(stderr, _("Error changing uid, aborting.\n"));
638 		return -1;
639 	}
640 	return 0;
641 }
642 #endif
643 
644 #ifdef AUDIT_LOG_PRIV
645 /* Send audit message */
646 static
send_audit_message(int success,security_context_t old_context,security_context_t new_context,const char * ttyn)647 int send_audit_message(int success, security_context_t old_context,
648 		       security_context_t new_context, const char *ttyn)
649 {
650 	char *msg = NULL;
651 	int rc;
652 	int audit_fd = audit_open();
653 
654 	if (audit_fd < 0) {
655 		fprintf(stderr, _("Error connecting to audit system.\n"));
656 		return -1;
657 	}
658 	if (asprintf(&msg, "newrole: old-context=%s new-context=%s",
659 		     old_context ? old_context : "?",
660 		     new_context ? new_context : "?") < 0) {
661 		fprintf(stderr, _("Error allocating memory.\n"));
662 		rc = -1;
663 		goto out;
664 	}
665 	rc = audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
666 				    msg, NULL, NULL, ttyn, success);
667 	if (rc <= 0) {
668 		fprintf(stderr, _("Error sending audit message.\n"));
669 		rc = -1;
670 		goto out;
671 	}
672 	rc = 0;
673       out:
674 	free(msg);
675 	close(audit_fd);
676 	return rc;
677 }
678 #else
679 static inline
send_audit_message(int success,security_context_t old_context,security_context_t new_context,const char * ttyn)680     int send_audit_message(int success __attribute__ ((unused)),
681 			   security_context_t old_context
682 			   __attribute__ ((unused)),
683 			   security_context_t new_context
684 			   __attribute__ ((unused)), const char *ttyn
685 			   __attribute__ ((unused)))
686 {
687 	return 0;
688 }
689 #endif
690 
691 /**
692  * This function attempts to relabel the tty. If this function fails, then
693  * the fd is closed, the contexts are free'd and -1 is returned. On success,
694  * a valid fd is returned and tty_context and new_tty_context are set.
695  *
696  * This function will not fail if it can not relabel the tty when selinux is
697  * in permissive mode.
698  */
relabel_tty(const char * ttyn,security_context_t new_context,security_context_t * tty_context,security_context_t * new_tty_context)699 static int relabel_tty(const char *ttyn, security_context_t new_context,
700 		       security_context_t * tty_context,
701 		       security_context_t * new_tty_context)
702 {
703 	int fd, rc;
704 	int enforcing = security_getenforce();
705 	security_context_t tty_con = NULL;
706 	security_context_t new_tty_con = NULL;
707 
708 	if (!ttyn)
709 		return 0;
710 
711 	if (enforcing < 0) {
712 		fprintf(stderr, _("Could not determine enforcing mode.\n"));
713 		return -1;
714 	}
715 
716 	/* Re-open TTY descriptor */
717 	fd = open(ttyn, O_RDWR | O_NONBLOCK);
718 	if (fd < 0) {
719 		fprintf(stderr, _("Error!  Could not open %s.\n"), ttyn);
720 		return fd;
721 	}
722 	/* this craziness is to make sure we cann't block on open and deadlock */
723 	rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
724 	if (rc) {
725 		fprintf(stderr, _("Error!  Could not clear O_NONBLOCK on %s\n"), ttyn);
726 		close(fd);
727 		return rc;
728 	}
729 
730 	if (fgetfilecon(fd, &tty_con) < 0) {
731 		fprintf(stderr, _("%s!  Could not get current context "
732 				  "for %s, not relabeling tty.\n"),
733 			enforcing ? "Error" : "Warning", ttyn);
734 		if (enforcing)
735 			goto close_fd;
736 	}
737 
738 	if (tty_con &&
739 	    (security_compute_relabel(new_context, tty_con,
740 				      string_to_security_class("chr_file"), &new_tty_con) < 0)) {
741 		fprintf(stderr, _("%s!  Could not get new context for %s, "
742 				  "not relabeling tty.\n"),
743 			enforcing ? "Error" : "Warning", ttyn);
744 		if (enforcing)
745 			goto close_fd;
746 	}
747 
748 	if (new_tty_con)
749 		if (fsetfilecon(fd, new_tty_con) < 0) {
750 			fprintf(stderr,
751 				_("%s!  Could not set new context for %s\n"),
752 				enforcing ? "Error" : "Warning", ttyn);
753 			freecon(new_tty_con);
754 			new_tty_con = NULL;
755 			if (enforcing)
756 				goto close_fd;
757 		}
758 
759 	*tty_context = tty_con;
760 	*new_tty_context = new_tty_con;
761 	return fd;
762 
763       close_fd:
764 	freecon(tty_con);
765 	close(fd);
766 	return -1;
767 }
768 
769 /**
770  * This function attempts to revert the relabeling done to the tty.
771  * fd   - referencing the opened ttyn
772  * ttyn - name of tty to restore
773  * tty_context     - original context of the tty
774  * new_tty_context - context tty was relabeled to
775  *
776  * Returns zero on success, non-zero otherwise
777  */
restore_tty_label(int fd,const char * ttyn,security_context_t tty_context,security_context_t new_tty_context)778 static int restore_tty_label(int fd, const char *ttyn,
779 			     security_context_t tty_context,
780 			     security_context_t new_tty_context)
781 {
782 	int rc = 0;
783 	security_context_t chk_tty_context = NULL;
784 
785 	if (!ttyn)
786 		goto skip_relabel;
787 
788 	if (!new_tty_context)
789 		goto skip_relabel;
790 
791 	/* Verify that the tty still has the context set by newrole. */
792 	if ((rc = fgetfilecon(fd, &chk_tty_context)) < 0) {
793 		fprintf(stderr, "Could not fgetfilecon %s.\n", ttyn);
794 		goto skip_relabel;
795 	}
796 
797 	if ((rc = strcmp(chk_tty_context, new_tty_context))) {
798 		fprintf(stderr, _("%s changed labels.\n"), ttyn);
799 		goto skip_relabel;
800 	}
801 
802 	if ((rc = fsetfilecon(fd, tty_context)) < 0)
803 		fprintf(stderr,
804 			_("Warning! Could not restore context for %s\n"), ttyn);
805       skip_relabel:
806 	freecon(chk_tty_context);
807 	return rc;
808 }
809 
810 /**
811  * Parses and validates the provided command line options and
812  * constructs a new context based on our old context and the
813  * arguments specified on the command line. On success
814  * new_context will be set to valid values, otherwise its value
815  * is left unchanged.
816  *
817  * Returns zero on success, non-zero otherwise.
818  */
parse_command_line_arguments(int argc,char ** argv,char * ttyn,security_context_t old_context,security_context_t * new_context,int * preserve_environment)819 static int parse_command_line_arguments(int argc, char **argv, char *ttyn,
820 					security_context_t old_context,
821 					security_context_t * new_context,
822 					int *preserve_environment)
823 {
824 	int flag_index;		/* flag index in argv[] */
825 	int clflag;		/* holds codes for command line flags */
826 	char *role_s = NULL;	/* role spec'd by user in argv[] */
827 	char *type_s = NULL;	/* type spec'd by user in argv[] */
828 	char *type_ptr = NULL;	/* stores malloc'd data from get_default_type */
829 	char *level_s = NULL;	/* level spec'd by user in argv[] */
830 	char *range_ptr = NULL;
831 	security_context_t new_con = NULL;
832 	security_context_t tty_con = NULL;
833 	context_t context = NULL;	/* manipulatable form of new_context */
834 	const struct option long_options[] = {
835 		{"role", 1, 0, 'r'},
836 		{"type", 1, 0, 't'},
837 		{"level", 1, 0, 'l'},
838 		{"preserve-environment", 0, 0, 'p'},
839 		{"version", 0, 0, 'V'},
840 		{NULL, 0, 0, 0}
841 	};
842 
843 	*preserve_environment = 0;
844 	while (1) {
845 		clflag = getopt_long(argc, argv, "r:t:l:pV", long_options,
846 				     &flag_index);
847 		if (clflag == -1)
848 			break;
849 
850 		switch (clflag) {
851 		case 'V':
852 			printf("newrole: %s version %s\n", PACKAGE, VERSION);
853 			exit(0);
854 			break;
855 		case 'p':
856 			*preserve_environment = 1;
857 			break;
858 		case 'r':
859 			if (role_s) {
860 				fprintf(stderr,
861 					_("Error: multiple roles specified\n"));
862 				return -1;
863 			}
864 			role_s = optarg;
865 			break;
866 		case 't':
867 			if (type_s) {
868 				fprintf(stderr,
869 					_("Error: multiple types specified\n"));
870 				return -1;
871 			}
872 			type_s = optarg;
873 			break;
874 		case 'l':
875 			if (!is_selinux_mls_enabled()) {
876 				fprintf(stderr, _("Sorry, -l may be used with "
877 						  "SELinux MLS support.\n"));
878 				return -1;
879 			}
880 			if (level_s) {
881 				fprintf(stderr, _("Error: multiple levels "
882 						  "specified\n"));
883 				return -1;
884 			}
885 			if (ttyn) {
886 				if (fgetfilecon(STDIN_FILENO, &tty_con) >= 0) {
887 					if (selinux_check_securetty_context
888 					    (tty_con) < 0) {
889 						fprintf(stderr,
890 							_
891 							("Error: you are not allowed to change levels on a non secure terminal \n"));
892 						freecon(tty_con);
893 						return -1;
894 					}
895 					freecon(tty_con);
896 				}
897 			}
898 
899 			level_s = optarg;
900 			break;
901 		default:
902 			fprintf(stderr, "%s\n", USAGE_STRING);
903 			return -1;
904 		}
905 	}
906 
907 	/* Verify that the combination of command-line arguments are viable */
908 	if (!(role_s || type_s || level_s)) {
909 		fprintf(stderr, "%s\n", USAGE_STRING);
910 		return -1;
911 	}
912 
913 	/* Fill in a default type if one hasn't been specified. */
914 	if (role_s && !type_s) {
915 		/* get_default_type() returns malloc'd memory */
916 		if (get_default_type(role_s, &type_ptr)) {
917 			fprintf(stderr, _("Couldn't get default type.\n"));
918 			send_audit_message(0, old_context, new_con, ttyn);
919 			return -1;
920 		}
921 		type_s = type_ptr;
922 	}
923 
924 	/* Create a temporary new context structure we extract and modify */
925 	context = context_new(old_context);
926 	if (!context) {
927 		fprintf(stderr, _("failed to get new context.\n"));
928 		goto err_free;
929 	}
930 
931 	/* Modify the temporary new context */
932 	if (role_s)
933 		if (context_role_set(context, role_s)) {
934 			fprintf(stderr, _("failed to set new role %s\n"),
935 				role_s);
936 			goto err_free;
937 		}
938 
939 	if (type_s)
940 		if (context_type_set(context, type_s)) {
941 			fprintf(stderr, _("failed to set new type %s\n"),
942 				type_s);
943 			goto err_free;
944 		}
945 
946 	if (level_s) {
947 		range_ptr =
948 		    build_new_range(level_s, context_range_get(context));
949 		if (!range_ptr) {
950 			fprintf(stderr,
951 				_("failed to build new range with level %s\n"),
952 				level_s);
953 			goto err_free;
954 		}
955 		if (context_range_set(context, range_ptr)) {
956 			fprintf(stderr, _("failed to set new range %s\n"),
957 				range_ptr);
958 			goto err_free;
959 		}
960 	}
961 
962 	/* Construct the final new context */
963 	if (!(new_con = context_str(context))) {
964 		fprintf(stderr, _("failed to convert new context to string\n"));
965 		goto err_free;
966 	}
967 
968 	if (security_check_context(new_con) < 0) {
969 		fprintf(stderr, _("%s is not a valid context\n"), new_con);
970 		send_audit_message(0, old_context, new_con, ttyn);
971 		goto err_free;
972 	}
973 
974 	*new_context = strdup(new_con);
975 	if (!*new_context) {
976 		fprintf(stderr, _("Unable to allocate memory for new_context"));
977 		goto err_free;
978 	}
979 
980 	free(type_ptr);
981 	free(range_ptr);
982 	context_free(context);
983 	return 0;
984 
985       err_free:
986 	free(type_ptr);
987 	free(range_ptr);
988 	/* Don't free new_con, context_free(context) handles this */
989 	context_free(context);
990 	return -1;
991 }
992 
993 /**
994  * Take care of any signal setup
995  */
set_signal_handles(void)996 static int set_signal_handles(void)
997 {
998 	sigset_t empty;
999 
1000 	/* Empty the signal mask in case someone is blocking a signal */
1001 	if (sigemptyset(&empty)) {
1002 		fprintf(stderr, _("Unable to obtain empty signal set\n"));
1003 		return -1;
1004 	}
1005 
1006 	(void)sigprocmask(SIG_SETMASK, &empty, NULL);
1007 
1008 	/* Terminate on SIGHUP. */
1009 	if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
1010 		fprintf(stderr, _("Unable to set SIGHUP handler\n"));
1011 		return -1;
1012 	}
1013 
1014 	return 0;
1015 }
1016 
1017 /************************************************************************
1018  *
1019  * All code used for both PAM and shadow passwd goes in this section.
1020  *
1021  ************************************************************************/
1022 
main(int argc,char * argv[])1023 int main(int argc, char *argv[])
1024 {
1025 	security_context_t new_context = NULL;	/* target security context */
1026 	security_context_t old_context = NULL;	/* original securiy context */
1027 	security_context_t tty_context = NULL;	/* current context of tty */
1028 	security_context_t new_tty_context = NULL;	/* new context of tty */
1029 
1030 	struct passwd pw;	/* struct derived from passwd file line */
1031 	char *ttyn = NULL;	/* tty path */
1032 
1033 	char **old_environ;
1034 	int preserve_environment;
1035 
1036 	int fd;
1037 	pid_t childPid = 0;
1038 	char *shell_argv0 = NULL;
1039 	int rc;
1040 
1041 #ifdef USE_PAM
1042 	int pam_status;		/* pam return code */
1043 	pam_handle_t *pam_handle;	/* opaque handle used by all PAM functions */
1044 
1045 	/* This is a jump table of functions for PAM to use when it wants to *
1046 	 * communicate with the user.  We'll be using misc_conv(), which is  *
1047 	 * provided for us via pam_misc.h.                                   */
1048 	struct pam_conv pam_conversation = {
1049 		misc_conv,
1050 		NULL
1051 	};
1052 #endif
1053 
1054 	/*
1055 	 * Step 0: Setup
1056 	 *
1057 	 * Do some intial setup, including dropping capabilities, checking
1058 	 * if it makes sense to continue to run newrole, and setting up
1059 	 * a scrubbed environment.
1060 	 */
1061 	if (drop_capabilities(FALSE)) {
1062 		perror(_("Sorry, newrole failed to drop capabilities\n"));
1063 		return -1;
1064 	}
1065 	if (set_signal_handles())
1066 		return -1;
1067 
1068 #ifdef USE_NLS
1069 	setlocale(LC_ALL, "");
1070 	bindtextdomain(PACKAGE, LOCALEDIR);
1071 	textdomain(PACKAGE);
1072 #endif
1073 
1074 	old_environ = environ;
1075 	environ = NULL;
1076 
1077 	if (!is_selinux_enabled()) {
1078 		fprintf(stderr, _("Sorry, newrole may be used only on "
1079 				  "a SELinux kernel.\n"));
1080 		return -1;
1081 	}
1082 
1083 	if (security_getenforce() < 0) {
1084 		fprintf(stderr, _("Could not determine enforcing mode.\n"));
1085 		return -1;
1086 	}
1087 
1088 	/*
1089 	 * Step 1: Parse command line and valid arguments
1090 	 *
1091 	 * old_context and ttyn are required for audit logging,
1092 	 * context validation and pam
1093 	 */
1094 	if (getprevcon(&old_context)) {
1095 		fprintf(stderr, _("failed to get old_context.\n"));
1096 		return -1;
1097 	}
1098 
1099 	ttyn = ttyname(STDIN_FILENO);
1100 	if (!ttyn || *ttyn == '\0') {
1101 		fprintf(stderr,
1102 			_("Warning!  Could not retrieve tty information.\n"));
1103 	}
1104 
1105 	if (parse_command_line_arguments(argc, argv, ttyn, old_context,
1106 					 &new_context, &preserve_environment))
1107 		return -1;
1108 
1109 	/*
1110 	 * Step 2:  Authenticate the user.
1111 	 *
1112 	 * Re-authenticate the user running this program.
1113 	 * This is just to help confirm user intent (vs. invocation by
1114 	 * malicious software), not to authorize the operation (which is covered
1115 	 * by policy).  Trusted path mechanism would be preferred.
1116 	 */
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