Merge branch 'dbus-1.2'
[platform/upstream/dbus.git] / dbus / dbus-transport.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-transport.c DBusTransport object (internal to D-Bus implementation)
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include "dbus-transport-protected.h"
25 #include "dbus-transport-unix.h"
26 #include "dbus-transport-socket.h"
27 #include "dbus-connection-internal.h"
28 #include "dbus-watch.h"
29 #include "dbus-auth.h"
30 #include "dbus-address.h"
31 #include "dbus-credentials.h"
32 #include "dbus-message-private.h"
33 #include "dbus-marshal-header.h"
34 #ifdef DBUS_BUILD_TESTS
35 #include "dbus-server-debug-pipe.h"
36 #endif
37
38 /**
39  * @defgroup DBusTransport DBusTransport object
40  * @ingroup  DBusInternals
41  * @brief "Backend" for a DBusConnection.
42  *
43  * Types and functions related to DBusTransport.  A transport is an
44  * abstraction that can send and receive data via various kinds of
45  * network connections or other IPC mechanisms.
46  * 
47  * @{
48  */
49
50 /**
51  * @typedef DBusTransport
52  *
53  * Opaque object representing a way message stream.
54  * DBusTransport abstracts various kinds of actual
55  * transport mechanism, such as different network protocols,
56  * or encryption schemes.
57  */
58
59 static void
60 live_messages_notify (DBusCounter *counter,
61                            void        *user_data)
62 {
63   DBusTransport *transport = user_data;
64
65   _dbus_transport_ref (transport);
66
67 #if 0
68   _dbus_verbose ("Size counter value is now %d\n",
69                  (int) _dbus_counter_get_size_value (counter));
70   _dbus_verbose ("Unix FD counter value is now %d\n",
71                  (int) _dbus_counter_get_unix_fd_value (counter));
72 #endif
73   
74   /* disable or re-enable the read watch for the transport if
75    * required.
76    */
77   if (transport->vtable->live_messages_changed)
78     (* transport->vtable->live_messages_changed) (transport);
79
80   _dbus_transport_unref (transport);
81 }
82
83 /**
84  * Initializes the base class members of DBusTransport.  Chained up to
85  * by subclasses in their constructor.  The server GUID is the
86  * globally unique ID for the server creating this connection
87  * and will be #NULL for the client side of a connection. The GUID
88  * is in hex format.
89  *
90  * @param transport the transport being created.
91  * @param vtable the subclass vtable.
92  * @param server_guid non-#NULL if this transport is on the server side of a connection
93  * @param address the address of the transport
94  * @returns #TRUE on success.
95  */
96 dbus_bool_t
97 _dbus_transport_init_base (DBusTransport             *transport,
98                            const DBusTransportVTable *vtable,
99                            const DBusString          *server_guid,
100                            const DBusString          *address)
101 {
102   DBusMessageLoader *loader;
103   DBusAuth *auth;
104   DBusCounter *counter;
105   char *address_copy;
106   DBusCredentials *creds;
107   
108   loader = _dbus_message_loader_new ();
109   if (loader == NULL)
110     return FALSE;
111   
112   if (server_guid)
113     auth = _dbus_auth_server_new (server_guid);
114   else
115     auth = _dbus_auth_client_new ();
116   if (auth == NULL)
117     {
118       _dbus_message_loader_unref (loader);
119       return FALSE;
120     }
121
122   counter = _dbus_counter_new ();
123   if (counter == NULL)
124     {
125       _dbus_auth_unref (auth);
126       _dbus_message_loader_unref (loader);
127       return FALSE;
128     }  
129
130   creds = _dbus_credentials_new ();
131   if (creds == NULL)
132     {
133       _dbus_counter_unref (counter);
134       _dbus_auth_unref (auth);
135       _dbus_message_loader_unref (loader);
136       return FALSE;
137     }
138   
139   if (server_guid)
140     {
141       _dbus_assert (address == NULL);
142       address_copy = NULL;
143     }
144   else
145     {
146       _dbus_assert (address != NULL);
147
148       if (!_dbus_string_copy_data (address, &address_copy))
149         {
150           _dbus_credentials_unref (creds);
151           _dbus_counter_unref (counter);
152           _dbus_auth_unref (auth);
153           _dbus_message_loader_unref (loader);
154           return FALSE;
155         }
156     }
157   
158   transport->refcount = 1;
159   transport->vtable = vtable;
160   transport->loader = loader;
161   transport->auth = auth;
162   transport->live_messages = counter;
163   transport->authenticated = FALSE;
164   transport->disconnected = FALSE;
165   transport->is_server = (server_guid != NULL);
166   transport->send_credentials_pending = !transport->is_server;
167   transport->receive_credentials_pending = transport->is_server;
168   transport->address = address_copy;
169   
170   transport->unix_user_function = NULL;
171   transport->unix_user_data = NULL;
172   transport->free_unix_user_data = NULL;
173
174   transport->windows_user_function = NULL;
175   transport->windows_user_data = NULL;
176   transport->free_windows_user_data = NULL;
177   
178   transport->expected_guid = NULL;
179   
180   /* Try to default to something that won't totally hose the system,
181    * but doesn't impose too much of a limitation.
182    */
183   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
184
185   /* On Linux RLIMIT_NOFILE defaults to 1024, so allowing 4096 fds live
186      should be more than enough */
187   transport->max_live_messages_unix_fds = 4096;
188
189   /* credentials read from socket if any */
190   transport->credentials = creds;
191
192   _dbus_counter_set_notify (transport->live_messages,
193                             transport->max_live_messages_size,
194                             transport->max_live_messages_unix_fds,
195                             live_messages_notify,
196                             transport);
197
198   if (transport->address)
199     _dbus_verbose ("Initialized transport on address %s\n", transport->address);
200
201   return TRUE;
202 }
203
204 /**
205  * Finalizes base class members of DBusTransport.
206  * Chained up to from subclass finalizers.
207  *
208  * @param transport the transport.
209  */
210 void
211 _dbus_transport_finalize_base (DBusTransport *transport)
212 {
213   if (!transport->disconnected)
214     _dbus_transport_disconnect (transport);
215
216   if (transport->free_unix_user_data != NULL)
217     (* transport->free_unix_user_data) (transport->unix_user_data);
218
219   if (transport->free_windows_user_data != NULL)
220     (* transport->free_windows_user_data) (transport->windows_user_data);
221   
222   _dbus_message_loader_unref (transport->loader);
223   _dbus_auth_unref (transport->auth);
224   _dbus_counter_set_notify (transport->live_messages,
225                             0, 0, NULL, NULL);
226   _dbus_counter_unref (transport->live_messages);
227   dbus_free (transport->address);
228   dbus_free (transport->expected_guid);
229   if (transport->credentials)
230     _dbus_credentials_unref (transport->credentials);
231 }
232
233
234 /**
235  * Verifies if a given D-Bus address is a valid address
236  * by attempting to connect to it. If it is, returns the
237  * opened DBusTransport object. If it isn't, returns #NULL
238  * and sets @p error.
239  *
240  * @param error address where an error can be returned.
241  * @returns a new transport, or #NULL on failure.
242  */
243 static DBusTransport*
244 check_address (const char *address, DBusError *error)
245 {
246   DBusAddressEntry **entries;
247   DBusTransport *transport = NULL;
248   int len, i;
249
250   _dbus_assert (address != NULL);
251   _dbus_assert (*address != '\0');
252
253   if (!dbus_parse_address (address, &entries, &len, error))
254     return NULL;              /* not a valid address */
255
256   for (i = 0; i < len; i++)
257     {
258       transport = _dbus_transport_open (entries[i], error);
259       if (transport != NULL)
260         break;
261     }
262
263   dbus_address_entries_free (entries);
264   return transport;
265 }
266
267 /**
268  * Creates a new transport for the "autostart" method.
269  * This creates a client-side of a transport.
270  *
271  * @param error address where an error can be returned.
272  * @returns a new transport, or #NULL on failure.
273  */
274 static DBusTransport*
275 _dbus_transport_new_for_autolaunch (DBusError      *error)
276 {
277   DBusString address;
278   DBusTransport *result = NULL;
279
280   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
281
282   if (!_dbus_string_init (&address))
283     {
284       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
285       return NULL;
286     }
287
288   if (!_dbus_get_autolaunch_address (&address, error))
289     {
290       _DBUS_ASSERT_ERROR_IS_SET (error);
291       goto out;
292     }
293
294   result = check_address (_dbus_string_get_const_data (&address), error);
295   if (result == NULL)
296     _DBUS_ASSERT_ERROR_IS_SET (error);
297   else
298     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
299
300  out:
301   _dbus_string_free (&address);
302   return result;
303 }
304
305 static DBusTransportOpenResult
306 _dbus_transport_open_autolaunch (DBusAddressEntry  *entry,
307                                  DBusTransport    **transport_p,
308                                  DBusError         *error)
309 {
310   const char *method;
311   
312   method = dbus_address_entry_get_method (entry);
313   _dbus_assert (method != NULL);
314
315   if (strcmp (method, "autolaunch") == 0)
316     {
317       *transport_p = _dbus_transport_new_for_autolaunch (error);
318
319       if (*transport_p == NULL)
320         {
321           _DBUS_ASSERT_ERROR_IS_SET (error);
322           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
323         }
324       else
325         {
326           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
327           return DBUS_TRANSPORT_OPEN_OK;
328         }      
329     }
330   else
331     {
332       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
333       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
334     }
335 }
336
337 static const struct {
338   DBusTransportOpenResult (* func) (DBusAddressEntry *entry,
339                                     DBusTransport   **transport_p,
340                                     DBusError        *error);
341 } open_funcs[] = {
342   { _dbus_transport_open_socket },
343   { _dbus_transport_open_platform_specific },
344   { _dbus_transport_open_autolaunch }
345 #ifdef DBUS_BUILD_TESTS
346   , { _dbus_transport_open_debug_pipe }
347 #endif
348 };
349
350 /**
351  * Try to open a new transport for the given address entry.  (This
352  * opens a client-side-of-the-connection transport.)
353  * 
354  * @param entry the address entry
355  * @param error location to store reason for failure.
356  * @returns new transport of #NULL on failure.
357  */
358 DBusTransport*
359 _dbus_transport_open (DBusAddressEntry *entry,
360                       DBusError        *error)
361 {
362   DBusTransport *transport;
363   const char *expected_guid_orig;
364   char *expected_guid;
365   int i;
366   DBusError tmp_error = DBUS_ERROR_INIT;
367
368   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
369   
370   transport = NULL;
371   expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
372   expected_guid = _dbus_strdup (expected_guid_orig);
373
374   if (expected_guid_orig != NULL && expected_guid == NULL)
375     {
376       _DBUS_SET_OOM (error);
377       return NULL;
378     }
379
380   for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
381     {
382       DBusTransportOpenResult result;
383
384       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
385       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
386
387       switch (result)
388         {
389         case DBUS_TRANSPORT_OPEN_OK:
390           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
391           goto out;
392           break;
393         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
394           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
395           /* keep going through the loop of open funcs */
396           break;
397         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
398           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
399           goto out;
400           break;
401         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
402           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
403           goto out;
404           break;
405         }
406     }
407
408  out:
409   
410   if (transport == NULL)
411     {
412       if (!dbus_error_is_set (&tmp_error))
413         _dbus_set_bad_address (&tmp_error,
414                                NULL, NULL,
415                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
416       
417       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
418       dbus_move_error(&tmp_error, error);
419       dbus_free (expected_guid);
420     }
421   else
422     {
423       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
424
425       /* In the case of autostart the initial guid is NULL
426        * and the autostart transport recursively calls
427        * _dbus_open_transport wich returns a transport
428        * with a guid.  That guid is the definitive one.
429        *
430        * FIXME: if more transports are added they may have
431        * an effect on the expected_guid semantics (i.e. 
432        * expected_guid and transport->expected_guid may
433        * both have values).  This is very unlikely though
434        * we should either throw asserts here for those 
435        * corner cases or refactor the code so it is 
436        * clearer on what is expected and what is not
437        */
438       if(expected_guid)
439         transport->expected_guid = expected_guid;
440     }
441
442   return transport;
443 }
444
445 /**
446  * Increments the reference count for the transport.
447  *
448  * @param transport the transport.
449  * @returns the transport.
450  */
451 DBusTransport *
452 _dbus_transport_ref (DBusTransport *transport)
453 {
454   _dbus_assert (transport->refcount > 0);
455   
456   transport->refcount += 1;
457
458   return transport;
459 }
460
461 /**
462  * Decrements the reference count for the transport.
463  * Disconnects and finalizes the transport if
464  * the reference count reaches zero.
465  *
466  * @param transport the transport.
467  */
468 void
469 _dbus_transport_unref (DBusTransport *transport)
470 {
471   _dbus_assert (transport != NULL);
472   _dbus_assert (transport->refcount > 0);
473   
474   transport->refcount -= 1;
475   if (transport->refcount == 0)
476     {
477       _dbus_verbose ("%s: finalizing\n", _DBUS_FUNCTION_NAME);
478       
479       _dbus_assert (transport->vtable->finalize != NULL);
480       
481       (* transport->vtable->finalize) (transport);
482     }
483 }
484
485 /**
486  * Closes our end of the connection to a remote application. Further
487  * attempts to use this transport will fail. Only the first call to
488  * _dbus_transport_disconnect() will have an effect.
489  *
490  * @param transport the transport.
491  * 
492  */
493 void
494 _dbus_transport_disconnect (DBusTransport *transport)
495 {
496   _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME);
497   
498   _dbus_assert (transport->vtable->disconnect != NULL);
499   
500   if (transport->disconnected)
501     return;
502
503   (* transport->vtable->disconnect) (transport);
504   
505   transport->disconnected = TRUE;
506
507   _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
508 }
509
510 /**
511  * Returns #TRUE if the transport has not been disconnected.
512  * Disconnection can result from _dbus_transport_disconnect()
513  * or because the server drops its end of the connection.
514  *
515  * @param transport the transport.
516  * @returns whether we're connected
517  */
518 dbus_bool_t
519 _dbus_transport_get_is_connected (DBusTransport *transport)
520 {
521   return !transport->disconnected;
522 }
523
524 static dbus_bool_t
525 auth_via_unix_user_function (DBusTransport *transport)
526 {
527   DBusCredentials *auth_identity;
528   dbus_bool_t allow;
529   DBusConnection *connection;
530   DBusAllowUnixUserFunction unix_user_function;
531   void *unix_user_data;
532   dbus_uid_t uid;
533
534   /* Dropping the lock here probably isn't that safe. */
535   
536   auth_identity = _dbus_auth_get_identity (transport->auth);
537   _dbus_assert (auth_identity != NULL);
538
539   connection = transport->connection;
540   unix_user_function = transport->unix_user_function;
541   unix_user_data = transport->unix_user_data;
542   uid = _dbus_credentials_get_unix_uid (auth_identity);
543               
544   _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
545   _dbus_connection_unlock (connection);
546
547   allow = (* unix_user_function) (connection,
548                                   uid,
549                                   unix_user_data);
550               
551   _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
552   _dbus_connection_lock (connection);
553
554   if (allow)
555     {
556       _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
557     }
558   else
559     {
560       _dbus_verbose ("Client UID "DBUS_UID_FORMAT
561                      " was rejected, disconnecting\n",
562                      _dbus_credentials_get_unix_uid (auth_identity));
563       _dbus_transport_disconnect (transport);
564     }
565
566   return allow;
567 }
568
569 static dbus_bool_t
570 auth_via_windows_user_function (DBusTransport *transport)
571 {
572   DBusCredentials *auth_identity;  
573   dbus_bool_t allow;
574   DBusConnection *connection;
575   DBusAllowWindowsUserFunction windows_user_function;
576   void *windows_user_data;
577   char *windows_sid;
578
579   /* Dropping the lock here probably isn't that safe. */
580   
581   auth_identity = _dbus_auth_get_identity (transport->auth);
582   _dbus_assert (auth_identity != NULL);
583
584   connection = transport->connection;
585   windows_user_function = transport->windows_user_function;
586   windows_user_data = transport->unix_user_data;
587   windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
588
589   if (windows_sid == NULL)
590     {
591       /* OOM */
592       return FALSE;
593     }
594                 
595   _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
596   _dbus_connection_unlock (connection);
597
598   allow = (* windows_user_function) (connection,
599                                      windows_sid,
600                                      windows_user_data);
601               
602   _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME);
603   _dbus_connection_lock (connection);
604
605   if (allow)
606     {
607       _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
608     }
609   else
610     {
611       _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
612                      _dbus_credentials_get_windows_sid (auth_identity));
613       _dbus_transport_disconnect (transport);
614     }
615
616   return allow;
617 }
618
619 static dbus_bool_t
620 auth_via_default_rules (DBusTransport *transport)
621 {
622   DBusCredentials *auth_identity;
623   DBusCredentials *our_identity;
624   dbus_bool_t allow;
625   
626   auth_identity = _dbus_auth_get_identity (transport->auth);
627   _dbus_assert (auth_identity != NULL);
628
629   /* By default, connection is allowed if the client is 1) root or 2)
630    * has the same UID as us or 3) anonymous is allowed.
631    */
632   
633   our_identity = _dbus_credentials_new_from_current_process ();
634   if (our_identity == NULL)
635     {
636       /* OOM */
637       return FALSE;
638     }
639               
640   if (transport->allow_anonymous ||
641       _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
642       _dbus_credentials_same_user (our_identity,
643                                    auth_identity))
644     {
645       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
646           _dbus_verbose ("Client authorized as SID '%s'"
647                          "matching our SID '%s'\n",
648                          _dbus_credentials_get_windows_sid(auth_identity),
649                          _dbus_credentials_get_windows_sid(our_identity));
650       else
651           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
652                          " matching our UID "DBUS_UID_FORMAT"\n",
653                          _dbus_credentials_get_unix_uid(auth_identity),
654                          _dbus_credentials_get_unix_uid(our_identity));
655       /* We have authenticated! */
656       allow = TRUE;
657     }
658   else
659     {
660       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
661           _dbus_verbose ("Client authorized as SID '%s'"
662                          " but our SID is '%s', disconnecting\n",
663                          (_dbus_credentials_get_windows_sid(auth_identity) ?
664                           _dbus_credentials_get_windows_sid(auth_identity) : "<null>"),
665                          (_dbus_credentials_get_windows_sid(our_identity) ?
666                           _dbus_credentials_get_windows_sid(our_identity) : "<null>"));
667       else
668           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
669                          " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
670                          _dbus_credentials_get_unix_uid(auth_identity),
671                          _dbus_credentials_get_unix_uid(our_identity));
672       _dbus_transport_disconnect (transport);
673       allow = FALSE;
674     }  
675
676   _dbus_credentials_unref (our_identity);
677   
678   return allow;
679 }
680
681
682 /**
683  * Returns #TRUE if we have been authenticated.  Will return #TRUE
684  * even if the transport is disconnected.
685  *
686  * @todo we drop connection->mutex when calling the unix_user_function,
687  * and windows_user_function, which may not be safe really.
688  *
689  * @param transport the transport
690  * @returns whether we're authenticated
691  */
692 dbus_bool_t
693 _dbus_transport_get_is_authenticated (DBusTransport *transport)
694 {  
695   if (transport->authenticated)
696     return TRUE;
697   else
698     {
699       dbus_bool_t maybe_authenticated;
700       
701       if (transport->disconnected)
702         return FALSE;
703
704       /* paranoia ref since we call user callbacks sometimes */
705       _dbus_connection_ref_unlocked (transport->connection);
706       
707       maybe_authenticated =
708         (!(transport->send_credentials_pending ||
709            transport->receive_credentials_pending));
710
711       if (maybe_authenticated)
712         {
713           switch (_dbus_auth_do_work (transport->auth))
714             {
715             case DBUS_AUTH_STATE_AUTHENTICATED:
716               /* leave as maybe_authenticated */
717               break;
718             default:
719               maybe_authenticated = FALSE;
720             }
721         }
722
723       /* If we're the client, verify the GUID
724        */
725       if (maybe_authenticated && !transport->is_server)
726         {
727           const char *server_guid;
728
729           server_guid = _dbus_auth_get_guid_from_server (transport->auth);
730           _dbus_assert (server_guid != NULL);
731
732           if (transport->expected_guid &&
733               strcmp (transport->expected_guid, server_guid) != 0)
734             {
735               _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
736                              transport->expected_guid, server_guid);
737               _dbus_transport_disconnect (transport);
738               _dbus_connection_unref_unlocked (transport->connection);
739               return FALSE;
740             }
741
742           if (transport->expected_guid == NULL)
743             {
744               transport->expected_guid = _dbus_strdup (server_guid);
745
746               if (transport->expected_guid == NULL)
747                 {
748                   _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME);
749                   return FALSE;
750                 }
751             }
752         }
753
754       /* If we're the server, see if we want to allow this identity to proceed.
755        */
756       if (maybe_authenticated && transport->is_server)
757         {
758           dbus_bool_t allow;
759           DBusCredentials *auth_identity;
760           
761           auth_identity = _dbus_auth_get_identity (transport->auth);
762           _dbus_assert (auth_identity != NULL);
763           
764           /* If we have an auth'd user and a user function, delegate
765            * deciding whether auth credentials are good enough to the
766            * app; otherwise, use our default decision process.
767            */
768           if (transport->unix_user_function != NULL &&
769               _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
770             {
771               allow = auth_via_unix_user_function (transport);
772             }
773           else if (transport->windows_user_function != NULL &&
774                    _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
775             {
776               allow = auth_via_windows_user_function (transport);
777             }      
778           else
779             {
780               allow = auth_via_default_rules (transport);
781             }
782           
783           if (!allow)
784             maybe_authenticated = FALSE;
785         }
786
787       transport->authenticated = maybe_authenticated;
788
789       _dbus_connection_unref_unlocked (transport->connection);
790       return maybe_authenticated;
791     }
792 }
793
794 /**
795  * See dbus_connection_get_is_anonymous().
796  *
797  * @param transport the transport
798  * @returns #TRUE if not authenticated or authenticated as anonymous
799  */
800 dbus_bool_t
801 _dbus_transport_get_is_anonymous (DBusTransport *transport)
802 {
803   DBusCredentials *auth_identity;
804   
805   if (!transport->authenticated)
806     return TRUE;
807   
808   auth_identity = _dbus_auth_get_identity (transport->auth);
809
810   if (_dbus_credentials_are_anonymous (auth_identity))
811     return TRUE;
812   else
813     return FALSE;
814 }
815
816 /**
817  * Returns TRUE if the transport supports sending unix fds.
818  *
819  * @param transport the transport
820  * @returns #TRUE if TRUE it is possible to send unix fds across the transport.
821  */
822 dbus_bool_t
823 _dbus_transport_can_pass_unix_fd(DBusTransport *transport)
824 {
825   return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport);
826 }
827
828 /**
829  * Gets the address of a transport. It will be
830  * #NULL for a server-side transport.
831  *
832  * @param transport the transport
833  * @returns transport's address
834  */
835 const char*
836 _dbus_transport_get_address (DBusTransport *transport)
837 {
838   return transport->address;
839 }
840
841 /**
842  * Gets the id of the server we are connected to (see
843  * dbus_server_get_id()). Only works on client side.
844  *
845  * @param transport the transport
846  * @returns transport's server's id or #NULL if we are the server side
847  */
848 const char*
849 _dbus_transport_get_server_id (DBusTransport *transport)
850 {
851   if (transport->is_server)
852     return NULL;
853   else
854     return transport->expected_guid;
855 }
856
857 /**
858  * Handles a watch by reading data, writing data, or disconnecting
859  * the transport, as appropriate for the given condition.
860  *
861  * @param transport the transport.
862  * @param watch the watch.
863  * @param condition the current state of the watched file descriptor.
864  * @returns #FALSE if not enough memory to fully handle the watch
865  */
866 dbus_bool_t
867 _dbus_transport_handle_watch (DBusTransport           *transport,
868                               DBusWatch               *watch,
869                               unsigned int             condition)
870 {
871   dbus_bool_t retval;
872   
873   _dbus_assert (transport->vtable->handle_watch != NULL);
874
875   if (transport->disconnected)
876     return TRUE;
877
878   if (dbus_watch_get_socket (watch) < 0)
879     {
880       _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
881       return TRUE;
882     }
883   
884   _dbus_watch_sanitize_condition (watch, &condition);
885
886   _dbus_transport_ref (transport);
887   _dbus_watch_ref (watch);
888   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
889   _dbus_watch_unref (watch);
890   _dbus_transport_unref (transport);
891
892   return retval;
893 }
894
895 /**
896  * Sets the connection using this transport. Allows the transport
897  * to add watches to the connection, queue incoming messages,
898  * and pull outgoing messages.
899  *
900  * @param transport the transport.
901  * @param connection the connection.
902  * @returns #FALSE if not enough memory
903  */
904 dbus_bool_t
905 _dbus_transport_set_connection (DBusTransport  *transport,
906                                 DBusConnection *connection)
907 {
908   _dbus_assert (transport->vtable->connection_set != NULL);
909   _dbus_assert (transport->connection == NULL);
910   
911   transport->connection = connection;
912
913   _dbus_transport_ref (transport);
914   if (!(* transport->vtable->connection_set) (transport))
915     transport->connection = NULL;
916   _dbus_transport_unref (transport);
917
918   return transport->connection != NULL;
919 }
920
921 /**
922  * Get the socket file descriptor, if any.
923  *
924  * @param transport the transport
925  * @param fd_p pointer to fill in with the descriptor
926  * @returns #TRUE if a descriptor was available
927  */
928 dbus_bool_t
929 _dbus_transport_get_socket_fd (DBusTransport *transport,
930                                int           *fd_p)
931 {
932   dbus_bool_t retval;
933   
934   if (transport->vtable->get_socket_fd == NULL)
935     return FALSE;
936
937   if (transport->disconnected)
938     return FALSE;
939
940   _dbus_transport_ref (transport);
941
942   retval = (* transport->vtable->get_socket_fd) (transport,
943                                                  fd_p);
944   
945   _dbus_transport_unref (transport);
946
947   return retval;
948 }
949
950 /**
951  * Performs a single poll()/select() on the transport's file
952  * descriptors and then reads/writes data as appropriate,
953  * queueing incoming messages and sending outgoing messages.
954  * This is the backend for _dbus_connection_do_iteration().
955  * See _dbus_connection_do_iteration() for full details.
956  *
957  * @param transport the transport.
958  * @param flags indicates whether to read or write, and whether to block.
959  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
960  */
961 void
962 _dbus_transport_do_iteration (DBusTransport  *transport,
963                               unsigned int    flags,
964                               int             timeout_milliseconds)
965 {
966   _dbus_assert (transport->vtable->do_iteration != NULL);
967
968   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
969                  flags, timeout_milliseconds, !transport->disconnected);
970   
971   if ((flags & (DBUS_ITERATION_DO_WRITING |
972                 DBUS_ITERATION_DO_READING)) == 0)
973     return; /* Nothing to do */
974
975   if (transport->disconnected)
976     return;
977
978   _dbus_transport_ref (transport);
979   (* transport->vtable->do_iteration) (transport, flags,
980                                        timeout_milliseconds);
981   _dbus_transport_unref (transport);
982
983   _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
984 }
985
986 static dbus_bool_t
987 recover_unused_bytes (DBusTransport *transport)
988 {
989   if (_dbus_auth_needs_decoding (transport->auth))
990     {
991       DBusString plaintext;
992       const DBusString *encoded;
993       DBusString *buffer;
994       int orig_len;
995       
996       if (!_dbus_string_init (&plaintext))
997         goto nomem;
998       
999       _dbus_auth_get_unused_bytes (transport->auth,
1000                                    &encoded);
1001
1002       if (!_dbus_auth_decode_data (transport->auth,
1003                                    encoded, &plaintext))
1004         {
1005           _dbus_string_free (&plaintext);
1006           goto nomem;
1007         }
1008       
1009       _dbus_message_loader_get_buffer (transport->loader,
1010                                        &buffer);
1011       
1012       orig_len = _dbus_string_get_length (buffer);
1013       
1014       if (!_dbus_string_move (&plaintext, 0, buffer,
1015                               orig_len))
1016         {
1017           _dbus_string_free (&plaintext);
1018           goto nomem;
1019         }
1020       
1021       _dbus_verbose (" %d unused bytes sent to message loader\n", 
1022                      _dbus_string_get_length (buffer) -
1023                      orig_len);
1024       
1025       _dbus_message_loader_return_buffer (transport->loader,
1026                                           buffer,
1027                                           _dbus_string_get_length (buffer) -
1028                                           orig_len);
1029
1030       _dbus_auth_delete_unused_bytes (transport->auth);
1031       
1032       _dbus_string_free (&plaintext);
1033     }
1034   else
1035     {
1036       const DBusString *bytes;
1037       DBusString *buffer;
1038       int orig_len;
1039       dbus_bool_t succeeded;
1040
1041       _dbus_message_loader_get_buffer (transport->loader,
1042                                        &buffer);
1043                 
1044       orig_len = _dbus_string_get_length (buffer);
1045                 
1046       _dbus_auth_get_unused_bytes (transport->auth,
1047                                    &bytes);
1048
1049       succeeded = TRUE;
1050       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
1051         succeeded = FALSE;
1052       
1053       _dbus_verbose (" %d unused bytes sent to message loader\n", 
1054                      _dbus_string_get_length (buffer) -
1055                      orig_len);
1056       
1057       _dbus_message_loader_return_buffer (transport->loader,
1058                                           buffer,
1059                                           _dbus_string_get_length (buffer) -
1060                                           orig_len);
1061
1062       if (succeeded)
1063         _dbus_auth_delete_unused_bytes (transport->auth);
1064       else
1065         goto nomem;
1066     }
1067
1068   return TRUE;
1069
1070  nomem:
1071   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
1072   return FALSE;
1073 }
1074
1075 /**
1076  * Reports our current dispatch status (whether there's buffered
1077  * data to be queued as messages, or not, or we need memory).
1078  *
1079  * @param transport the transport
1080  * @returns current status
1081  */
1082 DBusDispatchStatus
1083 _dbus_transport_get_dispatch_status (DBusTransport *transport)
1084 {
1085   if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size ||
1086       _dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds)
1087     return DBUS_DISPATCH_COMPLETE; /* complete for now */
1088
1089   if (!_dbus_transport_get_is_authenticated (transport))
1090     {
1091       if (_dbus_auth_do_work (transport->auth) ==
1092           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
1093         return DBUS_DISPATCH_NEED_MEMORY;
1094       else if (!_dbus_transport_get_is_authenticated (transport))
1095         return DBUS_DISPATCH_COMPLETE;
1096     }
1097
1098   if (!transport->unused_bytes_recovered &&
1099       !recover_unused_bytes (transport))
1100     return DBUS_DISPATCH_NEED_MEMORY;
1101
1102   transport->unused_bytes_recovered = TRUE;
1103   
1104   if (!_dbus_message_loader_queue_messages (transport->loader))
1105     return DBUS_DISPATCH_NEED_MEMORY;
1106
1107   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
1108     return DBUS_DISPATCH_DATA_REMAINS;
1109   else
1110     return DBUS_DISPATCH_COMPLETE;
1111 }
1112
1113 /**
1114  * Processes data we've read while handling a watch, potentially
1115  * converting some of it to messages and queueing those messages on
1116  * the connection.
1117  *
1118  * @param transport the transport
1119  * @returns #TRUE if we had enough memory to queue all messages
1120  */
1121 dbus_bool_t
1122 _dbus_transport_queue_messages (DBusTransport *transport)
1123 {
1124   DBusDispatchStatus status;
1125
1126 #if 0
1127   _dbus_verbose ("_dbus_transport_queue_messages()\n");
1128 #endif
1129   
1130   /* Queue any messages */
1131   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
1132     {
1133       DBusMessage *message;
1134       DBusList *link;
1135
1136       link = _dbus_message_loader_pop_message_link (transport->loader);
1137       _dbus_assert (link != NULL);
1138       
1139       message = link->data;
1140       
1141       _dbus_verbose ("queueing received message %p\n", message);
1142
1143       if (!_dbus_message_add_counter (message, transport->live_messages))
1144         {
1145           _dbus_message_loader_putback_message_link (transport->loader,
1146                                                      link);
1147           status = DBUS_DISPATCH_NEED_MEMORY;
1148           break;
1149         }
1150       else
1151         {
1152           /* pass ownership of link and message ref to connection */
1153           _dbus_connection_queue_received_message_link (transport->connection,
1154                                                         link);
1155         }
1156     }
1157
1158   if (_dbus_message_loader_get_is_corrupted (transport->loader))
1159     {
1160       _dbus_verbose ("Corrupted message stream, disconnecting\n");
1161       _dbus_transport_disconnect (transport);
1162     }
1163
1164   return status != DBUS_DISPATCH_NEED_MEMORY;
1165 }
1166
1167 /**
1168  * See dbus_connection_set_max_message_size().
1169  *
1170  * @param transport the transport
1171  * @param size the max size of a single message
1172  */
1173 void
1174 _dbus_transport_set_max_message_size (DBusTransport  *transport,
1175                                       long            size)
1176 {
1177   _dbus_message_loader_set_max_message_size (transport->loader, size);
1178 }
1179
1180 /**
1181  * See dbus_connection_set_max_message_unix_fds().
1182  *
1183  * @param transport the transport
1184  * @param n the max number of unix fds of a single message
1185  */
1186 void
1187 _dbus_transport_set_max_message_unix_fds (DBusTransport  *transport,
1188                                           long            n)
1189 {
1190   _dbus_message_loader_set_max_message_unix_fds (transport->loader, n);
1191 }
1192
1193 /**
1194  * See dbus_connection_get_max_message_size().
1195  *
1196  * @param transport the transport
1197  * @returns max message size
1198  */
1199 long
1200 _dbus_transport_get_max_message_size (DBusTransport  *transport)
1201 {
1202   return _dbus_message_loader_get_max_message_size (transport->loader);
1203 }
1204
1205 /**
1206  * See dbus_connection_get_max_message_unix_fds().
1207  *
1208  * @param transport the transport
1209  * @returns max message unix fds
1210  */
1211 long
1212 _dbus_transport_get_max_message_unix_fds (DBusTransport  *transport)
1213 {
1214   return _dbus_message_loader_get_max_message_unix_fds (transport->loader);
1215 }
1216
1217 /**
1218  * See dbus_connection_set_max_received_size().
1219  *
1220  * @param transport the transport
1221  * @param size the max size of all incoming messages
1222  */
1223 void
1224 _dbus_transport_set_max_received_size (DBusTransport  *transport,
1225                                        long            size)
1226 {
1227   transport->max_live_messages_size = size;
1228   _dbus_counter_set_notify (transport->live_messages,
1229                             transport->max_live_messages_size,
1230                             transport->max_live_messages_unix_fds,
1231                             live_messages_notify,
1232                             transport);
1233 }
1234
1235 /**
1236  * See dbus_connection_set_max_received_unix_fds().
1237  *
1238  * @param transport the transport
1239  * @param n the max unix fds of all incoming messages
1240  */
1241 void
1242 _dbus_transport_set_max_received_unix_fds (DBusTransport  *transport,
1243                                            long            n)
1244 {
1245   transport->max_live_messages_unix_fds = n;
1246   _dbus_counter_set_notify (transport->live_messages,
1247                             transport->max_live_messages_size,
1248                             transport->max_live_messages_unix_fds,
1249                             live_messages_notify,
1250                             transport);
1251 }
1252
1253 /**
1254  * See dbus_connection_get_max_received_size().
1255  *
1256  * @param transport the transport
1257  * @returns max bytes for all live messages
1258  */
1259 long
1260 _dbus_transport_get_max_received_size (DBusTransport  *transport)
1261 {
1262   return transport->max_live_messages_size;
1263 }
1264
1265 /**
1266  * See dbus_connection_set_max_received_unix_fds().
1267  *
1268  * @param transport the transport
1269  * @returns max unix fds for all live messages
1270  */
1271 long
1272 _dbus_transport_get_max_received_unix_fds (DBusTransport  *transport)
1273 {
1274   return transport->max_live_messages_unix_fds;
1275 }
1276
1277 /**
1278  * See dbus_connection_get_unix_user().
1279  *
1280  * @param transport the transport
1281  * @param uid return location for the user ID
1282  * @returns #TRUE if uid is filled in with a valid user ID
1283  */
1284 dbus_bool_t
1285 _dbus_transport_get_unix_user (DBusTransport *transport,
1286                                unsigned long *uid)
1287 {
1288   DBusCredentials *auth_identity;
1289
1290   *uid = _DBUS_INT32_MAX; /* better than some root or system user in
1291                            * case of bugs in the caller. Caller should
1292                            * never use this value on purpose, however.
1293                            */
1294   
1295   if (!transport->authenticated)
1296     return FALSE;
1297   
1298   auth_identity = _dbus_auth_get_identity (transport->auth);
1299
1300   if (_dbus_credentials_include (auth_identity,
1301                                  DBUS_CREDENTIAL_UNIX_USER_ID))
1302     {
1303       *uid = _dbus_credentials_get_unix_uid (auth_identity);
1304       return TRUE;
1305     }
1306   else
1307     return FALSE;
1308 }
1309
1310 /**
1311  * See dbus_connection_get_unix_process_id().
1312  *
1313  * @param transport the transport
1314  * @param pid return location for the process ID
1315  * @returns #TRUE if uid is filled in with a valid process ID
1316  */
1317 dbus_bool_t
1318 _dbus_transport_get_unix_process_id (DBusTransport *transport,
1319                                      unsigned long *pid)
1320 {
1321   DBusCredentials *auth_identity;
1322
1323   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
1324                           * but we set it to a safe number, INT_MAX,
1325                           * just to root out possible bugs in bad callers.
1326                           */
1327   
1328   if (!transport->authenticated)
1329     return FALSE;
1330   
1331   auth_identity = _dbus_auth_get_identity (transport->auth);
1332
1333   if (_dbus_credentials_include (auth_identity,
1334                                  DBUS_CREDENTIAL_UNIX_PROCESS_ID))
1335     {
1336       *pid = _dbus_credentials_get_unix_pid (auth_identity);
1337       return TRUE;
1338     }
1339   else
1340     return FALSE;
1341 }
1342
1343 /**
1344  * See dbus_connection_get_adt_audit_session_data().
1345  *
1346  * @param transport the transport
1347  * @param data return location for the ADT audit data 
1348  * @param data_size return length of audit data
1349  * @returns #TRUE if audit data is filled in with a valid ucred
1350  */
1351 dbus_bool_t
1352 _dbus_transport_get_adt_audit_session_data (DBusTransport      *transport,
1353                                             void              **data,
1354                                             int                *data_size)
1355 {
1356   DBusCredentials *auth_identity;
1357
1358   *data = NULL;
1359   *data_size = 0;
1360   
1361   if (!transport->authenticated)
1362     return FALSE;
1363   
1364   auth_identity = _dbus_auth_get_identity (transport->auth);
1365
1366   if (_dbus_credentials_include (auth_identity,
1367                                  DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID))
1368     {
1369       *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity);
1370       *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity);
1371       return TRUE;
1372     }
1373   else
1374     return FALSE;
1375 }
1376
1377 /**
1378  * See dbus_connection_set_unix_user_function().
1379  *
1380  * @param transport the transport
1381  * @param function the predicate
1382  * @param data data to pass to the predicate
1383  * @param free_data_function function to free the data
1384  * @param old_data the old user data to be freed
1385  * @param old_free_data_function old free data function to free it with
1386  */
1387 void
1388 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
1389                                         DBusAllowUnixUserFunction  function,
1390                                         void                      *data,
1391                                         DBusFreeFunction           free_data_function,
1392                                         void                     **old_data,
1393                                         DBusFreeFunction          *old_free_data_function)
1394 {  
1395   *old_data = transport->unix_user_data;
1396   *old_free_data_function = transport->free_unix_user_data;
1397
1398   transport->unix_user_function = function;
1399   transport->unix_user_data = data;
1400   transport->free_unix_user_data = free_data_function;
1401 }
1402
1403 /**
1404  * See dbus_connection_get_windows_user().
1405  *
1406  * @param transport the transport
1407  * @param windows_sid_p return location for the user ID
1408  * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it
1409  */
1410 dbus_bool_t
1411 _dbus_transport_get_windows_user (DBusTransport              *transport,
1412                                   char                      **windows_sid_p)
1413 {
1414   DBusCredentials *auth_identity;
1415
1416   *windows_sid_p = NULL;
1417   
1418   if (!transport->authenticated)
1419     return FALSE;
1420   
1421   auth_identity = _dbus_auth_get_identity (transport->auth);
1422
1423   if (_dbus_credentials_include (auth_identity,
1424                                  DBUS_CREDENTIAL_WINDOWS_SID))
1425     {
1426       /* If no memory, we are supposed to return TRUE and set NULL */
1427       *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
1428
1429       return TRUE;
1430     }
1431   else
1432     return FALSE;
1433 }
1434
1435 /**
1436  * See dbus_connection_set_windows_user_function().
1437  *
1438  * @param transport the transport
1439  * @param function the predicate
1440  * @param data data to pass to the predicate
1441  * @param free_data_function function to free the data
1442  * @param old_data the old user data to be freed
1443  * @param old_free_data_function old free data function to free it with
1444  */
1445
1446 void
1447 _dbus_transport_set_windows_user_function (DBusTransport              *transport,
1448                                            DBusAllowWindowsUserFunction   function,
1449                                            void                       *data,
1450                                            DBusFreeFunction            free_data_function,
1451                                            void                      **old_data,
1452                                            DBusFreeFunction           *old_free_data_function)
1453 {
1454   *old_data = transport->windows_user_data;
1455   *old_free_data_function = transport->free_windows_user_data;
1456
1457   transport->windows_user_function = function;
1458   transport->windows_user_data = data;
1459   transport->free_windows_user_data = free_data_function;
1460 }
1461
1462 /**
1463  * Sets the SASL authentication mechanisms supported by this transport.
1464  *
1465  * @param transport the transport
1466  * @param mechanisms the #NULL-terminated array of mechanisms
1467  *
1468  * @returns #FALSE if no memory
1469  */
1470 dbus_bool_t
1471 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
1472                                      const char    **mechanisms)
1473 {
1474   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
1475 }
1476
1477 /**
1478  * See dbus_connection_set_allow_anonymous()
1479  *
1480  * @param transport the transport
1481  * @param value #TRUE to allow anonymous connection
1482  */
1483 void
1484 _dbus_transport_set_allow_anonymous (DBusTransport              *transport,
1485                                      dbus_bool_t                 value)
1486 {
1487   transport->allow_anonymous = value != FALSE;
1488 }
1489
1490 /** @} */