diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 8fd86f29348..af0f125c739 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -168,6 +168,8 @@ uint64_t util_string_bloom64(const char *str); /* libudev-util-private.c */ int util_delete_path(struct udev *udev, const char *path); +uid_t util_lookup_user(struct udev *udev, const char *user); +gid_t util_lookup_group(struct udev *udev, const char *group); int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); ssize_t print_kmsg(const char *fmt, ...) _printf_(1, 2); diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index 93e78d5d079..d9cdde17514 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -77,6 +77,70 @@ int util_delete_path(struct udev *udev, const char *path) return err; } +uid_t util_lookup_user(struct udev *udev, const char *user) +{ + char *endptr; + struct passwd pwbuf; + struct passwd *pw; + uid_t uid; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + char *buf = alloca(buflen); + + if (streq(user, "root")) + return 0; + uid = strtoul(user, &endptr, 10); + if (endptr[0] == '\0') + return uid; + + errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw); + if (pw != NULL) + return pw->pw_uid; + if (errno == 0 || errno == ENOENT || errno == ESRCH) + udev_err(udev, "specified user '%s' unknown\n", user); + else + udev_err(udev, "error resolving user '%s': %m\n", user); + return 0; +} + +gid_t util_lookup_group(struct udev *udev, const char *group) +{ + char *endptr; + struct group grbuf; + struct group *gr; + gid_t gid = 0; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + char *buf = NULL; + + if (streq(group, "root")) + return 0; + gid = strtoul(group, &endptr, 10); + if (endptr[0] == '\0') + return gid; + gid = 0; + for (;;) { + char *newbuf; + + newbuf = realloc(buf, buflen); + if (!newbuf) + break; + buf = newbuf; + errno = getgrnam_r(group, &grbuf, buf, buflen, &gr); + if (gr != NULL) { + gid = gr->gr_gid; + } else if (errno == ERANGE) { + buflen *= 2; + continue; + } else if (errno == 0 || errno == ENOENT || errno == ESRCH) { + udev_err(udev, "specified group '%s' unknown\n", group); + } else { + udev_err(udev, "error resolving group '%s': %m\n", group); + } + break; + } + free(buf); + return gid; +} + /* handle "[/]" format */ int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value) diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 55185920fa0..cc562156fa6 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -459,7 +459,6 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) { unsigned int i; uid_t uid; unsigned int off; - int r; /* lookup, if we know it already */ for (i = 0; i < rules->uids_cur; i++) { @@ -469,9 +468,7 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) { return uid; } } - r = get_user_creds(&owner, &uid, NULL, NULL, NULL); - if (r < 0) - uid = 0; + uid = util_lookup_user(rules->udev, owner); /* grow buffer if needed */ if (rules->uids_cur+1 >= rules->uids_max) { @@ -502,7 +499,6 @@ static gid_t add_gid(struct udev_rules *rules, const char *group) { unsigned int i; gid_t gid; unsigned int off; - int r; /* lookup, if we know it already */ for (i = 0; i < rules->gids_cur; i++) { @@ -512,9 +508,7 @@ static gid_t add_gid(struct udev_rules *rules, const char *group) { return gid; } } - r = get_group_creds(&group, &gid); - if (r < 0) - gid = 0; + gid = util_lookup_group(rules->udev, group); /* grow buffer if needed */ if (rules->gids_cur+1 >= rules->gids_max) { @@ -2176,7 +2170,6 @@ int udev_rules_apply_to_event(struct udev_rules *rules, break; case TK_A_OWNER: { char owner[UTIL_NAME_SIZE]; - int r; if (event->owner_final) break; @@ -2184,9 +2177,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, event->owner_final = true; udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner)); event->owner_set = true; - r = get_user_creds(&owner, &event->uid, NULL, NULL, NULL); - if (r < 0) - event->uid = 0; + event->uid = util_lookup_user(event->udev, owner); log_debug("OWNER %u %s:%u", event->uid, rules_str(rules, rule->rule.filename_off), @@ -2195,7 +2186,6 @@ int udev_rules_apply_to_event(struct udev_rules *rules, } case TK_A_GROUP: { char group[UTIL_NAME_SIZE]; - int r; if (event->group_final) break; @@ -2203,9 +2193,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, event->group_final = true; udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group)); event->group_set = true; - r = get_group_creds(&group, &event->gid); - if (r < 0) - event->gid = 0; + event->gid = util_lookup_group(event->udev, group); log_debug("GROUP %u %s:%u", event->gid, rules_str(rules, rule->rule.filename_off),