diff options
Diffstat (limited to 'src/global/mail_open_ok.c')
-rw-r--r-- | src/global/mail_open_ok.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/global/mail_open_ok.c b/src/global/mail_open_ok.c new file mode 100644 index 0000000..a1bacad --- /dev/null +++ b/src/global/mail_open_ok.c @@ -0,0 +1,127 @@ +/*++ +/* NAME +/* mail_open_ok 3 +/* SUMMARY +/* scrutinize mail queue file +/* SYNOPSIS +/* #include <mail_open_ok.h> +/* +/* int mail_open_ok(queue_name, queue_id, statp, pathp) +/* const char *queue_name; +/* const char *queue_id; +/* struct stat *statp; +/* char **pathp +/* DESCRIPTION +/* mail_open_ok() determines if it is OK to open the specified +/* queue file. +/* +/* The queue name and queue id should conform to the syntax +/* requirements for these names. +/* Unfortunately, on some systems readdir() etc. can return bogus +/* file names. For this reason, the code silently ignores invalid +/* queue file names. +/* +/* The file should have mode 0700. Files with other permissions +/* are silently ignored. +/* +/* The file should be a regular file. +/* Files that do not satisfy this requirement are skipped with +/* a warning. +/* +/* The file link count is not restricted. With a writable maildrop +/* directory, refusal to deliver linked files is prone to denial of +/* service attack; it's better to deliver mail too often than not. +/* +/* Upon return, the \fIstatp\fR argument receives the file +/* attributes and \fIpathp\fR a copy of the file name. The file +/* name is volatile. Make a copy if it is to be used for any +/* appreciable amount of time. +/* DIAGNOSTICS +/* Warnings: bad file attributes (file type), multiple hard links. +/* mail_open_ok() returns MAIL_OPEN_YES for good files, MAIL_OPEN_NO +/* for anything else. It is left up to the system administrator to +/* deal with non-file objects. +/* BUGS +/* mail_open_ok() examines a queue file without actually opening +/* it, and therefore is susceptible to race conditions. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System libraries. */ + +#include <sys_defs.h> +#include <sys/stat.h> +#include <time.h> +#include <errno.h> + +/* Utility library. */ + +#include <msg.h> +#include <warn_stat.h> + +/* Global library. */ + +#include "mail_queue.h" +#include "mail_open_ok.h" + +/* mail_open_ok - see if this file is OK to open */ + +int mail_open_ok(const char *queue_name, const char *queue_id, + struct stat * statp, const char **path) +{ + if (mail_queue_name_ok(queue_name) == 0) { + msg_warn("bad mail queue name: %s", queue_name); + return (MAIL_OPEN_NO); + } + if (mail_queue_id_ok(queue_id) == 0) + return (MAIL_OPEN_NO); + + + /* + * I really would like to look up the file attributes *after* opening the + * file so that we could save one directory traversal on systems without + * name-to-inode cache. However, we don't necessarily always want to open + * the file. + */ + *path = mail_queue_path((VSTRING *) 0, queue_name, queue_id); + + if (lstat(*path, statp) < 0) { + if (errno != ENOENT) + msg_warn("%s: %m", *path); + return (MAIL_OPEN_NO); + } + if (!S_ISREG(statp->st_mode)) { + msg_warn("%s: uid %ld: not a regular file", *path, (long) statp->st_uid); + return (MAIL_OPEN_NO); + } + if ((statp->st_mode & S_IRWXU) != MAIL_QUEUE_STAT_READY) + return (MAIL_OPEN_NO); + + /* + * Workaround for spurious "file has 2 links" warnings in showq. As + * kernels have evolved from non-interruptible system calls towards + * fine-grained locks, the showq command has become likely to observe a + * file while the queue manager is in the middle of renaming it, at a + * time when the file has links to both the old and new name. We now log + * the warning only when the condition appears to be persistent. + */ +#define MINUTE_SECONDS 60 /* XXX should be centralized */ + + if (statp->st_nlink > 1) { + if (msg_verbose) + msg_info("%s: uid %ld: file has %d links", *path, + (long) statp->st_uid, (int) statp->st_nlink); + else if (statp->st_ctime < time((time_t *) 0) - MINUTE_SECONDS) + msg_warn("%s: uid %ld: file has %d links", *path, + (long) statp->st_uid, (int) statp->st_nlink); + } + return (MAIL_OPEN_YES); +} |