1 /* lock.c: The opielock() library function.
3 %%% portions-copyright-cmetz-96
4 Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights
5 Reserved. The Inner Net License Version 2 applies to these portions of
7 You should have received a copy of the license with this software. If
8 you didn't get a copy, you may request one from <license@inner.net>.
10 Portions of this software are Copyright 1995 by Randall Atkinson and Dan
11 McDonald, All Rights Reserved. All Rights under this copyright are assigned
12 to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
13 License Agreement applies to this software.
17 Modified by cmetz for OPIE 2.4. Use snprintf.
18 Modified by cmetz for OPIE 2.31. Put locks in a separate dir.
20 Modified by cmetz for OPIE 2.3. Do refcounts whether or not we
21 actually lock. Fixed USER_LOCKING=0 case.
22 Modified by cmetz for OPIE 2.22. Added reference count for locks.
23 Changed lock filename/refcount symbol names to better indicate
24 that they're not user serviceable.
25 Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al.
26 Use "principal" instead of "name" to make it clearer.
27 Ifdef around some headers, be more careful about allowed
28 error return values. Check open() return value properly.
30 Created at NRL for OPIE 2.2 from opiesubr2.c
37 #endif /* HAVE_STRING_H */
40 #endif /* HAVE_UNISTD_H */
46 #endif /* HAVE_STDLIB_H */
51 #define lstat(x, y) stat(x, y)
52 #endif /* !HAVE_LSTAT */
54 int __opie_lockrefcount = 0;
55 static int do_atexit = 1;
57 VOIDRET opiedisableaeh FUNCTION_NOARGS
62 char *__opie_lockfilename = (char *)0;
64 /* atexit() handler for opielock() */
65 VOIDRET opieunlockaeh FUNCTION_NOARGS
67 if (__opie_lockfilename) {
68 __opie_lockrefcount = 0;
72 #endif /* USER_LOCKING */
75 Serialize (we hope) authentication of user to prevent race conditions.
76 Creates a lock file with a name of OPIE_LOCK_PREFIX with the user name
77 appended. This file contains the pid of the lock's owner and a time()
78 stamp. We use the former to check for dead owners and the latter to
79 provide an upper bound on the lock duration. If there are any problems,
80 we assume the lock is bogus.
82 The value of this locking and its security implications are still not
83 completely clear and require further study.
85 One could conceivably hack this facility to provide locking of user
86 accounts after several authentication failures.
88 Return -1 on low-level error, 0 if ok, 1 on locking failure.
90 int opielock FUNCTION((principal), char *principal)
93 int fh, waits = 0, rval = -1, pid, t, i;
94 char buffer[128], buffer2[128], *c, *c2;
95 struct stat statbuf[2];
97 if (getuid() && geteuid()) {
99 syslog(LOG_DEBUG, "opielock: requires superuser priveleges");
104 if (__opie_lockfilename) {
105 __opie_lockrefcount++;
109 if (!(__opie_lockfilename = (char *)malloc(sizeof(OPIE_LOCK_DIR) + 1 + strlen(principal))))
112 strcpy(__opie_lockfilename, OPIE_LOCK_DIR);
114 if (mkdir(__opie_lockfilename, 0700) < 0)
118 if (lstat(__opie_lockfilename, &statbuf[0]) < 0)
121 if (statbuf[0].st_uid) {
123 syslog(LOG_DEBUG, "opielock: %s isn't owned by the superuser.", __opie_lockfilename);
128 if (!S_ISDIR(statbuf[0].st_mode)) {
130 syslog(LOG_DEBUG, "opielock: %s isn't a directory.", __opie_lockfilename);
135 if ((statbuf[0].st_mode & 0777) != 00700) {
137 syslog(LOG_DEBUG, "opielock: permissions on %s are not correct.", __opie_lockfilename);
142 strcat(__opie_lockfilename, "/");
143 strcat(__opie_lockfilename, principal);
147 if (!lstat(__opie_lockfilename, &statbuf[0]))
148 if (!S_ISREG(statbuf[0].st_mode))
151 if ((fh = open(__opie_lockfilename, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0) {
152 if (lstat(__opie_lockfilename, &statbuf[1]) < 0)
154 if (statbuf[0].st_ino != statbuf[1].st_ino)
156 if (statbuf[0].st_mode != statbuf[1].st_mode)
158 if ((fh = open(__opie_lockfilename, O_RDONLY, 0600)) < 0)
160 if ((i = read(fh, buffer, sizeof(buffer))) <= 0)
163 buffer[sizeof(buffer) - 1] = 0;
166 if (!(c = strchr(buffer, '\n')))
171 if (!(c2 = strchr(c, '\n')))
176 if (!(pid = atoi(buffer)))
182 if ((t + OPIE_LOCK_TIMEOUT) < time(0))
198 if (lstat(__opie_lockfilename, &statbuf[0]) < 0)
200 if (fstat(fh, &statbuf[1]) < 0)
202 if (!S_ISREG(statbuf[0].st_mode) || (statbuf[0].st_mode != statbuf[1].st_mode) || (statbuf[0].st_ino != statbuf[1].st_ino))
205 if (snprintf(buffer, sizeof(buffer), "%d\n%d\n", getpid(), time(0)) >= sizeof(buffer))
208 i = strlen(buffer) + 1;
209 if (lseek(fh, 0, SEEK_SET)) {
211 unlink(__opie_lockfilename);
215 if (write(fh, buffer, i) != i) {
217 unlink(__opie_lockfilename);
222 if ((fh = open(__opie_lockfilename, O_RDWR, 0600)) < 0) {
223 unlink(__opie_lockfilename);
226 if (read(fh, buffer2, i) != i) {
228 unlink(__opie_lockfilename);
233 if (memcmp(buffer, buffer2, i)) {
234 unlink(__opie_lockfilename);
238 __opie_lockrefcount++;
241 atexit(opieunlockaeh);
246 if (!__opie_lockrefcount) {
247 free (__opie_lockfilename);
248 __opie_lockfilename = NULL;
251 #else /* USER_LOCKING */
252 __opie_lockrefcount++;
254 #endif /* USER_LOCKING */