1 /* $Id: port-linux.c,v 1.3 2006/09/01 05:38:41 djm Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com>
5  * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * Linux-specific portability code - just SELinux support at present
22  */
23 
24 #include "includes.h"
25 
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <string.h>
29 
30 #ifdef WITH_SELINUX
31 #include "log.h"
32 #include "port-linux.h"
33 
34 #include <selinux/selinux.h>
35 #include <selinux/flask.h>
36 #include <selinux/get_context_list.h>
37 
38 /* Wrapper around is_selinux_enabled() to log its return value once only */
39 static int
40 ssh_selinux_enabled(void)
41 {
42 	static int enabled = -1;
43 
44 	if (enabled == -1) {
45 		enabled = is_selinux_enabled();
46 		debug("SELinux support %s", enabled ? "enabled" : "disabled");
47 	}
48 
49 	return (enabled);
50 }
51 
52 /* Return the default security context for the given username */
53 static security_context_t
54 ssh_selinux_getctxbyname(char *pwname)
55 {
56 	security_context_t sc;
57 	char *sename = NULL, *lvl = NULL;
58 	int r;
59 
60 #ifdef HAVE_GETSEUSERBYNAME
61 	if (getseuserbyname(pwname, &sename, &lvl) != 0)
62 		return NULL;
63 #else
64 	sename = pwname;
65 	lvl = NULL;
66 #endif
67 
68 #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
69 	r = get_default_context_with_level(sename, lvl, NULL, &sc);
70 #else
71 	r = get_default_context(sename, NULL, &sc);
72 #endif
73 
74 	if (r != 0) {
75 		switch (security_getenforce()) {
76 		case -1:
77 			fatal("%s: ssh_selinux_getctxbyname: "
78 			    "security_getenforce() failed", __func__);
79 		case 0:
80 			error("%s: Failed to get default SELinux security "
81 			    "context for %s", __func__, pwname);
82 		default:
83 			fatal("%s: Failed to get default SELinux security "
84 			    "context for %s (in enforcing mode)",
85 			    __func__, pwname);
86 		}
87 	}
88 
89 #ifdef HAVE_GETSEUSERBYNAME
90 	if (sename != NULL)
91 		xfree(sename);
92 	if (lvl != NULL)
93 		xfree(lvl);
94 #endif
95 
96 	return (sc);
97 }
98 
99 /* Set the execution context to the default for the specified user */
100 void
101 ssh_selinux_setup_exec_context(char *pwname)
102 {
103 	security_context_t user_ctx = NULL;
104 
105 	if (!ssh_selinux_enabled())
106 		return;
107 
108 	debug3("%s: setting execution context", __func__);
109 
110 	user_ctx = ssh_selinux_getctxbyname(pwname);
111 	if (setexeccon(user_ctx) != 0) {
112 		switch (security_getenforce()) {
113 		case -1:
114 			fatal("%s: security_getenforce() failed", __func__);
115 		case 0:
116 			error("%s: Failed to set SELinux execution "
117 			    "context for %s", __func__, pwname);
118 		default:
119 			fatal("%s: Failed to set SELinux execution context "
120 			    "for %s (in enforcing mode)", __func__, pwname);
121 		}
122 	}
123 	if (user_ctx != NULL)
124 		freecon(user_ctx);
125 
126 	debug3("%s: done", __func__);
127 }
128 
129 /* Set the TTY context for the specified user */
130 void
131 ssh_selinux_setup_pty(char *pwname, const char *tty)
132 {
133 	security_context_t new_tty_ctx = NULL;
134 	security_context_t user_ctx = NULL;
135 	security_context_t old_tty_ctx = NULL;
136 
137 	if (!ssh_selinux_enabled())
138 		return;
139 
140 	debug3("%s: setting TTY context on %s", __func__, tty);
141 
142 	user_ctx = ssh_selinux_getctxbyname(pwname);
143 
144 	/* XXX: should these calls fatal() upon failure in enforcing mode? */
145 
146 	if (getfilecon(tty, &old_tty_ctx) == -1) {
147 		error("%s: getfilecon: %s", __func__, strerror(errno));
148 		goto out;
149 	}
150 
151 	if (security_compute_relabel(user_ctx, old_tty_ctx,
152 	    SECCLASS_CHR_FILE, &new_tty_ctx) != 0) {
153 		error("%s: security_compute_relabel: %s",
154 		    __func__, strerror(errno));
155 		goto out;
156 	}
157 
158 	if (setfilecon(tty, new_tty_ctx) != 0)
159 		error("%s: setfilecon: %s", __func__, strerror(errno));
160  out:
161 	if (new_tty_ctx != NULL)
162 		freecon(new_tty_ctx);
163 	if (old_tty_ctx != NULL)
164 		freecon(old_tty_ctx);
165 	if (user_ctx != NULL)
166 		freecon(user_ctx);
167 	debug3("%s: done", __func__);
168 }
169 #endif /* WITH_SELINUX */
170