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