Add IgnoreOnIsolate=yes to dbus.service
[platform/upstream/dbus.git] / bus / audit.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  * audit.c - libaudit integration for SELinux and AppArmor
3  *
4  * Based on apparmor.c, selinux.c
5  *
6  * Copyright © 2014-2015 Canonical, Ltd.
7  * Copyright © 2015 Collabora Ltd.
8  *
9  * Licensed under the Academic Free License version 2.1
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  */
26
27 #include <config.h>
28 #include "audit.h"
29
30 #ifdef HAVE_ERRNO_H
31 #include <errno.h>
32 #endif
33
34 #ifdef HAVE_LIBAUDIT
35 #include <cap-ng.h>
36 #include <libaudit.h>
37 #endif
38
39 #include <dbus/dbus-internals.h>
40 #ifdef DBUS_UNIX
41 #include <dbus/dbus-userdb.h>
42 #endif
43
44 #ifdef HAVE_LIBAUDIT
45 static int audit_fd = -1;
46 #endif
47
48 /**
49  * Open the libaudit fd if appropriate.
50  */
51 void
52 bus_audit_init (BusContext *context)
53 {
54 #ifdef HAVE_LIBAUDIT
55   int i;
56
57   capng_get_caps_process ();
58
59   /* Work around a bug in libcap-ng < 0.7.7: it leaks a fd, which isn't
60    * close-on-exec. Assume it will be one of the first few fds. */
61   for (i = 3; i < 42; i++)
62     _dbus_fd_set_close_on_exec (i);
63
64   if (!capng_have_capability (CAPNG_EFFECTIVE, CAP_AUDIT_WRITE))
65     return;
66
67   audit_fd = audit_open ();
68
69   if (audit_fd < 0)
70     {
71       int e = errno;
72
73       /* If kernel doesn't support audit, bail out */
74       if (e == EINVAL || e == EPROTONOSUPPORT || e == EAFNOSUPPORT)
75         return;
76
77       bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
78                        "Failed to open connection to the audit subsystem: %s",
79                        _dbus_strerror (e));
80     }
81 #endif /* HAVE_LIBAUDIT */
82 }
83
84 /**
85  * If libaudit is in use and it would be appropriate to write audit records,
86  * return the libaudit fd. Otherwise return -1.
87  */
88 int
89 bus_audit_get_fd (void)
90 {
91 #ifdef HAVE_LIBAUDIT
92   if (audit_fd >= 0)
93   {
94     return audit_fd;
95   }
96 #endif
97
98   return -1;
99 }
100
101 /**
102  * Close the libaudit fd.
103  */
104 void
105 bus_audit_shutdown (void)
106 {
107 #ifdef HAVE_LIBAUDIT
108   audit_close (audit_fd);
109 #endif /* HAVE_LIBAUDIT */
110 }
111
112 /* The !HAVE_LIBAUDIT case lives in dbus-sysdeps-util-unix.c */
113 #ifdef HAVE_LIBAUDIT
114 /**
115  * Changes the user and group the bus is running as.
116  *
117  * @param user the user to become
118  * @param error return location for errors
119  * @returns #FALSE on failure
120  */
121 dbus_bool_t
122 _dbus_change_to_daemon_user  (const char    *user,
123                               DBusError     *error)
124 {
125   dbus_uid_t uid;
126   dbus_gid_t gid;
127   DBusString u;
128
129   _dbus_string_init_const (&u, user);
130
131   if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
132     {
133       dbus_set_error (error, DBUS_ERROR_FAILED,
134                       "User '%s' does not appear to exist?",
135                       user);
136       return FALSE;
137     }
138
139   /* If we were root */
140   if (_dbus_geteuid () == 0)
141     {
142       int rc;
143       int have_audit_write;
144
145       have_audit_write = capng_have_capability (CAPNG_PERMITTED, CAP_AUDIT_WRITE);
146       capng_clear (CAPNG_SELECT_BOTH);
147       /* Only attempt to retain CAP_AUDIT_WRITE if we had it when
148        * starting.  See:
149        * https://bugs.freedesktop.org/show_bug.cgi?id=49062#c9
150        */
151       if (have_audit_write)
152         capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
153                       CAP_AUDIT_WRITE);
154       rc = capng_change_id (uid, gid, CAPNG_DROP_SUPP_GRP);
155       if (rc)
156         {
157           switch (rc) {
158             default:
159               dbus_set_error (error, DBUS_ERROR_FAILED,
160                               "Failed to drop capabilities: %s\n",
161                               _dbus_strerror (errno));
162               break;
163             case -4:
164               dbus_set_error (error, _dbus_error_from_errno (errno),
165                               "Failed to set GID to %lu: %s", gid,
166                               _dbus_strerror (errno));
167               break;
168             case -5:
169               dbus_set_error (error, _dbus_error_from_errno (errno),
170                               "Failed to drop supplementary groups: %s",
171                               _dbus_strerror (errno));
172               break;
173             case -6:
174               dbus_set_error (error, _dbus_error_from_errno (errno),
175                               "Failed to set UID to %lu: %s", uid,
176                               _dbus_strerror (errno));
177               break;
178             case -7:
179               dbus_set_error (error, _dbus_error_from_errno (errno),
180                               "Failed to unset keep-capabilities: %s\n",
181                               _dbus_strerror (errno));
182               break;
183           }
184           return FALSE;
185         }
186     }
187
188  return TRUE;
189 }
190 #endif