Start
[exim.git] / src / src / lookups / lf_check_file.c
1 /* $Cambridge: exim/src/src/lookups/lf_check_file.c,v 1.1 2004/10/07 13:10:01 ph10 Exp $ */
2
3 /*************************************************
4 * Exim - an Internet mail transport agent *
5 *************************************************/
6
7 /* Copyright (c) University of Cambridge 1995 - 2004 */
8 /* See the file NOTICE for conditions of use and distribution. */
9
10
11 #include "../exim.h"
12 #include "lf_functions.h"
13
14
15
16 /*************************************************
17 * Check a file's credentials *
18 *************************************************/
19
20 /* fstat can normally be expected to work on an open file, but there are some
21 NFS states where it may not.
22
23 Arguments:
24 fd an open file descriptor or -1
25 filename a file name if fd is -1
26 s_type type of file (S_IFREG or S_IFDIR)
27 modemask a mask specifying mode bits that must *not* be set
28 owners NULL or a list of of allowable uids, count in the first item
29 owngroups NULL or a list of allowable gids, count in the first item
30 type name of lookup type for putting in error message
31 errmsg where to put an error message
32
33 Returns: -1 stat() or fstat() failed
34 0 OK
35 +1 something didn't match
36
37 Side effect: sets errno to ERRNO_BADUGID, ERRNO_NOTREGULAR or ERRNO_BADMODE for
38 bad uid/gid, not a regular file, or bad mode; otherwise leaves it
39 to what fstat set it to.
40 */
41
42 int
43 lf_check_file(int fd, uschar *filename, int s_type, int modemask, uid_t *owners,
44 gid_t *owngroups, char *type, uschar **errmsg)
45 {
46 int i;
47 struct stat statbuf;
48
49 if ((fd >= 0 && fstat(fd, &statbuf) != 0) ||
50 (fd < 0 && Ustat(filename, &statbuf) != 0))
51 {
52 int save_errno = errno;
53 *errmsg = string_sprintf("%s: stat failed", filename);
54 errno = save_errno;
55 return -1;
56 }
57
58 if ((statbuf.st_mode & S_IFMT) != s_type)
59 {
60 if (s_type == S_IFREG)
61 {
62 *errmsg = string_sprintf("%s is not a regular file (%s lookup)",
63 filename, type);
64 errno = ERRNO_NOTREGULAR;
65 }
66 else
67 {
68 *errmsg = string_sprintf("%s is not a directory (%s lookup)",
69 filename, type);
70 errno = ERRNO_NOTDIRECTORY;
71 }
72 return +1;
73 }
74
75 if ((statbuf.st_mode & modemask) != 0)
76 {
77 *errmsg = string_sprintf("%s (%s lookup): file mode %.4o should not contain "
78 "%.4o", filename, type, statbuf.st_mode & 07777,
79 statbuf.st_mode & modemask);
80 errno = ERRNO_BADMODE;
81 return +1;
82 }
83
84 if (owners != NULL)
85 {
86 BOOL uid_ok = FALSE;
87 for (i = 1; i <= (int)owners[0]; i++)
88 if (owners[i] == statbuf.st_uid) { uid_ok = TRUE; break; }
89 if (!uid_ok)
90 {
91 *errmsg = string_sprintf("%s (%s lookup): file has wrong owner", filename,
92 type);
93 errno = ERRNO_BADUGID;
94 return +1;
95 }
96 }
97
98 if (owngroups != NULL)
99 {
100 BOOL gid_ok = FALSE;
101 for (i = 1; i <= (int)owngroups[0]; i++)
102 if (owngroups[i] == statbuf.st_gid) { gid_ok = TRUE; break; }
103 if (!gid_ok)
104 {
105 *errmsg = string_sprintf("%s (%s lookup): file has wrong group", filename,
106 type);
107 errno = ERRNO_BADUGID;
108 return +1;
109 }
110 }
111
112 return 0;
113 }
114
115 /* End of lf_check_file.c */