1*54925bf6Swillf /*
2*54925bf6Swillf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3*54925bf6Swillf  * Use is subject to license terms.
4*54925bf6Swillf  */
5*54925bf6Swillf #pragma ident	"%Z%%M%	%I%	%E% SMI"
6*54925bf6Swillf 
7*54925bf6Swillf /*
8*54925bf6Swillf  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9*54925bf6Swillf  *
10*54925bf6Swillf  *	Openvision retains the copyright to derivative works of
11*54925bf6Swillf  *	this source code.  Do *NOT* create a derivative of this
12*54925bf6Swillf  *	source code before consulting with your legal department.
13*54925bf6Swillf  *	Do *NOT* integrate *ANY* of this source code into another
14*54925bf6Swillf  *	product before consulting with your legal department.
15*54925bf6Swillf  *
16*54925bf6Swillf  *	For further information, read the top-level Openvision
17*54925bf6Swillf  *	copyright which is contained in the top-level MIT Kerberos
18*54925bf6Swillf  *	copyright.
19*54925bf6Swillf  *
20*54925bf6Swillf  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
21*54925bf6Swillf  *
22*54925bf6Swillf  */
23*54925bf6Swillf 
24*54925bf6Swillf 
25*54925bf6Swillf /*
26*54925bf6Swillf  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
27*54925bf6Swillf  *
28*54925bf6Swillf  * $Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/adb_openclose.c,v 1.8 2002/10/08 20:20:29 tlyu Exp $
29*54925bf6Swillf  */
30*54925bf6Swillf 
31*54925bf6Swillf #if !defined(lint) && !defined(__CODECENTER__)
32*54925bf6Swillf static char *rcsid = "$Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/adb_openclose.c,v 1.8 2002/10/08 20:20:29 tlyu Exp $";
33*54925bf6Swillf #endif
34*54925bf6Swillf 
35*54925bf6Swillf #include	<sys/file.h>
36*54925bf6Swillf #include	<fcntl.h>
37*54925bf6Swillf #include	<unistd.h>
38*54925bf6Swillf #include        <k5-int.h>
39*54925bf6Swillf #include	"policy_db.h"
40*54925bf6Swillf #include	<stdlib.h>
41*54925bf6Swillf #include        <db.h>
42*54925bf6Swillf 
43*54925bf6Swillf #define MAX_LOCK_TRIES 5
44*54925bf6Swillf 
45*54925bf6Swillf struct _locklist {
46*54925bf6Swillf      osa_adb_lock_ent lockinfo;
47*54925bf6Swillf      struct _locklist *next;
48*54925bf6Swillf };
49*54925bf6Swillf 
50*54925bf6Swillf krb5_error_code osa_adb_create_db(char *filename, char *lockfilename,
51*54925bf6Swillf 				  int magic)
52*54925bf6Swillf {
53*54925bf6Swillf      int lf;
54*54925bf6Swillf      DB *db;
55*54925bf6Swillf      BTREEINFO btinfo;
56*54925bf6Swillf 
57*54925bf6Swillf      memset(&btinfo, 0, sizeof(btinfo));
58*54925bf6Swillf      btinfo.flags = 0;
59*54925bf6Swillf      btinfo.cachesize = 0;
60*54925bf6Swillf      btinfo.psize = 4096;
61*54925bf6Swillf      btinfo.lorder = 0;
62*54925bf6Swillf      btinfo.minkeypage = 0;
63*54925bf6Swillf      btinfo.compare = NULL;
64*54925bf6Swillf      btinfo.prefix = NULL;
65*54925bf6Swillf      db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_BTREE, &btinfo);
66*54925bf6Swillf      if (db == NULL)
67*54925bf6Swillf 	  return errno;
68*54925bf6Swillf      if (db->close(db) < 0)
69*54925bf6Swillf 	  return errno;
70*54925bf6Swillf 
71*54925bf6Swillf      /* only create the lock file if we successfully created the db */
72*54925bf6Swillf      lf = THREEPARAMOPEN(lockfilename, O_RDWR | O_CREAT | O_EXCL, 0600);
73*54925bf6Swillf      if (lf == -1)
74*54925bf6Swillf 	  return errno;
75*54925bf6Swillf      (void) close(lf);
76*54925bf6Swillf 
77*54925bf6Swillf      return OSA_ADB_OK;
78*54925bf6Swillf }
79*54925bf6Swillf 
80*54925bf6Swillf krb5_error_code osa_adb_destroy_db(char *filename, char *lockfilename,
81*54925bf6Swillf 				 int magic)
82*54925bf6Swillf {
83*54925bf6Swillf      /* the admin databases do not contain security-critical data */
84*54925bf6Swillf      if (unlink(filename) < 0 ||
85*54925bf6Swillf 	 unlink(lockfilename) < 0)
86*54925bf6Swillf 	  return errno;
87*54925bf6Swillf      return OSA_ADB_OK;
88*54925bf6Swillf }
89*54925bf6Swillf 
90*54925bf6Swillf krb5_error_code osa_adb_rename_db(char *filefrom, char *lockfrom,
91*54925bf6Swillf 				char *fileto, char *lockto, int magic)
92*54925bf6Swillf {
93*54925bf6Swillf      osa_adb_db_t fromdb, todb;
94*54925bf6Swillf      krb5_error_code ret;
95*54925bf6Swillf 
96*54925bf6Swillf      /* make sure todb exists */
97*54925bf6Swillf      /*LINTED*/
98*54925bf6Swillf      if ((ret = osa_adb_create_db(fileto, lockto, magic)) &&
99*54925bf6Swillf 	 ret != EEXIST)
100*54925bf6Swillf 	  return ret;
101*54925bf6Swillf 
102*54925bf6Swillf      if ((ret = osa_adb_init_db(&fromdb, filefrom, lockfrom, magic)))
103*54925bf6Swillf 	  return ret;
104*54925bf6Swillf      if ((ret = osa_adb_init_db(&todb, fileto, lockto, magic))) {
105*54925bf6Swillf 	  (void) osa_adb_fini_db(fromdb, magic);
106*54925bf6Swillf 	  return ret;
107*54925bf6Swillf      }
108*54925bf6Swillf      if ((ret = osa_adb_get_lock(fromdb, KRB5_DB_LOCKMODE_PERMANENT))) {
109*54925bf6Swillf 	  (void) osa_adb_fini_db(fromdb, magic);
110*54925bf6Swillf 	  (void) osa_adb_fini_db(todb, magic);
111*54925bf6Swillf 	  return ret;
112*54925bf6Swillf      }
113*54925bf6Swillf      if ((ret = osa_adb_get_lock(todb, KRB5_DB_LOCKMODE_PERMANENT))) {
114*54925bf6Swillf 	  (void) osa_adb_fini_db(fromdb, magic);
115*54925bf6Swillf 	  (void) osa_adb_fini_db(todb, magic);
116*54925bf6Swillf 	  return ret;
117*54925bf6Swillf      }
118*54925bf6Swillf      if ((rename(filefrom, fileto) < 0)) {
119*54925bf6Swillf 	  (void) osa_adb_fini_db(fromdb, magic);
120*54925bf6Swillf 	  (void) osa_adb_fini_db(todb, magic);
121*54925bf6Swillf 	  return errno;
122*54925bf6Swillf      }
123*54925bf6Swillf      /*
124*54925bf6Swillf       * Do not release the lock on fromdb because it is being renamed
125*54925bf6Swillf       * out of existence; no one can ever use it again.
126*54925bf6Swillf       */
127*54925bf6Swillf      if ((ret = osa_adb_release_lock(todb))) {
128*54925bf6Swillf 	  (void) osa_adb_fini_db(fromdb, magic);
129*54925bf6Swillf 	  (void) osa_adb_fini_db(todb, magic);
130*54925bf6Swillf 	  return ret;
131*54925bf6Swillf      }
132*54925bf6Swillf 
133*54925bf6Swillf      (void) osa_adb_fini_db(fromdb, magic);
134*54925bf6Swillf      (void) osa_adb_fini_db(todb, magic);
135*54925bf6Swillf      return 0;
136*54925bf6Swillf }
137*54925bf6Swillf 
138*54925bf6Swillf krb5_error_code osa_adb_init_db(osa_adb_db_t *dbp, char *filename,
139*54925bf6Swillf 			      char *lockfilename, int magic)
140*54925bf6Swillf {
141*54925bf6Swillf      osa_adb_db_t db;
142*54925bf6Swillf      static struct _locklist *locklist = NULL;
143*54925bf6Swillf      struct _locklist *lockp;
144*54925bf6Swillf      krb5_error_code code;
145*54925bf6Swillf 
146*54925bf6Swillf      if (dbp == NULL || filename == NULL)
147*54925bf6Swillf 	  return EINVAL;
148*54925bf6Swillf 
149*54925bf6Swillf      db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent));
150*54925bf6Swillf      if (db == NULL)
151*54925bf6Swillf 	  return ENOMEM;
152*54925bf6Swillf 
153*54925bf6Swillf      memset(db, 0, sizeof(*db));
154*54925bf6Swillf      db->info.hash = NULL;
155*54925bf6Swillf      db->info.bsize = 256;
156*54925bf6Swillf      db->info.ffactor = 8;
157*54925bf6Swillf      db->info.nelem = 25000;
158*54925bf6Swillf      db->info.lorder = 0;
159*54925bf6Swillf 
160*54925bf6Swillf      db->btinfo.flags = 0;
161*54925bf6Swillf      db->btinfo.cachesize = 0;
162*54925bf6Swillf      db->btinfo.psize = 4096;
163*54925bf6Swillf      db->btinfo.lorder = 0;
164*54925bf6Swillf      db->btinfo.minkeypage = 0;
165*54925bf6Swillf      db->btinfo.compare = NULL;
166*54925bf6Swillf      db->btinfo.prefix = NULL;
167*54925bf6Swillf      /*
168*54925bf6Swillf       * A process is allowed to open the same database multiple times
169*54925bf6Swillf       * and access it via different handles.  If the handles use
170*54925bf6Swillf       * distinct lockinfo structures, things get confused: lock(A),
171*54925bf6Swillf       * lock(B), release(B) will result in the kernel unlocking the
172*54925bf6Swillf       * lock file but handle A will still think the file is locked.
173*54925bf6Swillf       * Therefore, all handles using the same lock file must share a
174*54925bf6Swillf       * single lockinfo structure.
175*54925bf6Swillf       *
176*54925bf6Swillf       * It is not sufficient to have a single lockinfo structure,
177*54925bf6Swillf       * however, because a single process may also wish to open
178*54925bf6Swillf       * multiple different databases simultaneously, with different
179*54925bf6Swillf       * lock files.  This code used to use a single static lockinfo
180*54925bf6Swillf       * structure, which means that the second database opened used
181*54925bf6Swillf       * the first database's lock file.  This was Bad.
182*54925bf6Swillf       *
183*54925bf6Swillf       * We now maintain a linked list of lockinfo structures, keyed by
184*54925bf6Swillf       * lockfilename.  An entry is added when this function is called
185*54925bf6Swillf       * with a new lockfilename, and all subsequent calls with that
186*54925bf6Swillf       * lockfilename use the existing entry, updating the refcnt.
187*54925bf6Swillf       * When the database is closed with fini_db(), the refcnt is
188*54925bf6Swillf       * decremented, and when it is zero the lockinfo structure is
189*54925bf6Swillf       * freed and reset.  The entry in the linked list, however, is
190*54925bf6Swillf       * never removed; it will just be reinitialized the next time
191*54925bf6Swillf       * init_db is called with the right lockfilename.
192*54925bf6Swillf       */
193*54925bf6Swillf 
194*54925bf6Swillf      /* find or create the lockinfo structure for lockfilename */
195*54925bf6Swillf      lockp = locklist;
196*54925bf6Swillf      while (lockp) {
197*54925bf6Swillf 	  if (strcmp(lockp->lockinfo.filename, lockfilename) == 0)
198*54925bf6Swillf 	       break;
199*54925bf6Swillf 	  else
200*54925bf6Swillf 	       lockp = lockp->next;
201*54925bf6Swillf      }
202*54925bf6Swillf      if (lockp == NULL) {
203*54925bf6Swillf 	  /* doesn't exist, create it, add to list */
204*54925bf6Swillf 	  lockp = (struct _locklist *) malloc(sizeof(*lockp));
205*54925bf6Swillf 	  if (lockp == NULL) {
206*54925bf6Swillf 	       free(db);
207*54925bf6Swillf 	       return ENOMEM;
208*54925bf6Swillf 	  }
209*54925bf6Swillf 	  memset(lockp, 0, sizeof(*lockp));
210*54925bf6Swillf 	  lockp->next = locklist;
211*54925bf6Swillf 	  locklist = lockp;
212*54925bf6Swillf      }
213*54925bf6Swillf 
214*54925bf6Swillf      /* now initialize lockp->lockinfo if necessary */
215*54925bf6Swillf      if (lockp->lockinfo.lockfile == NULL) {
216*54925bf6Swillf 	  if ((code = krb5int_init_context_kdc(&lockp->lockinfo.context))) {
217*54925bf6Swillf 	       free(db);
218*54925bf6Swillf 	       return((krb5_error_code) code);
219*54925bf6Swillf 	  }
220*54925bf6Swillf 
221*54925bf6Swillf 	  /*
222*54925bf6Swillf 	   * needs be open read/write so that write locking can work with
223*54925bf6Swillf 	   * POSIX systems
224*54925bf6Swillf 	   */
225*54925bf6Swillf 	  lockp->lockinfo.filename = strdup(lockfilename);
226*54925bf6Swillf 	  if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+F")) == NULL) {
227*54925bf6Swillf 	       /*
228*54925bf6Swillf 		* maybe someone took away write permission so we could only
229*54925bf6Swillf 		* get shared locks?
230*54925bf6Swillf 		*/
231*54925bf6Swillf 	       if ((lockp->lockinfo.lockfile = fopen(lockfilename, "rF"))
232*54925bf6Swillf 		   == NULL) {
233*54925bf6Swillf 		    free(db);
234*54925bf6Swillf 		    return OSA_ADB_NOLOCKFILE;
235*54925bf6Swillf 	       }
236*54925bf6Swillf 	  }
237*54925bf6Swillf 	  lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0;
238*54925bf6Swillf      }
239*54925bf6Swillf 
240*54925bf6Swillf      /* lockp is set, lockinfo is initialized, update the reference count */
241*54925bf6Swillf      db->lock = &lockp->lockinfo;
242*54925bf6Swillf      db->lock->refcnt++;
243*54925bf6Swillf 
244*54925bf6Swillf      db->opencnt = 0;
245*54925bf6Swillf      db->filename = strdup(filename);
246*54925bf6Swillf      db->magic = magic;
247*54925bf6Swillf 
248*54925bf6Swillf      *dbp = db;
249*54925bf6Swillf 
250*54925bf6Swillf      return OSA_ADB_OK;
251*54925bf6Swillf }
252*54925bf6Swillf 
253*54925bf6Swillf krb5_error_code osa_adb_fini_db(osa_adb_db_t db, int magic)
254*54925bf6Swillf {
255*54925bf6Swillf      if (db->magic != magic)
256*54925bf6Swillf 	  return EINVAL;
257*54925bf6Swillf      if (db->lock->refcnt == 0) {
258*54925bf6Swillf 	  /* barry says this can't happen */
259*54925bf6Swillf 	  return OSA_ADB_FAILURE;
260*54925bf6Swillf      } else {
261*54925bf6Swillf 	  db->lock->refcnt--;
262*54925bf6Swillf      }
263*54925bf6Swillf 
264*54925bf6Swillf      if (db->lock->refcnt == 0) {
265*54925bf6Swillf 	  /*
266*54925bf6Swillf 	   * Don't free db->lock->filename, it is used as a key to
267*54925bf6Swillf 	   * find the lockinfo entry in the linked list.  If the
268*54925bf6Swillf 	   * lockfile doesn't exist, we must be closing the database
269*54925bf6Swillf 	   * after trashing it.  This has to be allowed, so don't
270*54925bf6Swillf 	   * generate an error.
271*54925bf6Swillf 	   */
272*54925bf6Swillf 	  if (db->lock->lockmode != KRB5_DB_LOCKMODE_PERMANENT)
273*54925bf6Swillf 	       (void) fclose(db->lock->lockfile);
274*54925bf6Swillf 	  db->lock->lockfile = NULL;
275*54925bf6Swillf 	  krb5_free_context(db->lock->context);
276*54925bf6Swillf      }
277*54925bf6Swillf 
278*54925bf6Swillf      db->magic = 0;
279*54925bf6Swillf      free(db->filename);
280*54925bf6Swillf      free(db);
281*54925bf6Swillf      return OSA_ADB_OK;
282*54925bf6Swillf }
283*54925bf6Swillf 
284*54925bf6Swillf krb5_error_code osa_adb_get_lock(osa_adb_db_t db, int mode)
285*54925bf6Swillf {
286*54925bf6Swillf      int tries, gotlock, perm, krb5_mode, ret = 0;
287*54925bf6Swillf 
288*54925bf6Swillf      if (db->lock->lockmode >= mode) {
289*54925bf6Swillf 	  /* No need to upgrade lock, just incr refcnt and return */
290*54925bf6Swillf 	  db->lock->lockcnt++;
291*54925bf6Swillf 	  return(OSA_ADB_OK);
292*54925bf6Swillf      }
293*54925bf6Swillf 
294*54925bf6Swillf      perm = 0;
295*54925bf6Swillf      switch (mode) {
296*54925bf6Swillf 	case KRB5_DB_LOCKMODE_PERMANENT:
297*54925bf6Swillf 	  perm = 1;
298*54925bf6Swillf 	/*LINTED*/
299*54925bf6Swillf 	case KRB5_DB_LOCKMODE_EXCLUSIVE:
300*54925bf6Swillf 	  krb5_mode = KRB5_LOCKMODE_EXCLUSIVE;
301*54925bf6Swillf 	  break;
302*54925bf6Swillf 	case KRB5_DB_LOCKMODE_SHARED:
303*54925bf6Swillf 	  krb5_mode = KRB5_LOCKMODE_SHARED;
304*54925bf6Swillf 	  break;
305*54925bf6Swillf 	default:
306*54925bf6Swillf 	  return(EINVAL);
307*54925bf6Swillf      }
308*54925bf6Swillf 
309*54925bf6Swillf      for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
310*54925bf6Swillf 	  if ((ret = krb5_lock_file(db->lock->context,
311*54925bf6Swillf 				    fileno(db->lock->lockfile),
312*54925bf6Swillf 				    krb5_mode|KRB5_LOCKMODE_DONTBLOCK)) == 0) {
313*54925bf6Swillf 	       gotlock++;
314*54925bf6Swillf 	       break;
315*54925bf6Swillf 	  } else if (ret == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
316*54925bf6Swillf 	       /* tried to exclusive-lock something we don't have */
317*54925bf6Swillf 	       /* write access to */
318*54925bf6Swillf 	       return OSA_ADB_NOEXCL_PERM;
319*54925bf6Swillf 
320*54925bf6Swillf 	  sleep(1);
321*54925bf6Swillf      }
322*54925bf6Swillf 
323*54925bf6Swillf      /* test for all the likely "can't get lock" error codes */
324*54925bf6Swillf      if (ret == EACCES || ret == EAGAIN || ret == EWOULDBLOCK)
325*54925bf6Swillf 	  return OSA_ADB_CANTLOCK_DB;
326*54925bf6Swillf      else if (ret != 0)
327*54925bf6Swillf 	  return ret;
328*54925bf6Swillf 
329*54925bf6Swillf      /*
330*54925bf6Swillf       * If the file no longer exists, someone acquired a permanent
331*54925bf6Swillf       * lock.  If that process terminates its exclusive lock is lost,
332*54925bf6Swillf       * but if we already had the file open we can (probably) lock it
333*54925bf6Swillf       * even though it has been unlinked.  So we need to insist that
334*54925bf6Swillf       * it exist.
335*54925bf6Swillf       */
336*54925bf6Swillf      if (access(db->lock->filename, F_OK) < 0) {
337*54925bf6Swillf 	  (void) krb5_lock_file(db->lock->context,
338*54925bf6Swillf 				fileno(db->lock->lockfile),
339*54925bf6Swillf 				KRB5_LOCKMODE_UNLOCK);
340*54925bf6Swillf 	  return OSA_ADB_NOLOCKFILE;
341*54925bf6Swillf      }
342*54925bf6Swillf 
343*54925bf6Swillf      /* we have the shared/exclusive lock */
344*54925bf6Swillf 
345*54925bf6Swillf      if (perm) {
346*54925bf6Swillf 	  if (unlink(db->lock->filename) < 0) {
347*54925bf6Swillf 	       /* somehow we can't delete the file, but we already */
348*54925bf6Swillf 	       /* have the lock, so release it and return */
349*54925bf6Swillf 
350*54925bf6Swillf 	       ret = errno;
351*54925bf6Swillf 	       (void) krb5_lock_file(db->lock->context,
352*54925bf6Swillf 				     fileno(db->lock->lockfile),
353*54925bf6Swillf 				     KRB5_LOCKMODE_UNLOCK);
354*54925bf6Swillf 
355*54925bf6Swillf 	       /* maybe we should return CANTLOCK_DB.. but that would */
356*54925bf6Swillf 	       /* look just like the db was already locked */
357*54925bf6Swillf 	       return ret;
358*54925bf6Swillf 	  }
359*54925bf6Swillf 
360*54925bf6Swillf 	  /* this releases our exclusive lock.. which is okay because */
361*54925bf6Swillf 	  /* now no one else can get one either */
362*54925bf6Swillf 	  (void) fclose(db->lock->lockfile);
363*54925bf6Swillf      }
364*54925bf6Swillf 
365*54925bf6Swillf      db->lock->lockmode = mode;
366*54925bf6Swillf      db->lock->lockcnt++;
367*54925bf6Swillf      return OSA_ADB_OK;
368*54925bf6Swillf }
369*54925bf6Swillf 
370*54925bf6Swillf krb5_error_code osa_adb_release_lock(osa_adb_db_t db)
371*54925bf6Swillf {
372*54925bf6Swillf      int ret, fd;
373*54925bf6Swillf 
374*54925bf6Swillf      if (!db->lock->lockcnt)		/* lock already unlocked */
375*54925bf6Swillf 	  return OSA_ADB_NOTLOCKED;
376*54925bf6Swillf 
377*54925bf6Swillf      if (--db->lock->lockcnt == 0) {
378*54925bf6Swillf 	  if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) {
379*54925bf6Swillf 	       /* now we need to create the file since it does not exist */
380*54925bf6Swillf                fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL,
381*54925bf6Swillf                                    0600);
382*54925bf6Swillf 	       if ((db->lock->lockfile = fdopen(fd, "w+F")) == NULL)
383*54925bf6Swillf 		    return OSA_ADB_NOLOCKFILE;
384*54925bf6Swillf 	  } else if ((ret = krb5_lock_file(db->lock->context,
385*54925bf6Swillf 					  fileno(db->lock->lockfile),
386*54925bf6Swillf 					  KRB5_LOCKMODE_UNLOCK)))
387*54925bf6Swillf 	       return ret;
388*54925bf6Swillf 
389*54925bf6Swillf 	  db->lock->lockmode = 0;
390*54925bf6Swillf      }
391*54925bf6Swillf      return OSA_ADB_OK;
392*54925bf6Swillf }
393*54925bf6Swillf 
394*54925bf6Swillf krb5_error_code osa_adb_open_and_lock(osa_adb_princ_t db, int locktype)
395*54925bf6Swillf {
396*54925bf6Swillf      int ret;
397*54925bf6Swillf 
398*54925bf6Swillf      ret = osa_adb_get_lock(db, locktype);
399*54925bf6Swillf      if (ret != OSA_ADB_OK)
400*54925bf6Swillf 	  return ret;
401*54925bf6Swillf      if (db->opencnt)
402*54925bf6Swillf 	  goto open_ok;
403*54925bf6Swillf 
404*54925bf6Swillf      db->db = dbopen(db->filename, O_RDWR, 0600, DB_BTREE, &db->btinfo);
405*54925bf6Swillf      if (db->db != NULL)
406*54925bf6Swillf 	 goto open_ok;
407*54925bf6Swillf      switch (errno) {
408*54925bf6Swillf #ifdef EFTYPE
409*54925bf6Swillf      case EFTYPE:
410*54925bf6Swillf #endif
411*54925bf6Swillf      case EINVAL:
412*54925bf6Swillf 	  db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info);
413*54925bf6Swillf 	  if (db->db != NULL)
414*54925bf6Swillf 	       goto open_ok;
415*54925bf6Swillf      default:
416*54925bf6Swillf 	  (void) osa_adb_release_lock(db);
417*54925bf6Swillf 	  if (errno == EINVAL)
418*54925bf6Swillf 	       return OSA_ADB_BAD_DB;
419*54925bf6Swillf 	  return errno;
420*54925bf6Swillf      }
421*54925bf6Swillf open_ok:
422*54925bf6Swillf      db->opencnt++;
423*54925bf6Swillf      return OSA_ADB_OK;
424*54925bf6Swillf }
425*54925bf6Swillf 
426*54925bf6Swillf krb5_error_code osa_adb_close_and_unlock(osa_adb_princ_t db)
427*54925bf6Swillf {
428*54925bf6Swillf      if (--db->opencnt)
429*54925bf6Swillf 	  return osa_adb_release_lock(db);
430*54925bf6Swillf      if(db->db != NULL && db->db->close(db->db) == -1) {
431*54925bf6Swillf 	  (void) osa_adb_release_lock(db);
432*54925bf6Swillf 	  return OSA_ADB_FAILURE;
433*54925bf6Swillf      }
434*54925bf6Swillf 
435*54925bf6Swillf      db->db = NULL;
436*54925bf6Swillf 
437*54925bf6Swillf      return(osa_adb_release_lock(db));
438*54925bf6Swillf }
439