1004388ebScasper /*
254925bf6Swillf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3004388ebScasper  * Use is subject to license terms.
4004388ebScasper  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
7*55fea89dSDan Cross  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
107c478bd9Sstevel@tonic-gate  *	this source code.  Do *NOT* create a derivative of this
117c478bd9Sstevel@tonic-gate  *	source code before consulting with your legal department.
127c478bd9Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
137c478bd9Sstevel@tonic-gate  *	product before consulting with your legal department.
147c478bd9Sstevel@tonic-gate  *
157c478bd9Sstevel@tonic-gate  *	For further information, read the top-level Openvision
167c478bd9Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
177c478bd9Sstevel@tonic-gate  *	copyright.
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
207c478bd9Sstevel@tonic-gate  *
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate /*
257c478bd9Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include	<sys/file.h>
297c478bd9Sstevel@tonic-gate #include	<fcntl.h>
307c478bd9Sstevel@tonic-gate #include	<unistd.h>
3154925bf6Swillf #include        <k5-int.h>
3254925bf6Swillf #include	"policy_db.h"
337c478bd9Sstevel@tonic-gate #include	<stdlib.h>
3454925bf6Swillf #include        <db.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #define MAX_LOCK_TRIES 5
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate struct _locklist {
397c478bd9Sstevel@tonic-gate      osa_adb_lock_ent lockinfo;
407c478bd9Sstevel@tonic-gate      struct _locklist *next;
417c478bd9Sstevel@tonic-gate };
427c478bd9Sstevel@tonic-gate 
osa_adb_create_db(char * filename,char * lockfilename,int magic)4354925bf6Swillf krb5_error_code osa_adb_create_db(char *filename, char *lockfilename,
4454925bf6Swillf 				  int magic)
457c478bd9Sstevel@tonic-gate {
467c478bd9Sstevel@tonic-gate      int lf;
477c478bd9Sstevel@tonic-gate      DB *db;
4856a424ccSmp      BTREEINFO btinfo;
49*55fea89dSDan Cross 
5056a424ccSmp      memset(&btinfo, 0, sizeof(btinfo));
5156a424ccSmp      btinfo.flags = 0;
5256a424ccSmp      btinfo.cachesize = 0;
5356a424ccSmp      btinfo.psize = 4096;
5456a424ccSmp      btinfo.lorder = 0;
5556a424ccSmp      btinfo.minkeypage = 0;
5656a424ccSmp      btinfo.compare = NULL;
5756a424ccSmp      btinfo.prefix = NULL;
5856a424ccSmp      db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_BTREE, &btinfo);
597c478bd9Sstevel@tonic-gate      if (db == NULL)
607c478bd9Sstevel@tonic-gate 	  return errno;
617c478bd9Sstevel@tonic-gate      if (db->close(db) < 0)
627c478bd9Sstevel@tonic-gate 	  return errno;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate      /* only create the lock file if we successfully created the db */
657c478bd9Sstevel@tonic-gate      lf = THREEPARAMOPEN(lockfilename, O_RDWR | O_CREAT | O_EXCL, 0600);
667c478bd9Sstevel@tonic-gate      if (lf == -1)
677c478bd9Sstevel@tonic-gate 	  return errno;
687c478bd9Sstevel@tonic-gate      (void) close(lf);
69*55fea89dSDan Cross 
707c478bd9Sstevel@tonic-gate      return OSA_ADB_OK;
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate 
osa_adb_destroy_db(char * filename,char * lockfilename,int magic)7354925bf6Swillf krb5_error_code osa_adb_destroy_db(char *filename, char *lockfilename,
747c478bd9Sstevel@tonic-gate 				 int magic)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate      /* the admin databases do not contain security-critical data */
777c478bd9Sstevel@tonic-gate      if (unlink(filename) < 0 ||
787c478bd9Sstevel@tonic-gate 	 unlink(lockfilename) < 0)
797c478bd9Sstevel@tonic-gate 	  return errno;
807c478bd9Sstevel@tonic-gate      return OSA_ADB_OK;
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
osa_adb_rename_db(char * filefrom,char * lockfrom,char * fileto,char * lockto,int magic)8354925bf6Swillf krb5_error_code osa_adb_rename_db(char *filefrom, char *lockfrom,
847c478bd9Sstevel@tonic-gate 				char *fileto, char *lockto, int magic)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate      osa_adb_db_t fromdb, todb;
8754925bf6Swillf      krb5_error_code ret;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate      /* make sure todb exists */
9054925bf6Swillf      /*LINTED*/
917c478bd9Sstevel@tonic-gate      if ((ret = osa_adb_create_db(fileto, lockto, magic)) &&
927c478bd9Sstevel@tonic-gate 	 ret != EEXIST)
937c478bd9Sstevel@tonic-gate 	  return ret;
947c478bd9Sstevel@tonic-gate 
9556a424ccSmp      if ((ret = osa_adb_init_db(&fromdb, filefrom, lockfrom, magic)))
967c478bd9Sstevel@tonic-gate 	  return ret;
9756a424ccSmp      if ((ret = osa_adb_init_db(&todb, fileto, lockto, magic))) {
987c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(fromdb, magic);
997c478bd9Sstevel@tonic-gate 	  return ret;
1007c478bd9Sstevel@tonic-gate      }
10154925bf6Swillf      if ((ret = osa_adb_get_lock(fromdb, KRB5_DB_LOCKMODE_PERMANENT))) {
1027c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(fromdb, magic);
1037c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(todb, magic);
1047c478bd9Sstevel@tonic-gate 	  return ret;
1057c478bd9Sstevel@tonic-gate      }
10654925bf6Swillf      if ((ret = osa_adb_get_lock(todb, KRB5_DB_LOCKMODE_PERMANENT))) {
1077c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(fromdb, magic);
1087c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(todb, magic);
1097c478bd9Sstevel@tonic-gate 	  return ret;
1107c478bd9Sstevel@tonic-gate      }
11156a424ccSmp      if ((rename(filefrom, fileto) < 0)) {
1127c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(fromdb, magic);
1137c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(todb, magic);
1147c478bd9Sstevel@tonic-gate 	  return errno;
1157c478bd9Sstevel@tonic-gate      }
1167c478bd9Sstevel@tonic-gate      /*
1177c478bd9Sstevel@tonic-gate       * Do not release the lock on fromdb because it is being renamed
1187c478bd9Sstevel@tonic-gate       * out of existence; no one can ever use it again.
1197c478bd9Sstevel@tonic-gate       */
12056a424ccSmp      if ((ret = osa_adb_release_lock(todb))) {
1217c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(fromdb, magic);
1227c478bd9Sstevel@tonic-gate 	  (void) osa_adb_fini_db(todb, magic);
1237c478bd9Sstevel@tonic-gate 	  return ret;
1247c478bd9Sstevel@tonic-gate      }
125*55fea89dSDan Cross 
1267c478bd9Sstevel@tonic-gate      (void) osa_adb_fini_db(fromdb, magic);
1277c478bd9Sstevel@tonic-gate      (void) osa_adb_fini_db(todb, magic);
1287c478bd9Sstevel@tonic-gate      return 0;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
osa_adb_init_db(osa_adb_db_t * dbp,char * filename,char * lockfilename,int magic)13154925bf6Swillf krb5_error_code osa_adb_init_db(osa_adb_db_t *dbp, char *filename,
1327c478bd9Sstevel@tonic-gate 			      char *lockfilename, int magic)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate      osa_adb_db_t db;
1357c478bd9Sstevel@tonic-gate      static struct _locklist *locklist = NULL;
1367c478bd9Sstevel@tonic-gate      struct _locklist *lockp;
1377c478bd9Sstevel@tonic-gate      krb5_error_code code;
138*55fea89dSDan Cross 
1397c478bd9Sstevel@tonic-gate      if (dbp == NULL || filename == NULL)
1407c478bd9Sstevel@tonic-gate 	  return EINVAL;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate      db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent));
1437c478bd9Sstevel@tonic-gate      if (db == NULL)
1447c478bd9Sstevel@tonic-gate 	  return ENOMEM;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate      memset(db, 0, sizeof(*db));
1477c478bd9Sstevel@tonic-gate      db->info.hash = NULL;
1487c478bd9Sstevel@tonic-gate      db->info.bsize = 256;
1497c478bd9Sstevel@tonic-gate      db->info.ffactor = 8;
1507c478bd9Sstevel@tonic-gate      db->info.nelem = 25000;
1517c478bd9Sstevel@tonic-gate      db->info.lorder = 0;
1527c478bd9Sstevel@tonic-gate 
15356a424ccSmp      db->btinfo.flags = 0;
15456a424ccSmp      db->btinfo.cachesize = 0;
15556a424ccSmp      db->btinfo.psize = 4096;
15656a424ccSmp      db->btinfo.lorder = 0;
15756a424ccSmp      db->btinfo.minkeypage = 0;
15856a424ccSmp      db->btinfo.compare = NULL;
15956a424ccSmp      db->btinfo.prefix = NULL;
1607c478bd9Sstevel@tonic-gate      /*
1617c478bd9Sstevel@tonic-gate       * A process is allowed to open the same database multiple times
1627c478bd9Sstevel@tonic-gate       * and access it via different handles.  If the handles use
1637c478bd9Sstevel@tonic-gate       * distinct lockinfo structures, things get confused: lock(A),
1647c478bd9Sstevel@tonic-gate       * lock(B), release(B) will result in the kernel unlocking the
1657c478bd9Sstevel@tonic-gate       * lock file but handle A will still think the file is locked.
1667c478bd9Sstevel@tonic-gate       * Therefore, all handles using the same lock file must share a
1677c478bd9Sstevel@tonic-gate       * single lockinfo structure.
1687c478bd9Sstevel@tonic-gate       *
1697c478bd9Sstevel@tonic-gate       * It is not sufficient to have a single lockinfo structure,
1707c478bd9Sstevel@tonic-gate       * however, because a single process may also wish to open
1717c478bd9Sstevel@tonic-gate       * multiple different databases simultaneously, with different
1727c478bd9Sstevel@tonic-gate       * lock files.  This code used to use a single static lockinfo
1737c478bd9Sstevel@tonic-gate       * structure, which means that the second database opened used
1747c478bd9Sstevel@tonic-gate       * the first database's lock file.  This was Bad.
1757c478bd9Sstevel@tonic-gate       *
1767c478bd9Sstevel@tonic-gate       * We now maintain a linked list of lockinfo structures, keyed by
1777c478bd9Sstevel@tonic-gate       * lockfilename.  An entry is added when this function is called
1787c478bd9Sstevel@tonic-gate       * with a new lockfilename, and all subsequent calls with that
1797c478bd9Sstevel@tonic-gate       * lockfilename use the existing entry, updating the refcnt.
1807c478bd9Sstevel@tonic-gate       * When the database is closed with fini_db(), the refcnt is
1817c478bd9Sstevel@tonic-gate       * decremented, and when it is zero the lockinfo structure is
1827c478bd9Sstevel@tonic-gate       * freed and reset.  The entry in the linked list, however, is
1837c478bd9Sstevel@tonic-gate       * never removed; it will just be reinitialized the next time
1847c478bd9Sstevel@tonic-gate       * init_db is called with the right lockfilename.
1857c478bd9Sstevel@tonic-gate       */
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate      /* find or create the lockinfo structure for lockfilename */
1887c478bd9Sstevel@tonic-gate      lockp = locklist;
1897c478bd9Sstevel@tonic-gate      while (lockp) {
1907c478bd9Sstevel@tonic-gate 	  if (strcmp(lockp->lockinfo.filename, lockfilename) == 0)
1917c478bd9Sstevel@tonic-gate 	       break;
1927c478bd9Sstevel@tonic-gate 	  else
1937c478bd9Sstevel@tonic-gate 	       lockp = lockp->next;
1947c478bd9Sstevel@tonic-gate      }
1957c478bd9Sstevel@tonic-gate      if (lockp == NULL) {
1967c478bd9Sstevel@tonic-gate 	  /* doesn't exist, create it, add to list */
1977c478bd9Sstevel@tonic-gate 	  lockp = (struct _locklist *) malloc(sizeof(*lockp));
1987c478bd9Sstevel@tonic-gate 	  if (lockp == NULL) {
1997c478bd9Sstevel@tonic-gate 	       free(db);
2007c478bd9Sstevel@tonic-gate 	       return ENOMEM;
2017c478bd9Sstevel@tonic-gate 	  }
2027c478bd9Sstevel@tonic-gate 	  memset(lockp, 0, sizeof(*lockp));
2037c478bd9Sstevel@tonic-gate 	  lockp->next = locklist;
2047c478bd9Sstevel@tonic-gate 	  locklist = lockp;
2057c478bd9Sstevel@tonic-gate      }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate      /* now initialize lockp->lockinfo if necessary */
2087c478bd9Sstevel@tonic-gate      if (lockp->lockinfo.lockfile == NULL) {
20954925bf6Swillf 	  if ((code = krb5int_init_context_kdc(&lockp->lockinfo.context))) {
2107c478bd9Sstevel@tonic-gate 	       free(db);
21154925bf6Swillf 	       return((krb5_error_code) code);
2127c478bd9Sstevel@tonic-gate 	  }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	  /*
2157c478bd9Sstevel@tonic-gate 	   * needs be open read/write so that write locking can work with
2167c478bd9Sstevel@tonic-gate 	   * POSIX systems
2177c478bd9Sstevel@tonic-gate 	   */
2187c478bd9Sstevel@tonic-gate 	  lockp->lockinfo.filename = strdup(lockfilename);
219004388ebScasper 	  if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+F")) == NULL) {
2207c478bd9Sstevel@tonic-gate 	       /*
2217c478bd9Sstevel@tonic-gate 		* maybe someone took away write permission so we could only
2227c478bd9Sstevel@tonic-gate 		* get shared locks?
2237c478bd9Sstevel@tonic-gate 		*/
224004388ebScasper 	       if ((lockp->lockinfo.lockfile = fopen(lockfilename, "rF"))
2257c478bd9Sstevel@tonic-gate 		   == NULL) {
2267c478bd9Sstevel@tonic-gate 		    free(db);
2277c478bd9Sstevel@tonic-gate 		    return OSA_ADB_NOLOCKFILE;
2287c478bd9Sstevel@tonic-gate 	       }
2297c478bd9Sstevel@tonic-gate 	  }
2307c478bd9Sstevel@tonic-gate 	  lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0;
2317c478bd9Sstevel@tonic-gate      }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate      /* lockp is set, lockinfo is initialized, update the reference count */
2347c478bd9Sstevel@tonic-gate      db->lock = &lockp->lockinfo;
2357c478bd9Sstevel@tonic-gate      db->lock->refcnt++;
2367c478bd9Sstevel@tonic-gate 
23756a424ccSmp      db->opencnt = 0;
2387c478bd9Sstevel@tonic-gate      db->filename = strdup(filename);
2397c478bd9Sstevel@tonic-gate      db->magic = magic;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate      *dbp = db;
242*55fea89dSDan Cross 
2437c478bd9Sstevel@tonic-gate      return OSA_ADB_OK;
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
osa_adb_fini_db(osa_adb_db_t db,int magic)24654925bf6Swillf krb5_error_code osa_adb_fini_db(osa_adb_db_t db, int magic)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate      if (db->magic != magic)
2497c478bd9Sstevel@tonic-gate 	  return EINVAL;
2507c478bd9Sstevel@tonic-gate      if (db->lock->refcnt == 0) {
2517c478bd9Sstevel@tonic-gate 	  /* barry says this can't happen */
2527c478bd9Sstevel@tonic-gate 	  return OSA_ADB_FAILURE;
2537c478bd9Sstevel@tonic-gate      } else {
2547c478bd9Sstevel@tonic-gate 	  db->lock->refcnt--;
2557c478bd9Sstevel@tonic-gate      }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate      if (db->lock->refcnt == 0) {
2587c478bd9Sstevel@tonic-gate 	  /*
2597c478bd9Sstevel@tonic-gate 	   * Don't free db->lock->filename, it is used as a key to
2607c478bd9Sstevel@tonic-gate 	   * find the lockinfo entry in the linked list.  If the
2617c478bd9Sstevel@tonic-gate 	   * lockfile doesn't exist, we must be closing the database
2627c478bd9Sstevel@tonic-gate 	   * after trashing it.  This has to be allowed, so don't
2637c478bd9Sstevel@tonic-gate 	   * generate an error.
2647c478bd9Sstevel@tonic-gate 	   */
26554925bf6Swillf 	  if (db->lock->lockmode != KRB5_DB_LOCKMODE_PERMANENT)
2667c478bd9Sstevel@tonic-gate 	       (void) fclose(db->lock->lockfile);
2677c478bd9Sstevel@tonic-gate 	  db->lock->lockfile = NULL;
2687c478bd9Sstevel@tonic-gate 	  krb5_free_context(db->lock->context);
2697c478bd9Sstevel@tonic-gate      }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate      db->magic = 0;
2727c478bd9Sstevel@tonic-gate      free(db->filename);
2737c478bd9Sstevel@tonic-gate      free(db);
2747c478bd9Sstevel@tonic-gate      return OSA_ADB_OK;
275*55fea89dSDan Cross }
276*55fea89dSDan Cross 
osa_adb_get_lock(osa_adb_db_t db,int mode)27754925bf6Swillf krb5_error_code osa_adb_get_lock(osa_adb_db_t db, int mode)
2787c478bd9Sstevel@tonic-gate {
27954925bf6Swillf      int tries, gotlock, perm, krb5_mode, ret = 0;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate      if (db->lock->lockmode >= mode) {
2827c478bd9Sstevel@tonic-gate 	  /* No need to upgrade lock, just incr refcnt and return */
2837c478bd9Sstevel@tonic-gate 	  db->lock->lockcnt++;
2847c478bd9Sstevel@tonic-gate 	  return(OSA_ADB_OK);
2857c478bd9Sstevel@tonic-gate      }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate      perm = 0;
2887c478bd9Sstevel@tonic-gate      switch (mode) {
28954925bf6Swillf 	case KRB5_DB_LOCKMODE_PERMANENT:
2907c478bd9Sstevel@tonic-gate 	  perm = 1;
2910b16192fSToomas Soome 	/* FALLTHROUGH */
29254925bf6Swillf 	case KRB5_DB_LOCKMODE_EXCLUSIVE:
2937c478bd9Sstevel@tonic-gate 	  krb5_mode = KRB5_LOCKMODE_EXCLUSIVE;
2947c478bd9Sstevel@tonic-gate 	  break;
29554925bf6Swillf 	case KRB5_DB_LOCKMODE_SHARED:
2967c478bd9Sstevel@tonic-gate 	  krb5_mode = KRB5_LOCKMODE_SHARED;
2977c478bd9Sstevel@tonic-gate 	  break;
2987c478bd9Sstevel@tonic-gate 	default:
2997c478bd9Sstevel@tonic-gate 	  return(EINVAL);
3007c478bd9Sstevel@tonic-gate      }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate      for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
3037c478bd9Sstevel@tonic-gate 	  if ((ret = krb5_lock_file(db->lock->context,
3047c478bd9Sstevel@tonic-gate 				    fileno(db->lock->lockfile),
3057c478bd9Sstevel@tonic-gate 				    krb5_mode|KRB5_LOCKMODE_DONTBLOCK)) == 0) {
3067c478bd9Sstevel@tonic-gate 	       gotlock++;
3077c478bd9Sstevel@tonic-gate 	       break;
30854925bf6Swillf 	  } else if (ret == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
3097c478bd9Sstevel@tonic-gate 	       /* tried to exclusive-lock something we don't have */
3107c478bd9Sstevel@tonic-gate 	       /* write access to */
3117c478bd9Sstevel@tonic-gate 	       return OSA_ADB_NOEXCL_PERM;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	  sleep(1);
3147c478bd9Sstevel@tonic-gate      }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate      /* test for all the likely "can't get lock" error codes */
3177c478bd9Sstevel@tonic-gate      if (ret == EACCES || ret == EAGAIN || ret == EWOULDBLOCK)
3187c478bd9Sstevel@tonic-gate 	  return OSA_ADB_CANTLOCK_DB;
3197c478bd9Sstevel@tonic-gate      else if (ret != 0)
3207c478bd9Sstevel@tonic-gate 	  return ret;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate      /*
3237c478bd9Sstevel@tonic-gate       * If the file no longer exists, someone acquired a permanent
3247c478bd9Sstevel@tonic-gate       * lock.  If that process terminates its exclusive lock is lost,
3257c478bd9Sstevel@tonic-gate       * but if we already had the file open we can (probably) lock it
3267c478bd9Sstevel@tonic-gate       * even though it has been unlinked.  So we need to insist that
3277c478bd9Sstevel@tonic-gate       * it exist.
3287c478bd9Sstevel@tonic-gate       */
3297c478bd9Sstevel@tonic-gate      if (access(db->lock->filename, F_OK) < 0) {
3307c478bd9Sstevel@tonic-gate 	  (void) krb5_lock_file(db->lock->context,
3317c478bd9Sstevel@tonic-gate 				fileno(db->lock->lockfile),
3327c478bd9Sstevel@tonic-gate 				KRB5_LOCKMODE_UNLOCK);
3337c478bd9Sstevel@tonic-gate 	  return OSA_ADB_NOLOCKFILE;
3347c478bd9Sstevel@tonic-gate      }
335*55fea89dSDan Cross 
3367c478bd9Sstevel@tonic-gate      /* we have the shared/exclusive lock */
337*55fea89dSDan Cross 
3387c478bd9Sstevel@tonic-gate      if (perm) {
3397c478bd9Sstevel@tonic-gate 	  if (unlink(db->lock->filename) < 0) {
3407c478bd9Sstevel@tonic-gate 	       /* somehow we can't delete the file, but we already */
3417c478bd9Sstevel@tonic-gate 	       /* have the lock, so release it and return */
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	       ret = errno;
3447c478bd9Sstevel@tonic-gate 	       (void) krb5_lock_file(db->lock->context,
3457c478bd9Sstevel@tonic-gate 				     fileno(db->lock->lockfile),
3467c478bd9Sstevel@tonic-gate 				     KRB5_LOCKMODE_UNLOCK);
347*55fea89dSDan Cross 
3487c478bd9Sstevel@tonic-gate 	       /* maybe we should return CANTLOCK_DB.. but that would */
3497c478bd9Sstevel@tonic-gate 	       /* look just like the db was already locked */
3507c478bd9Sstevel@tonic-gate 	       return ret;
3517c478bd9Sstevel@tonic-gate 	  }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	  /* this releases our exclusive lock.. which is okay because */
3547c478bd9Sstevel@tonic-gate 	  /* now no one else can get one either */
3557c478bd9Sstevel@tonic-gate 	  (void) fclose(db->lock->lockfile);
3567c478bd9Sstevel@tonic-gate      }
357*55fea89dSDan Cross 
3587c478bd9Sstevel@tonic-gate      db->lock->lockmode = mode;
3597c478bd9Sstevel@tonic-gate      db->lock->lockcnt++;
3607c478bd9Sstevel@tonic-gate      return OSA_ADB_OK;
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
osa_adb_release_lock(osa_adb_db_t db)36354925bf6Swillf krb5_error_code osa_adb_release_lock(osa_adb_db_t db)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate      int ret, fd;
366*55fea89dSDan Cross 
3677c478bd9Sstevel@tonic-gate      if (!db->lock->lockcnt)		/* lock already unlocked */
3687c478bd9Sstevel@tonic-gate 	  return OSA_ADB_NOTLOCKED;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate      if (--db->lock->lockcnt == 0) {
37154925bf6Swillf 	  if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) {
3727c478bd9Sstevel@tonic-gate 	       /* now we need to create the file since it does not exist */
3737c478bd9Sstevel@tonic-gate                fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL,
3747c478bd9Sstevel@tonic-gate                                    0600);
375004388ebScasper 	       if ((db->lock->lockfile = fdopen(fd, "w+F")) == NULL)
3767c478bd9Sstevel@tonic-gate 		    return OSA_ADB_NOLOCKFILE;
37756a424ccSmp 	  } else if ((ret = krb5_lock_file(db->lock->context,
3787c478bd9Sstevel@tonic-gate 					  fileno(db->lock->lockfile),
37956a424ccSmp 					  KRB5_LOCKMODE_UNLOCK)))
3807c478bd9Sstevel@tonic-gate 	       return ret;
381*55fea89dSDan Cross 
3827c478bd9Sstevel@tonic-gate 	  db->lock->lockmode = 0;
3837c478bd9Sstevel@tonic-gate      }
3847c478bd9Sstevel@tonic-gate      return OSA_ADB_OK;
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
osa_adb_open_and_lock(osa_adb_princ_t db,int locktype)38754925bf6Swillf krb5_error_code osa_adb_open_and_lock(osa_adb_princ_t db, int locktype)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate      int ret;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate      ret = osa_adb_get_lock(db, locktype);
3927c478bd9Sstevel@tonic-gate      if (ret != OSA_ADB_OK)
3937c478bd9Sstevel@tonic-gate 	  return ret;
39456a424ccSmp      if (db->opencnt)
39556a424ccSmp 	  goto open_ok;
39656a424ccSmp 
39756a424ccSmp      db->db = dbopen(db->filename, O_RDWR, 0600, DB_BTREE, &db->btinfo);
39856a424ccSmp      if (db->db != NULL)
39956a424ccSmp 	 goto open_ok;
40056a424ccSmp      switch (errno) {
40156a424ccSmp #ifdef EFTYPE
40256a424ccSmp      case EFTYPE:
40356a424ccSmp #endif
40456a424ccSmp      case EINVAL:
40556a424ccSmp 	  db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info);
40656a424ccSmp 	  if (db->db != NULL)
40756a424ccSmp 	       goto open_ok;
4080b16192fSToomas Soome 	  /* FALLTHROUGH */
40956a424ccSmp      default:
4107c478bd9Sstevel@tonic-gate 	  (void) osa_adb_release_lock(db);
41156a424ccSmp 	  if (errno == EINVAL)
4127c478bd9Sstevel@tonic-gate 	       return OSA_ADB_BAD_DB;
4137c478bd9Sstevel@tonic-gate 	  return errno;
4147c478bd9Sstevel@tonic-gate      }
41556a424ccSmp open_ok:
41656a424ccSmp      db->opencnt++;
4177c478bd9Sstevel@tonic-gate      return OSA_ADB_OK;
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
osa_adb_close_and_unlock(osa_adb_princ_t db)42054925bf6Swillf krb5_error_code osa_adb_close_and_unlock(osa_adb_princ_t db)
4217c478bd9Sstevel@tonic-gate {
42256a424ccSmp      if (--db->opencnt)
42356a424ccSmp 	  return osa_adb_release_lock(db);
42456a424ccSmp      if(db->db != NULL && db->db->close(db->db) == -1) {
4257c478bd9Sstevel@tonic-gate 	  (void) osa_adb_release_lock(db);
4267c478bd9Sstevel@tonic-gate 	  return OSA_ADB_FAILURE;
4277c478bd9Sstevel@tonic-gate      }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate      db->db = NULL;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate      return(osa_adb_release_lock(db));
4327c478bd9Sstevel@tonic-gate }
433