summaryrefslogtreecommitdiffstats
path: root/src/directory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/directory.c')
-rw-r--r--src/directory.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/directory.c b/src/directory.c
new file mode 100644
index 0000000..1890208
--- /dev/null
+++ b/src/directory.c
@@ -0,0 +1,95 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) The Exim Maintainers 2010 - 2022 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+#include "exim.h"
+
+
+/*************************************************
+* Attempt to create a directory *
+*************************************************/
+
+/* All the directories that Exim ever creates for itself are within the spool
+directory as defined by spool_directory. We are prepared to create as many as
+necessary from that directory downwards, inclusive. However, directory creation
+can also be required in appendfile and sieve filters. The making function
+therefore has a parent argument, below which the new directories are to go. It
+can be NULL if the name is absolute.
+
+If a non-root uid has been specified for exim, and we are currently running as
+root, ensure the directory is owned by the non-root id if the parent is the
+spool directory.
+
+Arguments:
+ parent parent directory name; if NULL the name must be absolute
+ name directory name within the parent that we want
+ mode mode for the new directory
+ panic if TRUE, panic on failure
+
+Returns: panic on failure if panic is set; otherwise return FALSE;
+ TRUE on success.
+*/
+
+BOOL
+directory_make(const uschar *parent, const uschar *name,
+ int mode, BOOL panic)
+{
+BOOL use_chown = parent == spool_directory && geteuid() == root_uid;
+uschar * p;
+uschar c = 1;
+struct stat statbuf;
+uschar * path;
+
+if (is_tainted(name))
+ { p = US"create"; path = US name; errno = ERRNO_TAINT; goto bad; }
+
+if (parent)
+ {
+ path = string_sprintf("%s%s%s", parent, US"/", name);
+ p = path + Ustrlen(parent);
+ }
+else
+ {
+ path = string_copy(name);
+ p = path + 1;
+ }
+
+/* Walk the path creating any missing directories */
+
+while (c && *p)
+ {
+ while (*p && *p != '/') p++;
+ c = *p;
+ *p = '\0';
+ if (Ustat(path, &statbuf) != 0)
+ {
+ if (mkdir(CS path, mode) < 0 && errno != EEXIST)
+ { p = US"create"; goto bad; }
+
+ /* Set the ownership if necessary. */
+
+ if (use_chown && exim_chown(path, exim_uid, exim_gid))
+ { p = US"set owner on"; goto bad; }
+
+ /* It appears that any mode bits greater than 0777 are ignored by
+ mkdir(), at least on some operating systems. Therefore, if the mode
+ contains any such bits, do an explicit mode setting. */
+
+ if (mode & 0777000) (void) Uchmod(path, mode);
+ }
+ *p++ = c;
+ }
+
+return TRUE;
+
+bad:
+ if (panic) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "Failed to %s directory \"%s\": %s\n", p, path, exim_errstr(errno));
+ return FALSE;
+}
+
+/* End of directory.c */