From: Lennart Poettering Date: Mon, 27 Jun 2011 20:44:12 +0000 (+0200) Subject: logind: automatically deduce seat from display X-Git-Tag: v30~141 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=4d6d6518c301c844be59c1b3a0d2092a3218572f logind: automatically deduce seat from display --- diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 136f610cb..050eb7160 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -53,9 +53,10 @@ " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \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; diff --git a/src/logind-session.c b/src/logind-session.c index e71ff4f14..9fcbf460a 100644 --- a/src/logind-session.c +++ b/src/logind-session.c @@ -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; } diff --git a/src/logind-user.c b/src/logind-user.c index 63033e0fd..dff317e6b 100644 --- a/src/logind-user.c +++ b/src/logind-user.c @@ -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; } diff --git a/src/pam-module.c b/src/pam-module.c index ad8ca91d0..e1ad8c9bf 100644 --- a/src/pam-module.c +++ b/src/pam-module.c @@ -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, diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c index d7e1ebaef..b620aa6ee 100644 --- a/src/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent.c @@ -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) diff --git a/src/util.c b/src/util.c index 5d57d52dc..278f0184d 100644 --- a/src/util.c +++ b/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", diff --git a/src/util.h b/src/util.h index ceabe92cf..a26fb6f17 100644 --- a/src/util.h +++ b/src/util.h @@ -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)