Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/openssh/src/openbsd-compat/port-linux.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* | - | ||||||||||||
2 | * Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com> | - | ||||||||||||
3 | * Copyright (c) 2006 Damien Miller <djm@openbsd.org> | - | ||||||||||||
4 | * | - | ||||||||||||
5 | * Permission to use, copy, modify, and distribute this software for any | - | ||||||||||||
6 | * purpose with or without fee is hereby granted, provided that the above | - | ||||||||||||
7 | * copyright notice and this permission notice appear in all copies. | - | ||||||||||||
8 | * | - | ||||||||||||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | - | ||||||||||||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | - | ||||||||||||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | - | ||||||||||||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | - | ||||||||||||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | - | ||||||||||||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | - | ||||||||||||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | - | ||||||||||||
16 | */ | - | ||||||||||||
17 | - | |||||||||||||
18 | /* | - | ||||||||||||
19 | * Linux-specific portability code - just SELinux support at present | - | ||||||||||||
20 | */ | - | ||||||||||||
21 | - | |||||||||||||
22 | #include "includes.h" | - | ||||||||||||
23 | - | |||||||||||||
24 | #if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST) | - | ||||||||||||
25 | #include <errno.h> | - | ||||||||||||
26 | #include <stdarg.h> | - | ||||||||||||
27 | #include <string.h> | - | ||||||||||||
28 | #include <stdio.h> | - | ||||||||||||
29 | #include <stdlib.h> | - | ||||||||||||
30 | - | |||||||||||||
31 | #include "log.h" | - | ||||||||||||
32 | #include "xmalloc.h" | - | ||||||||||||
33 | #include "port-linux.h" | - | ||||||||||||
34 | - | |||||||||||||
35 | #ifdef WITH_SELINUX | - | ||||||||||||
36 | #include <selinux/selinux.h> | - | ||||||||||||
37 | #include <selinux/get_context_list.h> | - | ||||||||||||
38 | - | |||||||||||||
39 | #ifndef SSH_SELINUX_UNCONFINED_TYPE | - | ||||||||||||
40 | # define SSH_SELINUX_UNCONFINED_TYPE ":unconfined_t:" | - | ||||||||||||
41 | #endif | - | ||||||||||||
42 | - | |||||||||||||
43 | /* Wrapper around is_selinux_enabled() to log its return value once only */ | - | ||||||||||||
44 | int | - | ||||||||||||
45 | ssh_selinux_enabled(void) | - | ||||||||||||
46 | { | - | ||||||||||||
47 | static int enabled = -1; | - | ||||||||||||
48 | - | |||||||||||||
49 | if (enabled == -1) { | - | ||||||||||||
50 | enabled = (is_selinux_enabled() == 1); | - | ||||||||||||
51 | debug("SELinux support %s", enabled ? "enabled" : "disabled"); | - | ||||||||||||
52 | } | - | ||||||||||||
53 | - | |||||||||||||
54 | return (enabled); | - | ||||||||||||
55 | } | - | ||||||||||||
56 | - | |||||||||||||
57 | /* Return the default security context for the given username */ | - | ||||||||||||
58 | static security_context_t | - | ||||||||||||
59 | ssh_selinux_getctxbyname(char *pwname) | - | ||||||||||||
60 | { | - | ||||||||||||
61 | security_context_t sc = NULL; | - | ||||||||||||
62 | char *sename = NULL, *lvl = NULL; | - | ||||||||||||
63 | int r; | - | ||||||||||||
64 | - | |||||||||||||
65 | #ifdef HAVE_GETSEUSERBYNAME | - | ||||||||||||
66 | if (getseuserbyname(pwname, &sename, &lvl) != 0) | - | ||||||||||||
67 | return NULL; | - | ||||||||||||
68 | #else | - | ||||||||||||
69 | sename = pwname; | - | ||||||||||||
70 | lvl = NULL; | - | ||||||||||||
71 | #endif | - | ||||||||||||
72 | - | |||||||||||||
73 | #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL | - | ||||||||||||
74 | r = get_default_context_with_level(sename, lvl, NULL, &sc); | - | ||||||||||||
75 | #else | - | ||||||||||||
76 | r = get_default_context(sename, NULL, &sc); | - | ||||||||||||
77 | #endif | - | ||||||||||||
78 | - | |||||||||||||
79 | if (r != 0) { | - | ||||||||||||
80 | switch (security_getenforce()) { | - | ||||||||||||
81 | case -1: | - | ||||||||||||
82 | fatal("%s: ssh_selinux_getctxbyname: " | - | ||||||||||||
83 | "security_getenforce() failed", __func__); | - | ||||||||||||
84 | case 0: | - | ||||||||||||
85 | error("%s: Failed to get default SELinux security " | - | ||||||||||||
86 | "context for %s", __func__, pwname); | - | ||||||||||||
87 | sc = NULL; | - | ||||||||||||
88 | break; | - | ||||||||||||
89 | default: | - | ||||||||||||
90 | fatal("%s: Failed to get default SELinux security " | - | ||||||||||||
91 | "context for %s (in enforcing mode)", | - | ||||||||||||
92 | __func__, pwname); | - | ||||||||||||
93 | } | - | ||||||||||||
94 | } | - | ||||||||||||
95 | - | |||||||||||||
96 | #ifdef HAVE_GETSEUSERBYNAME | - | ||||||||||||
97 | free(sename); | - | ||||||||||||
98 | free(lvl); | - | ||||||||||||
99 | #endif | - | ||||||||||||
100 | - | |||||||||||||
101 | return sc; | - | ||||||||||||
102 | } | - | ||||||||||||
103 | - | |||||||||||||
104 | /* Set the execution context to the default for the specified user */ | - | ||||||||||||
105 | void | - | ||||||||||||
106 | ssh_selinux_setup_exec_context(char *pwname) | - | ||||||||||||
107 | { | - | ||||||||||||
108 | security_context_t user_ctx = NULL; | - | ||||||||||||
109 | - | |||||||||||||
110 | if (!ssh_selinux_enabled()) | - | ||||||||||||
111 | return; | - | ||||||||||||
112 | - | |||||||||||||
113 | debug3("%s: setting execution context", __func__); | - | ||||||||||||
114 | - | |||||||||||||
115 | user_ctx = ssh_selinux_getctxbyname(pwname); | - | ||||||||||||
116 | if (setexeccon(user_ctx) != 0) { | - | ||||||||||||
117 | switch (security_getenforce()) { | - | ||||||||||||
118 | case -1: | - | ||||||||||||
119 | fatal("%s: security_getenforce() failed", __func__); | - | ||||||||||||
120 | case 0: | - | ||||||||||||
121 | error("%s: Failed to set SELinux execution " | - | ||||||||||||
122 | "context for %s", __func__, pwname); | - | ||||||||||||
123 | break; | - | ||||||||||||
124 | default: | - | ||||||||||||
125 | fatal("%s: Failed to set SELinux execution context " | - | ||||||||||||
126 | "for %s (in enforcing mode)", __func__, pwname); | - | ||||||||||||
127 | } | - | ||||||||||||
128 | } | - | ||||||||||||
129 | if (user_ctx != NULL) | - | ||||||||||||
130 | freecon(user_ctx); | - | ||||||||||||
131 | - | |||||||||||||
132 | debug3("%s: done", __func__); | - | ||||||||||||
133 | } | - | ||||||||||||
134 | - | |||||||||||||
135 | /* Set the TTY context for the specified user */ | - | ||||||||||||
136 | void | - | ||||||||||||
137 | ssh_selinux_setup_pty(char *pwname, const char *tty) | - | ||||||||||||
138 | { | - | ||||||||||||
139 | security_context_t new_tty_ctx = NULL; | - | ||||||||||||
140 | security_context_t user_ctx = NULL; | - | ||||||||||||
141 | security_context_t old_tty_ctx = NULL; | - | ||||||||||||
142 | security_class_t chrclass; | - | ||||||||||||
143 | - | |||||||||||||
144 | if (!ssh_selinux_enabled()) | - | ||||||||||||
145 | return; | - | ||||||||||||
146 | - | |||||||||||||
147 | debug3("%s: setting TTY context on %s", __func__, tty); | - | ||||||||||||
148 | - | |||||||||||||
149 | user_ctx = ssh_selinux_getctxbyname(pwname); | - | ||||||||||||
150 | - | |||||||||||||
151 | /* XXX: should these calls fatal() upon failure in enforcing mode? */ | - | ||||||||||||
152 | - | |||||||||||||
153 | if (getfilecon(tty, &old_tty_ctx) == -1) { | - | ||||||||||||
154 | error("%s: getfilecon: %s", __func__, strerror(errno)); | - | ||||||||||||
155 | goto out; | - | ||||||||||||
156 | } | - | ||||||||||||
157 | if ((chrclass = string_to_security_class("chr_file")) == 0) { | - | ||||||||||||
158 | error("%s: couldn't get security class for chr_file", __func__); | - | ||||||||||||
159 | goto out; | - | ||||||||||||
160 | } | - | ||||||||||||
161 | if (security_compute_relabel(user_ctx, old_tty_ctx, | - | ||||||||||||
162 | chrclass, &new_tty_ctx) != 0) { | - | ||||||||||||
163 | error("%s: security_compute_relabel: %s", | - | ||||||||||||
164 | __func__, strerror(errno)); | - | ||||||||||||
165 | goto out; | - | ||||||||||||
166 | } | - | ||||||||||||
167 | - | |||||||||||||
168 | if (setfilecon(tty, new_tty_ctx) != 0) | - | ||||||||||||
169 | error("%s: setfilecon: %s", __func__, strerror(errno)); | - | ||||||||||||
170 | out: | - | ||||||||||||
171 | if (new_tty_ctx != NULL) | - | ||||||||||||
172 | freecon(new_tty_ctx); | - | ||||||||||||
173 | if (old_tty_ctx != NULL) | - | ||||||||||||
174 | freecon(old_tty_ctx); | - | ||||||||||||
175 | if (user_ctx != NULL) | - | ||||||||||||
176 | freecon(user_ctx); | - | ||||||||||||
177 | debug3("%s: done", __func__); | - | ||||||||||||
178 | } | - | ||||||||||||
179 | - | |||||||||||||
180 | void | - | ||||||||||||
181 | ssh_selinux_change_context(const char *newname) | - | ||||||||||||
182 | { | - | ||||||||||||
183 | int len, newlen; | - | ||||||||||||
184 | char *oldctx, *newctx, *cx; | - | ||||||||||||
185 | void (*switchlog) (const char *fmt,...) = logit; | - | ||||||||||||
186 | - | |||||||||||||
187 | if (!ssh_selinux_enabled()) | - | ||||||||||||
188 | return; | - | ||||||||||||
189 | - | |||||||||||||
190 | if (getcon((security_context_t *)&oldctx) < 0) { | - | ||||||||||||
191 | logit("%s: getcon failed with %s", __func__, strerror(errno)); | - | ||||||||||||
192 | return; | - | ||||||||||||
193 | } | - | ||||||||||||
194 | if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) == | - | ||||||||||||
195 | NULL) { | - | ||||||||||||
196 | logit ("%s: unparseable context %s", __func__, oldctx); | - | ||||||||||||
197 | return; | - | ||||||||||||
198 | } | - | ||||||||||||
199 | - | |||||||||||||
200 | /* | - | ||||||||||||
201 | * Check whether we are attempting to switch away from an unconfined | - | ||||||||||||
202 | * security context. | - | ||||||||||||
203 | */ | - | ||||||||||||
204 | if (strncmp(cx, SSH_SELINUX_UNCONFINED_TYPE, | - | ||||||||||||
205 | sizeof(SSH_SELINUX_UNCONFINED_TYPE) - 1) == 0) | - | ||||||||||||
206 | switchlog = debug3; | - | ||||||||||||
207 | - | |||||||||||||
208 | newlen = strlen(oldctx) + strlen(newname) + 1; | - | ||||||||||||
209 | newctx = xmalloc(newlen); | - | ||||||||||||
210 | len = cx - oldctx + 1; | - | ||||||||||||
211 | memcpy(newctx, oldctx, len); | - | ||||||||||||
212 | strlcpy(newctx + len, newname, newlen - len); | - | ||||||||||||
213 | if ((cx = index(cx + 1, ':'))) | - | ||||||||||||
214 | strlcat(newctx, cx, newlen); | - | ||||||||||||
215 | debug3("%s: setting context from '%s' to '%s'", __func__, | - | ||||||||||||
216 | oldctx, newctx); | - | ||||||||||||
217 | if (setcon(newctx) < 0) | - | ||||||||||||
218 | switchlog("%s: setcon %s from %s failed with %s", __func__, | - | ||||||||||||
219 | newctx, oldctx, strerror(errno)); | - | ||||||||||||
220 | free(oldctx); | - | ||||||||||||
221 | free(newctx); | - | ||||||||||||
222 | } | - | ||||||||||||
223 | - | |||||||||||||
224 | void | - | ||||||||||||
225 | ssh_selinux_setfscreatecon(const char *path) | - | ||||||||||||
226 | { | - | ||||||||||||
227 | security_context_t context; | - | ||||||||||||
228 | - | |||||||||||||
229 | if (!ssh_selinux_enabled()) | - | ||||||||||||
230 | return; | - | ||||||||||||
231 | if (path == NULL) { | - | ||||||||||||
232 | setfscreatecon(NULL); | - | ||||||||||||
233 | return; | - | ||||||||||||
234 | } | - | ||||||||||||
235 | if (matchpathcon(path, 0700, &context) == 0) | - | ||||||||||||
236 | setfscreatecon(context); | - | ||||||||||||
237 | } | - | ||||||||||||
238 | - | |||||||||||||
239 | #endif /* WITH_SELINUX */ | - | ||||||||||||
240 | - | |||||||||||||
241 | #ifdef LINUX_OOM_ADJUST | - | ||||||||||||
242 | /* | - | ||||||||||||
243 | * The magic "don't kill me" values, old and new, as documented in eg: | - | ||||||||||||
244 | * http://lxr.linux.no/#linux+v2.6.32/Documentation/filesystems/proc.txt | - | ||||||||||||
245 | * http://lxr.linux.no/#linux+v2.6.36/Documentation/filesystems/proc.txt | - | ||||||||||||
246 | */ | - | ||||||||||||
247 | - | |||||||||||||
248 | static int oom_adj_save = INT_MIN; | - | ||||||||||||
249 | static char *oom_adj_path = NULL; | - | ||||||||||||
250 | struct { | - | ||||||||||||
251 | char *path; | - | ||||||||||||
252 | int value; | - | ||||||||||||
253 | } oom_adjust[] = { | - | ||||||||||||
254 | {"/proc/self/oom_score_adj", -1000}, /* kernels >= 2.6.36 */ | - | ||||||||||||
255 | {"/proc/self/oom_adj", -17}, /* kernels <= 2.6.35 */ | - | ||||||||||||
256 | {NULL, 0}, | - | ||||||||||||
257 | }; | - | ||||||||||||
258 | - | |||||||||||||
259 | /* | - | ||||||||||||
260 | * Tell the kernel's out-of-memory killer to avoid sshd. | - | ||||||||||||
261 | * Returns the previous oom_adj value or zero. | - | ||||||||||||
262 | */ | - | ||||||||||||
263 | void | - | ||||||||||||
264 | oom_adjust_setup(void) | - | ||||||||||||
265 | { | - | ||||||||||||
266 | int i, value; | - | ||||||||||||
267 | FILE *fp; | - | ||||||||||||
268 | - | |||||||||||||
269 | debug3("%s", __func__); | - | ||||||||||||
270 | for (i = 0; oom_adjust[i].path != NULL; i++) {
| 0 | ||||||||||||
271 | oom_adj_path = oom_adjust[i].path; | - | ||||||||||||
272 | value = oom_adjust[i].value; | - | ||||||||||||
273 | if ((fp = fopen(oom_adj_path, "r+")) != NULL) {
| 0 | ||||||||||||
274 | if (fscanf(fp, "%d", &oom_adj_save) != 1)
| 0 | ||||||||||||
275 | verbose("error reading %s: %s", oom_adj_path, never executed: verbose("error reading %s: %s", oom_adj_path, strerror( (*__errno_location ()) )); | 0 | ||||||||||||
276 | strerror(errno)); never executed: verbose("error reading %s: %s", oom_adj_path, strerror( (*__errno_location ()) )); | 0 | ||||||||||||
277 | else { | - | ||||||||||||
278 | rewind(fp); | - | ||||||||||||
279 | if (fprintf(fp, "%d\n", value) <= 0)
| 0 | ||||||||||||
280 | verbose("error writing %s: %s", never executed: verbose("error writing %s: %s", oom_adj_path, strerror( (*__errno_location ()) )); | 0 | ||||||||||||
281 | oom_adj_path, strerror(errno)); never executed: verbose("error writing %s: %s", oom_adj_path, strerror( (*__errno_location ()) )); | 0 | ||||||||||||
282 | else | - | ||||||||||||
283 | debug("Set %s from %d to %d", never executed: debug("Set %s from %d to %d", oom_adj_path, oom_adj_save, value); | 0 | ||||||||||||
284 | oom_adj_path, oom_adj_save, value); never executed: debug("Set %s from %d to %d", oom_adj_path, oom_adj_save, value); | 0 | ||||||||||||
285 | } | - | ||||||||||||
286 | fclose(fp); | - | ||||||||||||
287 | return; never executed: return; | 0 | ||||||||||||
288 | } | - | ||||||||||||
289 | } never executed: end of block | 0 | ||||||||||||
290 | oom_adj_path = NULL; | - | ||||||||||||
291 | } never executed: end of block | 0 | ||||||||||||
292 | - | |||||||||||||
293 | /* Restore the saved OOM adjustment */ | - | ||||||||||||
294 | void | - | ||||||||||||
295 | oom_adjust_restore(void) | - | ||||||||||||
296 | { | - | ||||||||||||
297 | FILE *fp; | - | ||||||||||||
298 | - | |||||||||||||
299 | debug3("%s", __func__); | - | ||||||||||||
300 | if (oom_adj_save == INT_MIN || oom_adj_path == NULL ||
| 0 | ||||||||||||
301 | (fp = fopen(oom_adj_path, "w")) == NULL)
| 0 | ||||||||||||
302 | return; never executed: return; | 0 | ||||||||||||
303 | - | |||||||||||||
304 | if (fprintf(fp, "%d\n", oom_adj_save) <= 0)
| 0 | ||||||||||||
305 | verbose("error writing %s: %s", oom_adj_path, strerror(errno)); never executed: verbose("error writing %s: %s", oom_adj_path, strerror( (*__errno_location ()) )); | 0 | ||||||||||||
306 | else | - | ||||||||||||
307 | debug("Set %s to %d", oom_adj_path, oom_adj_save); never executed: debug("Set %s to %d", oom_adj_path, oom_adj_save); | 0 | ||||||||||||
308 | - | |||||||||||||
309 | fclose(fp); | - | ||||||||||||
310 | return; never executed: return; | 0 | ||||||||||||
311 | } | - | ||||||||||||
312 | #endif /* LINUX_OOM_ADJUST */ | - | ||||||||||||
313 | #endif /* WITH_SELINUX || LINUX_OOM_ADJUST */ | - | ||||||||||||
Source code | Switch to Preprocessed file |