From 83cd6b754b270091840456a2c8a66dae19f5a7dc Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 9 Apr 2012 16:37:54 +0200 Subject: [PATCH] udev: convert 'uaccess' to a builtin --- Makefile.am | 45 ++++++-------- rules/80-drivers.rules | 2 +- src/login/70-uaccess.rules | 2 +- src/login/73-seat-late.rules.in | 2 +- src/udev/test-udev.c | 2 +- src/udev/test/rule-syntax-check.py | 2 +- src/udev/test/udev-test.pl | 6 +- src/udev/udev-builtin-uaccess.c | 99 ++++++++++++++++++++++++++++++ src/udev/udev-builtin.c | 3 + src/udev/udev-event.c | 17 ++--- src/udev/udev-rules.c | 64 +++++++++++++------ src/udev/udev.h | 6 +- 12 files changed, 188 insertions(+), 62 deletions(-) create mode 100644 src/udev/udev-builtin-uaccess.c diff --git a/Makefile.am b/Makefile.am index d4b706eb3..95119e30d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/rules/80-drivers.rules b/rules/80-drivers.rules index 38ebfeb0e..692510c91 100644 --- a/rules/80-drivers.rules +++ b/rules/80-drivers.rules @@ -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" diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules index 693249226..18dd4433e 100644 --- a/src/login/70-uaccess.rules +++ b/src/login/70-uaccess.rules @@ -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 diff --git a/src/login/73-seat-late.rules.in b/src/login/73-seat-late.rules.in index 0847932d7..933c952b9 100644 --- a/src/login/73-seat-late.rules.in +++ b/src/login/73-seat-late.rules.in @@ -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" diff --git a/src/udev/test-udev.c b/src/udev/test-udev.c index 53ecd95bc..150cb16a3 100644 --- a/src/udev/test-udev.c +++ b/src/udev/test-udev.c @@ -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; diff --git a/src/udev/test/rule-syntax-check.py b/src/udev/test/rule-syntax-check.py index ff1b63d07..4fa3042d4 100755 --- a/src/udev/test/rule-syntax-check.py +++ b/src/udev/test/rule-syntax-check.py @@ -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 = '' diff --git a/src/udev/test/udev-test.pl b/src/udev/test/udev-test.pl index 0b379b0d9..e2bfae32b 100755 --- a/src/udev/test/udev-test.pl +++ b/src/udev/test/udev-test.pl @@ -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 index 000000000..662bac9e0 --- /dev/null +++ b/src/udev/udev-builtin-uaccess.c @@ -0,0 +1,99 @@ +/* + * manage device node user ACL + * + * Copyright 2010-2012 Kay Sievers + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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", +}; diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index b6b3ddc01..508a22ecf 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -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) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 703581a8b..2b4cc6923 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -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; } diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index d9de4bb1e..73e17c65c 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -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: diff --git a/src/udev/udev.h b/src/udev/udev.h index ecf8cc5fe..681660ecb 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -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); -- 2.30.2