xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/mail_open_ok.c (revision b49cc1491953ef2348eff9c84520ffd0678a5c8d)
1 /*	$NetBSD: mail_open_ok.c,v 1.1.1.1 2009/06/23 10:08:46 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	mail_open_ok 3
6 /* SUMMARY
7 /*	scrutinize mail queue file
8 /* SYNOPSIS
9 /*	#include <mail_open_ok.h>
10 /*
11 /*	int	mail_open_ok(queue_name, queue_id, statp, pathp)
12 /*	const char *queue_name;
13 /*	const char *queue_id;
14 /*	struct stat *statp;
15 /*	char	**pathp
16 /* DESCRIPTION
17 /*	mail_open_ok() determines if it is OK to open the specified
18 /*	queue file.
19 /*
20 /*	The queue name and queue id should conform to the syntax
21 /*	requirements for these names.
22 /*	Unfortunately, on some systems readdir() etc. can return bogus
23 /*	file names. For this reason, the code silently ignores invalid
24 /*	queue file names.
25 /*
26 /*	The file should have mode 0700. Files with other permissions
27 /*	are silently ignored.
28 /*
29 /*	The file should be a regular file.
30 /*	Files that do not satisfy this requirement are skipped with
31 /*	a warning.
32 /*
33 /*	The file link count is not restricted. With a writable maildrop
34 /*	directory, refusal to deliver linked files is prone to denial of
35 /*	service attack; it's better to deliver mail too often than not.
36 /*
37 /*	Upon return, the \fIstatp\fR argument receives the file
38 /*	attributes and \fIpathp\fR a copy of the file name. The file
39 /*	name is volatile. Make a copy if it is to be used for any
40 /*	appreciable amount of time.
41 /* DIAGNOSTICS
42 /*	Warnings: bad file attributes (file type), multiple hard links.
43 /*	mail_open_ok() returns MAIL_OPEN_YES for good files, MAIL_OPEN_NO
44 /*	for anything else. It is left up to the system administrator to
45 /*	deal with non-file objects.
46 /* BUGS
47 /*	mail_open_ok() examines a queue file without actually opening
48 /*	it, and therefore is susceptible to race conditions.
49 /* LICENSE
50 /* .ad
51 /* .fi
52 /*	The Secure Mailer license must be distributed with this software.
53 /* AUTHOR(S)
54 /*	Wietse Venema
55 /*	IBM T.J. Watson Research
56 /*	P.O. Box 704
57 /*	Yorktown Heights, NY 10598, USA
58 /*--*/
59 
60 /* System libraries. */
61 
62 #include <sys_defs.h>
63 #include <sys/stat.h>
64 #include <time.h>
65 #include <errno.h>
66 
67 /* Utility library. */
68 
69 #include <msg.h>
70 
71 /* Global library. */
72 
73 #include "mail_queue.h"
74 #include "mail_open_ok.h"
75 
76 /* mail_open_ok - see if this file is OK to open */
77 
78 int     mail_open_ok(const char *queue_name, const char *queue_id,
79 		             struct stat * statp, const char **path)
80 {
81     if (mail_queue_name_ok(queue_name) == 0) {
82 	msg_warn("bad mail queue name: %s", queue_name);
83 	return (MAIL_OPEN_NO);
84     }
85     if (mail_queue_id_ok(queue_id) == 0)
86 	return (MAIL_OPEN_NO);
87 
88 
89     /*
90      * I really would like to look up the file attributes *after* opening the
91      * file so that we could save one directory traversal on systems without
92      * name-to-inode cache. However, we don't necessarily always want to open
93      * the file.
94      */
95     *path = mail_queue_path((VSTRING *) 0, queue_name, queue_id);
96 
97     if (lstat(*path, statp) < 0) {
98 	if (errno != ENOENT)
99 	    msg_warn("%s: %m", *path);
100 	return (MAIL_OPEN_NO);
101     }
102     if (!S_ISREG(statp->st_mode)) {
103 	msg_warn("%s: uid %ld: not a regular file", *path, (long) statp->st_uid);
104 	return (MAIL_OPEN_NO);
105     }
106     if ((statp->st_mode & S_IRWXU) != MAIL_QUEUE_STAT_READY)
107 	return (MAIL_OPEN_NO);
108 
109     /*
110      * Workaround for spurious "file has 2 links" warnings in showq. As
111      * kernels have evolved from non-interruptible system calls towards
112      * fine-grained locks, the showq command has become likely to observe a
113      * file while the queue manager is in the middle of renaming it, at a
114      * time when the file has links to both the old and new name. We now log
115      * the warning only when the condition appears to be persistent.
116      */
117 #define MINUTE_SECONDS	60			/* XXX should be centralized */
118 
119     if (statp->st_nlink > 1) {
120 	if (msg_verbose)
121 	    msg_info("%s: uid %ld: file has %d links", *path,
122 		     (long) statp->st_uid, (int) statp->st_nlink);
123 	else if (statp->st_ctime < time((time_t *) 0) - MINUTE_SECONDS)
124 	    msg_warn("%s: uid %ld: file has %d links", *path,
125 		     (long) statp->st_uid, (int) statp->st_nlink);
126     }
127     return (MAIL_OPEN_YES);
128 }
129