lock.c revision 59300
1229997Sken/* lock.c: The opielock() library function. 2229997Sken 3232604Strasz%%% portions-copyright-cmetz-96 4229997SkenPortions of this software are Copyright 1996-1998 by Craig Metz, All Rights 5229997SkenReserved. The Inner Net License Version 2 applies to these portions of 6232604Straszthe software. 7232604StraszYou should have received a copy of the license with this software. If 8232604Straszyou didn't get a copy, you may request one from <license@inner.net>. 9229997Sken 10229997SkenPortions of this software are Copyright 1995 by Randall Atkinson and Dan 11229997SkenMcDonald, All Rights Reserved. All Rights under this copyright are assigned 12229997Skento the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 13229997SkenLicense Agreement applies to this software. 14229997Sken 15229997Sken History: 16229997Sken 17229997Sken Modified by cmetz for OPIE 2.31. Put locks in a separate dir. 18229997Sken Bug fixes. 19229997Sken Modified by cmetz for OPIE 2.3. Do refcounts whether or not we 20229997Sken actually lock. Fixed USER_LOCKING=0 case. 21229997Sken Modified by cmetz for OPIE 2.22. Added reference count for locks. 22229997Sken Changed lock filename/refcount symbol names to better indicate 23229997Sken that they're not user serviceable. 24229997Sken Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. 25229997Sken Use "principal" instead of "name" to make it clearer. 26229997Sken Ifdef around some headers, be more careful about allowed 27229997Sken error return values. Check open() return value properly. 28229997Sken Avoid NULL. 29229997Sken Created at NRL for OPIE 2.2 from opiesubr2.c 30229997Sken 31229997Sken$FreeBSD: head/contrib/opie/libopie/lock.c 59300 2000-04-17 00:01:23Z kris $ 32229997Sken*/ 33229997Sken#include "opie_cfg.h" 34229997Sken#if HAVE_STRING_H 35229997Sken#include <string.h> 36229997Sken#endif /* HAVE_STRING_H */ 37229997Sken#if HAVE_UNISTD_H 38229997Sken#include <unistd.h> 39229997Sken#endif /* HAVE_UNISTD_H */ 40229997Sken#include <sys/stat.h> 41229997Sken#include <syslog.h> 42229997Sken#include <fcntl.h> 43229997Sken#if HAVE_STDLIB_H 44229997Sken#include <stdlib.h> 45229997Sken#endif /* HAVE_STDLIB_H */ 46229997Sken#include <errno.h> 47229997Sken#include "opie.h" 48229997Sken 49229997Sken#if !HAVE_LSTAT 50229997Sken#define lstat(x, y) stat(x, y) 51229997Sken#endif /* !HAVE_LSTAT */ 52229997Sken 53229997Skenint __opie_lockrefcount = 0; 54229997Skenstatic int do_atexit = 1; 55249009Strasz 56229997SkenVOIDRET opiedisableaeh FUNCTION_NOARGS 57229997Sken{ 58229997Sken do_atexit = 0; 59229997Sken} 60229997Sken#if USER_LOCKING 61229997Skenchar *__opie_lockfilename = (char *)0; 62229997Sken 63229997Sken/* atexit() handler for opielock() */ 64229997SkenVOIDRET opieunlockaeh FUNCTION_NOARGS 65229997Sken{ 66229997Sken if (__opie_lockfilename) { 67229997Sken __opie_lockrefcount = 0; 68229997Sken opieunlock(); 69229997Sken } 70229997Sken} 71229997Sken#endif /* USER_LOCKING */ 72229997Sken 73229997Sken/* 74229997Sken Serialize (we hope) authentication of user to prevent race conditions. 75229997Sken Creates a lock file with a name of OPIE_LOCK_PREFIX with the user name 76229997Sken appended. This file contains the pid of the lock's owner and a time() 77229997Sken stamp. We use the former to check for dead owners and the latter to 78229997Sken provide an upper bound on the lock duration. If there are any problems, 79229997Sken we assume the lock is bogus. 80229997Sken 81229997Sken The value of this locking and its security implications are still not 82229997Sken completely clear and require further study. 83229997Sken 84229997Sken One could conceivably hack this facility to provide locking of user 85229997Sken accounts after several authentication failures. 86229997Sken 87229997Sken Return -1 on low-level error, 0 if ok, 1 on locking failure. 88229997Sken*/ 89229997Skenint opielock FUNCTION((principal), char *principal) 90229997Sken{ 91229997Sken#if USER_LOCKING 92229997Sken int fh, waits = 0, rval = -1, pid, t, i; 93249019Strasz char buffer[128], buffer2[128], *c, *c2; 94249019Strasz struct stat statbuf[2]; 95249019Strasz 96229997Sken if (getuid() && geteuid()) { 97229997Sken#if DEBUG 98229997Sken syslog(LOG_DEBUG, "opielock: requires superuser priveleges"); 99229997Sken#endif /* DEBUG */ 100229997Sken return -1; 101229997Sken }; 102229997Sken 103229997Sken if (__opie_lockfilename) { 104229997Sken __opie_lockrefcount++; 105229997Sken return 0; 106229997Sken } 107229997Sken 108229997Sken if (!(__opie_lockfilename = (char *)malloc(sizeof(OPIE_LOCK_DIR) + 1 + strlen(principal)))) 109229997Sken return -1; 110229997Sken 111229997Sken strcpy(__opie_lockfilename, OPIE_LOCK_DIR); 112229997Sken 113229997Sken if (mkdir(__opie_lockfilename, 0700) < 0) 114229997Sken if (errno != EEXIST) 115229997Sken return -1; 116229997Sken 117229997Sken if (lstat(__opie_lockfilename, &statbuf[0]) < 0) 118229997Sken return -1; 119229997Sken 120229997Sken if (statbuf[0].st_uid) { 121229997Sken#if DEBUG 122229997Sken syslog(LOG_DEBUG, "opielock: %s isn't owned by the superuser.", __opie_lockfilename); 123229997Sken#endif /* DEBUG */ 124229997Sken return -1; 125229997Sken }; 126229997Sken 127229997Sken if (!S_ISDIR(statbuf[0].st_mode)) { 128229997Sken#if DEBUG 129229997Sken syslog(LOG_DEBUG, "opielock: %s isn't a directory.", __opie_lockfilename); 130229997Sken#endif /* DEBUG */ 131229997Sken return -1; 132229997Sken }; 133229997Sken 134229997Sken if ((statbuf[0].st_mode & 0777) != 00700) { 135229997Sken#if DEBUG 136229997Sken syslog(LOG_DEBUG, "opielock: permissions on %s are not correct.", __opie_lockfilename); 137229997Sken#endif /* DEBUG */ 138229997Sken return -1; 139229997Sken }; 140229997Sken 141229997Sken strcat(__opie_lockfilename, "/"); 142229997Sken strcat(__opie_lockfilename, principal); 143229997Sken 144229997Sken fh = -1; 145229997Sken while (fh < 0) { 146229997Sken if (!lstat(__opie_lockfilename, &statbuf[0])) 147229997Sken if (!S_ISREG(statbuf[0].st_mode)) 148229997Sken goto lockret; 149229997Sken 150229997Sken if ((fh = open(__opie_lockfilename, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0) { 151229997Sken if (lstat(__opie_lockfilename, &statbuf[1]) < 0) 152229997Sken goto lockret; 153229997Sken if (statbuf[0].st_ino != statbuf[1].st_ino) 154229997Sken goto lockret; 155229997Sken if (statbuf[0].st_mode != statbuf[1].st_mode) 156229997Sken goto lockret; 157229997Sken if ((fh = open(__opie_lockfilename, O_RDONLY, 0600)) < 0) 158229997Sken goto lockret; 159229997Sken if ((i = read(fh, buffer, sizeof(buffer))) <= 0) 160229997Sken goto lockret; 161229997Sken 162229997Sken buffer[sizeof(buffer) - 1] = 0; 163229997Sken buffer[i - 1] = 0; 164229997Sken 165229997Sken if (!(c = strchr(buffer, '\n'))) 166229997Sken break; 167229997Sken 168229997Sken *(c++) = 0; 169229997Sken 170229997Sken if (!(c2 = strchr(c, '\n'))) 171229997Sken break; 172229997Sken 173229997Sken *(c2++) = 0; 174229997Sken 175229997Sken if (!(pid = atoi(buffer))) 176229997Sken break; 177229997Sken 178229997Sken if (!(t = atoi(c))) 179229997Sken break; 180229997Sken 181229997Sken if ((t + OPIE_LOCK_TIMEOUT) < time(0)) 182229997Sken break; 183229997Sken 184229997Sken if (kill(pid, 0)) 185229997Sken break; 186229997Sken 187229997Sken close(fh); 188229997Sken fh = 0; 189229997Sken sleep(1); 190229997Sken if (waits++ > 3) { 191229997Sken rval = 1; 192229997Sken goto lockret; 193229997Sken }; 194229997Sken }; 195229997Sken }; 196229997Sken 197229997Sken if (lstat(__opie_lockfilename, &statbuf[0]) < 0) 198229997Sken goto lockret; 199229997Sken if (fstat(fh, &statbuf[1]) < 0) 200229997Sken goto lockret; 201229997Sken if (!S_ISREG(statbuf[0].st_mode) || (statbuf[0].st_mode != statbuf[1].st_mode) || (statbuf[0].st_ino != statbuf[1].st_ino)) 202229997Sken goto lockret; 203229997Sken 204229997Sken sprintf(buffer, "%d\n%d\n", getpid(), time(0)); 205229997Sken i = strlen(buffer) + 1; 206229997Sken if (lseek(fh, 0, SEEK_SET)) { 207229997Sken close(fh); 208229997Sken unlink(__opie_lockfilename); 209229997Sken fh = 0; 210229997Sken goto lockret; 211229997Sken }; 212229997Sken if (write(fh, buffer, i) != i) { 213229997Sken close(fh); 214229997Sken unlink(__opie_lockfilename); 215229997Sken fh = 0; 216229997Sken goto lockret; 217229997Sken }; 218229997Sken close(fh); 219229997Sken if ((fh = open(__opie_lockfilename, O_RDWR, 0600)) < 0) { 220229997Sken unlink(__opie_lockfilename); 221229997Sken goto lockret; 222229997Sken }; 223229997Sken if (read(fh, buffer2, i) != i) { 224229997Sken close(fh); 225229997Sken unlink(__opie_lockfilename); 226229997Sken fh = 0; 227229997Sken goto lockret; 228229997Sken }; 229229997Sken close(fh); 230229997Sken if (memcmp(buffer, buffer2, i)) { 231229997Sken unlink(__opie_lockfilename); 232229997Sken goto lockret; 233229997Sken }; 234229997Sken 235229997Sken __opie_lockrefcount++; 236229997Sken rval = 0; 237229997Sken if (do_atexit) 238229997Sken atexit(opieunlockaeh); 239229997Sken 240229997Skenlockret: 241229997Sken if (fh >= 0) 242229997Sken close(fh); 243229997Sken if (!__opie_lockrefcount) { 244229997Sken free (__opie_lockfilename); 245229997Sken __opie_lockfilename = NULL; 246229997Sken }; 247229997Sken return rval; 248229997Sken#else /* USER_LOCKING */ 249229997Sken __opie_lockrefcount++; 250229997Sken return 0; 251229997Sken#endif /* USER_LOCKING */ 252229997Sken} 253229997Sken