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