2003-03-24 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 1.2
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-connection-internal.h"
27 #include "dbus-watch.h"
28 #include "dbus-auth.h"
29 #include "dbus-address.h"
30 #ifdef DBUS_BUILD_TESTS
31 #include "dbus-transport-debug.h"
32 #include "dbus-server-debug-pipe.h"
33 #endif
34
35 /**
36  * @defgroup DBusTransport DBusTransport object
37  * @ingroup  DBusInternals
38  * @brief "Backend" for a DBusConnection.
39  *
40  * Types and functions related to DBusTransport.  A transport is an
41  * abstraction that can send and receive data via various kinds of
42  * network connections or other IPC mechanisms.
43  * 
44  * @{
45  */
46
47 /**
48  * @typedef DBusTransport
49  *
50  * Opaque object representing a way message stream.
51  * DBusTransport abstracts various kinds of actual
52  * transport mechanism, such as different network protocols,
53  * or encryption schemes.
54  */
55
56 static void
57 live_messages_size_notify (DBusCounter *counter,
58                            void        *user_data)
59 {
60   DBusTransport *transport = user_data;
61
62   _dbus_transport_ref (transport);
63
64 #if 0
65   _dbus_verbose ("Counter value is now %d\n",
66                  (int) _dbus_counter_get_value (counter));
67 #endif
68   
69   /* disable or re-enable the read watch for the transport if
70    * required.
71    */
72   if (* transport->vtable->live_messages_changed)
73     (* transport->vtable->live_messages_changed) (transport);
74
75   _dbus_transport_unref (transport);
76 }
77
78 /**
79  * Initializes the base class members of DBusTransport.
80  * Chained up to by subclasses in their constructor.
81  *
82  * @param transport the transport being created.
83  * @param vtable the subclass vtable.
84  * @param server #TRUE if this transport is on the server side of a connection
85  * @returns #TRUE on success.
86  */
87 dbus_bool_t
88 _dbus_transport_init_base (DBusTransport             *transport,
89                            const DBusTransportVTable *vtable,
90                            dbus_bool_t                server)
91 {
92   DBusMessageLoader *loader;
93   DBusAuth *auth;
94   DBusCounter *counter;
95   
96   loader = _dbus_message_loader_new ();
97   if (loader == NULL)
98     return FALSE;
99   
100   if (server)
101     auth = _dbus_auth_server_new ();
102   else
103     auth = _dbus_auth_client_new ();
104   if (auth == NULL)
105     {
106       _dbus_message_loader_unref (loader);
107       return FALSE;
108     }
109
110   counter = _dbus_counter_new ();
111   if (counter == NULL)
112     {
113       _dbus_auth_unref (auth);
114       _dbus_message_loader_unref (loader);
115       return FALSE;
116     }
117   
118   transport->refcount = 1;
119   transport->vtable = vtable;
120   transport->loader = loader;
121   transport->auth = auth;
122   transport->live_messages_size = counter;
123   transport->authenticated = FALSE;
124   transport->messages_need_sending = FALSE;
125   transport->disconnected = FALSE;
126   transport->send_credentials_pending = !server;
127   transport->receive_credentials_pending = server;
128   transport->is_server = server;
129
130   transport->unix_user_function = NULL;
131   transport->unix_user_data = NULL;
132   transport->free_unix_user_data = NULL;
133   
134   /* Try to default to something that won't totally hose the system,
135    * but doesn't impose too much of a limitation.
136    */
137   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
138   
139   transport->credentials.pid = -1;
140   transport->credentials.uid = -1;
141   transport->credentials.gid = -1;
142
143   _dbus_counter_set_notify (transport->live_messages_size,
144                             transport->max_live_messages_size,
145                             live_messages_size_notify,
146                             transport);
147   
148   return TRUE;
149 }
150
151 /**
152  * Finalizes base class members of DBusTransport.
153  * Chained up to from subclass finalizers.
154  *
155  * @param transport the transport.
156  */
157 void
158 _dbus_transport_finalize_base (DBusTransport *transport)
159 {
160   if (!transport->disconnected)
161     _dbus_transport_disconnect (transport);
162
163   if (transport->free_unix_user_data != NULL)
164     (* transport->free_unix_user_data) (transport->unix_user_data);
165   
166   _dbus_message_loader_unref (transport->loader);
167   _dbus_auth_unref (transport->auth);
168   _dbus_counter_set_notify (transport->live_messages_size,
169                             0, NULL, NULL);
170   _dbus_counter_unref (transport->live_messages_size);
171 }
172
173 /**
174  * Opens a new transport for the given address.  (This opens a
175  * client-side-of-the-connection transport.)
176  *
177  * @todo error messages on bad address could really be better.
178  * DBusResultCode is a bit limiting here.
179  * 
180  * @param address the address.
181  * @param error location to store reason for failure.
182  * @returns new transport of #NULL on failure.
183  */
184 DBusTransport*
185 _dbus_transport_open (const char     *address,
186                       DBusError      *error)
187 {
188   DBusTransport *transport;
189   DBusAddressEntry **entries;
190   int len, i;
191   const char *address_problem_type;
192   const char *address_problem_field;
193   const char *address_problem_other;
194
195   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
196   
197   if (!dbus_parse_address (address, &entries, &len, error))
198     return NULL;
199
200   transport = NULL;
201   address_problem_type = NULL;
202   address_problem_field = NULL;
203   address_problem_other = NULL;
204   
205   for (i = 0; i < len; i++)
206     {
207       const char *method = dbus_address_entry_get_method (entries[i]);
208
209       if (strcmp (method, "unix") == 0)
210         {
211           const char *path = dbus_address_entry_get_value (entries[i], "path");
212
213           if (path == NULL)
214             {
215               address_problem_type = "unix";
216               address_problem_field = "path";              
217               goto bad_address;
218             }
219
220           transport = _dbus_transport_new_for_domain_socket (path, FALSE, error);
221         }
222       else if (strcmp (method, "tcp") == 0)
223         {
224           const char *host = dbus_address_entry_get_value (entries[i], "host");
225           const char *port = dbus_address_entry_get_value (entries[i], "port");
226           DBusString  str;
227           long lport;
228           dbus_bool_t sresult;
229           
230           if (port == NULL)
231             {
232               address_problem_type = "tcp";
233               address_problem_field = "port";
234               goto bad_address;
235             }
236
237           _dbus_string_init_const (&str, port);
238           sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
239           _dbus_string_free (&str);
240           
241           if (sresult == FALSE || lport <= 0 || lport > 65535)
242             {
243               address_problem_other = "Port is not an integer between 0 and 65535";
244               goto bad_address;
245             }
246           
247           transport = _dbus_transport_new_for_tcp_socket (host, lport, FALSE, error);
248         }
249 #ifdef DBUS_BUILD_TESTS
250       else if (strcmp (method, "debug") == 0)
251         {
252           const char *name = dbus_address_entry_get_value (entries[i], "name");
253
254           if (name == NULL)
255             {
256               address_problem_type = "debug";
257               address_problem_field = "name";
258               goto bad_address;
259             }
260
261           transport = _dbus_transport_debug_client_new (name, error);
262         }
263       else if (strcmp (method, "debug-pipe") == 0)
264         {
265           const char *name = dbus_address_entry_get_value (entries[i], "name");
266
267           if (name == NULL)
268             {
269               address_problem_type = "debug-pipe";
270               address_problem_field = "name";
271               goto bad_address;
272             }
273
274           transport = _dbus_transport_debug_pipe_new (name, error);
275         }
276 #endif
277       else
278         {
279           address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
280           goto bad_address;
281         }
282
283       if (transport)
284         break;    
285     }
286   
287   dbus_address_entries_free (entries);
288   return transport;
289
290  bad_address:
291   dbus_address_entries_free (entries);
292
293   if (address_problem_type != NULL)
294     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
295                     "Address of type %s was missing argument %s",
296                     address_problem_type, address_problem_field);
297   else
298     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
299                     "Could not parse address: %s",
300                     address_problem_other);
301
302   return NULL;
303 }
304
305 /**
306  * Increments the reference count for the transport.
307  *
308  * @param transport the transport.
309  */
310 void
311 _dbus_transport_ref (DBusTransport *transport)
312 {
313   _dbus_assert (transport->refcount > 0);
314   
315   transport->refcount += 1;
316 }
317
318 /**
319  * Decrements the reference count for the transport.
320  * Disconnects and finalizes the transport if
321  * the reference count reaches zero.
322  *
323  * @param transport the transport.
324  */
325 void
326 _dbus_transport_unref (DBusTransport *transport)
327 {
328   _dbus_assert (transport != NULL);
329   _dbus_assert (transport->refcount > 0);
330
331   transport->refcount -= 1;
332   if (transport->refcount == 0)
333     {
334       _dbus_assert (transport->vtable->finalize != NULL);
335       
336       (* transport->vtable->finalize) (transport);
337     }
338 }
339
340 /**
341  * Closes our end of the connection to a remote application. Further
342  * attempts to use this transport will fail. Only the first call to
343  * _dbus_transport_disconnect() will have an effect.
344  *
345  * @param transport the transport.
346  * 
347  */
348 void
349 _dbus_transport_disconnect (DBusTransport *transport)
350 {
351   _dbus_assert (transport->vtable->disconnect != NULL);
352
353   if (transport->disconnected)
354     return;
355
356   (* transport->vtable->disconnect) (transport);
357   
358   transport->disconnected = TRUE;
359
360   if (transport->connection)
361     _dbus_connection_notify_disconnected (transport->connection);
362 }
363
364 /**
365  * Returns #TRUE if the transport has not been disconnected.
366  * Disconnection can result from _dbus_transport_disconnect()
367  * or because the server drops its end of the connection.
368  *
369  * @param transport the transport.
370  * @returns whether we're connected
371  */
372 dbus_bool_t
373 _dbus_transport_get_is_connected (DBusTransport *transport)
374 {
375   return !transport->disconnected;
376 }
377
378 /**
379  * Returns #TRUE if we have been authenticated.  Will return #TRUE
380  * even if the transport is disconnected.
381  *
382  * @todo needs to drop connection->mutex when calling the unix_user_function
383  *
384  * @param transport the transport
385  * @returns whether we're authenticated
386  */
387 dbus_bool_t
388 _dbus_transport_get_is_authenticated (DBusTransport *transport)
389 {  
390   if (transport->authenticated)
391     return TRUE;
392   else
393     {
394       dbus_bool_t maybe_authenticated;
395       
396       if (transport->disconnected)
397         return FALSE;
398       
399       maybe_authenticated =
400         (!(transport->send_credentials_pending ||
401            transport->receive_credentials_pending)) &&
402         _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_AUTHENTICATED;
403
404       /* If we've authenticated as some identity, check that the auth
405        * identity is the same as our own identity.  In the future, we
406        * may have API allowing applications to specify how this is
407        * done, for example they may allow connection as any identity,
408        * but then impose restrictions on certain identities.
409        * Or they may give certain identities extra privileges.
410        */
411       
412       if (maybe_authenticated && transport->is_server)
413         {
414           DBusCredentials auth_identity;
415
416           _dbus_auth_get_identity (transport->auth, &auth_identity);
417
418           if (transport->unix_user_function != NULL)
419             {
420               /* FIXME we hold the connection lock here and should drop it */
421               if (!(* transport->unix_user_function) (transport->connection,
422                                                       auth_identity.uid,
423                                                       transport->unix_user_data))
424                 {
425                   _dbus_verbose ("Client UID %d was rejected, disconnecting\n",
426                                  auth_identity.uid);
427                   _dbus_transport_disconnect (transport);
428                   return FALSE;
429                 }
430               else
431                 {
432                   _dbus_verbose ("Client UID %d authorized\n", auth_identity.uid);
433                 }
434             }
435           else
436             {
437               DBusCredentials our_identity;
438               
439               _dbus_credentials_from_current_process (&our_identity);
440               
441               if (!_dbus_credentials_match (&our_identity,
442                                             &auth_identity))
443                 {
444                   _dbus_verbose ("Client authorized as UID %d but our UID is %d, disconnecting\n",
445                                  auth_identity.uid, our_identity.uid);
446                   _dbus_transport_disconnect (transport);
447                   return FALSE;
448                 }
449               else
450                 {
451                   _dbus_verbose ("Client authorized as UID %d matching our UID %d\n",
452                                  auth_identity.uid, our_identity.uid);
453                 }
454             }
455         }
456
457       transport->authenticated = maybe_authenticated;
458       
459       return transport->authenticated;
460     }
461 }
462
463 /**
464  * Handles a watch by reading data, writing data, or disconnecting
465  * the transport, as appropriate for the given condition.
466  *
467  * @param transport the transport.
468  * @param watch the watch.
469  * @param condition the current state of the watched file descriptor.
470  * @returns #FALSE if not enough memory to fully handle the watch
471  */
472 dbus_bool_t
473 _dbus_transport_handle_watch (DBusTransport           *transport,
474                               DBusWatch               *watch,
475                               unsigned int             condition)
476 {
477   dbus_bool_t retval;
478   
479   _dbus_assert (transport->vtable->handle_watch != NULL);
480
481   if (transport->disconnected)
482     return TRUE;
483
484   if (dbus_watch_get_fd (watch) < 0)
485     {
486       _dbus_warn ("Tried to handle an invalidated watch; this watch should have been removed\n");
487       return TRUE;
488     }
489   
490   _dbus_watch_sanitize_condition (watch, &condition);
491
492   _dbus_transport_ref (transport);
493   _dbus_watch_ref (watch);
494   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
495   _dbus_watch_unref (watch);
496   _dbus_transport_unref (transport);
497
498   return retval;
499 }
500
501 /**
502  * Sets the connection using this transport. Allows the transport
503  * to add watches to the connection, queue incoming messages,
504  * and pull outgoing messages.
505  *
506  * @param transport the transport.
507  * @param connection the connection.
508  * @returns #FALSE if not enough memory
509  */
510 dbus_bool_t
511 _dbus_transport_set_connection (DBusTransport  *transport,
512                                 DBusConnection *connection)
513 {
514   _dbus_assert (transport->vtable->connection_set != NULL);
515   _dbus_assert (transport->connection == NULL);
516   
517   transport->connection = connection;
518
519   _dbus_transport_ref (transport);
520   if (!(* transport->vtable->connection_set) (transport))
521     transport->connection = NULL;
522   _dbus_transport_unref (transport);
523
524   return transport->connection != NULL;
525 }
526
527 /**
528  * Notifies the transport when the outgoing message queue goes from
529  * empty to non-empty or vice versa. Typically causes the transport to
530  * add or remove its DBUS_WATCH_WRITABLE watch.
531  *
532  * @param transport the transport.
533  * @param queue_length the length of the outgoing message queue.
534  *
535  */
536 void
537 _dbus_transport_messages_pending (DBusTransport  *transport,
538                                   int             queue_length)
539 {
540   _dbus_assert (transport->vtable->messages_pending != NULL);
541
542   if (transport->disconnected)
543     return;
544
545   transport->messages_need_sending = queue_length > 0;
546
547   _dbus_transport_ref (transport);
548   (* transport->vtable->messages_pending) (transport,
549                                            queue_length);
550   _dbus_transport_unref (transport);
551 }
552
553 /**
554  * Performs a single poll()/select() on the transport's file
555  * descriptors and then reads/writes data as appropriate,
556  * queueing incoming messages and sending outgoing messages.
557  * This is the backend for _dbus_connection_do_iteration().
558  * See _dbus_connection_do_iteration() for full details.
559  *
560  * @param transport the transport.
561  * @param flags indicates whether to read or write, and whether to block.
562  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
563  */
564 void
565 _dbus_transport_do_iteration (DBusTransport  *transport,
566                               unsigned int    flags,
567                               int             timeout_milliseconds)
568 {
569   _dbus_assert (transport->vtable->do_iteration != NULL);
570
571   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
572                  flags, timeout_milliseconds, !transport->disconnected);
573   
574   if ((flags & (DBUS_ITERATION_DO_WRITING |
575                 DBUS_ITERATION_DO_READING)) == 0)
576     return; /* Nothing to do */
577
578   if (transport->disconnected)
579     return;
580
581   _dbus_transport_ref (transport);
582   (* transport->vtable->do_iteration) (transport, flags,
583                                        timeout_milliseconds);
584   _dbus_transport_unref (transport);
585 }
586
587 static dbus_bool_t
588 recover_unused_bytes (DBusTransport *transport)
589 {
590   if (_dbus_auth_do_work (transport->auth) != DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES)
591     return TRUE;
592   
593   if (_dbus_auth_needs_decoding (transport->auth))
594     {
595       DBusString plaintext;
596       const DBusString *encoded;
597       DBusString *buffer;
598       int orig_len;
599       
600       if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
601         goto nomem;
602       
603       _dbus_auth_get_unused_bytes (transport->auth,
604                                    &encoded);
605
606       if (!_dbus_auth_decode_data (transport->auth,
607                                    encoded, &plaintext))
608         {
609           _dbus_string_free (&plaintext);
610           goto nomem;
611         }
612       
613       _dbus_message_loader_get_buffer (transport->loader,
614                                        &buffer);
615       
616       orig_len = _dbus_string_get_length (buffer);
617       
618       if (!_dbus_string_move (&plaintext, 0, buffer,
619                               orig_len))
620         {
621           _dbus_string_free (&plaintext);
622           goto nomem;
623         }
624       
625       _dbus_verbose (" %d unused bytes sent to message loader\n", 
626                      _dbus_string_get_length (buffer) -
627                      orig_len);
628       
629       _dbus_message_loader_return_buffer (transport->loader,
630                                           buffer,
631                                           _dbus_string_get_length (buffer) -
632                                           orig_len);
633
634       _dbus_auth_delete_unused_bytes (transport->auth);
635       
636       _dbus_string_free (&plaintext);
637     }
638   else
639     {
640       const DBusString *bytes;
641       DBusString *buffer;
642       int orig_len;
643       dbus_bool_t succeeded;
644
645       _dbus_message_loader_get_buffer (transport->loader,
646                                        &buffer);
647                 
648       orig_len = _dbus_string_get_length (buffer);
649                 
650       _dbus_auth_get_unused_bytes (transport->auth,
651                                    &bytes);
652
653       succeeded = TRUE;
654       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
655         succeeded = FALSE;
656       
657       _dbus_verbose (" %d unused bytes sent to message loader\n", 
658                      _dbus_string_get_length (buffer) -
659                      orig_len);
660       
661       _dbus_message_loader_return_buffer (transport->loader,
662                                           buffer,
663                                           _dbus_string_get_length (buffer) -
664                                           orig_len);
665
666       if (succeeded)
667         _dbus_auth_delete_unused_bytes (transport->auth);
668       else
669         goto nomem;
670     }
671
672   return TRUE;
673
674  nomem:
675   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
676   return FALSE;
677 }
678
679 /**
680  * Reports our current dispatch status (whether there's buffered
681  * data to be queued as messages, or not, or we need memory).
682  *
683  * @param transport the transport
684  * @returns current status
685  */
686 DBusDispatchStatus
687 _dbus_transport_get_dispatch_status (DBusTransport *transport)
688 {
689   if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
690     return DBUS_DISPATCH_COMPLETE; /* complete for now */
691
692   if (!_dbus_transport_get_is_authenticated (transport))
693     {
694       switch (_dbus_auth_do_work (transport->auth))
695         {
696         case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
697           return DBUS_DISPATCH_NEED_MEMORY;
698         case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
699           if (!recover_unused_bytes (transport))
700             return DBUS_DISPATCH_NEED_MEMORY;
701           break;
702         default:
703           break;
704         }
705     }
706   
707   if (!_dbus_message_loader_queue_messages (transport->loader))
708     return DBUS_DISPATCH_NEED_MEMORY;
709
710   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
711     return DBUS_DISPATCH_DATA_REMAINS;
712   else
713     return DBUS_DISPATCH_COMPLETE;
714 }
715
716 /**
717  * Processes data we've read while handling a watch, potentially
718  * converting some of it to messages and queueing those messages on
719  * the connection.
720  *
721  * @param transport the transport
722  * @returns #TRUE if we had enough memory to queue all messages
723  */
724 dbus_bool_t
725 _dbus_transport_queue_messages (DBusTransport *transport)
726 {
727   DBusDispatchStatus status;
728   
729   /* Queue any messages */
730   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
731     {
732       DBusMessage *message;
733       DBusList *link;
734
735       link = _dbus_message_loader_pop_message_link (transport->loader);
736       _dbus_assert (link != NULL);
737       
738       message = link->data;
739       
740       _dbus_verbose ("queueing received message %p\n", message);
741
742       _dbus_message_add_size_counter (message, transport->live_messages_size);
743
744       /* pass ownership of link and message ref to connection */
745       _dbus_connection_queue_received_message_link (transport->connection,
746                                                     link);
747     }
748
749   if (_dbus_message_loader_get_is_corrupted (transport->loader))
750     {
751       _dbus_verbose ("Corrupted message stream, disconnecting\n");
752       _dbus_transport_disconnect (transport);
753     }
754
755   return status != DBUS_DISPATCH_NEED_MEMORY;
756 }
757
758 /**
759  * See dbus_connection_set_max_message_size().
760  *
761  * @param transport the transport
762  * @param size the max size of a single message
763  */
764 void
765 _dbus_transport_set_max_message_size (DBusTransport  *transport,
766                                       long            size)
767 {
768   _dbus_message_loader_set_max_message_size (transport->loader, size);
769 }
770
771 /**
772  * See dbus_connection_get_max_message_size().
773  *
774  * @param transport the transport
775  * @returns max message size
776  */
777 long
778 _dbus_transport_get_max_message_size (DBusTransport  *transport)
779 {
780   return _dbus_message_loader_get_max_message_size (transport->loader);
781 }
782
783 /**
784  * See dbus_connection_set_max_live_messages_size().
785  *
786  * @param transport the transport
787  * @param size the max size of all incoming messages
788  */
789 void
790 _dbus_transport_set_max_live_messages_size (DBusTransport  *transport,
791                                             long            size)
792 {
793   transport->max_live_messages_size = size;
794   _dbus_counter_set_notify (transport->live_messages_size,
795                             transport->max_live_messages_size,
796                             live_messages_size_notify,
797                             transport);
798 }
799
800
801 /**
802  * See dbus_connection_get_max_live_messages_size().
803  *
804  * @param transport the transport
805  * @returns max bytes for all live messages
806  */
807 long
808 _dbus_transport_get_max_live_messages_size (DBusTransport  *transport)
809 {
810   return transport->max_live_messages_size;
811 }
812
813 /**
814  * See dbus_connection_get_unix_user().
815  *
816  * @param transport the transport
817  * @param uid return location for the user ID
818  * @returns #TRUE if uid is filled in with a valid user ID
819  */
820 dbus_bool_t
821 _dbus_transport_get_unix_user (DBusTransport *transport,
822                                unsigned long *uid)
823 {
824   DBusCredentials auth_identity;
825
826   *uid = _DBUS_INT_MAX; /* better than some root or system user in
827                          * case of bugs in the caller. Caller should
828                          * never use this value on purpose, however.
829                          */
830   
831   if (!transport->authenticated)
832     return FALSE;
833   
834   _dbus_auth_get_identity (transport->auth, &auth_identity);
835
836   if (auth_identity.uid >= 0)
837     {
838       *uid = auth_identity.uid;
839       return TRUE;
840     }
841   else
842     return FALSE;
843 }
844
845 /**
846  * See dbus_connection_set_unix_user_function().
847  *
848  * @param transport the transport
849  * @param function the predicate
850  * @param data data to pass to the predicate
851  * @param free_data_function function to free the data
852  * @param old_data the old user data to be freed
853  * @param old_free_data_function old free data function to free it with
854  */
855 void
856 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
857                                         DBusAllowUnixUserFunction  function,
858                                         void                      *data,
859                                         DBusFreeFunction           free_data_function,
860                                         void                     **old_data,
861                                         DBusFreeFunction          *old_free_data_function)
862 {  
863   *old_data = transport->unix_user_data;
864   *old_free_data_function = transport->free_unix_user_data;
865
866   transport->unix_user_function = function;
867   transport->unix_user_data = data;
868   transport->free_unix_user_data = free_data_function;
869 }
870
871 /** @} */