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