1 /* $NetBSD: mail_open_ok.c,v 1.1.1.2 2013/01/02 18:58:58 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 #include <warn_stat.h> 71 72 /* Global library. */ 73 74 #include "mail_queue.h" 75 #include "mail_open_ok.h" 76 77 /* mail_open_ok - see if this file is OK to open */ 78 79 int mail_open_ok(const char *queue_name, const char *queue_id, 80 struct stat * statp, const char **path) 81 { 82 if (mail_queue_name_ok(queue_name) == 0) { 83 msg_warn("bad mail queue name: %s", queue_name); 84 return (MAIL_OPEN_NO); 85 } 86 if (mail_queue_id_ok(queue_id) == 0) 87 return (MAIL_OPEN_NO); 88 89 90 /* 91 * I really would like to look up the file attributes *after* opening the 92 * file so that we could save one directory traversal on systems without 93 * name-to-inode cache. However, we don't necessarily always want to open 94 * the file. 95 */ 96 *path = mail_queue_path((VSTRING *) 0, queue_name, queue_id); 97 98 if (lstat(*path, statp) < 0) { 99 if (errno != ENOENT) 100 msg_warn("%s: %m", *path); 101 return (MAIL_OPEN_NO); 102 } 103 if (!S_ISREG(statp->st_mode)) { 104 msg_warn("%s: uid %ld: not a regular file", *path, (long) statp->st_uid); 105 return (MAIL_OPEN_NO); 106 } 107 if ((statp->st_mode & S_IRWXU) != MAIL_QUEUE_STAT_READY) 108 return (MAIL_OPEN_NO); 109 110 /* 111 * Workaround for spurious "file has 2 links" warnings in showq. As 112 * kernels have evolved from non-interruptible system calls towards 113 * fine-grained locks, the showq command has become likely to observe a 114 * file while the queue manager is in the middle of renaming it, at a 115 * time when the file has links to both the old and new name. We now log 116 * the warning only when the condition appears to be persistent. 117 */ 118 #define MINUTE_SECONDS 60 /* XXX should be centralized */ 119 120 if (statp->st_nlink > 1) { 121 if (msg_verbose) 122 msg_info("%s: uid %ld: file has %d links", *path, 123 (long) statp->st_uid, (int) statp->st_nlink); 124 else if (statp->st_ctime < time((time_t *) 0) - MINUTE_SECONDS) 125 msg_warn("%s: uid %ld: file has %d links", *path, 126 (long) statp->st_uid, (int) statp->st_nlink); 127 } 128 return (MAIL_OPEN_YES); 129 } 130