summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libudev/libudev-util.c101
-rw-r--r--src/shared/macro.h21
-rw-r--r--src/shared/util.c265
-rw-r--r--src/shared/util.h54
-rw-r--r--src/udev/udevadm.c2
-rw-r--r--src/udev/udevd.c8
6 files changed, 290 insertions, 161 deletions
diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c
index 6268a8a4a7..00dc6e157e 100644
--- a/src/libudev/libudev-util.c
+++ b/src/libudev/libudev-util.c
@@ -48,107 +48,6 @@
* Utilities useful when dealing with devices and device node names.
*/
-int util_delete_path(struct udev *udev, const char *path)
-{
- char p[UTIL_PATH_SIZE];
- char *pos;
- int err = 0;
-
- if (path[0] == '/')
- while(path[1] == '/')
- path++;
- strscpy(p, sizeof(p), path);
- pos = strrchr(p, '/');
- if (pos == p || pos == NULL)
- return 0;
-
- for (;;) {
- *pos = '\0';
- pos = strrchr(p, '/');
-
- /* don't remove the last one */
- if ((pos == p) || (pos == NULL))
- break;
-
- err = rmdir(p);
- if (err < 0) {
- if (errno == ENOENT)
- err = 0;
- break;
- }
- }
- 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;
-
- if (buflen == -1)
- buflen = 1024;
- 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_GETGR_R_SIZE_MAX);
- char *buf = NULL;
-
- if (buflen == -1)
- buflen = 1024;
- 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 "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
int util_resolve_subsys_kernel(struct udev *udev, const char *string,
char *result, size_t maxsize, int read_value)
diff --git a/src/shared/macro.h b/src/shared/macro.h
index e8c564837b..cea13182ec 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -37,6 +37,10 @@
#define _public_ __attribute__ ((visibility("default")))
#define _cleanup_(x) __attribute__((cleanup(x)))
+/* Temporarily disable some warnings */
+#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\"")
#define DISABLE_WARNING_FORMAT_NONLITERAL \
_Pragma("GCC diagnostic push"); \
@@ -103,6 +107,23 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
} while (false)
+#if defined(static_assert)
+/* static_assert() is sometimes defined in a way that trips up
+ * -Wdeclaration-after-statement, hence let's temporarily turn off
+ * this warning around it. */
+#define assert_cc(expr) \
+ DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \
+ static_assert(expr, #expr); \
+ REENABLE_WARNING
+#else
+#define assert_cc(expr) \
+ DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \
+ struct CONCATENATE(_assert_struct_, __LINE__) { \
+ char x[(expr) ? 0 : -1]; \
+ }; \
+ REENABLE_WARNING
+#endif
+
#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
diff --git a/src/shared/util.c b/src/shared/util.c
index bbe18ecf31..61513bade5 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -180,6 +180,34 @@ int unlink_noerrno(const char *path) {
return 0;
}
+int parse_uid(const char *s, uid_t* ret_uid) {
+ unsigned long ul = 0;
+ uid_t uid;
+ int r;
+
+ assert(s);
+ assert(ret_uid);
+
+ r = safe_atolu(s, &ul);
+ if (r < 0)
+ return r;
+
+ uid = (uid_t) ul;
+
+ if ((unsigned long) uid != ul)
+ return -ERANGE;
+
+ /* Some libc APIs use (uid_t) -1 as special placeholder */
+ if (uid == (uid_t) 0xFFFFFFFF)
+ return -ENXIO;
+
+ /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
+ if (uid == (uid_t) 0xFFFF)
+ return -ENXIO;
+
+ *ret_uid = uid;
+ return 0;
+}
int safe_atou(const char *s, unsigned *ret_u) {
char *x = NULL;
unsigned long l;
@@ -353,6 +381,69 @@ char *strappend(const char *s, const char *suffix) {
return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
}
+int rmdir_parents(const char *path, const char *stop) {
+ size_t l;
+ int r = 0;
+
+ assert(path);
+ assert(stop);
+
+ l = strlen(path);
+
+ /* Skip trailing slashes */
+ while (l > 0 && path[l-1] == '/')
+ l--;
+
+ while (l > 0) {
+ char *t;
+
+ /* Skip last component */
+ while (l > 0 && path[l-1] != '/')
+ l--;
+
+ /* Skip trailing slashes */
+ while (l > 0 && path[l-1] == '/')
+ l--;
+
+ if (l <= 0)
+ break;
+
+ if (!(t = strndup(path, l)))
+ return -ENOMEM;
+
+ if (path_startswith(stop, t)) {
+ free(t);
+ return 0;
+ }
+
+ r = rmdir(t);
+ free(t);
+
+ if (r < 0)
+ if (errno != ENOENT)
+ return -errno;
+ }
+
+ return 0;
+}
+
+int dev_urandom(void *p, size_t n) {
+ _cleanup_close_ int fd;
+ ssize_t k;
+
+ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return errno == ENOENT ? -ENOSYS : -errno;
+
+ k = loop_read(fd, p, n, true);
+ if (k < 0)
+ return (int) k;
+ if ((size_t) k != n)
+ return -EIO;
+
+ return 0;
+}
+
char hexchar(int x) {
static const char table[16] = "0123456789abcdef";
@@ -578,6 +669,43 @@ int flush_fd(int fd) {
}
}
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
+ FILE *f;
+ char *t;
+ int fd;
+
+ assert(path);
+ assert(_f);
+ assert(_temp_path);
+
+ t = tempfn_xxxxxx(path);
+ if (!t)
+ return -ENOMEM;
+
+#if HAVE_DECL_MKOSTEMP
+ fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
+#else
+ fd = mkstemp_safe(t);
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+ if (fd < 0) {
+ free(t);
+ return -errno;
+ }
+
+ f = fdopen(fd, "we");
+ if (!f) {
+ unlink(t);
+ free(t);
+ return -errno;
+ }
+
+ *_f = f;
+ *_temp_path = t;
+
+ return 0;
+}
+
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
uint8_t *p = buf;
ssize_t n = 0;
@@ -613,23 +741,6 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
return n;
}
-int dev_urandom(void *p, size_t n) {
- _cleanup_close_ int fd;
- ssize_t k;
-
- fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return errno == ENOENT ? -ENOSYS : -errno;
-
- k = loop_read(fd, p, n, true);
- if (k < 0)
- return (int) k;
- if ((size_t) k != n)
- return -EIO;
-
- return 0;
-}
-
void random_bytes(void *p, size_t n) {
static bool srand_called = false;
uint8_t *q;
@@ -755,39 +866,107 @@ bool nulstr_contains(const char*nulstr, const char *needle) {
return false;
}
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
- FILE *f;
- char *t;
- int fd;
+int get_user_creds(
+ const char **username,
+ uid_t *uid, gid_t *gid,
+ const char **home,
+ const char **shell) {
- assert(path);
- assert(_f);
- assert(_temp_path);
+ struct passwd *p;
+ uid_t u;
- t = tempfn_xxxxxx(path);
- if (!t)
- return -ENOMEM;
+ assert(username);
+ assert(*username);
-#if HAVE_DECL_MKOSTEMP
- fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
-#else
- fd = mkstemp_safe(t);
- fcntl(fd, F_SETFD, FD_CLOEXEC);
-#endif
- if (fd < 0) {
- free(t);
- return -errno;
+ /* We enforce some special rules for uid=0: in order to avoid
+ * NSS lookups for root we hardcode its data. */
+
+ if (streq(*username, "root") || streq(*username, "0")) {
+ *username = "root";
+
+ if (uid)
+ *uid = 0;
+
+ if (gid)
+ *gid = 0;
+
+ if (home)
+ *home = "/root";
+
+ if (shell)
+ *shell = "/bin/sh";
+
+ return 0;
}
- f = fdopen(fd, "we");
- if (!f) {
- unlink(t);
- free(t);
- return -errno;
+ if (parse_uid(*username, &u) >= 0) {
+ errno = 0;
+ p = getpwuid(u);
+
+ /* If there are multiple users with the same id, make
+ * sure to leave $USER to the configured value instead
+ * of the first occurrence in the database. However if
+ * the uid was configured by a numeric uid, then let's
+ * pick the real username from /etc/passwd. */
+ if (p)
+ *username = p->pw_name;
+ } else {
+ errno = 0;
+ p = getpwnam(*username);
}
- *_f = f;
- *_temp_path = t;
+ if (!p)
+ return errno > 0 ? -errno : -ESRCH;
+
+ if (uid)
+ *uid = p->pw_uid;
+
+ if (gid)
+ *gid = p->pw_gid;
+
+ if (home)
+ *home = p->pw_dir;
+
+ if (shell)
+ *shell = p->pw_shell;
+
+ return 0;
+}
+
+int get_group_creds(const char **groupname, gid_t *gid) {
+ struct group *g;
+ gid_t id;
+
+ assert(groupname);
+
+ /* We enforce some special rules for gid=0: in order to avoid
+ * NSS lookups for root we hardcode its data. */
+
+ if (streq(*groupname, "root") || streq(*groupname, "0")) {
+ *groupname = "root";
+
+ if (gid)
+ *gid = 0;
+
+ return 0;
+ }
+
+ if (parse_gid(*groupname, &id) >= 0) {
+ errno = 0;
+ g = getgrgid(id);
+
+ if (g)
+ *groupname = g->gr_name;
+ } else {
+ errno = 0;
+ g = getgrnam(*groupname);
+ }
+
+ if (!g)
+ return errno > 0 ? -errno : -ESRCH;
+
+ if (gid)
+ *gid = g->gr_gid;
return 0;
}
diff --git a/src/shared/util.h b/src/shared/util.h
index d5c6705497..60ea971dc3 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -132,6 +132,8 @@ char *endswith(const char *s, const char *postfix) _pure_;
int close_nointr(int fd);
int safe_close(int fd);
+int parse_uid(const char *s, uid_t* ret_uid);
+#define parse_gid(s, ret_uid) parse_uid(s, ret_uid)
int safe_atou(const char *s, unsigned *ret_u);
int safe_atoi(const char *s, int *ret_i);
@@ -139,6 +141,31 @@ int safe_atoi(const char *s, int *ret_i);
int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i);
+
+#if __WORDSIZE == 32
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+ assert_cc(sizeof(unsigned long) == sizeof(unsigned));
+ return safe_atou(s, (unsigned*) ret_u);
+}
+static inline int safe_atoli(const char *s, long int *ret_u) {
+ assert_cc(sizeof(long int) == sizeof(int));
+ return safe_atoi(s, (int*) ret_u);
+}
+#else
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+ assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
+ return safe_atollu(s, (unsigned long long*) ret_u);
+}
+static inline int safe_atoli(const char *s, long int *ret_u) {
+ assert_cc(sizeof(long int) == sizeof(long long int));
+ return safe_atolli(s, (long long int*) ret_u);
+}
+#endif
+
+static inline int safe_atou64(const char *s, uint64_t *ret_u) {
+ assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
+ return safe_atollu(s, (unsigned long long*) ret_u);
+}
const char* split(const char **state, size_t *l, const char *separator, bool quoted);
#define FOREACH_WORD_QUOTED(word, length, s, state) \
@@ -152,6 +179,7 @@ char *strnappend(const char *s, const char *suffix, size_t length);
char *truncate_nl(char *s);
+int rmdir_parents(const char *path, const char *stop);
char hexchar(int x) _const_;
char octchar(int x) _const_;
@@ -235,6 +263,9 @@ int null_or_empty_fd(int fd);
bool nulstr_contains(const char*nulstr, const char *needle);
+int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
+int get_group_creds(const char **groupname, gid_t *gid);
+
char *strjoin(const char *x, ...) _sentinel_;
bool is_main_thread(void);
@@ -338,16 +369,19 @@ static inline void _reset_errno_(int *saved_errno) {
int unlink_noerrno(const char *path);
-#define strappenda(a, b) \
- ({ \
- const char *_a_ = (a), *_b_ = (b); \
- char *_c_; \
- size_t _x_, _y_; \
- _x_ = strlen(_a_); \
- _y_ = strlen(_b_); \
- _c_ = alloca(_x_ + _y_ + 1); \
- strcpy(stpcpy(_c_, _a_), _b_); \
- _c_; \
+#define strappenda(a, ...) \
+ ({ \
+ int _len = strlen(a); \
+ unsigned _i; \
+ char *_d_, *_p_; \
+ const char *_appendees_[] = { __VA_ARGS__ }; \
+ for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \
+ _len += strlen(_appendees_[_i]); \
+ _d_ = alloca(_len + 1); \
+ _p_ = stpcpy(_d_, a); \
+ for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \
+ _p_ = stpcpy(_p_, _appendees_[_i]); \
+ _d_; \
})
static inline void qsort_safe(void *base, size_t nmemb, size_t size,
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index aaf94262a8..1d2e7dd5d6 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -76,7 +76,7 @@ static int adm_help(struct udev *udev, int argc, char *argv[]) {
static int run_command(struct udev *udev, const struct udevadm_cmd *cmd, int argc, char *argv[]) {
if (cmd->debug)
log_set_max_level(LOG_DEBUG);
- log_debug("calling: %s\n", cmd->name);
+ log_debug("calling: %s", cmd->name);
return cmd->cmd(udev, argc, argv);
}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 5b0db0a0b1..cd94724f54 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1060,6 +1060,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, 'V' },
{}
};
+
int c;
assert(argc >= 0);
@@ -1068,7 +1069,6 @@ static int parse_argv(int argc, char *argv[]) {
while ((c = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL)) >= 0) {
int r;
-
switch (c) {
case 'd':
@@ -1138,7 +1138,6 @@ int main(int argc, char *argv[]) {
goto exit;
log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
log_open();
udev_set_log_fn(udev, udev_main_log);
@@ -1163,10 +1162,7 @@ int main(int argc, char *argv[]) {
label_init("/dev");
/* set umask before creating any file/directory */
- if(chdir("/")!= 0) {
- log_error("unable to change into directory '/'");
- goto exit;
- }
+ chdir("/");
umask(022);
mkdir("/run/udev", 0755);