2007-06-13 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / bus / selinux.c
1 /* -*- mode: C; c-file-style: "gnu" -*-
2  * selinux.c  SELinux security checks for D-Bus
3  *
4  * Author: Matthew Rickard <mjricka@epoch.ncsc.mil>
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include <dbus/dbus-internals.h>
24 #include <dbus/dbus-string.h>
25 #include "selinux.h"
26 #include "services.h"
27 #include "policy.h"
28 #include "utils.h"
29 #include "config-parser.h"
30
31 #ifdef HAVE_SELINUX
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <pthread.h>
36 #include <syslog.h>
37 #include <selinux/selinux.h>
38 #include <selinux/avc.h>
39 #include <selinux/av_permissions.h>
40 #include <selinux/flask.h>
41 #include <signal.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #ifdef HAVE_LIBAUDIT
45 #include <libaudit.h>
46 #endif /* HAVE_LIBAUDIT */
47 #endif /* HAVE_SELINUX */
48
49 #define BUS_SID_FROM_SELINUX(sid)  ((BusSELinuxID*) (sid))
50 #define SELINUX_SID_FROM_BUS(sid)  ((security_id_t) (sid))
51
52 #ifdef HAVE_SELINUX
53 /* Store the value telling us if SELinux is enabled in the kernel. */
54 static dbus_bool_t selinux_enabled = FALSE;
55
56 /* Store an avc_entry_ref to speed AVC decisions. */
57 static struct avc_entry_ref aeref;
58
59 /* Store the SID of the bus itself to use as the default. */
60 static security_id_t bus_sid = SECSID_WILD;
61
62 /* Thread to listen for SELinux status changes via netlink. */
63 static pthread_t avc_notify_thread;
64
65 /* Prototypes for AVC callback functions.  */
66 static void log_callback (const char *fmt, ...);
67 static void log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft);
68 static void *avc_create_thread (void (*run) (void));
69 static void avc_stop_thread (void *thread);
70 static void *avc_alloc_lock (void);
71 static void avc_get_lock (void *lock);
72 static void avc_release_lock (void *lock);
73 static void avc_free_lock (void *lock);
74
75 /* AVC callback structures for use in avc_init.  */
76 static const struct avc_memory_callback mem_cb =
77 {
78   .func_malloc = dbus_malloc,
79   .func_free = dbus_free
80 };
81 static const struct avc_log_callback log_cb =
82 {
83   .func_log = log_callback,
84   .func_audit = log_audit_callback
85 };
86 static const struct avc_thread_callback thread_cb =
87 {
88   .func_create_thread = avc_create_thread,
89   .func_stop_thread = avc_stop_thread
90 };
91 static const struct avc_lock_callback lock_cb =
92 {
93   .func_alloc_lock = avc_alloc_lock,
94   .func_get_lock = avc_get_lock,
95   .func_release_lock = avc_release_lock,
96   .func_free_lock = avc_free_lock
97 };
98 #endif /* HAVE_SELINUX */
99
100 /**
101  * Log callback to log denial messages from the AVC.
102  * This is used in avc_init.  Logs to both standard
103  * error and syslogd.
104  *
105  * @param fmt the format string
106  * @param variable argument list
107  */
108 #ifdef HAVE_SELINUX
109
110 #ifdef HAVE_LIBAUDIT
111 static int audit_fd = -1;
112 #endif
113
114 static void
115 audit_init(void)
116 {
117 #ifdef HAVE_LIBAUDIT  
118   audit_fd = audit_open ();
119
120   if (audit_fd < 0)
121     {
122       /* If kernel doesn't support audit, bail out */
123       if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)
124         return;
125       /* If user bus, bail out */
126       if (errno == EPERM && getuid() != 0)
127         return;
128       _dbus_warn ("Failed opening connection to the audit subsystem");
129     }
130 #endif /* HAVE_LIBAUDIT */
131 }
132
133 static void 
134 log_callback (const char *fmt, ...) 
135 {
136   va_list ap;
137
138   va_start(ap, fmt);
139
140 #ifdef HAVE_LIBAUDIT
141   if (audit_fd >= 0)
142   {
143     char buf[PATH_MAX*2];
144     
145     /* FIXME: need to change this to show real user */
146     vsnprintf(buf, sizeof(buf), fmt, ap);
147     audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
148                                NULL, getuid());
149     return;
150   }
151 #endif /* HAVE_LIBAUDIT */
152   
153   vsyslog (LOG_INFO, fmt, ap);
154   va_end(ap);
155 }
156
157 /**
158  * On a policy reload we need to reparse the SELinux configuration file, since
159  * this could have changed.  Send a SIGHUP to reload all configs.
160  */
161 static int
162 policy_reload_callback (u_int32_t event, security_id_t ssid, 
163                         security_id_t tsid, security_class_t tclass, 
164                         access_vector_t perms, access_vector_t *out_retained)
165 {
166   if (event == AVC_CALLBACK_RESET)
167     return raise (SIGHUP);
168   
169   return 0;
170 }
171
172 /**
173  * Log any auxiliary data 
174  */
175 static void
176 log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft)
177 {
178   DBusString *audmsg = data;
179   _dbus_string_copy_to_buffer (audmsg, buf, bufleft);
180 }
181
182 /**
183  * Create thread to notify the AVC of enforcing and policy reload
184  * changes via netlink.
185  *
186  * @param run the thread run function
187  * @return pointer to the thread
188  */
189 static void *
190 avc_create_thread (void (*run) (void))
191 {
192   int rc;
193
194   rc = pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
195   if (rc != 0)
196     {
197       _dbus_warn ("Failed to start AVC thread: %s\n", _dbus_strerror (rc));
198       exit (1);
199     }
200   return &avc_notify_thread;
201 }
202
203 /* Stop AVC netlink thread.  */
204 static void
205 avc_stop_thread (void *thread)
206 {
207   pthread_cancel (*(pthread_t *) thread);
208 }
209
210 /* Allocate a new AVC lock.  */
211 static void *
212 avc_alloc_lock (void)
213 {
214   pthread_mutex_t *avc_mutex;
215
216   avc_mutex = dbus_new (pthread_mutex_t, 1);
217   if (avc_mutex == NULL)
218     {
219       _dbus_warn ("Could not create mutex: %s\n", _dbus_strerror (errno));
220       exit (1);
221     }
222   pthread_mutex_init (avc_mutex, NULL);
223
224   return avc_mutex;
225 }
226
227 /* Acquire an AVC lock.  */
228 static void
229 avc_get_lock (void *lock)
230 {
231   pthread_mutex_lock (lock);
232 }
233
234 /* Release an AVC lock.  */
235 static void
236 avc_release_lock (void *lock)
237 {
238   pthread_mutex_unlock (lock);
239 }
240
241 /* Free an AVC lock.  */
242 static void
243 avc_free_lock (void *lock)
244 {
245   pthread_mutex_destroy (lock);
246   dbus_free (lock);
247 }
248 #endif /* HAVE_SELINUX */
249
250 /**
251  * Return whether or not SELinux is enabled; must be
252  * called after bus_selinux_init.
253  */
254 dbus_bool_t
255 bus_selinux_enabled (void)
256 {
257 #ifdef HAVE_SELINUX
258   return selinux_enabled;
259 #else
260   return FALSE;
261 #endif /* HAVE_SELINUX */
262 }
263
264 /**
265  * Do early initialization; determine whether SELinux is enabled.
266  */
267 dbus_bool_t
268 bus_selinux_pre_init (void)
269 {
270 #ifdef HAVE_SELINUX
271   int r;
272   _dbus_assert (bus_sid == SECSID_WILD);
273   
274   /* Determine if we are running an SELinux kernel. */
275   r = is_selinux_enabled ();
276   if (r < 0)
277     {
278       _dbus_warn ("Could not tell if SELinux is enabled: %s\n",
279                   _dbus_strerror (errno));
280       return FALSE;
281     }
282
283   selinux_enabled = r != 0;
284   return TRUE;
285 #else
286   return TRUE;
287 #endif
288 }
289
290 /**
291  * Initialize the user space access vector cache (AVC) for D-Bus and set up
292  * logging callbacks.
293  */
294 dbus_bool_t
295 bus_selinux_full_init (void)
296 {
297 #ifdef HAVE_SELINUX
298   char *bus_context;
299
300   _dbus_assert (bus_sid == SECSID_WILD);
301   
302   if (!selinux_enabled)
303     {
304       _dbus_verbose ("SELinux not enabled in this kernel.\n");
305       return TRUE;
306     }
307
308   _dbus_verbose ("SELinux is enabled in this kernel.\n");
309
310   avc_entry_ref_init (&aeref);
311   if (avc_init ("avc", &mem_cb, &log_cb, &thread_cb, &lock_cb) < 0)
312     {
313       _dbus_warn ("Failed to start Access Vector Cache (AVC).\n");
314       return FALSE;
315     }
316   else
317     {
318       openlog ("dbus", LOG_PERROR, LOG_USER);
319       _dbus_verbose ("Access Vector Cache (AVC) started.\n");
320     }
321
322   if (avc_add_callback (policy_reload_callback, AVC_CALLBACK_RESET,
323                        NULL, NULL, 0, 0) < 0)
324     {
325       _dbus_warn ("Failed to add policy reload callback: %s\n",
326                   _dbus_strerror (errno));
327       avc_destroy ();
328       return FALSE;
329     }
330
331   bus_context = NULL;
332   bus_sid = SECSID_WILD;
333
334   if (getcon (&bus_context) < 0)
335     {
336       _dbus_verbose ("Error getting context of bus: %s\n",
337                      _dbus_strerror (errno));
338       return FALSE;
339     }
340       
341   if (avc_context_to_sid (bus_context, &bus_sid) < 0)
342     {
343       _dbus_verbose ("Error getting SID from bus context: %s\n",
344                      _dbus_strerror (errno));
345       freecon (bus_context);
346       return FALSE;
347     }
348
349   freecon (bus_context);
350   
351   audit_init ();
352
353   return TRUE;
354 #else
355   return TRUE;
356 #endif /* HAVE_SELINUX */
357 }
358
359 /**
360  * Decrement SID reference count.
361  * 
362  * @param sid the SID to decrement
363  */
364 void
365 bus_selinux_id_unref (BusSELinuxID *sid)
366 {
367 #ifdef HAVE_SELINUX
368   if (!selinux_enabled)
369     return;
370
371   _dbus_assert (sid != NULL);
372   
373   sidput (SELINUX_SID_FROM_BUS (sid));
374 #endif /* HAVE_SELINUX */
375 }
376
377 void
378 bus_selinux_id_ref (BusSELinuxID *sid)
379 {
380 #ifdef HAVE_SELINUX
381   if (!selinux_enabled)
382     return;
383
384   _dbus_assert (sid != NULL);
385   
386   sidget (SELINUX_SID_FROM_BUS (sid));
387 #endif /* HAVE_SELINUX */
388 }
389
390 /**
391  * Determine if the SELinux security policy allows the given sender
392  * security context to go to the given recipient security context.
393  * This function determines if the requested permissions are to be
394  * granted from the connection to the message bus or to another
395  * optionally supplied security identifier (e.g. for a service
396  * context).  Currently these permissions are either send_msg or
397  * acquire_svc in the dbus class.
398  *
399  * @param sender_sid source security context
400  * @param override_sid is the target security context.  If SECSID_WILD this will
401  *        use the context of the bus itself (e.g. the default).
402  * @param target_class is the target security class.
403  * @param requested is the requested permissions.
404  * @returns #TRUE if security policy allows the send.
405  */
406 #ifdef HAVE_SELINUX
407 static dbus_bool_t
408 bus_selinux_check (BusSELinuxID        *sender_sid,
409                    BusSELinuxID        *override_sid,
410                    security_class_t     target_class,
411                    access_vector_t      requested,
412                    DBusString          *auxdata)
413 {
414   if (!selinux_enabled)
415     return TRUE;
416
417   /* Make the security check.  AVC checks enforcing mode here as well. */
418   if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid),
419                     override_sid ?
420                     SELINUX_SID_FROM_BUS (override_sid) :
421                     SELINUX_SID_FROM_BUS (bus_sid), 
422                     target_class, requested, &aeref, auxdata) < 0)
423     {
424       _dbus_verbose ("SELinux denying due to security policy.\n");
425       return FALSE;
426     }
427   else
428     return TRUE;
429 }
430 #endif /* HAVE_SELINUX */
431
432 /**
433  * Returns true if the given connection can acquire a service,
434  * assuming the given security ID is needed for that service.
435  *
436  * @param connection connection that wants to own the service
437  * @param service_sid the SID of the service from the table
438  * @returns #TRUE if acquire is permitted.
439  */
440 dbus_bool_t
441 bus_selinux_allows_acquire_service (DBusConnection     *connection,
442                                     BusSELinuxID       *service_sid,
443                                     const char         *service_name,
444                                     DBusError          *error)
445 {
446 #ifdef HAVE_SELINUX
447   BusSELinuxID *connection_sid;
448   unsigned long spid;
449   DBusString auxdata;
450   dbus_bool_t ret;
451   
452   if (!selinux_enabled)
453     return TRUE;
454   
455   connection_sid = bus_connection_get_selinux_id (connection);
456   if (!dbus_connection_get_unix_process_id (connection, &spid))
457     spid = 0;
458
459   if (!_dbus_string_init (&auxdata))
460     goto oom;
461  
462   if (!_dbus_string_append (&auxdata, "service="))
463     goto oom;
464
465   if (!_dbus_string_append (&auxdata, service_name))
466     goto oom;
467
468   if (spid)
469     {
470       if (!_dbus_string_append (&auxdata, " spid="))
471         goto oom;
472
473       if (!_dbus_string_append_uint (&auxdata, spid))
474         goto oom;
475     }
476   
477   ret = bus_selinux_check (connection_sid,
478                            service_sid,
479                            SECCLASS_DBUS,
480                            DBUS__ACQUIRE_SVC,
481                            &auxdata);
482
483   _dbus_string_free (&auxdata);
484   return ret;
485
486  oom:
487   _dbus_string_free (&auxdata);
488   BUS_SET_OOM (error);
489   return FALSE;
490
491 #else
492   return TRUE;
493 #endif /* HAVE_SELINUX */
494 }
495
496 /**
497  * Check if SELinux security controls allow the message to be sent to a
498  * particular connection based on the security context of the sender and
499  * that of the receiver. The destination connection need not be the
500  * addressed recipient, it could be an "eavesdropper"
501  *
502  * @param sender the sender of the message.
503  * @param proposed_recipient the connection the message is to be sent to.
504  * @returns whether to allow the send
505  */
506 dbus_bool_t
507 bus_selinux_allows_send (DBusConnection     *sender,
508                          DBusConnection     *proposed_recipient,
509                          const char         *msgtype,
510                          const char         *interface,
511                          const char         *member,
512                          const char         *error_name,
513                          const char         *destination,
514                          DBusError          *error)
515 {
516 #ifdef HAVE_SELINUX
517   BusSELinuxID *recipient_sid;
518   BusSELinuxID *sender_sid;
519   unsigned long spid, tpid;
520   DBusString auxdata;
521   dbus_bool_t ret;
522   dbus_bool_t string_alloced;
523
524   if (!selinux_enabled)
525     return TRUE;
526
527   if (!sender || !dbus_connection_get_unix_process_id (sender, &spid))
528     spid = 0;
529   if (!proposed_recipient || !dbus_connection_get_unix_process_id (proposed_recipient, &tpid))
530     tpid = 0;
531
532   string_alloced = FALSE;
533   if (!_dbus_string_init (&auxdata))
534     goto oom;
535   string_alloced = TRUE;
536
537   if (!_dbus_string_append (&auxdata, "msgtype="))
538     goto oom;
539
540   if (!_dbus_string_append (&auxdata, msgtype))
541     goto oom;
542
543   if (interface)
544     {
545       if (!_dbus_string_append (&auxdata, " interface="))
546         goto oom;
547       if (!_dbus_string_append (&auxdata, interface))
548         goto oom;
549     }
550
551   if (member)
552     {
553       if (!_dbus_string_append (&auxdata, " member="))
554         goto oom;
555       if (!_dbus_string_append (&auxdata, member))
556         goto oom;
557     }
558
559   if (error_name)
560     {
561       if (!_dbus_string_append (&auxdata, " error_name="))
562         goto oom;
563       if (!_dbus_string_append (&auxdata, error_name))
564         goto oom;
565     }
566
567   if (destination)
568     {
569       if (!_dbus_string_append (&auxdata, " dest="))
570         goto oom;
571       if (!_dbus_string_append (&auxdata, destination))
572         goto oom;
573     }
574
575   if (spid)
576     {
577       if (!_dbus_string_append (&auxdata, " spid="))
578         goto oom;
579
580       if (!_dbus_string_append_uint (&auxdata, spid))
581         goto oom;
582     }
583
584   if (tpid)
585     {
586       if (!_dbus_string_append (&auxdata, " tpid="))
587         goto oom;
588
589       if (!_dbus_string_append_uint (&auxdata, tpid))
590         goto oom;
591     }
592
593   sender_sid = bus_connection_get_selinux_id (sender);
594   /* A NULL proposed_recipient means the bus itself. */
595   if (proposed_recipient)
596     recipient_sid = bus_connection_get_selinux_id (proposed_recipient);
597   else
598     recipient_sid = BUS_SID_FROM_SELINUX (bus_sid);
599
600   ret = bus_selinux_check (sender_sid, 
601                            recipient_sid,
602                            SECCLASS_DBUS, 
603                            DBUS__SEND_MSG,
604                            &auxdata);
605
606   _dbus_string_free (&auxdata);
607
608   return ret;
609
610  oom:
611   if (string_alloced)
612     _dbus_string_free (&auxdata);
613   BUS_SET_OOM (error);
614   return FALSE;
615   
616 #else
617   return TRUE;
618 #endif /* HAVE_SELINUX */
619 }
620
621 dbus_bool_t
622 bus_selinux_append_context (DBusMessage    *message,
623                             BusSELinuxID   *sid,
624                             DBusError      *error)
625 {
626 #ifdef HAVE_SELINUX
627   char *context;
628
629   if (avc_sid_to_context (SELINUX_SID_FROM_BUS (sid), &context) < 0)
630     {
631       if (errno == ENOMEM)
632         BUS_SET_OOM (error);
633       else
634         dbus_set_error (error, DBUS_ERROR_FAILED,
635                         "Error getting context from SID: %s\n",
636                         _dbus_strerror (errno));
637       return FALSE;
638     }
639   if (!dbus_message_append_args (message,
640                                  DBUS_TYPE_ARRAY,
641                                  DBUS_TYPE_BYTE,
642                                  &context,
643                                  strlen (context),
644                                  DBUS_TYPE_INVALID))
645     {
646       _DBUS_SET_OOM (error);
647       return FALSE;
648     }
649   freecon (context);
650   return TRUE;
651 #else
652   return TRUE;
653 #endif
654 }
655
656 /**
657  * Gets the security context of a connection to the bus. It is up to
658  * the caller to freecon() when they are done. 
659  *
660  * @param connection the connection to get the context of.
661  * @param con the location to store the security context.
662  * @returns #TRUE if context is successfully obtained.
663  */
664 #ifdef HAVE_SELINUX
665 static dbus_bool_t
666 bus_connection_read_selinux_context (DBusConnection     *connection,
667                                      char              **con)
668 {
669   int fd;
670
671   if (!selinux_enabled)
672     return FALSE;
673
674   _dbus_assert (connection != NULL);
675   
676   if (!dbus_connection_get_unix_fd (connection, &fd))
677     {
678       _dbus_verbose ("Failed to get file descriptor of socket.\n");
679       return FALSE;
680     }
681   
682   if (getpeercon (fd, con) < 0)
683     {
684       _dbus_verbose ("Error getting context of socket peer: %s\n",
685                      _dbus_strerror (errno));
686       return FALSE;
687     }
688   
689   _dbus_verbose ("Successfully read connection context.\n");
690   return TRUE;
691 }
692 #endif /* HAVE_SELINUX */
693
694 /**
695  * Read the SELinux ID from the connection.
696  *
697  * @param connection the connection to read from
698  * @returns the SID if successfully determined, #NULL otherwise.
699  */
700 BusSELinuxID*
701 bus_selinux_init_connection_id (DBusConnection *connection,
702                                 DBusError      *error)
703 {
704 #ifdef HAVE_SELINUX
705   char *con;
706   security_id_t sid;
707   
708   if (!selinux_enabled)
709     return NULL;
710
711   if (!bus_connection_read_selinux_context (connection, &con))
712     {
713       dbus_set_error (error, DBUS_ERROR_FAILED,
714                       "Failed to read an SELinux context from connection");
715       _dbus_verbose ("Error getting peer context.\n");
716       return NULL;
717     }
718
719   _dbus_verbose ("Converting context to SID to store on connection\n");
720
721   if (avc_context_to_sid (con, &sid) < 0)
722     {
723       if (errno == ENOMEM)
724         BUS_SET_OOM (error);
725       else
726         dbus_set_error (error, DBUS_ERROR_FAILED,
727                         "Error getting SID from context \"%s\": %s\n",
728                         con, _dbus_strerror (errno));
729       
730       _dbus_warn ("Error getting SID from context \"%s\": %s\n",
731                   con, _dbus_strerror (errno));
732       
733       freecon (con);
734       return NULL;
735     }
736  
737   freecon (con); 
738   return BUS_SID_FROM_SELINUX (sid);
739 #else
740   return NULL;
741 #endif /* HAVE_SELINUX */
742 }
743
744
745 /**
746  * Function for freeing hash table data.  These SIDs
747  * should no longer be referenced.
748  */
749 static void
750 bus_selinux_id_table_free_value (BusSELinuxID *sid)
751 {
752 #ifdef HAVE_SELINUX
753   /* NULL sometimes due to how DBusHashTable works */
754   if (sid)
755     bus_selinux_id_unref (sid);
756 #endif /* HAVE_SELINUX */
757 }
758
759 /**
760  * Creates a new table mapping service names to security ID.
761  * A security ID is a "compiled" security context, a security
762  * context is just a string.
763  *
764  * @returns the new table or #NULL if no memory
765  */
766 DBusHashTable*
767 bus_selinux_id_table_new (void)
768 {
769   return _dbus_hash_table_new (DBUS_HASH_STRING,
770                                (DBusFreeFunction) dbus_free,
771                                (DBusFreeFunction) bus_selinux_id_table_free_value);
772 }
773
774 /** 
775  * Hashes a service name and service context into the service SID
776  * table as a string and a SID.
777  *
778  * @param service_name is the name of the service.
779  * @param service_context is the context of the service.
780  * @param service_table is the table to hash them into.
781  * @return #FALSE if not enough memory
782  */
783 dbus_bool_t
784 bus_selinux_id_table_insert (DBusHashTable *service_table,
785                              const char    *service_name,
786                              const char    *service_context)
787 {
788 #ifdef HAVE_SELINUX
789   dbus_bool_t retval;
790   security_id_t sid;
791   char *key;
792
793   if (!selinux_enabled)
794     return TRUE;
795
796   sid = SECSID_WILD;
797   retval = FALSE;
798
799   key = _dbus_strdup (service_name);
800   if (key == NULL)
801     return retval;
802   
803   if (avc_context_to_sid ((char *) service_context, &sid) < 0)
804     {
805       if (errno == ENOMEM)
806         {
807           dbus_free (key);
808           return FALSE;
809         }
810
811       _dbus_warn ("Error getting SID from context \"%s\": %s\n",
812                   (char *) service_context,
813                   _dbus_strerror (errno));
814       goto out;
815     }
816
817   if (!_dbus_hash_table_insert_string (service_table,
818                                        key,
819                                        BUS_SID_FROM_SELINUX (sid)))
820     goto out;
821
822   _dbus_verbose ("Parsed \tservice: %s \n\t\tcontext: %s\n",
823                   key, 
824                   sid->ctx);
825
826   /* These are owned by the hash, so clear them to avoid unref */
827   key = NULL;
828   sid = SECSID_WILD;
829
830   retval = TRUE;
831   
832  out:
833   if (sid != SECSID_WILD)
834     sidput (sid);
835
836   if (key)
837     dbus_free (key);
838
839   return retval;
840 #else
841   return TRUE;
842 #endif /* HAVE_SELINUX */
843 }
844
845
846 /**
847  * Find the security identifier associated with a particular service
848  * name.  Return a pointer to this SID, or #NULL/SECSID_WILD if the
849  * service is not found in the hash table.  This should be nearly a
850  * constant time operation.  If SELinux support is not available,
851  * always return NULL.
852  *
853  * @param service_table the hash table to check for service name.
854  * @param service_name the name of the service to look for.
855  * @returns the SELinux ID associated with the service
856  */
857 BusSELinuxID*
858 bus_selinux_id_table_lookup (DBusHashTable    *service_table,
859                              const DBusString *service_name)
860 {
861 #ifdef HAVE_SELINUX
862   security_id_t sid;
863
864   sid = SECSID_WILD;     /* default context */
865
866   if (!selinux_enabled)
867     return NULL;
868   
869   _dbus_verbose ("Looking up service SID for %s\n",
870                  _dbus_string_get_const_data (service_name));
871
872   sid = _dbus_hash_table_lookup_string (service_table,
873                                         _dbus_string_get_const_data (service_name));
874
875   if (sid == SECSID_WILD)
876     _dbus_verbose ("Service %s not found\n", 
877                    _dbus_string_get_const_data (service_name));
878   else
879     _dbus_verbose ("Service %s found\n", 
880                    _dbus_string_get_const_data (service_name));
881
882   return BUS_SID_FROM_SELINUX (sid);
883 #endif /* HAVE_SELINUX */
884   return NULL;
885 }
886
887 /**
888  * Get the SELinux policy root.  This is used to find the D-Bus
889  * specific config file within the policy.
890  */
891 const char *
892 bus_selinux_get_policy_root (void)
893 {
894 #ifdef HAVE_SELINUX
895   return selinux_policy_root ();
896 #else
897   return NULL;
898 #endif /* HAVE_SELINUX */
899
900
901 /**
902  * For debugging:  Print out the current hash table of service SIDs.
903  */
904 void
905 bus_selinux_id_table_print (DBusHashTable *service_table)
906 {
907 #ifdef DBUS_ENABLE_VERBOSE_MODE
908 #ifdef HAVE_SELINUX
909   DBusHashIter iter;
910
911   if (!selinux_enabled)
912     return;
913   
914   _dbus_verbose ("Service SID Table:\n");
915   _dbus_hash_iter_init (service_table, &iter);
916   while (_dbus_hash_iter_next (&iter))
917     {
918       const char *key = _dbus_hash_iter_get_string_key (&iter);
919       security_id_t sid = _dbus_hash_iter_get_value (&iter);
920       _dbus_verbose ("The key is %s\n", key);
921       _dbus_verbose ("The context is %s\n", sid->ctx);
922       _dbus_verbose ("The refcount is %d\n", sid->refcnt);
923     }
924 #endif /* HAVE_SELINUX */
925 #endif /* DBUS_ENABLE_VERBOSE_MODE */
926 }
927
928
929 #ifdef DBUS_ENABLE_VERBOSE_MODE
930 #ifdef HAVE_SELINUX
931 /**
932  * Print out some AVC statistics.
933  */
934 static void
935 bus_avc_print_stats (void)
936 {
937   struct avc_cache_stats cstats;
938
939   if (!selinux_enabled)
940     return;
941   
942   _dbus_verbose ("AVC Statistics:\n");
943   avc_cache_stats (&cstats);
944   avc_av_stats ();
945   _dbus_verbose ("AVC Cache Statistics:\n");
946   _dbus_verbose ("Entry lookups: %d\n", cstats.entry_lookups);
947   _dbus_verbose ("Entry hits: %d\n", cstats.entry_hits);
948   _dbus_verbose ("Entry misses %d\n", cstats.entry_misses);
949   _dbus_verbose ("Entry discards: %d\n", cstats.entry_discards);
950   _dbus_verbose ("CAV lookups: %d\n", cstats.cav_lookups);
951   _dbus_verbose ("CAV hits: %d\n", cstats.cav_hits);
952   _dbus_verbose ("CAV probes: %d\n", cstats.cav_probes);
953   _dbus_verbose ("CAV misses: %d\n", cstats.cav_misses);
954 }
955 #endif /* HAVE_SELINUX */
956 #endif /* DBUS_ENABLE_VERBOSE_MODE */
957
958
959 /**
960  * Destroy the AVC before we terminate.
961  */
962 void
963 bus_selinux_shutdown (void)
964 {
965 #ifdef HAVE_SELINUX
966   if (!selinux_enabled)
967     return;
968
969   _dbus_verbose ("AVC shutdown\n");
970
971   if (bus_sid != SECSID_WILD)
972     {
973       sidput (bus_sid);
974       bus_sid = SECSID_WILD;
975
976 #ifdef DBUS_ENABLE_VERBOSE_MODE
977  
978       if (_dbus_is_verbose()) 
979         bus_avc_print_stats ();
980  
981 #endif /* DBUS_ENABLE_VERBOSE_MODE */
982
983       avc_destroy ();
984 #ifdef HAVE_LIBAUDIT
985       audit_close (audit_fd);
986 #endif /* HAVE_LIBAUDIT */
987     }
988 #endif /* HAVE_SELINUX */
989 }
990