lock.c revision 22347
1/* lock.c: The opielock() library function. 2 3%%% portions-copyright-cmetz 4Portions of this software are Copyright 1996 by Craig Metz, All Rights 5Reserved. The Inner Net License Version 2 applies to these portions of 6the software. 7You should have received a copy of the license with this software. If 8you didn't get a copy, you may request one from <license@inner.net>. 9 10Portions of this software are Copyright 1995 by Randall Atkinson and Dan 11McDonald, All Rights Reserved. All Rights under this copyright are assigned 12to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 13License Agreement applies to this software. 14 15 History: 16 17 Modified by cmetz for OPIE 2.3. Do refcounts whether or not we 18 actually lock. Fixed USER_LOCKING=0 case. 19 Modified by cmetz for OPIE 2.22. Added reference count for locks. 20 Changed lock filename/refcount symbol names to better indicate 21 that they're not user serviceable. 22 Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. 23 Use "principal" instead of "name" to make it clearer. 24 Ifdef around some headers, be more careful about allowed 25 error return values. Check open() return value properly. 26 Avoid NULL. 27 Created at NRL for OPIE 2.2 from opiesubr2.c 28*/ 29#include "opie_cfg.h" 30#if HAVE_STRING_H 31#include <string.h> 32#endif /* HAVE_STRING_H */ 33#if HAVE_UNISTD_H 34#include <unistd.h> 35#endif /* HAVE_UNISTD_H */ 36#include <fcntl.h> 37#if HAVE_STDLIB_H 38#include <stdlib.h> 39#endif /* HAVE_STDLIB_H */ 40#include "opie.h" 41 42int __opie_lockrefcount = 0; 43 44#if USER_LOCKING 45char *__opie_lockfilename = (char *)0; 46 47/* atexit() handler for opielock() */ 48static VOIDRET opieunlockaeh FUNCTION_NOARGS 49{ 50 if (__opie_lockfilename) { 51 __opie_lockrefcount = 0; 52 opieunlock(); 53 } 54} 55#endif /* USER_LOCKING */ 56 57/* 58 Serialize (we hope) authentication of user to prevent race conditions. 59 Creates a lock file with a name of OPIE_LOCK_PREFIX with the user name 60 appended. This file contains the pid of the lock's owner and a time() 61 stamp. We use the former to check for dead owners and the latter to 62 provide an upper bound on the lock duration. If there are any problems, 63 we assume the lock is bogus. 64 65 The value of this locking and its security implications are still not 66 completely clear and require further study. 67 68 One could conceivably hack this facility to provide locking of user 69 accounts after several authentication failures. 70 71 Return -1 on low-level error, 0 if ok, 1 on locking failure. 72*/ 73int opielock FUNCTION((principal), char *principal) 74{ 75#if USER_LOCKING 76 int fh, waits = 0, rval = -1, pid, t, i; 77 char buffer[128], buffer2[128], *c, *c2; 78 79 if (__opie_lockfilename) { 80 __opie_lockrefcount++; 81 return 0; 82 } 83 84 if (!(__opie_lockfilename = (char *)malloc(sizeof(OPIE_LOCK_PREFIX) + strlen(principal)))) 85 return -1; 86 87 strcpy(__opie_lockfilename, OPIE_LOCK_PREFIX); 88 strcat(__opie_lockfilename, principal); 89 90 fh = 0; 91 while (!fh) 92 if ((fh = open(__opie_lockfilename, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0) { 93 if ((fh = open(__opie_lockfilename, O_RDWR, 0600)) < 0) 94 goto lockret; 95 if ((i = read(fh, buffer, sizeof(buffer))) <= 0) 96 goto lockret; 97 98 buffer[sizeof(buffer) - 1] = 0; 99 buffer[i - 1] = 0; 100 101 if (!(c = strchr(buffer, '\n'))) 102 break; 103 104 *(c++) = 0; 105 106 if (!(c2 = strchr(c, '\n'))) 107 break; 108 109 *(c2++) = 0; 110 111 if (!(pid = atoi(buffer))) 112 break; 113 114 if (!(t = atoi(c))) 115 break; 116 117 if ((time(0) + OPIE_LOCK_TIMEOUT) < t) 118 break; 119 120 if (kill(pid, 0)) 121 break; 122 123 close(fh); 124 fh = 0; 125 sleep(1); 126 if (waits++ > 3) { 127 rval = 1; 128 goto lockret; 129 }; 130 }; 131 132 sprintf(buffer, "%d\n%d\n", getpid(), time(0)); 133 i = strlen(buffer) + 1; 134 if (lseek(fh, 0, SEEK_SET)) { 135 close(fh); 136 unlink(__opie_lockfilename); 137 fh = 0; 138 goto lockret; 139 }; 140 if (write(fh, buffer, i) != i) { 141 close(fh); 142 unlink(__opie_lockfilename); 143 fh = 0; 144 goto lockret; 145 }; 146 close(fh); 147 if ((fh = open(__opie_lockfilename, O_RDWR, 0600)) < 0) { 148 unlink(__opie_lockfilename); 149 goto lockret; 150 }; 151 if (read(fh, buffer2, i) != i) { 152 close(fh); 153 unlink(__opie_lockfilename); 154 fh = 0; 155 goto lockret; 156 }; 157 close(fh); 158 if (memcmp(buffer, buffer2, i)) { 159 unlink(__opie_lockfilename); 160 goto lockret; 161 }; 162 163 __opie_lockrefcount++; 164 rval = 0; 165 atexit(opieunlockaeh); 166 167lockret: 168 if (fh) 169 close(fh); 170 return rval; 171#else /* USER_LOCKING */ 172 __opie_lockrefcount++; 173 return 0; 174#endif /* USER_LOCKING */ 175} 176