📄 krb_dbm.c
字号:
/* * $Source: /usr/src/kerberosIV/kdb/RCS/krb_dbm.c,v $ * $Author: sklower $ * * Copyright 1988 by the Massachusetts Institute of Technology. * * For copying and distribution information, please see the file * <mit-copyright.h>. */#ifndef lintstatic char rcsid_krb_dbm_c[] ="$Header: /usr/src/kerberosIV/kdb/RCS/krb_dbm.c,v 4.12 92/12/01 11:52:19 sklower Exp $";#endif lint#include <sys/types.h>#include <sys/uio.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/resource.h>#include <sys/errno.h>#include <sys/file.h>#include <netinet/in.h>#include <mit-copyright.h>#include <stdio.h>#include <string.h>#include <des.h>#include <krb.h>#include <krb_db.h>#include <ndbm.h>#define KERB_DB_MAX_RETRY 5#ifdef DEBUGextern int debug;extern long kerb_debug;extern char *progname;#endifextern char *malloc();extern int errno;static init = 0;static char default_db_name[] = DBM_FILE;static char *current_db_name = default_db_name;static void encode_princ_key(), decode_princ_key();static void encode_princ_contents(), decode_princ_contents();static void kerb_dbl_fini();static int kerb_dbl_lock();static void kerb_dbl_unlock();static struct timeval timestamp;/* current time of request */static int non_blocking = 0;/* * This module contains all of the code which directly interfaces to * the underlying representation of the Kerberos database; this * implementation uses a DBM or NDBM indexed "file" (actually * implemented as two separate files) to store the relations, plus a * third file as a semaphore to allow the database to be replaced out * from underneath the KDC server. *//* * Locking: * * There are two distinct locking protocols used. One is designed to * lock against processes (the admin_server, for one) which make * incremental changes to the database; the other is designed to lock * against utilities (kdb_util, kpropd) which replace the entire * database in one fell swoop. * * The first locking protocol is implemented using flock() in the * krb_dbl_lock() and krb_dbl_unlock routines. * * The second locking protocol is necessary because DBM "files" are * actually implemented as two separate files, and it is impossible to * atomically rename two files simultaneously. It assumes that the * database is replaced only very infrequently in comparison to the time * needed to do a database read operation. * * A third file is used as a "version" semaphore; the modification * time of this file is the "version number" of the database. * At the start of a read operation, the reader checks the version * number; at the end of the read operation, it checks again. If the * version number changed, or if the semaphore was nonexistant at * either time, the reader sleeps for a second to let things * stabilize, and then tries again; if it does not succeed after * KERB_DB_MAX_RETRY attempts, it gives up. * * On update, the semaphore file is deleted (if it exists) before any * update takes place; at the end of the update, it is replaced, with * a version number strictly greater than the version number which * existed at the start of the update. * * If the system crashes in the middle of an update, the semaphore * file is not automatically created on reboot; this is a feature, not * a bug, since the database may be inconsistant. Note that the * absence of a semaphore file does not prevent another _update_ from * taking place later. Database replacements take place automatically * only on slave servers; a crash in the middle of an update will be * fixed by the next slave propagation. A crash in the middle of an * update on the master would be somewhat more serious, but this would * likely be noticed by an administrator, who could fix the problem and * retry the operation. *//* Macros to convert ndbm names to dbm names. * Note that dbm_nextkey() cannot be simply converted using a macro, since * it is invoked giving the database, and nextkey() needs the previous key. * * Instead, all routines call "dbm_next" instead. */#define dbm_next(db,key) dbm_nextkey(db)/* * Utility routine: generate name of database file. */static char *gen_dbsuffix(db_name, sfx) char *db_name; char *sfx;{ char *dbsuffix; if (sfx == NULL) sfx = ".ok"; dbsuffix = malloc (strlen(db_name) + strlen(sfx) + 1); strcpy(dbsuffix, db_name); strcat(dbsuffix, sfx); return dbsuffix;}/* * initialization for data base routines. */kerb_db_init(){ init = 1; return (0);}/* * gracefully shut down database--must be called by ANY program that does * a kerb_db_init */kerb_db_fini(){}/* * Set the "name" of the current database to some alternate value. * * Passing a null pointer as "name" will set back to the default. * If the alternate database doesn't exist, nothing is changed. */kerb_db_set_name(name) char *name;{ DBM *db; if (name == NULL) name = default_db_name; db = dbm_open(name, 0, 0); if (db == NULL) return errno; dbm_close(db); kerb_dbl_fini(); current_db_name = name; return 0;}/* * Return the last modification time of the database. */long kerb_get_db_age(){ struct stat st; char *okname; long age; okname = gen_dbsuffix(current_db_name, ".ok"); if (stat (okname, &st) < 0) age = 0; else age = st.st_mtime; free (okname); return age;}/* * Remove the semaphore file; indicates that database is currently * under renovation. * * This is only for use when moving the database out from underneath * the server (for example, during slave updates). */static long kerb_start_update(db_name) char *db_name;{ char *okname = gen_dbsuffix(db_name, ".ok"); long age = kerb_get_db_age(); if (unlink(okname) < 0 && errno != ENOENT) { age = -1; } free (okname); return age;}static long kerb_end_update(db_name, age) char *db_name; long age;{ int fd; int retval = 0; char *new_okname = gen_dbsuffix(db_name, ".ok#"); char *okname = gen_dbsuffix(db_name, ".ok"); fd = open (new_okname, O_CREAT|O_RDWR|O_TRUNC, 0600); if (fd < 0) retval = errno; else { struct stat st; struct timeval tv[2]; /* make sure that semaphore is "after" previous value. */ if (fstat (fd, &st) == 0 && st.st_mtime <= age) { tv[0].tv_sec = st.st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = age; tv[1].tv_usec = 0; /* set times.. */ utimes (new_okname, tv); fsync(fd); } close(fd); if (rename (new_okname, okname) < 0) retval = errno; } free (new_okname); free (okname); return retval;}static long kerb_start_read(){ return kerb_get_db_age();}static long kerb_end_read(age) u_long age;{ if (kerb_get_db_age() != age || age == -1) { return -1; } return 0;}/* * Create the database, assuming it's not there. */kerb_db_create(db_name) char *db_name;{ char *okname = gen_dbsuffix(db_name, ".ok"); int fd; register int ret = 0; DBM *db; db = dbm_open(db_name, O_RDWR|O_CREAT|O_EXCL, 0600); if (db == NULL) ret = errno; else dbm_close(db); if (ret == 0) { fd = open (okname, O_CREAT|O_RDWR|O_TRUNC, 0600); if (fd < 0) ret = errno; close(fd); } return ret;}/* * "Atomically" rename the database in a way that locks out read * access in the middle of the rename. * * Not perfect; if we crash in the middle of an update, we don't * necessarily know to complete the transaction the rename, but... */kerb_db_rename(from, to) char *from; char *to;{ char *fromdir = gen_dbsuffix (from, ".db"); char *todir = gen_dbsuffix (to, ".db"); char *fromok = gen_dbsuffix(from, ".ok"); long trans = kerb_start_update(to); int ok = 0; if (rename (fromdir, todir) == 0) { (void) unlink (fromok); ok = 1; } free (fromok); free (fromdir); free (todir); if (ok) return kerb_end_update(to, trans); else return -1;}/* * look up a principal in the data base returns number of principals * found , and whether there were more than requested. */kerb_db_get_principal(name, inst, principal, max, more) char *name; /* could have wild card */ char *inst; /* could have wild card */ Principal *principal; unsigned int max; /* max number of name structs to return */ int *more; /* where there more than 'max' tuples? */{ int found = 0, code; extern int errorproc(); int wildp, wildi; datum key, contents; char testname[ANAME_SZ], testinst[INST_SZ]; u_long trans; int try; DBM *db; if (!init) kerb_db_init(); /* initialize database routines */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -