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