2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
5 #pragma ident "%Z%%M% %I% %E% SMI"
8 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
10 * Openvision retains the copyright to derivative works of
11 * this source code. Do *NOT* create a derivative of this
12 * source code before consulting with your legal department.
13 * Do *NOT* integrate *ANY* of this source code into another
14 * product before consulting with your legal department.
16 * For further information, read the top-level Openvision
17 * copyright which is contained in the top-level MIT Kerberos
20 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
26 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
28 * $Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/adb_openclose.c,v 1.8 2002/10/08 20:20:29 tlyu Exp $
31 #if !defined(lint) && !defined(__CODECENTER__)
32 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 $";
39 #include "policy_db.h"
43 #define MAX_LOCK_TRIES 5
46 osa_adb_lock_ent lockinfo
;
47 struct _locklist
*next
;
50 krb5_error_code
osa_adb_create_db(char *filename
, char *lockfilename
,
57 memset(&btinfo
, 0, sizeof(btinfo
));
62 btinfo
.minkeypage
= 0;
63 btinfo
.compare
= NULL
;
65 db
= dbopen(filename
, O_RDWR
| O_CREAT
| O_EXCL
, 0600, DB_BTREE
, &btinfo
);
68 if (db
->close(db
) < 0)
71 /* only create the lock file if we successfully created the db */
72 lf
= THREEPARAMOPEN(lockfilename
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
80 krb5_error_code
osa_adb_destroy_db(char *filename
, char *lockfilename
,
83 /* the admin databases do not contain security-critical data */
84 if (unlink(filename
) < 0 ||
85 unlink(lockfilename
) < 0)
90 krb5_error_code
osa_adb_rename_db(char *filefrom
, char *lockfrom
,
91 char *fileto
, char *lockto
, int magic
)
93 osa_adb_db_t fromdb
, todb
;
96 /* make sure todb exists */
98 if ((ret
= osa_adb_create_db(fileto
, lockto
, magic
)) &&
102 if ((ret
= osa_adb_init_db(&fromdb
, filefrom
, lockfrom
, magic
)))
104 if ((ret
= osa_adb_init_db(&todb
, fileto
, lockto
, magic
))) {
105 (void) osa_adb_fini_db(fromdb
, magic
);
108 if ((ret
= osa_adb_get_lock(fromdb
, KRB5_DB_LOCKMODE_PERMANENT
))) {
109 (void) osa_adb_fini_db(fromdb
, magic
);
110 (void) osa_adb_fini_db(todb
, magic
);
113 if ((ret
= osa_adb_get_lock(todb
, KRB5_DB_LOCKMODE_PERMANENT
))) {
114 (void) osa_adb_fini_db(fromdb
, magic
);
115 (void) osa_adb_fini_db(todb
, magic
);
118 if ((rename(filefrom
, fileto
) < 0)) {
119 (void) osa_adb_fini_db(fromdb
, magic
);
120 (void) osa_adb_fini_db(todb
, magic
);
124 * Do not release the lock on fromdb because it is being renamed
125 * out of existence; no one can ever use it again.
127 if ((ret
= osa_adb_release_lock(todb
))) {
128 (void) osa_adb_fini_db(fromdb
, magic
);
129 (void) osa_adb_fini_db(todb
, magic
);
133 (void) osa_adb_fini_db(fromdb
, magic
);
134 (void) osa_adb_fini_db(todb
, magic
);
138 krb5_error_code
osa_adb_init_db(osa_adb_db_t
*dbp
, char *filename
,
139 char *lockfilename
, int magic
)
142 static struct _locklist
*locklist
= NULL
;
143 struct _locklist
*lockp
;
144 krb5_error_code code
;
146 if (dbp
== NULL
|| filename
== NULL
)
149 db
= (osa_adb_princ_t
) malloc(sizeof(osa_adb_db_ent
));
153 memset(db
, 0, sizeof(*db
));
154 db
->info
.hash
= NULL
;
155 db
->info
.bsize
= 256;
156 db
->info
.ffactor
= 8;
157 db
->info
.nelem
= 25000;
160 db
->btinfo
.flags
= 0;
161 db
->btinfo
.cachesize
= 0;
162 db
->btinfo
.psize
= 4096;
163 db
->btinfo
.lorder
= 0;
164 db
->btinfo
.minkeypage
= 0;
165 db
->btinfo
.compare
= NULL
;
166 db
->btinfo
.prefix
= NULL
;
168 * A process is allowed to open the same database multiple times
169 * and access it via different handles. If the handles use
170 * distinct lockinfo structures, things get confused: lock(A),
171 * lock(B), release(B) will result in the kernel unlocking the
172 * lock file but handle A will still think the file is locked.
173 * Therefore, all handles using the same lock file must share a
174 * single lockinfo structure.
176 * It is not sufficient to have a single lockinfo structure,
177 * however, because a single process may also wish to open
178 * multiple different databases simultaneously, with different
179 * lock files. This code used to use a single static lockinfo
180 * structure, which means that the second database opened used
181 * the first database's lock file. This was Bad.
183 * We now maintain a linked list of lockinfo structures, keyed by
184 * lockfilename. An entry is added when this function is called
185 * with a new lockfilename, and all subsequent calls with that
186 * lockfilename use the existing entry, updating the refcnt.
187 * When the database is closed with fini_db(), the refcnt is
188 * decremented, and when it is zero the lockinfo structure is
189 * freed and reset. The entry in the linked list, however, is
190 * never removed; it will just be reinitialized the next time
191 * init_db is called with the right lockfilename.
194 /* find or create the lockinfo structure for lockfilename */
197 if (strcmp(lockp
->lockinfo
.filename
, lockfilename
) == 0)
203 /* doesn't exist, create it, add to list */
204 lockp
= (struct _locklist
*) malloc(sizeof(*lockp
));
209 memset(lockp
, 0, sizeof(*lockp
));
210 lockp
->next
= locklist
;
214 /* now initialize lockp->lockinfo if necessary */
215 if (lockp
->lockinfo
.lockfile
== NULL
) {
216 if ((code
= krb5int_init_context_kdc(&lockp
->lockinfo
.context
))) {
218 return((krb5_error_code
) code
);
222 * needs be open read/write so that write locking can work with
225 lockp
->lockinfo
.filename
= strdup(lockfilename
);
226 if ((lockp
->lockinfo
.lockfile
= fopen(lockfilename
, "r+F")) == NULL
) {
228 * maybe someone took away write permission so we could only
231 if ((lockp
->lockinfo
.lockfile
= fopen(lockfilename
, "rF"))
234 return OSA_ADB_NOLOCKFILE
;
237 lockp
->lockinfo
.lockmode
= lockp
->lockinfo
.lockcnt
= 0;
240 /* lockp is set, lockinfo is initialized, update the reference count */
241 db
->lock
= &lockp
->lockinfo
;
245 db
->filename
= strdup(filename
);
253 krb5_error_code
osa_adb_fini_db(osa_adb_db_t db
, int magic
)
255 if (db
->magic
!= magic
)
257 if (db
->lock
->refcnt
== 0) {
258 /* barry says this can't happen */
259 return OSA_ADB_FAILURE
;
264 if (db
->lock
->refcnt
== 0) {
266 * Don't free db->lock->filename, it is used as a key to
267 * find the lockinfo entry in the linked list. If the
268 * lockfile doesn't exist, we must be closing the database
269 * after trashing it. This has to be allowed, so don't
272 if (db
->lock
->lockmode
!= KRB5_DB_LOCKMODE_PERMANENT
)
273 (void) fclose(db
->lock
->lockfile
);
274 db
->lock
->lockfile
= NULL
;
275 krb5_free_context(db
->lock
->context
);
284 krb5_error_code
osa_adb_get_lock(osa_adb_db_t db
, int mode
)
286 int tries
, gotlock
, perm
, krb5_mode
, ret
= 0;
288 if (db
->lock
->lockmode
>= mode
) {
289 /* No need to upgrade lock, just incr refcnt and return */
296 case KRB5_DB_LOCKMODE_PERMANENT
:
299 case KRB5_DB_LOCKMODE_EXCLUSIVE
:
300 krb5_mode
= KRB5_LOCKMODE_EXCLUSIVE
;
302 case KRB5_DB_LOCKMODE_SHARED
:
303 krb5_mode
= KRB5_LOCKMODE_SHARED
;
309 for (gotlock
= tries
= 0; tries
< MAX_LOCK_TRIES
; tries
++) {
310 if ((ret
= krb5_lock_file(db
->lock
->context
,
311 fileno(db
->lock
->lockfile
),
312 krb5_mode
|KRB5_LOCKMODE_DONTBLOCK
)) == 0) {
315 } else if (ret
== EBADF
&& mode
== KRB5_DB_LOCKMODE_EXCLUSIVE
)
316 /* tried to exclusive-lock something we don't have */
317 /* write access to */
318 return OSA_ADB_NOEXCL_PERM
;
323 /* test for all the likely "can't get lock" error codes */
324 if (ret
== EACCES
|| ret
== EAGAIN
|| ret
== EWOULDBLOCK
)
325 return OSA_ADB_CANTLOCK_DB
;
330 * If the file no longer exists, someone acquired a permanent
331 * lock. If that process terminates its exclusive lock is lost,
332 * but if we already had the file open we can (probably) lock it
333 * even though it has been unlinked. So we need to insist that
336 if (access(db
->lock
->filename
, F_OK
) < 0) {
337 (void) krb5_lock_file(db
->lock
->context
,
338 fileno(db
->lock
->lockfile
),
339 KRB5_LOCKMODE_UNLOCK
);
340 return OSA_ADB_NOLOCKFILE
;
343 /* we have the shared/exclusive lock */
346 if (unlink(db
->lock
->filename
) < 0) {
347 /* somehow we can't delete the file, but we already */
348 /* have the lock, so release it and return */
351 (void) krb5_lock_file(db
->lock
->context
,
352 fileno(db
->lock
->lockfile
),
353 KRB5_LOCKMODE_UNLOCK
);
355 /* maybe we should return CANTLOCK_DB.. but that would */
356 /* look just like the db was already locked */
360 /* this releases our exclusive lock.. which is okay because */
361 /* now no one else can get one either */
362 (void) fclose(db
->lock
->lockfile
);
365 db
->lock
->lockmode
= mode
;
370 krb5_error_code
osa_adb_release_lock(osa_adb_db_t db
)
374 if (!db
->lock
->lockcnt
) /* lock already unlocked */
375 return OSA_ADB_NOTLOCKED
;
377 if (--db
->lock
->lockcnt
== 0) {
378 if (db
->lock
->lockmode
== KRB5_DB_LOCKMODE_PERMANENT
) {
379 /* now we need to create the file since it does not exist */
380 fd
= THREEPARAMOPEN(db
->lock
->filename
,O_RDWR
| O_CREAT
| O_EXCL
,
382 if ((db
->lock
->lockfile
= fdopen(fd
, "w+F")) == NULL
)
383 return OSA_ADB_NOLOCKFILE
;
384 } else if ((ret
= krb5_lock_file(db
->lock
->context
,
385 fileno(db
->lock
->lockfile
),
386 KRB5_LOCKMODE_UNLOCK
)))
389 db
->lock
->lockmode
= 0;
394 krb5_error_code
osa_adb_open_and_lock(osa_adb_princ_t db
, int locktype
)
398 ret
= osa_adb_get_lock(db
, locktype
);
399 if (ret
!= OSA_ADB_OK
)
404 db
->db
= dbopen(db
->filename
, O_RDWR
, 0600, DB_BTREE
, &db
->btinfo
);
412 db
->db
= dbopen(db
->filename
, O_RDWR
, 0600, DB_HASH
, &db
->info
);
416 (void) osa_adb_release_lock(db
);
418 return OSA_ADB_BAD_DB
;
426 krb5_error_code
osa_adb_close_and_unlock(osa_adb_princ_t db
)
429 return osa_adb_release_lock(db
);
430 if(db
->db
!= NULL
&& db
->db
->close(db
->db
) == -1) {
431 (void) osa_adb_release_lock(db
);
432 return OSA_ADB_FAILURE
;
437 return(osa_adb_release_lock(db
));