Fix out-of-bounds error when incorporating email from stdin
[mmh] / sbr / m_mktemp.c
1 /*
2 ** m_mktemp.c -- Construct a temporary file.
3 **
4 ** This code is Copyright (c) 2010, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <errno.h>
11 #include <unistd.h>
12 #include <sys/stat.h>
13
14 static char *get_temp_dir();
15
16 /*  Create a temporary file.  If pfx_in is null, the temporary file
17 **  will be created in the temporary directory (more on that later).
18 **  If pfx_in is not null, then the temporary file location will be
19 **  defined by the value pfx_in.
20 **
21 **  The file created will be at the pathname specified appended with
22 **  6 random (we hope :) characters.
23 **
24 **  The return value will be the pathname to the file created.
25 **
26 **  CAUTION: The return pointer references static data.  If
27 **  you need to modify, or save, the return string, make a copy of it
28 **  first.
29 **
30 **  When pfx_in is null, the temporary directory is determined as
31 **  follows, in order:
32 **
33 **    MHTMPDIR envvar
34 **    TMPDIR envvar
35 **    TMP envvar
36 **    User's mail directory.
37 **
38 **  NOTE: One will probably use m_mktemp2() instead of this function.
39 **  For example, if you want to create a temp file in the defined
40 **  temporary directory, but with a custom basename prefix, do
41 **  something like the following:
42 **
43 **    char *tmp_pathname = m_mktemp2(NULL, "mypre", ...);
44 */
45 char *
46 m_mktemp(
47         const char *pfx_in,  /* Pathname prefix for temporary file. */
48         int *fd_ret,         /* (return,opt.) File descriptor to temp file. */
49         FILE **fp_ret        /* (return,opt.) FILE pointer to temp file. */
50 )
51 {
52         static char tmpfil[BUFSIZ];
53         int fd = -1;
54         int keep_open = 0;
55         mode_t oldmode = umask(077);
56
57         if (pfx_in == NULL) {
58                 snprintf(tmpfil, sizeof(tmpfil), "%s/nmhXXXXXX",
59                                 get_temp_dir());
60         } else {
61                 snprintf(tmpfil, sizeof(tmpfil), "%sXXXXXX", pfx_in);
62         }
63
64         fd = mkstemp(tmpfil);
65         if (fd < 0) {
66                 umask(oldmode);
67                 return NULL;
68         }
69         if (fd_ret != NULL) {
70                 *fd_ret = fd;
71                 keep_open = 1;
72         }
73         if (fp_ret != NULL) {
74                 FILE *fp = fdopen(fd, "w+");
75                 if (fp == NULL) {
76                         int olderr = errno;
77                         unlink(tmpfil);
78                         close(fd);
79                         errno = olderr;
80                         umask(oldmode);
81                         return NULL;
82                 }
83                 *fp_ret = fp;
84                 keep_open = 1;
85         }
86         if (!keep_open) {
87                 close(fd);
88         }
89         umask(oldmode);
90         return tmpfil;
91 }
92
93 /*
94 ** This version allows one to specify the directory the temp file should
95 ** by created based on a given pathname.  Although m_mktemp() technically
96 ** supports this, this version is when the directory is defined by
97 ** a separate variable from the prefix, eliminating the caller from having
98 ** to do string manipulation to generate the desired. pathname prefix.
99 **
100 ** The pfx_in parameter specifies a basename prefix for the file.  If dir_in
101 ** is NULL, then the defined temporary directory (see comments to m_mktemp()
102 ** above) is used to create the temp file.
103 */
104 char *
105 m_mktemp2(
106         const char *dir_in,   /* Directory to place temp file. */
107         const char *pfx_in,   /* Basename prefix for temp file. */
108         int *fd_ret,          /* (return,opt.) File descriptor to temp file. */
109         FILE **fp_ret         /* (return,opt.) FILE pointer to temp file. */
110 )
111 {
112         static char buffer[BUFSIZ];
113         char *cp;
114         int n;
115
116         if (dir_in == NULL) {
117                 if (pfx_in == NULL) {
118                         return m_mktemp(NULL, fd_ret, fp_ret);
119                 }
120                 snprintf(buffer, sizeof(buffer), "%s/%s", get_temp_dir(), pfx_in);
121                 return m_mktemp(buffer, fd_ret, fp_ret);
122         }
123
124         if ((cp = mhbasename((char *)dir_in)) == dir_in) {
125                 /* No directory component */
126                 return m_mktemp(pfx_in, fd_ret, fp_ret);
127         }
128         n = (int)(cp-dir_in-1); /* Length of dir component */
129         snprintf(buffer, sizeof(buffer), "%.*s/%s", n, dir_in, pfx_in);
130         return m_mktemp(buffer, fd_ret, fp_ret);
131 }
132
133
134 static char *
135 get_temp_dir()
136 {
137         /* Ignore envvars if we are setuid */
138         if ((getuid()==geteuid()) && (getgid()==getegid())) {
139                 char *tmpdir = NULL;
140                 tmpdir = getenv("MHTMPDIR");
141                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
142
143                 tmpdir = getenv("TMPDIR");
144                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
145
146                 tmpdir = getenv("TMP");
147                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
148         }
149         return toabsdir("+");
150 }