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