Revert "Rename authorized_identity in authenticated_identity for clarity sake."
[platform/upstream/dbus.git] / dbus / dbus-authorization.c
1 #include <config.h>
2 #include "dbus-internals.h"
3 #include "dbus-authorization.h"
4 #include "dbus-connection.h"
5 #include "dbus-connection-internal.h"
6
7 struct DBusAuthorization {
8   int refcount;
9
10   DBusConnection *connection;
11
12   /* Authorization functions, used as callback by SASL (implemented by
13    * DBUsAuth) */
14   DBusAllowUnixUserFunction unix_authorization_cb;
15   void *unix_data;
16   DBusFreeFunction unix_data_free;
17
18   DBusAllowWindowsUserFunction windows_authorization_cb;
19   void *windows_data;
20   DBusFreeFunction windows_data_free;
21
22   dbus_bool_t allow_anonymous;
23 };
24
25
26 DBusAuthorization *
27 _dbus_authorization_new (void)
28 {
29   DBusAuthorization *ret;
30
31   ret = dbus_malloc0 (sizeof (DBusAuthorization));
32   if (ret == NULL)
33     {
34       _dbus_verbose ("OOM\n");
35       return NULL; /* OOM */
36     }
37
38   ret->refcount = 1;
39
40   return ret;
41 }
42
43 DBusAuthorization *
44 _dbus_authorization_ref (DBusAuthorization *self)
45 {
46   _dbus_assert (self != NULL);
47
48   self->refcount += 1;
49
50   return self;
51 }
52
53 void
54 _dbus_authorization_unref (DBusAuthorization *self)
55 {
56   _dbus_assert (self != NULL);
57   _dbus_assert (self->refcount > 0);
58
59   self->refcount -= 1;
60
61   if (self->refcount == 0)
62     {
63       _dbus_verbose ("last reference, finalizing\n");
64
65       if (self->unix_data && self->unix_data_free)
66         {
67           _dbus_verbose ("freeing unix authorization callback data\n");
68           (*self->unix_data_free) (self->unix_data);
69           self->unix_data = NULL;
70         }
71
72       if (self->windows_data && self->windows_data_free)
73         {
74           _dbus_verbose ("freeing windows authorization callback data\n");
75           (*self->windows_data_free) (self->windows_data);
76           self->windows_data = NULL;
77         }
78
79       dbus_free (self);
80     }
81 }
82
83 /* Called by transport's set_connection with the connection locked */
84 void
85 _dbus_authorization_set_connection (DBusAuthorization *self,
86                                 DBusConnection *connection)
87 {
88   _dbus_assert (connection != NULL);
89   _dbus_assert (self->connection == NULL);
90
91   self->connection = connection;
92 }
93
94
95 /**
96  * Set the user set authorization callback for Unix identities authorizations.
97  * The callback will be called at the end of the EXTERNAL authentication
98  * mechanism and on every message.
99
100  * See dbus_connection_set_unix_authorization_callback() and
101  * _dbus_transport_set_unix_authorization_callback().
102  *
103  * @param self the authorization struct
104  * @param function the predicate
105  * @param data data to pass to the predicate
106  * @param free_data_function function to free the data
107  * @param old_data the old user data to be freed
108  * @param old_free_data_function old free data function to free it with
109  */
110 void
111 _dbus_authorization_set_unix_authorization_callback (DBusAuthorization             *self,
112                                         DBusAllowUnixUserFunction  function,
113                                         void                      *data,
114                                         DBusFreeFunction           free_data_function,
115                                         void                     **old_data,
116                                         DBusFreeFunction          *old_free_data_function)
117 {
118   *old_data = self->unix_data;
119   *old_free_data_function = self->unix_data_free;
120
121   self->unix_authorization_cb = function;
122   self->unix_data = data;
123   self->unix_data_free = free_data_function;
124 }
125
126 /**
127  * Set the user set authorization callback for Windows identities
128  * authorizations.
129  * The callback will be called at the end of the EXTERNAL authentication
130  * mechanism and on every message.
131  *
132  * See dbus_connection_set_windows_authorization_callback() and
133  * _dbus_transport_set_windows_authorization_callback().
134  *
135  * @param self the authorization struct
136  * @param function the predicate
137  * @param data data to pass to the predicate
138  * @param free_data_function function to free the data
139  * @param old_data the old user data to be freed
140  * @param old_free_data_function old free data function to free it with
141  */
142
143 void
144 _dbus_authorization_set_windows_authorization_callback (DBusAuthorization              *self,
145                                            DBusAllowWindowsUserFunction   function,
146                                            void                       *data,
147                                            DBusFreeFunction            free_data_function,
148                                            void                      **old_data,
149                                            DBusFreeFunction           *old_free_data_function)
150 {
151   *old_data = self->windows_data;
152   *old_free_data_function = self->windows_data_free;
153
154   self->windows_authorization_cb = function;
155   self->windows_data = data;
156   self->windows_data_free = free_data_function;
157 }
158
159 static dbus_bool_t
160 auth_via_unix_authorization_callback (DBusAuthorization *self,
161                              DBusCredentials *auth_identity)
162 {
163
164   dbus_bool_t allow;
165   dbus_uid_t uid;
166
167   /* Dropping the lock here probably isn't that safe. */
168
169   _dbus_assert (auth_identity != NULL);
170
171   uid = _dbus_credentials_get_unix_uid (auth_identity);
172
173   _dbus_verbose ("unlock connection before executing user's authorization callback\n");
174   _dbus_connection_unlock (self->connection);
175
176   allow = (*self->unix_authorization_cb) (self->connection,
177                                   uid,
178                                   self->unix_data);
179
180   _dbus_verbose ("lock connection post unix-authorization callback\n");
181   _dbus_connection_lock (self->connection);
182
183   if (allow)
184     {
185       _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
186     }
187   else
188     {
189       _dbus_verbose ("Client UID "DBUS_UID_FORMAT " wasn't authorized.\n",
190           _dbus_credentials_get_unix_uid (auth_identity));
191     }
192
193   return allow;
194 }
195
196
197 static dbus_bool_t
198 auth_via_windows_authorization_callback (DBusAuthorization *self,
199                                 DBusCredentials *auth_identity)
200 {
201   dbus_bool_t allow;
202   char *windows_sid;
203
204   /* Dropping the lock here probably isn't that safe. */
205
206   _dbus_assert (auth_identity != NULL);
207
208   windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
209
210   if (windows_sid == NULL)
211     return FALSE; /* OOM */
212
213   _dbus_verbose ("unlock connection before executing user's authorization callback\n");
214   _dbus_connection_unlock (self->connection);
215
216   allow = (*self->windows_authorization_cb) (self->connection,
217                                      windows_sid,
218                                      self->windows_data);
219
220   _dbus_verbose ("lock connection post windows user's authorization callback\n");
221   _dbus_connection_lock (self->connection);
222
223   if (allow)
224     {
225       _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
226     }
227   else
228     {
229       _dbus_verbose ("Client SID '%s' wasn't authorized\n",
230                      _dbus_credentials_get_windows_sid (auth_identity));
231     }
232
233   dbus_free (windows_sid);
234
235   return allow;
236 }
237
238 static dbus_bool_t
239 auth_via_default_rules (DBusAuthorization *self,
240                         DBusCredentials *auth_identity)
241
242 {
243   DBusCredentials *our_identity;
244   dbus_bool_t allow;
245
246   _dbus_assert (auth_identity != NULL);
247
248   /* By default, connection is allowed if the client is 1) root or 2)
249    * has the same UID as us or 3) anonymous is allowed.
250    */
251
252   our_identity = _dbus_credentials_new_from_current_process ();
253   if (our_identity == NULL)
254     return FALSE; /* OOM */
255
256   if (self->allow_anonymous ||
257       _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
258       _dbus_credentials_same_user (our_identity, auth_identity))
259     {
260       if (_dbus_credentials_include (our_identity, DBUS_CREDENTIAL_WINDOWS_SID))
261           _dbus_verbose ("Client authenticated as SID '%s'"
262                          "matching our SID '%s': authorized\n",
263                          _dbus_credentials_get_windows_sid (auth_identity),
264                          _dbus_credentials_get_windows_sid (our_identity));
265       else
266           _dbus_verbose ("Client authenticated as UID "DBUS_UID_FORMAT
267                          " matching our UID "DBUS_UID_FORMAT": authorized\n",
268                          _dbus_credentials_get_unix_uid (auth_identity),
269                          _dbus_credentials_get_unix_uid (our_identity));
270       /* We have authenticated! */
271       allow = TRUE;
272     }
273   else
274     {
275       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
276           _dbus_verbose ("Client authenticated as SID '%s'"
277                          " but our SID is '%s', not authorizing\n",
278                          (_dbus_credentials_get_windows_sid(auth_identity) ?
279                           _dbus_credentials_get_windows_sid(auth_identity) : "<null>"),
280                          (_dbus_credentials_get_windows_sid(our_identity) ?
281                           _dbus_credentials_get_windows_sid(our_identity) : "<null>"));
282       else
283           _dbus_verbose ("Client authenticated as UID "DBUS_UID_FORMAT
284                          " but our UID is "DBUS_UID_FORMAT", not authorizing\n",
285                          _dbus_credentials_get_unix_uid(auth_identity),
286                          _dbus_credentials_get_unix_uid(our_identity));
287       allow = FALSE;
288     }
289
290   _dbus_credentials_unref (our_identity);
291
292   return allow;
293 }
294
295 /* Called with DBusConnection lock held */
296 dbus_bool_t
297 _dbus_authorization_do_authorization (DBusAuthorization *self,
298     DBusCredentials *auth_identity)
299 {
300   dbus_bool_t allow;
301
302   /* maybe-FIXME: at this point we *should* have a connection set unless we
303    * are in some test case, but we assert its presence only in some if's
304    * branches since default_rules does not need one and is used in a test case
305    * without a connection set */
306
307   if (_dbus_credentials_are_anonymous (auth_identity))
308     {
309       allow = self->allow_anonymous;
310     }
311   if (self->unix_authorization_cb != NULL &&
312       _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
313     {
314       _dbus_assert (self->connection != NULL);
315       allow = auth_via_unix_authorization_callback (self, auth_identity);
316     }
317   else if (self->windows_authorization_cb != NULL &&
318       _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
319     {
320       _dbus_assert (self->connection != NULL);
321       allow = auth_via_windows_authorization_callback (self, auth_identity);
322     }
323   else
324     {
325       allow = auth_via_default_rules (self, auth_identity);
326     }
327
328   return allow;
329 }
330
331
332
333 /**
334  * See dbus_connection_set_allow_anonymous()
335  *
336  * @param self an authorization struct
337  * @param value #TRUE to allow anonymous connection
338  */
339 void
340 _dbus_authorization_set_allow_anonymous (DBusAuthorization *self,
341                                      dbus_bool_t value)
342 {
343   self->allow_anonymous = value != FALSE;
344 }