chiark / gitweb /
logind: automatically deduce seat from display
authorLennart Poettering <lennart@poettering.net>
Mon, 27 Jun 2011 20:44:12 +0000 (22:44 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 27 Jun 2011 20:44:12 +0000 (22:44 +0200)
src/logind-dbus.c
src/logind-session.c
src/logind-user.c
src/pam-module.c
src/tty-ask-password-agent.c
src/util.c
src/util.h

index 136f610cb625b746931d166cad087e0aae6c73c4..050eb7160edde03b4a7b075208b2c53c5357ab57 100644 (file)
         "  <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;
index e71ff4f14e9aaca2ca5965653e4912ca4d8cb2ad..9fcbf460a3a2f40fdccbb7016dfa8cc0c3010a43 100644 (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;
         }
 
index 63033e0fd3a37e299b808b87814df44ff4e1a29c..dff317e6bda267323dc97ce90b0b1465f39f364c 100644 (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;
         }
 
index ad8ca91d03fe412c2b596b86d58c6ff8239f3c01..e1ad8c9bfade571dc1ea020c8bcb2d1c4910dd28 100644 (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,
index d7e1ebaef69b79cad16083190972ff982f6b743c..b620aa6ee3e5dece2d3ef4dd684f959272287f6d 100644 (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)
index 5d57d52dc8ba7763f5e9b52f699e8c839ad0eb60..278f0184de9f86ed9bce726d6ee201dfe7431202 100644 (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",
index ceabe92cf444f93c29b0047bfbe2d05127c03097..a26fb6f1777017e8bcbd9716d45de507dbeca4fb 100644 (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)