122347Spst/* lock.c: The opielock() library function. 222347Spst 329964Sache%%% portions-copyright-cmetz-96 492914SmarkmPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights 522347SpstReserved. The Inner Net License Version 2 applies to these portions of 622347Spstthe software. 722347SpstYou should have received a copy of the license with this software. If 822347Spstyou didn't get a copy, you may request one from <license@inner.net>. 922347Spst 1022347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan 1122347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned 1222347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 1322347SpstLicense Agreement applies to this software. 1422347Spst 1522347Spst History: 1622347Spst 1792914Smarkm Modified by cmetz for OPIE 2.4. Use snprintf. 1829964Sache Modified by cmetz for OPIE 2.31. Put locks in a separate dir. 1929964Sache Bug fixes. 2022347Spst Modified by cmetz for OPIE 2.3. Do refcounts whether or not we 2122347Spst actually lock. Fixed USER_LOCKING=0 case. 2222347Spst Modified by cmetz for OPIE 2.22. Added reference count for locks. 2322347Spst Changed lock filename/refcount symbol names to better indicate 2422347Spst that they're not user serviceable. 2522347Spst Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. 2622347Spst Use "principal" instead of "name" to make it clearer. 2722347Spst Ifdef around some headers, be more careful about allowed 2822347Spst error return values. Check open() return value properly. 2922347Spst Avoid NULL. 3022347Spst Created at NRL for OPIE 2.2 from opiesubr2.c 3159300Skris 3259300Skris$FreeBSD$ 3322347Spst*/ 3422347Spst#include "opie_cfg.h" 3522347Spst#if HAVE_STRING_H 3622347Spst#include <string.h> 3722347Spst#endif /* HAVE_STRING_H */ 3822347Spst#if HAVE_UNISTD_H 3922347Spst#include <unistd.h> 4022347Spst#endif /* HAVE_UNISTD_H */ 4129964Sache#include <sys/stat.h> 4229964Sache#include <syslog.h> 4322347Spst#include <fcntl.h> 4422347Spst#if HAVE_STDLIB_H 4522347Spst#include <stdlib.h> 4622347Spst#endif /* HAVE_STDLIB_H */ 4729964Sache#include <errno.h> 4822347Spst#include "opie.h" 4922347Spst 5029964Sache#if !HAVE_LSTAT 5129964Sache#define lstat(x, y) stat(x, y) 5229964Sache#endif /* !HAVE_LSTAT */ 5329964Sache 5422347Spstint __opie_lockrefcount = 0; 5559300Skrisstatic int do_atexit = 1; 5622347Spst 5759300SkrisVOIDRET opiedisableaeh FUNCTION_NOARGS 5859300Skris{ 5959300Skris do_atexit = 0; 6059300Skris} 6122347Spst#if USER_LOCKING 6222347Spstchar *__opie_lockfilename = (char *)0; 6322347Spst 6422347Spst/* atexit() handler for opielock() */ 6559300SkrisVOIDRET opieunlockaeh FUNCTION_NOARGS 6622347Spst{ 6722347Spst if (__opie_lockfilename) { 6822347Spst __opie_lockrefcount = 0; 6922347Spst opieunlock(); 7022347Spst } 7122347Spst} 7222347Spst#endif /* USER_LOCKING */ 7322347Spst 7422347Spst/* 7522347Spst Serialize (we hope) authentication of user to prevent race conditions. 7622347Spst Creates a lock file with a name of OPIE_LOCK_PREFIX with the user name 7722347Spst appended. This file contains the pid of the lock's owner and a time() 7822347Spst stamp. We use the former to check for dead owners and the latter to 7922347Spst provide an upper bound on the lock duration. If there are any problems, 8022347Spst we assume the lock is bogus. 8122347Spst 8222347Spst The value of this locking and its security implications are still not 8322347Spst completely clear and require further study. 8422347Spst 8522347Spst One could conceivably hack this facility to provide locking of user 8622347Spst accounts after several authentication failures. 8722347Spst 8822347Spst Return -1 on low-level error, 0 if ok, 1 on locking failure. 8922347Spst*/ 9022347Spstint opielock FUNCTION((principal), char *principal) 9122347Spst{ 9222347Spst#if USER_LOCKING 9322347Spst int fh, waits = 0, rval = -1, pid, t, i; 9422347Spst char buffer[128], buffer2[128], *c, *c2; 9529964Sache struct stat statbuf[2]; 9622347Spst 9729964Sache if (getuid() && geteuid()) { 9829964Sache#if DEBUG 9929964Sache syslog(LOG_DEBUG, "opielock: requires superuser priveleges"); 10029964Sache#endif /* DEBUG */ 10129964Sache return -1; 10229964Sache }; 10329964Sache 10422347Spst if (__opie_lockfilename) { 10522347Spst __opie_lockrefcount++; 10622347Spst return 0; 10722347Spst } 10822347Spst 10929964Sache if (!(__opie_lockfilename = (char *)malloc(sizeof(OPIE_LOCK_DIR) + 1 + strlen(principal)))) 11022347Spst return -1; 11122347Spst 11229964Sache strcpy(__opie_lockfilename, OPIE_LOCK_DIR); 11329964Sache 11429964Sache if (mkdir(__opie_lockfilename, 0700) < 0) 11529964Sache if (errno != EEXIST) 11629964Sache return -1; 11729964Sache 11829964Sache if (lstat(__opie_lockfilename, &statbuf[0]) < 0) 11929964Sache return -1; 12029964Sache 12129964Sache if (statbuf[0].st_uid) { 12229964Sache#if DEBUG 12329964Sache syslog(LOG_DEBUG, "opielock: %s isn't owned by the superuser.", __opie_lockfilename); 12429964Sache#endif /* DEBUG */ 12529964Sache return -1; 12629964Sache }; 12729964Sache 12829964Sache if (!S_ISDIR(statbuf[0].st_mode)) { 12929964Sache#if DEBUG 13029964Sache syslog(LOG_DEBUG, "opielock: %s isn't a directory.", __opie_lockfilename); 13129964Sache#endif /* DEBUG */ 13229964Sache return -1; 13329964Sache }; 13429964Sache 13529964Sache if ((statbuf[0].st_mode & 0777) != 00700) { 13629964Sache#if DEBUG 13729964Sache syslog(LOG_DEBUG, "opielock: permissions on %s are not correct.", __opie_lockfilename); 13829964Sache#endif /* DEBUG */ 13929964Sache return -1; 14029964Sache }; 14129964Sache 14229964Sache strcat(__opie_lockfilename, "/"); 14322347Spst strcat(__opie_lockfilename, principal); 14422347Spst 14529964Sache fh = -1; 14629964Sache while (fh < 0) { 14729964Sache if (!lstat(__opie_lockfilename, &statbuf[0])) 14829964Sache if (!S_ISREG(statbuf[0].st_mode)) 14929964Sache goto lockret; 15029964Sache 15122347Spst if ((fh = open(__opie_lockfilename, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0) { 15229964Sache if (lstat(__opie_lockfilename, &statbuf[1]) < 0) 15322347Spst goto lockret; 15429964Sache if (statbuf[0].st_ino != statbuf[1].st_ino) 15529964Sache goto lockret; 15629964Sache if (statbuf[0].st_mode != statbuf[1].st_mode) 15729964Sache goto lockret; 15829964Sache if ((fh = open(__opie_lockfilename, O_RDONLY, 0600)) < 0) 15929964Sache goto lockret; 16022347Spst if ((i = read(fh, buffer, sizeof(buffer))) <= 0) 16122347Spst goto lockret; 16222347Spst 16322347Spst buffer[sizeof(buffer) - 1] = 0; 16422347Spst buffer[i - 1] = 0; 16522347Spst 16622347Spst if (!(c = strchr(buffer, '\n'))) 16722347Spst break; 16822347Spst 16922347Spst *(c++) = 0; 17022347Spst 17122347Spst if (!(c2 = strchr(c, '\n'))) 17222347Spst break; 17322347Spst 17422347Spst *(c2++) = 0; 17522347Spst 17622347Spst if (!(pid = atoi(buffer))) 17722347Spst break; 17822347Spst 17922347Spst if (!(t = atoi(c))) 18022347Spst break; 18122347Spst 18229964Sache if ((t + OPIE_LOCK_TIMEOUT) < time(0)) 18322347Spst break; 18422347Spst 18522347Spst if (kill(pid, 0)) 18622347Spst break; 18722347Spst 18822347Spst close(fh); 18922347Spst fh = 0; 19022347Spst sleep(1); 19122347Spst if (waits++ > 3) { 19222347Spst rval = 1; 19322347Spst goto lockret; 19422347Spst }; 19522347Spst }; 19629964Sache }; 19722347Spst 19829964Sache if (lstat(__opie_lockfilename, &statbuf[0]) < 0) 19929964Sache goto lockret; 20029964Sache if (fstat(fh, &statbuf[1]) < 0) 20129964Sache goto lockret; 20229964Sache if (!S_ISREG(statbuf[0].st_mode) || (statbuf[0].st_mode != statbuf[1].st_mode) || (statbuf[0].st_ino != statbuf[1].st_ino)) 20329964Sache goto lockret; 20429964Sache 20592914Smarkm if (snprintf(buffer, sizeof(buffer), "%d\n%d\n", getpid(), time(0)) >= sizeof(buffer)) 20692914Smarkm goto lockret; 20792914Smarkm 20822347Spst i = strlen(buffer) + 1; 20922347Spst if (lseek(fh, 0, SEEK_SET)) { 21022347Spst close(fh); 21122347Spst unlink(__opie_lockfilename); 21222347Spst fh = 0; 21322347Spst goto lockret; 21422347Spst }; 21522347Spst if (write(fh, buffer, i) != i) { 21622347Spst close(fh); 21722347Spst unlink(__opie_lockfilename); 21822347Spst fh = 0; 21922347Spst goto lockret; 22022347Spst }; 22122347Spst close(fh); 22222347Spst if ((fh = open(__opie_lockfilename, O_RDWR, 0600)) < 0) { 22322347Spst unlink(__opie_lockfilename); 22422347Spst goto lockret; 22522347Spst }; 22622347Spst if (read(fh, buffer2, i) != i) { 22722347Spst close(fh); 22822347Spst unlink(__opie_lockfilename); 22922347Spst fh = 0; 23022347Spst goto lockret; 23122347Spst }; 23222347Spst close(fh); 23322347Spst if (memcmp(buffer, buffer2, i)) { 23422347Spst unlink(__opie_lockfilename); 23522347Spst goto lockret; 23622347Spst }; 23722347Spst 23822347Spst __opie_lockrefcount++; 23922347Spst rval = 0; 24059300Skris if (do_atexit) 24159300Skris atexit(opieunlockaeh); 24222347Spst 24322347Spstlockret: 24429964Sache if (fh >= 0) 24522347Spst close(fh); 24629964Sache if (!__opie_lockrefcount) { 24729964Sache free (__opie_lockfilename); 24829964Sache __opie_lockfilename = NULL; 24929964Sache }; 25022347Spst return rval; 25122347Spst#else /* USER_LOCKING */ 25222347Spst __opie_lockrefcount++; 25322347Spst return 0; 25422347Spst#endif /* USER_LOCKING */ 25522347Spst} 256