1/* $NetBSD$ */ 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 78int 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