[systemd-commits] 6 commits - .gitignore Makefile-man.am Makefile.am TODO man/systemd-socket-proxyd.xml src/core src/libsystemd-bus src/login src/machine src/shared src/systemd src/test

Lennart Poettering lennart at kemper.freedesktop.org
Thu Nov 28 09:47:59 PST 2013


 .gitignore                            |    1 
 Makefile-man.am                       |    2 
 Makefile.am                           |   31 -
 TODO                                  |  277 +++--------
 man/systemd-socket-proxyd.xml         |   96 +---
 src/core/dbus-manager.c               |    8 
 src/core/dbus.c                       |   16 
 src/core/selinux-access.c             |  219 +--------
 src/core/service.c                    |    5 
 src/libsystemd-bus/bus-control.c      |  154 ++++--
 src/libsystemd-bus/bus-convenience.c  |   30 +
 src/libsystemd-bus/bus-creds.c        |  796 ++++++++++++++++++++++++++++++++++
 src/libsystemd-bus/bus-creds.h        |   67 ++
 src/libsystemd-bus/bus-dump.c         |  227 ++++++---
 src/libsystemd-bus/bus-dump.h         |    2 
 src/libsystemd-bus/bus-internal.h     |    2 
 src/libsystemd-bus/bus-kernel.c       |   61 +-
 src/libsystemd-bus/bus-message.c      |  234 ---------
 src/libsystemd-bus/bus-message.h      |   30 -
 src/libsystemd-bus/bus-util.c         |   31 -
 src/libsystemd-bus/bus-util.h         |    2 
 src/libsystemd-bus/busctl.c           |   44 +
 src/libsystemd-bus/libsystemd-bus.sym |   76 +--
 src/libsystemd-bus/sd-bus.c           |  120 ++---
 src/libsystemd-bus/test-bus-chat.c    |    4 
 src/libsystemd-bus/test-bus-creds.c   |   46 +
 src/libsystemd-bus/test-bus-kernel.c  |   18 
 src/login/logind-dbus.c               |   47 +-
 src/login/logind-seat-dbus.c          |    9 
 src/login/logind-session-dbus.c       |   23 
 src/login/logind-user-dbus.c          |    9 
 src/machine/machine-dbus.c            |    9 
 src/machine/machined-dbus.c           |   16 
 src/shared/audit.c                    |   57 --
 src/shared/util.c                     |   33 -
 src/systemd/sd-bus.h                  |  119 +++--
 src/test/test-strv.c                  |   27 +
 37 files changed, 1849 insertions(+), 1099 deletions(-)

New commits:
commit f38afcd0c7f558ca5bf0854b42f8c6954f8ad7f3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Nov 28 18:42:00 2013 +0100

    clean up TODO

diff --git a/TODO b/TODO
index 6a130ac..127994a 100644
--- a/TODO
+++ b/TODO
@@ -4,8 +4,6 @@ Bugfixes:
     $ systemctl enable getty at .service
     ln -s '/usr/lib/systemd/system/getty at .service' '/etc/systemd/system/getty.target.wants/getty at .service'
 
-* check systemd-tmpfiles for selinux context hookup for mknod(), symlink() and similar
-
 * swap units that are activated by one name but shown in the kernel under another are semi-broken
 
 * Dangling symlinks of .automount unit files in .wants/ directories, set up
@@ -21,101 +19,60 @@ Bugfixes:
 
   Cannot add dependency job for unit display-manager.service, ignoring: Unit display-manager.service failed to load: No such file or directory. See system logs and 'systemctl status display-manager.service' for details.
 
-Fedora 20:
-
-* external: ps should gain colums for slice
+External:
 
-* localed:
-  - localectl: support new converted x11→console keymaps
+* ps should gain colums for slice
 
-* when installing fedora with yum --installroot /var/run is a directory, not a symlink
+* Fedora: when installing fedora with yum --installroot /var/run is a directory, not a symlink
    https://bugzilla.redhat.com/show_bug.cgi?id=975864
 
-CGroup Rework Completion:
-
-* implement system-wide DefaultCPUAccounting=1 switch (and similar for blockio, memory?)
-
-* implement per-slice CPUFairScheduling=1 switch
-
-* handle jointly mounted controllers correctly
+* Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros.
 
-* introduce high-level settings for RT budget, swappiness
+* Fedora: post FPC ticket to move add %tmpfiles_create to the packaging guidelines
 
 Features:
 
-* general: get rid of readdir_r/dirent_storage stuff, it's unnecessary on Linux
+* cgroups:
+  - implement system-wide DefaultCPUAccounting=1 switch (and similar for blockio, memory?)
+  - implement per-slice CPUFairScheduling=1 switch
+  - handle jointly mounted controllers correctly
+  - introduce high-level settings for RT budget, swappiness
+  - how to reset dynamically changed unit cgroup attributes sanely?
+  - when reloading configuration, apply new cgroup configuration
+  - when recursively showing the cgroup hierarchy, optionally also show
+    the hierarchies of child processes
 
-* add API to clone sd_bus_message objects
+* transient units:
+  - allow creating auxiliary units with the same call
+  - add field to transient units that indicate whether systemd or somebody else saves/restores its settings, for integration with libvirt
+  - ensure scope units may be started only a single time
 
-* sd-bus: synthesized messages should get serial number (uint32_t) -1
+* switch to SipHash for hashmaps/sets?
 
-* sd-event: allow multiple signal handlers per signal
+* general: get rid of readdir_r/dirent_storage stuff, it's unnecessary on Linux
 
 * when we detect low battery and no AC on boot, show pretty splash and refuse boot
 
 * move libasyncns into systemd as libsystemd-asyncns
 
-* calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1
-
-* sd-bus: when triggering property change events, allow a NULL strv indicate that all properties listed as such are send out as changed
-
-* sd-bus: enforce signatures on response messages
-
-* sd-bus: see if we can drop more message validation on the sending side
-
-* sd-bus: introduce sd_bus_creds object and attach it to messages as well as allow querying it for names
-
-* sd-bus: support "const" properties as flag
-
-* sd-event: when a handler returns an error, just turn off its event
-  source, but do not return anything up to the event loop
-  caller. Instead add parameter to sd_event_request_quit() to take
-  retval. This way errors rippling upwards are the option, not the
-  default
-
-* sd-event: child pid handling: first invoke waitid(WNOHANG) and call event handler, only afterwards reap the process
-
-* sd-event: native support for watchdog stuff
-
-* machined, localed: when we try to kill an empty cgroup, generate an ESRCH call over the bus
-
-* sd-bus: SD_BUS_COMMENT() macro for inclusion in vtables, syntax inspired by gdbus
+* machined, localed: when we try to kill an empty cgroup, generate an ESRCH error over the bus
 
 * libsystemd-journal, libsystemd-login, libudev: add calls to easily attach these objects to sd-event event loops
 
 * be more careful what we export on the bus as (usec_t) 0 and (usec_t) -1
 
-* add field to transient units that indicate whether systemd or somebody else saves/restores its settings, for integration with libvirt
-
-* systemctl: rework wait filter to not require match callback
-
 * unify dispatch table in systemctl_main() and friends
 
-* bus: access policy as vtable flag
-
-* journalctl: support -M to read journal of containers and determine journal directory from root directory of container
-
-* tmpfiles: to make sure we don't delete unpacked tarballs with old timestamps right-away never delete stuff that is inside a directory with a new mtime
-
-* "systemctl mask" should find all names by which a unit is accessible
-  (i.e. by scanning for symlinks to it) and link them all to /dev/null
-
 * Automatically configure swap partition to use for hibernation by looking for largest swap partition on the root disk?
 
 * remove NSS usage from PID 1 (notably the specifiers)
 
-* socket-proxyd:
-  - Support multiple inherited sockets mapped to different remote hosts
-  - Use a nonblocking alternative to getaddrinfo
-
-* "systemctl cat" or "systemctl view" command or or so, that cats the backing unit file of a service, plus its drop-ins and shows them in a pager
+* socket-proxyd:Use a nonblocking alternative to getaddrinfo
 
 * rfkill,backlight: we probably should run the load tools inside of the udev rules so that the state is properly initialized by the time other software sees it
 
 * Add a new Distribute=$NUMBER key to socket units that makes use of SO_REUSEPORT to distribute network traffic on $NUMBER instances
 
-* tmpfiles: when applying ownership to /run/log/journal, also do this for the journal fails contained in it
-
 * we probably should replace the left-over uses of strv_append() and replace them by strv_push() or strv_extend()
 
 * move config_parse_path_strv() out of conf-parser.c
@@ -132,95 +89,38 @@ Features:
 
 * refuse boot if /etc/os-release is missing or /etc/machine-id cannot be set up
 
-* ensure scope units may be started only a single time
-
-* better error message if you run systemctl without systemd running
-
-* systemctl status output should should include list of triggering units and their status
-
-* for transient units, instead of writing out drop-ins for all properties consider serializing them in the normal serialization stream
-
-* logind: when logging out, remove user-owned sysv and posix IPC objects
-
-* session scopes/user unit: add RequiresMountsFor for the home directory of the user
-
-* add a man page containing packaging guidelines and recommending usage of things like Documentation=, PrivateTmp=, PrivateNetwork= and ReadOnlyDirectories=/etc /usr.
-
-* journalctl: instead --after-cursor= maybe have a --cursor=XYZ+1 syntax?
-
 * given that logind/machined now let PID 1 do all nasty work, we can
   probably reduce the capability set they retain substantially.
 
 * btrfs raid assembly: some .device jobs stay stuck in the queue
 
-* Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros.
-
-* Fedora: post FPC ticket to move add %tmpfiles_create to the packaging guidelines
-
 * make sure gdm doesn't use multi-user-x but the new default X configuration file, and then remove multi-user-x from systemd
 
-* when parsing calendar timestamps support the UTC timezone (even if we won't support arbitrary timezone specs, support UTC itself certainly makes sense), also support syntaxes such as +0200
-
-* when a kernel driver logs in a tight loop, we should ratelimit that too.
-
-* "systemctl disable" of a unit instance removes all symlinks, but should
-  only remove the instance symlink (systemctl disable of a template
-  unit however should remove them all).
-
-* journald: optionally, log debug messages to /run but everything else to /var
-
-* systemctl list-unit-files should list generated files (and probably with a new state "generated" for them, or so)
-
-* journald: when we drop syslog messages because the syslog socket is
-  full, make sure to write how many messages are lost as first thing
-  to syslog when it works again.
-
 * man: the documentation of Restart= currently is very misleading and suggests the tools from ExecStartPre= might get restarted.
 
 * load .d/*.conf dropins for device units
 
-* service_coldplug() appears to reinstall the wrong stop timeout watch.
-
-* transient units: allow creating auxiliary units with the same call
-
-* how to reset dynamically changed attributes sanely?
-
-* when reloading configuration, apply new cgroup configuration
-
-* journald: make sure ratelimit is actually really per-service with the new cgroup changes
-
 * gparted needs to disable auto-activation of mount units somehow, or
   maybe we should stop doing auto-activation of this after boot
   entirely. https://bugzilla.gnome.org/show_bug.cgi?id=701676
   Maybe take a BSD lock at the disk device node and teach udev to
   check for that and suppress event handling.
 
-* when recursively showing the cgroup hierarchy, optionally also show
-  the hierarchies of child processes
-
 * document logic of auto/noauto and fail/nofail in fstab in systemd.mount or systemd-fstab-generator man page
 
 * something pulls in pcre as shared object dependency into our daemons such as hostnamed.
 
-* document systemd-journal-flush.service properly
-
-* change systemd-journal-flush into a service that stays around during
-  boot, and causes the journal to be moved back to /run on shutdown,
-  so that we don't keep /var busy. This needs to happen synchronously,
-  hence doing this via signals is not going to work.
-
 * allow implementation of InaccessibleDirectories=/ plus
   ReadOnlyDirectories=... for whitelisting files for a service.
 
 * libsystemd-bus:
   - default policy (allow uid == 0 and our own uid)
+  - access policy as vtable flag
   - enforce alignment of pointers passed in
   - when kdbus doesn't take our message without memfds, try again with memfds
   - implement translator service
-  - port systemd to new library
   - implement busname unit type in systemd
   - move to gvariant
-  - merge busctl into systemctl or so?
   - synthesize sd_bus_message objects from kernel messages
   - properly implement name registry ioctls for kdbus
   - implement monitor logic
@@ -228,15 +128,27 @@ Features:
   - longer term:
     * priority queues
     * priority inheritance
+  - synthesized messages should get serial number (uint32_t) -1
+  - when triggering property change events, allow a NULL strv indicate that all properties listed as such are send out as changed
+  - enforce signatures on response messages
+  - see if we can drop more message validation on the sending side
+  - support "const" properties as flag
+  - add API to clone sd_bus_message objects
+  - SD_BUS_COMMENT() macro for inclusion in vtables, syntax inspired by gdbus
+
+* sd-event
+  - allow multiple signal handlers per signal
+  - when a handler returns an error, just turn off its event source,
+    but do not return anything up to the event loop caller. Instead
+    add parameter to sd_event_request_quit() to take retval. This way
+    errors rippling upwards are the option, not the default
+  - child pid handling: first invoke waitid(WNOHANG) and call event handler, only afterwards reap the process
+  - native support for watchdog stuff
 
 * in the final killing spree, detect processes from the root directory, and
   complain loudly if they have argv[0][0] == '@' set.
   https://bugzilla.redhat.com/show_bug.cgi?id=961044
 
-* add an option to nspawn that uses seccomp to make socket(AF_NETLINK,
-  SOCK_RAW, NETLINK_AUDIT) fail the the appropriate error code that
-  makes the audit userspace to think auditing is not available in the
-  kernel.
 
 * Introduce a way how we can kill the main process of a service with KillSignal, but all processes with SIGKILL later on
   https://bugzilla.redhat.com/show_bug.cgi?id=952634
@@ -248,11 +160,6 @@ Features:
 * dbus: when a unit failed to load (i.e. is in UNIT_ERROR state), we
   should be able to safely try another attempt when the bus call LoadUnit() is invoked.
 
-* if pam_systemd is invoked by su from a process that is outside of a
-  any session we should probably just become a NOP, since that's
-  usually not a real user session but just some system code that just
-  needs setuid().
-
 * add a pam module that passes the hdd passphrase into the PAM stack and then expires it, for usage by gdm auto-login.
 
 * add a pam module that on password changes updates any LUKS slot where the password matches
@@ -261,8 +168,6 @@ Features:
 
 * timedatctl, localectl: possibly make some commands work without the daemon, for chroot situations...
 
-* logind: add Suspend() bus calls which take timestamps to fix double suspend issues when somebody hits suspend and closes laptop quickly.
-
 * cgtop: make cgtop useful in a container
 
 * test/:
@@ -301,37 +206,19 @@ Features:
   installed to the ESP. Define a way how an installer can figure out
   whether a BLS compliant boot loader is installed.
 
-* man: remove .include documentation, and instead push people to use .d/*.conf
-
 * think about requeuing jobs when daemon-reload is issued? usecase:
   the initrd issues a reload after fstab from the host is accessible
   and we might want to requeue the mounts local-fs acquired through
   that automatically.
 
-* rework specifier logic so that we can distinguish OOM errors from other errors
-
 * systemd-inhibit: make taking delay locks useful: support sending SIGINT or SIGTERM on PrepareForSleep()
 
 * journal-or-kmsg is currently broken? See reverted commit 4a01181e460686d8b4a543b1dfa7f77c9e3c5ab8.
 
 * remove any syslog support from log.c -- we probably can't do this before split-off udev is gone for good
 
-* documentation: recommend to connect the timer units of a service to the service via Also= in [Install]
-
-* add a tool that lists active timer units plus their next elapse and the time the units ran last
-
-* man: document the very specific env the shutdown drop-in tools live in
-
 * shutdown logging: store to EFI var, and store to USB stick?
 
-* man: extend runlevel(8) to mention that runlevels suck, and are dead. Maybe add runlevel(7) with a note about that too
-
-* systemctl: maybe add "systemctl add-wants" or so...
-
-* man: add more examples to man pages
-
-* man: maybe sort directives in man pages, and take sections from --help and apply them to man too
-
 * write UI tool that pops up emergency messages from the journal as notification
 
 * think about window-manager-run-as-user-service problem: exit 0 → activate shutdown.target; exit != 0 → restart service
@@ -381,6 +268,13 @@ Features:
   - logind: add equivalent to sd_pid_get_owner_uid() to the D-Bus API
   - pam: when leaving a session explicitly exclude the ReleaseSession() caller process from the killing spree
   - we should probably handle SIGTERM/SIGINT to not leave dot files around, just in case
+  - when logging out, remove user-owned sysv and posix IPC objects
+  - session scopes/user unit: add RequiresMountsFor for the home directory of the user
+  - add Suspend() bus calls which take timestamps to fix double suspend issues when somebody hits suspend and closes laptop quickly.
+  - if pam_systemd is invoked by su from a process that is outside of a
+    any session we should probably just become a NOP, since that's
+    usually not a real user session but just some system code that just
+    needs setuid().
 
 * exec: when deinitializating a tty device fix the perms and group, too, not only when initializing. Set access mode/gid to 0620/tty.
 
@@ -404,7 +298,6 @@ Features:
   - journal: add a setgid "systemd-journal" utility to invoke from libsystemd-journal, which passes fds via STDOUT and does PK access
   - journactl: support negative filtering, i.e. FOOBAR!="waldo",
     and !FOOBAR for events without FOOBAR.
-  - journal: when rotating, copy over old acls/access mode
   - journal: send out marker messages every now and then, and immediately sync with fdatasync() afterwards, in order to have hourly guaranteed syncs.
   - journal-send.c, log.c: when the log socket is clogged, and we drop, count this and write a message about this when it gets unclogged again.
   - journal: find a way to allow dropping history early, based on priority, other rules
@@ -415,14 +308,24 @@ Features:
   - refuse taking lower-case variable names in sd_journal_send() and friends.
   - journald: we currently rotate only after MaxUse+MaxFilesize has been reached.
   - journal: deal nicely with byte-by-byte copied files, especially regards header
-  - journalctl: expand tabs
   - journal: store euid in journal if it differs from uid
   - journal: sanely deal with entries which are larger than the individual file size, but where the components would fit
   - Replace utmp, wtmp, btmp, and lastlog completely with journal
-  - Port upower to use the journal for historical power information used in future calculations
+  - journalctl: instead --after-cursor= maybe have a --cursor=XYZ+1 syntax?
+  - journalctl: support -M to read journal of containers and determine journal directory from root directory of container
+  - tmpfiles: when applying ownership to /run/log/journal, also do this for the journal fails contained in it
+  - when a kernel driver logs in a tight loop, we should ratelimit that too.
+  - journald: optionally, log debug messages to /run but everything else to /var
+  - journald: when we drop syslog messages because the syslog socket is
+    full, make sure to write how many messages are lost as first thing
+    to syslog when it works again.
+  - journald: make sure ratelimit is actually really per-service with the new cgroup changes
+  - change systemd-journal-flush into a service that stays around during
+    boot, and causes the journal to be moved back to /run on shutdown,
+    so that we don't keep /var busy. This needs to happen synchronously,
+    hence doing this via signals is not going to work.
 
 * document:
-  - document unit_name_mangle()
   - document that deps in [Unit] sections ignore Alias= fileds in
     [Install] units of other units, unless those units are disabled
   - man: clarify that time-sync.target is not only sysv compat but also useful otherwise. Same for similar targets
@@ -431,6 +334,14 @@ Features:
   - document the exit codes when services fail before they are exec()ed
   - document that service reload may be implemented as service reexec
   - document in wiki how to map ical recurrence events to systemd timer unit calendar specifications
+  - add a man page containing packaging guidelines and recommending usage of things like Documentation=, PrivateTmp=, PrivateNetwork= and ReadOnlyDirectories=/etc /usr.
+  - document systemd-journal-flush.service properly
+  - man: remove .include documentation, and instead push people to use .d/*.conf
+  - documentation: recommend to connect the timer units of a service to the service via Also= in [Install]
+  - man: document the very specific env the shutdown drop-in tools live in
+  - man: extend runlevel(8) to mention that runlevels suck, and are dead. Maybe add runlevel(7) with a note about that too
+  - man: add more examples to man pages
+  - man: maybe sort directives in man pages, and take sections from --help and apply them to man too
 
 * systemctl:
   - systemctl list-jobs - show dependencies
@@ -446,6 +357,20 @@ Features:
   - systemctl: "Journal has been rotated since unit was started." message is misleading
   - support "systemctl stop foobar at .service" to stop all units matching a certain template
   - Something is wrong with symlink handling of "autovt at .service" in "systemctl list-unit-files"
+  - rework wait filter to not require match callback
+  - "systemctl cat" or "systemctl view" command or or so, that cats the backing unit file of a service, plus its drop-ins and shows them in a pager
+  - better error message if you run systemctl without systemd running
+  - systemctl status output should should include list of triggering units and their status
+  - in systemctl list-timers show time trggering units ran last
+
+* unit install:
+  - "systemctl mask" should find all names by which a unit is accessible
+    (i.e. by scanning for symlinks to it) and link them all to /dev/null
+  - "systemctl disable" of a unit instance removes all symlinks, but should
+    only remove the instance symlink (systemctl disable of a template
+    unit however should remove them all).
+  - systemctl list-unit-files should list generated files (and probably with a new state "generated" for them, or so)
+  - systemctl: maybe add "systemctl add-wants" or so...
 
 * introduce ntp.service (or suchlike) as symlink that is used to arbitrate between various NTP implementations
 
@@ -457,6 +382,8 @@ Features:
     o CLOCK_REALTIME makes jumps (TFD_TIMER_CANCEL_ON_SET)
     o DST changes
   - Support 2012-02~4 as syntax for specifying the fourth to last day of the month.
+  - calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1
+  - when parsing calendar timestamps support the UTC timezone (even if we won't support arbitrary timezone specs, support UTC itself certainly makes sense), also support syntaxes such as +0200
   - Modulate timer frequency based on battery state
   - anacron-like feature
 
@@ -480,8 +407,6 @@ Features:
   logs-show.c. Alternatively: use libelfutil, which seems to be the
   better supported alternative.
 
-* figure out relation of --all and --full in the various tools
-
 * add libsystemd-password or so to query passwords during boot using the password agent logic
 
 * If we show an error about a unit (such as not showing up) and it has no Description string, then show a description string generated form the reverse of unit_name_mangle().
@@ -490,13 +415,10 @@ Features:
 * fedup: don't delete initrd on switch-root
 * fedup: generator
 
-* timedated:
-  - timedated: refuse time changes when NTP is on
+* timedated: refuse time changes when NTP is on
 
 * clean up date formatting and parsing so that all absolute/relative timestamps we format can also be parsed
 
-* introduce generic AUGMENT_PID=, AUGMENT_DEVICE= fields
-
 * on shutdown: move utmp, wall, audit logic all into PID 1 (or logind?), get rid of systemd-update-utmp-runlevel
 
 * add "provisioning" instructions to setup an empty /etc + /var
@@ -509,14 +431,10 @@ Features:
 * make repeated alt-ctrl-del presses printing a dump, or even force a reboot without
   waiting for the timeout
 
-* high level net_prio setting in execution context
-
 * hostnamed: before returning information from /etc/machine-info.conf check the modification data and reread. Similar for localed, ...
 
 * currently x-systemd.timeout is lost in the initrd, since crypttab is copied into dracut, but fstab isn't
 
-* refuse boot if /etc/machine-id is not useful (or set taint?)
-
 * nspawn:
   - nspawn: consider changing users for -u with su, so that NSS resolving works correctly
   - nspawn: implement personality changes a la linux32(8)
@@ -530,6 +448,10 @@ Features:
   - nspawn: maybe explicitly reset loginuid?
   - nspawn: make it work for dwalsh and shared /usr containers -- tmpfs mounts as command line parameters, selinux exec context
   - refuses to boot containers without /etc/machine-id (OK?), and with empty /etc/machine-id (not OK).
+  - add an option to nspawn that uses seccomp to make socket(AF_NETLINK,
+    SOCK_RAW, NETLINK_AUDIT) fail the the appropriate error code that
+    makes the audit userspace to think auditing is not available in the
+    kernel.
 
 * cryptsetup:
   - cryptsetup-generator: allow specification of passwords in crypttab itself
@@ -537,8 +459,6 @@ Features:
     https://bugs.freedesktop.org/show_bug.cgi?id=54982
   - support rd.luks.allow-discards= kernel cmdline params in cryptsetup generator
 
-* move debug shell to tty6 and make sure this doesn't break the gettys on tty6
-
 * hw watchdog: optionally try to use the preset watchdog timeout instead of always overriding it
   https://bugs.freedesktop.org/show_bug.cgi?id=54712
 
@@ -574,8 +494,6 @@ Features:
   when done. That means clients don't get a successful method reply,
   but much rather a disconnect on success.
 
-* use opterr = 0 for all getopt tools
-
 * properly handle loop back mounts via fstab, especially regards to fsck/passno
 
 * allow services with no ExecStart= but with an ExecStop=
@@ -593,8 +511,6 @@ Features:
   - syscall filter: port to libseccomp
   - system-wide seccomp filter
 
-* .device aliases need to be implemented with the "following" logic, probably.
-
 * load-fragment: when loading a unit file via a chain of symlinks
   verify that it isn't masked via any of the names traversed.
 
@@ -615,8 +531,6 @@ Features:
      - answer expire packet on pipe with AUTOFS_DEV_IOCTL_{READY,FAIL}_CMD
    - AUTOFS_DEV_IOCTL_EXPIRE_CMD returns
 
-* services which create their own subcgroups break cgroup-empty notification (needs to be fixed in the kernel)
-
 * ExecOnFailure=/usr/bin/foo
 
 * udev:
@@ -652,7 +566,9 @@ Features:
 
 * when a bus name of a service disappears from the bus make sure to queue further activation requests
 
-* tmpfiles: apply "x" on "D" too (see patch from William Douglas)
+* tmpfiles:
+  - check systemd-tmpfiles for selinux context hookup for mknod(), symlink() and similar
+  - apply "x" on "D" too (see patch from William Douglas)
 
 * for services: don't set $HOME in services unless requested
 
@@ -678,7 +594,7 @@ Features:
   when we start a service in order to avoid confusion when a user
   assumes starting a service is enough to make it accessible
 
-* support User= and Group= attributes for AF_UNIX sockets.
+* support User= and Group= attributes for AF_UNIX sockets. (difficult, requires NSS from PID 1?)
 
 * Make it possible to set the keymap independently from the font on
   the kernel cmdline. Right now setting one resets also the other.
@@ -732,8 +648,6 @@ Features:
 * dot output for --test showing the 'initial transaction'
 
 * port over to LISTEN_FDS/LISTEN_PID:
-   - rpcbind (/var/run/rpcbind.sock!) HAVEPATCH
-   - cups     HAVEPATCH
    - postfix, saslauthd
    - apache/samba
    - libvirtd (/var/run/libvirt/libvirt-sock-ro)
@@ -771,12 +685,7 @@ Features:
 External:
 
 * dbus:
-   - dbus --user
    - natively watch for dbus-*.service symlinks (PENDING)
-   - allow specification of socket mode/umask when allocating DBusServer
-   - allow disabling of fd passing when connecting a AF_UNIX connection
-   - allow disabling of UID passing for AUTH EXTERNAL
-   - always pass cred data along each message
    - teach dbus to activate all services it finds in /etc/systemd/services/org-*.service
 
 * fix alsa mixer restore to not print error when no config is stored

commit 5b12334d35eadf1f45cc3d631fd1a2e72ffaea0a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Nov 28 17:50:02 2013 +0100

    bus: add new sd_bus_creds object to encapsulate process credentials
    
    This way we can unify handling of credentials that are attached to
    messages, or can be queried for bus name owners or connection peers.
    
    This also adds the ability to extend incomplete credential information
    with data from /proc,
    
    Also, provide a convenience call that will automatically determine the
    most appropriate credential object for an incoming message, by using the
    the attached information if possible, the sending name information if
    available and otherwise the peer's credentials.

diff --git a/.gitignore b/.gitignore
index f8f6c8a..84c83a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,6 +90,7 @@
 /tags
 /test-boot-timestamp
 /test-bus-chat
+/test-bus-creds
 /test-bus-error
 /test-bus-introspect
 /test-bus-kernel
diff --git a/Makefile.am b/Makefile.am
index 47b864c..90874df 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -769,7 +769,9 @@ libsystemd_shared_la_SOURCES = \
 	src/shared/errno-list.c \
 	src/shared/errno-list.h \
 	src/shared/syscall-list.c \
-	src/shared/syscall-list.h
+	src/shared/syscall-list.h \
+	src/shared/audit.c \
+	src/shared/audit.h
 
 nodist_libsystemd_shared_la_SOURCES = \
 	src/shared/errno-from-name.h \
@@ -843,14 +845,6 @@ libsystemd_capability_la_LIBADD = \
 	$(CAP_LIBS)
 
 # ------------------------------------------------------------------------------
-noinst_LTLIBRARIES += \
-	libsystemd-audit.la
-
-libsystemd_audit_la_SOURCES = \
-	src/shared/audit.c \
-	src/shared/audit.h
-
-# ------------------------------------------------------------------------------
 if HAVE_ACL
 noinst_LTLIBRARIES += \
 	libsystemd-acl.la
@@ -1013,7 +1007,6 @@ libsystemd_core_la_LIBADD = \
 	libsystemd-capability.la \
 	libsystemd-units.la \
 	libsystemd-label.la \
-	libsystemd-audit.la \
 	libsystemd-id128-internal.la \
 	libsystemd-daemon-internal.la \
 	libudev-internal.la \
@@ -1957,6 +1950,8 @@ libsystemd_bus_la_SOURCES = \
 	src/libsystemd-bus/bus-container.h \
 	src/libsystemd-bus/bus-message.c \
 	src/libsystemd-bus/bus-message.h \
+	src/libsystemd-bus/bus-creds.c \
+	src/libsystemd-bus/bus-creds.h \
 	src/libsystemd-bus/bus-signature.c \
 	src/libsystemd-bus/bus-signature.h \
 	src/libsystemd-bus/bus-type.c \
@@ -2035,6 +2030,7 @@ tests += \
 	test-bus-introspect \
 	test-bus-objects \
 	test-bus-error \
+	test-bus-creds \
 	test-event
 
 bin_PROGRAMS += \
@@ -2119,6 +2115,17 @@ test_bus_error_LDADD = \
 	libsystemd-daemon-internal.la \
 	libsystemd-shared.la
 
+test_bus_creds_SOURCES = \
+	src/libsystemd-bus/test-bus-creds.c
+
+test_bus_creds_LDADD = \
+	libsystemd-bus-internal.la \
+	libsystemd-id128-internal.la \
+	libsystemd-daemon-internal.la \
+	libsystemd-shared.la \
+	libsystemd-bus-dump.la \
+	libsystemd-capability.la
+
 test_bus_match_SOURCES = \
 	src/libsystemd-bus/test-bus-match.c
 
@@ -3086,7 +3093,6 @@ nodist_libsystemd_journal_core_la_SOURCES = \
 libsystemd_journal_core_la_LIBADD = \
 	libsystemd-journal-internal.la \
 	libudev-internal.la \
-	libsystemd-audit.la \
 	libsystemd-capability.la \
 	libsystemd-label.la \
 	libsystemd-daemon-internal.la \
@@ -3778,7 +3784,6 @@ libsystemd_machine_core_la_SOURCES = \
 
 libsystemd_machine_core_la_LIBADD = \
 	libsystemd-label.la \
-	libsystemd-audit.la \
 	libsystemd-daemon-internal.la \
 	libsystemd-bus-internal.la \
 	libsystemd-id128-internal.la \
@@ -3933,7 +3938,6 @@ libsystemd_logind_core_la_SOURCES = \
 libsystemd_logind_core_la_LIBADD = \
 	libsystemd-label.la \
 	libsystemd-capability.la \
-	libsystemd-audit.la \
 	libsystemd-daemon-internal.la \
 	libsystemd-id128-internal.la \
 	libsystemd-bus-internal.la \
@@ -4073,7 +4077,6 @@ pam_systemd_la_LDFLAGS = \
 
 pam_systemd_la_LIBADD = \
 	libsystemd-capability.la \
-	libsystemd-audit.la \
 	libsystemd-bus-internal.la \
 	libsystemd-id128-internal.la \
 	libsystemd-daemon-internal.la \
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index b934624..8f63721 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -338,7 +338,13 @@ static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *us
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
diff --git a/src/core/dbus.c b/src/core/dbus.c
index d130e09..7d7c6cb 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -247,9 +247,14 @@ static int selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata,
         }
 
         if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 pid_t pid;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return 0;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return 0;
 
@@ -300,6 +305,7 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
         assert(path);
 
         if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -307,9 +313,13 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 u = manager_get_unit_by_pid(m, pid);
         } else {
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index cca3df6..21c7a8c 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -41,91 +41,16 @@
 #include "audit.h"
 #include "selinux-util.h"
 #include "audit-fd.h"
+#include "strv.h"
 
 static bool initialized = false;
 
-struct auditstruct {
+struct audit_info {
+        sd_bus_creds *creds;
         const char *path;
-        char *cmdline;
-        uid_t loginuid;
-        uid_t uid;
-        gid_t gid;
+        const char *cmdline;
 };
 
-static int bus_get_selinux_security_context(
-                sd_bus *bus,
-                const char *name,
-                sd_bus_error *error,
-                char **ret) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        const void *p;
-        size_t sz;
-        char *b;
-        int r;
-
-        assert(bus);
-        assert(name);
-        assert(ret);
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "GetConnectionSELinuxSecurityContext",
-                        error, &m,
-                        "s", name);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read_array(m, 'y', &p, &sz);
-        if (r < 0)
-                return r;
-
-        b = strndup(p, sz);
-        if (!b)
-                return -ENOMEM;
-
-        *ret = b;
-        return 0;
-}
-
-static int bus_get_audit_data(
-                sd_bus *bus,
-                const char *name,
-                struct auditstruct *audit) {
-
-        pid_t pid;
-        int r;
-
-        assert(bus);
-        assert(name);
-        assert(audit);
-
-        r = sd_bus_get_owner_pid(bus, name, &pid);
-        if (r < 0)
-                return r;
-
-        r = audit_loginuid_from_pid(pid, &audit->loginuid);
-        if (r < 0)
-                return r;
-
-        r = get_process_uid(pid, &audit->uid);
-        if (r < 0)
-                return r;
-
-        r = get_process_gid(pid, &audit->gid);
-        if (r < 0)
-                return r;
-
-        r = get_process_cmdline(pid, 0, true, &audit->cmdline);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
 /*
    Any time an access gets denied this callback will be called
    with the aduit data.  We then need to just copy the audit data into the msgbuf.
@@ -136,19 +61,19 @@ static int audit_callback(
                 char *msgbuf,
                 size_t msgbufsize) {
 
-        struct auditstruct *audit = (struct auditstruct *) auditdata;
+        const struct audit_info *audit = auditdata;
+        uid_t uid = 0, login_uid = 0;
+        gid_t gid = 0;
+
+        sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid);
+        sd_bus_creds_get_uid(audit->creds, &uid);
+        sd_bus_creds_get_gid(audit->creds, &gid);
 
         snprintf(msgbuf, msgbufsize,
                  "auid=%d uid=%d gid=%d%s%s%s%s%s%s",
-                 audit->loginuid,
-                 audit->uid,
-                 audit->gid,
-                 (audit->path ? " path=\"" : ""),
-                 strempty(audit->path),
-                 (audit->path ? "\"" : ""),
-                 (audit->cmdline ? " cmdline=\"" : ""),
-                 strempty(audit->cmdline),
-                 (audit->cmdline ? "\"" : ""));
+                 login_uid, uid, gid,
+                 audit->path ? " path=\"" : "", strempty(audit->path), audit->path ? "\"" : "",
+                 audit->cmdline ? " cmdline=\"" : "", strempty(audit->cmdline), audit->cmdline ? "\"" : "");
 
         msgbuf[msgbufsize-1] = 0;
 
@@ -164,13 +89,12 @@ static int audit_callback(
 _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
         va_list ap;
 
-        va_start(ap, fmt);
-
 #ifdef HAVE_AUDIT
         if (get_audit_fd() >= 0) {
                 _cleanup_free_ char *buf = NULL;
                 int r;
 
+                va_start(ap, fmt);
                 r = vasprintf(&buf, fmt, ap);
                 va_end(ap);
 
@@ -178,10 +102,10 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
                         audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
                         return 0;
                 }
-
-                va_start(ap, fmt);
         }
 #endif
+
+        va_start(ap, fmt);
         log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
         va_end(ap);
 
@@ -238,76 +162,6 @@ void selinux_access_free(void) {
         initialized = false;
 }
 
-static int get_audit_data(
-                sd_bus *bus,
-                sd_bus_message *message,
-                struct auditstruct *audit) {
-
-        struct ucred ucred;
-        const char *sender;
-        socklen_t len;
-        int r, fd;
-
-        sender = sd_bus_message_get_sender(message);
-        if (sender)
-                return bus_get_audit_data(bus, sender, audit);
-
-        fd = sd_bus_get_fd(bus);
-        if (fd < 0)
-                return fd;
-
-        len = sizeof(ucred);
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
-        if (r < 0)
-                return -errno;
-
-        audit->uid = ucred.uid;
-        audit->gid = ucred.gid;
-
-        r = audit_loginuid_from_pid(ucred.pid, &audit->loginuid);
-        if (r < 0)
-                return r;
-
-        r = get_process_cmdline(ucred.pid, 0, true, &audit->cmdline);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-/*
-   This function returns the security context of the remote end of the dbus
-   connections.  Whether it is on the bus or a local connection.
-*/
-static int get_calling_context(
-                sd_bus *bus,
-                sd_bus_message *message,
-                sd_bus_error *error,
-                security_context_t *ret) {
-
-        const char *sender;
-        int r, fd;
-
-        /*
-           If sender exists then
-           if sender is NULL this indicates a local connection.  Grab the fd
-           from dbus and do an getpeercon to peers process context
-        */
-        sender = sd_bus_message_get_sender(message);
-        if (sender)
-                return bus_get_selinux_security_context(bus, sender, error, ret);
-
-        fd = sd_bus_get_fd(bus);
-        if (fd < 0)
-                return fd;
-
-        r = getpeercon(fd, ret);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
 /*
    This function communicates with the kernel to check whether or not it should
    allow the access.
@@ -321,9 +175,12 @@ int selinux_generic_access_check(
                 const char *permission,
                 sd_bus_error *error) {
 
-        security_context_t scon = NULL, fcon = NULL;
-        const char *tclass = NULL;
-        struct auditstruct audit;
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        const char *tclass = NULL, *scon = NULL;
+        struct audit_info audit_info = {};
+        _cleanup_free_ char *cl = NULL;
+        security_context_t fcon = NULL;
+        char **cmdline = NULL;
         int r = 0;
 
         assert(bus);
@@ -338,12 +195,16 @@ int selinux_generic_access_check(
         if (r < 0)
                 return r;
 
-        audit.uid = audit.loginuid = (uid_t) -1;
-        audit.gid = (gid_t) -1;
-        audit.cmdline = NULL;
-        audit.path = path;
+        r = sd_bus_query_sender_creds(
+                        message,
+                        SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|
+                        SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID|
+                        SD_BUS_CREDS_SELINUX_CONTEXT,
+                        &creds);
+        if (r < 0)
+                goto finish;
 
-        r = get_calling_context(bus, message, error, &scon);
+        r = sd_bus_creds_get_selinux_context(creds, &scon);
         if (r < 0)
                 goto finish;
 
@@ -367,21 +228,23 @@ int selinux_generic_access_check(
                 tclass = "system";
         }
 
-        get_audit_data(bus, message, &audit);
+        sd_bus_creds_get_cmdline(creds, &cmdline);
+        cl = strv_join(cmdline, " ");
+
+        audit_info.creds = creds;
+        audit_info.path = path;
+        audit_info.cmdline = cl;
 
-        errno = 0;
-        r = selinux_check_access(scon, fcon, tclass, permission, &audit);
+        r = selinux_check_access((security_context_t) scon, fcon, tclass, permission, &audit_info);
         if (r < 0)
                 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
 
-        log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, audit.cmdline, r);
+        log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r);
 
 finish:
-        free(audit.cmdline);
-        freecon(scon);
         freecon(fcon);
 
-        if (r && security_getenforce() != 1) {
+        if (r < 0 && security_getenforce() != 1) {
                 sd_bus_error_free(error);
                 r = 0;
         }
diff --git a/src/core/service.c b/src/core/service.c
index 5b41c36..cdbe4c8 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -3673,11 +3673,14 @@ static void service_bus_name_owner_change(
                     s->state == SERVICE_RUNNING ||
                     s->state == SERVICE_RELOAD)) {
 
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 pid_t pid;
 
                 /* Try to acquire PID from bus service */
 
-                r = sd_bus_get_owner_pid(u->manager->api_bus, name, &pid);
+                r = sd_bus_get_owner_creds(u->manager->api_bus, name, SD_BUS_CREDS_PID, &creds);
+                if (r >= 0)
+                        r = sd_bus_creds_get_pid(creds, &pid);
                 if (r >= 0) {
                         log_debug_unit(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid);
 
diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c
index f217269..43e2848 100644
--- a/src/libsystemd-bus/bus-control.c
+++ b/src/libsystemd-bus/bus-control.c
@@ -260,80 +260,114 @@ _public_ int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner) {
         return 0;
 }
 
-_public_ int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid) {
+_public_ int sd_bus_get_owner_creds(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds) {
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        uint32_t u;
+        _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
+        pid_t pid = 0;
         int r;
 
-        if (!bus)
-                return -EINVAL;
-        if (!name)
-                return -EINVAL;
-        if (!uid)
-                return -EINVAL;
-        if (!BUS_IS_OPEN(bus->state))
-                return -ENOTCONN;
-        if (bus_pid_changed(bus))
-                return -ECHILD;
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
+        assert_return(creds, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/",
-                        "org.freedesktop.DBus",
-                        "GetConnectionUnixUser",
-                        NULL,
-                        &reply,
-                        "s",
-                        name);
-        if (r < 0)
-                return r;
+        c = bus_creds_new();
+        if (!c)
+                return -ENOMEM;
 
-        r = sd_bus_message_read(reply, "u", &u);
-        if (r < 0)
-                return r;
+        if ((mask & SD_BUS_CREDS_PID) ||
+            mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) {
+                uint32_t u;
 
-        *uid = (uid_t) u;
-        return 0;
-}
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.DBus",
+                                "/",
+                                "org.freedesktop.DBus",
+                                "GetConnectionUnixProcessID",
+                                NULL,
+                                &reply,
+                                "s",
+                                name);
+                if (r < 0)
+                        return r;
 
-_public_ int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        uint32_t u;
-        int r;
+                r = sd_bus_message_read(reply, "u", &u);
+                if (r < 0)
+                        return r;
 
-        if (!bus)
-                return -EINVAL;
-        if (!name)
-                return -EINVAL;
-        if (!pid)
-                return -EINVAL;
-        if (!BUS_IS_OPEN(bus->state))
-                return -ENOTCONN;
-        if (bus_pid_changed(bus))
-                return -ECHILD;
+                pid = u;
+                if (mask & SD_BUS_CREDS_PID) {
+                        c->pid = u;
+                        c->mask |= SD_BUS_CREDS_PID;
+                }
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/",
-                        "org.freedesktop.DBus",
-                        "GetConnectionUnixProcessID",
-                        NULL,
-                        &reply,
-                        "s",
-                        name);
-        if (r < 0)
-                return r;
+                reply = sd_bus_message_unref(reply);
+        }
+
+        if (mask & SD_BUS_CREDS_UID) {
+                uint32_t u;
+
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.DBus",
+                                "/",
+                                "org.freedesktop.DBus",
+                                "GetConnectionUnixUser",
+                                NULL,
+                                &reply,
+                                "s",
+                                name);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read(reply, "u", &u);
+                if (r < 0)
+                        return r;
+
+                c->uid = u;
+                c->mask |= SD_BUS_CREDS_UID;
+
+                reply = sd_bus_message_unref(reply);
+        }
+
+        if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+                const void *p;
+                size_t sz;
+
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.DBus",
+                                "/",
+                                "org.freedesktop.DBus",
+                                "GetConnectionSELinuxSecurityContext",
+                                NULL,
+                                &reply,
+                                "s",
+                                name);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read_array(reply, 'y', &p, &sz);
+                if (r < 0)
+                        return r;
+
+                c->label = strndup(p, sz);
+                if (!c->label)
+                        return -ENOMEM;
+
+                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+        }
 
-        r = sd_bus_message_read(reply, "u", &u);
+        r = bus_creds_add_more(c, mask, pid, 0);
         if (r < 0)
                 return r;
 
-        if (u == 0)
-                return -EIO;
+        *creds = c;
+        c = NULL;
 
-        *pid = (uid_t) u;
         return 0;
 }
 
diff --git a/src/libsystemd-bus/bus-convenience.c b/src/libsystemd-bus/bus-convenience.c
index e765ddb..e57b26b 100644
--- a/src/libsystemd-bus/bus-convenience.c
+++ b/src/libsystemd-bus/bus-convenience.c
@@ -410,3 +410,33 @@ _public_ int sd_bus_set_property(
 
         return sd_bus_call(bus, m, 0, error, NULL);
 }
+
+_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
+        sd_bus_creds *c;
+
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+        c = sd_bus_message_get_creds(call);
+
+        /* All data we need? */
+        if (c && (mask & ~c->mask) == 0) {
+                *creds = sd_bus_creds_ref(c);
+                return 0;
+        }
+
+        /* No data passed? Or not enough data passed to retrieve the missing bits? */
+        if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
+                /* We couldn't read anything from the call, let's try
+                 * to get it from the sender or peer */
+
+                if (call->sender)
+                        return sd_bus_get_owner_creds(call->bus, call->sender, mask, creds);
+                else
+                        return sd_bus_get_peer_creds(call->bus, mask, creds);
+        }
+
+        return sd_bus_creds_extend(c, mask, creds);
+}
diff --git a/src/libsystemd-bus/bus-creds.c b/src/libsystemd-bus/bus-creds.c
new file mode 100644
index 0000000..5ca70cc
--- /dev/null
+++ b/src/libsystemd-bus/bus-creds.c
@@ -0,0 +1,796 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+
+#include "util.h"
+#include "cgroup-util.h"
+#include "fileio.h"
+#include "audit.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "time-util.h"
+#include "bus-creds.h"
+
+enum {
+        CAP_OFFSET_INHERITABLE = 0,
+        CAP_OFFSET_PERMITTED = 1,
+        CAP_OFFSET_EFFECTIVE = 2,
+        CAP_OFFSET_BOUNDING = 3
+};
+
+void bus_creds_done(sd_bus_creds *c) {
+        assert(c);
+
+        /* For internal bus cred structures that are allocated by
+         * something else */
+
+        free(c->session);
+        free(c->unit);
+        free(c->user_unit);
+        free(c->slice);
+
+        free(c->cmdline_array);
+}
+
+_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
+        assert_return(c, NULL);
+
+        if (c->allocated) {
+                assert(c->n_ref > 0);
+                c->n_ref++;
+        } else {
+                sd_bus_message *m;
+
+                /* If this is an embedded creds structure, then
+                 * forward ref counting to the message */
+                m = container_of(c, sd_bus_message, creds);
+                sd_bus_message_ref(m);
+        }
+
+        return c;
+}
+
+_public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
+        assert_return(c, NULL);
+
+        if (c->allocated) {
+                assert(c->n_ref > 0);
+                c->n_ref--;
+
+                if (c->n_ref == 0) {
+                        bus_creds_done(c);
+
+                        free(c->comm);
+                        free(c->tid_comm);
+                        free(c->exe);
+                        free(c->cmdline);
+                        free(c->cgroup);
+                        free(c->capability);
+                        free(c->label);
+                        free(c);
+                }
+        } else {
+                sd_bus_message *m;
+
+                m = container_of(c, sd_bus_message, creds);
+                sd_bus_message_unref(m);
+        }
+
+
+        return NULL;
+}
+
+_public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) {
+        assert_return(c, 0);
+
+        return c->mask;
+}
+
+sd_bus_creds* bus_creds_new(void) {
+        sd_bus_creds *c;
+
+        c = new0(sd_bus_creds, 1);
+        if (!c)
+                return NULL;
+
+        c->allocated = true;
+        c->n_ref = 1;
+        return c;
+}
+
+_public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
+        sd_bus_creds *c;
+        int r;
+
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
+        assert_return(ret, -EINVAL);
+
+        if (pid == 0)
+                pid = getpid();
+
+        c = bus_creds_new();
+        if (!c)
+                return -ENOMEM;
+
+        r = bus_creds_add_more(c, mask, pid, 0);
+        if (r < 0) {
+                free(c);
+                return r;
+        }
+
+        /* Check if the process existed at all, in case we haven't
+         * figured that out already */
+        if (kill(pid, 0) < 0 && errno == ESRCH) {
+                sd_bus_creds_unref(c);
+                return -ESRCH;
+        }
+
+        *ret = c;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
+        assert_return(c, -EINVAL);
+        assert_return(uid, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
+
+        *uid = c->uid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
+        assert_return(c, -EINVAL);
+        assert_return(gid, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
+
+        *gid = c->gid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
+        assert_return(c, -EINVAL);
+        assert_return(pid, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_PID, -ENODATA);
+
+        assert(c->pid > 0);
+        *pid = c->pid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
+        assert_return(c, -EINVAL);
+        assert_return(tid, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_TID, -ENODATA);
+
+        assert(c->tid > 0);
+        *tid = c->tid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
+        assert_return(c, -EINVAL);
+        assert_return(usec, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_PID_STARTTIME, -ENODATA);
+
+        assert(c->pid_starttime > 0);
+        *usec = c->pid_starttime;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT, -ENODATA);
+
+        assert(c->label);
+        *ret = c->label;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_COMM, -ENODATA);
+
+        assert(c->comm);
+        *ret = c->comm;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_TID_COMM, -ENODATA);
+
+        assert(c->tid_comm);
+        *ret = c->tid_comm;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_EXE, -ENODATA);
+
+        assert(c->exe);
+        *ret = c->exe;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_CGROUP, -ENODATA);
+
+        assert(c->cgroup);
+        *ret = c->cgroup;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_UNIT, -ENODATA);
+
+        assert(c->cgroup);
+
+        if (!c->unit) {
+                r = cg_path_get_unit(c->cgroup, (char**) &c->unit);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->unit;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_USER_UNIT, -ENODATA);
+
+        assert(c->cgroup);
+
+        if (!c->user_unit) {
+                r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->user_unit;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_SLICE, -ENODATA);
+
+        assert(c->cgroup);
+
+        if (!c->slice) {
+                r = cg_path_get_slice(c->cgroup, (char**) &c->slice);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->slice;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_SESSION, -ENODATA);
+
+        assert(c->cgroup);
+
+        if (!c->session) {
+                r = cg_path_get_session(c->cgroup, (char**) &c->session);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->session;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
+        assert_return(c, -EINVAL);
+        assert_return(uid, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_OWNER_UID, -ENODATA);
+
+        assert(c->cgroup);
+
+        return cg_path_get_owner_uid(c->cgroup, uid);
+}
+
+_public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
+        size_t n, i;
+        const char *p;
+        bool first;
+
+        assert_return(c, -EINVAL);
+        assert_return(c->cmdline, -ESRCH);
+        assert_return(c->mask & SD_BUS_CREDS_CMDLINE, -ENODATA);
+
+        assert(c->cmdline);
+
+        for (p = c->cmdline, n = 0; p < c->cmdline + c->cmdline_length; p++)
+                if (*p == 0)
+                        n++;
+
+        *(char***) &c->cmdline_array = new(char*, n + 1);
+        if (!c->cmdline_array)
+                return -ENOMEM;
+
+        for (p = c->cmdline, i = 0, first = true; p < c->cmdline + c->cmdline_length; p++) {
+                if (first)
+                        c->cmdline_array[i++] = (char*) p;
+
+                first = *p == 0;
+        }
+
+        c->cmdline_array[i] = NULL;
+        *cmdline = c->cmdline_array;
+
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
+        assert_return(c, -EINVAL);
+        assert_return(sessionid, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID, -ENODATA);
+
+        *sessionid = c->audit_session_id;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
+        assert_return(c, -EINVAL);
+        assert_return(uid, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID, -ENODATA);
+
+        *uid = c->audit_login_uid;
+        return 0;
+}
+
+static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
+        size_t sz;
+
+        assert(c);
+        assert(c->capability);
+
+        sz = c->capability_size / 4;
+        if ((size_t) capability >= sz*8)
+                return 0;
+
+        return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
+}
+
+_public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS, -ENODATA);
+
+        return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
+}
+
+_public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_PERMITTED_CAPS, -ENODATA);
+
+        return has_cap(c, CAP_OFFSET_PERMITTED, capability);
+}
+
+_public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS, -ENODATA);
+
+        return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
+}
+
+_public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+        assert_return(c->mask & SD_BUS_CREDS_BOUNDING_CAPS, -ENODATA);
+
+        return has_cap(c, CAP_OFFSET_BOUNDING, capability);
+}
+
+static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
+        size_t sz;
+        unsigned i;
+
+        assert(c);
+        assert(p);
+
+        p += strspn(p, WHITESPACE);
+
+        sz = strlen(p);
+        if (sz % 2 != 0)
+                return -EINVAL;
+
+        sz /= 2;
+        if (!c->capability) {
+                c->capability = new0(uint8_t, sz * 4);
+                if (!c->capability)
+                        return -ENOMEM;
+
+                c->capability_size = sz * 4;
+        }
+
+        for (i = 0; i < sz; i ++) {
+                int x, y;
+
+                x = unhexchar(p[i*2]);
+                y = unhexchar(p[i*2+1]);
+
+                if (x < 0 || y < 0)
+                        return -EINVAL;
+
+                c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
+        }
+
+        return 0;
+}
+
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
+        uint64_t missing;
+        int r;
+
+        assert(c);
+        assert(c->allocated);
+
+        missing = mask & ~c->mask;
+        if (missing == 0)
+                return 0;
+
+        /* Try to retrieve PID from creds if it wasn't passed to us */
+        if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
+                pid = c->pid;
+
+        if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
+                tid = c->pid;
+
+        /* Without pid we cannot do much... */
+        if (pid <= 0)
+                return 0;
+
+        if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
+                       SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
+                       SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
+
+                _cleanup_fclose_ FILE *f = NULL;
+                char line[LINE_MAX];
+                const char *p;
+
+                p = procfs_file_alloca(pid, "status");
+
+                f = fopen(p, "re");
+                if (!f)
+                        return errno == ENOENT ? -ESRCH : -errno;
+
+                FOREACH_LINE(line, f, return -errno) {
+                        truncate_nl(line);
+
+                        if (missing & SD_BUS_CREDS_UID) {
+                                p = startswith(line, "Uid:");
+                                if (p) {
+                                        unsigned long uid;
+
+                                        p += strspn(p, WHITESPACE);
+                                        if (sscanf(p, "%lu", &uid) != 1)
+                                                return -EIO;
+
+                                        c->uid = (uid_t) uid;
+                                        c->mask |= SD_BUS_CREDS_UID;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_GID) {
+                                p = startswith(line, "Gid:");
+                                if (p) {
+                                        unsigned long gid;
+
+                                        p += strspn(p, WHITESPACE);
+                                        if (sscanf(p, "%lu", &gid) != 1)
+                                                return -EIO;
+
+                                        c->gid = (uid_t) gid;
+                                        c->mask |= SD_BUS_CREDS_GID;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
+                                p = startswith(line, "CapEff:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
+                                p = startswith(line, "CapPrm:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
+                                p = startswith(line, "CapInh:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
+                                p = startswith(line, "CapBnd:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
+                                        continue;
+                                }
+                        }
+                }
+        }
+
+        if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
+                unsigned long long st;
+
+                r = get_starttime_of_pid(pid, &st);
+                if (r < 0)
+                        return r;
+
+                c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
+                c->mask |= SD_BUS_CREDS_PID_STARTTIME;
+        }
+
+        if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
+                const char *p;
+
+                p = procfs_file_alloca(pid, "attr/current");
+                r = read_one_line_file(p, &c->label);
+                if (r < 0 && r != -ENOENT)
+                        return r;
+                else if (r >= 0)
+                        c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+        }
+
+        if (missing & SD_BUS_CREDS_COMM) {
+                r = get_process_comm(pid, &c->comm);
+                if (r < 0)
+                        return r;
+
+                c->mask |= SD_BUS_CREDS_COMM;
+        }
+
+        if (missing & SD_BUS_CREDS_EXE) {
+                r = get_process_exe(pid, &c->exe);
+                if (r < 0)
+                        return r;
+
+                c->mask |= SD_BUS_CREDS_EXE;
+        }
+
+        if (missing & SD_BUS_CREDS_CMDLINE) {
+                const char *p;
+
+                p = procfs_file_alloca(pid, "cmdline");
+                r = read_full_file(p, &c->cmdline, &c->cmdline_length);
+                if (r < 0)
+                        return r;
+
+                if (c->cmdline_length == 0) {
+                        free(c->cmdline);
+                        c->cmdline = NULL;
+                } else
+                        c->mask |= SD_BUS_CREDS_CMDLINE;
+        }
+
+        if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
+                _cleanup_free_ char *p = NULL;
+
+                if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
+                        return -ENOMEM;
+
+                r = read_one_line_file(p, &c->tid_comm);
+                if (r < 0)
+                        return r == -ENOENT ? -ESRCH : r;
+
+                c->mask |= SD_BUS_CREDS_TID_COMM;
+        }
+
+        if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
+
+                r = cg_pid_get_path(NULL, pid, &c->cgroup);
+                if (r < 0)
+                        return r;
+
+                c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
+        }
+
+        if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
+                r = audit_session_from_pid(pid, &c->audit_session_id);
+                if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != ENOENT)
+                        return r;
+                else if (r >= 0)
+                        c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+        }
+
+        if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
+                r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
+                if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != ENOENT)
+                        return r;
+                else if (r >= 0)
+                        c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_creds_extend(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if ((mask & ~c->mask) == 0) {
+                /* There's already all data we need. */
+
+                *ret = sd_bus_creds_ref(c);
+                return 0;
+        }
+
+        n = bus_creds_new();
+        if (!n)
+                return -ENOMEM;
+
+        /* Copy the original data over */
+
+        if (c->mask & mask & SD_BUS_CREDS_UID) {
+                n->uid = c->uid;
+                n->mask |= SD_BUS_CREDS_UID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_GID) {
+                n->gid = c->gid;
+                n->mask |= SD_BUS_CREDS_GID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_PID) {
+                n->pid = c->pid;
+                n->mask |= SD_BUS_CREDS_PID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_TID) {
+                n->tid = c->tid;
+                n->mask |= SD_BUS_CREDS_TID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
+                n->pid_starttime = c->pid_starttime;
+                n->mask |= SD_BUS_CREDS_PID_STARTTIME;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_COMM) {
+                n->comm = strdup(c->comm);
+                if (!n->comm)
+                        return -ENOMEM;
+
+                n->mask |= SD_BUS_CREDS_COMM;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
+                n->tid_comm = strdup(c->tid_comm);
+                if (!n->tid_comm)
+                        return -ENOMEM;
+
+                n->mask |= SD_BUS_CREDS_TID_COMM;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_EXE) {
+                n->exe = strdup(c->exe);
+                if (!n->exe)
+                        return -ENOMEM;
+
+                n->mask |= SD_BUS_CREDS_EXE;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
+                n->cmdline = memdup(c->cmdline, c->cmdline_length);
+                if (!n->cmdline)
+                        return -ENOMEM;
+
+                n->cmdline_length = c->cmdline_length;
+                n->mask |= SD_BUS_CREDS_CMDLINE;
+        }
+
+        if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) {
+                n->cgroup = strdup(c->cgroup);
+                if (!n->cgroup)
+                        return -ENOMEM;
+
+                n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID);
+        }
+
+        if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
+                n->capability = memdup(c->capability, c->capability_size);
+                if (!n->capability)
+                        return -ENOMEM;
+
+                n->capability_size = c->capability_size;
+                n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
+                n->audit_session_id = c->audit_session_id;
+                n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
+                n->audit_login_uid = c->audit_login_uid;
+                n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
+        }
+
+        /* Get more data */
+
+        r = bus_creds_add_more(n, mask,
+                               c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
+                               c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
+        if (r < 0)
+                return r;
+
+        *ret = n;
+        n = NULL;
+        return 0;
+}
diff --git a/src/libsystemd-bus/bus-creds.h b/src/libsystemd-bus/bus-creds.h
new file mode 100644
index 0000000..e2416aa
--- /dev/null
+++ b/src/libsystemd-bus/bus-creds.h
@@ -0,0 +1,67 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include "sd-bus.h"
+#include "time-util.h"
+
+struct sd_bus_creds {
+        bool allocated;
+        unsigned n_ref;
+        uint64_t mask;
+
+        uid_t uid;
+        gid_t gid;
+        pid_t pid;
+        usec_t pid_starttime;
+        pid_t tid;
+
+        char *comm;
+        char *tid_comm;
+        char *exe;
+
+        char *cmdline;
+        size_t cmdline_length;
+        char **cmdline_array;
+
+        char *cgroup;
+        char *session;
+        char *unit;
+        char *user_unit;
+        char *slice;
+
+        uint8_t *capability;
+        size_t capability_size;
+
+        uint32_t audit_session_id;
+        uid_t audit_login_uid;
+
+        char *label;
+};
+
+sd_bus_creds* bus_creds_new(void);
+
+void bus_creds_done(sd_bus_creds *c);
+
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid);
diff --git a/src/libsystemd-bus/bus-dump.c b/src/libsystemd-bus/bus-dump.c
index 8231cfa..9545e18 100644
--- a/src/libsystemd-bus/bus-dump.c
+++ b/src/libsystemd-bus/bus-dump.c
@@ -24,6 +24,7 @@
 #include "util.h"
 #include "capability.h"
 #include "strv.h"
+#include "audit.h"
 
 #include "bus-message.h"
 #include "bus-internal.h"
@@ -45,13 +46,8 @@ static char *indent(unsigned level) {
 }
 
 int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
-        const char *u = NULL, *uu = NULL, *s = NULL;
-        char **cmdline = NULL;
         unsigned level = 1;
         int r;
-        uid_t owner, audit_loginuid;
-        uint32_t audit_sessionid;
-        bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
 
         assert(m);
 
@@ -96,23 +92,6 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
                                 ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
                                 ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
 
-                if (m->pid != 0)
-                        fprintf(f, "  PID=%lu", (unsigned long) m->pid);
-                if (m->pid_starttime != 0)
-                        fprintf(f, "  PIDStartTime=%llu", (unsigned long long) m->pid_starttime);
-                if (m->tid != 0)
-                        fprintf(f, "  TID=%lu", (unsigned long) m->tid);
-                if (m->uid_valid)
-                        fprintf(f, "  UID=%lu", (unsigned long) m->uid);
-                r = sd_bus_message_get_owner_uid(m, &owner);
-                if (r >= 0)
-                        fprintf(f, "  OwnerUID=%lu", (unsigned long) owner);
-                if (m->gid_valid)
-                        fprintf(f, "  GID=%lu", (unsigned long) m->gid);
-
-                if (m->pid != 0 || m->pid_starttime != 0 || m->tid != 0 || m->uid_valid || r >= 0 || m->gid_valid)
-                        fputs("\n", f);
-
                 if (m->monotonic != 0)
                         fprintf(f, "  Monotonic=%llu", (unsigned long long) m->monotonic);
                 if (m->realtime != 0)
@@ -121,70 +100,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
                 if (m->monotonic != 0 || m->realtime != 0)
                         fputs("\n", f);
 
-                if (m->exe)
-                        fprintf(f, "  Exe=%s", m->exe);
-                if (m->comm)
-                        fprintf(f, "  Comm=%s", m->comm);
-                if (m->tid_comm)
-                        fprintf(f, "  TIDComm=%s", m->tid_comm);
-                if (m->label)
-                        fprintf(f, "  Label=%s", m->label);
-
-                if (m->exe || m->comm || m->tid_comm || m->label)
-                        fputs("\n", f);
-
-                if (sd_bus_message_get_cmdline(m, &cmdline) >= 0) {
-                        char **c;
-
-                        fputs("  CommandLine=[", f);
-                        STRV_FOREACH(c, cmdline) {
-                                if (c != cmdline)
-                                        fputc(' ', f);
-
-                                fputs(*c, f);
-                        }
-
-                        fputs("]\n", f);
-                }
-
-                if (m->cgroup)
-                        fprintf(f, "  CGroup=%s\n", m->cgroup);
-
-                sd_bus_message_get_unit(m, &u);
-                if (u)
-                        fprintf(f, "  Unit=%s", u);
-                sd_bus_message_get_user_unit(m, &uu);
-                if (uu)
-                        fprintf(f, "  UserUnit=%s", uu);
-                sd_bus_message_get_session(m, &s);
-                if (s)
-                        fprintf(f, "  Session=%s", s);
-                if (sd_bus_message_get_audit_loginuid(m, &audit_loginuid) >= 0) {
-                        audit_loginuid_is_set = true;
-                        fprintf(f, "  AuditLoginUID=%lu", (unsigned long) audit_loginuid);
-                }
-                if (sd_bus_message_get_audit_sessionid(m, &audit_sessionid) >= 0) {
-                        audit_sessionid_is_set = true;
-                        fprintf(f, "  AuditSessionID=%lu", (unsigned long) audit_sessionid);
-                }
-
-                if (u || uu || s || audit_loginuid_is_set || audit_sessionid_is_set)
-                        fputs("\n", f);
-
-                r = sd_bus_message_has_effective_cap(m, 0);
-                if (r >= 0) {
-                        unsigned long c, last_cap;
-
-                        fprintf(f, "  Capabilities=%s", r ? cap_to_name(0) : "");
-
-                        last_cap = cap_last_cap();
-                        for (c = 0; c < last_cap; c++) {
-                                r = sd_bus_message_has_effective_cap(m, c);
-                                if (r > 0)
-                                        fprintf(f, "|%s", cap_to_name(c));
-                        }
-                        fputs("\n", f);
-                }
+                bus_creds_dump(&m->creds, f);
         }
 
         r = sd_bus_message_rewind(m, true);
@@ -333,3 +249,142 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
         fprintf(f, "  };\n\n");
         return 0;
 }
+
+static void dump_capabilities(
+                sd_bus_creds *c,
+                FILE *f,
+                const char *name,
+                int (*has)(sd_bus_creds *c, int capability)) {
+
+        unsigned long i, last_cap;
+        unsigned n = 0;
+        int r;
+
+        assert(c);
+        assert(f);
+        assert(name);
+        assert(has);
+
+        i = 0;
+        r = has(c, i);
+        if (r < 0)
+                return;
+
+        fprintf(f, "  %s=", name);
+        last_cap = cap_last_cap();
+
+        for (;;) {
+                if (r > 0) {
+                        if (n > 0)
+                                fputc(' ', f);
+                        if (n % 4 == 3)
+                                fputs("\n          ", f);
+
+                        fputs(cap_to_name(i), f);
+                        n++;
+                }
+
+                i++;
+
+                if (i > last_cap)
+                        break;
+
+                r = has(c, i);
+        }
+
+        fputs("\n", f);
+}
+
+int bus_creds_dump(sd_bus_creds *c, FILE *f) {
+        bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
+        const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
+        uid_t owner, audit_loginuid;
+        uint32_t audit_sessionid;
+        char **cmdline = NULL;
+        int r;
+
+        assert(c);
+
+        if (!f)
+                f = stdout;
+
+        if (c->mask & SD_BUS_CREDS_PID)
+                fprintf(f, "  PID=%lu", (unsigned long) c->pid);
+        if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
+                fprintf(f, "  PIDStartTime=%llu", (unsigned long long) c->pid_starttime);
+        if (c->mask & SD_BUS_CREDS_TID)
+                fprintf(f, "  TID=%lu", (unsigned long) c->tid);
+        if (c->mask & SD_BUS_CREDS_UID)
+                fprintf(f, "  UID=%lu", (unsigned long) c->uid);
+        r = sd_bus_creds_get_owner_uid(c, &owner);
+        if (r >= 0)
+                fprintf(f, "  OwnerUID=%lu", (unsigned long) owner);
+        if (c->mask & SD_BUS_CREDS_GID)
+                fprintf(f, "  GID=%lu", (unsigned long) c->gid);
+
+        if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0)
+                fputs("\n", f);
+
+        if (c->mask & SD_BUS_CREDS_EXE)
+                fprintf(f, "  Exe=%s", c->exe);
+        if (c->mask & SD_BUS_CREDS_COMM)
+                fprintf(f, "  Comm=%s", c->comm);
+        if (c->mask & SD_BUS_CREDS_TID_COMM)
+                fprintf(f, "  TIDComm=%s", c->tid_comm);
+        if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
+                fprintf(f, "  Label=%s", c->label);
+
+        if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_SELINUX_CONTEXT))
+                fputs("\n", f);
+
+        if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
+                char **i;
+
+                fputs("  CommandLine=", f);
+                STRV_FOREACH(i, cmdline) {
+                        if (i != cmdline)
+                                fputc(' ', f);
+
+                        fputs(*i, f);
+                }
+
+                fputs("\n", f);
+        }
+
+        if (c->mask & SD_BUS_CREDS_CGROUP)
+                fprintf(f, "  CGroup=%s", c->cgroup);
+        sd_bus_creds_get_unit(c, &u);
+        if (u)
+                fprintf(f, "  Unit=%s", u);
+        sd_bus_creds_get_user_unit(c, &uu);
+        if (uu)
+                fprintf(f, "  UserUnit=%s", uu);
+        sd_bus_creds_get_slice(c, &sl);
+        if (sl)
+                fprintf(f, "  Slice=%s", sl);
+        sd_bus_creds_get_session(c, &s);
+        if (s)
+                fprintf(f, "  Session=%s", s);
+
+        if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
+                fputs("\n", f);
+
+        if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
+                audit_loginuid_is_set = true;
+                fprintf(f, "  AuditLoginUID=%lu", (unsigned long) audit_loginuid);
+        }
+        if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
+                audit_sessionid_is_set = true;
+                fprintf(f, "  AuditSessionID=%lu", (unsigned long) audit_sessionid);
+        }
+
+        if (audit_loginuid_is_set || audit_sessionid_is_set)
+                fputs("\n", f);
+
+        dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
+        dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
+        dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
+        dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
+
+        return 0;
+}
diff --git a/src/libsystemd-bus/bus-dump.h b/src/libsystemd-bus/bus-dump.h
index 51aa6aa..bb1d25d 100644
--- a/src/libsystemd-bus/bus-dump.h
+++ b/src/libsystemd-bus/bus-dump.h
@@ -27,3 +27,5 @@
 #include "sd-bus.h"
 
 int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header);
+
+int bus_creds_dump(sd_bus_creds *c, FILE *f);
diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index 7a695c7..accb838 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -213,6 +213,8 @@ struct sd_bus {
         struct ucred ucred;
         char label[NAME_MAX];
 
+        uint64_t creds_mask;
+
         int *fds;
         unsigned n_fds;
 
diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c
index da9474d..84d84df 100644
--- a/src/libsystemd-bus/bus-kernel.c
+++ b/src/libsystemd-bus/bus-kernel.c
@@ -548,31 +548,48 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_mess
                         idx += d->memfd.size;
 
                 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
-                        m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
-                        m->uid = d->creds.uid;
-                        m->gid = d->creds.gid;
-                        m->pid = d->creds.pid;
-                        m->tid = d->creds.tid;
-                        m->uid_valid = m->gid_valid = true;
+                        m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
+                        m->creds.uid = d->creds.uid;
+                        m->creds.gid = d->creds.gid;
+                        m->creds.pid = d->creds.pid;
+                        m->creds.tid = d->creds.tid;
+                        m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID) & bus->creds_mask;
+
                 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
                         m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
                         m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
-                } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
-                        m->comm = d->str;
-                else if (d->type == KDBUS_MSG_SRC_TID_COMM)
-                        m->tid_comm = d->str;
-                else if (d->type == KDBUS_MSG_SRC_EXE)
-                        m->exe = d->str;
-                else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
-                        m->cmdline = d->str;
-                        m->cmdline_length = l;
-                } else if (d->type == KDBUS_MSG_SRC_CGROUP)
-                        m->cgroup = d->str;
-                else if (d->type == KDBUS_MSG_SRC_AUDIT)
-                        m->audit = &d->audit;
-                else if (d->type == KDBUS_MSG_SRC_CAPS) {
-                        m->capability = d->data;
-                        m->capability_size = l;
+
+                } else if (d->type == KDBUS_MSG_SRC_PID_COMM) {
+                        m->creds.comm = d->str;
+                        m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
+
+                } else if (d->type == KDBUS_MSG_SRC_TID_COMM) {
+                        m->creds.tid_comm = d->str;
+                        m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
+
+                } else if (d->type == KDBUS_MSG_SRC_EXE) {
+                        m->creds.exe = d->str;
+                        m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
+
+                } else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
+                        m->creds.cmdline = d->str;
+                        m->creds.cmdline_length = l;
+                        m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
+
+                } else if (d->type == KDBUS_MSG_SRC_CGROUP) {
+                        m->creds.cgroup = d->str;
+                        m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
+
+                } else if (d->type == KDBUS_MSG_SRC_AUDIT) {
+                        m->creds.audit_session_id = d->audit.sessionid;
+                        m->creds.audit_login_uid = d->audit.loginuid;
+                        m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
+
+                } else if (d->type == KDBUS_MSG_SRC_CAPS) {
+                        m->creds.capability = d->data;
+                        m->creds.capability_size = l;
+                        m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
+
                 } else if (d->type == KDBUS_MSG_DST_NAME)
                         destination = d->str;
                 else if (d->type != KDBUS_MSG_FDS &&
diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c
index 132426f..dd058e7 100644
--- a/src/libsystemd-bus/bus-message.c
+++ b/src/libsystemd-bus/bus-message.c
@@ -143,16 +143,12 @@ static void message_free(sd_bus_message *m) {
         if (m->iovec != m->iovec_fixed)
                 free(m->iovec);
 
-        free(m->cmdline_array);
-
         message_reset_containers(m);
         free(m->root_container.signature);
 
         free(m->peeked_signature);
 
-        free(m->unit);
-        free(m->user_unit);
-        free(m->session);
+        bus_creds_done(&m->creds);
         free(m);
 }
 
@@ -358,15 +354,17 @@ int bus_message_from_header(
         m->n_fds = n_fds;
 
         if (ucred) {
-                m->uid = ucred->uid;
-                m->pid = ucred->pid;
-                m->gid = ucred->gid;
-                m->uid_valid = m->gid_valid = true;
+                m->creds.uid = ucred->uid;
+                m->creds.pid = ucred->pid;
+                m->creds.gid = ucred->gid;
+                m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID;
         }
 
         if (label) {
-                m->label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
-                memcpy(m->label, label, label_sz + 1);
+                m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
+                memcpy(m->creds.label, label, label_sz + 1);
+
+                m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
         }
 
         if (bus)
@@ -811,63 +809,10 @@ _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
         return &m->error;
 }
 
-_public_ int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid) {
-        assert_return(m, -EINVAL);
-        assert_return(uid, -EINVAL);
-        assert_return(m->uid_valid, -ESRCH);
-
-        *uid = m->uid;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid) {
-        assert_return(m, -EINVAL);
-        assert_return(gid, -EINVAL);
-        assert_return(m->gid_valid, -ESRCH);
-
-        *gid = m->gid;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid) {
-        assert_return(m, -EINVAL);
-        assert_return(pid, -EINVAL);
-        assert_return(m->pid > 0, -ESRCH);
-
-        *pid = m->pid;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid) {
-        assert_return(m, -EINVAL);
-        assert_return(tid, -EINVAL);
-        assert_return(m->tid > 0, -ESRCH);
-
-        *tid = m->tid;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_pid_starttime(sd_bus_message *m, uint64_t *usec) {
-        assert_return(m, -EINVAL);
-        assert_return(usec, -EINVAL);
-        assert_return(m->pid_starttime > 0, -ESRCH);
-
-        *usec = m->pid_starttime;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_selinux_context(sd_bus_message *m, const char **ret) {
-        assert_return(m, -EINVAL);
-        assert_return(m->label, -ESRCH);
-
-        *ret = m->label;
-        return 0;
-}
-
 _public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) {
         assert_return(m, -EINVAL);
         assert_return(usec, -EINVAL);
-        assert_return(m->monotonic > 0, -ESRCH);
+        assert_return(m->monotonic > 0, -ENODATA);
 
         *usec = m->monotonic;
         return 0;
@@ -876,166 +821,19 @@ _public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t
 _public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) {
         assert_return(m, -EINVAL);
         assert_return(usec, -EINVAL);
-        assert_return(m->realtime > 0, -ESRCH);
+        assert_return(m->realtime > 0, -ENODATA);
 
         *usec = m->realtime;
         return 0;
 }
 
-_public_ int sd_bus_message_get_comm(sd_bus_message *m, const char **ret) {
-        assert_return(m, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(m->comm, -ESRCH);
-
-        *ret = m->comm;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_tid_comm(sd_bus_message *m, const char **ret) {
-        assert_return(m, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(m->tid_comm, -ESRCH);
-
-        *ret = m->tid_comm;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_exe(sd_bus_message *m, const char **ret) {
-        assert_return(m, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(m->exe, -ESRCH);
-
-        *ret = m->exe;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_cgroup(sd_bus_message *m, const char **ret) {
-        assert_return(m, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(m->cgroup, -ESRCH);
-
-        *ret = m->cgroup;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_unit(sd_bus_message *m, const char **ret) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(m->cgroup, -ESRCH);
-
-        if (!m->unit) {
-                r = cg_path_get_unit(m->cgroup, &m->unit);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = m->unit;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_user_unit(sd_bus_message *m, const char **ret) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(m->cgroup, -ESRCH);
-
-        if (!m->user_unit) {
-                r = cg_path_get_user_unit(m->cgroup, &m->user_unit);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = m->user_unit;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_session(sd_bus_message *m, const char **ret) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(m->cgroup, -ESRCH);
-
-        if (!m->session) {
-                r = cg_path_get_session(m->cgroup, &m->session);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = m->session;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_owner_uid(sd_bus_message *m, uid_t *uid) {
-        assert_return(m, -EINVAL);
-        assert_return(uid, -EINVAL);
-        assert_return(m->cgroup, -ESRCH);
-
-        return cg_path_get_owner_uid(m->cgroup, uid);
-}
-
-_public_ int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline) {
-        size_t n, i;
-        const char *p;
-        bool first;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->cmdline, -ESRCH);
-
-        for (p = m->cmdline, n = 0; p < m->cmdline + m->cmdline_length; p++)
-                if (*p == 0)
-                        n++;
-
-        m->cmdline_array = new(char*, n + 1);
-        if (!m->cmdline_array)
-                return -ENOMEM;
-
-        for (p = m->cmdline, i = 0, first = true; p < m->cmdline + m->cmdline_length; p++) {
-                if (first)
-                        m->cmdline_array[i++] = (char*) p;
-
-                first = *p == 0;
-        }
-
-        m->cmdline_array[i] = NULL;
-        *cmdline = m->cmdline_array;
-
-        return 0;
-}
-
-_public_ int sd_bus_message_get_audit_sessionid(sd_bus_message *m, uint32_t *sessionid) {
-        assert_return(m, -EINVAL);
-        assert_return(sessionid, -EINVAL);
-        assert_return(m->audit, -ESRCH);
-
-        *sessionid = m->audit->sessionid;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_audit_loginuid(sd_bus_message *m, uid_t *uid) {
-        assert_return(m, -EINVAL);
-        assert_return(uid, -EINVAL);
-        assert_return(m->audit, -ESRCH);
-
-        *uid = m->audit->loginuid;
-        return 0;
-}
-
-_public_ int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability) {
-        unsigned sz;
-
-        assert_return(m, -EINVAL);
-        assert_return(capability < 0, -EINVAL);
-        assert_return(!m->capability, -ESRCH);
+_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
+        assert_return(m, NULL);
 
-        sz = m->capability_size / 4;
-        if ((unsigned) capability >= sz*8)
-                return 0;
+        if (m->creds.mask == 0)
+                return NULL;
 
-        return !!(m->capability[2 * sz + (capability / 8)] & (1 << (capability % 8)));
+        return &m->creds;
 }
 
 _public_ int sd_bus_message_is_signal(sd_bus_message *m,
diff --git a/src/libsystemd-bus/bus-message.h b/src/libsystemd-bus/bus-message.h
index 8c0ba86..72a79f7 100644
--- a/src/libsystemd-bus/bus-message.h
+++ b/src/libsystemd-bus/bus-message.h
@@ -29,6 +29,7 @@
 #include "sd-bus.h"
 #include "kdbus.h"
 #include "time-util.h"
+#include "bus-creds.h"
 
 struct bus_container {
         char enclosing;
@@ -78,19 +79,14 @@ struct sd_bus_message {
 
         sd_bus_error error;
 
-        uid_t uid;
-        gid_t gid;
-        pid_t pid;
-        pid_t tid;
-        usec_t pid_starttime;
+        sd_bus_creds creds;
+
         usec_t monotonic;
         usec_t realtime;
 
         bool sealed:1;
         bool dont_send:1;
         bool allow_fds:1;
-        bool uid_valid:1;
-        bool gid_valid:1;
         bool free_header:1;
         bool free_kdbus:1;
         bool free_fds:1;
@@ -102,8 +98,6 @@ struct sd_bus_message {
         struct bus_body_part *body_end;
         unsigned n_body_parts;
 
-        char *label;
-
         size_t rindex;
         struct bus_body_part *cached_rindex_part;
         size_t cached_rindex_part_begin;
@@ -126,24 +120,6 @@ struct sd_bus_message {
 
         char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
         char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
-
-        const char *exe;
-        const char *comm;
-        const char *tid_comm;
-        const char *cgroup;
-
-        const char *cmdline;
-        size_t cmdline_length;
-        char **cmdline_array;
-
-        char *session;
-        char *unit;
-        char *user_unit;
-
-        struct kdbus_audit *audit;
-
-        uint8_t *capability;
-        size_t capability_size;
 };
 
 #define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != SD_BUS_NATIVE_ENDIAN)
diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c
index 7a21975..5069aaa 100644
--- a/src/libsystemd-bus/bus-util.c
+++ b/src/libsystemd-bus/bus-util.c
@@ -20,6 +20,7 @@
 ***/
 
 #include <sys/socket.h>
+#include <sys/capability.h>
 
 #include "util.h"
 #include "strv.h"
@@ -137,7 +138,7 @@ int bus_verify_polkit(
                 bool *_challenge,
                 sd_bus_error *e) {
 
-        const char *sender;
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         uid_t uid;
         int r;
 
@@ -145,11 +146,11 @@ int bus_verify_polkit(
         assert(m);
         assert(action);
 
-        sender = sd_bus_message_get_sender(m);
-        if (!sender)
-                return -EBADMSG;
+        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
 
-        r = sd_bus_get_owner_uid(bus, sender, &uid);
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -160,6 +161,11 @@ int bus_verify_polkit(
         else {
                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
                 int authorized = false, challenge = false;
+                const char *sender;
+
+                sender = sd_bus_message_get_sender(m);
+                if (!sender)
+                        return -EBADMSG;
 
                 r = sd_bus_call_method(
                                 bus,
@@ -271,8 +277,9 @@ int bus_verify_polkit_async(
 #ifdef ENABLE_POLKIT
         _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
         AsyncPolkitQuery *q;
-#endif
         const char *sender;
+#endif
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         uid_t uid;
         int r;
 
@@ -319,17 +326,21 @@ int bus_verify_polkit_async(
         }
 #endif
 
-        sender = sd_bus_message_get_sender(m);
-        if (!sender)
-                return -EBADMSG;
+        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
 
-        r = sd_bus_get_owner_uid(bus, sender, &uid);
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
         if (uid == 0)
                 return 1;
+
 #ifdef ENABLE_POLKIT
+        sender = sd_bus_message_get_sender(m);
+        if (!sender)
+                return -EBADMSG;
 
         r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
         if (r < 0)
diff --git a/src/libsystemd-bus/bus-util.h b/src/libsystemd-bus/bus-util.h
index 38d468e..9d49237 100644
--- a/src/libsystemd-bus/bus-util.h
+++ b/src/libsystemd-bus/bus-util.h
@@ -137,9 +137,11 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref);
 
 #define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp)
 #define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
+#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp)
 #define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
 
 #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type)              \
diff --git a/src/libsystemd-bus/busctl.c b/src/libsystemd-bus/busctl.c
index 4204adb..24db48a 100644
--- a/src/libsystemd-bus/busctl.c
+++ b/src/libsystemd-bus/busctl.c
@@ -75,41 +75,47 @@ static int list_bus_names(sd_bus *bus, char **argv) {
                (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 20, "CONNECTION");
 
         STRV_FOREACH(i, l) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 _cleanup_free_ char *owner = NULL;
                 sd_id128_t mid;
-                pid_t pid;
-                uid_t uid;
 
                 if (arg_no_unique && (*i)[0] == ':')
                         continue;
 
                 printf("%-*s", (int) max_i, *i);
 
-                r = sd_bus_get_owner_pid(bus, *i, &pid);
+                r = sd_bus_get_owner_creds(bus, *i, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM, &creds);
                 if (r >= 0) {
-                        _cleanup_free_ char *comm = NULL;
+                        pid_t pid;
+                        uid_t uid;
 
-                        printf(" %10lu", (unsigned long) pid);
+                        r = sd_bus_creds_get_pid(creds, &pid);
+                        if (r >= 0) {
+                                const char *comm = NULL;
 
-                        get_process_comm(pid, &comm);
-                        printf(" %-15s", strna(comm));
-                } else
-                        printf("          - -              ");
+                                sd_bus_creds_get_comm(creds, &comm);
 
-                r = sd_bus_get_owner_uid(bus, *i, &uid);
-                if (r >= 0) {
-                        _cleanup_free_ char *u = NULL;
+                                printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
+                        } else
+                                printf("          - -              ");
 
-                        u = uid_to_name(uid);
-                        if (!u)
-                                return log_oom();
+                        r = sd_bus_creds_get_uid(creds, &uid);
+                        if (r >= 0) {
+                                _cleanup_free_ char *u = NULL;
 
-                        if (strlen(u) > 16)
-                                u[16] = 0;
+                                u = uid_to_name(uid);
+                                if (!u)
+                                        return log_oom();
 
-                        printf(" %-16s", u);
+                                if (strlen(u) > 16)
+                                        u[16] = 0;
+
+                                printf(" %-16s", u);
+                        } else
+                                printf(" -               ");
                 } else
-                        printf(" -               ");
+                        printf("          - -               -               ");
+
 
                 r = sd_bus_get_owner(bus, *i, &owner);
                 if (r >= 0)
diff --git a/src/libsystemd-bus/libsystemd-bus.sym b/src/libsystemd-bus/libsystemd-bus.sym
index 9cf06c4..435c794 100644
--- a/src/libsystemd-bus/libsystemd-bus.sym
+++ b/src/libsystemd-bus/libsystemd-bus.sym
@@ -28,13 +28,6 @@ global:
         sd_bus_negotiate_fds;
         sd_bus_negotiate_attach_timestamp;
         sd_bus_negotiate_attach_creds;
-        sd_bus_negotiate_attach_comm;
-        sd_bus_negotiate_attach_exe;
-        sd_bus_negotiate_attach_cmdline;
-        sd_bus_negotiate_attach_cgroup;
-        sd_bus_negotiate_attach_caps;
-        sd_bus_negotiate_attach_selinux_context;
-        sd_bus_negotiate_attach_audit;
         sd_bus_start;
         sd_bus_close;
         sd_bus_ref;
@@ -42,6 +35,7 @@ global:
         sd_bus_is_open;
         sd_bus_can_send;
         sd_bus_get_server_id;
+        sd_bus_get_peer_creds;
         sd_bus_send;
         sd_bus_send_to;
         sd_bus_get_fd;
@@ -82,6 +76,7 @@ global:
         sd_bus_message_new_method_errnof;
         sd_bus_message_ref;
         sd_bus_message_unref;
+        sd_bus_message_get_bus;
         sd_bus_message_get_type;
         sd_bus_message_get_serial;
         sd_bus_message_get_reply_serial;
@@ -95,27 +90,9 @@ global:
         sd_bus_message_get_sender;
         sd_bus_message_get_error;
         sd_bus_message_get_errno;
-        sd_bus_message_get_bus;
         sd_bus_message_get_monotonic_timestamp;
         sd_bus_message_get_realtime_timestamp;
-        sd_bus_message_get_uid;
-        sd_bus_message_get_gid;
-        sd_bus_message_get_pid;
-        sd_bus_message_get_tid;
-        sd_bus_message_get_pid_starttime;
-        sd_bus_message_get_selinux_context;
-        sd_bus_message_get_comm;
-        sd_bus_message_get_tid_comm;
-        sd_bus_message_get_exe;
-        sd_bus_message_get_cgroup;
-        sd_bus_message_get_cmdline;
-        sd_bus_message_get_unit;
-        sd_bus_message_get_user_unit;
-        sd_bus_message_get_session;
-        sd_bus_message_get_owner_uid;
-        sd_bus_message_get_audit_sessionid;
-        sd_bus_message_get_audit_loginuid;
-        sd_bus_message_has_effective_cap;
+        sd_bus_message_get_creds;
         sd_bus_message_is_signal;
         sd_bus_message_is_method_call;
         sd_bus_message_is_method_error;
@@ -147,6 +124,15 @@ global:
         sd_bus_message_at_end;
         sd_bus_message_rewind;
 
+        /* Bus management */
+        sd_bus_get_unique_name;
+        sd_bus_request_name;
+        sd_bus_release_name;
+        sd_bus_list_names;
+        sd_bus_get_owner;
+        sd_bus_get_owner_creds;
+        sd_bus_get_owner_machine_id;
+
         /* Convenience calls */
         sd_bus_call_method;
         sd_bus_get_property;
@@ -166,16 +152,36 @@ global:
         sd_bus_emit_interfaces_added;
         sd_bus_emit_interfaces_removed_strv;
         sd_bus_emit_interfaces_removed;
+        sd_bus_query_sender_creds;
 
-        /* Bus management */
-        sd_bus_get_unique_name;
-        sd_bus_request_name;
-        sd_bus_release_name;
-        sd_bus_list_names;
-        sd_bus_get_owner;
-        sd_bus_get_owner_uid;
-        sd_bus_get_owner_pid;
-        sd_bus_get_owner_machine_id;
+        /* Credentials */
+        sd_bus_creds_new_from_pid;
+        sd_bus_creds_ref;
+        sd_bus_creds_unref;
+        sd_bus_creds_extend;
+        sd_bus_creds_get_mask;
+        sd_bus_creds_get_uid;
+        sd_bus_creds_get_gid;
+        sd_bus_creds_get_pid;
+        sd_bus_creds_get_pid_starttime;
+        sd_bus_creds_get_tid;
+        sd_bus_creds_get_comm;
+        sd_bus_creds_get_tid_comm;
+        sd_bus_creds_get_exe;
+        sd_bus_creds_get_cmdline;
+        sd_bus_creds_get_cgroup;
+        sd_bus_creds_get_unit;
+        sd_bus_creds_get_user_unit;
+        sd_bus_creds_get_slice;
+        sd_bus_creds_get_session;
+        sd_bus_creds_get_owner_uid;
+        sd_bus_creds_has_effective_cap;
+        sd_bus_creds_has_permitted_cap;
+        sd_bus_creds_has_inheritable_cap;
+        sd_bus_creds_has_bounding_cap;
+        sd_bus_creds_get_selinux_context;
+        sd_bus_creds_get_audit_session_id;
+        sd_bus_creds_get_audit_login_uid;
 
         /* Error structures */
         sd_bus_error_free;
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 49a2abc..97a8c68 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -283,75 +283,38 @@ _public_ int sd_bus_negotiate_attach_timestamp(sd_bus *bus, int b) {
         return 0;
 }
 
-_public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, int b) {
+_public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t mask) {
         assert_return(bus, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_MAX, -EINVAL);
         assert_return(bus->state == BUS_UNSET, -EPERM);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CREDS, b);
-        return 0;
-}
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CREDS,
+                 !!(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID)));
 
-_public_ int sd_bus_negotiate_attach_comm(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_COMM,
+                 !!(mask & (SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)));
 
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_COMM, b);
-        return 0;
-}
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_EXE,
+                 !!(mask & SD_BUS_CREDS_EXE));
 
-_public_ int sd_bus_negotiate_attach_exe(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CMDLINE,
+                 !!(mask & SD_BUS_CREDS_CMDLINE));
 
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_EXE, b);
-        return 0;
-}
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CGROUP,
+                 !!(mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)));
 
-_public_ int sd_bus_negotiate_attach_cmdline(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CAPS,
+                 !!(mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)));
 
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CMDLINE, b);
-        return 0;
-}
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_SECLABEL,
+                 !!(mask & SD_BUS_CREDS_SELINUX_CONTEXT));
 
-_public_ int sd_bus_negotiate_attach_cgroup(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CGROUP, b);
-        return 0;
-}
-
-_public_ int sd_bus_negotiate_attach_caps(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CAPS, b);
-        return 0;
-}
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_AUDIT,
+                 !!(mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
 
-_public_ int sd_bus_negotiate_attach_selinux_context(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        bus->creds_mask = mask;
 
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_SECLABEL, b);
-        return 0;
-}
-
-_public_ int sd_bus_negotiate_attach_audit(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_AUDIT, b);
         return 0;
 }
 
@@ -2812,3 +2775,48 @@ _public_ char *sd_bus_label_unescape(const char *f) {
 
         return r;
 }
+
+_public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
+        sd_bus_creds *c;
+        pid_t pid = 0;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
+        assert_return(ret, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(!bus->is_kernel, -ENOTSUP);
+
+        if (!bus->ucred_valid && !isempty(bus->label))
+                return -ENODATA;
+
+        c = bus_creds_new();
+        if (!c)
+                return -ENOMEM;
+
+        if (bus->ucred_valid) {
+                pid = c->pid = bus->ucred.pid;
+                c->uid = bus->ucred.uid;
+                c->gid = bus->ucred.gid;
+
+                c->mask |= ((SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask) & bus->creds_mask;
+        }
+
+        if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
+                c->label = strdup(bus->label);
+                if (!c->label) {
+                        sd_bus_creds_unref(c);
+                        return -ENOMEM;
+                }
+
+                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT | bus->creds_mask;
+        }
+
+        r = bus_creds_add_more(c, mask, pid, 0);
+        if (r < 0)
+                return r;
+
+        *ret = c;
+        return 0;
+}
diff --git a/src/libsystemd-bus/test-bus-chat.c b/src/libsystemd-bus/test-bus-chat.c
index 66a5df9..021379f 100644
--- a/src/libsystemd-bus/test-bus-chat.c
+++ b/src/libsystemd-bus/test-bus-chat.c
@@ -158,8 +158,8 @@ static int server(sd_bus *bus) {
                 if (!m)
                         continue;
 
-                sd_bus_message_get_pid(m, &pid);
-                sd_bus_message_get_selinux_context(m, &label);
+                sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
+                sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
                 log_info("Got message! member=%s pid=%lu label=%s",
                          strna(sd_bus_message_get_member(m)),
                          (unsigned long) pid,
diff --git a/src/libsystemd-bus/test-bus-creds.c b/src/libsystemd-bus/test-bus-creds.c
new file mode 100644
index 0000000..0a9b2ca
--- /dev/null
+++ b/src/libsystemd-bus/test-bus-creds.c
@@ -0,0 +1,46 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+#include "bus-dump.h"
+#include "bus-util.h"
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        int r;
+
+        r = sd_bus_creds_new_from_pid(0, _SD_BUS_CREDS_MAX, &creds);
+        assert_se(r >= 0);
+
+        bus_creds_dump(creds, NULL);
+
+        creds = sd_bus_creds_unref(creds);
+
+        r = sd_bus_creds_new_from_pid(1, _SD_BUS_CREDS_MAX, &creds);
+        if (r != -EACCES) {
+                assert_se(r >= 0);
+                putchar('\n');
+                bus_creds_dump(creds, NULL);
+        }
+
+        return 0;
+}
diff --git a/src/libsystemd-bus/test-bus-kernel.c b/src/libsystemd-bus/test-bus-kernel.c
index 44d2fa7..f970ca5 100644
--- a/src/libsystemd-bus/test-bus-kernel.c
+++ b/src/libsystemd-bus/test-bus-kernel.c
@@ -63,24 +63,10 @@ int main(int argc, char *argv[]) {
         assert_se(r >= 0);
 
         assert_se(sd_bus_negotiate_attach_timestamp(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_creds(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_comm(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_exe(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_cmdline(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_cgroup(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_caps(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_selinux_context(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_audit(a, 1) >= 0);
+        assert_se(sd_bus_negotiate_attach_creds(a, _SD_BUS_CREDS_MAX) >= 0);
 
         assert_se(sd_bus_negotiate_attach_timestamp(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_creds(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_comm(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_exe(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_cmdline(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_cgroup(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_caps(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_selinux_context(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_audit(b, 1) >= 0);
+        assert_se(sd_bus_negotiate_attach_creds(b, _SD_BUS_CREDS_MAX) >= 0);
 
         r = sd_bus_start(a);
         assert_se(r >= 0);
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index a4bdf5f..0461d18 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -172,7 +172,13 @@ static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
@@ -234,7 +240,13 @@ static int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *us
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
@@ -543,9 +555,15 @@ static int method_create_session(sd_bus *bus, sd_bus_message *message, void *use
         }
 
         if (leader <= 0) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
                 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
+                r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
                 if (r < 0)
                         return r;
         }
@@ -1424,6 +1442,7 @@ static int method_do_shutdown_or_sleep(
                 sd_bus_message_handler_t method,
                 sd_bus_error *error) {
 
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         bool multiple_sessions, blocked;
         int interactive, r;
         uid_t uid;
@@ -1455,7 +1474,11 @@ static int method_do_shutdown_or_sleep(
                         return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
         }
 
-        r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -1579,6 +1602,7 @@ static int method_can_shutdown_or_sleep(
                 const char *sleep_verb,
                 sd_bus_error *error) {
 
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         bool multiple_sessions, challenge, blocked;
         const char *result = NULL;
         uid_t uid;
@@ -1600,7 +1624,11 @@ static int method_can_shutdown_or_sleep(
                         return sd_bus_reply_method_return(message, "s", "na");
         }
 
-        r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -1722,6 +1750,7 @@ static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *u
 }
 
 static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         const char *who, *why, *what, *mode;
         _cleanup_free_ char *id = NULL;
         _cleanup_close_ int fifo_fd = -1;
@@ -1774,11 +1803,15 @@ static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata,
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_owner_pid(m->bus, sd_bus_message_get_sender(message), &pid);
+        r = sd_bus_creds_get_pid(creds, &pid);
         if (r < 0)
                 return r;
 
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index f274c0d..76158e5 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -266,6 +266,7 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
         assert(m);
 
         if (streq(path, "/org/freedesktop/login1/seat/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 Session *session;
                 pid_t pid;
@@ -274,9 +275,13 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_session_by_pid(m, pid, &session);
                 if (r <= 0)
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index bb62b26..4bbe75e 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -225,6 +225,7 @@ static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
 }
 
 static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         Session *s = userdata;
         uid_t uid;
         int r, b;
@@ -237,7 +238,11 @@ static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *user
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -283,6 +288,7 @@ static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
 }
 
 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         Session *s = userdata;
         int r, force;
         uid_t uid;
@@ -295,7 +301,11 @@ static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userd
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -477,6 +487,7 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo
         assert(m);
 
         if (streq(path, "/org/freedesktop/login1/session/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -484,9 +495,13 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_session_by_pid(m, pid, &session);
                 if (r <= 0)
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index 6a77e33..b034515 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -247,6 +247,7 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void
         assert(m);
 
         if (streq(path, "/org/freedesktop/login1/user/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -254,9 +255,13 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_user_by_pid(m, pid, &user);
                 if (r <= 0)
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index c6a794b..1f24b11 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -154,6 +154,7 @@ int machine_object_find(sd_bus *bus, const char *path, const char *interface, vo
         assert(m);
 
         if (streq(path, "/org/freedesktop/machine1/machine/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -161,9 +162,13 @@ int machine_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_machine_by_pid(m, pid, &machine);
                 if (r <= 0)
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 34cd61d..726cc4c 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -102,7 +102,13 @@ static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
@@ -216,9 +222,15 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
                 return r;
 
         if (leader == 0) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
                 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
+                r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
                 if (r < 0)
                         return r;
         }
diff --git a/src/shared/audit.c b/src/shared/audit.c
index 97560cc..9ab4640 100644
--- a/src/shared/audit.c
+++ b/src/shared/audit.c
@@ -26,8 +26,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
-#include <sys/prctl.h>
-#include <sys/capability.h>
 
 #include "macro.h"
 #include "audit.h"
@@ -37,91 +35,64 @@
 #include "virt.h"
 
 int audit_session_from_pid(pid_t pid, uint32_t *id) {
-        char *s;
+        _cleanup_free_ char *s = NULL;
+        const char *p;
         uint32_t u;
         int r;
 
         assert(id);
 
-        if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
-                return -ENOENT;
-
         /* Audit doesn't support containers right now */
         if (detect_container(NULL) > 0)
                 return -ENOTSUP;
 
         if (pid == 0)
-                r = read_one_line_file("/proc/self/sessionid", &s);
-        else {
-                char *p;
-
-                if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0)
-                        return -ENOMEM;
-
-                r = read_one_line_file(p, &s);
-                free(p);
-        }
+                p = "/proc/self/sessionid";
+        else
+                p = procfs_file_alloca(pid, "sessionid");
 
+        r = read_one_line_file(p, &s);
         if (r < 0)
                 return r;
 
         r = safe_atou32(s, &u);
-        free(s);
-
         if (r < 0)
                 return r;
 
         if (u == (uint32_t) -1 || u <= 0)
-                return -ENOENT;
+                return -ENXIO;
 
         *id = u;
         return 0;
 }
 
 int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
-        char *s;
+        _cleanup_free_ char *s = NULL;
+        const char *p;
         uid_t u;
         int r;
 
         assert(uid);
 
-        /* Only use audit login uid if we are executed with sufficient
-         * capabilities so that pam_loginuid could do its job. If we
-         * are lacking the CAP_AUDIT_CONTROL capabality we most likely
-         * are being run in a container and /proc/self/loginuid is
-         * useless since it probably contains a uid of the host
-         * system. */
-
-        if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
-                return -ENOENT;
-
         /* Audit doesn't support containers right now */
         if (detect_container(NULL) > 0)
                 return -ENOTSUP;
 
         if (pid == 0)
-                r = read_one_line_file("/proc/self/loginuid", &s);
-        else {
-                char *p;
-
-                if (asprintf(&p, "/proc/%lu/loginuid", (unsigned long) pid) < 0)
-                        return -ENOMEM;
-
-                r = read_one_line_file(p, &s);
-                free(p);
-        }
+                p = "/proc/self/loginuid";
+        else
+                p = procfs_file_alloca(pid, "loginuid");
 
+        r = read_one_line_file(p, &s);
         if (r < 0)
                 return r;
 
         r = parse_uid(s, &u);
-        free(s);
-
         if (r < 0)
                 return r;
 
         if (u == (uid_t) -1)
-                return -ENOENT;
+                return -ENXIO;
 
         *uid = (uid_t) u;
         return 0;
diff --git a/src/shared/util.c b/src/shared/util.c
index 0fce253..38134ae 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -430,7 +430,7 @@ char *split_quoted(const char *c, size_t *l, char **state) {
                 *state = (char*) e;
         }
 
-        return current;
+        return (char*) current;
 }
 
 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
@@ -497,7 +497,7 @@ int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
 
         f = fopen(p, "re");
         if (!f)
-                return -errno;
+                return errno == ENOENT ? -ESRCH : -errno;
 
         if (!fgets(line, sizeof(line), f)) {
                 if (ferror(f))
@@ -563,6 +563,7 @@ char *truncate_nl(char *s) {
 
 int get_process_comm(pid_t pid, char **name) {
         const char *p;
+        int r;
 
         assert(name);
         assert(pid >= 0);
@@ -572,7 +573,11 @@ int get_process_comm(pid_t pid, char **name) {
         else
                 p = procfs_file_alloca(pid, "comm");
 
-        return read_one_line_file(p, name);
+        r = read_one_line_file(p, name);
+        if (r == -ENOENT)
+                return -ESRCH;
+
+        return r;
 }
 
 int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
@@ -729,7 +734,7 @@ int get_process_exe(pid_t pid, char **name) {
 
         r = readlink_malloc(p, name);
         if (r < 0)
-                return r;
+                return r == -ENOENT ? -ESRCH : r;
 
         d = endswith(*name, " (deleted)");
         if (d)
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 9c001b1..202fdb8 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -37,6 +37,7 @@ _SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_bus sd_bus;
 typedef struct sd_bus_message sd_bus_message;
+typedef struct sd_bus_creds sd_bus_creds;
 
 typedef struct {
         const char *name;
@@ -44,6 +45,34 @@ typedef struct {
         int need_free;
 } sd_bus_error;
 
+/* Flags */
+
+enum {
+        SD_BUS_CREDS_UID              = 1ULL << 0,
+        SD_BUS_CREDS_GID              = 1ULL << 1,
+        SD_BUS_CREDS_PID              = 1ULL << 2,
+        SD_BUS_CREDS_PID_STARTTIME    = 1ULL << 3,
+        SD_BUS_CREDS_TID              = 1ULL << 4,
+        SD_BUS_CREDS_COMM             = 1ULL << 5,
+        SD_BUS_CREDS_TID_COMM         = 1ULL << 6,
+        SD_BUS_CREDS_EXE              = 1ULL << 7,
+        SD_BUS_CREDS_CMDLINE          = 1ULL << 8,
+        SD_BUS_CREDS_CGROUP           = 1ULL << 9,
+        SD_BUS_CREDS_UNIT             = 1ULL << 10,
+        SD_BUS_CREDS_USER_UNIT        = 1ULL << 11,
+        SD_BUS_CREDS_SLICE            = 1ULL << 12,
+        SD_BUS_CREDS_SESSION          = 1ULL << 13,
+        SD_BUS_CREDS_OWNER_UID        = 1ULL << 14,
+        SD_BUS_CREDS_EFFECTIVE_CAPS   = 1ULL << 15,
+        SD_BUS_CREDS_PERMITTED_CAPS   = 1ULL << 16,
+        SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 17,
+        SD_BUS_CREDS_BOUNDING_CAPS    = 1ULL << 18,
+        SD_BUS_CREDS_SELINUX_CONTEXT  = 1ULL << 19,
+        SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 20,
+        SD_BUS_CREDS_AUDIT_LOGIN_UID  = 1ULL << 21,
+        _SD_BUS_CREDS_MAX             = (1ULL << 22) -1,
+};
+
 /* Callbacks */
 
 typedef int (*sd_bus_message_handler_t)(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
@@ -74,14 +103,7 @@ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id);
 int sd_bus_set_anonymous(sd_bus *bus, int b);
 int sd_bus_negotiate_fds(sd_bus *bus, int b);
 int sd_bus_negotiate_attach_timestamp(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_creds(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_comm(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_exe(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_cmdline(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_cgroup(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_caps(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_selinux_context(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_audit(sd_bus *bus, int b);
+int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t creds_mask);
 int sd_bus_start(sd_bus *ret);
 
 void sd_bus_close(sd_bus *bus);
@@ -92,6 +114,7 @@ sd_bus *sd_bus_unref(sd_bus *bus);
 int sd_bus_is_open(sd_bus *bus);
 int sd_bus_can_send(sd_bus *bus, char type);
 int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *peer);
+int sd_bus_get_peer_creds(sd_bus *bus, uint64_t creds_mask, sd_bus_creds **ret);
 
 int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial);
 int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *serial);
@@ -149,6 +172,8 @@ int sd_bus_message_new_method_errnof(sd_bus_message *call, sd_bus_message **m, i
 sd_bus_message* sd_bus_message_ref(sd_bus_message *m);
 sd_bus_message* sd_bus_message_unref(sd_bus_message *m);
 
+sd_bus* sd_bus_message_get_bus(sd_bus_message *m);
+
 int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type);
 int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial);
 int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial);
@@ -164,28 +189,9 @@ const char *sd_bus_message_get_sender(sd_bus_message *m);
 const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m);
 int sd_bus_message_get_errno(sd_bus_message *m);
 
-sd_bus* sd_bus_message_get_bus(sd_bus_message *m);
-
 int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec);
 int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec);
-int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid);
-int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid);
-int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid);
-int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid);
-int sd_bus_message_get_pid_starttime(sd_bus_message *m, uint64_t *usec);
-int sd_bus_message_get_selinux_context(sd_bus_message *m, const char **r);
-int sd_bus_message_get_comm(sd_bus_message *m, const char **r);
-int sd_bus_message_get_tid_comm(sd_bus_message *m, const char **r);
-int sd_bus_message_get_exe(sd_bus_message *m, const char **r);
-int sd_bus_message_get_cgroup(sd_bus_message *m, const char **r);
-int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline);
-int sd_bus_message_get_unit(sd_bus_message *m, const char **unit);
-int sd_bus_message_get_user_unit(sd_bus_message *m, const char **unit);
-int sd_bus_message_get_session(sd_bus_message *m, const char **session);
-int sd_bus_message_get_owner_uid(sd_bus_message *m, uid_t *uid);
-int sd_bus_message_get_audit_sessionid(sd_bus_message *m, uint32_t *sessionid);
-int sd_bus_message_get_audit_loginuid(sd_bus_message *m, uid_t *loginuid);
-int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability);
+sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m); /* do not unref the result */
 
 int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member);
 int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member);
@@ -221,6 +227,16 @@ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *content
 int sd_bus_message_at_end(sd_bus_message *m, int complete);
 int sd_bus_message_rewind(sd_bus_message *m, int complete);
 
+/* Bus management */
+
+int sd_bus_get_unique_name(sd_bus *bus, const char **unique);
+int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
+int sd_bus_release_name(sd_bus *bus, const char *name);
+int sd_bus_list_names(sd_bus *bus, char ***l);
+int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner); /* free the result! */
+int sd_bus_get_owner_creds(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds); /* unref the result! */
+int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine);
+
 /* Convenience calls */
 
 int sd_bus_call_method(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, sd_bus_message **reply, const char *types, ...);
@@ -246,16 +262,39 @@ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *inte
 int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces);
 int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_;
 
-/* Bus management */
-
-int sd_bus_get_unique_name(sd_bus *bus, const char **unique);
-int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
-int sd_bus_release_name(sd_bus *bus, const char *name);
-int sd_bus_list_names(sd_bus *bus, char ***l);
-int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner); /* free the result! */
-int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid);
-int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid);
-int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine);
+int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds);
+
+/* Credential handling */
+
+int sd_bus_creds_new_from_pid(pid_t pid, uint64_t creds_mask, sd_bus_creds **ret);
+sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c);
+sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c);
+uint64_t sd_bus_creds_get_mask(sd_bus_creds *c);
+
+int sd_bus_creds_extend(sd_bus_creds *c, uint64_t creds_mask, sd_bus_creds **ret); /* unref the result */
+
+int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid);
+int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid);
+int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid);
+int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec);
+int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid);
+int sd_bus_creds_get_comm(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_exe(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline);
+int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_unit(sd_bus_creds *c, const char **unit);
+int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **unit);
+int sd_bus_creds_get_slice(sd_bus_creds *c, const char **slice);
+int sd_bus_creds_get_session(sd_bus_creds *c, const char **session);
+int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid);
+int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid);
+int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *loginuid);
 
 /* Error structures */
 
@@ -273,6 +312,8 @@ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e);
 int sd_bus_error_is_set(const sd_bus_error *e);
 int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
 
+/* Auxiliary macros */
+
 #define SD_BUS_MESSAGE_APPEND_ID128(x) 16,                              \
                 (x).bytes[0],  (x).bytes[1],  (x).bytes[2],  (x).bytes[3], \
                 (x).bytes[4],  (x).bytes[5],  (x).bytes[6],  (x).bytes[7], \
@@ -285,6 +326,8 @@ int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
                 &(x).bytes[8],  &(x).bytes[9],  &(x).bytes[10], &(x).bytes[11], \
                 &(x).bytes[12], &(x).bytes[13], &(x).bytes[14], &(x).bytes[15]
 
+/* Label escaping */
+
 char *sd_bus_label_escape(const char *s);
 char *sd_bus_label_unescape(const char *f);
 

commit 70f75a523b16ad495a7791d595ee3eececf75953
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 22:37:52 2013 +0100

    util: fix handling of trailing whitespace in split_quoted()
    
    Inspired by a patch by Lukas Nykryn.

diff --git a/src/shared/util.c b/src/shared/util.c
index d31bd52..0fce253 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -373,17 +373,21 @@ char *split(const char *c, size_t *l, const char *separator, char **state) {
 /* Split a string into words, but consider strings enclosed in '' and
  * "" as words even if they include spaces. */
 char *split_quoted(const char *c, size_t *l, char **state) {
-        char *current, *e;
+        const char *current, *e;
         bool escaped = false;
 
-        current = *state ? *state : (char*) c;
+        assert(c);
+        assert(l);
+        assert(state);
 
-        if (!*current || *c == 0)
-                return NULL;
+        current = *state ? *state : c;
 
         current += strspn(current, WHITESPACE);
 
-        if (*current == '\'') {
+        if (*current == 0)
+                return NULL;
+
+        else if (*current == '\'') {
                 current ++;
 
                 for (e = current; *e; e++) {
@@ -396,7 +400,8 @@ char *split_quoted(const char *c, size_t *l, char **state) {
                 }
 
                 *l = e-current;
-                *state = *e == 0 ? e : e+1;
+                *state = (char*) (*e == 0 ? e : e+1);
+
         } else if (*current == '\"') {
                 current ++;
 
@@ -410,7 +415,8 @@ char *split_quoted(const char *c, size_t *l, char **state) {
                 }
 
                 *l = e-current;
-                *state = *e == 0 ? e : e+1;
+                *state = (char*) (*e == 0 ? e : e+1);
+
         } else {
                 for (e = current; *e; e++) {
                         if (escaped)
@@ -421,10 +427,10 @@ char *split_quoted(const char *c, size_t *l, char **state) {
                                 break;
                 }
                 *l = e-current;
-                *state = e;
+                *state = (char*) e;
         }
 
-        return (char*) current;
+        return current;
 }
 
 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index e468859..068e421 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -143,6 +143,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
         char **t;
 
         p = strv_join_quoted((char **)split);
+        assert_se(p);
         printf("-%s- --- -%s-\n", p, quoted); /* fprintf deals with NULL, puts does not */
         assert_se(p);
         assert_se(streq(p, quoted));
@@ -156,6 +157,20 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
         }
 }
 
+static void test_strv_quote_unquote2(const char *quoted, const char ** list) {
+        _cleanup_strv_free_ char **s;
+        unsigned i = 0;
+        char **t;
+
+        s = strv_split_quoted(quoted);
+        assert_se(s);
+
+        STRV_FOREACH(t, s)
+                assert_se(streq(list[i++], *t));
+
+        assert_se(list[i] == NULL);
+}
+
 static void test_strv_split(void) {
         char **s;
         unsigned i = 0;
@@ -405,6 +420,18 @@ int main(int argc, char *argv[]) {
         test_strv_quote_unquote(input_table_quotes, QUOTES_STRING);
         test_strv_quote_unquote(input_table_spaces, SPACES_STRING);
 
+        test_strv_quote_unquote2("    foo=bar     \"waldo\"    zzz    ", (const char*[]) { "foo=bar", "waldo", "zzz", NULL });
+        test_strv_quote_unquote2("", (const char*[]) { NULL });
+        test_strv_quote_unquote2(" ", (const char*[]) { NULL });
+        test_strv_quote_unquote2("   ", (const char*[]) { NULL });
+        test_strv_quote_unquote2("   x", (const char*[]) { "x", NULL });
+        test_strv_quote_unquote2("x   ", (const char*[]) { "x", NULL });
+        test_strv_quote_unquote2("  x   ", (const char*[]) { "x", NULL });
+        test_strv_quote_unquote2("  \"x\"   ", (const char*[]) { "x", NULL });
+        test_strv_quote_unquote2("  \'x\'   ", (const char*[]) { "x", NULL });
+        test_strv_quote_unquote2("  \'x\"\'   ", (const char*[]) { "x\"", NULL });
+        test_strv_quote_unquote2("  \"x\'\"   ", (const char*[]) { "x\'", NULL });
+
         test_strv_split();
         test_strv_split_newlines();
         test_strv_split_nulstr();

commit fb1454005dda75cdab5795285a8607237033d6a8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 21:14:56 2013 +0100

    man: move socket-proxyd man page to section 8, since it is not in the $PATH

diff --git a/Makefile-man.am b/Makefile-man.am
index f2b6164..52275ce 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -68,7 +68,7 @@ MANPAGES += \
 	man/systemd-run.1 \
 	man/systemd-shutdownd.service.8 \
 	man/systemd-sleep.conf.5 \
-	man/systemd-socket-proxyd.1 \
+	man/systemd-socket-proxyd.8 \
 	man/systemd-suspend.service.8 \
 	man/systemd-sysctl.service.8 \
 	man/systemd-system-update-generator.8 \
diff --git a/man/systemd-socket-proxyd.xml b/man/systemd-socket-proxyd.xml
index 095af31..4aef620 100644
--- a/man/systemd-socket-proxyd.xml
+++ b/man/systemd-socket-proxyd.xml
@@ -35,7 +35,7 @@
         </refentryinfo>
         <refmeta>
                 <refentrytitle>systemd-socket-proxyd</refentrytitle>
-                <manvolnum>1</manvolnum>
+                <manvolnum>8</manvolnum>
         </refmeta>
         <refnamediv>
                 <refname>systemd-socket-proxyd</refname>

commit 34c7dc47d3beb9aebc8f5e4a8698b3c9acff0048
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 21:14:08 2013 +0100

    man: get rid of shell script example in systemd-socket-proxyd man page

diff --git a/TODO b/TODO
index de3488f..6a130ac 100644
--- a/TODO
+++ b/TODO
@@ -107,8 +107,6 @@ Features:
 * socket-proxyd:
   - Support multiple inherited sockets mapped to different remote hosts
   - Use a nonblocking alternative to getaddrinfo
-  - Until we can start daemons directly, find a less ugly, less racy alternative than shell scripts for the second man page example.
-  - Support starting daemons directly without requiring a shell script; update man pages
 
 * "systemctl cat" or "systemctl view" command or or so, that cats the backing unit file of a service, plus its drop-ins and shows them in a pager
 
diff --git a/man/systemd-socket-proxyd.xml b/man/systemd-socket-proxyd.xml
index ffa94f4..095af31 100644
--- a/man/systemd-socket-proxyd.xml
+++ b/man/systemd-socket-proxyd.xml
@@ -108,11 +108,11 @@
         <refsect1>
                 <title>Examples</title>
                 <refsect2>
-                        <title>Direct-Use Example</title>
+                        <title>Simple Example</title>
                         <para>Use two services with a dependency
                         and no namespace isolation.</para>
-                        <example label="proxy socket unit">
-                                <title>/etc/systemd/system/proxy-to-nginx.socket</title>
+                        <example>
+                                <title>proxy-to-nginx.socket</title>
                                 <programlisting>
 <![CDATA[[Socket]
 ListenStream=80
@@ -121,21 +121,21 @@ ListenStream=80
 WantedBy=sockets.target]]>
 </programlisting>
                         </example>
-                        <example label="proxy service unit">
-                                <title>/etc/systemd/system/proxy-to-nginx.service</title>
+                        <example>
+                                <title>proxy-to-nginx.service</title>
                                 <programlisting>
 <![CDATA[[Unit]
-After=nginx.service
 Requires=nginx.service
+After=nginx.service
 
 [Service]
-ExecStart=/usr/bin/systemd-socket-proxyd /tmp/nginx.sock
-PrivateTmp=true
-PrivateNetwork=true]]>
+ExecStart=/usr/lib/systemd/systemd-socket-proxyd /tmp/nginx.sock
+PrivateTmp=yes
+PrivateNetwork=yes]]>
 </programlisting>
                         </example>
-                        <example label="nginx configuration">
-                                <title>/etc/nginx/nginx.conf</title>
+                        <example>
+                                <title>nginx.conf</title>
                                 <programlisting>
 <![CDATA[[...]
 server {
@@ -143,7 +143,8 @@ server {
     [...]]]>
 </programlisting>
                         </example>
-                        <example label="commands">
+                        <example>
+                                <title>Enabling the proxy</title>
                                 <programlisting>
 <![CDATA[# systemctl enable proxy-to-nginx.socket
 # systemctl start proxy-to-nginx.socket
@@ -152,17 +153,16 @@ $ curl http://localhost:80/]]>
                         </example>
                 </refsect2>
                 <refsect2>
-                        <title>Indirect-Use Example</title>
-                        <para>Use a shell script to isolate the
-                        service and proxy into the same namespace.
-                        This is particularly useful for running
-                        TCP-only daemons without the daemon
-                        affecting ports on regular
-                        interfaces.</para>
-                        <example label="combined proxy and nginx socket unit">
-
-                                <title>
-                                /etc/systemd/system/proxy-with-nginx.socket</title>
+                        <title>Namespace Example</title>
+                        <para>Similar as above, but runs the socket
+                        proxy and the main service in the same private
+                        namespace, assuming that
+                        <filename>nginx.service</filename> has
+                        <varname>PrivateTmp=</varname> and
+                        <varname>PrivateNetwork=</varname> set,
+                        too.</para>
+                        <example>
+                                <title>proxy-to-nginx.socket</title>
                                 <programlisting>
 <![CDATA[[Socket]
 ListenStream=80
@@ -171,37 +171,22 @@ ListenStream=80
 WantedBy=sockets.target]]>
 </programlisting>
                         </example>
-                        <example label="combined proxy and nginx service unit">
-
-                                <title>
-                                /etc/systemd/system/proxy-with-nginx.service</title>
+                        <example>
+                                <title>proxy-to-nginx.service</title>
                                 <programlisting>
 <![CDATA[[Unit]
-After=remote-fs.target nss-lookup.target
+Requires=nginx.service
+After=nginx.service
+JoinsNamespaceOf=nginx.service
 
 [Service]
-ExecStartPre=/usr/sbin/nginx -t
-ExecStart=/usr/bin/socket-proxyd-nginx.sh
-PrivateTmp=true
-PrivateNetwork=true]]>
+ExecStart=/usr/lib/systemd/systemd-socket-proxyd 127.0.0.1:8080
+PrivateTmp=yes
+PrivateNetwork=yes]]>
 </programlisting>
                         </example>
-                        <example label="shell script">
-                                <title>
-                                /usr/bin/socket-proxyd-nginx.sh</title>
-                                <programlisting>
-<![CDATA[#!/bin/sh
-/usr/sbin/nginx
-while [ ! -f /tmp/nginx.pid ]
-  do
-     /usr/bin/inotifywait /tmp/nginx.pid
-  done
-exec /usr/bin/systemd-socket-proxyd localhost 8080]]>
-</programlisting>
-                        </example>
-                        <example label="nginx configuration">
-                                <title>
-                                /etc/nginx/nginx.conf</title>
+                        <example>
+                                <title>nginx.conf</title>
                                 <programlisting>
 <![CDATA[[...]
 server {
@@ -210,10 +195,11 @@ server {
     [...]]]>
 </programlisting>
                         </example>
-                        <example label="commands">
+                        <example>
+                                <title>Enabling the proxy</title>
                                 <programlisting>
-<![CDATA[# systemctl enable proxy-with-nginx.socket
-# systemctl start proxy-with-nginx.socket
+<![CDATA[# systemctl enable proxy-to-nginx.socket
+# systemctl start proxy-to-nginx.socket
 $ curl http://localhost:80/]]>
 </programlisting>
                         </example>
@@ -226,7 +212,9 @@ $ curl http://localhost:80/]]>
                         <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-                        <citerefentry><refentrytitle>socat</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                        <citerefentry><refentrytitle>socat</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>nginx</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>curl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 </para>
         </refsect1>
 </refentry>

commit 07504d6b152084040e48f7657b0f56f364003334
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 20:55:15 2013 +0100

    Revert "socket-proxyd: Add --listener option for listener/destination pairs."
    
    This reverts commit adcf4c81c58511b67644e17fa743d1729d3c9ccf.
    
    We have a better solution for the problem of making two processes run in
    the same namespace, and --listener is not needed hence and should be
    dropped.
    
    Conflicts:
    	man/systemd-socket-proxyd.xml

diff --git a/man/systemd-socket-proxyd.xml b/man/systemd-socket-proxyd.xml
index 4eb13e4..ffa94f4 100644
--- a/man/systemd-socket-proxyd.xml
+++ b/man/systemd-socket-proxyd.xml
@@ -59,7 +59,7 @@
                 <para>
                 <command>systemd-socket-proxyd</command> is a generic
                 socket-activated network socket forwarder proxy daemon
-                for IPV4, IPv6 and UNIX stream sockets. It may be used
+                for IPv4, IPv6 and UNIX stream sockets. It may be used
                 to bi-directionally forward traffic from a local listening socket to a
                 local or remote destination socket.</para>
 



More information about the systemd-commits mailing list