xref: /freebsd/crypto/openssh/openbsd-compat/port-linux.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
1 /* $Id: port-linux.c,v 1.5 2008/03/26 20:27:21 dtucker 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 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 			break;
83 		default:
84 			fatal("%s: Failed to get default SELinux security "
85 			    "context for %s (in enforcing mode)",
86 			    __func__, pwname);
87 		}
88 	}
89 
90 #ifdef HAVE_GETSEUSERBYNAME
91 	if (sename != NULL)
92 		xfree(sename);
93 	if (lvl != NULL)
94 		xfree(lvl);
95 #endif
96 
97 	return (sc);
98 }
99 
100 /* Set the execution context to the default for the specified user */
101 void
102 ssh_selinux_setup_exec_context(char *pwname)
103 {
104 	security_context_t user_ctx = NULL;
105 
106 	if (!ssh_selinux_enabled())
107 		return;
108 
109 	debug3("%s: setting execution context", __func__);
110 
111 	user_ctx = ssh_selinux_getctxbyname(pwname);
112 	if (setexeccon(user_ctx) != 0) {
113 		switch (security_getenforce()) {
114 		case -1:
115 			fatal("%s: security_getenforce() failed", __func__);
116 		case 0:
117 			error("%s: Failed to set SELinux execution "
118 			    "context for %s", __func__, pwname);
119 			break;
120 		default:
121 			fatal("%s: Failed to set SELinux execution context "
122 			    "for %s (in enforcing mode)", __func__, pwname);
123 		}
124 	}
125 	if (user_ctx != NULL)
126 		freecon(user_ctx);
127 
128 	debug3("%s: done", __func__);
129 }
130 
131 /* Set the TTY context for the specified user */
132 void
133 ssh_selinux_setup_pty(char *pwname, const char *tty)
134 {
135 	security_context_t new_tty_ctx = NULL;
136 	security_context_t user_ctx = NULL;
137 	security_context_t old_tty_ctx = NULL;
138 
139 	if (!ssh_selinux_enabled())
140 		return;
141 
142 	debug3("%s: setting TTY context on %s", __func__, tty);
143 
144 	user_ctx = ssh_selinux_getctxbyname(pwname);
145 
146 	/* XXX: should these calls fatal() upon failure in enforcing mode? */
147 
148 	if (getfilecon(tty, &old_tty_ctx) == -1) {
149 		error("%s: getfilecon: %s", __func__, strerror(errno));
150 		goto out;
151 	}
152 
153 	if (security_compute_relabel(user_ctx, old_tty_ctx,
154 	    SECCLASS_CHR_FILE, &new_tty_ctx) != 0) {
155 		error("%s: security_compute_relabel: %s",
156 		    __func__, strerror(errno));
157 		goto out;
158 	}
159 
160 	if (setfilecon(tty, new_tty_ctx) != 0)
161 		error("%s: setfilecon: %s", __func__, strerror(errno));
162  out:
163 	if (new_tty_ctx != NULL)
164 		freecon(new_tty_ctx);
165 	if (old_tty_ctx != NULL)
166 		freecon(old_tty_ctx);
167 	if (user_ctx != NULL)
168 		freecon(user_ctx);
169 	debug3("%s: done", __func__);
170 }
171 #endif /* WITH_SELINUX */
172