2004-08-09 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / bus / selinux.c
1 /* selinux.c  SELinux security checks for D-BUS
2  *
3  * Author: Matthew Rickard <mjricka@epoch.ncsc.mil>
4  *
5  * Licensed under the Academic Free License version 2.1
6  * 
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 #include <dbus/dbus-internals.h>
23 #include <dbus/dbus-string.h>
24 #include "selinux.h"
25 #include "services.h"
26 #include "policy.h"
27 #include "utils.h"
28 #include "config-parser.h"
29
30 #ifdef HAVE_SELINUX
31 #include <errno.h>
32 #include <syslog.h>
33 #include <selinux/selinux.h>
34 #include <selinux/avc.h>
35 #include <selinux/av_permissions.h>
36 #include <selinux/flask.h>
37 #include <stdarg.h>
38 #endif /* HAVE_SELINUX */
39
40 #define BUS_SID_FROM_SELINUX(sid)  ((BusSELinuxID*) (sid))
41 #define SELINUX_SID_FROM_BUS(sid)  ((security_id_t) (sid))
42
43 #ifdef HAVE_SELINUX
44 /* Store the value telling us if SELinux is enabled in the kernel. */
45 static dbus_bool_t selinux_enabled = FALSE;
46
47 /* Store an avc_entry_ref to speed AVC decisions. */
48 static struct avc_entry_ref aeref;
49
50 static security_id_t bus_sid = SECSID_WILD;
51 #endif /* HAVE_SELINUX */
52
53 /**
54  * Log callback to log denial messages from the AVC.
55  * This is used in avc_init.  Logs to both standard
56  * error and syslogd.
57  *
58  * @param fmt the format string
59  * @param variable argument list
60  */
61 #ifdef HAVE_SELINUX
62 static void 
63 log_callback (const char *fmt, ...) 
64 {
65   va_list ap;
66   va_start(ap, fmt);
67   vsyslog (LOG_INFO, fmt, ap);
68   va_end(ap);
69 }
70 #endif /* HAVE_SELINUX */
71
72
73 /**
74  * Initialize the user space access vector cache (AVC) for D-BUS and set up
75  * logging callbacks.
76  */
77 dbus_bool_t
78 bus_selinux_init (void)
79 {
80 #ifdef HAVE_SELINUX
81   struct avc_log_callback log_cb = {(void*)log_callback, NULL};
82   int r;
83   char *bus_context;
84
85   _dbus_assert (bus_sid == SECSID_WILD);
86   
87   /* Determine if we are running an SELinux kernel. */
88   r = is_selinux_enabled ();
89   if (r < 0)
90     {
91       _dbus_warn ("Could not tell if SELinux is enabled: %s\n",
92                   _dbus_strerror (errno));
93       return FALSE;
94     }
95
96   selinux_enabled = r != 0;
97
98   if (!selinux_enabled)
99     {
100       _dbus_verbose ("SELinux not enabled in this kernel.\n");
101       return TRUE;
102     }
103
104   _dbus_verbose ("SELinux is enabled in this kernel.\n");
105
106   avc_entry_ref_init (&aeref);
107   if (avc_init ("avc", NULL, &log_cb, NULL, NULL) < 0)
108     {
109       _dbus_warn ("Failed to start Access Vector Cache (AVC).\n");
110       return FALSE;
111     }
112   else
113     {
114       openlog ("dbus", LOG_PERROR, LOG_USER);
115       _dbus_verbose ("Access Vector Cache (AVC) started.\n");
116     }
117
118   bus_context = NULL;
119   bus_sid = SECSID_WILD;
120
121   if (getcon (&bus_context) < 0)
122     {
123       _dbus_verbose ("Error getting context of bus: %s\n",
124                      _dbus_strerror (errno));
125       return FALSE;
126     }
127       
128   if (avc_context_to_sid (bus_context, &bus_sid) < 0)
129     {
130       _dbus_verbose ("Error getting SID from bus context: %s\n",
131                      _dbus_strerror (errno));
132       freecon (bus_context);
133       return FALSE;
134     }
135
136   freecon (bus_context);
137   
138   return TRUE;
139 #else
140   return TRUE;
141 #endif /* HAVE_SELINUX */
142 }
143
144
145 /**
146  * Decrement SID reference count.
147  * 
148  * @param sid the SID to decrement
149  */
150 void
151 bus_selinux_id_unref (BusSELinuxID *sid)
152 {
153 #ifdef HAVE_SELINUX
154   if (!selinux_enabled)
155     return;
156
157   _dbus_assert (sid != NULL);
158   
159   sidput (SELINUX_SID_FROM_BUS (sid));
160 #endif /* HAVE_SELINUX */
161 }
162
163 void
164 bus_selinux_id_ref (BusSELinuxID *sid)
165 {
166 #ifdef HAVE_SELINUX
167   if (!selinux_enabled)
168     return;
169
170   _dbus_assert (sid != NULL);
171   
172   sidget (SELINUX_SID_FROM_BUS (sid));
173 #endif /* HAVE_SELINUX */
174 }
175
176 /**
177  * Determine if the SELinux security policy allows the given sender
178  * security context to go to the given recipient security context.
179  * This function determines if the requested permissions are to be
180  * granted from the connection to the message bus or to another
181  * optionally supplied security identifier (e.g. for a service
182  * context).  Currently these permissions are either send_msg or
183  * acquire_svc in the dbus class.
184  *
185  * @param sender_sid source security context
186  * @param override_sid is the target security context.  If SECSID_WILD this will
187  *        use the context of the bus itself (e.g. the default).
188  * @param target_class is the target security class.
189  * @param requested is the requested permissions.
190  * @returns #TRUE if security policy allows the send.
191  */
192 #ifdef HAVE_SELINUX
193 static dbus_bool_t
194 bus_selinux_check (BusSELinuxID        *sender_sid,
195                    BusSELinuxID        *override_sid,
196                    security_class_t     target_class,
197                    access_vector_t      requested)
198 {
199   if (!selinux_enabled)
200     return TRUE;
201   
202   /* Make the security check.  AVC checks enforcing mode here as well. */
203   if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid),
204                     override_sid ?
205                     SELINUX_SID_FROM_BUS (override_sid) :
206                     SELINUX_SID_FROM_BUS (bus_sid), 
207                     target_class, requested, &aeref, NULL) < 0)
208     {
209       _dbus_verbose ("SELinux denying due to security policy.\n");
210       return FALSE;
211     }
212   else
213     return TRUE;
214 }
215 #endif /* HAVE_SELINUX */
216
217 /**
218  * Returns true if the given connection can acquire a service,
219  * assuming the given security ID is needed for that service.
220  *
221  * @param connection connection that wants to own the service
222  * @param service_sid the SID of the service from the table
223  * @returns #TRUE if acquire is permitted.
224  */
225 dbus_bool_t
226 bus_selinux_allows_acquire_service (DBusConnection     *connection,
227                                     BusSELinuxID       *service_sid)
228 {
229 #ifdef HAVE_SELINUX
230   BusSELinuxID *connection_sid;
231   
232   if (!selinux_enabled)
233     return TRUE;
234
235   connection_sid = bus_connection_get_selinux_id (connection);
236   
237   return bus_selinux_check (connection_sid,
238                             service_sid,
239                             SECCLASS_DBUS,
240                             DBUS__ACQUIRE_SVC);
241 #else
242   return TRUE;
243 #endif /* HAVE_SELINUX */
244 }
245
246 /**
247  * Check if SELinux security controls allow the message to be sent to a
248  * particular connection based on the security context of the sender and
249  * that of the receiver. The destination connection need not be the
250  * addressed recipient, it could be an "eavesdropper"
251  *
252  * @param sender the sender of the message.
253  * @param proposed_recipient the connection the message is to be sent to.
254  * @returns whether to allow the send
255  */
256 dbus_bool_t
257 bus_selinux_allows_send (DBusConnection     *sender,
258                          DBusConnection     *proposed_recipient)
259 {
260 #ifdef HAVE_SELINUX
261   BusSELinuxID *recipient_sid;
262   BusSELinuxID *sender_sid;
263
264   if (!selinux_enabled)
265     return TRUE;
266
267   sender_sid = bus_connection_get_selinux_id (sender);
268   /* A NULL proposed_recipient means the bus itself. */
269   if (proposed_recipient)
270     recipient_sid = bus_connection_get_selinux_id (proposed_recipient);
271   else
272     recipient_sid = BUS_SID_FROM_SELINUX (bus_sid);
273
274   return bus_selinux_check (sender_sid, recipient_sid,
275                             SECCLASS_DBUS, DBUS__SEND_MSG);
276 #else
277   return TRUE;
278 #endif /* HAVE_SELINUX */
279 }
280
281 /**
282  * Gets the security context of a connection to the bus. It is up to
283  * the caller to freecon() when they are done. 
284  *
285  * @param connection the connection to get the context of.
286  * @param con the location to store the security context.
287  * @returns #TRUE if context is successfully obtained.
288  */
289 #ifdef HAVE_SELINUX
290 static dbus_bool_t
291 bus_connection_read_selinux_context (DBusConnection     *connection,
292                                      char              **con)
293 {
294   int fd;
295
296   if (!selinux_enabled)
297     return FALSE;
298
299   _dbus_assert (connection != NULL);
300   
301   if (!dbus_connection_get_unix_fd (connection, &fd))
302     {
303       _dbus_verbose ("Failed to get file descriptor of socket.\n");
304       return FALSE;
305     }
306   
307   if (getpeercon (fd, con) < 0)
308     {
309       _dbus_verbose ("Error getting context of socket peer: %s\n",
310                      _dbus_strerror (errno));
311       return FALSE;
312     }
313   
314   _dbus_verbose ("Successfully read connection context.\n");
315   return TRUE;
316 }
317 #endif /* HAVE_SELINUX */
318
319 /**
320  * Read the SELinux ID from the connection.
321  *
322  * @param connection the connection to read from
323  * @returns the SID if successfully determined, #NULL otherwise.
324  */
325 BusSELinuxID*
326 bus_selinux_init_connection_id (DBusConnection *connection,
327                                 DBusError      *error)
328 {
329 #ifdef HAVE_SELINUX
330   char *con;
331   security_id_t sid;
332   
333   if (!selinux_enabled)
334     return NULL;
335
336   if (!bus_connection_read_selinux_context (connection, &con))
337     {
338       dbus_set_error (error, DBUS_ERROR_FAILED,
339                       "Failed to read an SELinux context from connection");
340       _dbus_verbose ("Error getting peer context.\n");
341       return NULL;
342     }
343
344   _dbus_verbose ("Converting context to SID to store on connection\n");
345
346   if (avc_context_to_sid (con, &sid) < 0)
347     {
348       if (errno == ENOMEM)
349         BUS_SET_OOM (error);
350       else
351         dbus_set_error (error, DBUS_ERROR_FAILED,
352                         "Error getting SID from context: %s\n",
353                         _dbus_strerror (errno));
354       
355       _dbus_warn ("Error getting SID from context: %s\n",
356                   _dbus_strerror (errno));
357       
358       freecon (con);
359       return NULL;
360     }
361  
362   freecon (con); 
363   return BUS_SID_FROM_SELINUX (sid);
364 #else
365   return NULL;
366 #endif /* HAVE_SELINUX */
367 }
368
369
370 /* Function for freeing hash table data.  These SIDs
371  * should no longer be referenced.
372  */
373 static void
374 bus_selinux_id_table_free_value (BusSELinuxID *sid)
375 {
376 #ifdef HAVE_SELINUX
377   /* NULL sometimes due to how DBusHashTable works */
378   if (sid)
379     bus_selinux_id_unref (sid);
380 #endif /* HAVE_SELINUX */
381 }
382
383 /**
384  * Creates a new table mapping service names to security ID.
385  * A security ID is a "compiled" security context, a security
386  * context is just a string.
387  *
388  * @returns the new table or #NULL if no memory
389  */
390 DBusHashTable*
391 bus_selinux_id_table_new (void)
392 {
393   return _dbus_hash_table_new (DBUS_HASH_STRING,
394                                (DBusFreeFunction) dbus_free,
395                                (DBusFreeFunction) bus_selinux_id_table_free_value);
396 }
397
398 /** 
399  * Hashes a service name and service context into the service SID
400  * table as a string and a SID.
401  *
402  * @param service_name is the name of the service.
403  * @param service_context is the context of the service.
404  * @param service_table is the table to hash them into.
405  * @return #FALSE if not enough memory
406  */
407 dbus_bool_t
408 bus_selinux_id_table_insert (DBusHashTable *service_table,
409                              const char    *service_name,
410                              const char    *service_context)
411 {
412 #ifdef HAVE_SELINUX
413   dbus_bool_t retval;
414   security_id_t sid;
415   char *key;
416
417   if (!selinux_enabled)
418     return TRUE;
419
420   sid = SECSID_WILD;
421   retval = FALSE;
422
423   key = _dbus_strdup (service_name);
424   if (key == NULL)
425     return retval;
426   
427   if (avc_context_to_sid (service_context, &sid) < 0)
428     {
429       _dbus_assert (errno == ENOMEM);
430       goto out;
431     }
432
433   if (!_dbus_hash_table_insert_string (service_table,
434                                        key,
435                                        BUS_SID_FROM_SELINUX (sid)))
436     goto out;
437
438   _dbus_verbose ("Parsed \tservice: %s \n\t\tcontext: %s\n",
439                   key, 
440                   sid->ctx);
441
442   /* These are owned by the hash, so clear them to avoid unref */
443   key = NULL;
444   sid = SECSID_WILD;
445
446   retval = TRUE;
447   
448  out:
449   if (sid != SECSID_WILD)
450     sidput (sid);
451
452   if (key)
453     dbus_free (key);
454
455   return retval;
456 #else
457   return TRUE;
458 #endif /* HAVE_SELINUX */
459 }
460
461
462 /**
463  * Find the security identifier associated with a particular service
464  * name.  Return a pointer to this SID, or #NULL/SECSID_WILD if the
465  * service is not found in the hash table.  This should be nearly a
466  * constant time operation.  If SELinux support is not available,
467  * always return NULL.
468  *
469  * @todo This should return a const security_id_t since we don't
470  *       want the caller to mess with it.
471  *
472  * @param service_table the hash table to check for service name.
473  * @param service_name the name of the service to look for.
474  * @returns the SELinux ID associated with the service
475  */
476 BusSELinuxID*
477 bus_selinux_id_table_lookup (DBusHashTable    *service_table,
478                              const DBusString *service_name)
479 {
480 #ifdef HAVE_SELINUX
481   security_id_t sid;
482
483   sid = SECSID_WILD;     /* default context */
484
485   if (!selinux_enabled)
486     return NULL;
487   
488   _dbus_verbose ("Looking up service SID for %s\n",
489                  _dbus_string_get_const_data (service_name));
490
491   sid = _dbus_hash_table_lookup_string (service_table,
492                                         _dbus_string_get_const_data (service_name));
493
494   if (sid == SECSID_WILD)
495     _dbus_verbose ("Service %s not found\n", 
496                    _dbus_string_get_const_data (service_name));
497   else
498     _dbus_verbose ("Service %s found\n", 
499                    _dbus_string_get_const_data (service_name));
500
501   return BUS_SID_FROM_SELINUX (sid);
502 #endif /* HAVE_SELINUX */
503   return NULL;
504 }
505
506 #ifdef HAVE_SELINUX
507 static dbus_bool_t
508 bus_selinux_id_table_copy_over (DBusHashTable    *dest,
509                                 DBusHashTable    *override)
510 {
511   const char *key;
512   char *key_copy;
513   BusSELinuxID *sid;
514   DBusHashIter iter;
515   
516   _dbus_hash_iter_init (override, &iter);
517   while (_dbus_hash_iter_next (&iter))
518     {
519       key = _dbus_hash_iter_get_string_key (&iter);
520       sid = _dbus_hash_iter_get_value (&iter);
521
522       key_copy = _dbus_strdup (key);
523       if (key_copy == NULL)
524         return FALSE;
525
526       if (!_dbus_hash_table_insert_string (dest,
527                                            key_copy,
528                                            sid))
529         {
530           dbus_free (key_copy);
531           return FALSE;
532         }
533
534       bus_selinux_id_ref (sid);
535     }
536
537   return TRUE;
538 }
539 #endif /* HAVE_SELINUX */
540
541 /**
542  * Creates the union of the two tables (each table maps a service
543  * name to a security ID). In case of the same service name in
544  * both tables, the security ID from "override" will be used.
545  *
546  * @param base the base table
547  * @param override the table that takes precedence in the merge
548  * @returns the new table, or #NULL if out of memory
549  */
550 DBusHashTable*
551 bus_selinux_id_table_union (DBusHashTable    *base,
552                             DBusHashTable    *override)
553 {
554   DBusHashTable *combined_table;
555
556   combined_table = bus_selinux_id_table_new ();
557
558   if (combined_table == NULL)
559     return NULL;
560   
561 #ifdef HAVE_SELINUX 
562   if (!selinux_enabled)
563     return combined_table;
564
565   if (!bus_selinux_id_table_copy_over (combined_table, base))
566     {
567       _dbus_hash_table_unref (combined_table);
568       return NULL;
569     }
570
571   if (!bus_selinux_id_table_copy_over (combined_table, override))
572     {
573       _dbus_hash_table_unref (combined_table);
574       return NULL;
575     }
576 #endif /* HAVE_SELINUX */
577   
578   return combined_table;
579 }
580
581 /**
582  * For debugging:  Print out the current hash table of service SIDs.
583  */
584 void
585 bus_selinux_id_table_print (DBusHashTable *service_table)
586 {
587 #ifdef DBUS_ENABLE_VERBOSE_MODE
588 #ifdef HAVE_SELINUX
589   DBusHashIter iter;
590
591   if (!selinux_enabled)
592     return;
593   
594   _dbus_verbose ("Service SID Table:\n");
595   _dbus_hash_iter_init (service_table, &iter);
596   while (_dbus_hash_iter_next (&iter))
597     {
598       const char *key = _dbus_hash_iter_get_string_key (&iter);
599       security_id_t sid = _dbus_hash_iter_get_value (&iter);
600       _dbus_verbose ("The key is %s\n", key);
601       _dbus_verbose ("The context is %s\n", sid->ctx);
602       _dbus_verbose ("The refcount is %d\n", sid->refcnt);
603     }
604 #endif /* HAVE_SELINUX */
605 #endif /* DBUS_ENABLE_VERBOSE_MODE */
606 }
607
608
609 #ifdef DBUS_ENABLE_VERBOSE_MODE
610 #ifdef HAVE_SELINUX
611 /**
612  * Print out some AVC statistics.
613  */
614 static void
615 bus_avc_print_stats (void)
616 {
617   struct avc_cache_stats cstats;
618
619   if (!selinux_enabled)
620     return;
621   
622   _dbus_verbose ("AVC Statistics:\n");
623   avc_cache_stats (&cstats);
624   avc_av_stats ();
625   _dbus_verbose ("AVC Cache Statistics:\n");
626   _dbus_verbose ("Entry lookups: %d\n", cstats.entry_lookups);
627   _dbus_verbose ("Entry hits: %d\n", cstats.entry_hits);
628   _dbus_verbose ("Entry misses %d\n", cstats.entry_misses);
629   _dbus_verbose ("Entry discards: %d\n", cstats.entry_discards);
630   _dbus_verbose ("CAV lookups: %d\n", cstats.cav_lookups);
631   _dbus_verbose ("CAV hits: %d\n", cstats.cav_hits);
632   _dbus_verbose ("CAV probes: %d\n", cstats.cav_probes);
633   _dbus_verbose ("CAV misses: %d\n", cstats.cav_misses);
634 }
635 #endif /* HAVE_SELINUX */
636 #endif /* DBUS_ENABLE_VERBOSE_MODE */
637
638
639 /**
640  * Destroy the AVC before we terminate.
641  */
642 void
643 bus_selinux_shutdown (void)
644 {
645 #ifdef HAVE_SELINUX
646   if (!selinux_enabled)
647     return;
648
649   sidput (bus_sid);
650   bus_sid = SECSID_WILD;
651   
652 #ifdef DBUS_ENABLE_VERBOSE_MODE
653   bus_avc_print_stats ();
654 #endif /* DBUS_ENABLE_VERBOSE_MODE */
655
656   avc_destroy ();
657 #endif /* HAVE_SELINUX */
658 }
659