chiark / gitweb /
udev: convert 'uaccess' to a builtin
authorKay Sievers <kay@vrfy.org>
Mon, 9 Apr 2012 14:37:54 +0000 (16:37 +0200)
committerKay Sievers <kay@vrfy.org>
Mon, 9 Apr 2012 17:25:41 +0000 (19:25 +0200)
12 files changed:
Makefile.am
rules/80-drivers.rules
src/login/70-uaccess.rules
src/login/73-seat-late.rules.in
src/udev/test-udev.c
src/udev/test/rule-syntax-check.py
src/udev/test/udev-test.pl
src/udev/udev-builtin-uaccess.c [new file with mode: 0644]
src/udev/udev-builtin.c
src/udev/udev-event.c
src/udev/udev-rules.c
src/udev/udev.h

index d4b706eb3bd3035cfaa365aa1b28fd58c7ea24c1..95119e30dbbdf538e304420584b5b46287141d78 100644 (file)
@@ -1271,7 +1271,9 @@ udev_common_sources = \
        src/udev/udev-builtin-input_id.c \
        src/udev/udev-builtin-kmod.c \
        src/udev/udev-builtin-path_id.c \
-       src/udev/udev-builtin-usb_id.c
+       src/udev/udev-builtin-usb_id.c \
+       src/systemd/sd-daemon.h \
+       src/sd-daemon.c
 
 udev_common_CFLAGS = \
        $(BLKID_CFLAGS) \
@@ -1287,11 +1289,23 @@ udev_common_CPPFLAGS = \
        -DFIRMWARE_PATH="$(FIRMWARE_PATH)" \
        -DUSB_DATABASE=\"$(USB_DATABASE)\" -DPCI_DATABASE=\"$(PCI_DATABASE)\"
 
+if HAVE_ACL
+udev_common_sources += \
+       src/udev/udev-builtin-uaccess.c \
+       src/login/logind-acl.c \
+       src/acl-util.c
+
+udev_common_CFLAGS += \
+       $(ACL_CFLAGS)
+
+udev_common_LDADD += \
+       libsystemd-login.la \
+       $(ACL_LIBS)
+endif
+
 udevd_SOURCES = \
        $(udev_common_sources) \
-       src/udev/udevd.c \
-       src/systemd/sd-daemon.h \
-       src/sd-daemon.c
+       src/udev/udevd.c
 
 udevd_CFLAGS = \
        $(udev_common_CFLAGS)
@@ -2597,29 +2611,6 @@ systemd_multi_seat_x_LDADD = \
 rootlibexec_PROGRAMS += \
        systemd-multi-seat-x
 
-systemd_uaccess_SOURCES = \
-       src/login/uaccess.c
-
-if HAVE_ACL
-systemd_uaccess_SOURCES += \
-       src/login/logind-acl.c \
-       src/acl-util.c
-endif
-
-systemd_uaccess_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(ACL_CFLAGS)
-
-systemd_uaccess_LDADD = \
-       libsystemd-basic.la \
-       libsystemd-daemon.la \
-       libsystemd-login.la \
-       libudev.la \
-       $(ACL_LIBS)
-
-rootlibexec_PROGRAMS += \
-       systemd-uaccess
-
 dist_udevrules_DATA += \
        src/login/70-uaccess.rules
 
index 38ebfeb0e6145754cf90a9efc4da4b5277339263..692510c9121c945cf6eba42ac7efe41c10a09f8f 100644 (file)
@@ -7,6 +7,6 @@ SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", IMPORT{builtin}="kmod load tifm_sd
 SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", IMPORT{builtin}="kmod load tifm_ms"
 SUBSYSTEM=="memstick", IMPORT{builtin}="kmod load ms_block mspro_block"
 SUBSYSTEM=="i2o", IMPORT{builtin}="kmod load i2o_block"
-SUBSYSTEM=="module", KERNEL=="parport_pc", IMPORT{builtin}="kmod load ppdev"
+SUBSYSTEM=="module", KERNEL=="parport_pc", RUN{builtin}="kmod load ppdev"
 
 LABEL="drivers_end"
index 693249226060bdde063c522b32a6dcf4c357c7e4..18dd4433e73996c4cc08c673bc262fa82f0c48ad 100644 (file)
@@ -9,7 +9,7 @@ ACTION=="remove", GOTO="uaccess_end"
 ENV{MAJOR}=="", GOTO="uaccess_end"
 
 # PTP/MTP protocol devices, cameras, portable media players
-SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{program}="usb_id --export %p"
+SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id"
 SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess"
 
 # Digicams with proprietary protocol
index 0847932d77577c09e75fff6dc942227c8ac503d4..933c952b97089eb8834a9c906a070670ab1b75a6 100644 (file)
@@ -12,6 +12,6 @@ ENV{ID_SEAT}=="", IMPORT{parent}="ID_SEAT"
 
 ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}"
 
-TAG=="uaccess", ENV{MAJOR}!="", RUN+="@rootlibexecdir@/systemd-uaccess $env{DEVNAME} $env{ID_SEAT}"
+TAG=="uaccess", ENV{MAJOR}!="", RUN{builtin}+="uaccess"
 
 LABEL="seat_late_end"
index 53ecd95bcfe5d7f975c5b1d4ca8437fbb3545cfb..150cb16a3103a31ea7a9a2884493765b95996050 100644 (file)
@@ -88,7 +88,7 @@ int main(int argc, char *argv[])
 
         /* do what devtmpfs usually provides us */
         if (udev_device_get_devnode(dev) != NULL) {
-                mode_t mode;
+                mode_t mode = 0600;
 
                 if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
                         mode |= S_IFBLK;
index ff1b63d075ac7a9dbf4b0e622b3059b8dad9707a..4fa3042d4f29d84b8efc5dc7ccfe02d4307191cb 100755 (executable)
@@ -28,7 +28,7 @@ if len(sys.argv) < 2:
 no_args_tests = re.compile('(ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|RESULT|TEST)\s*(?:=|!)=\s*"([^"]*)"$')
 args_tests = re.compile('(ATTRS?|ENV|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*"([^"]*)"$')
 no_args_assign = re.compile('(NAME|SYMLINK|OWNER|GROUP|MODE|TAG|PROGRAM|RUN|LABEL|GOTO|WAIT_FOR|OPTIONS|IMPORT)\s*(?:\+=|:=|=)\s*"([^"]*)"$')
-args_assign = re.compile('(ATTR|ENV|IMPORT){([a-zA-Z0-9/_.*%-]+)}\s*=\s*"([^"]*)"$')
+args_assign = re.compile('(ATTR|ENV|IMPORT|RUN){([a-zA-Z0-9/_.*%-]+)}\s*=\s*"([^"]*)"$')
 
 result = 0
 buffer = ''
index 0b379b0d9a708e61de7bc625dbe3b212b1886e0f..e2bfae32bfc1fb6fbc0f1e7490c42dc22eb773f6 100755 (executable)
@@ -21,8 +21,8 @@ use warnings;
 use strict;
 
 my $PWD                 = $ENV{PWD};
-my $sysfs               = "test/sys";
-my $udev_bin            = "./test-udev";
+my $sysfs               = "src/udev/test/sys";
+my $udev_bin            = ".libs/test-udev";
 my $valgrind            = 0;
 my $udev_bin_valgrind   = "valgrind --tool=memcheck --leak-check=yes --quiet $udev_bin";
 my $udev_root           = "udev-root";
@@ -1347,7 +1347,7 @@ sub udev {
         if ($valgrind > 0) {
                 system("$udev_bin_valgrind $action $devpath");
         } else {
-                system("$udev_bin $action $devpath");
+                system("$udev_bin", "$action", "$devpath");
         }
 }
 
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
new file mode 100644 (file)
index 0000000..662bac9
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * manage device node user ACL
+ *
+ * Copyright 2010-2012 Kay Sievers <kay@vrfy.org>
+ * Copyright 2010 Lennart Poettering
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <getopt.h>
+
+#include <systemd/sd-daemon.h>
+#include <systemd/sd-login.h>
+#include "logind-acl.h"
+#include "udev.h"
+#include "util.h"
+
+static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool test)
+{
+        int r;
+        const char *path = NULL, *seat;
+        bool changed_acl = false;
+        uid_t uid;
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        /* don't muck around with ACLs when the system is not running systemd */
+        if (!sd_booted())
+                return 0;
+
+        path = udev_device_get_devnode(dev);
+        seat = udev_device_get_property_value(dev, "ID_SEAT");
+        if (!seat)
+                seat = "seat0";
+
+        r = sd_seat_get_active(seat, NULL, &uid);
+        if (r == -ENOENT) {
+                /* No active session on this seat */
+                r = 0;
+                goto finish;
+        } else if (r < 0) {
+                log_error("Failed to determine active user on seat %s.", seat);
+                goto finish;
+        }
+
+        r = devnode_acl(path, true, false, 0, true, uid);
+        if (r < 0) {
+                log_error("Failed to apply ACL on %s: %s", path, strerror(-r));
+                goto finish;
+        }
+
+        changed_acl = true;
+        r = 0;
+
+finish:
+        if (path && !changed_acl) {
+                int k;
+
+                /* Better be safe than sorry and reset ACL */
+                k = devnode_acl(path, true, false, 0, false, 0);
+                if (k < 0) {
+                        log_error("Failed to apply ACL on %s: %s", path, strerror(-k));
+                        if (r >= 0)
+                                r = k;
+                }
+        }
+
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+const struct udev_builtin udev_builtin_uaccess = {
+        .name = "uaccess",
+        .cmd = builtin_uaccess,
+        .help = "manage device node user ACL",
+};
index b6b3ddc01918cba21af1da34e3984c15ce8f5e2c..508a22ecf8ca199bee1277dc5be60954d88ec7b8 100644 (file)
@@ -34,6 +34,9 @@ static const struct udev_builtin *builtins[] = {
         [UDEV_BUILTIN_PCI_DB] = &udev_builtin_pci_db,
         [UDEV_BUILTIN_USB_DB] = &udev_builtin_usb_db,
         [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
+#ifdef HAVE_ACL
+        [UDEV_BUILTIN_UACCESS] = &udev_builtin_uaccess,
+#endif
 };
 
 int udev_builtin_init(struct udev *udev)
index 703581a8b351382bdbf3c113ad9073748648a599..2b4cc6923e2364d5ad131035cc282922aa6d1cd1 100644 (file)
@@ -943,15 +943,20 @@ out:
         return err;
 }
 
-int udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask)
+void udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask)
 {
         struct udev_list_entry *list_entry;
-        int err = 0;
 
         udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
                 const char *cmd = udev_list_entry_get_name(list_entry);
+                enum udev_builtin_cmd builtin_cmd = udev_list_entry_get_num(list_entry);
+
+                if (builtin_cmd < UDEV_BUILTIN_MAX) {
+                        char command[UTIL_PATH_SIZE];
 
-                if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
+                        udev_event_apply_format(event, cmd, command, sizeof(command));
+                        udev_builtin_run(event->dev, builtin_cmd, command, false);
+                } else if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
                         struct udev_monitor *monitor;
 
                         monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]);
@@ -970,11 +975,7 @@ int udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask)
 
                         udev_event_apply_format(event, cmd, program, sizeof(program));
                         envp = udev_device_get_properties_envp(event->dev);
-                        if (udev_event_spawn(event, program, envp, sigmask, NULL, 0) < 0) {
-                                if (udev_list_entry_get_num(list_entry))
-                                        err = -1;
-                        }
+                        udev_event_spawn(event, program, envp, sigmask, NULL, 0);
                 }
         }
-        return err;
 }
index d9de4bb1ec8ec8621375f58b22d0fe17c0104279..73e17c65c0f12b00af114eb810b6016046b545d2 100644 (file)
@@ -168,7 +168,8 @@ enum token_type {
         TK_A_NAME,                      /* val */
         TK_A_DEVLINK,                   /* val */
         TK_A_ATTR,                      /* val, attr */
-        TK_A_RUN,                       /* val, bool */
+        TK_A_RUN_BUILTIN,               /* val, bool */
+        TK_A_RUN_PROGRAM,               /* val, bool */
         TK_A_GOTO,                      /* size_t */
 
         TK_END,
@@ -305,7 +306,8 @@ static const char *token_str(enum token_type type)
                 [TK_A_NAME] =                   "A NAME",
                 [TK_A_DEVLINK] =                "A DEVLINK",
                 [TK_A_ATTR] =                   "A ATTR",
-                [TK_A_RUN] =                    "A RUN",
+                [TK_A_RUN_BUILTIN] =            "A RUN_BUILTIN",
+                [TK_A_RUN_PROGRAM] =            "A RUN_PROGRAM",
                 [TK_A_GOTO] =                   "A GOTO",
 
                 [TK_END] =                      "END",
@@ -359,7 +361,8 @@ static void dump_token(struct udev_rules *rules, struct token *token)
         case TK_A_OWNER:
         case TK_A_GROUP:
         case TK_A_MODE:
-        case TK_A_RUN:
+        case TK_A_RUN_BUILTIN:
+        case TK_A_RUN_PROGRAM:
                 log_debug("%s %s '%s'(%s)\n",
                           token_str(type), operation_str(op), value, string_glob_str(glob));
                 break;
@@ -1049,7 +1052,9 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
         case TK_A_STRING_ESCAPE_REPLACE:
         case TK_A_DB_PERSIST:
                 break;
-        case TK_A_RUN:
+        case TK_A_RUN_BUILTIN:
+                token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
+        case TK_A_RUN_PROGRAM:
                 token->key.value_off = add_string(rule_tmp->rules, value);
                 break;
         case TK_A_INOTIFY_WATCH:
@@ -1379,7 +1384,7 @@ static int add_rule(struct udev_rules *rules, char *line,
                                 log_error("IMPORT{} type missing, ignoring IMPORT %s:%u\n", filename, lineno);
                                 continue;
                         }
-                        if (strstr(attr, "program")) {
+                        if (strcmp(attr, "program") == 0) {
                                 /* find known built-in command */
                                 if (value[0] != '/') {
                                         enum udev_builtin_cmd cmd;
@@ -1393,22 +1398,23 @@ static int add_rule(struct udev_rules *rules, char *line,
                                         }
                                 }
                                 rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
-                        } else if (strstr(attr, "builtin")) {
+                        } else if (strcmp(attr, "builtin") == 0) {
                                 enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
 
                                 if (cmd < UDEV_BUILTIN_MAX)
                                         rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
                                 else
                                         log_error("IMPORT{builtin}: '%s' unknown %s:%u\n", value, filename, lineno);
-                        } else if (strstr(attr, "file")) {
+                        } else if (strcmp(attr, "file") == 0) {
                                 rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
-                        } else if (strstr(attr, "db")) {
+                        } else if (strcmp(attr, "db") == 0) {
                                 rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
-                        } else if (strstr(attr, "cmdline")) {
+                        } else if (strcmp(attr, "cmdline") == 0) {
                                 rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
-                        } else if (strstr(attr, "parent")) {
+                        } else if (strcmp(attr, "parent") == 0) {
                                 rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
-                        }
+                        } else
+                                log_error("IMPORT{} unknown type, ignoring IMPORT %s:%u\n", filename, lineno);
                         continue;
                 }
 
@@ -1429,11 +1435,29 @@ static int add_rule(struct udev_rules *rules, char *line,
                         continue;
                 }
 
-                if (strcmp(key, "RUN") == 0) {
-                        if (strncmp(value, "socket:", 7) == 0)
-                                log_error("RUN+=\"socket:...\" support will be removed from a future udev release. "
-                                    "Please remove it from: %s:%u and use libudev to subscribe to events.\n", filename, lineno);
-                        rule_add_key(&rule_tmp, TK_A_RUN, op, value, NULL);
+                if (strncmp(key, "RUN", sizeof("RUN")-1) == 0) {
+                        attr = get_key_attribute(rules->udev, key + sizeof("RUN")-1);
+                        if (attr == NULL)
+                                attr = "program";
+
+                        if (strcmp(attr, "builtin") == 0) {
+                                enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
+
+                                if (cmd < UDEV_BUILTIN_MAX)
+                                        rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd);
+                                else
+                                        log_error("IMPORT{builtin}: '%s' unknown %s:%u\n", value, filename, lineno);
+                        } else if (strcmp(attr, "program") == 0) {
+                                enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX;
+
+                                if (strncmp(value, "socket:", 7) == 0)
+                                        log_error("RUN+=\"socket:...\" support will be removed from a future udev release. "
+                                            "Please remove it from: %s:%u and use libudev to subscribe to events.\n", filename, lineno);
+                                rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd);
+                        } else {
+                                log_error("RUN{} unknown type, ignoring RUN %s:%u\n", filename, lineno);
+                        }
+
                         continue;
                 }
 
@@ -2602,14 +2626,18 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                         }
                         break;
                 }
-                case TK_A_RUN: {
+                case TK_A_RUN_BUILTIN:
+                case TK_A_RUN_PROGRAM: {
+                        struct udev_list_entry *entry;
+
                         if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
                                 udev_list_cleanup(&event->run_list);
                         log_debug("RUN '%s' %s:%u\n",
                                   &rules->buf[cur->key.value_off],
                                   &rules->buf[rule->rule.filename_off],
                                   rule->rule.filename_line);
-                        udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL);
+                        entry = udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL);
+                        udev_list_entry_set_num(entry, cur->key.builtin_cmd);
                         break;
                 }
                 case TK_A_GOTO:
index ecf8cc5fe367c64eff9e519168d602c7088d164a..681660ecb78d734a4a5e95cefaaadf11a47b7f15 100644 (file)
@@ -78,7 +78,7 @@ int udev_event_spawn(struct udev_event *event,
                      const char *cmd, char **envp, const sigset_t *sigmask,
                      char *result, size_t ressize);
 int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules, const sigset_t *sigset);
-int udev_event_execute_run(struct udev_event *event, const sigset_t *sigset);
+void udev_event_execute_run(struct udev_event *event, const sigset_t *sigset);
 int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]);
 
 /* udev-watch.c */
@@ -138,6 +138,9 @@ enum udev_builtin_cmd {
         UDEV_BUILTIN_PCI_DB,
         UDEV_BUILTIN_USB_DB,
         UDEV_BUILTIN_USB_ID,
+#ifdef HAVE_ACL
+        UDEV_BUILTIN_UACCESS,
+#endif
         UDEV_BUILTIN_MAX
 };
 struct udev_builtin {
@@ -157,6 +160,7 @@ extern const struct udev_builtin udev_builtin_path_id;
 extern const struct udev_builtin udev_builtin_pci_db;
 extern const struct udev_builtin udev_builtin_usb_db;
 extern const struct udev_builtin udev_builtin_usb_id;
+extern const struct udev_builtin udev_builtin_uaccess;
 int udev_builtin_init(struct udev *udev);
 void udev_builtin_exit(struct udev *udev);
 enum udev_builtin_cmd udev_builtin_lookup(const char *command);