-
Products
JBoss Enterprise Middleware
Web Server Developer Studio Portfolio Edition JBoss Operations Network FuseSource Integration Products Web Framework Kit Application Platform Data Grid Portal Platform SOA Platform Business Rules Management System (BRMS) Data Services Platform Messaging JBoss Community or JBoss enterprise -
Solutions
By IT challenge
Application development Business process management Enterprise application integration Interoperability Operational efficiency Security VirtualizationMigration Center
Migrate to Red Hat Enterprise Linux Systems management Upgrading to Red Hat Enterprise Linux JBoss Enterprise Middleware IBM AIX to Red Hat Enterprise Linux HP-UX to Red Hat Enterprise Linux Solaris to Red Hat Enterprise Linux UNIX to Red Hat Enterprise Linux Start a conversation with Red Hat Migration services
Issue #3 January 2005
Features
- Firefox rising
- Coming soon in Enterprise Linux
- Get on D-BUS
- Desktop and hardware configuration
- Introducing NetworkManager
- Video: Red Hat Academy
- Getting ready for Red Hat Summit
- From teacher to crusader
- LAMP lights the web
From the Inside
In each Issue
- Editor's blog
- Red Hat speaks
- Ask Shadowman
- Tips & tricks
- Fedora status report
- Magazine archive
- Contest
Feedback
Get on D-BUS
by John Palmieri
- Introduction
- What is D-BUS?
- Anatomy of a message
- Built-in security
- Even more security with a little help from a friend
- A conduit for making things just work
- A fresh new view on how applications are designed
- Integration is the name of the game
- Problems we face
- The future of D-BUS
- Conclusion
- Further reading
- About the author
Introduction
For the longest time Linux applications were islands unto themselves, unable to effectively communicate and cooperate except through primitive means of pipes, sockets, shared memory, and file systems. The problem with these mechanisms were that they could be used differently by different applications. If a connection was made, it was often only between a couple of application as the work needed to get the applications talking was often not worth the trouble. It would be like a country constructing ports that only fit one type of ship. Anyone could send a ship over the ocean to this port, but only those ships that were build to fit would have any success of docking. What was needed was a standard for ships to dock and a security protocol to make sure they were allowed to dock. Many solutions such as Corba, DCOP, SOAP, XML-RPC, and XPCOM sprung up during the years to address parts of the problem. Most of these solutions were either too hard to use or confined to specific groups of users or problem domains. One solution stands out as way to unite Linux from the kernel up to the desktop. D-BUS has the momentum and backing of a diverse group of users and is designed from the ground up for the purpose of easy to use communication between applications and also the OS. If you haven't already, it is time to get on D-BUS!
If you haven't already, it is time to get on the D-BUS!
What is D-BUS?
D-BUS is an IPC mechanism for sending and receiving messages across a common communications channel. It was started in 2002 by Havoc Pennington and Alex Larsson of Red Hat, Inc. and Anders Carlsson formerly of CodeFactory AB as part of the freedesktop.org project to standardize around one messaging platform for the desktop. Today it is rapidly moving towards 1.0 status with a few major changes in the works.
At the protocol level D-BUS can be used as a peer-to-peer message transport for applications to communicate directly with each other. The real power of D-BUS comes from the bus daemons which act as routers for messages. There are two standard buses that a developer can rely on always being around. These are the system bus and the session bus.
The system bus is a global daemon that any application running in any context can use as a transport. It is a single point where applications can export services that anyone can use. Only one system bus daemon can be run at a time.
The session bus is a bus local to the current user's session. It is used for communication between applications running within the same X session. For every login to X, a session bus daemon is started.
Anatomy of a message
D-BUS specifies a common binary format in which to transport information. This is commonly referred to as a message. Because it is a binary protocol, D-BUS messages incur low overhead when marshaling and dmarshling data. Messages consist of a two sections, the header and the body. The header contains the meta data for the message. This can include routing information and (planned for the future 1.0 release) the type signature for the data. The body contains the data being sent.
Each piece of data has a type code associated with it and is packed into the body accordingly. Some common types include bytes, 32 and 64 bit integers, doubles, and strings. On top of that, complex types such as arrays, dictionaries, and in the future, named structs can be encoded into a message. This allows communication between applications written in a wide range of languages with the ability to retain a common set of data structures. Right now data types are encoded with the data inside the body of the message in a type code, data, type code, data format. Work is currently being done to separate the types from the data, creating a type signature field in the header and making the body a pure data stream.
In the D-BUS world, messages are sent to objects, not applications.
Applications themselves are free to register as many objects as they wish.
A D-BUS object can be thought of like any other object in most programming
language with the exception that they are pointed to not by memory addresses
but by object paths. Object paths take the form of a string which looks
similar to Unix file system paths. For example D-BUS exports the
/org/freedesktop/DBus object.
Interfaces are also supported by D-BUS. They simply allow the same method
name to be used more than once with the interface specifying which of
those methods is actually invoked. Interfaces group methods and signals
together and can be thought of as the type for the object instance.
Interfaces are specified by period delimited strings. D-BUS exports the
org.freedesktop.DBus interface.
To route the message to the correct recipient, objects and interfaces are
not enough. For this we have the concept of
services. A service is a unique location on the
bus owned by an application. When a D-BUS application starts it registers
one or more services that it will then own until it releases them. If
another process tries to own a service that is already registered, it will
get back an error message stating that the service is not available.
Because of this uniqueness, services can be used not just as a way to
route messages but also as a way to track the life cycle of an
application. D-BUS supports activation of services. If a service is not
registered when a object is invoked on it and auto-activation has been
enabled, D-BUS will look into its listing of activate services to find a
match and start the application. Upon termination of the application the
D-BUS daemon will de-register any services associated with that process.
It will also send a signal to anyone who is watching that the service has
been closed, thereby allowing the listening application to react
appropriately. Services are specified by a period delimited string
similar to interface names. The service exported by D-BUS is
org.freedesktop.DBus.
D-BUS objects are invoked through both methods and signals. D-BUS methods are like any other method in an object-oriented language. You invoke a method on an object directly by sending a method message to an object's interface on a service. The message may contain a list of parameters you wish to send to the method. A method can reply back both synchronously, where your program waits for a reply, or asynchronously where your program will be notified when a reply has been received. Methods do not have to send a reply back. Signals are simple notifications that an event has occurred. A signal is broadcast over the bus and therefor does not require a service to send to. Anyone listening for a particular signal will be notified when it is emitted.
There are a couple of other message types which are sent on the bus. These are method return messages and error messages. Method return messages are similar to method messages. They, however, do not have a method to invoke, and instead of parameter data being sent, return data is sent in the body of the message. Error messages are a special case of a method return message which return the error type and error string of the exception raised by the method call.
Now that you have read about the basics, let us look at some practical
code for talking to the
org.freedesktop.DBus service. Example 1, “Low level C ListServices example”, Example 2, “glib ListServices example”,
and Example 3, “python ListServices example” show how to invoke the
ListServices method using the lowlevel C,
glib and python bindings. They are all modified from the D-BUS tutorial
if you wish to read more about the code.
int
main (int argc, char **argv)
{
DBusConnection *connection;
DBusError error;
DBusMessage *message;
DBusMessage *reply;
int reply_timeout;
char **service_list;
int service_list_len;
int i;
dbus_error_init (&error);
connection = dbus_bus_get (DBUS_BUS_SYSTEM,
&error);
if (connection == NULL)
{
fprintf(stderr, "Failed to open connection to bus: %s\n",
error.message);
dbus_error_free (error);
exit (1);
}
/* Construct the message */
message = dbus_message_new_method_call ("org.freedesktop.DBus", /*service*/
"/org/freedesktop/DBus", /*path*/
"org.freedesktop.DBus", /*interface*/
"ListServices");
/* Call ListServices method */
reply_timeout = -1; /*don't timeout*/
reply = dbus_connection_send_with_reply_and_block (connection,
message, reply_timeout,
&error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "Error: %s\n",
error.message);
exit (1);
}
/* Extract the data from the reply */
if (!dbus_message_get_args (reply, &error,
DBUS_TYPE_ARRAY, &service_list,
DBUS_TYPE_INT32, &service_list_len,
DBUS_TYPE_INVALID))
{
fprintf (stderr, "Failed to complete ListServices call: %s\n",
error.message);
exit (1);
}
dbus_message_unref (reply);
dbus_message_unref (message);
/* Print the results */
printf ("Services on the message bus:\n");
i = 0;
while (i < service_list_len)
{
assert (service_list[i] != NULL);
printf (" %s\n", service_list[i]);
++i;
}
assert (service_list[i] == NULL);
for (i = 0; i < service_list_len; i++)
free (service_list[i]);
free (service_list);
return 0;
}
int
main (int argc, char **argv)
{
DBusGConnection *connection;
GError *error;
DBusGProxy *proxy;
DBusGPendingCall *call;
char **service_list;
int service_list_len;
int i;
g_type_init ();
error = NULL;
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM,
&error);
if (connection == NULL)
{
g_printerr ("Failed to open connection to bus: %s\n",
error->message);
g_error_free (error);
exit (1);
}
/* Create a proxy object for the "bus driver" (service org.freedesktop.DBus) */
proxy = dbus_g_proxy_new_for_service (connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus");
/* Call ListServices method */
call = dbus_g_proxy_begin_call (proxy, "ListServices", DBUS_TYPE_INVALID);
error = NULL;
if (!dbus_g_proxy_end_call (proxy, call, &error,
DBUS_TYPE_ARRAY, &service_list,
DBUS_TYPE_INT32, &service_list_len,
DBUS_TYPE_INVALID))
{
g_printerr ("Failed to complete ListServices call: %s\n",
error->message);
g_error_free (error);
exit (1);
}
/* Print the results */
g_print ("Services on the message bus:\n");
i = 0;
while (i < service_list_len)
{
g_assert (service_list[i] != NULL);
g_print (" %s\n", service_list[i]);
++i;
}
g_assert (service_list[i] == NULL);
g_strfreev (service_list);
return 0;
}
import dbus
bus = dbus.SystemBus()
remote_service = bus.get_service("org.freedesktop.DBus")
remote_object = remote_service.get_object("/org/freedesktop/DBus",
"org.freedesktop.DBus")
service_list = remote_object.ListServices()
print ("Services on the message bus:\n")
for service in service_list:
print service
Built-in security
As was stated earlier, security is a requirement for any solution that
wants to become the standard for inter-application communications. D-BUS
was designed with this in mind and has security built-in. Security policy
is specified in XML files commonly placed in the
/etc/dbus-1/system.d/ directory and loaded when D-BUS
starts. The following NetworkManager.conf file
serves as a nice example of D-BUS policy:
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="org.freedesktop.NetworkManager"/>
<allow send_destination="org.freedesktop.NetworkManager"/>
<allow send_interface="org.freedesktop.NetworkManager"/>
</policy>
<policy at_console="true">
<allow send_destination="org.freedesktop.NetworkManager"/>
<allow send_interface="org.freedesktop.NetworkManager"/>
</policy>
<policy context="default">
<deny own="org.freedesktop.NetworkManager"/>
<deny send_destination="org.freedesktop.NetworkManager"/>
<deny send_interface="org.freedesktop.NetworkManager"/>
</policy>
</busconfig>
As can be seen, if no rules match, by default we deny anyone from owning or sending to the NetworkManager service and interface. As one can also see, any process running as the root user can own the service and send messages to it through the NetworkManager interface.
What is most interesting in this security policy is the
at_console rule. This feature is Red Hat
specific though any distro that uses the
pam_console module can take advantage of
the at_console rules. It can be
generally assumed that anyone marked as a console user is physically
sitting in front of the computer. For a certain class of applications we
may wish to allow the console user to control functionality that would
normally be reserved for the root user. An example of this is changing
network configuration. The at_console
rule allows a console user to invoke methods on the NetworkManager service
which is running as the root user. This in turn allows a user who is
physically at the computer to change which wired or wireless network they
are connected to without typing in a root password. This might sound
insecure at first but the truth is anyone physically at the computer has
the power to do much more harmful things such as simply unplugging from
the network. Restricting what can be changed through security policy and
methods exported by the NetworkManager daemon mitigates the risk. As with
anything security related, using the
at_console rule to allow access to root
functionality should be evaluated carefully on a case by case basis.
Here is a complete listing of allow and deny rules:
send_interface="interface_name"
send_member="method_or_signal_name"
send_error="error_name"
send_destination="service_name"
send_type="method_call" | "method_return" | "signal" | "error"
send_path="/path/name"
receive_interface="interface_name"
receive_member="method_or_signal_name"
receive_error="error_name"
receive_sender="service_name"
receive_type="method_call" | "method_return" | "signal" | "error"
receive_path="/path/name"
send_requested_reply="true" | "false"
receive_requested_reply="true" | "false"
eavesdrop="true" | "false"
own="servicename"
user="username"
group="groupname"
at_console="true"|"false"
Even more security with a little help from a friend
In some instances the built-in security policies are not enough. This is why SELinux security contexts have been integrated into D-BUS. What SELinux brings to the table is the ability to restrict access to services by specific applications. For instance, we could add an SELinux policy to say that only the NetworkManagerNotification process can send messages to the NetworkManager service. Suppose we wanted to implement this. We must first associate the the NetworkManager service to an SELinux context. This is done in the D-BUS policy file:
<selinux>
<associate own="org.freedesktop.NetworkManager" context="system_u:object_r:dbus_networkmanager_service_t"/>
</selinux>
You would then add SELinux rules to match up NetworkManagerNotification's
context to the context we just associated with the NetworkManager service.
More information about SELinux and D-BUS can be found in the
dbus-daemon-1 man page in the D-BUS CVS
module.
A conduit for making things just work
While D-BUS itself is just a generic IPC system, what makes it exciting are the things it is being used for today. One of the most exciting areas being exploited with D-BUS is hardware discovery and management. D-BUS allows us to unify the world of hardware management tools by allowing them to talk with each other and get information from a single ease to use source. By unifying the hardware layer we are able to deliver a much better experience to the user. The goal is to make hardware "just work" instead of making the user work to use their hardware.
One barrier to this that currently exists is the system/user barrier. This barrier exists for security reasons and was conceived at a time when most people were using shared systems and direct access to the system could be disastrous for the other users. In today's world, more and more people own their own computers. One of the ways to solve this problem was to prompt the user for the root password whenever a program needed access to the system. This proves to be tedious for the user and potentially a security risk as is suffers from being vulnerable to spoofing attacks or someone looking over a user's shoulder. With the new approach, D-BUS is used to expose carefully selected system functionality to the user. The built-in security of D-BUS takes over for the traditional Unix permissions. Unlike with password prompts, if a vulnerability is exploited with the D-BUS service only a subset of the system is exposed, which can be further limited by careful use of SELinux policies. With the password prompt, once an attacker is able to obtain root they have a run of the system. The less times a user has to enter the root password, the better. Another benefit of the user not having to use password dialogs is that to the user the system seems to just work where previously it needed user input.
Today there are a handful of applications in Fedora which utilize D-BUS to realize the Just Works design philosophy. As areas of need are identified more applications will be written or modified to utilize D-BUS and help make Linux easier to use.
HAL is the glue of the hardware layer. It is the single point where D-BUS aware applications can get information about hardware that exists on the computer. HAL knows when hardware has been added or removed and can gather information about the device from the kernel and other sources. It can also fire off scripts and send D-BUS signals whenever a change happens to the hardware of the system. (For more information about HAL, read the Desktop and hardware configuration article in this issue of Red Hat Magazine.)
For configuring printers in Fedora this is
cups-config-daemon. It works in
conjunction with the printer dialog in
eggcups. When HAL detects a printer has
been added, it calls a script to try and automatically configure the
printer. If the printer can not be detected the
GetUserDriver method is invoked on the
/com/redhat/PrintDriverSelection object
running as a service in eggcups. The
eggcups code then looks to see if the
user had previously configured the printer driver. If it has,
cups-config-daemon is notified via a
D-BUS call and the printer is configured. If not, a dialog is shown to
the user so that they can select a printer that most closely matches the
make and model of their printer. Once the user has selected a printer,
the users choice is stored in gconf and
cups-config-daemon is notified. The
reason for storing printer driver configuration in the user session as
opposed to the system is to accommodate systems with read only roots such
as live CDs or the Stateless Linux project. Ideally the printer will
always be auto-configured and the user will never have to see the driver
dialog.
The gnome-volume-manager daemon is a
policy daemon that runs in the session and whose sole purpose in life is
to detect when media is added that the user can use. Such media include
USB thumb drives, cameras, flash cards, blank CD-Rs, and audio CDs.
Based on user configured policy, certain actions are taken depending on the
type of media. For mass storage devices such as thumb drives, the media
is mounted. Blank CD-Rs pop up the Nautilus CD burner, cameras invoke a
photo viewing application, and audio CDs start up the CD player. It does
this by watching for device added and device removed D-BUS signals from
HAL and invoking policy code if a device which it cares about changes
state.
NetworkManager is able to keep track of all network connections and automatically change networks based on link status. For instance, if HAL detects that the link to the wired network has gone down it will send a D-BUS signal that the property has changed on the device. NetworkManager will see this and ask HAL through D-BUS if there are any other devices that have a link. If so it will switch the network connection to use that device. Other applications can even use NetworkManager's D-BUS API to get information on devices and link status or even control those devices with ease. For more information about NetworkManager, read the NetworkManager article in this month's issue.
There are many other application that need to be written to get to the dream of having hardware just working. These are first generation applications that will only get better and serve as a template as we move into other areas in need of the same treatment. What is nice is we have proven it can be done, and with D-BUS the user experience of Linux can be improved in leaps and bounds.
A fresh new view on how applications are designed
D-BUS has given us a fresh new view on how applications can be designed. No longer are we constrained by islands of functionality. Common information can be placed in a D-BUS service that acts as a single definitive source, as we have seen with HAL, instead of application trying and mostly failing to gather that information on their own. We have also seen processes reach across the system/session barrier to make configuring hardware a breeze. We may even see applications in the future that are designed not as a single monolithic process but as a series of smaller D-BUS services that work together to form a larger whole.
Another area that is being researched as a use for D-BUS is security through process segregation. Headed up by Colin Walters, the imsep project aims to kill a whole class of security exploits, and they are using D-BUS to accomplish it. Image loaders are a complex mess of code. More than once a security alert has gone out over flaws in the way code such as that found in Mozilla and gtk+ loads images. In the case of Mozilla, images are loaded off the Internet, causing concerns for remote exploits that are able to take over a victim's computer simply by downloading an image off the Internet. While this attack vector is pretty hard to accomplish, imsep hopes to mitigating the risk even lower by locating the image loaders in a separate caged process that can decode images and send them raw to the applications over D-BUS. By separating out high risk code into their own processes, these bits of code can be further locked down using SELinux policy and other security measures such as running as an unprivileged user. Even if the code could be exploited, there isn't much it could do because it would be locked away from the rest of the application and the system. Though this code is not ready for mainstream use yet, it shows the potential for more secure designs using D-BUS. You can read more about imsep on the project's home page.
Integration is the name of the game
D-BUS integrates the system from the kernel up to the desktop. For a server system, segregation of the different levels made sense. It was the easy thing to do and server roles are pretty static and well defined for the most part. Desktops are different. Because the users of desktop systems are so diverse the system needs to be dynamic to serve the changing needs of its users. One minute a piece of hardware may exist, and the next the user might decide to pull it out.
While it was not feasible to embed D-BUS directly into the kernel, integrating D-BUS and the kernel has become a top priority for some. For this Robert Love came up with the kobject patch which is a simple event layer in the kernel that broadcasts over a netlink socket. Kay Sievers has a number of projects in relation to this including the kernel event system to D-BUS bridge.
By integrating the different layers, we will be able to have the whole system act as one unit and adapt to the relatively chaotic environment that desktop users tend to create on their computers. In theory all applications on the system should utilize D-BUS in some way. I can see D-BUS being used to track the running state of all the servers on a computer. If one goes down a service can automatically restart it or notify the user through the use of a notification service such as the one being developed by Mike Hern and Christian Hammond. These things can not happen unless applications are integrated with D-BUS. Integration is one of the things that will really set Linux desktops apart from other offering. Because of the nature of open source, the ability for all applications to be integrated through D-BUS in some significant way should be fairly easy, making the desktop and Linux in general much more useful. Applications no longer have to be an island unto themselves.
Because of the nature of open source, the ability for all applications to be integrated through D-BUS in some significant way should be fairly easy, making the desktop and Linux in general much more useful.
Problems we face
There are a number of problem we face when embracing D-BUS. There are problems with integration in that it is a huge undertaking and involves many different groups thinking differently about how they design their applications. Political problems have already arisen where some projects are taking a wait and see approach before embrace the use of D-BUS. Some resistance comes from those who think that D-BUS leads us away from how Unix has worked in the past. For D-BUS to become successful we need a critical mass of projects using it. Once that happens more and more projects will start to find it useful and integrate it.
Another huge problem with any IPC mechanism is keeping APIs standard. D-BUS is useless if projects publish non-compatible APIs every time they do a release since the sole purpose of D-BUS is to enable communication between different applications.
All of these are important problems but they are by no means unsurmountable. Integration has already started and many groups are looking at how they can use D-BUS in their project. D-BUS was actually created to bridge one of the biggest political hurdles that effect the Linux desktop today. D-BUS was designed with both the GNOME and KDE communities in mind, and both groups seem to be putting down their differences and embracing D-BUS as evidenced by bindings for both GNOME's glib base library and KDE's Qt base library. Because of this and the fact that many distributions are embracing D-BUS, critical mass can't be that far behind. And, as far as the API is concerned, there may be problems but it shouldn't be any worse than the problems faced by traditional shared libraries.
The future of D-BUS
1.0 is coming soon. When that happens D-BUS's own APIs will solidify. While not much of the API is expected to change there will be some changes needed to reflect the change in how we handle types and type signatures. It is now left up to application designers to figure out what the future of D-BUS has in store. D-BUS should become just another boring layer underneath the rest of the system. The real interesting parts should be the layers above it. That is where the innovation is going to happen. D-BUS will just be one of the transports to get us there.
Conclusion
You the reader should be using D-BUS in your applications today. Or, if you are not a programmer but know one, you should send them this article to read. D-BUS is an enabling technology. By itself it is useless, but integrated into applications the possibilities are endless. D-BUS helps break down the barriers and do things that were previously impossible or hard to do in Linux and it helps us do those things securely. The resources are there and the benefits are obvious. It is time to get on D-BUS.
Further reading
- D-BUS project page — The project page for all things D-BUS. You will find the specification, API docs and a tutorial here.
- Connect desktop apps using D-BUS — An article by Ross Burton for the IBM developerWorks website. A nice primer on how to use D-BUS.
- SELinux project page — The project page for SE-Linux setup by the National Security Agency. SE-Linux is a core component of D-BUS's security architecture.




