audit: use DBUS_SYSTEM_LOG_WARNING if we cannot open the audit fd
[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   audit_fd = audit_open ();
56
57   if (audit_fd < 0)
58     {
59       int e = errno;
60
61       /* If kernel doesn't support audit, bail out */
62       if (e == EINVAL || e == EPROTONOSUPPORT || e == EAFNOSUPPORT)
63         return;
64
65       /* If user bus, bail out */
66       if (e == EPERM && getuid () != 0)
67         return;
68
69       bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
70                        "Failed to open connection to the audit subsystem: %s",
71                        _dbus_strerror (e));
72     }
73 #endif /* HAVE_LIBAUDIT */
74 }
75
76 /**
77  * If libaudit is in use and it would be appropriate to write audit records,
78  * return the libaudit fd. Otherwise return -1.
79  */
80 int
81 bus_audit_get_fd (void)
82 {
83 #ifdef HAVE_LIBAUDIT
84   if (audit_fd >= 0)
85   {
86     capng_get_caps_process ();
87
88     if (!capng_have_capability (CAPNG_EFFECTIVE, CAP_AUDIT_WRITE))
89       return -1;
90
91     return audit_fd;
92   }
93 #endif
94
95   return -1;
96 }
97
98 /**
99  * Close the libaudit fd.
100  */
101 void
102 bus_audit_shutdown (void)
103 {
104 #ifdef HAVE_LIBAUDIT
105   audit_close (audit_fd);
106 #endif /* HAVE_LIBAUDIT */
107 }
108
109 /* The !HAVE_LIBAUDIT case lives in dbus-sysdeps-util-unix.c */
110 #ifdef HAVE_LIBAUDIT
111 /**
112  * Changes the user and group the bus is running as.
113  *
114  * @param user the user to become
115  * @param error return location for errors
116  * @returns #FALSE on failure
117  */
118 dbus_bool_t
119 _dbus_change_to_daemon_user  (const char    *user,
120                               DBusError     *error)
121 {
122   dbus_uid_t uid;
123   dbus_gid_t gid;
124   DBusString u;
125
126   _dbus_string_init_const (&u, user);
127
128   if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
129     {
130       dbus_set_error (error, DBUS_ERROR_FAILED,
131                       "User '%s' does not appear to exist?",
132                       user);
133       return FALSE;
134     }
135
136   /* If we were root */
137   if (_dbus_geteuid () == 0)
138     {
139       int rc;
140       int have_audit_write;
141
142       have_audit_write = capng_have_capability (CAPNG_PERMITTED, CAP_AUDIT_WRITE);
143       capng_clear (CAPNG_SELECT_BOTH);
144       /* Only attempt to retain CAP_AUDIT_WRITE if we had it when
145        * starting.  See:
146        * https://bugs.freedesktop.org/show_bug.cgi?id=49062#c9
147        */
148       if (have_audit_write)
149         capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
150                       CAP_AUDIT_WRITE);
151       rc = capng_change_id (uid, gid, CAPNG_DROP_SUPP_GRP);
152       if (rc)
153         {
154           switch (rc) {
155             default:
156               dbus_set_error (error, DBUS_ERROR_FAILED,
157                               "Failed to drop capabilities: %s\n",
158                               _dbus_strerror (errno));
159               break;
160             case -4:
161               dbus_set_error (error, _dbus_error_from_errno (errno),
162                               "Failed to set GID to %lu: %s", gid,
163                               _dbus_strerror (errno));
164               break;
165             case -5:
166               _dbus_warn ("Failed to drop supplementary groups: %s\n",
167                           _dbus_strerror (errno));
168               break;
169             case -6:
170               dbus_set_error (error, _dbus_error_from_errno (errno),
171                               "Failed to set UID to %lu: %s", uid,
172                               _dbus_strerror (errno));
173               break;
174             case -7:
175               dbus_set_error (error, _dbus_error_from_errno (errno),
176                               "Failed to unset keep-capabilities: %s\n",
177                               _dbus_strerror (errno));
178               break;
179           }
180           return FALSE;
181         }
182     }
183
184  return TRUE;
185 }
186 #endif