1 /*
2  * Temp file utilities for CUPS.
3  *
4  * Copyright © 2007-2018 by Apple Inc.
5  * Copyright © 1997-2006 by Easy Software Products.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8  * information.
9  */
10 
11 /*
12  * Include necessary headers...
13  */
14 
15 #include "cups-private.h"
16 #include "debug-internal.h"
17 #include <stdlib.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #if defined(_WIN32) || defined(__EMX__)
21 #  include <io.h>
22 #else
23 #  include <unistd.h>
24 #endif /* _WIN32 || __EMX__ */
25 
26 
27 /*
28  * 'cupsTempFd()' - Creates a temporary file.
29  *
30  * The temporary filename is returned in the filename buffer.
31  * The temporary file is opened for reading and writing.
32  */
33 
34 int					/* O - New file descriptor or -1 on error */
cupsTempFd(char * filename,int len)35 cupsTempFd(char *filename,		/* I - Pointer to buffer */
36            int  len)			/* I - Size of buffer */
37 {
38   int		fd;			/* File descriptor for temp file */
39   int		tries;			/* Number of tries */
40   const char	*tmpdir;		/* TMPDIR environment var */
41 #if defined(__APPLE__) || defined(_WIN32)
42   char		tmppath[1024];		/* Temporary directory */
43 #endif /* __APPLE__ || _WIN32 */
44 #ifdef _WIN32
45   DWORD		curtime;		/* Current time */
46 #else
47   struct timeval curtime;		/* Current time */
48 #endif /* _WIN32 */
49 
50 
51  /*
52   * See if TMPDIR is defined...
53   */
54 
55 #ifdef _WIN32
56   if ((tmpdir = getenv("TEMP")) == NULL)
57   {
58     GetTempPathA(sizeof(tmppath), tmppath);
59     tmpdir = tmppath;
60   }
61 
62 #elif defined(__APPLE__)
63  /*
64   * On macOS and iOS, the TMPDIR environment variable is not always the best
65   * location to place temporary files due to sandboxing.  Instead, the confstr
66   * function should be called to get the proper per-user, per-process TMPDIR
67   * value.
68   */
69 
70   if ((tmpdir = getenv("TMPDIR")) != NULL && access(tmpdir, W_OK))
71     tmpdir = NULL;
72 
73   if (!tmpdir)
74   {
75     if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmppath, sizeof(tmppath)))
76       tmpdir = tmppath;
77     else
78       tmpdir = "/private/tmp";		/* This should never happen */
79   }
80 
81 #else
82  /*
83   * Previously we put root temporary files in the default CUPS temporary
84   * directory under /var/spool/cups.  However, since the scheduler cleans
85   * out temporary files there and runs independently of the user apps, we
86   * don't want to use it unless specifically told to by cupsd.
87   */
88 
89   if ((tmpdir = getenv("TMPDIR")) == NULL)
90     tmpdir = "/tmp";
91 #endif /* _WIN32 */
92 
93  /*
94   * Make the temporary name using the specified directory...
95   */
96 
97   tries = 0;
98 
99   do
100   {
101 #ifdef _WIN32
102    /*
103     * Get the current time of day...
104     */
105 
106     curtime =  GetTickCount() + tries;
107 
108    /*
109     * Format a string using the hex time values...
110     */
111 
112     snprintf(filename, (size_t)len - 1, "%s/%05lx%08lx", tmpdir, GetCurrentProcessId(), curtime);
113 #else
114    /*
115     * Get the current time of day...
116     */
117 
118     gettimeofday(&curtime, NULL);
119 
120    /*
121     * Format a string using the hex time values...
122     */
123 
124     snprintf(filename, (size_t)len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(), (unsigned)(curtime.tv_sec + curtime.tv_usec + tries));
125 #endif /* _WIN32 */
126 
127    /*
128     * Open the file in "exclusive" mode, making sure that we don't
129     * stomp on an existing file or someone's symlink crack...
130     */
131 
132 #ifdef _WIN32
133     fd = open(filename, _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY,
134               _S_IREAD | _S_IWRITE);
135 #elif defined(O_NOFOLLOW)
136     fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
137 #else
138     fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
139 #endif /* _WIN32 */
140 
141     if (fd < 0 && errno != EEXIST)
142       break;
143 
144     tries ++;
145   }
146   while (fd < 0 && tries < 1000);
147 
148  /*
149   * Return the file descriptor...
150   */
151 
152   return (fd);
153 }
154 
155 
156 /*
157  * 'cupsTempFile()' - Generates a temporary filename.
158  *
159  * The temporary filename is returned in the filename buffer.
160  * This function is deprecated and will no longer generate a temporary
161  * filename - use @link cupsTempFd@ or @link cupsTempFile2@ instead.
162  *
163  * @deprecated@
164  */
165 
166 char *					/* O - Filename or @code NULL@ on error */
cupsTempFile(char * filename,int len)167 cupsTempFile(char *filename,		/* I - Pointer to buffer */
168              int  len)			/* I - Size of buffer */
169 {
170   (void)len;
171 
172   if (filename)
173     *filename = '\0';
174 
175   return (NULL);
176 }
177 
178 
179 /*
180  * 'cupsTempFile2()' - Creates a temporary CUPS file.
181  *
182  * The temporary filename is returned in the filename buffer.
183  * The temporary file is opened for writing.
184  *
185  * @since CUPS 1.2/macOS 10.5@
186  */
187 
188 cups_file_t *				/* O - CUPS file or @code NULL@ on error */
cupsTempFile2(char * filename,int len)189 cupsTempFile2(char *filename,		/* I - Pointer to buffer */
190               int  len)			/* I - Size of buffer */
191 {
192   cups_file_t	*file;			/* CUPS file */
193   int		fd;			/* File descriptor */
194 
195 
196   if ((fd = cupsTempFd(filename, len)) < 0)
197     return (NULL);
198   else if ((file = cupsFileOpenFd(fd, "w")) == NULL)
199   {
200     close(fd);
201     unlink(filename);
202     return (NULL);
203   }
204   else
205     return (file);
206 }
207