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