c3b341bbb858e972a83d1ef8443edf78a6d24b85
[exim.git] / src / src / directory.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2010 - 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2009 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-only */
9
10 #include "exim.h"
11
12
13 /*************************************************
14 *           Attempt to create a directory        *
15 *************************************************/
16
17 /* All the directories that Exim ever creates for itself are within the spool
18 directory as defined by spool_directory. We are prepared to create as many as
19 necessary from that directory downwards, inclusive. However, directory creation
20 can also be required in appendfile and sieve filters. The making function
21 therefore has a parent argument, below which the new directories are to go. It
22 can be NULL if the name is absolute.
23
24 If a non-root uid has been specified for exim, and we are currently running as
25 root, ensure the directory is owned by the non-root id if the parent is the
26 spool directory.
27
28 Arguments:
29   parent    parent directory name; if NULL the name must be absolute
30   name      directory name within the parent that we want
31   mode      mode for the new directory
32   panic     if TRUE, panic on failure
33
34 Returns:    panic on failure if panic is set; otherwise return FALSE;
35             TRUE on success.
36 */
37
38 BOOL
39 directory_make(const uschar *parent, const uschar *name,
40                int mode, BOOL panic)
41 {
42 BOOL use_chown = parent == spool_directory && geteuid() == root_uid;
43 uschar * p;
44 uschar c = 1;
45 struct stat statbuf;
46 uschar * path;
47
48 if (is_tainted(name)) 
49   { p = US"create"; path = US name; errno = ERRNO_TAINT; goto bad; }
50
51 if (parent)
52   {
53   path = string_sprintf("%s%s%s", parent, US"/", name);
54   p = path + Ustrlen(parent);
55   }
56 else
57   {
58   path = string_copy(name);
59   p = path + 1;
60   }
61
62 /* Walk the path creating any missing directories */
63
64 while (c && *p)
65   {
66   while (*p && *p != '/') p++;
67   c = *p;
68   *p = '\0';
69   if (Ustat(path, &statbuf) != 0)
70     {
71     if (mkdir(CS path, mode) < 0 && errno != EEXIST)
72       { p = US"create"; goto bad; }
73
74     /* Set the ownership if necessary. */
75
76     if (use_chown && exim_chown(path, exim_uid, exim_gid))
77       { p = US"set owner on"; goto bad; }
78
79     /* It appears that any mode bits greater than 0777 are ignored by
80     mkdir(), at least on some operating systems. Therefore, if the mode
81     contains any such bits, do an explicit mode setting. */
82
83     if (mode & 0777000) (void) Uchmod(path, mode);
84     }
85   *p++ = c;
86   }
87
88 return TRUE;
89
90 bad:
91   if (panic) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
92     "Failed to %s directory \"%s\": %s\n", p, path, exim_errstr(errno));
93   return FALSE;
94 }
95
96 /* End of directory.c */