|
|
1.1 root 1: /*
2: * $Source: /usr/src/kerberosIV/kdb/RCS/krb_dbm.c,v $
3: * $Author: kfall $
4: *
5: * Copyright 1988 by the Massachusetts Institute of Technology.
6: *
7: * For copying and distribution information, please see the file
8: * <mit-copyright.h>.
9: */
10:
11: #ifndef lint
12: static char rcsid_krb_dbm_c[] =
13: "$Header: /usr/src/kerberosIV/kdb/RCS/krb_dbm.c,v 4.10 90/06/25 20:52:39 kfall Exp $";
14: #endif lint
15:
16: #include <sys/types.h>
17: #include <sys/uio.h>
18: #include <sys/time.h>
19: #include <sys/stat.h>
20: #include <sys/resource.h>
21: #include <sys/errno.h>
22: #include <sys/file.h>
23: #include <netinet/in.h>
24: #include <mit-copyright.h>
25: #include <stdio.h>
26: #include <string.h>
27: #include <des.h>
28: #include <krb.h>
29: #include <krb_db.h>
30: #include <ndbm.h>
31:
32: #define KERB_DB_MAX_RETRY 5
33:
34: #ifdef DEBUG
35: extern int debug;
36: extern long kerb_debug;
37: extern char *progname;
38: #endif
39: extern char *malloc();
40: extern int errno;
41:
42: static init = 0;
43: static char default_db_name[] = DBM_FILE;
44: static char *current_db_name = default_db_name;
45: static void encode_princ_key(), decode_princ_key();
46: static void encode_princ_contents(), decode_princ_contents();
47: static void kerb_dbl_fini();
48: static int kerb_dbl_lock();
49: static void kerb_dbl_unlock();
50:
51: static struct timeval timestamp;/* current time of request */
52: static int non_blocking = 0;
53:
54: /*
55: * This module contains all of the code which directly interfaces to
56: * the underlying representation of the Kerberos database; this
57: * implementation uses a DBM or NDBM indexed "file" (actually
58: * implemented as two separate files) to store the relations, plus a
59: * third file as a semaphore to allow the database to be replaced out
60: * from underneath the KDC server.
61: */
62:
63: /*
64: * Locking:
65: *
66: * There are two distinct locking protocols used. One is designed to
67: * lock against processes (the admin_server, for one) which make
68: * incremental changes to the database; the other is designed to lock
69: * against utilities (kdb_util, kpropd) which replace the entire
70: * database in one fell swoop.
71: *
72: * The first locking protocol is implemented using flock() in the
73: * krb_dbl_lock() and krb_dbl_unlock routines.
74: *
75: * The second locking protocol is necessary because DBM "files" are
76: * actually implemented as two separate files, and it is impossible to
77: * atomically rename two files simultaneously. It assumes that the
78: * database is replaced only very infrequently in comparison to the time
79: * needed to do a database read operation.
80: *
81: * A third file is used as a "version" semaphore; the modification
82: * time of this file is the "version number" of the database.
83: * At the start of a read operation, the reader checks the version
84: * number; at the end of the read operation, it checks again. If the
85: * version number changed, or if the semaphore was nonexistant at
86: * either time, the reader sleeps for a second to let things
87: * stabilize, and then tries again; if it does not succeed after
88: * KERB_DB_MAX_RETRY attempts, it gives up.
89: *
90: * On update, the semaphore file is deleted (if it exists) before any
91: * update takes place; at the end of the update, it is replaced, with
92: * a version number strictly greater than the version number which
93: * existed at the start of the update.
94: *
95: * If the system crashes in the middle of an update, the semaphore
96: * file is not automatically created on reboot; this is a feature, not
97: * a bug, since the database may be inconsistant. Note that the
98: * absence of a semaphore file does not prevent another _update_ from
99: * taking place later. Database replacements take place automatically
100: * only on slave servers; a crash in the middle of an update will be
101: * fixed by the next slave propagation. A crash in the middle of an
102: * update on the master would be somewhat more serious, but this would
103: * likely be noticed by an administrator, who could fix the problem and
104: * retry the operation.
105: */
106:
107: /* Macros to convert ndbm names to dbm names.
108: * Note that dbm_nextkey() cannot be simply converted using a macro, since
109: * it is invoked giving the database, and nextkey() needs the previous key.
110: *
111: * Instead, all routines call "dbm_next" instead.
112: */
113:
114: #define dbm_next(db,key) dbm_nextkey(db)
115:
116: /*
117: * Utility routine: generate name of database file.
118: */
119:
120: static char *gen_dbsuffix(db_name, sfx)
121: char *db_name;
122: char *sfx;
123: {
124: char *dbsuffix;
125:
126: if (sfx == NULL)
127: sfx = ".ok";
128:
129: dbsuffix = malloc (strlen(db_name) + strlen(sfx) + 1);
130: strcpy(dbsuffix, db_name);
131: strcat(dbsuffix, sfx);
132: return dbsuffix;
133: }
134:
135: /*
136: * initialization for data base routines.
137: */
138:
139: kerb_db_init()
140: {
141: init = 1;
142: return (0);
143: }
144:
145: /*
146: * gracefully shut down database--must be called by ANY program that does
147: * a kerb_db_init
148: */
149:
150: kerb_db_fini()
151: {
152: }
153:
154: /*
155: * Set the "name" of the current database to some alternate value.
156: *
157: * Passing a null pointer as "name" will set back to the default.
158: * If the alternate database doesn't exist, nothing is changed.
159: */
160:
161: kerb_db_set_name(name)
162: char *name;
163: {
164: DBM *db;
165:
166: if (name == NULL)
167: name = default_db_name;
168: db = dbm_open(name, 0, 0);
169: if (db == NULL)
170: return errno;
171: dbm_close(db);
172: kerb_dbl_fini();
173: current_db_name = name;
174: return 0;
175: }
176:
177: /*
178: * Return the last modification time of the database.
179: */
180:
181: long kerb_get_db_age()
182: {
183: struct stat st;
184: char *okname;
185: long age;
186:
187: okname = gen_dbsuffix(current_db_name, ".ok");
188:
189: if (stat (okname, &st) < 0)
190: age = 0;
191: else
192: age = st.st_mtime;
193:
194: free (okname);
195: return age;
196: }
197:
198: /*
199: * Remove the semaphore file; indicates that database is currently
200: * under renovation.
201: *
202: * This is only for use when moving the database out from underneath
203: * the server (for example, during slave updates).
204: */
205:
206: static long kerb_start_update(db_name)
207: char *db_name;
208: {
209: char *okname = gen_dbsuffix(db_name, ".ok");
210: long age = kerb_get_db_age();
211:
212: if (unlink(okname) < 0
213: && errno != ENOENT) {
214: age = -1;
215: }
216: free (okname);
217: return age;
218: }
219:
220: static long kerb_end_update(db_name, age)
221: char *db_name;
222: long age;
223: {
224: int fd;
225: int retval = 0;
226: char *new_okname = gen_dbsuffix(db_name, ".ok#");
227: char *okname = gen_dbsuffix(db_name, ".ok");
228:
229: fd = open (new_okname, O_CREAT|O_RDWR|O_TRUNC, 0600);
230: if (fd < 0)
231: retval = errno;
232: else {
233: struct stat st;
234: struct timeval tv[2];
235: /* make sure that semaphore is "after" previous value. */
236: if (fstat (fd, &st) == 0
237: && st.st_mtime <= age) {
238: tv[0].tv_sec = st.st_atime;
239: tv[0].tv_usec = 0;
240: tv[1].tv_sec = age;
241: tv[1].tv_usec = 0;
242: /* set times.. */
243: utimes (new_okname, tv);
244: fsync(fd);
245: }
246: close(fd);
247: if (rename (new_okname, okname) < 0)
248: retval = errno;
249: }
250:
251: free (new_okname);
252: free (okname);
253:
254: return retval;
255: }
256:
257: static long kerb_start_read()
258: {
259: return kerb_get_db_age();
260: }
261:
262: static long kerb_end_read(age)
263: u_long age;
264: {
265: if (kerb_get_db_age() != age || age == -1) {
266: return -1;
267: }
268: return 0;
269: }
270:
271: /*
272: * Create the database, assuming it's not there.
273: */
274:
275: kerb_db_create(db_name)
276: char *db_name;
277: {
278: char *okname = gen_dbsuffix(db_name, ".ok");
279: int fd;
280: register int ret = 0;
281: DBM *db;
282:
283: db = dbm_open(db_name, O_RDWR|O_CREAT|O_EXCL, 0600);
284: if (db == NULL)
285: ret = errno;
286: else
287: dbm_close(db);
288:
289: if (ret == 0) {
290: fd = open (okname, O_CREAT|O_RDWR|O_TRUNC, 0600);
291: if (fd < 0)
292: ret = errno;
293: close(fd);
294: }
295: return ret;
296: }
297:
298: /*
299: * "Atomically" rename the database in a way that locks out read
300: * access in the middle of the rename.
301: *
302: * Not perfect; if we crash in the middle of an update, we don't
303: * necessarily know to complete the transaction the rename, but...
304: */
305:
306: kerb_db_rename(from, to)
307: char *from;
308: char *to;
309: {
310: char *fromdir = gen_dbsuffix (from, ".dir");
311: char *todir = gen_dbsuffix (to, ".dir");
312: char *frompag = gen_dbsuffix (from , ".pag");
313: char *topag = gen_dbsuffix (to, ".pag");
314: char *fromok = gen_dbsuffix(from, ".ok");
315: long trans = kerb_start_update(to);
316: int ok;
317:
318: if ((rename (fromdir, todir) == 0)
319: && (rename (frompag, topag) == 0)) {
320: (void) unlink (fromok);
321: ok = 1;
322: }
323:
324: free (fromok);
325: free (fromdir);
326: free (todir);
327: free (frompag);
328: free (topag);
329: if (ok)
330: return kerb_end_update(to, trans);
331: else
332: return -1;
333: }
334:
335: /*
336: * look up a principal in the data base returns number of principals
337: * found , and whether there were more than requested.
338: */
339:
340: kerb_db_get_principal(name, inst, principal, max, more)
341: char *name; /* could have wild card */
342: char *inst; /* could have wild card */
343: Principal *principal;
344: unsigned int max; /* max number of name structs to return */
345: int *more; /* where there more than 'max' tuples? */
346:
347: {
348: int found = 0, code;
349: extern int errorproc();
350: int wildp, wildi;
351: datum key, contents;
352: char testname[ANAME_SZ], testinst[INST_SZ];
353: u_long trans;
354: int try;
355: DBM *db;
356:
357: if (!init)
358: kerb_db_init(); /* initialize database routines */
359:
360: for (try = 0; try < KERB_DB_MAX_RETRY; try++) {
361: trans = kerb_start_read();
362:
363: if ((code = kerb_dbl_lock(KERB_DBL_SHARED)) != 0)
364: return -1;
365:
366: db = dbm_open(current_db_name, O_RDONLY, 0600);
367:
368: *more = 0;
369:
370: #ifdef DEBUG
371: if (kerb_debug & 2)
372: fprintf(stderr,
373: "%s: db_get_principal for %s %s max = %d",
374: progname, name, inst, max);
375: #endif
376:
377: wildp = !strcmp(name, "*");
378: wildi = !strcmp(inst, "*");
379:
380: if (!wildi && !wildp) { /* nothing's wild */
381: encode_princ_key(&key, name, inst);
382: contents = dbm_fetch(db, key);
383: if (contents.dptr == NULL) {
384: found = 0;
385: goto done;
386: }
387: decode_princ_contents(&contents, principal);
388: #ifdef DEBUG
389: if (kerb_debug & 1) {
390: fprintf(stderr, "\t found %s %s p_n length %d t_n length %d\n",
391: principal->name, principal->instance,
392: strlen(principal->name),
393: strlen(principal->instance));
394: }
395: #endif
396: found = 1;
397: goto done;
398: }
399: /* process wild cards by looping through entire database */
400:
401: for (key = dbm_firstkey(db); key.dptr != NULL;
402: key = dbm_next(db, key)) {
403: decode_princ_key(&key, testname, testinst);
404: if ((wildp || !strcmp(testname, name)) &&
405: (wildi || !strcmp(testinst, inst))) { /* have a match */
406: if (found >= max) {
407: *more = 1;
408: goto done;
409: } else {
410: found++;
411: contents = dbm_fetch(db, key);
412: decode_princ_contents(&contents, principal);
413: #ifdef DEBUG
414: if (kerb_debug & 1) {
415: fprintf(stderr,
416: "\tfound %s %s p_n length %d t_n length %d\n",
417: principal->name, principal->instance,
418: strlen(principal->name),
419: strlen(principal->instance));
420: }
421: #endif
422: principal++; /* point to next */
423: }
424: }
425: }
426:
427: done:
428: kerb_dbl_unlock(); /* unlock read lock */
429: dbm_close(db);
430: if (kerb_end_read(trans) == 0)
431: break;
432: found = -1;
433: if (!non_blocking)
434: sleep(1);
435: }
436: return (found);
437: }
438:
439: /*
440: * Update a name in the data base. Returns number of names
441: * successfully updated.
442: */
443:
444: kerb_db_put_principal(principal, max)
445: Principal *principal;
446: unsigned int max; /* number of principal structs to
447: * update */
448:
449: {
450: int found = 0, code;
451: u_long i;
452: extern int errorproc();
453: datum key, contents;
454: DBM *db;
455:
456: gettimeofday(×tamp, NULL);
457:
458: if (!init)
459: kerb_db_init();
460:
461: if ((code = kerb_dbl_lock(KERB_DBL_EXCLUSIVE)) != 0)
462: return -1;
463:
464: db = dbm_open(current_db_name, O_RDWR, 0600);
465:
466: #ifdef DEBUG
467: if (kerb_debug & 2)
468: fprintf(stderr, "%s: kerb_db_put_principal max = %d",
469: progname, max);
470: #endif
471:
472: /* for each one, stuff temps, and do replace/append */
473: for (i = 0; i < max; i++) {
474: encode_princ_contents(&contents, principal);
475: encode_princ_key(&key, principal->name, principal->instance);
476: dbm_store(db, key, contents, DBM_REPLACE);
477: #ifdef DEBUG
478: if (kerb_debug & 1) {
479: fprintf(stderr, "\n put %s %s\n",
480: principal->name, principal->instance);
481: }
482: #endif
483: found++;
484: principal++; /* bump to next struct */
485: }
486:
487: dbm_close(db);
488: kerb_dbl_unlock(); /* unlock database */
489: return (found);
490: }
491:
492: static void
493: encode_princ_key(key, name, instance)
494: datum *key;
495: char *name, *instance;
496: {
497: static char keystring[ANAME_SZ + INST_SZ];
498:
499: bzero(keystring, ANAME_SZ + INST_SZ);
500: strncpy(keystring, name, ANAME_SZ);
501: strncpy(&keystring[ANAME_SZ], instance, INST_SZ);
502: key->dptr = keystring;
503: key->dsize = ANAME_SZ + INST_SZ;
504: }
505:
506: static void
507: decode_princ_key(key, name, instance)
508: datum *key;
509: char *name, *instance;
510: {
511: strncpy(name, key->dptr, ANAME_SZ);
512: strncpy(instance, key->dptr + ANAME_SZ, INST_SZ);
513: name[ANAME_SZ - 1] = '\0';
514: instance[INST_SZ - 1] = '\0';
515: }
516:
517: static void
518: encode_princ_contents(contents, principal)
519: datum *contents;
520: Principal *principal;
521: {
522: contents->dsize = sizeof(*principal);
523: contents->dptr = (char *) principal;
524: }
525:
526: static void
527: decode_princ_contents(contents, principal)
528: datum *contents;
529: Principal *principal;
530: {
531: bcopy(contents->dptr, (char *) principal, sizeof(*principal));
532: }
533:
534: kerb_db_get_stat(s)
535: DB_stat *s;
536: {
537: gettimeofday(×tamp, NULL);
538:
539:
540: s->cpu = 0;
541: s->elapsed = 0;
542: s->dio = 0;
543: s->pfault = 0;
544: s->t_stamp = timestamp.tv_sec;
545: s->n_retrieve = 0;
546: s->n_replace = 0;
547: s->n_append = 0;
548: s->n_get_stat = 0;
549: s->n_put_stat = 0;
550: /* update local copy too */
551: }
552:
553: kerb_db_put_stat(s)
554: DB_stat *s;
555: {
556: }
557:
558: delta_stat(a, b, c)
559: DB_stat *a, *b, *c;
560: {
561: /* c = a - b then b = a for the next time */
562:
563: c->cpu = a->cpu - b->cpu;
564: c->elapsed = a->elapsed - b->elapsed;
565: c->dio = a->dio - b->dio;
566: c->pfault = a->pfault - b->pfault;
567: c->t_stamp = a->t_stamp - b->t_stamp;
568: c->n_retrieve = a->n_retrieve - b->n_retrieve;
569: c->n_replace = a->n_replace - b->n_replace;
570: c->n_append = a->n_append - b->n_append;
571: c->n_get_stat = a->n_get_stat - b->n_get_stat;
572: c->n_put_stat = a->n_put_stat - b->n_put_stat;
573:
574: bcopy(a, b, sizeof(DB_stat));
575: return;
576: }
577:
578: /*
579: * look up a dba in the data base returns number of dbas found , and
580: * whether there were more than requested.
581: */
582:
583: kerb_db_get_dba(dba_name, dba_inst, dba, max, more)
584: char *dba_name; /* could have wild card */
585: char *dba_inst; /* could have wild card */
586: Dba *dba;
587: unsigned int max; /* max number of name structs to return */
588: int *more; /* where there more than 'max' tuples? */
589:
590: {
591: *more = 0;
592: return (0);
593: }
594:
595: kerb_db_iterate (func, arg)
596: int (*func)();
597: char *arg; /* void *, really */
598: {
599: datum key, contents;
600: Principal *principal;
601: int code;
602: DBM *db;
603:
604: kerb_db_init(); /* initialize and open the database */
605: if ((code = kerb_dbl_lock(KERB_DBL_SHARED)) != 0)
606: return code;
607:
608: db = dbm_open(current_db_name, O_RDONLY, 0600);
609:
610: for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_next(db, key)) {
611: contents = dbm_fetch (db, key);
612: /* XXX may not be properly aligned */
613: principal = (Principal *) contents.dptr;
614: if ((code = (*func)(arg, principal)) != 0)
615: return code;
616: }
617: dbm_close(db);
618: kerb_dbl_unlock();
619: return 0;
620: }
621:
622: static int dblfd = -1;
623: static int mylock = 0;
624: static int inited = 0;
625:
626: static kerb_dbl_init()
627: {
628: if (!inited) {
629: char *filename = gen_dbsuffix (current_db_name, ".ok");
630: if ((dblfd = open(filename, 0)) < 0) {
631: fprintf(stderr, "kerb_dbl_init: couldn't open %s\n", filename);
632: fflush(stderr);
633: perror("open");
634: exit(1);
635: }
636: free(filename);
637: inited++;
638: }
639: return (0);
640: }
641:
642: static void kerb_dbl_fini()
643: {
644: close(dblfd);
645: dblfd = -1;
646: inited = 0;
647: mylock = 0;
648: }
649:
650: static int kerb_dbl_lock(mode)
651: int mode;
652: {
653: int flock_mode;
654:
655: if (!inited)
656: kerb_dbl_init();
657: if (mylock) { /* Detect lock call when lock already
658: * locked */
659: fprintf(stderr, "Kerberos locking error (mylock)\n");
660: fflush(stderr);
661: exit(1);
662: }
663: switch (mode) {
664: case KERB_DBL_EXCLUSIVE:
665: flock_mode = LOCK_EX;
666: break;
667: case KERB_DBL_SHARED:
668: flock_mode = LOCK_SH;
669: break;
670: default:
671: fprintf(stderr, "invalid lock mode %d\n", mode);
672: abort();
673: }
674: if (non_blocking)
675: flock_mode |= LOCK_NB;
676:
677: if (flock(dblfd, flock_mode) < 0)
678: return errno;
679: mylock++;
680: return 0;
681: }
682:
683: static void kerb_dbl_unlock()
684: {
685: if (!mylock) { /* lock already unlocked */
686: fprintf(stderr, "Kerberos database lock not locked when unlocking.\n");
687: fflush(stderr);
688: exit(1);
689: }
690: if (flock(dblfd, LOCK_UN) < 0) {
691: fprintf(stderr, "Kerberos database lock error. (unlocking)\n");
692: fflush(stderr);
693: perror("flock");
694: exit(1);
695: }
696: mylock = 0;
697: }
698:
699: int kerb_db_set_lockmode(mode)
700: int mode;
701: {
702: int old = non_blocking;
703: non_blocking = mode;
704: return old;
705: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.