#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "hexdecoct.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
+int fopen_unlocked(const char *path, const char *options, FILE **ret) {
+ assert(ret);
+
+ FILE *f = fopen(path, options);
+ if (!f)
+ return -errno;
+
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
+ *ret = f;
+ return 0;
+}
+
+int fdopen_unlocked(int fd, const char *options, FILE **ret) {
+ assert(ret);
+
+ FILE *f = fdopen(fd, options);
+ if (!f)
+ return -errno;
+
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
+ *ret = f;
+ return 0;
+}
+
+FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
+ FILE *f = open_memstream(ptr, sizeloc);
+ if (!f)
+ return NULL;
+
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
+ return f;
+}
+
int write_string_stream_ts(
FILE *f,
const char *line,
if (r < 0)
return r;
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
(void) fchmod_umask(fileno(f), 0644);
r = write_string_stream_ts(f, line, flags, ts);
assert(!ts);
if (flags & WRITE_STRING_FILE_CREATE) {
- f = fopen(fn, "we");
- if (!f) {
- r = -errno;
+ r = fopen_unlocked(fn, "we", &f);
+ if (r < 0)
goto fail;
- }
} else {
int fd;
goto fail;
}
- f = fdopen(fd, "w");
- if (!f) {
- r = -errno;
+ r = fdopen_unlocked(fd, "w", &f);
+ if (r < 0) {
safe_close(fd);
goto fail;
}
}
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
setvbuf(f, NULL, _IONBF, 0);
int read_one_line_file(const char *fn, char **line) {
_cleanup_fclose_ FILE *f = NULL;
+ int r;
assert(fn);
assert(line);
- f = fopen(fn, "re");
- if (!f)
- return -errno;
-
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ r = fopen_unlocked(fn, "re", &f);
+ if (r < 0)
+ return r;
return read_line(f, LONG_LINE_MAX, line);
}
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *buf = NULL;
size_t l, k;
+ int r;
assert(fn);
assert(blob);
if (!buf)
return -ENOMEM;
- f = fopen(fn, "re");
- if (!f)
- return -errno;
-
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ r = fopen_unlocked(fn, "re", &f);
+ if (r < 0)
+ return r;
/* We try to read one byte more than we need, so that we know whether we hit eof */
errno = 0;
return 1;
}
-int read_full_stream(
+int read_full_stream_full(
FILE *f,
+ const char *filename,
+ ReadFullFileFlags flags,
char **ret_contents,
size_t *ret_size) {
_cleanup_free_ char *buf = NULL;
struct stat st;
- size_t n, l;
- int fd;
+ size_t n, n_next, l;
+ int fd, r;
assert(f);
assert(ret_contents);
+ assert(!(flags & READ_FULL_FILE_UNBASE64) || ret_size);
- n = LINE_MAX; /* Start size */
+ n_next = LINE_MAX; /* Start size */
fd = fileno(f);
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
* optimize our buffering) */
- if (fstat(fileno(f), &st) < 0)
+ if (fstat(fd, &st) < 0)
return -errno;
if (S_ISREG(st.st_mode)) {
* size of 0. Note that we increase the size to read here by one, so that the first read attempt
* already makes us notice the EOF. */
if (st.st_size > 0)
- n = st.st_size + 1;
+ n_next = st.st_size + 1;
+
+ if (flags & READ_FULL_FILE_SECURE)
+ (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
}
}
- l = 0;
+ n = l = 0;
for (;;) {
char *t;
size_t k;
- t = realloc(buf, n + 1);
- if (!t)
- return -ENOMEM;
+ if (flags & READ_FULL_FILE_SECURE) {
+ t = malloc(n_next + 1);
+ if (!t) {
+ r = -ENOMEM;
+ goto finalize;
+ }
+ memcpy_safe(t, buf, n);
+ explicit_bzero_safe(buf, n);
+ } else {
+ t = realloc(buf, n_next + 1);
+ if (!t)
+ return -ENOMEM;
+ }
buf = t;
+ n = n_next;
+
errno = 0;
k = fread(buf + l, 1, n - l, f);
if (k > 0)
l += k;
- if (ferror(f))
- return errno > 0 ? -errno : -EIO;
+ if (ferror(f)) {
+ r = errno > 0 ? -errno : -EIO;
+ goto finalize;
+ }
if (feof(f))
break;
assert(l == n);
/* Safety check */
- if (n >= READ_FULL_BYTES_MAX)
- return -E2BIG;
+ if (n >= READ_FULL_BYTES_MAX) {
+ r = -E2BIG;
+ goto finalize;
+ }
+
+ n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
+ }
- n = MIN(n * 2, READ_FULL_BYTES_MAX);
+ if (flags & READ_FULL_FILE_UNBASE64) {
+ buf[l++] = 0;
+ r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
+ goto finalize;
}
if (!ret_size) {
* trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
* there'd be ambiguity about what we just read. */
- if (memchr(buf, 0, l))
- return -EBADMSG;
+ if (memchr(buf, 0, l)) {
+ r = -EBADMSG;
+ goto finalize;
+ }
}
buf[l] = 0;
*ret_size = l;
return 0;
+
+finalize:
+ if (flags & READ_FULL_FILE_SECURE)
+ explicit_bzero_safe(buf, n);
+
+ return r;
}
-int read_full_file(const char *fn, char **contents, size_t *size) {
+int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
_cleanup_fclose_ FILE *f = NULL;
+ int r;
- assert(fn);
+ assert(filename);
assert(contents);
- f = fopen(fn, "re");
- if (!f)
- return -errno;
-
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ r = fopen_unlocked(filename, "re", &f);
+ if (r < 0)
+ return r;
- return read_full_stream(f, contents, size);
+ return read_full_stream_full(f, filename, flags, contents, size);
}
int executable_is_script(const char *path, char **interpreter) {
return 1;
}
+
+int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
+ struct stat _st;
+
+ if (!filename)
+ return 0;
+
+ if (!st) {
+ if (stat(filename, &_st) < 0)
+ return -errno;
+ st = &_st;
+ }
+
+ if ((st->st_mode & S_IRWXO) == 0)
+ return 0;
+
+ if (unit)
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "%s has %04o mode that is too permissive, please adjust the access mode.",
+ filename, st->st_mode & 07777);
+ else
+ log_warning("%s has %04o mode that is too permissive, please adjust the access mode.",
+ filename, st->st_mode & 07777);
+ return 0;
+}