summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2014-09-18 18:46:21 -0400
committerAnthony G. Basile <blueness@gentoo.org>2014-09-18 18:46:21 -0400
commit15f72fb47214133818a9b20ad4d4cb3d8c4fa508 (patch)
tree07ca3c178e549b9679a75d8ab8abb28aa4a5dc2f /src/shared
parent1e446d862a89ba3475a9df516a9e57a590e9fcd8 (diff)
src/shared: import upstream code needed for recent commits
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/macro.h21
-rw-r--r--src/shared/util.c265
-rw-r--r--src/shared/util.h54
3 files changed, 287 insertions, 53 deletions
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,