Systemd/src/dbus-common.c
Kay Sievers 2b583ce657 use /run instead of /dev/.run
Instead of the /dev/.run trick we have currently implemented, we decided
to move the early-boot runtime dir to /run.

An existing /var/run directory is bind-mounted to /run. If /var/run is
already a symlink, no action is taken.

An existing /var/lock directory is bind-mounted to /run/lock.
If /var/lock is already a symlink, no action is taken.

To implement the directory vs. symlink logic, we have a:
  ConditionPathIsDirectory=
now, which is used in the mount units.

Skipped mount unit in case of symlink:
  $ systemctl status var-run.mount
  var-run.mount - Runtime Directory
    Loaded: loaded (/lib/systemd/system/var-run.mount)
    Active: inactive (dead)
            start condition failed at Fri, 25 Mar 2011 04:51:41 +0100; 6min ago
     Where: /var/run
      What: /run
    CGroup: name=systemd:/system/var-run.mount

The systemd rpm needs to make sure to add something like:
  %pre
  mkdir -p -m0755 /run >/dev/null 2>&1 || :
or it needs to be added to filesystem.rpm.

Udev -git already uses /run if that exists, and is writable at bootup.
Otherwise it falls back to the current /dev/.udev.

Dracut and plymouth need to be adopted to switch from /dev/.run to run
too.

Cheers,
Kay
2011-03-28 23:00:00 +02:00

235 lines
6.8 KiB
C

/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <assert.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>
#include "log.h"
#include "dbus-common.h"
#include "util.h"
#include "def.h"
int bus_check_peercred(DBusConnection *c) {
int fd;
struct ucred ucred;
socklen_t l;
assert(c);
assert_se(dbus_connection_get_unix_fd(c, &fd));
l = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
log_error("SO_PEERCRED failed: %m");
return -errno;
}
if (l != sizeof(struct ucred)) {
log_error("SO_PEERCRED returned wrong size.");
return -E2BIG;
}
if (ucred.uid != 0)
return -EPERM;
return 1;
}
static int sync_auth(DBusConnection *bus, DBusError *error) {
usec_t begin, tstamp;
assert(bus);
/* This complexity should probably move into D-Bus itself:
*
* https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
begin = tstamp = now(CLOCK_MONOTONIC);
for (;;) {
if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
break;
if (dbus_connection_get_is_authenticated(bus))
break;
if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
break;
tstamp = now(CLOCK_MONOTONIC);
}
if (!dbus_connection_get_is_connected(bus)) {
dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
return -ECONNREFUSED;
}
if (!dbus_connection_get_is_authenticated(bus)) {
dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
return -EACCES;
}
return 0;
}
int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private, DBusError *error) {
DBusConnection *bus;
int r;
assert(_bus);
/* If we are root, then let's not go via the bus */
if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
if (!(bus = dbus_connection_open_private("unix:path=/run/systemd/private", error))) {
#ifndef LEGACY
dbus_error_free(error);
/* Retry with the pre v21 socket name, to ease upgrades */
if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", error)))
#endif
return -EIO;
}
dbus_connection_set_exit_on_disconnect(bus, FALSE);
if (bus_check_peercred(bus) < 0) {
dbus_connection_close(bus);
dbus_connection_unref(bus);
dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
return -EACCES;
}
if (private)
*private = true;
} else {
if (!(bus = dbus_bus_get_private(t, error)))
return -EIO;
dbus_connection_set_exit_on_disconnect(bus, FALSE);
if (private)
*private = false;
}
if ((r = sync_auth(bus, error)) < 0) {
dbus_connection_close(bus);
dbus_connection_unref(bus);
return r;
}
*_bus = bus;
return 0;
}
int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
DBusConnection *bus;
char *p = NULL;
int r;
assert(_bus);
assert(user || host);
if (user && host)
asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
else if (user)
asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
else if (host)
asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
if (!p) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
return -ENOMEM;
}
bus = dbus_connection_open_private(p, error);
free(p);
if (!bus)
return -EIO;
dbus_connection_set_exit_on_disconnect(bus, FALSE);
if ((r = sync_auth(bus, error)) < 0) {
dbus_connection_close(bus);
dbus_connection_unref(bus);
return r;
}
if (!dbus_bus_register(bus, error)) {
dbus_connection_close(bus);
dbus_connection_unref(bus);
return r;
}
*_bus = bus;
return 0;
}
int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
DBusConnection *bus;
int r;
assert(_bus);
/* Don't bother with PolicyKit if we are root */
if (geteuid() == 0)
return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
if (!(bus = dbus_connection_open_private("exec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error)))
return -EIO;
dbus_connection_set_exit_on_disconnect(bus, FALSE);
if ((r = sync_auth(bus, error)) < 0) {
dbus_connection_close(bus);
dbus_connection_unref(bus);
return r;
}
if (!dbus_bus_register(bus, error)) {
dbus_connection_close(bus);
dbus_connection_unref(bus);
return r;
}
*_bus = bus;
return 0;
}
const char *bus_error_message(const DBusError *error) {
assert(error);
/* Sometimes the D-Bus server is a little bit too verbose with
* its error messages, so let's override them here */
if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
return "Access denied";
return error->message;
}