mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-13 13:17:43 +03:00
logind: automatically deduce seat from display
This commit is contained in:
parent
cd58752a15
commit
4d6d6518c3
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
57
src/util.c
57
src/util.c
@ -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",
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user