home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / kerberosIV / kdb / krb_dbm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-07  |  16.3 KB  |  710 lines

  1. /*
  2.  * $Source: /usr/src/kerberosIV/kdb/RCS/krb_dbm.c,v $
  3.  * $Author: bostic $ 
  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.11 91/03/07 23:50:29 bostic 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 = 0;
  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.     if (dbm_store(db, key, contents, DBM_REPLACE) == -1) {
  477.         found = -1;
  478.         perror("dbm_store");
  479.         break;
  480.     }
  481. #ifdef DEBUG
  482.     if (kerb_debug & 1) {
  483.         fprintf(stderr, "\n put %s %s\n",
  484.         principal->name, principal->instance);
  485.     }
  486. #endif
  487.     found++;
  488.     principal++;        /* bump to next struct               */
  489.     }
  490.  
  491.     dbm_close(db);
  492.     kerb_dbl_unlock();        /* unlock database */
  493.     return (found);
  494. }
  495.  
  496. static void
  497. encode_princ_key(key, name, instance)
  498.     datum  *key;
  499.     char   *name, *instance;
  500. {
  501.     static char keystring[ANAME_SZ + INST_SZ];
  502.  
  503.     bzero(keystring, ANAME_SZ + INST_SZ);
  504.     strncpy(keystring, name, ANAME_SZ);
  505.     strncpy(&keystring[ANAME_SZ], instance, INST_SZ);
  506.     key->dptr = keystring;
  507.     key->dsize = ANAME_SZ + INST_SZ;
  508. }
  509.  
  510. static void
  511. decode_princ_key(key, name, instance)
  512.     datum  *key;
  513.     char   *name, *instance;
  514. {
  515.     strncpy(name, key->dptr, ANAME_SZ);
  516.     strncpy(instance, key->dptr + ANAME_SZ, INST_SZ);
  517.     name[ANAME_SZ - 1] = '\0';
  518.     instance[INST_SZ - 1] = '\0';
  519. }
  520.  
  521. static void
  522. encode_princ_contents(contents, principal)
  523.     datum  *contents;
  524.     Principal *principal;
  525. {
  526.     contents->dsize = sizeof(*principal);
  527.     contents->dptr = (char *) principal;
  528. }
  529.  
  530. static void
  531. decode_princ_contents(contents, principal)
  532.     datum  *contents;
  533.     Principal *principal;
  534. {
  535.     bcopy(contents->dptr, (char *) principal, sizeof(*principal));
  536. }
  537.  
  538. kerb_db_get_stat(s)
  539.     DB_stat *s;
  540. {
  541.     gettimeofday(×tamp, NULL);
  542.  
  543.  
  544.     s->cpu = 0;
  545.     s->elapsed = 0;
  546.     s->dio = 0;
  547.     s->pfault = 0;
  548.     s->t_stamp = timestamp.tv_sec;
  549.     s->n_retrieve = 0;
  550.     s->n_replace = 0;
  551.     s->n_append = 0;
  552.     s->n_get_stat = 0;
  553.     s->n_put_stat = 0;
  554.     /* update local copy too */
  555. }
  556.  
  557. kerb_db_put_stat(s)
  558.     DB_stat *s;
  559. {
  560. }
  561.  
  562. delta_stat(a, b, c)
  563.     DB_stat *a, *b, *c;
  564. {
  565.     /* c = a - b then b = a for the next time */
  566.  
  567.     c->cpu = a->cpu - b->cpu;
  568.     c->elapsed = a->elapsed - b->elapsed;
  569.     c->dio = a->dio - b->dio;
  570.     c->pfault = a->pfault - b->pfault;
  571.     c->t_stamp = a->t_stamp - b->t_stamp;
  572.     c->n_retrieve = a->n_retrieve - b->n_retrieve;
  573.     c->n_replace = a->n_replace - b->n_replace;
  574.     c->n_append = a->n_append - b->n_append;
  575.     c->n_get_stat = a->n_get_stat - b->n_get_stat;
  576.     c->n_put_stat = a->n_put_stat - b->n_put_stat;
  577.  
  578.     bcopy(a, b, sizeof(DB_stat));
  579.     return;
  580. }
  581.  
  582. /*
  583.  * look up a dba in the data base returns number of dbas found , and
  584.  * whether there were more than requested. 
  585.  */
  586.  
  587. kerb_db_get_dba(dba_name, dba_inst, dba, max, more)
  588.     char   *dba_name;        /* could have wild card */
  589.     char   *dba_inst;        /* could have wild card */
  590.     Dba    *dba;
  591.     unsigned int max;        /* max number of name structs to return */
  592.     int    *more;        /* where there more than 'max' tuples? */
  593.  
  594. {
  595.     *more = 0;
  596.     return (0);
  597. }
  598.  
  599. kerb_db_iterate (func, arg)
  600.     int (*func)();
  601.     char *arg;            /* void *, really */
  602. {
  603.     datum key, contents;
  604.     Principal *principal;
  605.     int code;
  606.     DBM *db;
  607.     
  608.     kerb_db_init();        /* initialize and open the database */
  609.     if ((code = kerb_dbl_lock(KERB_DBL_SHARED)) != 0)
  610.     return code;
  611.  
  612.     db = dbm_open(current_db_name, O_RDONLY, 0600);
  613.  
  614.     for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_next(db, key)) {
  615.     contents = dbm_fetch (db, key);
  616.     /* XXX may not be properly aligned */
  617.     principal = (Principal *) contents.dptr;
  618.     if ((code = (*func)(arg, principal)) != 0)
  619.         return code;
  620.     }
  621.     dbm_close(db);
  622.     kerb_dbl_unlock();
  623.     return 0;
  624. }
  625.  
  626. static int dblfd = -1;
  627. static int mylock = 0;
  628. static int inited = 0;
  629.  
  630. static kerb_dbl_init()
  631. {
  632.     if (!inited) {
  633.     char *filename = gen_dbsuffix (current_db_name, ".ok");
  634.     if ((dblfd = open(filename, 0)) < 0) {
  635.         fprintf(stderr, "kerb_dbl_init: couldn't open %s\n", filename);
  636.         fflush(stderr);
  637.         perror("open");
  638.         exit(1);
  639.     }
  640.     free(filename);
  641.     inited++;
  642.     }
  643.     return (0);
  644. }
  645.  
  646. static void kerb_dbl_fini()
  647. {
  648.     close(dblfd);
  649.     dblfd = -1;
  650.     inited = 0;
  651.     mylock = 0;
  652. }
  653.  
  654. static int kerb_dbl_lock(mode)
  655.     int     mode;
  656. {
  657.     int flock_mode;
  658.     
  659.     if (!inited)
  660.     kerb_dbl_init();
  661.     if (mylock) {        /* Detect lock call when lock already
  662.                  * locked */
  663.     fprintf(stderr, "Kerberos locking error (mylock)\n");
  664.     fflush(stderr);
  665.     exit(1);
  666.     }
  667.     switch (mode) {
  668.     case KERB_DBL_EXCLUSIVE:
  669.     flock_mode = LOCK_EX;
  670.     break;
  671.     case KERB_DBL_SHARED:
  672.     flock_mode = LOCK_SH;
  673.     break;
  674.     default:
  675.     fprintf(stderr, "invalid lock mode %d\n", mode);
  676.     abort();
  677.     }
  678.     if (non_blocking)
  679.     flock_mode |= LOCK_NB;
  680.     
  681.     if (flock(dblfd, flock_mode) < 0) 
  682.     return errno;
  683.     mylock++;
  684.     return 0;
  685. }
  686.  
  687. static void kerb_dbl_unlock()
  688. {
  689.     if (!mylock) {        /* lock already unlocked */
  690.     fprintf(stderr, "Kerberos database lock not locked when unlocking.\n");
  691.     fflush(stderr);
  692.     exit(1);
  693.     }
  694.     if (flock(dblfd, LOCK_UN) < 0) {
  695.     fprintf(stderr, "Kerberos database lock error. (unlocking)\n");
  696.     fflush(stderr);
  697.     perror("flock");
  698.     exit(1);
  699.     }
  700.     mylock = 0;
  701. }
  702.  
  703. int kerb_db_set_lockmode(mode)
  704.     int mode;
  705. {
  706.     int old = non_blocking;
  707.     non_blocking = mode;
  708.     return old;
  709. }
  710.