Move mktemp.c to stdlib where it belongs.
authormillert <millert@openbsd.org>
Fri, 19 Jan 2024 16:30:28 +0000 (16:30 +0000)
committermillert <millert@openbsd.org>
Fri, 19 Jan 2024 16:30:28 +0000 (16:30 +0000)
OK deraadt@

lib/libc/stdio/Makefile.inc
lib/libc/stdio/mktemp.3 [deleted file]
lib/libc/stdio/mktemp.c [deleted file]
lib/libc/stdlib/Makefile.inc
lib/libc/stdlib/mktemp.3 [new file with mode: 0644]
lib/libc/stdlib/mktemp.c [new file with mode: 0644]

index 00ae1b2..356e3fc 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile.inc,v 1.29 2016/03/30 06:38:41 jmc Exp $
+#      $OpenBSD: Makefile.inc,v 1.30 2024/01/19 16:30:28 millert Exp $
 
 # stdio sources
 .PATH: ${LIBCSRCDIR}/stdio
@@ -9,7 +9,7 @@ SRCS+=  asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
        fgetln.c fgetpos.c fgets.c fileno.c findfp.c flags.c fmemopen.c \
        fopen.c fprintf.c fpurge.c fputc.c fputs.c fread.c freopen.c fscanf.c \
        fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwrite.c \
-       getc.c getchar.c getw.c makebuf.c mktemp.c open_memstream.c \
+       getc.c getchar.c getw.c makebuf.c open_memstream.c \
        open_wmemstream.c perror.c printf.c putc.c putchar.c puts.c putw.c \
        refill.c remove.c rewind.c rget.c scanf.c setbuf.c setbuffer.c \
        setvbuf.c snprintf.c sprintf.c sscanf.c stdio.c tempnam.c tmpfile.c \
@@ -22,7 +22,7 @@ SRCS+=        asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
        getdelim.c getline.c dprintf.c vdprintf.c
 
 MAN+=  fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fmemopen.3 \
-       fopen.3 fputs.3 fread.3 fseek.3 funopen.3 getc.3 mktemp.3 \
+       fopen.3 fputs.3 fread.3 fseek.3 funopen.3 getc.3 \
        open_memstream.3 perror.3 printf.3 putc.3 remove.3 scanf.3 setbuf.3 \
        setvbuf.3 stdio.3 tmpnam.3 ungetc.3 fgetws.3 fputws.3 fwide.3 getwc.3 \
        putwc.3 ungetwc.3 wprintf.3 wscanf.3 getdelim.3
diff --git a/lib/libc/stdio/mktemp.3 b/lib/libc/stdio/mktemp.3
deleted file mode 100644 (file)
index 050a5c8..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-.\"    $OpenBSD: mktemp.3,v 1.56 2022/08/04 06:20:24 jsg Exp $
-.\"
-.\" Copyright (c) 1989, 1991, 1993
-.\"    The Regents of the University of California.  All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\"    notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\"    notice, this list of conditions and the following disclaimer in the
-.\"    documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of the University nor the names of its contributors
-.\"    may be used to endorse or promote products derived from this software
-.\"    without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.Dd $Mdocdate: August 4 2022 $
-.Dt MKTEMP 3
-.Os
-.Sh NAME
-.Nm mktemp ,
-.Nm mkstemp ,
-.Nm mkostemp ,
-.Nm mkstemps ,
-.Nm mkostemps ,
-.Nm mkdtemp
-.Nd make temporary file name (unique)
-.Sh SYNOPSIS
-.In stdlib.h
-.Ft char *
-.Fn mktemp "char *template"
-.Ft int
-.Fn mkstemp "char *template"
-.Ft int
-.Fn mkstemps "char *template" "int suffixlen"
-.Ft char *
-.Fn mkdtemp "char *template"
-.In stdlib.h
-.In fcntl.h
-.Ft int
-.Fn mkostemp "char *template" "int flags"
-.Ft int
-.Fn mkostemps "char *template" "int suffixlen" "int flags"
-.Sh DESCRIPTION
-The
-.Fn mktemp
-family of functions take the given file name template and overwrite
-a portion of it to create a new file name.
-This file name is unique and suitable for use by the application.
-The template may be any file name with at least six trailing
-.Em X Ns s ,
-for example
-.Pa /tmp/temp.XXXXXXXX .
-The trailing
-.Em X Ns s
-are replaced with a unique digit and letter combination.
-The number of unique file names that can be returned
-depends on the number of
-.Em X Ns s
-provided;
-.Fn mktemp
-will try at least 2 ** 31 combinations before giving up.
-At least six
-.Em X Ns s
-must be used, though 10 is much better.
-.Pp
-The
-.Fn mktemp
-function generates a temporary file name based on a template as
-described above.
-Because
-.Fn mktemp
-does not actually create the temporary file, there is a window of
-opportunity during which another process can open the file instead.
-Because of this race condition,
-.Fn mktemp
-should not be used where
-.Fn mkstemp
-can be used instead.
-.Fn mktemp
-was marked as a legacy interface in
-.St -p1003.1-2001 .
-.Pp
-The
-.Fn mkstemp
-function makes the same replacement to the template and creates the template
-file, mode 0600, returning a file descriptor opened for reading and writing.
-This avoids the race between testing for a file's existence and opening it
-for use.
-.Pp
-The
-.Fn mkostemp
-function acts the same as
-.Fn mkstemp ,
-except that the
-.Fa flags
-argument may contain zero or more of the following flags for the underlying
-.Xr open 2
-system call:
-.Pp
-.Bl -tag -width "O_CLOEXECXX" -offset indent -compact
-.It Dv O_APPEND
-Append on each write.
-.It Dv O_CLOEXEC
-Set the close-on-exec flag on the new file descriptor.
-.It Dv O_SYNC
-Perform synchronous I/O operations.
-.El
-.Pp
-The
-.Fn mkstemps
-and
-.Fn mkostemps
-functions act the same as
-.Fn mkstemp
-and
-.Fn mkostemp ,
-except they permit a suffix to exist in the template.
-The template should be of the form
-.Pa /tmp/tmpXXXXXXXXXXsuffix .
-.Fn mkstemps
-and
-.Fn mkostemps
-are told the length of the suffix string, i.e.,
-.Li strlen("suffix") .
-.Pp
-The
-.Fn mkdtemp
-function makes the same replacement to the template as in
-.Fn mktemp
-and creates the template directory, mode 0700.
-.Sh RETURN VALUES
-The
-.Fn mktemp
-and
-.Fn mkdtemp
-functions return a pointer to the template on success and
-.Dv NULL
-on failure.
-The
-.Fn mkstemp ,
-.Fn mkostemp ,
-.Fn mkstemps ,
-and
-.Fn mkostemps
-functions return \-1 if no suitable file could be created.
-If any call fails, an error code is placed in the global variable
-.Va errno .
-.Sh EXAMPLES
-Quite often a programmer will want to replace a use of
-.Fn mktemp
-with
-.Fn mkstemp ,
-usually to avoid the problems described above.
-Doing this correctly requires a good understanding of the code in question.
-.Pp
-For instance, code of this form:
-.Bd -literal -offset indent
-char sfn[19];
-FILE *sfp;
-
-strlcpy(sfn, "/tmp/ed.XXXXXXXXXX", sizeof(sfn));
-if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
-       warn("%s", sfn);
-       return (NULL);
-}
-return (sfp);
-.Ed
-.Pp
-should be rewritten like this:
-.Bd -literal -offset indent
-char sfn[19];
-FILE *sfp;
-int fd;
-
-strlcpy(sfn, "/tmp/ed.XXXXXXXXXX", sizeof(sfn));
-if ((fd = mkstemp(sfn)) == -1 ||
-    (sfp = fdopen(fd, "w+")) == NULL) {
-       if (fd != -1) {
-               unlink(sfn);
-               close(fd);
-       }
-       warn("%s", sfn);
-       return (NULL);
-}
-return (sfp);
-.Ed
-.Pp
-Often one will find code which uses
-.Fn mktemp
-very early on, perhaps to globally initialize the template nicely, but the
-code which calls
-.Xr open 2
-or
-.Xr fopen 3
-on that file name will occur much later.
-(In almost all cases, the use of
-.Xr fopen 3
-will mean that the flags
-.Dv O_CREAT
-|
-.Dv O_EXCL
-are not given to
-.Xr open 2 ,
-and thus a symbolic link race becomes possible, hence making
-necessary the use of
-.Xr fdopen 3
-as seen above.)
-Furthermore, one must be careful about code which opens, closes, and then
-re-opens the file in question.
-Finally, one must ensure that upon error the temporary file is
-removed correctly.
-.Pp
-There are also cases where modifying the code to use
-.Fn mktemp ,
-in concert with
-.Xr open 2
-using the flags
-.Dv O_CREAT
-|
-.Dv O_EXCL ,
-is better, as long as the code retries a new template if
-.Xr open 2
-fails with an
-.Va errno
-of
-.Er EEXIST .
-.Sh ERRORS
-The
-.Fn mktemp ,
-.Fn mkstemp ,
-.Fn mkostemp ,
-and
-.Fn mkdtemp
-functions may set
-.Va errno
-to one of the following values:
-.Bl -tag -width Er
-.It Bq Er EINVAL
-The
-.Ar template
-argument has fewer than six trailing
-.Em X Ns s .
-.It Bq Er EEXIST
-All file names tried are already in use.
-Consider appending more
-.Em X Ns s to the
-.Ar template .
-.El
-.Pp
-The
-.Fn mkstemps
-and
-.Fn mkostemps
-functions may set
-.Va errno
-to
-.Bl -tag -width Er
-.It Bq Er EINVAL
-The
-.Ar template
-argument length is less than
-.Ar suffixlen
-or it has fewer than six
-.Em X Ns s
-before the suffix.
-.It Bq Er EEXIST
-All file names tried are already in use.
-Consider appending more
-.Em X Ns s to the
-.Ar template .
-.El
-.Pp
-In addition, the
-.Fn mkostemp
-and
-.Fn mkostemps
-functions may also set
-.Va errno
-to
-.Bl -tag -width Er
-.It Bq Er EINVAL
-.Fa flags
-is invalid.
-.El
-.Pp
-The
-.Fn mktemp
-function may also set
-.Va errno
-to any value specified by the
-.Xr lstat 2
-function.
-.Pp
-The
-.Fn mkstemp ,
-.Fn mkostemp ,
-.Fn mkstemps ,
-and
-.Fn mkostemps
-functions may also set
-.Va errno
-to any value specified by the
-.Xr open 2
-function.
-.Pp
-The
-.Fn mkdtemp
-function may also set
-.Va errno
-to any value specified by the
-.Xr mkdir 2
-function.
-.Sh SEE ALSO
-.Xr chmod 2 ,
-.Xr lstat 2 ,
-.Xr mkdir 2 ,
-.Xr open 2 ,
-.Xr tempnam 3 ,
-.Xr tmpfile 3 ,
-.Xr tmpnam 3
-.Sh STANDARDS
-The
-.Fn mkdtemp
-and
-.Fn mkstemp
-functions conform to the
-.St -p1003.1-2008
-specification.
-The ability to specify more than six
-.Em X Ns s
-is an extension to that standard.
-The
-.Fn mkostemp
-function is expected to conform to a future revision of that standard.
-.Pp
-The
-.Fn mktemp
-function conforms to
-.St -p1003.1-2001 ;
-as of
-.St -p1003.1-2008
-it is no longer a part of the standard.
-.Pp
-The
-.Fn mkstemps
-and
-.Fn mkostemps
-functions are non-standard and should not be used if portability is required.
-.Sh HISTORY
-A
-.Fn mktemp
-function appeared in
-.At v7 .
-The
-.Fn mkdtemp
-function appeared in
-.Ox 2.2 .
-The
-.Fn mkstemp
-function appeared in
-.Bx 4.3 .
-The
-.Fn mkstemps
-function appeared in
-.Ox 2.3 .
-The
-.Fn mkostemp
-and
-.Fn mkostemps
-functions appeared in
-.Ox 5.7 .
-.Sh BUGS
-For
-.Fn mktemp
-there is an obvious race between file name selection and file
-creation and deletion: the program is typically written to call
-.Xr tmpnam 3 ,
-.Xr tempnam 3 ,
-or
-.Fn mktemp .
-Subsequently, the program calls
-.Xr open 2
-or
-.Xr fopen 3
-and erroneously opens a file (or symbolic link, FIFO or other
-device) that the attacker has created in the expected file location.
-Hence
-.Fn mkstemp
-is recommended, since it atomically creates the file.
-An attacker can guess the file names produced by
-.Fn mktemp .
-Whenever it is possible,
-.Fn mkstemp
-or
-.Fn mkdtemp
-should be used instead.
-.Pp
-For this reason,
-.Xr ld 1
-will output a warning message whenever it links code that uses
-.Fn mktemp .
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
deleted file mode 100644 (file)
index ef9a183..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/*     $OpenBSD: mktemp.c,v 1.39 2017/11/28 06:55:49 tb Exp $ */
-/*
- * Copyright (c) 1996-1998, 2008 Theo de Raadt
- * Copyright (c) 1997, 2008-2009 Todd C. Miller
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-
-#define MKTEMP_NAME    0
-#define MKTEMP_FILE    1
-#define MKTEMP_DIR     2
-
-#define TEMPCHARS      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
-#define NUM_CHARS      (sizeof(TEMPCHARS) - 1)
-#define MIN_X          6
-
-#define MKOTEMP_FLAGS  (O_APPEND | O_CLOEXEC | O_DSYNC | O_RSYNC | O_SYNC)
-
-#ifndef nitems
-#define nitems(_a)     (sizeof((_a)) / sizeof((_a)[0]))
-#endif
-
-static int
-mktemp_internal(char *path, int slen, int mode, int flags)
-{
-       char *start, *cp, *ep;
-       const char tempchars[] = TEMPCHARS;
-       unsigned int tries;
-       struct stat sb;
-       size_t len;
-       int fd;
-
-       len = strlen(path);
-       if (len < MIN_X || slen < 0 || (size_t)slen > len - MIN_X) {
-               errno = EINVAL;
-               return(-1);
-       }
-       ep = path + len - slen;
-
-       for (start = ep; start > path && start[-1] == 'X'; start--)
-               ;
-       if (ep - start < MIN_X) {
-               errno = EINVAL;
-               return(-1);
-       }
-
-       if (flags & ~MKOTEMP_FLAGS) {
-               errno = EINVAL;
-               return(-1);
-       }
-       flags |= O_CREAT | O_EXCL | O_RDWR;
-
-       tries = INT_MAX;
-       do {
-               cp = start;
-               do {
-                       unsigned short rbuf[16];
-                       unsigned int i;
-
-                       /*
-                        * Avoid lots of arc4random() calls by using
-                        * a buffer sized for up to 16 Xs at a time.
-                        */
-                       arc4random_buf(rbuf, sizeof(rbuf));
-                       for (i = 0; i < nitems(rbuf) && cp != ep; i++)
-                               *cp++ = tempchars[rbuf[i] % NUM_CHARS];
-               } while (cp != ep);
-
-               switch (mode) {
-               case MKTEMP_NAME:
-                       if (lstat(path, &sb) != 0)
-                               return(errno == ENOENT ? 0 : -1);
-                       break;
-               case MKTEMP_FILE:
-                       fd = open(path, flags, S_IRUSR|S_IWUSR);
-                       if (fd != -1 || errno != EEXIST)
-                               return(fd);
-                       break;
-               case MKTEMP_DIR:
-                       if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0)
-                               return(0);
-                       if (errno != EEXIST)
-                               return(-1);
-                       break;
-               }
-       } while (--tries);
-
-       errno = EEXIST;
-       return(-1);
-}
-
-char *
-_mktemp(char *path)
-{
-       if (mktemp_internal(path, 0, MKTEMP_NAME, 0) == -1)
-               return(NULL);
-       return(path);
-}
-
-__warn_references(mktemp,
-    "mktemp() possibly used unsafely; consider using mkstemp()");
-
-char *
-mktemp(char *path)
-{
-       return(_mktemp(path));
-}
-
-int
-mkostemps(char *path, int slen, int flags)
-{
-       return(mktemp_internal(path, slen, MKTEMP_FILE, flags));
-}
-
-int
-mkstemp(char *path)
-{
-       return(mktemp_internal(path, 0, MKTEMP_FILE, 0));
-}
-DEF_WEAK(mkstemp);
-
-int
-mkostemp(char *path, int flags)
-{
-       return(mktemp_internal(path, 0, MKTEMP_FILE, flags));
-}
-DEF_WEAK(mkostemp);
-
-int
-mkstemps(char *path, int slen)
-{
-       return(mktemp_internal(path, slen, MKTEMP_FILE, 0));
-}
-
-char *
-mkdtemp(char *path)
-{
-       int error;
-
-       error = mktemp_internal(path, 0, MKTEMP_DIR, 0);
-       return(error ? NULL : path);
-}
index 55b8018..fa4836f 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile.inc,v 1.64 2017/12/16 20:06:55 guenther Exp $
+#      $OpenBSD: Makefile.inc,v 1.65 2024/01/19 16:30:28 millert Exp $
 
 # stdlib sources
 .PATH: ${LIBCSRCDIR}/arch/${MACHINE_CPU}/stdlib ${LIBCSRCDIR}/stdlib
@@ -6,7 +6,7 @@
 SRCS+= a64l.c abort.c atexit.c atoi.c atof.c atol.c atoll.c bsearch.c \
        exit.c ecvt.c gcvt.c getenv.c getopt_long.c \
        getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c insque.c \
-       l64a.c llabs.c lldiv.c lsearch.c malloc.c reallocarray.c \
+       l64a.c llabs.c lldiv.c lsearch.c malloc.c mktemp.c reallocarray.c \
        merge.c posix_pty.c qsort.c radixsort.c rand.c random.c \
        realpath.c remque.c setenv.c strtoimax.c \
        strtol.c strtoll.c strtonum.c strtoul.c strtoull.c strtoumax.c \
@@ -28,6 +28,6 @@ SRCS+=        abs.c div.c labs.c ldiv.c
 MAN+=  a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 atoll.3 \
        bsearch.3 div.3 ecvt.3 exit.3 getenv.3 getopt.3 getopt_long.3 \
        getsubopt.3 hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 \
-       lldiv.3 lsearch.3 malloc.3 posix_memalign.3 posix_openpt.3 ptsname.3 \
-       qsort.3 radixsort.3 rand48.3 rand.3 random.3 realpath.3 \
+       lldiv.3 lsearch.3 malloc.3 mktemp.3 posix_memalign.3 posix_openpt.3 \
+       ptsname.3 qsort.3 radixsort.3 rand48.3 rand.3 random.3 realpath.3 \
        strtod.3 strtonum.3 strtol.3 strtoul.3 system.3 tsearch.3
diff --git a/lib/libc/stdlib/mktemp.3 b/lib/libc/stdlib/mktemp.3
new file mode 100644 (file)
index 0000000..d4bd7bd
--- /dev/null
@@ -0,0 +1,415 @@
+.\"    $OpenBSD: mktemp.3,v 1.1 2024/01/19 16:30:28 millert Exp $
+.\"
+.\" Copyright (c) 1989, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd $Mdocdate: January 19 2024 $
+.Dt MKTEMP 3
+.Os
+.Sh NAME
+.Nm mktemp ,
+.Nm mkstemp ,
+.Nm mkostemp ,
+.Nm mkstemps ,
+.Nm mkostemps ,
+.Nm mkdtemp
+.Nd make temporary file name (unique)
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft char *
+.Fn mktemp "char *template"
+.Ft int
+.Fn mkstemp "char *template"
+.Ft int
+.Fn mkstemps "char *template" "int suffixlen"
+.Ft char *
+.Fn mkdtemp "char *template"
+.In stdlib.h
+.In fcntl.h
+.Ft int
+.Fn mkostemp "char *template" "int flags"
+.Ft int
+.Fn mkostemps "char *template" "int suffixlen" "int flags"
+.Sh DESCRIPTION
+The
+.Fn mktemp
+family of functions take the given file name template and overwrite
+a portion of it to create a new file name.
+This file name is unique and suitable for use by the application.
+The template may be any file name with at least six trailing
+.Em X Ns s ,
+for example
+.Pa /tmp/temp.XXXXXXXX .
+The trailing
+.Em X Ns s
+are replaced with a unique digit and letter combination.
+The number of unique file names that can be returned
+depends on the number of
+.Em X Ns s
+provided;
+.Fn mktemp
+will try at least 2 ** 31 combinations before giving up.
+At least six
+.Em X Ns s
+must be used, though 10 is much better.
+.Pp
+The
+.Fn mktemp
+function generates a temporary file name based on a template as
+described above.
+Because
+.Fn mktemp
+does not actually create the temporary file, there is a window of
+opportunity during which another process can open the file instead.
+Because of this race condition,
+.Fn mktemp
+should not be used where
+.Fn mkstemp
+can be used instead.
+.Fn mktemp
+was marked as a legacy interface in
+.St -p1003.1-2001 .
+.Pp
+The
+.Fn mkstemp
+function makes the same replacement to the template and creates the template
+file, mode 0600, returning a file descriptor opened for reading and writing.
+This avoids the race between testing for a file's existence and opening it
+for use.
+.Pp
+The
+.Fn mkostemp
+function acts the same as
+.Fn mkstemp ,
+except that the
+.Fa flags
+argument may contain zero or more of the following flags for the underlying
+.Xr open 2
+system call:
+.Pp
+.Bl -tag -width "O_CLOEXECXX" -offset indent -compact
+.It Dv O_APPEND
+Append on each write.
+.It Dv O_CLOEXEC
+Set the close-on-exec flag on the new file descriptor.
+.It Dv O_SYNC
+Perform synchronous I/O operations.
+.El
+.Pp
+The
+.Fn mkstemps
+and
+.Fn mkostemps
+functions act the same as
+.Fn mkstemp
+and
+.Fn mkostemp ,
+except they permit a suffix to exist in the template.
+The template should be of the form
+.Pa /tmp/tmpXXXXXXXXXXsuffix .
+.Fn mkstemps
+and
+.Fn mkostemps
+are told the length of the suffix string, i.e.,
+.Li strlen("suffix") .
+.Pp
+The
+.Fn mkdtemp
+function makes the same replacement to the template as in
+.Fn mktemp
+and creates the template directory, mode 0700.
+.Sh RETURN VALUES
+The
+.Fn mktemp
+and
+.Fn mkdtemp
+functions return a pointer to the template on success and
+.Dv NULL
+on failure.
+The
+.Fn mkstemp ,
+.Fn mkostemp ,
+.Fn mkstemps ,
+and
+.Fn mkostemps
+functions return \-1 if no suitable file could be created.
+If any call fails, an error code is placed in the global variable
+.Va errno .
+.Sh EXAMPLES
+Quite often a programmer will want to replace a use of
+.Fn mktemp
+with
+.Fn mkstemp ,
+usually to avoid the problems described above.
+Doing this correctly requires a good understanding of the code in question.
+.Pp
+For instance, code of this form:
+.Bd -literal -offset indent
+char sfn[19];
+FILE *sfp;
+
+strlcpy(sfn, "/tmp/ed.XXXXXXXXXX", sizeof(sfn));
+if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
+       warn("%s", sfn);
+       return (NULL);
+}
+return (sfp);
+.Ed
+.Pp
+should be rewritten like this:
+.Bd -literal -offset indent
+char sfn[19];
+FILE *sfp;
+int fd;
+
+strlcpy(sfn, "/tmp/ed.XXXXXXXXXX", sizeof(sfn));
+if ((fd = mkstemp(sfn)) == -1 ||
+    (sfp = fdopen(fd, "w+")) == NULL) {
+       if (fd != -1) {
+               unlink(sfn);
+               close(fd);
+       }
+       warn("%s", sfn);
+       return (NULL);
+}
+return (sfp);
+.Ed
+.Pp
+Often one will find code which uses
+.Fn mktemp
+very early on, perhaps to globally initialize the template nicely, but the
+code which calls
+.Xr open 2
+or
+.Xr fopen 3
+on that file name will occur much later.
+(In almost all cases, the use of
+.Xr fopen 3
+will mean that the flags
+.Dv O_CREAT
+|
+.Dv O_EXCL
+are not given to
+.Xr open 2 ,
+and thus a symbolic link race becomes possible, hence making
+necessary the use of
+.Xr fdopen 3
+as seen above.)
+Furthermore, one must be careful about code which opens, closes, and then
+re-opens the file in question.
+Finally, one must ensure that upon error the temporary file is
+removed correctly.
+.Pp
+There are also cases where modifying the code to use
+.Fn mktemp ,
+in concert with
+.Xr open 2
+using the flags
+.Dv O_CREAT
+|
+.Dv O_EXCL ,
+is better, as long as the code retries a new template if
+.Xr open 2
+fails with an
+.Va errno
+of
+.Er EEXIST .
+.Sh ERRORS
+The
+.Fn mktemp ,
+.Fn mkstemp ,
+.Fn mkostemp ,
+and
+.Fn mkdtemp
+functions may set
+.Va errno
+to one of the following values:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Ar template
+argument has fewer than six trailing
+.Em X Ns s .
+.It Bq Er EEXIST
+All file names tried are already in use.
+Consider appending more
+.Em X Ns s to the
+.Ar template .
+.El
+.Pp
+The
+.Fn mkstemps
+and
+.Fn mkostemps
+functions may set
+.Va errno
+to
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Ar template
+argument length is less than
+.Ar suffixlen
+or it has fewer than six
+.Em X Ns s
+before the suffix.
+.It Bq Er EEXIST
+All file names tried are already in use.
+Consider appending more
+.Em X Ns s to the
+.Ar template .
+.El
+.Pp
+In addition, the
+.Fn mkostemp
+and
+.Fn mkostemps
+functions may also set
+.Va errno
+to
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa flags
+is invalid.
+.El
+.Pp
+The
+.Fn mktemp
+function may also set
+.Va errno
+to any value specified by the
+.Xr lstat 2
+function.
+.Pp
+The
+.Fn mkstemp ,
+.Fn mkostemp ,
+.Fn mkstemps ,
+and
+.Fn mkostemps
+functions may also set
+.Va errno
+to any value specified by the
+.Xr open 2
+function.
+.Pp
+The
+.Fn mkdtemp
+function may also set
+.Va errno
+to any value specified by the
+.Xr mkdir 2
+function.
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr lstat 2 ,
+.Xr mkdir 2 ,
+.Xr open 2 ,
+.Xr tempnam 3 ,
+.Xr tmpfile 3 ,
+.Xr tmpnam 3
+.Sh STANDARDS
+The
+.Fn mkdtemp
+and
+.Fn mkstemp
+functions conform to the
+.St -p1003.1-2008
+specification.
+The ability to specify more than six
+.Em X Ns s
+is an extension to that standard.
+The
+.Fn mkostemp
+function is expected to conform to a future revision of that standard.
+.Pp
+The
+.Fn mktemp
+function conforms to
+.St -p1003.1-2001 ;
+as of
+.St -p1003.1-2008
+it is no longer a part of the standard.
+.Pp
+The
+.Fn mkstemps
+and
+.Fn mkostemps
+functions are non-standard and should not be used if portability is required.
+.Sh HISTORY
+A
+.Fn mktemp
+function appeared in
+.At v7 .
+The
+.Fn mkdtemp
+function appeared in
+.Ox 2.2 .
+The
+.Fn mkstemp
+function appeared in
+.Bx 4.3 .
+The
+.Fn mkstemps
+function appeared in
+.Ox 2.3 .
+The
+.Fn mkostemp
+and
+.Fn mkostemps
+functions appeared in
+.Ox 5.7 .
+.Sh BUGS
+For
+.Fn mktemp
+there is an obvious race between file name selection and file
+creation and deletion: the program is typically written to call
+.Xr tmpnam 3 ,
+.Xr tempnam 3 ,
+or
+.Fn mktemp .
+Subsequently, the program calls
+.Xr open 2
+or
+.Xr fopen 3
+and erroneously opens a file (or symbolic link, FIFO or other
+device) that the attacker has created in the expected file location.
+Hence
+.Fn mkstemp
+is recommended, since it atomically creates the file.
+An attacker can guess the file names produced by
+.Fn mktemp .
+Whenever it is possible,
+.Fn mkstemp
+or
+.Fn mkdtemp
+should be used instead.
+.Pp
+For this reason,
+.Xr ld 1
+will output a warning message whenever it links code that uses
+.Fn mktemp .
diff --git a/lib/libc/stdlib/mktemp.c b/lib/libc/stdlib/mktemp.c
new file mode 100644 (file)
index 0000000..3b8bba7
--- /dev/null
@@ -0,0 +1,163 @@
+/*     $OpenBSD: mktemp.c,v 1.1 2024/01/19 16:30:28 millert Exp $ */
+/*
+ * Copyright (c) 1996-1998, 2008 Theo de Raadt
+ * Copyright (c) 1997, 2008-2009 Todd C. Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#define MKTEMP_NAME    0
+#define MKTEMP_FILE    1
+#define MKTEMP_DIR     2
+
+#define TEMPCHARS      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+#define NUM_CHARS      (sizeof(TEMPCHARS) - 1)
+#define MIN_X          6
+
+#define MKOTEMP_FLAGS  (O_APPEND | O_CLOEXEC | O_DSYNC | O_RSYNC | O_SYNC)
+
+#ifndef nitems
+#define nitems(_a)     (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+static int
+mktemp_internal(char *path, int slen, int mode, int flags)
+{
+       char *start, *cp, *ep;
+       const char tempchars[] = TEMPCHARS;
+       unsigned int tries;
+       struct stat sb;
+       size_t len;
+       int fd;
+
+       len = strlen(path);
+       if (len < MIN_X || slen < 0 || (size_t)slen > len - MIN_X) {
+               errno = EINVAL;
+               return(-1);
+       }
+       ep = path + len - slen;
+
+       for (start = ep; start > path && start[-1] == 'X'; start--)
+               ;
+       if (ep - start < MIN_X) {
+               errno = EINVAL;
+               return(-1);
+       }
+
+       if (flags & ~MKOTEMP_FLAGS) {
+               errno = EINVAL;
+               return(-1);
+       }
+       flags |= O_CREAT | O_EXCL | O_RDWR;
+
+       tries = INT_MAX;
+       do {
+               cp = start;
+               do {
+                       unsigned short rbuf[16];
+                       unsigned int i;
+
+                       /*
+                        * Avoid lots of arc4random() calls by using
+                        * a buffer sized for up to 16 Xs at a time.
+                        */
+                       arc4random_buf(rbuf, sizeof(rbuf));
+                       for (i = 0; i < nitems(rbuf) && cp != ep; i++)
+                               *cp++ = tempchars[rbuf[i] % NUM_CHARS];
+               } while (cp != ep);
+
+               switch (mode) {
+               case MKTEMP_NAME:
+                       if (lstat(path, &sb) != 0)
+                               return(errno == ENOENT ? 0 : -1);
+                       break;
+               case MKTEMP_FILE:
+                       fd = open(path, flags, S_IRUSR|S_IWUSR);
+                       if (fd != -1 || errno != EEXIST)
+                               return(fd);
+                       break;
+               case MKTEMP_DIR:
+                       if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0)
+                               return(0);
+                       if (errno != EEXIST)
+                               return(-1);
+                       break;
+               }
+       } while (--tries);
+
+       errno = EEXIST;
+       return(-1);
+}
+
+char *
+_mktemp(char *path)
+{
+       if (mktemp_internal(path, 0, MKTEMP_NAME, 0) == -1)
+               return(NULL);
+       return(path);
+}
+
+__warn_references(mktemp,
+    "mktemp() possibly used unsafely; consider using mkstemp()");
+
+char *
+mktemp(char *path)
+{
+       return(_mktemp(path));
+}
+
+int
+mkostemps(char *path, int slen, int flags)
+{
+       return(mktemp_internal(path, slen, MKTEMP_FILE, flags));
+}
+
+int
+mkstemp(char *path)
+{
+       return(mktemp_internal(path, 0, MKTEMP_FILE, 0));
+}
+DEF_WEAK(mkstemp);
+
+int
+mkostemp(char *path, int flags)
+{
+       return(mktemp_internal(path, 0, MKTEMP_FILE, flags));
+}
+DEF_WEAK(mkostemp);
+
+int
+mkstemps(char *path, int slen)
+{
+       return(mktemp_internal(path, slen, MKTEMP_FILE, 0));
+}
+
+char *
+mkdtemp(char *path)
+{
+       int error;
+
+       error = mktemp_internal(path, 0, MKTEMP_DIR, 0);
+       return(error ? NULL : path);
+}