| 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 |