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