X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Fsd-login.c;h=d24b2ed1fdd698f1b62bc04d5cdbe54b89c20df4;hp=4bc51e71a253ab4fea5fbcf8528ccb9b87868369;hb=bf34ab149f3038686bc75e1592179abac1700322;hpb=c84f5e4a825f17163ead0f60308d548b415334a5 diff --git a/src/login/sd-login.c b/src/login/sd-login.c index 4bc51e71a..d24b2ed1f 100644 --- a/src/login/sd-login.c +++ b/src/login/sd-login.c @@ -23,137 +23,165 @@ #include #include #include +#include #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) { - int r; - char *cgroup, *p; - - if (pid < 0) - return -EINVAL; - if (!session) - return -EINVAL; + assert_return(pid >= 0, -EINVAL); + assert_return(session, -EINVAL); - r = cg_pid_get_cgroup(pid, NULL, &cgroup); - if (r < 0) - return r; + return cg_pid_get_session(pid, session); +} - if (!startswith(cgroup, "/user/")) { - free(cgroup); - return -ENOENT; - } +_public_ int sd_pid_get_unit(pid_t pid, char **unit) { - p = strchr(cgroup + 6, '/'); - if (!p) { - free(cgroup); - return -ENOENT; - } + assert_return(pid >= 0, -EINVAL); + assert_return(unit, -EINVAL); - p++; - if (startswith(p, "shared/") || streq(p, "shared")) { - free(cgroup); - return -ENOENT; - } + return cg_pid_get_unit(pid, unit); +} - p = strndup(p, strcspn(p, "/")); - free(cgroup); +_public_ int sd_pid_get_user_unit(pid_t pid, char **unit) { - if (!p) - return -ENOMEM; + assert_return(pid >= 0, -EINVAL); + assert_return(unit, -EINVAL); - *session = p; - return 0; + return cg_pid_get_user_unit(pid, unit); } -_public_ int sd_pid_get_unit(pid_t pid, char **unit) { +_public_ int sd_pid_get_machine_name(pid_t pid, char **name) { - if (pid < 0) - return -EINVAL; + assert_return(pid >= 0, -EINVAL); + assert_return(name, -EINVAL); - if (!unit) - return -EINVAL; + return cg_pid_get_machine_name(pid, name); +} - return cg_pid_get_unit(pid, unit); +_public_ int sd_pid_get_slice(pid_t pid, char **slice) { + + assert_return(pid >= 0, -EINVAL); + assert_return(slice, -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; - char *root, *cgroup, *p, *cc; - struct stat st; - if (pid < 0) - return -EINVAL; + assert_return(fd >= 0, -EINVAL); + assert_return(session, -EINVAL); - if (!uid) - return -EINVAL; + r = getpeercred(fd, &ucred); + if (r < 0) + return r; + + return cg_pid_get_session(ucred.pid, session); +} - r = cg_pid_get_cgroup(pid, &root, &cgroup); +_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; - if (!startswith(cgroup, "/user/")) { - free(cgroup); - free(root); - return -ENOENT; - } + return cg_pid_get_owner_uid(ucred.pid, uid); +} - p = strchr(cgroup + 6, '/'); - if (!p) { - free(cgroup); - return -ENOENT; - } +_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); +} - p++; - p += strcspn(p, "/"); - *p = 0; +_public_ int sd_peer_get_user_unit(int fd, char **unit) { + struct ucred ucred; + int r; - r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc); - free(root); - free(cgroup); + assert_return(fd >= 0, -EINVAL); + assert_return(unit, -EINVAL); + r = getpeercred(fd, &ucred); if (r < 0) - return -ENOMEM; + return r; - r = lstat(cc, &st); - free(cc); + 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 -errno; + 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; - if (!S_ISDIR(st.st_mode)) - return -ENOTDIR; + assert_return(fd >= 0, -EINVAL); + assert_return(slice, -EINVAL); - *uid = st.st_uid; - return 0; + 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; @@ -165,13 +193,13 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) { } _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { - char *p, *w, *t, *state, *s = NULL; + char *w, *state; + _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL; size_t l; int r; const char *variable; - if (!seat) - return -EINVAL; + assert_return(seat, -EINVAL); variable = require_active ? "ACTIVE_UID" : "UIDS"; @@ -180,38 +208,26 @@ _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) return -ENOMEM; r = parse_env_file(p, NEWLINE, variable, &s, NULL); - free(p); - if (r < 0) { - free(s); + if (r < 0) return r; - } if (!s) return -EIO; - if (asprintf(&t, "%lu", (unsigned long) uid) < 0) { - free(s); + if (asprintf(&t, "%lu", (unsigned long) uid) < 0) return -ENOMEM; - } FOREACH_WORD(w, l, s, state) { - if (strncmp(t, w, l) == 0) { - free(s); - free(t); - + if (strneq(t, w, l)) return 1; - } } - free(s); - free(t); - return 0; } static int uid_get_array(uid_t uid, const char *variable, char ***array) { - char *p, *s = NULL; + _cleanup_free_ char *p = NULL, *s = NULL; char **a; int r; @@ -221,11 +237,7 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) { r = parse_env_file(p, NEWLINE, variable, &s, NULL); - free(p); - if (r < 0) { - free(s); - if (r == -ENOENT) { if (array) *array = NULL; @@ -242,7 +254,6 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) { } a = strv_split(s, " "); - free(s); if (!a) return -ENOMEM; @@ -282,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) @@ -304,104 +317,103 @@ static int file_of_session(const char *session, char **_p) { _public_ int sd_session_is_active(const char *session) { int r; - char *p, *s = NULL; + _cleanup_free_ char *p = NULL, *s = NULL; r = file_of_session(session, &p); if (r < 0) return r; r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); - free(p); - - if (r < 0) { - free(s); + if (r < 0) return r; - } if (!s) return -EIO; - r = parse_boolean(s); - free(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) { - char *p, *s = NULL; + _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) return r; r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); - free(p); - if (r < 0) { - free(s); + if (r < 0) return r; - } else if (!s) + else if (!s) return -EIO; *state = s; + s = NULL; + return 0; } _public_ int sd_session_get_uid(const char *session, uid_t *uid) { int r; - char *p, *s = NULL; + _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); - free(p); - - if (r < 0) { - free(s); + if (r < 0) return r; - } if (!s) return -EIO; - r = parse_uid(s, uid); - free(s); - - return r; + return parse_uid(s, uid); } static int session_get_string(const char *session, const char *field, char **value) { - char *p, *s = NULL; + _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) return r; r = parse_env_file(p, NEWLINE, field, &s, NULL); - free(p); - if (r < 0) { - free(s); + if (r < 0) return r; - } if (isempty(s)) return -ENOENT; *value = s; + s = NULL; return 0; } @@ -413,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); } @@ -429,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; @@ -438,29 +475,28 @@ static int file_of_seat(const char *seat, char **_p) { if (seat) p = strappend("/run/systemd/seats/", seat); else { - char *buf; + _cleanup_free_ char *buf = NULL; r = sd_session_get_seat(NULL, &buf); if (r < 0) return r; p = strappend("/run/systemd/seats/", buf); - free(buf); } if (!p) return -ENOMEM; *_p = p; + p = NULL; return 0; } _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { - char *p, *s = NULL, *t = NULL; + _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) @@ -470,46 +506,33 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { "ACTIVE", &s, "ACTIVE_UID", &t, NULL); - free(p); - - if (r < 0) { - free(s); - free(t); + if (r < 0) return r; - } - if (session && !s) { - free(t); + if (session && !s) return -ENOENT; - } - if (uid && !t) { - free(s); + if (uid && !t) return -ENOENT; - } if (uid && t) { r = parse_uid(t, uid); - if (r < 0) { - free(t); - free(s); + if (r < 0) return r; - } } - free(t); - - if (session && s) + if (session && s) { *session = s; - else - free(s); + s = NULL; + } return 0; } _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) { - char *p, *s = NULL, *t = NULL, **a = NULL; - uid_t *b = NULL; + _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; + _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ uid_t *b = NULL; unsigned n = 0; int r; @@ -521,25 +544,16 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui "SESSIONS", &s, "ACTIVE_SESSIONS", &t, NULL); - free(p); - if (r < 0) { - free(s); - free(t); + if (r < 0) return r; - } if (s) { a = strv_split(s, " "); - if (!a) { - free(s); - free(t); + if (!a) return -ENOMEM; - } } - free(s); - if (uids && t) { char *w, *state; size_t l; @@ -547,30 +561,22 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui FOREACH_WORD(w, l, t, state) n++; - if (n == 0) - b = NULL; - else { + if (n > 0) { unsigned i = 0; b = new(uid_t, n); - if (!b) { - strv_free(a); + if (!b) return -ENOMEM; - } FOREACH_WORD(w, l, t, state) { - char *k; + _cleanup_free_ char *k = NULL; k = strndup(w, l); - if (!k) { - free(t); - free(b); - strv_free(a); + if (!k) return -ENOMEM; - } r = parse_uid(k, b + i); - free(k); + if (r < 0) continue; @@ -579,17 +585,17 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui } } - free(t); - r = strv_length(a); - if (sessions) + if (sessions) { *sessions = a; - else - strv_free(a); + a = NULL; + } - if (uids) + if (uids) { *uids = b; + b = NULL; + } if (n_uids) *n_uids = n; @@ -598,9 +604,11 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui } static int seat_get_can(const char *seat, const char *variable) { - char *p, *s = NULL; + _cleanup_free_ char *p = NULL, *s = NULL; int r; + assert_return(variable, -EINVAL); + r = file_of_seat(seat, &p); if (r < 0) return r; @@ -608,20 +616,12 @@ static int seat_get_can(const char *seat, const char *variable) { r = parse_env_file(p, NEWLINE, variable, &s, NULL); - free(p); - - if (r < 0) { - free(s); + if (r < 0) return r; - } - - if (s) { - r = parse_boolean(s); - free(s); - } else - r = 0; + if (!s) + return 0; - return r; + return parse_boolean(s); } _public_ int sd_seat_can_multi_session(const char *seat) { @@ -645,10 +645,10 @@ _public_ int sd_get_sessions(char ***sessions) { } _public_ int sd_get_uids(uid_t **users) { - DIR *d; + _cleanup_closedir_ DIR *d; int r = 0; unsigned n = 0; - uid_t *l = NULL; + _cleanup_free_ uid_t *l = NULL; d = opendir("/run/systemd/users/"); if (!d) @@ -656,15 +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) { - r = -k; - goto finish; - } + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; if (!de) break; @@ -684,10 +682,8 @@ _public_ int sd_get_uids(uid_t **users) { n = MAX(16, 2*r); t = realloc(l, sizeof(uid_t) * n); - if (!t) { - r = -ENOMEM; - goto finish; - } + if (!t) + return -ENOMEM; l = t; } @@ -698,19 +694,66 @@ _public_ int sd_get_uids(uid_t **users) { r++; } -finish: - if (d) - closedir(d); + if (users) { + *users = l; + l = NULL; + } - if (r >= 0) { - if (users) - *users = l; - } else - free(l); + return r; +} + +_public_ int sd_get_machine_names(char ***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) { return (int) (unsigned long) m - 1; } @@ -723,12 +766,11 @@ _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) - return errno; + return -errno; if (!category || streq(category, "seat")) { k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE); @@ -760,6 +802,16 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { good = true; } + if (!category || streq(category, "machine")) { + k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + if (!good) { close_nointr(fd); return -EINVAL; @@ -772,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); @@ -783,16 +834,37 @@ _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) { + + 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 + * this API to keep our options open should we later on need + * it. */ + return POLLIN; +} + +_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) { + + 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 + * options open should we later on need it. */ + *timeout_usec = (uint64_t) -1; + return 0; +}