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