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