diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/util.c | 127 | ||||
-rw-r--r-- | src/util/util.h | 21 |
2 files changed, 148 insertions, 0 deletions
diff --git a/src/util/util.c b/src/util/util.c index cfd26a58b..61e5efedc 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -957,3 +957,130 @@ errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *_unix_tim *_unix_time = ut; return EOK; } + +struct tmpfile_watch { + const char *filename; +}; + +static int unlink_dbg(const char *filename) +{ + errno_t ret; + + ret = unlink(filename); + if (ret != 0) { + if (errno == 2) { + DEBUG(SSSDBG_TRACE_INTERNAL, + "File already removed: [%s]\n", filename); + return 0; + } else { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot remove temporary file [%s]\n", filename); + return -1; + } + } + + return 0; +} + +static int unique_filename_destructor(void *memptr) +{ + struct tmpfile_watch *tw = talloc_get_type(memptr, struct tmpfile_watch); + + if (tw == NULL || tw->filename == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Wrong private pointer\n"); + return -1; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Unlinking [%s]\n", tw->filename); + + return unlink_dbg(tw->filename); +} + +static struct tmpfile_watch *tmpfile_watch_set(TALLOC_CTX *owner, + const char *filename) +{ + struct tmpfile_watch *tw = NULL; + + tw = talloc_zero(owner, struct tmpfile_watch); + if (tw == NULL) { + return NULL; + } + + tw->filename = talloc_strdup(tw, filename); + if (tw->filename == NULL) { + talloc_free(tw); + return NULL; + } + + talloc_set_destructor((TALLOC_CTX *) tw, + unique_filename_destructor); + return tw; +} + +int sss_unique_file_ex(TALLOC_CTX *owner, + char *path_tmpl, + mode_t file_umask, + errno_t *_err) +{ + size_t tmpl_len; + errno_t ret; + int fd = -1; + mode_t old_umask; + struct tmpfile_watch *tw = NULL; + + tmpl_len = strlen(path_tmpl); + if (tmpl_len < 6 || strcmp(path_tmpl + (tmpl_len - 6), "XXXXXX") != 0) { + DEBUG(SSSDBG_OP_FAILURE, + "Template too short or doesn't end with XXXXXX!\n"); + ret = EINVAL; + goto done; + } + + old_umask = umask(file_umask); + fd = mkstemp(path_tmpl); + umask(old_umask); + if (fd == -1) { + ret = errno; + DEBUG(SSSDBG_OP_FAILURE, + "mkstemp(\"%s\") failed [%d]: %s!\n", + path_tmpl, ret, strerror(ret)); + goto done; + } + + if (owner != NULL) { + tw = tmpfile_watch_set(owner, path_tmpl); + if (tw == NULL) { + unlink_dbg(path_tmpl); + ret = ENOMEM; + goto done; + } + } + + ret = EOK; +done: + if (_err) { + *_err = ret; + } + return fd; +} + +int sss_unique_file(TALLOC_CTX *owner, + char *path_tmpl, + errno_t *_err) +{ + return sss_unique_file_ex(owner, path_tmpl, 077, _err); +} + +errno_t sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl) +{ + int fd; + errno_t ret; + + fd = sss_unique_file(owner, path_tmpl, &ret); + /* We only care about a unique file name */ + if (fd >= 0) { + close(fd); + } + + return ret; +} diff --git a/src/util/util.h b/src/util/util.h index 3d90cf0d1..ecbed1c98 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -653,4 +653,25 @@ int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name, /* convert time from generalized form to unix time */ errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *unix_time); +/* Creates a unique file using mkstemp with provided umask. The template + * must end with XXXXXX. Returns the fd, sets _err to an errno value on error. + * + * Prefer using sss_unique_file() as it uses a secure umask internally. + */ +int sss_unique_file_ex(TALLOC_CTX *mem_ctx, + char *path_tmpl, + mode_t file_umask, + errno_t *_err); +int sss_unique_file(TALLOC_CTX *owner, + char *path_tmpl, + errno_t *_err); + +/* Creates a unique filename using mkstemp with secure umask. The template + * must end with XXXXXX + * + * path_tmpl must be a talloc context. Destructor would be set on the filename + * so that it's guaranteed the file is removed. + */ +int sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl); + #endif /* __SSSD_UTIL_H__ */ |