* io/ftw.c (ftw_startup): Use fchdir to return to original
[glibc.git] / nscd / selinux.c
blobf0ac3cdf9aa956a85eba3a922b1fa17c3df0ad3c
1 /* SELinux access controls for nscd.
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include "config.h"
22 #include <error.h>
23 #include <errno.h>
24 #include <libintl.h>
25 #include <pthread.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <syslog.h>
30 #include <unistd.h>
31 #include <selinux/av_permissions.h>
32 #include <selinux/avc.h>
33 #include <selinux/flask.h>
34 #include <selinux/selinux.h>
35 #ifdef HAVE_LIBAUDIT
36 #include <libaudit.h>
37 #endif
39 #include "dbg_log.h"
40 #include "selinux.h"
43 #ifdef HAVE_SELINUX
44 /* Global variable to tell if the kernel has SELinux support. */
45 int selinux_enabled;
47 /* Define mappings of access vector permissions to request types. */
48 static const int perms[LASTREQ] =
50 [GETPWBYNAME] = NSCD__GETPWD,
51 [GETPWBYUID] = NSCD__GETPWD,
52 [GETGRBYNAME] = NSCD__GETGRP,
53 [GETGRBYGID] = NSCD__GETGRP,
54 [GETHOSTBYNAME] = NSCD__GETHOST,
55 [GETHOSTBYNAMEv6] = NSCD__GETHOST,
56 [GETHOSTBYADDR] = NSCD__GETHOST,
57 [GETHOSTBYADDRv6] = NSCD__GETHOST,
58 [GETSTAT] = NSCD__GETSTAT,
59 [SHUTDOWN] = NSCD__ADMIN,
60 [INVALIDATE] = NSCD__ADMIN,
61 [GETFDPW] = NSCD__SHMEMPWD,
62 [GETFDGR] = NSCD__SHMEMGRP,
63 [GETFDHST] = NSCD__SHMEMHOST,
64 [GETAI] = NSCD__GETHOST,
65 [INITGROUPS] = NSCD__GETGRP
68 /* Store an entry ref to speed AVC decisions. */
69 static struct avc_entry_ref aeref;
71 /* Thread to listen for SELinux status changes via netlink. */
72 static pthread_t avc_notify_thread;
74 #ifdef HAVE_LIBAUDIT
75 /* Prototype for supporting the audit daemon */
76 static void log_callback (const char *fmt, ...);
77 #endif
79 /* Prototypes for AVC callback functions. */
80 static void *avc_create_thread (void (*run) (void));
81 static void avc_stop_thread (void *thread);
82 static void *avc_alloc_lock (void);
83 static void avc_get_lock (void *lock);
84 static void avc_release_lock (void *lock);
85 static void avc_free_lock (void *lock);
87 /* AVC callback structures for use in avc_init. */
88 static const struct avc_log_callback log_cb =
90 #ifdef HAVE_LIBAUDIT
91 .func_log = log_callback,
92 #else
93 .func_log = dbg_log,
94 #endif
95 .func_audit = NULL
97 static const struct avc_thread_callback thread_cb =
99 .func_create_thread = avc_create_thread,
100 .func_stop_thread = avc_stop_thread
102 static const struct avc_lock_callback lock_cb =
104 .func_alloc_lock = avc_alloc_lock,
105 .func_get_lock = avc_get_lock,
106 .func_release_lock = avc_release_lock,
107 .func_free_lock = avc_free_lock
110 #ifdef HAVE_LIBAUDIT
111 /* The audit system's netlink socket descriptor */
112 static int audit_fd = -1;
114 /* When an avc denial occurs, log it to audit system */
115 static void
116 log_callback (const char *fmt, ...)
118 if (audit_fd >= 0)
120 va_list ap;
121 va_start (ap, fmt);
123 char *buf;
124 int e = vasprintf (&buf, fmt, ap);
125 if (e < 0)
127 buf = alloca (BUFSIZ);
128 vsnprintf (buf, BUFSIZ, fmt, ap);
131 /* FIXME: need to attribute this to real user, using getuid for now */
132 audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
133 NULL, getuid ());
135 if (e >= 0)
136 free (buf);
138 va_end (ap);
142 /* Initialize the connection to the audit system */
143 static void
144 audit_init (void)
146 audit_fd = audit_open ();
147 if (audit_fd < 0
148 /* If kernel doesn't support audit, bail out */
149 && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
150 dbg_log (_("Failed opening connection to the audit subsystem"));
152 #endif /* HAVE_LIBAUDIT */
154 /* Determine if we are running on an SELinux kernel. Set selinux_enabled
155 to the result. */
156 void
157 nscd_selinux_enabled (int *selinux_enabled)
159 *selinux_enabled = is_selinux_enabled ();
160 if (*selinux_enabled < 0)
162 dbg_log (_("Failed to determine if kernel supports SELinux"));
163 exit (EXIT_FAILURE);
168 /* Create thread for AVC netlink notification. */
169 static void *
170 avc_create_thread (void (*run) (void))
172 int rc;
174 rc =
175 pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
176 if (rc != 0)
177 error (EXIT_FAILURE, rc, _("Failed to start AVC thread"));
179 return &avc_notify_thread;
183 /* Stop AVC netlink thread. */
184 static void
185 avc_stop_thread (void *thread)
187 pthread_cancel (*(pthread_t *) thread);
191 /* Allocate a new AVC lock. */
192 static void *
193 avc_alloc_lock (void)
195 pthread_mutex_t *avc_mutex;
197 avc_mutex = malloc (sizeof (pthread_mutex_t));
198 if (avc_mutex == NULL)
199 error (EXIT_FAILURE, errno, _("Failed to create AVC lock"));
200 pthread_mutex_init (avc_mutex, NULL);
202 return avc_mutex;
206 /* Acquire an AVC lock. */
207 static void
208 avc_get_lock (void *lock)
210 pthread_mutex_lock (lock);
214 /* Release an AVC lock. */
215 static void
216 avc_release_lock (void *lock)
218 pthread_mutex_unlock (lock);
222 /* Free an AVC lock. */
223 static void
224 avc_free_lock (void *lock)
226 pthread_mutex_destroy (lock);
227 free (lock);
231 /* Initialize the user space access vector cache (AVC) for NSCD along with
232 log/thread/lock callbacks. */
233 void
234 nscd_avc_init (void)
236 avc_entry_ref_init (&aeref);
238 if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0)
239 error (EXIT_FAILURE, errno, _("Failed to start AVC"));
240 else
241 dbg_log (_("Access Vector Cache (AVC) started"));
242 #ifdef HAVE_LIBAUDIT
243 audit_init ();
244 #endif
248 /* Check the permission from the caller (via getpeercon) to nscd.
249 Returns 0 if access is allowed, 1 if denied, and -1 on error. */
251 nscd_request_avc_has_perm (int fd, request_type req)
253 /* Initialize to NULL so we know what to free in case of failure. */
254 security_context_t scon = NULL;
255 security_context_t tcon = NULL;
256 security_id_t ssid = NULL;
257 security_id_t tsid = NULL;
258 int rc = -1;
260 if (getpeercon (fd, &scon) < 0)
262 dbg_log (_("Error getting context of socket peer"));
263 goto out;
265 if (getcon (&tcon) < 0)
267 dbg_log (_("Error getting context of nscd"));
268 goto out;
270 if (avc_context_to_sid (scon, &ssid) < 0
271 || avc_context_to_sid (tcon, &tsid) < 0)
273 dbg_log (_("Error getting sid from context"));
274 goto out;
277 rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0;
279 out:
280 if (scon)
281 freecon (scon);
282 if (tcon)
283 freecon (tcon);
284 if (ssid)
285 sidput (ssid);
286 if (tsid)
287 sidput (tsid);
289 return rc;
293 /* Wrapper to get AVC statistics. */
294 void
295 nscd_avc_cache_stats (struct avc_cache_stats *cstats)
297 avc_cache_stats (cstats);
301 /* Print the AVC statistics to stdout. */
302 void
303 nscd_avc_print_stats (struct avc_cache_stats *cstats)
305 printf (_("\nSELinux AVC Statistics:\n\n"
306 "%15u entry lookups\n"
307 "%15u entry hits\n"
308 "%15u entry misses\n"
309 "%15u entry discards\n"
310 "%15u CAV lookups\n"
311 "%15u CAV hits\n"
312 "%15u CAV probes\n"
313 "%15u CAV misses\n"),
314 cstats->entry_lookups, cstats->entry_hits, cstats->entry_misses,
315 cstats->entry_discards, cstats->cav_lookups, cstats->cav_hits,
316 cstats->cav_probes, cstats->cav_misses);
320 /* Clean up the AVC before exiting. */
321 void
322 nscd_avc_destroy (void)
324 avc_destroy ();
325 #ifdef HAVE_LIBAUDIT
326 audit_close (audit_fd);
327 #endif
330 #endif /* HAVE_SELINUX */