1: /* A secure tmpfile() replacement.
2: *
3: * Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
4: *
5: * Permission to use, copy, modify, and/or distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: #include <paths.h>
19: #include <fcntl.h> /* O_TMPFILE requires -D_GNU_SOURCE */
20: #include <linux/version.h>
21: #include <stdlib.h> /* mkstemp() */
22: #include <stdio.h> /* fdopen() */
23: #include <sys/stat.h> /* umask() */
24:
25: #ifndef O_TMPFILE /* Too old GLIBC or kernel */
26: #warning O_TMPFILE missing on your system, tempfile() may not work!
27: #define __O_TMPFILE 020000000
28: #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) /* Define and let it fail at runtime */
29: #endif
30:
31: /**
32: * tempfile - A secure tmpfile() replacement
33: *
34: * This is the secure replacement for tmpfile() that does not exist in
35: * GLIBC. The function uses the Linux specific %O_TMPFILE and %O_EXCL
36: * for security. When the %FILE is fclose()'ed the file contents is
37: * lost. The file is hidden in the %_PATH_TMP directory on the system.
38: *
39: * This function requires Linux 3.11, or later, due to %O_TMPFILE.
40: *
41: * Returns:
42: * An open %FILE pointer, or %NULL on error.
43: */
44: FILE *tempfile(void)
45: {
46: #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
47: int fd;
48: mode_t oldmask;
49:
50: oldmask = umask(0077);
51: fd = open(_PATH_TMP, O_TMPFILE | O_RDWR | O_EXCL | O_CLOEXEC, S_IRUSR | S_IWUSR);
52: umask(oldmask);
53: if (-1 == fd)
54: return NULL;
55:
56: return fdopen(fd, "rw");
57: #else
58: #warning Too old kernel, reverting to wrap unsafe tmpfile() ...
59: return tmpfile();
60: #endif
61: }
62:
63: #ifdef UNITTEST
64: int main(void)
65: {
66: FILE *fp = tempfile(); system("ls -lrt "
67: _PATH_TMP " | tail -10"); return fclose(fp);
68: }
69: #endif
70:
71: /**
72: * Local Variables:
73: * compile-command: "make V=1 -f tempfile.mk"
74: * version-control: t
75: * indent-tabs-mode: t
76: * c-file-style: "linux"
77: * End:
78: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>