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