ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}"
{% if HAVE_ACL %}
-TAG=="uaccess", ENV{MAJOR}!="", RUN{builtin}+="uaccess"
+TAG=="uaccess|xaccess", ENV{MAJOR}!="", RUN{builtin}+="uaccess"
{% endif %}
LABEL="seat_late_end"
#include "tmpfile-util.h"
#include "udev-util.h"
#include "user-record.h"
+#include "user-util.h"
int seat_new(Manager *m, const char *id, Seat **ret) {
_cleanup_(seat_freep) Seat *s = NULL;
static int static_node_acl(Seat *s) {
#if HAVE_ACL
int r, ret = 0;
- uid_t uid;
+ _cleanup_set_free_ Set *uids = NULL;
assert(s);
- if (s->active)
- uid = s->active->user->user_record->uid;
- else
- uid = 0;
+ if (s->active) {
+ r = set_ensure_put(&uids, NULL, UID_TO_PTR(s->active->user->user_record->uid));
+ if (r < 0)
+ return log_oom();
+ }
_cleanup_closedir_ DIR *dir = opendir("/run/udev/static_node-tags/uaccess/");
if (!dir) {
if (!ERRNO_IS_NEG_DEVICE_ABSENT_OR_EMPTY(r))
log_debug_errno(r, "Failed to check if '/run/udev/static_node-tags/uaccess/%s' points to a static device node, ignoring: %m", de->d_name);
- r = devnode_acl(fd, uid);
+ r = devnode_acl(fd, uids);
if (r >= 0 || r == -ENOENT)
continue;
_cleanup_free_ char *node = NULL;
(void) fd_get_path(fd, &node);
- if (uid != 0) {
+ if (!set_isempty(uids)) {
RET_GATHER(ret, log_debug_errno(r, "Failed to apply ACL on '%s': %m", node ?: de->d_name));
/* Better be safe than sorry and reset ACL */
- r = devnode_acl(fd, /* uid= */ 0);
+ r = devnode_acl(fd, /* uids= */ NULL);
if (r >= 0 || r == -ENOENT)
continue;
}
#include <unistd.h>
#include "sd-bus.h"
+#include "sd-device.h"
#include "sd-event.h"
#include "sd-messages.h"
#include "sd-varlink.h"
#include "bus-error.h"
#include "bus-util.h"
#include "daemon-util.h"
+#include "device-util.h"
#include "devnum-util.h"
#include "env-file.h"
#include "errno-util.h"
}
}
+static int trigger_xaccess(void) {
+ int r;
+
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ r = sd_device_enumerator_new(&e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_tag(e, "xaccess");
+ if (r < 0)
+ return r;
+
+ FOREACH_DEVICE(e, d) {
+ /* Verify that the tag is still in place. */
+ r = sd_device_has_current_tag(d, "xaccess");
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ /* In case people mistag devices without nodes, we need to ignore this. */
+ r = sd_device_get_devname(d, NULL);
+ if (r == -ENOENT)
+ continue;
+ if (r < 0)
+ return r;
+
+ sd_id128_t uuid;
+ r = sd_device_trigger_with_uuid(d, SD_DEVICE_CHANGE, &uuid);
+ if (r < 0) {
+ log_device_debug_errno(d, r, "Failed to trigger 'change' event, ignoring: %m");
+ continue;
+ }
+
+ log_device_debug(d, "Triggered synthetic event (ACTION=change, UUID=%s).", SD_ID128_TO_UUID_STRING(uuid));
+ }
+
+ return 0;
+}
+
int session_save(Session *s) {
int r;
if (s->seat)
(void) seat_save(s->seat);
+ if (s->extra_device_access)
+ (void) trigger_xaccess();
+
/* Send signals */
(void) session_send_signal(s, true);
(void) user_send_changed(s->user, "Display");
(void) session_save(s);
(void) user_save(s->user);
+ if (s->extra_device_access)
+ (void) trigger_xaccess();
+
return r;
}
#include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h"
+#include "set.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
DLSYM_ARG(acl_to_any_text));
}
-int devnode_acl(int fd, uid_t uid) {
- bool changed = false, found = false;
+int devnode_acl(int fd, const Set *uids) {
+ _cleanup_set_free_ Set *found = NULL;
+ bool changed = false;
int r;
assert(fd >= 0);
if (tag != ACL_USER)
continue;
- if (uid > 0) {
+ if (!set_isempty(uids)) {
uid_t *u = sym_acl_get_qualifier(entry);
if (!u)
return -errno;
- if (*u == uid) {
+ if (set_contains(uids, UID_TO_PTR(*u))) {
acl_permset_t permset;
if (sym_acl_get_permset(entry, &permset) < 0)
return -errno;
changed = true;
}
- found = true;
+ r = set_ensure_put(&found, NULL, UID_TO_PTR(*u));
+ if (r < 0)
+ return r;
+
continue;
}
}
if (r < 0)
return -errno;
- if (!found && uid > 0) {
+ void *p;
+ SET_FOREACH(p, uids) {
+ uid_t uid = PTR_TO_UID(p);
+
+ if (uid == 0)
+ continue;
+
+ if (set_contains(found, UID_TO_PTR(uid)))
+ continue;
+
if (sym_acl_create_entry(&acl, &entry) < 0)
return -errno;
int dlopen_libacl(void);
-int devnode_acl(int fd, uid_t uid);
+int devnode_acl(int fd, const Set *uids);
int calc_acl_mask_if_needed(acl_t *acl_p);
int add_base_acls_if_needed(acl_t *acl_p, const char *path);
return -EOPNOTSUPP;
}
-static inline int devnode_acl(int fd, uid_t uid) {
+static inline int devnode_acl(int fd, const Set *uids) {
return -EOPNOTSUPP;
}
#include "sd-login.h"
#include "acl-util.h"
+#include "alloc-util.h"
#include "device-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "login-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
#include "udev-builtin.h"
+#include "user-util.h"
static int builtin_uaccess(UdevEvent *event, int argc, char *argv[]) {
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
- int r, k;
+ _cleanup_strv_free_ char **sessions = NULL;
+ _cleanup_set_free_ Set *uids = NULL;
+ uid_t uid;
+ int r = 0, k;
if (event->event_mode != EVENT_UDEV_WORKER) {
log_device_debug(dev, "Running in test mode, skipping execution of 'uaccess' builtin command.");
return ignore ? 0 : fd;
}
- const char *seat;
- r = device_get_seat(dev, &seat);
+ r = sd_device_has_tag(dev, "uaccess");
if (r < 0)
- return log_device_error_errno(dev, r, "Failed to get seat: %m");
+ return log_device_error_errno(dev, r, "Failed to query uaccess tag: %m");
- uid_t uid;
- r = sd_seat_get_active(seat, /* ret_session= */ NULL, &uid);
- if (r < 0) {
+ if (r > 0) {
+ const char *seat;
+ r = device_get_seat(dev, &seat);
+ if (r < 0)
+ return log_device_error_errno(dev, r, "Failed to get seat: %m");
+
+ r = sd_seat_get_active(seat, /* ret_session= */ NULL, &uid);
if (IN_SET(r, -ENXIO, -ENODATA))
/* No active session on this seat */
r = 0;
- else
- log_device_error_errno(dev, r, "Failed to determine active user on seat %s: %m", seat);
+ else if (r < 0)
+ log_device_error_errno(dev, r, "Failed to determine active user on seat %s, ignoring: %m", seat);
+ else {
+ if (set_ensure_put(&uids, NULL, UID_TO_PTR(uid)) < 0)
+ return log_oom();
+ }
+ }
- goto reset;
+ r = sd_device_has_tag(dev, "xaccess");
+ if (r < 0)
+ return log_device_error_errno(dev, r, "Failed to query device xaccess tag: %m");
+
+ if (r > 0) {
+ r = sd_get_sessions(&sessions);
+ if (r < 0)
+ return log_device_error_errno(dev, r, "Failed to list sessions: %m");
+
+ STRV_FOREACH(s, sessions) {
+ _cleanup_free_ char *state = NULL;
+ if (sd_session_get_state(*s, &state) < 0) {
+ log_device_debug_errno(dev, r, "Failed to query state for session %s, ignoring: %m", *s);
+ continue;
+ }
+ if (streq(state, "closing"))
+ continue;
+ r = sd_session_has_extra_device_access(*s);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to query extra device access for session %s, ignoring: %m", *s);
+ continue;
+ }
+ if (r == 0)
+ continue;
+ if (sd_session_get_uid(*s, &uid) < 0) {
+ log_device_debug_errno(dev, r, "Failed to query uid for session %s, ignoring: %m", *s);
+ continue;
+ }
+ if (set_ensure_put(&uids, NULL, UID_TO_PTR(uid)) < 0)
+ return log_oom();
+ }
}
- r = devnode_acl(fd, uid);
+ r = devnode_acl(fd, uids);
if (r < 0) {
log_device_full_errno(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL: %m");
goto reset;
reset:
/* Better be safe than sorry and reset ACL */
- k = devnode_acl(fd, /* uid= */ 0);
+ k = devnode_acl(fd, /* uids= */ NULL);
if (k < 0)
RET_GATHER(r, log_device_full_errno(dev, k == -ENOENT ? LOG_DEBUG : LOG_ERR, k, "Failed to flush ACLs: %m"));