chiark / gitweb /
sd-login: add calls that retrieve credentials of peers connected to AF_UNIX peers
[elogind.git] / src / login / sd-login.c
index 875d134efcc0aa70befd417ed7476f1ab6c6c6e6..d24b2ed1fdd698f1b62bc04d5cdbe54b89c20df4 100644 (file)
 #include "util.h"
 #include "cgroup-util.h"
 #include "macro.h"
-#include "sd-login.h"
 #include "strv.h"
 #include "fileio.h"
+#include "login-shared.h"
+#include "sd-login.h"
 
 _public_ int sd_pid_get_session(pid_t pid, char **session) {
-        if (pid < 0)
-                return -EINVAL;
 
-        if (!session)
-                return -EINVAL;
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(session, -EINVAL);
 
         return cg_pid_get_session(pid, session);
 }
 
 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
 
-        if (pid < 0)
-                return -EINVAL;
-        if (!unit)
-                return -EINVAL;
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(unit, -EINVAL);
 
         return cg_pid_get_unit(pid, unit);
 }
 
 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
 
-        if (pid < 0)
-                return -EINVAL;
-        if (!unit)
-                return -EINVAL;
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(unit, -EINVAL);
 
         return cg_pid_get_user_unit(pid, unit);
 }
 
 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
 
-        if (pid < 0)
-                return -EINVAL;
-        if (!name)
-                return -EINVAL;
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(name, -EINVAL);
 
         return cg_pid_get_machine_name(pid, name);
 }
 
-_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
+_public_ int sd_pid_get_slice(pid_t pid, char **slice) {
 
-        if (pid < 0)
-                return -EINVAL;
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(slice, -EINVAL);
 
-        if (!uid)
-                return -EINVAL;
+        return cg_pid_get_slice(pid, slice);
+}
+
+_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
+
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(uid, -EINVAL);
 
         return cg_pid_get_owner_uid(pid, uid);
 }
 
+_public_ int sd_peer_get_session(int fd, char **session) {
+        struct ucred ucred;
+        int r;
+
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(session, -EINVAL);
+
+        r = getpeercred(fd, &ucred);
+        if (r < 0)
+                return r;
+
+        return cg_pid_get_session(ucred.pid, session);
+}
+
+_public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
+        struct ucred ucred;
+        int r;
+
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(uid, -EINVAL);
+
+        r = getpeercred(fd, &ucred);
+        if (r < 0)
+                return r;
+
+        return cg_pid_get_owner_uid(ucred.pid, uid);
+}
+
+_public_ int sd_peer_get_unit(int fd, char **unit) {
+        struct ucred ucred;
+        int r;
+
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(unit, -EINVAL);
+
+        r = getpeercred(fd, &ucred);
+        if (r < 0)
+                return r;
+
+        return cg_pid_get_unit(ucred.pid, unit);
+}
+
+_public_ int sd_peer_get_user_unit(int fd, char **unit) {
+        struct ucred ucred;
+        int r;
+
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(unit, -EINVAL);
+
+        r = getpeercred(fd, &ucred);
+        if (r < 0)
+                return r;
+
+        return cg_pid_get_user_unit(ucred.pid, unit);
+}
+
+_public_ int sd_peer_get_machine_name(int fd, char **machine) {
+        struct ucred ucred;
+        int r;
+
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(machine, -EINVAL);
+
+        r = getpeercred(fd, &ucred);
+        if (r < 0)
+                return r;
+
+        return cg_pid_get_machine_name(ucred.pid, machine);
+}
+
+_public_ int sd_peer_get_slice(int fd, char **slice) {
+        struct ucred ucred;
+        int r;
+
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(slice, -EINVAL);
+
+        r = getpeercred(fd, &ucred);
+        if (r < 0)
+                return r;
+
+        return cg_pid_get_slice(ucred.pid, slice);
+}
+
 _public_ int sd_uid_get_state(uid_t uid, char**state) {
-        char *p, *s = NULL;
+        _cleanup_free_ char *p = NULL;
+        char *s = NULL;
         int r;
 
-        if (!state)
-                return -EINVAL;
+        assert_return(state, -EINVAL);
 
         if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
-        free(p);
-
         if (r == -ENOENT) {
                 free(s);
                 s = strdup("offline");
                 if (!s)
                         return -ENOMEM;
 
-                *state = s;
-                return 0;
         } else if (r < 0) {
                 free(s);
                 return r;
@@ -121,8 +199,7 @@ _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat)
         int r;
         const char *variable;
 
-        if (!seat)
-                return -EINVAL;
+        assert_return(seat, -EINVAL);
 
         variable = require_active ? "ACTIVE_UID" : "UIDS";
 
@@ -216,17 +293,19 @@ static int file_of_session(const char *session, char **_p) {
 
         assert(_p);
 
-        if (session)
+        if (session) {
+                if (!session_id_valid(session))
+                        return -EINVAL;
+
                 p = strappend("/run/systemd/sessions/", session);
-        else {
-                char *buf;
+        else {
+                _cleanup_free_ char *buf = NULL;
 
                 r = sd_pid_get_session(0, &buf);
                 if (r < 0)
                         return r;
 
                 p = strappend("/run/systemd/sessions/", buf);
-                free(buf);
         }
 
         if (!p)
@@ -245,24 +324,38 @@ _public_ int sd_session_is_active(const char *session) {
                 return r;
 
         r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
-
         if (r < 0)
                 return r;
 
         if (!s)
                 return -EIO;
 
-        r = parse_boolean(s);
+        return parse_boolean(s);
+}
 
-        return r;
+_public_ int sd_session_is_remote(const char *session) {
+        int r;
+        _cleanup_free_ char *p = NULL, *s = NULL;
+
+        r = file_of_session(session, &p);
+        if (r < 0)
+                return r;
+
+        r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
+        if (r < 0)
+                return r;
+
+        if (!s)
+                return -EIO;
+
+        return parse_boolean(s);
 }
 
 _public_ int sd_session_get_state(const char *session, char **state) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         int r;
 
-        if (!state)
-                return -EINVAL;
+        assert_return(state, -EINVAL);
 
         r = file_of_session(session, &p);
         if (r < 0)
@@ -285,32 +378,27 @@ _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
         int r;
         _cleanup_free_ char *p = NULL, *s = NULL;
 
-        if (!uid)
-                return -EINVAL;
+        assert_return(uid, -EINVAL);
 
         r = file_of_session(session, &p);
         if (r < 0)
                 return r;
 
         r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
-
         if (r < 0)
                 return r;
 
         if (!s)
                 return -EIO;
 
-        r = parse_uid(s, uid);
-
-        return r;
+        return parse_uid(s, uid);
 }
 
 static int session_get_string(const char *session, const char *field, char **value) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         int r;
 
-        if (!value)
-                return -EINVAL;
+        assert_return(value, -EINVAL);
 
         r = file_of_session(session, &p);
         if (r < 0)
@@ -337,6 +425,23 @@ _public_ int sd_session_get_tty(const char *session, char **tty) {
         return session_get_string(session, "TTY", tty);
 }
 
+_public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
+        _cleanup_free_ char *vtnr_string = NULL;
+        unsigned u;
+        int r;
+
+        r = session_get_string(session, "VTNR", &vtnr_string);
+        if (r < 0)
+                return r;
+
+        r = safe_atou(vtnr_string, &u);
+        if (r < 0)
+                return r;
+
+        *vtnr = u;
+        return 0;
+}
+
 _public_ int sd_session_get_service(const char *session, char **service) {
         return session_get_string(session, "SERVICE", service);
 }
@@ -353,6 +458,14 @@ _public_ int sd_session_get_display(const char *session, char **display) {
         return session_get_string(session, "DISPLAY", display);
 }
 
+_public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
+        return session_get_string(session, "REMOTE_USER", remote_user);
+}
+
+_public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
+        return session_get_string(session, "REMOTE_HOST", remote_host);
+}
+
 static int file_of_seat(const char *seat, char **_p) {
         char *p;
         int r;
@@ -383,8 +496,7 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
         int r;
 
-        if (!session && !uid)
-                return -EINVAL;
+        assert_return(session || uid, -EINVAL);
 
         r = file_of_seat(seat, &p);
         if (r < 0)
@@ -495,6 +607,8 @@ static int seat_get_can(const char *seat, const char *variable) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         int r;
 
+        assert_return(variable, -EINVAL);
+
         r = file_of_seat(seat, &p);
         if (r < 0)
                 return r;
@@ -504,13 +618,10 @@ static int seat_get_can(const char *seat, const char *variable) {
                            NULL);
         if (r < 0)
                 return r;
+        if (!s)
+                return 0;
 
-        if (s)
-                r = parse_boolean(s);
-        else
-                r = 0;
-
-        return r;
+        return parse_boolean(s);
 }
 
 _public_ int sd_seat_can_multi_session(const char *seat) {
@@ -545,13 +656,13 @@ _public_ int sd_get_uids(uid_t **users) {
 
         for (;;) {
                 struct dirent *de;
-                union dirent_storage buf;
                 int k;
                 uid_t uid;
 
-                k = readdir_r(d, &buf.de, &de);
-                if (k != 0)
-                        return -k;
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0)
+                        return -errno;
 
                 if (!de)
                         break;
@@ -592,7 +703,55 @@ _public_ int sd_get_uids(uid_t **users) {
 }
 
 _public_ int sd_get_machine_names(char ***machines) {
-        return get_files_in_directory("/run/systemd/machines/", machines);
+        char **l = NULL, **a, **b;
+        int r;
+
+        assert_return(machines, -EINVAL);
+
+        r = get_files_in_directory("/run/systemd/machines/", &l);
+        if (r < 0)
+                return r;
+
+        if (l) {
+                r = 0;
+
+                /* Filter out the unit: symlinks */
+                for (a = l, b = l; *a; a++) {
+                        if (startswith(*a, "unit:"))
+                                free(*a);
+                        else {
+                                *b = *a;
+                                b++;
+                                r++;
+                        }
+                }
+
+                *b = NULL;
+        }
+
+        *machines = l;
+        return r;
+}
+
+_public_ int sd_machine_get_class(const char *machine, char **class) {
+        _cleanup_free_ char *c = NULL;
+        const char *p;
+        int r;
+
+        assert_return(filename_is_safe(machine), -EINVAL);
+        assert_return(class, -EINVAL);
+
+        p = strappenda("/run/systemd/machines/", machine);
+        r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
+        if (r < 0)
+                return r;
+        if (!c)
+                return -EIO;
+
+        *class = c;
+        c = NULL;
+
+        return 0;
 }
 
 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
@@ -607,8 +766,7 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
         int fd, k;
         bool good = false;
 
-        if (!m)
-                return -EINVAL;
+        assert_return(m, -EINVAL);
 
         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
         if (fd < 0)
@@ -666,8 +824,7 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
         int fd;
 
-        if (!m)
-                return NULL;
+        assert_return(m, NULL);
 
         fd = MONITOR_TO_FD(m);
         close_nointr(fd);
@@ -677,24 +834,21 @@ _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
 
 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
 
-        if (!m)
-                return -EINVAL;
+        assert_return(m, -EINVAL);
 
         return flush_fd(MONITOR_TO_FD(m));
 }
 
 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
 
-        if (!m)
-                return -EINVAL;
+        assert_return(m, -EINVAL);
 
         return MONITOR_TO_FD(m);
 }
 
 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
 
-        if (!m)
-                return -EINVAL;
+        assert_return(m, -EINVAL);
 
         /* For now we will only return POLLIN here, since we don't
          * need anything else ever for inotify.  However, let's have
@@ -705,10 +859,8 @@ _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
 
 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
 
-        if (!m)
-                return -EINVAL;
-        if (!timeout_usec)
-                return -EINVAL;
+        assert_return(m, -EINVAL);
+        assert_return(timeout_usec, -EINVAL);
 
         /* For now we will only return (uint64_t) -1, since we don't
          * need any timeout. However, let's have this API to keep our