1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
4*7f2fe78bSCy Schubert *
5*7f2fe78bSCy Schubert * $Header$
6*7f2fe78bSCy Schubert */
7*7f2fe78bSCy Schubert
8*7f2fe78bSCy Schubert #include <k5-int.h>
9*7f2fe78bSCy Schubert #include <sys/file.h>
10*7f2fe78bSCy Schubert #include <fcntl.h>
11*7f2fe78bSCy Schubert #include <unistd.h>
12*7f2fe78bSCy Schubert #include "policy_db.h"
13*7f2fe78bSCy Schubert #include <stdlib.h>
14*7f2fe78bSCy Schubert #include <db.h>
15*7f2fe78bSCy Schubert
16*7f2fe78bSCy Schubert struct _locklist {
17*7f2fe78bSCy Schubert osa_adb_lock_ent lockinfo;
18*7f2fe78bSCy Schubert struct _locklist *next;
19*7f2fe78bSCy Schubert };
20*7f2fe78bSCy Schubert
21*7f2fe78bSCy Schubert krb5_error_code
osa_adb_create_db(char * filename,char * lockfilename,int magic)22*7f2fe78bSCy Schubert osa_adb_create_db(char *filename, char *lockfilename, int magic)
23*7f2fe78bSCy Schubert {
24*7f2fe78bSCy Schubert int lf;
25*7f2fe78bSCy Schubert DB *db;
26*7f2fe78bSCy Schubert BTREEINFO btinfo;
27*7f2fe78bSCy Schubert
28*7f2fe78bSCy Schubert memset(&btinfo, 0, sizeof(btinfo));
29*7f2fe78bSCy Schubert btinfo.flags = 0;
30*7f2fe78bSCy Schubert btinfo.cachesize = 0;
31*7f2fe78bSCy Schubert btinfo.psize = 4096;
32*7f2fe78bSCy Schubert btinfo.lorder = 0;
33*7f2fe78bSCy Schubert btinfo.minkeypage = 0;
34*7f2fe78bSCy Schubert btinfo.compare = NULL;
35*7f2fe78bSCy Schubert btinfo.prefix = NULL;
36*7f2fe78bSCy Schubert db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_BTREE, &btinfo);
37*7f2fe78bSCy Schubert if (db == NULL)
38*7f2fe78bSCy Schubert return errno;
39*7f2fe78bSCy Schubert if (db->close(db) < 0)
40*7f2fe78bSCy Schubert return errno;
41*7f2fe78bSCy Schubert
42*7f2fe78bSCy Schubert /* only create the lock file if we successfully created the db */
43*7f2fe78bSCy Schubert lf = THREEPARAMOPEN(lockfilename, O_RDWR | O_CREAT | O_EXCL, 0600);
44*7f2fe78bSCy Schubert if (lf == -1)
45*7f2fe78bSCy Schubert return errno;
46*7f2fe78bSCy Schubert (void) close(lf);
47*7f2fe78bSCy Schubert
48*7f2fe78bSCy Schubert return OSA_ADB_OK;
49*7f2fe78bSCy Schubert }
50*7f2fe78bSCy Schubert
51*7f2fe78bSCy Schubert krb5_error_code
osa_adb_destroy_db(char * filename,char * lockfilename,int magic)52*7f2fe78bSCy Schubert osa_adb_destroy_db(char *filename, char *lockfilename, int magic)
53*7f2fe78bSCy Schubert {
54*7f2fe78bSCy Schubert /* the admin databases do not contain security-critical data */
55*7f2fe78bSCy Schubert if (unlink(filename) < 0 ||
56*7f2fe78bSCy Schubert unlink(lockfilename) < 0)
57*7f2fe78bSCy Schubert return errno;
58*7f2fe78bSCy Schubert return OSA_ADB_OK;
59*7f2fe78bSCy Schubert }
60*7f2fe78bSCy Schubert
61*7f2fe78bSCy Schubert krb5_error_code
osa_adb_init_db(osa_adb_db_t * dbp,char * filename,char * lockfilename,int magic)62*7f2fe78bSCy Schubert osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfilename,
63*7f2fe78bSCy Schubert int magic)
64*7f2fe78bSCy Schubert {
65*7f2fe78bSCy Schubert osa_adb_db_t db;
66*7f2fe78bSCy Schubert static struct _locklist *locklist = NULL;
67*7f2fe78bSCy Schubert struct _locklist *lockp;
68*7f2fe78bSCy Schubert krb5_error_code code;
69*7f2fe78bSCy Schubert
70*7f2fe78bSCy Schubert if (dbp == NULL || filename == NULL)
71*7f2fe78bSCy Schubert return EINVAL;
72*7f2fe78bSCy Schubert
73*7f2fe78bSCy Schubert db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent));
74*7f2fe78bSCy Schubert if (db == NULL)
75*7f2fe78bSCy Schubert return ENOMEM;
76*7f2fe78bSCy Schubert
77*7f2fe78bSCy Schubert memset(db, 0, sizeof(*db));
78*7f2fe78bSCy Schubert db->info.hash = NULL;
79*7f2fe78bSCy Schubert db->info.bsize = 256;
80*7f2fe78bSCy Schubert db->info.ffactor = 8;
81*7f2fe78bSCy Schubert db->info.nelem = 25000;
82*7f2fe78bSCy Schubert db->info.lorder = 0;
83*7f2fe78bSCy Schubert
84*7f2fe78bSCy Schubert db->btinfo.flags = 0;
85*7f2fe78bSCy Schubert db->btinfo.cachesize = 0;
86*7f2fe78bSCy Schubert db->btinfo.psize = 4096;
87*7f2fe78bSCy Schubert db->btinfo.lorder = 0;
88*7f2fe78bSCy Schubert db->btinfo.minkeypage = 0;
89*7f2fe78bSCy Schubert db->btinfo.compare = NULL;
90*7f2fe78bSCy Schubert db->btinfo.prefix = NULL;
91*7f2fe78bSCy Schubert /*
92*7f2fe78bSCy Schubert * A process is allowed to open the same database multiple times
93*7f2fe78bSCy Schubert * and access it via different handles. If the handles use
94*7f2fe78bSCy Schubert * distinct lockinfo structures, things get confused: lock(A),
95*7f2fe78bSCy Schubert * lock(B), release(B) will result in the kernel unlocking the
96*7f2fe78bSCy Schubert * lock file but handle A will still think the file is locked.
97*7f2fe78bSCy Schubert * Therefore, all handles using the same lock file must share a
98*7f2fe78bSCy Schubert * single lockinfo structure.
99*7f2fe78bSCy Schubert *
100*7f2fe78bSCy Schubert * It is not sufficient to have a single lockinfo structure,
101*7f2fe78bSCy Schubert * however, because a single process may also wish to open
102*7f2fe78bSCy Schubert * multiple different databases simultaneously, with different
103*7f2fe78bSCy Schubert * lock files. This code used to use a single static lockinfo
104*7f2fe78bSCy Schubert * structure, which means that the second database opened used
105*7f2fe78bSCy Schubert * the first database's lock file. This was Bad.
106*7f2fe78bSCy Schubert *
107*7f2fe78bSCy Schubert * We now maintain a linked list of lockinfo structures, keyed by
108*7f2fe78bSCy Schubert * lockfilename. An entry is added when this function is called
109*7f2fe78bSCy Schubert * with a new lockfilename, and all subsequent calls with that
110*7f2fe78bSCy Schubert * lockfilename use the existing entry, updating the refcnt.
111*7f2fe78bSCy Schubert * When the database is closed with fini_db(), the refcnt is
112*7f2fe78bSCy Schubert * decremented, and when it is zero the lockinfo structure is
113*7f2fe78bSCy Schubert * freed and reset. The entry in the linked list, however, is
114*7f2fe78bSCy Schubert * never removed; it will just be reinitialized the next time
115*7f2fe78bSCy Schubert * init_db is called with the right lockfilename.
116*7f2fe78bSCy Schubert */
117*7f2fe78bSCy Schubert
118*7f2fe78bSCy Schubert /* find or create the lockinfo structure for lockfilename */
119*7f2fe78bSCy Schubert lockp = locklist;
120*7f2fe78bSCy Schubert while (lockp) {
121*7f2fe78bSCy Schubert if (strcmp(lockp->lockinfo.filename, lockfilename) == 0)
122*7f2fe78bSCy Schubert break;
123*7f2fe78bSCy Schubert else
124*7f2fe78bSCy Schubert lockp = lockp->next;
125*7f2fe78bSCy Schubert }
126*7f2fe78bSCy Schubert if (lockp == NULL) {
127*7f2fe78bSCy Schubert /* doesn't exist, create it, add to list */
128*7f2fe78bSCy Schubert lockp = (struct _locklist *) malloc(sizeof(*lockp));
129*7f2fe78bSCy Schubert if (lockp == NULL) {
130*7f2fe78bSCy Schubert free(db);
131*7f2fe78bSCy Schubert return ENOMEM;
132*7f2fe78bSCy Schubert }
133*7f2fe78bSCy Schubert memset(lockp, 0, sizeof(*lockp));
134*7f2fe78bSCy Schubert lockp->lockinfo.filename = strdup(lockfilename);
135*7f2fe78bSCy Schubert if (lockp->lockinfo.filename == NULL) {
136*7f2fe78bSCy Schubert free(lockp);
137*7f2fe78bSCy Schubert free(db);
138*7f2fe78bSCy Schubert return ENOMEM;
139*7f2fe78bSCy Schubert }
140*7f2fe78bSCy Schubert lockp->next = locklist;
141*7f2fe78bSCy Schubert locklist = lockp;
142*7f2fe78bSCy Schubert }
143*7f2fe78bSCy Schubert
144*7f2fe78bSCy Schubert /* now initialize lockp->lockinfo if necessary */
145*7f2fe78bSCy Schubert if (lockp->lockinfo.lockfile == NULL) {
146*7f2fe78bSCy Schubert if ((code = krb5int_init_context_kdc(&lockp->lockinfo.context))) {
147*7f2fe78bSCy Schubert free(db);
148*7f2fe78bSCy Schubert return((krb5_error_code) code);
149*7f2fe78bSCy Schubert }
150*7f2fe78bSCy Schubert
151*7f2fe78bSCy Schubert /*
152*7f2fe78bSCy Schubert * needs be open read/write so that write locking can work with
153*7f2fe78bSCy Schubert * POSIX systems
154*7f2fe78bSCy Schubert */
155*7f2fe78bSCy Schubert if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) {
156*7f2fe78bSCy Schubert /*
157*7f2fe78bSCy Schubert * maybe someone took away write permission so we could only
158*7f2fe78bSCy Schubert * get shared locks?
159*7f2fe78bSCy Schubert */
160*7f2fe78bSCy Schubert if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r"))
161*7f2fe78bSCy Schubert == NULL) {
162*7f2fe78bSCy Schubert free(db);
163*7f2fe78bSCy Schubert return OSA_ADB_NOLOCKFILE;
164*7f2fe78bSCy Schubert }
165*7f2fe78bSCy Schubert }
166*7f2fe78bSCy Schubert set_cloexec_file(lockp->lockinfo.lockfile);
167*7f2fe78bSCy Schubert lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0;
168*7f2fe78bSCy Schubert }
169*7f2fe78bSCy Schubert
170*7f2fe78bSCy Schubert /* lockp is set, lockinfo is initialized, update the reference count */
171*7f2fe78bSCy Schubert db->lock = &lockp->lockinfo;
172*7f2fe78bSCy Schubert db->lock->refcnt++;
173*7f2fe78bSCy Schubert
174*7f2fe78bSCy Schubert db->opencnt = 0;
175*7f2fe78bSCy Schubert db->filename = strdup(filename);
176*7f2fe78bSCy Schubert db->magic = magic;
177*7f2fe78bSCy Schubert
178*7f2fe78bSCy Schubert *dbp = db;
179*7f2fe78bSCy Schubert
180*7f2fe78bSCy Schubert return OSA_ADB_OK;
181*7f2fe78bSCy Schubert }
182*7f2fe78bSCy Schubert
183*7f2fe78bSCy Schubert krb5_error_code
osa_adb_fini_db(osa_adb_db_t db,int magic)184*7f2fe78bSCy Schubert osa_adb_fini_db(osa_adb_db_t db, int magic)
185*7f2fe78bSCy Schubert {
186*7f2fe78bSCy Schubert if (db->magic != magic)
187*7f2fe78bSCy Schubert return EINVAL;
188*7f2fe78bSCy Schubert if (db->lock->refcnt == 0) {
189*7f2fe78bSCy Schubert /* barry says this can't happen */
190*7f2fe78bSCy Schubert return OSA_ADB_FAILURE;
191*7f2fe78bSCy Schubert } else {
192*7f2fe78bSCy Schubert db->lock->refcnt--;
193*7f2fe78bSCy Schubert }
194*7f2fe78bSCy Schubert
195*7f2fe78bSCy Schubert if (db->lock->refcnt == 0) {
196*7f2fe78bSCy Schubert /*
197*7f2fe78bSCy Schubert * Don't free db->lock->filename, it is used as a key to
198*7f2fe78bSCy Schubert * find the lockinfo entry in the linked list. If the
199*7f2fe78bSCy Schubert * lockfile doesn't exist, we must be closing the database
200*7f2fe78bSCy Schubert * after trashing it. This has to be allowed, so don't
201*7f2fe78bSCy Schubert * generate an error.
202*7f2fe78bSCy Schubert */
203*7f2fe78bSCy Schubert if (db->lock->lockmode != KRB5_DB_LOCKMODE_PERMANENT)
204*7f2fe78bSCy Schubert (void) fclose(db->lock->lockfile);
205*7f2fe78bSCy Schubert db->lock->lockfile = NULL;
206*7f2fe78bSCy Schubert krb5_free_context(db->lock->context);
207*7f2fe78bSCy Schubert }
208*7f2fe78bSCy Schubert
209*7f2fe78bSCy Schubert db->magic = 0;
210*7f2fe78bSCy Schubert free(db->filename);
211*7f2fe78bSCy Schubert free(db);
212*7f2fe78bSCy Schubert return OSA_ADB_OK;
213*7f2fe78bSCy Schubert }
214*7f2fe78bSCy Schubert
215*7f2fe78bSCy Schubert krb5_error_code
osa_adb_get_lock(osa_adb_db_t db,int mode)216*7f2fe78bSCy Schubert osa_adb_get_lock(osa_adb_db_t db, int mode)
217*7f2fe78bSCy Schubert {
218*7f2fe78bSCy Schubert int perm, krb5_mode, ret = 0;
219*7f2fe78bSCy Schubert
220*7f2fe78bSCy Schubert if (db->lock->lockmode >= mode) {
221*7f2fe78bSCy Schubert /* No need to upgrade lock, just incr refcnt and return */
222*7f2fe78bSCy Schubert db->lock->lockcnt++;
223*7f2fe78bSCy Schubert return(OSA_ADB_OK);
224*7f2fe78bSCy Schubert }
225*7f2fe78bSCy Schubert
226*7f2fe78bSCy Schubert perm = 0;
227*7f2fe78bSCy Schubert switch (mode) {
228*7f2fe78bSCy Schubert case KRB5_DB_LOCKMODE_PERMANENT:
229*7f2fe78bSCy Schubert perm = 1;
230*7f2fe78bSCy Schubert case KRB5_DB_LOCKMODE_EXCLUSIVE:
231*7f2fe78bSCy Schubert krb5_mode = KRB5_LOCKMODE_EXCLUSIVE;
232*7f2fe78bSCy Schubert break;
233*7f2fe78bSCy Schubert case KRB5_DB_LOCKMODE_SHARED:
234*7f2fe78bSCy Schubert krb5_mode = KRB5_LOCKMODE_SHARED;
235*7f2fe78bSCy Schubert break;
236*7f2fe78bSCy Schubert default:
237*7f2fe78bSCy Schubert return(EINVAL);
238*7f2fe78bSCy Schubert }
239*7f2fe78bSCy Schubert
240*7f2fe78bSCy Schubert ret = krb5_lock_file(db->lock->context, fileno(db->lock->lockfile),
241*7f2fe78bSCy Schubert krb5_mode);
242*7f2fe78bSCy Schubert if (ret == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
243*7f2fe78bSCy Schubert return OSA_ADB_NOEXCL_PERM;
244*7f2fe78bSCy Schubert else if (ret == EACCES || ret == EAGAIN || ret == EWOULDBLOCK)
245*7f2fe78bSCy Schubert return OSA_ADB_CANTLOCK_DB;
246*7f2fe78bSCy Schubert else if (ret != 0)
247*7f2fe78bSCy Schubert return ret;
248*7f2fe78bSCy Schubert
249*7f2fe78bSCy Schubert /*
250*7f2fe78bSCy Schubert * If the file no longer exists, someone acquired a permanent
251*7f2fe78bSCy Schubert * lock. If that process terminates its exclusive lock is lost,
252*7f2fe78bSCy Schubert * but if we already had the file open we can (probably) lock it
253*7f2fe78bSCy Schubert * even though it has been unlinked. So we need to insist that
254*7f2fe78bSCy Schubert * it exist.
255*7f2fe78bSCy Schubert */
256*7f2fe78bSCy Schubert if (access(db->lock->filename, F_OK) < 0) {
257*7f2fe78bSCy Schubert (void) krb5_lock_file(db->lock->context,
258*7f2fe78bSCy Schubert fileno(db->lock->lockfile),
259*7f2fe78bSCy Schubert KRB5_LOCKMODE_UNLOCK);
260*7f2fe78bSCy Schubert return OSA_ADB_NOLOCKFILE;
261*7f2fe78bSCy Schubert }
262*7f2fe78bSCy Schubert
263*7f2fe78bSCy Schubert /* we have the shared/exclusive lock */
264*7f2fe78bSCy Schubert
265*7f2fe78bSCy Schubert if (perm) {
266*7f2fe78bSCy Schubert if (unlink(db->lock->filename) < 0) {
267*7f2fe78bSCy Schubert /* somehow we can't delete the file, but we already */
268*7f2fe78bSCy Schubert /* have the lock, so release it and return */
269*7f2fe78bSCy Schubert
270*7f2fe78bSCy Schubert ret = errno;
271*7f2fe78bSCy Schubert (void) krb5_lock_file(db->lock->context,
272*7f2fe78bSCy Schubert fileno(db->lock->lockfile),
273*7f2fe78bSCy Schubert KRB5_LOCKMODE_UNLOCK);
274*7f2fe78bSCy Schubert
275*7f2fe78bSCy Schubert /* maybe we should return CANTLOCK_DB.. but that would */
276*7f2fe78bSCy Schubert /* look just like the db was already locked */
277*7f2fe78bSCy Schubert return ret;
278*7f2fe78bSCy Schubert }
279*7f2fe78bSCy Schubert
280*7f2fe78bSCy Schubert /* this releases our exclusive lock.. which is okay because */
281*7f2fe78bSCy Schubert /* now no one else can get one either */
282*7f2fe78bSCy Schubert (void) fclose(db->lock->lockfile);
283*7f2fe78bSCy Schubert }
284*7f2fe78bSCy Schubert
285*7f2fe78bSCy Schubert db->lock->lockmode = mode;
286*7f2fe78bSCy Schubert db->lock->lockcnt++;
287*7f2fe78bSCy Schubert return OSA_ADB_OK;
288*7f2fe78bSCy Schubert }
289*7f2fe78bSCy Schubert
290*7f2fe78bSCy Schubert krb5_error_code
osa_adb_release_lock(osa_adb_db_t db)291*7f2fe78bSCy Schubert osa_adb_release_lock(osa_adb_db_t db)
292*7f2fe78bSCy Schubert {
293*7f2fe78bSCy Schubert int ret, fd;
294*7f2fe78bSCy Schubert
295*7f2fe78bSCy Schubert if (!db->lock->lockcnt) /* lock already unlocked */
296*7f2fe78bSCy Schubert return OSA_ADB_NOTLOCKED;
297*7f2fe78bSCy Schubert
298*7f2fe78bSCy Schubert if (--db->lock->lockcnt == 0) {
299*7f2fe78bSCy Schubert if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) {
300*7f2fe78bSCy Schubert /* now we need to create the file since it does not exist */
301*7f2fe78bSCy Schubert fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL,
302*7f2fe78bSCy Schubert 0600);
303*7f2fe78bSCy Schubert if (fd < 0)
304*7f2fe78bSCy Schubert return OSA_ADB_NOLOCKFILE;
305*7f2fe78bSCy Schubert set_cloexec_fd(fd);
306*7f2fe78bSCy Schubert if ((db->lock->lockfile = fdopen(fd, "w+")) == NULL)
307*7f2fe78bSCy Schubert return OSA_ADB_NOLOCKFILE;
308*7f2fe78bSCy Schubert } else if ((ret = krb5_lock_file(db->lock->context,
309*7f2fe78bSCy Schubert fileno(db->lock->lockfile),
310*7f2fe78bSCy Schubert KRB5_LOCKMODE_UNLOCK)))
311*7f2fe78bSCy Schubert return ret;
312*7f2fe78bSCy Schubert
313*7f2fe78bSCy Schubert db->lock->lockmode = 0;
314*7f2fe78bSCy Schubert }
315*7f2fe78bSCy Schubert return OSA_ADB_OK;
316*7f2fe78bSCy Schubert }
317*7f2fe78bSCy Schubert
318*7f2fe78bSCy Schubert krb5_error_code
osa_adb_open_and_lock(osa_adb_princ_t db,int locktype)319*7f2fe78bSCy Schubert osa_adb_open_and_lock(osa_adb_princ_t db, int locktype)
320*7f2fe78bSCy Schubert {
321*7f2fe78bSCy Schubert int ret;
322*7f2fe78bSCy Schubert
323*7f2fe78bSCy Schubert ret = osa_adb_get_lock(db, locktype);
324*7f2fe78bSCy Schubert if (ret != OSA_ADB_OK)
325*7f2fe78bSCy Schubert return ret;
326*7f2fe78bSCy Schubert if (db->opencnt)
327*7f2fe78bSCy Schubert goto open_ok;
328*7f2fe78bSCy Schubert
329*7f2fe78bSCy Schubert db->db = dbopen(db->filename, O_RDWR, 0600, DB_BTREE, &db->btinfo);
330*7f2fe78bSCy Schubert if (db->db == NULL && IS_EFTYPE(errno))
331*7f2fe78bSCy Schubert db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info);
332*7f2fe78bSCy Schubert if (db->db == NULL) {
333*7f2fe78bSCy Schubert (void)osa_adb_release_lock(db);
334*7f2fe78bSCy Schubert return (errno == EINVAL) ? OSA_ADB_BAD_DB : errno;
335*7f2fe78bSCy Schubert }
336*7f2fe78bSCy Schubert
337*7f2fe78bSCy Schubert open_ok:
338*7f2fe78bSCy Schubert db->opencnt++;
339*7f2fe78bSCy Schubert return OSA_ADB_OK;
340*7f2fe78bSCy Schubert }
341*7f2fe78bSCy Schubert
342*7f2fe78bSCy Schubert krb5_error_code
osa_adb_close_and_unlock(osa_adb_princ_t db)343*7f2fe78bSCy Schubert osa_adb_close_and_unlock(osa_adb_princ_t db)
344*7f2fe78bSCy Schubert {
345*7f2fe78bSCy Schubert if (--db->opencnt)
346*7f2fe78bSCy Schubert return osa_adb_release_lock(db);
347*7f2fe78bSCy Schubert if(db->db != NULL && db->db->close(db->db) == -1) {
348*7f2fe78bSCy Schubert (void) osa_adb_release_lock(db);
349*7f2fe78bSCy Schubert return OSA_ADB_FAILURE;
350*7f2fe78bSCy Schubert }
351*7f2fe78bSCy Schubert
352*7f2fe78bSCy Schubert db->db = NULL;
353*7f2fe78bSCy Schubert
354*7f2fe78bSCy Schubert return(osa_adb_release_lock(db));
355*7f2fe78bSCy Schubert }
356