Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:13.1
ConsoleKit
import-udev-acl-tool-from-udev.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File import-udev-acl-tool-from-udev.patch of Package ConsoleKit
From d491e4017d3a098b6a2a4fe5a73989c172dfa035 Mon Sep 17 00:00:00 2001 From: Michael Biebl <biebl@debian.org> Date: Mon, 19 Mar 2012 01:25:57 +0100 Subject: [PATCH] Import udev-acl tool from udev The udev-acl tool has been removed from udev in version 182. Add this tool to ConsoleKit for systems which don't use systemd-logind. --- configure.ac | 21 +++ tools/.gitignore | 1 + tools/70-udev-acl.rules | 76 +++++++++ tools/Makefile.am | 11 ++ tools/udev-acl.c | 430 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 539 insertions(+) create mode 100644 tools/70-udev-acl.rules create mode 100644 tools/udev-acl.c Index: ConsoleKit-0.4.5/configure.ac =================================================================== --- ConsoleKit-0.4.5.orig/configure.ac +++ ConsoleKit-0.4.5/configure.ac @@ -16,6 +16,7 @@ AC_GNU_SOURCE AC_ISC_POSIX AC_PROG_CC +AM_PROG_CC_C_O AC_STDC_HEADERS AC_DISABLE_STATIC AC_PROG_LIBTOOL @@ -233,6 +234,27 @@ if test "x$enable_pam_module" = "xyes"; fi AM_CONDITIONAL(ENABLE_PAM_MODULE, test "x$enable_pam_module" = "xyes") +dnl ------------------------------------------------------------------------------ +dnl udev-acl - apply ACLs for users with local forground sessions +dnl ------------------------------------------------------------------------------ +AC_ARG_ENABLE([udev-acl], + AS_HELP_STRING([--enable-udev-acl], [enable local user acl permissions support @<:@default=disabled@:>@]), + [], [enable_udev_acl=no]) +AS_IF([test "x$enable_udev_acl" = "xyes"], [ + + PKG_CHECK_MODULES([UDEV_ACL], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0 libudev]) + AC_CHECK_LIB([acl], [acl_init], [UDEV_ACL_LIBS="$UDEV_ACL_LIBS -lacl"], AC_MSG_ERROR([libacl not found])) + AC_CHECK_HEADER([acl/libacl.h], [:], AC_MSG_ERROR([libacl header not found])) + _udevdir=$($PKG_CONFIG --variable=udevdir udev) + if test -z "$_udevdir"; then + UDEVDIR="$_udevdir" + else + UDEVDIR="/usr/lib/udev" + fi +]) +AM_CONDITIONAL([ENABLE_UDEV_ACL], [test "x$enable_udev_acl" = "xyes"]) + + dnl --------------------------------------------------------------------------- dnl - Install directory for PAM security module dnl --------------------------------------------------------------------------- @@ -445,6 +467,7 @@ echo " Build backend: ${CK_BACKEND} PAM module dir: ${PAM_MODULE_DIR} Build PAM module: ${msg_pam_module} + Build udev-acl: ${enable_udev_acl} Build docs: ${enable_docbook_docs} PolicyKit support ${have_polkit} Index: ConsoleKit-0.4.5/tools/70-udev-acl.rules =================================================================== --- /dev/null +++ ConsoleKit-0.4.5/tools/70-udev-acl.rules @@ -0,0 +1,76 @@ +# do not edit this file, it will be overwritten on update + +# Do not use TAG+="uaccess" outside of this file. This variable is private to +# udev-acl of this udev release and may be replaced at any time. + +ENV{MAJOR}=="", GOTO="acl_end" +ACTION=="remove", GOTO="acl_apply" + +# systemd replaces udev-acl entirely, skip if active +TEST=="/sys/fs/cgroup/systemd", TAG=="uaccess", GOTO="acl_end" + +# PTP/MTP protocol devices, cameras, portable media players +SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess" + +# digicams with proprietary protocol +ENV{ID_GPHOTO2}=="*?", TAG+="uaccess" + +# SCSI and USB scanners +ENV{libsane_matched}=="yes", TAG+="uaccess" + +# HPLIP devices (necessary for ink level check and HP tool maintenance) +ENV{ID_HPLIP}=="1", TAG+="uaccess" + +# optical drives +SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess" +SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess" + +# sound devices +SUBSYSTEM=="sound", TAG+="uaccess" + +# ffado is an userspace driver for firewire sound cards +SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess" + +# webcams, frame grabber, TV cards +SUBSYSTEM=="video4linux", TAG+="uaccess" +SUBSYSTEM=="dvb", TAG+="uaccess" + +# IIDC devices: industrial cameras and some webcams +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="uaccess" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" +# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" + +# DRI video devices +SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess" + +# KVM +SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" + +# smart-card readers +ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess" + +# PDA devices +ENV{ID_PDA}=="*?", TAG+="uaccess" + +# Programmable remote control +ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess" + +# joysticks +SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess" + +# color measurement devices +ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess" + +# DDC/CI device, usually high-end monitors such as the DreamColor +ENV{DDC_DEVICE}=="*?", TAG+="uaccess" + +# media player raw devices (for user-mode drivers, Android SDK, etc.) +SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess" + +# apply ACL for all locally logged in users +LABEL="acl_apply", TAG=="uaccess", TEST=="/var/run/ConsoleKit/database", \ + RUN+="udev-acl --action=$env{ACTION} --device=$env{DEVNAME}" + +LABEL="acl_end" Index: ConsoleKit-0.4.5/tools/Makefile.am =================================================================== --- ConsoleKit-0.4.5.orig/tools/Makefile.am +++ ConsoleKit-0.4.5/tools/Makefile.am @@ -143,6 +143,17 @@ ck_get_x11_display_device_LDADD = \ $(top_builddir)/src/libck.la \ $(NULL) +if ENABLE_UDEV_ACL +udevdir = $(UDEVDIR) +udevrulesdir = $(UDEVDIR)/rules.d + +dist_udevrules_DATA = 70-udev-acl.rules +udev_PROGRAMS = udev-acl + +udev_acl_SOURCES = udev-acl.c +udev_acl_LDADD = $(UDEV_ACL_LIBS) +udev_acl_CFLAGS = $(UDEV_ACL_CFLAGS) +endif EXTRA_DIST = \ $(NULL) Index: ConsoleKit-0.4.5/tools/udev-acl.c =================================================================== --- /dev/null +++ ConsoleKit-0.4.5/tools/udev-acl.c @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2009 Kay Sievers <kay.sievers@vrfy.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details: + */ + +#include <acl/libacl.h> +#include <sys/stat.h> +#include <errno.h> +#include <getopt.h> +#include <glib.h> +#include <inttypes.h> +#include <libudev.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int debug; + +enum{ + ACTION_NONE = 0, + ACTION_REMOVE, + ACTION_ADD, + ACTION_CHANGE +}; + +static int set_facl(const char* filename, uid_t uid, int add) +{ + int get; + acl_t acl; + acl_entry_t entry = NULL; + acl_entry_t e; + acl_permset_t permset; + int ret; + + /* don't touch ACLs for root */ + if (uid == 0) + return 0; + + /* read current record */ + acl = acl_get_file(filename, ACL_TYPE_ACCESS); + if (!acl) + return -1; + + /* locate ACL_USER entry for uid */ + get = acl_get_entry(acl, ACL_FIRST_ENTRY, &e); + while (get == 1) { + acl_tag_t t; + + acl_get_tag_type(e, &t); + if (t == ACL_USER) { + uid_t *u; + + u = (uid_t*)acl_get_qualifier(e); + if (u == NULL) { + ret = -1; + goto out; + } + if (*u == uid) { + entry = e; + acl_free(u); + break; + } + acl_free(u); + } + + get = acl_get_entry(acl, ACL_NEXT_ENTRY, &e); + } + + /* remove ACL_USER entry for uid */ + if (!add) { + if (entry == NULL) { + ret = 0; + goto out; + } + acl_delete_entry(acl, entry); + goto update; + } + + /* create ACL_USER entry for uid */ + if (entry == NULL) { + ret = acl_create_entry(&acl, &entry); + if (ret != 0) + goto out; + acl_set_tag_type(entry, ACL_USER); + acl_set_qualifier(entry, &uid); + } + + /* add permissions for uid */ + acl_get_permset(entry, &permset); + acl_add_perm(permset, ACL_READ|ACL_WRITE); +update: + /* update record */ + if (debug) + printf("%c%u %s\n", add ? '+' : '-', uid, filename); + acl_calc_mask(&acl); + ret = acl_set_file(filename, ACL_TYPE_ACCESS, acl); + if (ret != 0) + goto out; +out: + acl_free(acl); + return ret; +} + +/* check if a given uid is listed */ +static int uid_in_list(GSList *list, uid_t uid) +{ + GSList *l; + + for (l = list; l != NULL; l = g_slist_next(l)) + if (uid == GPOINTER_TO_UINT(l->data)) + return 1; + return 0; +} + +/* return list of current uids of local active sessions */ +static GSList *uids_with_local_active_session(const char *own_id) +{ + GSList *list = NULL; + GKeyFile *keyfile; + + keyfile = g_key_file_new(); + if (g_key_file_load_from_file(keyfile, "/var/run/ConsoleKit/database", 0, NULL)) { + gchar **groups; + + groups = g_key_file_get_groups(keyfile, NULL); + if (groups != NULL) { + int i; + + for (i = 0; groups[i] != NULL; i++) { + uid_t u; + + if (!g_str_has_prefix(groups[i], "Session ")) + continue; + if (own_id != NULL &&g_str_has_suffix(groups[i], own_id)) + continue; + if (!g_key_file_get_boolean(keyfile, groups[i], "is_local", NULL)) + continue; + if (!g_key_file_get_boolean(keyfile, groups[i], "is_active", NULL)) + continue; + u = g_key_file_get_integer(keyfile, groups[i], "uid", NULL); + if (u > 0 && !uid_in_list(list, u)) + list = g_slist_prepend(list, GUINT_TO_POINTER(u)); + } + g_strfreev(groups); + } + } + g_key_file_free(keyfile); + + return list; +} + +/* ConsoleKit calls us with special variables */ +static int consolekit_called(const char *ck_action, uid_t *uid, uid_t *uid2, const char **remove_session_id, int *action) +{ + int a = ACTION_NONE; + uid_t u = 0; + uid_t u2 = 0; + const char *s; + const char *s2; + const char *old_session = NULL; + + if (ck_action == NULL || strcmp(ck_action, "seat_active_session_changed") != 0) + return -1; + + /* We can have one of: remove, add, change, no-change */ + s = getenv("CK_SEAT_OLD_SESSION_ID"); + s2 = getenv("CK_SEAT_SESSION_ID"); + if (s == NULL && s2 == NULL) { + return -1; + } else if (s2 == NULL) { + a = ACTION_REMOVE; + } else if (s == NULL) { + a = ACTION_ADD; + } else { + a = ACTION_CHANGE; + } + + switch (a) { + case ACTION_ADD: + s = getenv("CK_SEAT_SESSION_USER_UID"); + if (s == NULL) + return -1; + u = strtoul(s, NULL, 10); + + s = getenv("CK_SEAT_SESSION_IS_LOCAL"); + if (s == NULL) + return -1; + if (strcmp(s, "true") != 0) + return 0; + + break; + case ACTION_REMOVE: + s = getenv("CK_SEAT_OLD_SESSION_USER_UID"); + if (s == NULL) + return -1; + u = strtoul(s, NULL, 10); + + s = getenv("CK_SEAT_OLD_SESSION_IS_LOCAL"); + if (s == NULL) + return -1; + if (strcmp(s, "true") != 0) + return 0; + + old_session = getenv("CK_SEAT_OLD_SESSION_ID"); + if (old_session == NULL) + return -1; + + break; + case ACTION_CHANGE: + s = getenv("CK_SEAT_OLD_SESSION_USER_UID"); + if (s == NULL) + return -1; + u = strtoul(s, NULL, 10); + s = getenv("CK_SEAT_SESSION_USER_UID"); + if (s == NULL) + return -1; + u2 = strtoul(s, NULL, 10); + + s = getenv("CK_SEAT_OLD_SESSION_IS_LOCAL"); + s2 = getenv("CK_SEAT_SESSION_IS_LOCAL"); + if (s == NULL || s2 == NULL) + return -1; + /* don't process non-local session changes */ + if (strcmp(s, "true") != 0 && strcmp(s2, "true") != 0) + return 0; + + if (strcmp(s, "true") == 0 && strcmp(s, "true") == 0) { + /* process the change */ + if (u == u2) { + /* special case: we noop if we are + * changing between local sessions for + * the same uid */ + a = ACTION_NONE; + } + old_session = getenv("CK_SEAT_OLD_SESSION_ID"); + if (old_session == NULL) + return -1; + } else if (strcmp(s, "true") == 0) { + /* only process the removal */ + a = ACTION_REMOVE; + old_session = getenv("CK_SEAT_OLD_SESSION_ID"); + if (old_session == NULL) + return -1; + } else if (strcmp(s2, "true") == 0) { + /* only process the addition */ + a = ACTION_ADD; + u = u2; + } + break; + } + + *remove_session_id = old_session; + *uid = u; + *uid2 = u2; + *action = a; + return 0; +} + +/* add or remove a ACL for a given uid from all matching devices */ +static void apply_acl_to_devices(uid_t uid, int add) +{ + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *list_entry; + + /* iterate over all devices tagged with ACL_SET */ + udev = udev_new(); + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_tag(enumerate, "uaccess"); + udev_enumerate_scan_devices(enumerate); + udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { + struct udev_device *device; + const char *node; + + device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), + udev_list_entry_get_name(list_entry)); + if (device == NULL) + continue; + node = udev_device_get_devnode(device); + if (node == NULL) { + udev_device_unref(device); + continue; + } + set_facl(node, uid, add); + udev_device_unref(device); + } + udev_enumerate_unref(enumerate); + udev_unref(udev); +} + +static void +remove_uid (uid_t uid, const char *remove_session_id) +{ + /* + * Remove ACL for given uid from all matching devices + * when there is currently no local active session. + */ + GSList *list; + + list = uids_with_local_active_session(remove_session_id); + if (!uid_in_list(list, uid)) + apply_acl_to_devices(uid, 0); + g_slist_free(list); +} + +int main (int argc, char* argv[]) +{ + static const struct option options[] = { + { "action", required_argument, NULL, 'a' }, + { "device", required_argument, NULL, 'D' }, + { "user", required_argument, NULL, 'u' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + int action = -1; + const char *device = NULL; + bool uid_given = false; + uid_t uid = 0; + uid_t uid2 = 0; + const char* remove_session_id = NULL; + int rc = 0; + + /* valgrind is more important to us than a slice allocator */ + g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, 1); + + while (1) { + int option; + + option = getopt_long(argc, argv, "+a:D:u:dh", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'a': + if (strcmp(optarg, "remove") == 0) + action = ACTION_REMOVE; + else + action = ACTION_ADD; + break; + case 'D': + device = optarg; + break; + case 'u': + uid_given = true; + uid = strtoul(optarg, NULL, 10); + break; + case 'd': + debug = 1; + break; + case 'h': + printf("Usage: udev-acl --action=ACTION [--device=DEVICEFILE] [--user=UID]\n\n"); + goto out; + } + } + + if (action < 0 && device == NULL && !uid_given) + if (!consolekit_called(argv[optind], &uid, &uid2, &remove_session_id, &action)) + uid_given = true; + + if (action < 0) { + fprintf(stderr, "missing action\n\n"); + rc = 2; + goto out; + } + + if (device != NULL && uid_given) { + fprintf(stderr, "only one option, --device=DEVICEFILE or --user=UID expected\n\n"); + rc = 3; + goto out; + } + + if (uid_given) { + switch (action) { + case ACTION_ADD: + /* Add ACL for given uid to all matching devices. */ + apply_acl_to_devices(uid, 1); + break; + case ACTION_REMOVE: + remove_uid(uid, remove_session_id); + break; + case ACTION_CHANGE: + remove_uid(uid, remove_session_id); + apply_acl_to_devices(uid2, 1); + break; + case ACTION_NONE: + goto out; + break; + default: + g_assert_not_reached(); + break; + } + } else if (device != NULL) { + /* + * Add ACLs for all current session uids to a given device. + * + * Or remove ACLs for uids which do not have any current local + * active session. Remove is not really interesting, because in + * most cases the device node is removed anyway. + */ + GSList *list; + GSList *l; + + list = uids_with_local_active_session(NULL); + for (l = list; l != NULL; l = g_slist_next(l)) { + uid_t u; + + u = GPOINTER_TO_UINT(l->data); + if (action == ACTION_ADD || !uid_in_list(list, u)) + set_facl(device, u, action == ACTION_ADD); + } + g_slist_free(list); + } else { + fprintf(stderr, "--device=DEVICEFILE or --user=UID expected\n\n"); + rc = 3; + } +out: + return rc; +}
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor