summaryrefslogtreecommitdiff
path: root/util/libreboot-utils/mkhtemp.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/libreboot-utils/mkhtemp.c')
-rw-r--r--util/libreboot-utils/mkhtemp.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/util/libreboot-utils/mkhtemp.c b/util/libreboot-utils/mkhtemp.c
new file mode 100644
index 00000000..7564800a
--- /dev/null
+++ b/util/libreboot-utils/mkhtemp.c
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: MIT
+ * Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
+ *
+ * Hardened mktemp (mkhtemp!)
+ *
+ * WORK IN PROGRESS (proof of concept), or, v0.0000001
+ * DO NOT PUT THIS IN YOUR LINUX DISTRO YET.
+ *
+ * I will remove this notice when the code is mature, and
+ * probably contact several of your projects myself.
+ *
+ * See README. This is an ongoing project; no proper docs
+ * yet, and no manpage (yet!) - the code is documentation,
+ * while the specification that it implements evolves.
+ */
+
+#if defined(__linux__) && !defined(_GNU_SOURCE)
+/* for openat2 on linux */
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef __OpenBSD__
+#include <sys/param.h> /* pledge(2) */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "include/common.h"
+
+int
+main(int argc, char *argv[])
+{
+#if defined (PATH_LEN) && \
+ (PATH_LEN) >= 256
+ size_t maxlen = PATH_LEN;
+#else
+ size_t maxlen = 4096;
+#endif
+ size_t len;
+ size_t tlen;
+ size_t xc = 0;
+
+ char *tmpdir = NULL;
+ char *template = NULL;
+ char *p;
+ char *s = NULL;
+ char *rp;
+ char resolved[maxlen];
+ char c;
+
+ int fd = -1;
+ int type = MKHTEMP_FILE;
+ int stfu = 0; /* -q option */
+
+ if (lbgetprogname(argv[0]) == NULL)
+ err_no_cleanup(stfu, errno, "could not set progname");
+
+/* https://man.openbsd.org/pledge.2 */
+#if defined(__OpenBSD__) && defined(OpenBSD)
+#if (OpenBSD) >= 509
+ if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
+ goto err_usage;
+#endif
+#endif
+
+ while ((c =
+ getopt(argc, argv, "qdp:")) != -1) {
+
+ switch (c) {
+ case 'd':
+ type = MKHTEMP_DIR;
+ break;
+
+ case 'p':
+ tmpdir = optarg;
+ break;
+
+ case 'q': /* don't print errors */
+ /* (exit status unchanged) */
+ stfu = 1;
+ break;
+
+ default:
+ goto err_usage;
+ }
+ }
+
+ if (optind < argc)
+ template = argv[optind];
+ if (optind + 1 < argc)
+ goto err_usage;
+
+ /* custom template e.g. foo.XXXXXXXXXXXXXXXXXXXXX */
+ if (template != NULL) {
+ if (slen(template, maxlen, &tlen) < 0)
+ err_no_cleanup(stfu, EINVAL,
+ "invalid template");
+
+ for (p = template + tlen;
+ p > template && *--p == 'X'; xc++);
+
+ if (xc < 3) /* the gnu mktemp errs on less than 3 */
+ err_no_cleanup(stfu, EINVAL,
+ "template must have 3 X or more on end (12+ advised");
+ }
+
+ /* user supplied -p PATH - WARNING:
+ * this permits symlinks, but only here,
+ * not in the library, so they are resolved
+ * here first, and *only here*. the mkhtemp
+ * library blocks them. be careful
+ * when using -p
+ */
+ if (tmpdir != NULL) {
+ rp = realpath(tmpdir, resolved);
+ if (rp == NULL)
+ err_no_cleanup(stfu, errno, "%s", tmpdir);
+
+ tmpdir = resolved;
+ }
+
+ if (new_tmp_common(&fd, &s, type,
+ tmpdir, template) < 0)
+ err_no_cleanup(stfu, errno, "%s", s);
+
+#if defined(__OpenBSD__) && defined(OpenBSD)
+#if (OpenBSD) >= 509
+ if (pledge("stdio", NULL) == -1)
+ err_no_cleanup(stfu, errno, "pledge, exit");
+#endif
+#endif
+
+ if (s == NULL)
+ err_no_cleanup(stfu, EFAULT, "bad string initialisation");
+ if (*s == '\0')
+ err_no_cleanup(stfu, EFAULT, "empty string initialisation");
+ if (slen(s, maxlen, &len) < 0)
+ err_no_cleanup(stfu, EFAULT, "unterminated string initialisiert");
+
+ printf("%s\n", s);
+
+ return EXIT_SUCCESS;
+
+err_usage:
+ err_no_cleanup(stfu, EINVAL,
+ "usage: %s [-d] [-p dir] [template]\n", getnvmprogname());
+}/*
+
+ ( >:3 )
+ /| |\
+ / \ */