1 /* $OpenBSD: locking.c,v 1.2 1998/08/15 23:11:30 millert Exp $ */ 2 3 /* 4 * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> 5 * Copyright (c) 1996-1998 David Mazieres <dm@lcs.mit.edu> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the authors may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 21 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 * THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #ifndef lint 32 static char rcsid[] = "$OpenBSD: locking.c,v 1.2 1998/08/15 23:11:30 millert Exp $"; 33 #endif /* not lint */ 34 35 #include <sys/param.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <pwd.h> 39 #include <syslog.h> 40 #include <time.h> 41 #include <unistd.h> 42 #include <errno.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include "pathnames.h" 46 #include "mail.local.h" 47 48 static char lpath[MAXPATHLEN]; 49 50 void 51 rellock() 52 { 53 54 if (lpath[0]) 55 unlink(lpath); 56 } 57 58 int 59 getlock(name, pw) 60 char *name; 61 struct passwd *pw; 62 { 63 struct stat sb, fsb; 64 int lfd=-1; 65 char buf[8*1024]; 66 int tries = 0; 67 68 (void)snprintf(lpath, sizeof lpath, "%s/%s.lock", 69 _PATH_MAILDIR, name); 70 71 if (stat(_PATH_MAILDIR, &sb) != -1 && 72 (sb.st_mode & S_IWOTH) == S_IWOTH) { 73 /* 74 * We have a writeable spool, deal with it as 75 * securely as possible. 76 */ 77 time_t ctim = -1; 78 79 seteuid(pw->pw_uid); 80 if (lstat(lpath, &sb) != -1) 81 ctim = sb.st_ctime; 82 while (1) { 83 /* 84 * Deal with existing user.lock files 85 * or directories or symbolic links that 86 * should not be here. 87 */ 88 if (readlink(lpath, buf, sizeof buf-1) != -1) { 89 if (lstat(lpath, &sb) != -1 && 90 S_ISLNK(fsb.st_mode)) { 91 seteuid(sb.st_uid); 92 unlink(lpath); 93 seteuid(pw->pw_uid); 94 } 95 goto again; 96 } 97 if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK, 98 S_IRUSR|S_IWUSR)) != -1) 99 break; 100 again: 101 if (tries > 10) { 102 err(NOTFATAL, "%s: %s", lpath, 103 strerror(errno)); 104 seteuid(0); 105 return(-1); 106 } 107 if (tries > 9 && 108 (lfd = open(lpath, O_WRONLY|O_EXLOCK, 0)) != -1) { 109 if (fstat(lfd, &fsb) != -1 && 110 lstat(lpath, &sb) != -1) { 111 if (fsb.st_dev == sb.st_dev && 112 fsb.st_ino == sb.st_ino && 113 ctim == fsb.st_ctime ) { 114 seteuid(fsb.st_uid); 115 baditem(lpath); 116 seteuid(pw->pw_uid); 117 } 118 } 119 } 120 sleep(1 << tries); 121 tries++; 122 continue; 123 } 124 seteuid(0); 125 } else { 126 /* 127 * Only root can write the spool directory. 128 */ 129 while (1) { 130 if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL, 131 S_IRUSR|S_IWUSR)) != -1) 132 break; 133 if (tries > 9) { 134 err(NOTFATAL, "%s: %s", lpath, strerror(errno)); 135 return(-1); 136 } 137 sleep(1 << tries); 138 tries++; 139 } 140 } 141 return(lfd); 142 } 143 144 void 145 baditem(path) 146 char *path; 147 { 148 char npath[MAXPATHLEN]; 149 150 if (unlink(path) == 0) 151 return; 152 snprintf(npath, sizeof npath, "%s/mailXXXXXXXXXX", _PATH_MAILDIR); 153 if (mktemp(npath) == NULL) 154 return; 155 if (rename(path, npath) == -1) 156 unlink(npath); 157 else 158 err(NOTFATAL, "nasty spool item %s renamed to %s", 159 path, npath); 160 /* XXX if we fail to rename, another attempt will happen later */ 161 } 162 163 #ifdef __STDC__ 164 #include <stdarg.h> 165 #else 166 #include <varargs.h> 167 #endif 168 169 void 170 #ifdef __STDC__ 171 err(int isfatal, const char *fmt, ...) 172 #else 173 err(isfatal, fmt) 174 int isfatal; 175 char *fmt; 176 va_dcl 177 #endif 178 { 179 va_list ap; 180 #ifdef __STDC__ 181 va_start(ap, fmt); 182 #else 183 va_start(ap); 184 #endif 185 vsyslog(LOG_ERR, fmt, ap); 186 va_end(ap); 187 if (isfatal) 188 exit(1); 189 } 190