]> sourceware.org Git - glibc.git/blame - nscd/selinux.c
* nscd/selinux.c (log_callback): Use audit_log_user_avc_message.
[glibc.git] / nscd / selinux.c
CommitLineData
74a30a58 1/* SELinux access controls for nscd.
64d64de6 2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
74a30a58
UD
3 This file is part of the GNU C Library.
4 Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
5
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.
10
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.
15
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. */
20
ec23b9be 21#include "config.h"
74a30a58
UD
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>
62a8cefb 30#include <unistd.h>
74a30a58
UD
31#include <selinux/av_permissions.h>
32#include <selinux/avc.h>
33#include <selinux/flask.h>
34#include <selinux/selinux.h>
ec23b9be
UD
35#ifdef HAVE_LIBAUDIT
36#include <libaudit.h>
37#endif
74a30a58
UD
38
39#include "dbg_log.h"
40#include "selinux.h"
41
42
43#ifdef HAVE_SELINUX
44/* Global variable to tell if the kernel has SELinux support. */
45int selinux_enabled;
46
47/* Define mappings of access vector permissions to request types. */
48static const int perms[LASTREQ] =
49{
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,
f7e7a396
UD
64 [GETAI] = NSCD__GETHOST,
65 [INITGROUPS] = NSCD__GETGRP
74a30a58
UD
66};
67
68/* Store an entry ref to speed AVC decisions. */
69static struct avc_entry_ref aeref;
70
71/* Thread to listen for SELinux status changes via netlink. */
72static pthread_t avc_notify_thread;
73
ec23b9be
UD
74#ifdef HAVE_LIBAUDIT
75/* Prototype for supporting the audit daemon */
76static void log_callback (const char *fmt, ...);
77#endif
78
74a30a58
UD
79/* Prototypes for AVC callback functions. */
80static void *avc_create_thread (void (*run) (void));
81static void avc_stop_thread (void *thread);
82static void *avc_alloc_lock (void);
83static void avc_get_lock (void *lock);
84static void avc_release_lock (void *lock);
85static void avc_free_lock (void *lock);
86
87/* AVC callback structures for use in avc_init. */
88static const struct avc_log_callback log_cb =
89{
ec23b9be
UD
90#ifdef HAVE_LIBAUDIT
91 .func_log = log_callback,
92#else
74a30a58 93 .func_log = dbg_log,
ec23b9be 94#endif
74a30a58
UD
95 .func_audit = NULL
96};
97static const struct avc_thread_callback thread_cb =
98{
99 .func_create_thread = avc_create_thread,
100 .func_stop_thread = avc_stop_thread
101};
102static const struct avc_lock_callback lock_cb =
103{
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
108};
109
ec23b9be
UD
110#ifdef HAVE_LIBAUDIT
111/* The audit system's netlink socket descriptor */
112static int audit_fd = -1;
113
114/* When an avc denial occurs, log it to audit system */
64d64de6 115static void
ec23b9be
UD
116log_callback (const char *fmt, ...)
117{
62a8cefb
UD
118 if (audit_fd >= 0)
119 {
120 va_list ap;
121 va_start (ap, fmt);
122
123 char *buf;
124 int e = vasprintf (&buf, fmt, ap);
125 if (e < 0)
126 {
127 buf = alloca (BUFSIZ);
128 vsnprintf (buf, BUFSIZ, fmt, ap);
129 }
130
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 ());
ec23b9be 134
62a8cefb
UD
135 if (e >= 0)
136 free (buf);
137
138 va_end (ap);
139 }
ec23b9be
UD
140}
141
142/* Initialize the connection to the audit system */
64d64de6 143static void
ec23b9be
UD
144audit_init (void)
145{
146 audit_fd = audit_open ();
62a8cefb
UD
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"));
ec23b9be
UD
151}
152#endif /* HAVE_LIBAUDIT */
74a30a58
UD
153
154/* Determine if we are running on an SELinux kernel. Set selinux_enabled
155 to the result. */
156void
157nscd_selinux_enabled (int *selinux_enabled)
158{
159 *selinux_enabled = is_selinux_enabled ();
160 if (*selinux_enabled < 0)
161 {
162 dbg_log (_("Failed to determine if kernel supports SELinux"));
163 exit (EXIT_FAILURE);
164 }
165}
166
167
168/* Create thread for AVC netlink notification. */
169static void *
170avc_create_thread (void (*run) (void))
171{
172 int rc;
173
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"));
178
179 return &avc_notify_thread;
180}
181
182
183/* Stop AVC netlink thread. */
184static void
185avc_stop_thread (void *thread)
186{
187 pthread_cancel (*(pthread_t *) thread);
188}
189
190
191/* Allocate a new AVC lock. */
192static void *
193avc_alloc_lock (void)
194{
195 pthread_mutex_t *avc_mutex;
196
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);
201
202 return avc_mutex;
203}
204
205
206/* Acquire an AVC lock. */
207static void
208avc_get_lock (void *lock)
209{
210 pthread_mutex_lock (lock);
211}
212
213
214/* Release an AVC lock. */
215static void
216avc_release_lock (void *lock)
217{
218 pthread_mutex_unlock (lock);
219}
220
221
222/* Free an AVC lock. */
223static void
224avc_free_lock (void *lock)
225{
226 pthread_mutex_destroy (lock);
227 free (lock);
228}
229
230
231/* Initialize the user space access vector cache (AVC) for NSCD along with
232 log/thread/lock callbacks. */
233void
234nscd_avc_init (void)
235{
236 avc_entry_ref_init (&aeref);
237
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"));
ec23b9be
UD
242#ifdef HAVE_LIBAUDIT
243 audit_init ();
244#endif
74a30a58
UD
245}
246
247
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. */
250int
251nscd_request_avc_has_perm (int fd, request_type req)
252{
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;
259
260 if (getpeercon (fd, &scon) < 0)
261 {
262 dbg_log (_("Error getting context of socket peer"));
263 goto out;
264 }
265 if (getcon (&tcon) < 0)
266 {
267 dbg_log (_("Error getting context of nscd"));
268 goto out;
269 }
1945c96f
UD
270 if (avc_context_to_sid (scon, &ssid) < 0
271 || avc_context_to_sid (tcon, &tsid) < 0)
74a30a58
UD
272 {
273 dbg_log (_("Error getting sid from context"));
274 goto out;
275 }
276
277 rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0;
278
279out:
280 if (scon)
281 freecon (scon);
282 if (tcon)
283 freecon (tcon);
284 if (ssid)
285 sidput (ssid);
286 if (tsid)
287 sidput (tsid);
288
289 return rc;
290}
291
292
293/* Wrapper to get AVC statistics. */
294void
295nscd_avc_cache_stats (struct avc_cache_stats *cstats)
296{
297 avc_cache_stats (cstats);
298}
299
300
301/* Print the AVC statistics to stdout. */
302void
303nscd_avc_print_stats (struct avc_cache_stats *cstats)
304{
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);
317}
318
319
320/* Clean up the AVC before exiting. */
321void
322nscd_avc_destroy (void)
323{
324 avc_destroy ();
ec23b9be
UD
325#ifdef HAVE_LIBAUDIT
326 audit_close (audit_fd);
327#endif
74a30a58
UD
328}
329
330#endif /* HAVE_SELINUX */
This page took 0.086163 seconds and 5 git commands to generate.