Thursday, September 20, 2007

Policy, Mechanism and Time zones

In my last post I looked at D-Bus system bus activation and provided a step-by-step guide on how to use this. In this installment we’re going to look at a specific application of system bus activation; namely how it can be used from a desktop application to do a privileged operation: setting the timezone. This example will also feature usage of PolicyKit for lock down.


When dealing with programs that needs to do privileged operations, the first thing that one needs to do is to separate the mechanism (the piece of code actually doing the privileged bits) into a separate process from the rest of the program. The main program will then simply launch a small privileged helper whenever something privileged needs to happen. This is a good idea because it’s a lot easier to review a tiny privileged helper with minimal dependencies rather than a huge program that pulls in things like GTK+, Python, image loaders and what not. Typically, the privileged helper is written in a way such that it trusts no-one; it verifies all the incoming parameters and also checks whether the program that calls it should be allowed to do so. The latter part is where PolicyKit comes in - PolicyKit is an application-level toolkit that allows a mechanism to ask “is $USER allowed to do $ACTION?”. As such, PolicyKit comes with a set of data structures to help model these constructs.


Anyway, enough boring theory; the user experience we want is that the user can click on his predefined list of time zones to set it; something like this

modified intlclock

If the user is not privileged to do this action, we may show a dialog like this

stock PolicyKit-gnome dialog

that may (or may not) feature buttons to make the system remember that setting the time zone is OK. Such that the system won’t ask for authentication in the future. In other words, this is a one-time-pain dialog.


Let’s go through the code and see how all this works. First, we need to write a mechanism. This will need to run as uid 0 (e.g. root) and we choose D-Bus as the interface for using the mechanism. We choose a unique name for the service, org.gnome.ClockApplet.Mechanism and since we’d like to write it in C using dbus-glib, we need to write some XML to define the objects and interfaces that this service will expose. This is defined in this file. As evident, this service exposes a single object, /, that exposes a single interface org.gnome.ClockApplet.Mechanism that currently exposes a single method SetTimezone(string zonefile) where the argument to that function is a path to what time zone we want to use. The mechanism itself consists of two C files, available here and here and a single C header file, available here.


Then, exactly as in the last post we need a D-Bus configuration file and a D-Bus service file. There’s also a cheesy Makefile to tie it all together.


Now, with this mechanism in place, we can poke it via D-Bus

$ dbus-send --system --print-reply --dest=org.gnome.ClockApplet.Mechanism / org.gnome.ClockApplet.Mechanism.SetTimezone string:/usr/share/zoneinfo/Europe/Copenhagen
method return sender=:1.346 -> dest=:1.345 reply_serial=2

The usage of PolicyKit deserves some explanation. First of all, as stated in the docs, we need to declare one or more actions for our mechanism. As we only export a single action right now (setting the time zone), we declare only that one action via the PolicyKit .policy file here. When we extend the mechanism to e.g. provide functionality to set the time as well (via e.g. a SetTime(int64 secs_since_epoch) method) we can declare an action org.gnome.clockapplet.mechanism.settime in addition to our org.gnome.clockapplet.mechanism.settimezone one.


Now, whenever someone calls into the mechanism, we simply use libpolkit to query whether the caller is allowed to do the specific action:

sender = dbus_g_method_get_sender (context);
pk_caller = polkit_caller_new_from_dbus_name (system_bus_connection, sender, &dbus_error);
pk_action = polkit_action_new ();
polkit_action_set_action_id (pk_action, "org.gnome.clockapplet.mechanism.settimezone");
pk_result = polkit_context_can_caller_do_action (pk_context, pk_action, pk_caller);
polkit_caller_unref (pk_caller);
polkit_action_unref (pk_action);
if (pk_result != POLKIT_RESULT_YES) { /* bail out */ }

The system administrator can control, using the /etc/PolicyKit/PolicyKit.conf configuration file, exactly what users are allowed to do this and whether they are allowed to keep the privilege to do the action on a forever- or per-session basis. This shouldn’t be necessary since it’s possible to specify the default result for a given action. Distributors can tweak the .policy as they see fit; for example consumer-oriented distributions might want to patch this to make the defaults always be “yes” (to avoid the auth dialog entirely) and workstation-oriented distributions might want the defaults to be “auth_admin” (to require the system administrator password and not give a chance to remember the privilege). Finally, sites can override this using the system-wide configuration file, e.g. if I’m a huge site I can distribute a PolicyKit.conf file that allows certain users to always do an action, certain other users never to do an action, and finally a third set of users for whom I want them to enter their own (or the root) password. Again, see the /etc/PolicyKit/PolicyKit.conf configuration file for details.


The screenshots above show integration with the intlclock applet; that’s thanks to Matthias Clasen. I simply handed Matthias the mechanism code including a simple GTK demo application available here. This application simply attempts to call into the mechanism and if the mechanism throws the org.gnome.ClockApplet.Mechanism.NotPrivileged exception it uses PolicyKit-gnome (via the session bus) to prompt the user for authentication if applicable.


The PolicyKit stuff is mostly done; at least the plumbing is there. What I like to see is some more GNOME-ish porcelain to make this stuff even easier to use. First, it’s simply way too complicated to write dbus-glib D-Bus servers. There’s just way too much code; compare to the Python server in the last post. Second, I’d like to provide a small library with a subclassed GtkButton, e.g. PolicyKitGtkButton such that all the magic happens there and it shows e.g. a lock only if authentication will be needed. I’m also planning to do a song and dance at the Boston Summit about this. The list of users of PolicyKit right now includes only HAL. However, PackageKit, dconf and virt-manager are all in the process of picking it up. I’m also hoping NetworkManager and things like gnome-system-monitor will pick it up (for the process killing bits instead of falling back to running the entire UI as uid 0 just for this). With time, and not too much time, I’m hoping for PolicyKit to be a blessed dependency in GNOME and banish the idea of su/sudo wrappers to enable running X11 applications as uid 0.

Wednesday, August 1, 2007

System Bus Activation hits Fedora Rawhide

.. well, almost. Anyway, you can get packages here or wait until Rawhide opens again (it’s currently frozen for F8t1). Credit goes to Richard for finishing this work and getting it past Havoc. This is a really huge thing; it opens up a lot of possibilities for better desktop/OS integration.



Lots of pretty colors
Lots of pretty colors


To actually test the packages I wrote a simple test program and thought it might be useful to share it. First, you need a program that claims a name on the system bus. I just copied the one from the dbus-python repository and modified it slightly. You can see it here.


Second, as with any service on the system message bus (as opposed to the session bus which has different security characteristics) you need a file in /etc/dbus-1/system.d. Mine is named dk.fubar.Test.conf (but note that any unique file name ending in .conf will do) and is pretty much run-of-the-mill standard stuff and shouldn’t be a surprise if you’re familiar with services on the system bus. It looks like this.


Finally, for system bus activation to work you simply need to put a service file in /usr/share/dbus-1/system-services. Mine is named dk.fubar.Test.service (again, any unique name ending in .service will do) and looks like this:

[D-BUS Service]
Name=dk.fubar.Test
Exec=/usr/sbin/dbus-sysbus-test.py
User=root

and that’s it! Provided you installed everything correctly (there’s a cheesy Makefile to do this) things should Just Work(tm) and the following command should print

$ dbus-send --system --print-reply --dest=dk.fubar.Test /SomeObject dk.fubar.Test.SampleInterface.HelloWorld string:foo
method return sender=:1.517 -> dest=:1.516 reply_serial=2
array [
string "Hello"
string " from example-service.py"
string "with unique name"
string ":1.517"
]

If your service is capable of operating correctly when running as an unprivileged system user (e.g. ftp or whatever) instead of root (think least privilege), simply change the user mentioned in both the .service and .conf files.

Thursday, July 19, 2007

No more polling

I just committed code to hal to take advantage of asynchronous change notification events originating from SATA AN capable drives. This means we can avoid polling the drive and this should result in fewer wakeups in libata. This also opens the opportunity for the drive itself to go into a deeper sleep state when it’s not used. So all in all this should improve laptop battery life. I haven’t tried this on a laptop just yet, but when I find a suitable one I’m sure PowerTOP will tell me.



Mural at the back of 1369
I took this while testing this GPS receiver. Click to see where to get good coffee.


Credit goes to Kristen Carlson Accardi from Intel. She did the kernel bits, sent me a SATA AN capable drive and pointed me in the right direction. To try this out, you will need a recent kernel and also some patches not yet in Linus’ tree. See RH #204969 for details. I’m hoping this will make it into Fedora 8; the hal bits will for sure; for the kernel bits I suppose asking davej is in order.

Wednesday, June 20, 2007

PolicyKit release

Late last night I finally made a PolicyKit release. It’s almost ready for prime time; wait a month for 0.4 to get out and I should be able to maintain a stable API.



PolicyKit
PolicyKit in action


With Richard’s great work on D-Bus system bus activation it looks like we’re soon going to have nice upstream frameworks for enabling the desktop to do privileged operations in a hopefully sane way. Instead of having each and every distribution on the planet write their own configuration tools. I, for one, really wants to see some effort of merging such things into upstream GNOME and KDE as far as possible.

Tuesday, June 5, 2007

Interwebs

Normally I’m not opposed to what our new web overlords are serving us; you know; social networks and the ability to see what past and present, uh, peers are up to… but sometimes it’s just TMI - Maybe I just need to use the Interwebs less :-)

Monday, May 7, 2007

i’m in ur RAID, striping ur disks all the way to CA

Recently I acquired a pair of 500GB USB2 hard disks that I use in a RAID-1 configuration (on two different host controllers!); you know, to store my photos and other important, uh, stuff. I had some spare time this weekend to look at fd.o #6426 so I wrote a small patch to teach HAL about Linux software RAID.



gnome-device-manager showing Software RAID drive
RAID rebuilding


I also whipped up patch to gnome-device-manager such as to show the new properties introduced including whether an array is running in degraded mode or is being rebuilt. It’s pretty spiffy.


All that this code is doing right now is basically just listening to kernel events (via udev and priority data on /proc/mdstat) and then representing the RAID arrays as HAL drives and volumes. It’s spiffy because the RAID drive inherits things like storage.hotpluggable from the physical components (e.g. the two USB hard disks) so in my case the RAID array simply appears in Nautilus and is totally mountable just like a regular external drive. Works out of the box. Desktop integration++. However, we can do a bit better so for GNOME 2.20 I’ll be writing some patches to gnome-vfs and gvfs. You know, to use the new HAL properties to choose some helpful icons and icon captions.


Going forward, there needs to be some way of assembling and disassembling RAID arrays; hot-adding components to degraded arrays and so on and so on. Probably neither Nautilus nor gnome-device-manager is the right approach here. And there will probably be some sort of auto-assembly happening at the system-wide level anyway, need to sort that out with Kay (the udev maintainer) and also talk to various distro maintainers too. It’s also probably also time to revive my never properly announced GNOME Disk Utility project. Actually, that’s one reason that I split the Device Manager into a shell and library component; right now the shell is around 1200 lines (compared to 4000+ for the library) and there’s no reason that the Disk Utility shell would be a lot bigger. Plus it’s always awesome to put pretty UI on top of useful infrastructure.


Tomorrow I’m leaving for The Golden State to go the Red Hat summit, then hang out with Kay Sievers and finish off the west-coast invasion with FreedomHEC. The next two weeks are going to be busy.

Saturday, April 28, 2007

Battery Recall^WExchange

Just found, via the interwebs, that the battery in my 15″ Macbook Pro was recalled^Weligible for exchange almost a year ago although not for safety risks, merely because “… batteries supplied to Apple do not meet our high standards for battery performance.” [sic]. So that’s something. Anyway, since this is useful information, I wanted to add information to hal-info such that other Macbook Pro users would benefit as well. By getting spammed with a popup like this




Useful feature in g-p-m


But as it turns out this data is not easily available



$ cat /proc/acpi/battery/BAT0/info
present: yes
design capacity: 55000 mWh
last full capacity: 47150 mWh
battery technology: rechargeable
design voltage: 10800 mV
design capacity warning: 250 mWh
design capacity low: 100 mWh
capacity granularity 1: 10 mWh
capacity granularity 2: 10 mWh
model number: ASMB012
serial number:
battery type: LION012
OEM info: SMPN012


meaning it’s hard to match on anything sensible from the fdi file. Maybe this is because it’s a Smart Battery? FWIW, I can see that the sbs driver is loaded. Lazyweb, please help :-) - as comments on my blog are busted, please provide answers personally to me or, preferably, the hal list (requires subscription).


Btw, I couldn’t find this information by poking around in Mac OS X either… but it must be there; I mean, normal non-smart batteries record make, model and serial numbers just fine via ACPI. That’s what we use to tag other recalled battery units. So I’m sure it’s possible to get at. And if Apple wanted, they could easily have similar mechanisms for displaying notifications similar to the ones we have in GNOME. But I can understand it would hurt their bottom line. I guess.. this is one interesting aspect of getting your OS from the same vendor as where you get your hardware.


Anyway, I filled out the form and a new battery is on it’s way. I guess, uh, thanks Apple. Just wish you had notified me earlier and I wouldn’t have to find out this way ;-) .


Update: I suppose this isn’t technically a Product Recall; Apple specifically uses the word Exchange instead. I guess, from a legal point of view at least, there’s a difference. To me, as a consumer, it’s doesn’t make huge difference however… hmm.. maybe we need to add a new property info.is_eligible_for_exchange to the HAL spec to avoid using the word “recall” at all in such situations. I mean, to, uh, cover our collective asses from angry hardware vendors.