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