logind: automatically deduce seat from display

This commit is contained in:
Lennart Poettering 2011-06-27 22:44:12 +02:00
parent cd58752a15
commit 4d6d6518c3
7 changed files with 165 additions and 30 deletions

View file

@ -53,9 +53,10 @@
" <method name=\"CreateSession\">\n" \
" <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
" <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
" <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
" <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
@ -177,7 +178,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
DBusMessageIter iter;
int r;
char *id = NULL, *p;
int vtnr = -1;
uint32_t vtnr = 0;
int pipe_fds[2] = { -1, -1 };
DBusMessage *reply = NULL;
bool b;
@ -227,6 +228,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
return -ENOENT;
}
if (!dbus_message_iter_next(&iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
return -EINVAL;
dbus_message_iter_get_basic(&iter, &vtnr);
if (!dbus_message_iter_next(&iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return -EINVAL;
@ -234,20 +241,36 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
dbus_message_iter_get_basic(&iter, &tty);
if (tty_is_vc(tty)) {
int v;
if (!s)
s = m->vtconsole;
else if (s != m->vtconsole)
return -EINVAL;
vtnr = vtnr_from_tty(tty);
v = vtnr_from_tty(tty);
if (v <= 0)
return v < 0 ? v : -EINVAL;
if (vtnr <= 0)
return vtnr < 0 ? vtnr : -EINVAL;
vtnr = (uint32_t) v;
else if (vtnr != (uint32_t) v)
return -EINVAL;
} else if (s == m->vtconsole)
} else if (!isempty(tty) && seat_is_vtconsole(s))
return -EINVAL;
if (s) {
if (seat_is_vtconsole(s)) {
if (vtnr <= 0 || vtnr > 63)
return -EINVAL;
} else {
if (vtnr > 0)
return -EINVAL;
}
}
if (!dbus_message_iter_next(&iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return -EINVAL;

View file

@ -325,14 +325,6 @@ int session_activate(Session *s) {
return seat_apply_acls(s->seat, old_active);
}
bool x11_display_is_local(const char *display) {
assert(display);
return
display[0] == ':' &&
display[1] >= '0' &&
display[1] <= '9';
}
static int session_link_x11_socket(Session *s) {
char *t, *f, *c;
@ -345,7 +337,7 @@ static int session_link_x11_socket(Session *s) {
if (s->user->display)
return 0;
if (!s->display || !x11_display_is_local(s->display))
if (!s->display || !display_is_local(s->display))
return 0;
k = strspn(s->display+1, "0123456789");
@ -447,9 +439,9 @@ static int session_create_cgroup(Session *s) {
r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
if (r < 0) {
log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
free(p);
s->cgroup_path = NULL;
log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
return r;
}

View file

@ -177,7 +177,7 @@ int user_load(User *u) {
free(display);
}
if (s && s->display && x11_display_is_local(s->display))
if (s && s->display && display_is_local(s->display))
u->display = s;
return r;
@ -234,9 +234,9 @@ static int user_create_cgroup(User *u) {
r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
if (r < 0) {
log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
free(p);
u->cgroup_path = NULL;
log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
return r;
}

View file

@ -38,6 +38,7 @@
#include "strv.h"
#include "dbus-common.h"
#include "def.h"
#include "socket-util.h"
static int parse_argv(pam_handle_t *handle,
int argc, const char **argv,
@ -299,6 +300,71 @@ static bool check_user_lists(
return false;
}
static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) {
char *p = NULL;
int r;
int fd;
union sockaddr_union sa;
struct ucred ucred;
socklen_t l;
char *tty;
int v;
assert(display);
assert(seat);
assert(vtnr);
/* We deduce the X11 socket from the display name, then use
* SO_PEERCRED to determine the X11 server process, ask for
* the controlling tty of that and if it's a VC then we know
* the seat and the virtual terminal. Sounds ugly, is only
* semi-ugly. */
r = socket_from_display(display, &p);
if (r < 0)
return r;
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (fd < 0) {
free(p);
return -errno;
}
zero(sa);
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, p, sizeof(sa.un.sun_path)-1);
free(p);
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
close_nointr_nofail(fd);
return -errno;
}
l = sizeof(ucred);
r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
close_nointr_nofail(fd);
if (r < 0)
return -errno;
r = get_ctty(ucred.pid, NULL, &tty);
if (r < 0)
return r;
v = vtnr_from_tty(tty);
free(tty);
if (v < 0)
return v;
else if (v == 0)
return -ENOENT;
*seat = "seat0";
*vtnr = (uint32_t) v;
return 0;
}
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
@ -306,7 +372,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
struct passwd *pw;
bool kill_processes = false, debug = false;
const char *username, *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type;
const char *username, *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type, *cvtnr = NULL;
char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL;
DBusError error;
uint32_t uid, pid;
@ -317,6 +383,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
DBusMessage *m = NULL, *reply = NULL;
dbus_bool_t remote;
int r;
uint32_t vtnr = 0;
assert(handle);
@ -373,7 +440,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
pam_get_item(handle, PAM_TTY, (const void**) &tty);
pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
seat = pam_getenv(handle, "XDG_SEAT");
seat = pam_getenv(handle, "LOGIN_SEAT");
cvtnr = pam_getenv(handle, "LOGIN_VTNR");
service = strempty(service);
tty = strempty(tty);
@ -392,6 +460,12 @@ _public_ PAM_EXTERN int pam_sm_open_session(
tty = "";
}
if (!isempty(cvtnr))
safe_atou32(cvtnr, &vtnr);
if (!isempty(display) && isempty(seat) && vtnr <= 0)
get_seat_from_display(display, &seat, &vtnr);
type = !isempty(display) ? "x11" :
!isempty(tty) ? "tty" : "other";
@ -403,6 +477,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
DBUS_TYPE_STRING, &service,
DBUS_TYPE_STRING, &type,
DBUS_TYPE_STRING, &seat,
DBUS_TYPE_UINT32, &vtnr,
DBUS_TYPE_STRING, &tty,
DBUS_TYPE_STRING, &display,
DBUS_TYPE_BOOLEAN, &remote,

View file

@ -433,7 +433,8 @@ static int wall_tty_block(void) {
int fd, r;
dev_t devnr;
if ((r = get_ctty_devnr(&devnr)) < 0)
r = get_ctty_devnr(0, &devnr);
if (r < 0)
return -r;
if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0)

View file

@ -3114,23 +3114,28 @@ int getttyname_harder(int fd, char **r) {
if (streq(s, "tty")) {
free(s);
return get_ctty(r, NULL);
return get_ctty(0, NULL, r);
}
*r = s;
return 0;
}
int get_ctty_devnr(dev_t *d) {
int get_ctty_devnr(pid_t pid, dev_t *d) {
int k;
char line[LINE_MAX], *p;
char line[LINE_MAX], *p, *fn;
unsigned long ttynr;
FILE *f;
if (!(f = fopen("/proc/self/stat", "r")))
if (asprintf(&fn, "/proc/%lu/stat", (unsigned long) (pid <= 0 ? getpid() : pid)) < 0)
return -ENOMEM;
f = fopen(fn, "re");
free(fn);
if (!f)
return -errno;
if (!(fgets(line, sizeof(line), f))) {
if (!fgets(line, sizeof(line), f)) {
k = -errno;
fclose(f);
return k;
@ -3138,7 +3143,8 @@ int get_ctty_devnr(dev_t *d) {
fclose(f);
if (!(p = strrchr(line, ')')))
p = strrchr(line, ')');
if (!p)
return -EIO;
p++;
@ -3156,14 +3162,15 @@ int get_ctty_devnr(dev_t *d) {
return 0;
}
int get_ctty(char **r, dev_t *_devnr) {
int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
int k;
char fn[PATH_MAX], *s, *b, *p;
dev_t devnr;
assert(r);
if ((k = get_ctty_devnr(&devnr)) < 0)
k = get_ctty_devnr(pid, &devnr);
if (k < 0)
return k;
snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
@ -5123,6 +5130,40 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
return 0;
}
bool display_is_local(const char *display) {
assert(display);
return
display[0] == ':' &&
display[1] >= '0' &&
display[1] <= '9';
}
int socket_from_display(const char *display, char **path) {
size_t k;
char *f, *c;
assert(display);
assert(path);
if (!display_is_local(display))
return -EINVAL;
k = strspn(display+1, "0123456789");
f = new(char, sizeof("/tmp/.X11-unix/X") + k);
if (!f)
return -ENOMEM;
c = stpcpy(f, "/tmp/.X11-unix/X");
memcpy(c, display+1, k);
c[k] = 0;
*path = f;
return 0;
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",

View file

@ -353,8 +353,8 @@ char* getlogname_malloc(void);
int getttyname_malloc(int fd, char **r);
int getttyname_harder(int fd, char **r);
int get_ctty_devnr(dev_t *d);
int get_ctty(char **r, dev_t *_devnr);
int get_ctty_devnr(pid_t pid, dev_t *d);
int get_ctty(pid_t, dev_t *_devnr, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
@ -442,6 +442,9 @@ int hwclock_set_time(const struct tm *tm);
int audit_session_from_pid(pid_t pid, uint32_t *id);
bool display_is_local(const char *display);
int socket_from_display(const char *display, char **path);
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)