"Fossies" - the Fresh Open Source Software Archive

Member "krb5-1.18/src/plugins/kdb/db2/adb_openclose.c" (12 Feb 2020, 10783 Bytes) of package /linux/misc/krb5-1.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "adb_openclose.c" see the Fossies "Dox" file reference documentation.

    1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
    2 /*
    3  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
    4  *
    5  * $Header$
    6  */
    7 
    8 #include        <k5-int.h>
    9 #include        <sys/file.h>
   10 #include        <fcntl.h>
   11 #include        <unistd.h>
   12 #include        "policy_db.h"
   13 #include        <stdlib.h>
   14 #include        <db.h>
   15 
   16 struct _locklist {
   17     osa_adb_lock_ent lockinfo;
   18     struct _locklist *next;
   19 };
   20 
   21 krb5_error_code
   22 osa_adb_create_db(char *filename, char *lockfilename, int magic)
   23 {
   24     int lf;
   25     DB *db;
   26     BTREEINFO btinfo;
   27 
   28     memset(&btinfo, 0, sizeof(btinfo));
   29     btinfo.flags = 0;
   30     btinfo.cachesize = 0;
   31     btinfo.psize = 4096;
   32     btinfo.lorder = 0;
   33     btinfo.minkeypage = 0;
   34     btinfo.compare = NULL;
   35     btinfo.prefix = NULL;
   36     db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_BTREE, &btinfo);
   37     if (db == NULL)
   38         return errno;
   39     if (db->close(db) < 0)
   40         return errno;
   41 
   42     /* only create the lock file if we successfully created the db */
   43     lf = THREEPARAMOPEN(lockfilename, O_RDWR | O_CREAT | O_EXCL, 0600);
   44     if (lf == -1)
   45         return errno;
   46     (void) close(lf);
   47 
   48     return OSA_ADB_OK;
   49 }
   50 
   51 krb5_error_code
   52 osa_adb_destroy_db(char *filename, char *lockfilename, int magic)
   53 {
   54     /* the admin databases do not contain security-critical data */
   55     if (unlink(filename) < 0 ||
   56         unlink(lockfilename) < 0)
   57         return errno;
   58     return OSA_ADB_OK;
   59 }
   60 
   61 krb5_error_code
   62 osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfilename,
   63                 int magic)
   64 {
   65     osa_adb_db_t db;
   66     static struct _locklist *locklist = NULL;
   67     struct _locklist *lockp;
   68     krb5_error_code code;
   69 
   70     if (dbp == NULL || filename == NULL)
   71         return EINVAL;
   72 
   73     db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent));
   74     if (db == NULL)
   75         return ENOMEM;
   76 
   77     memset(db, 0, sizeof(*db));
   78     db->info.hash = NULL;
   79     db->info.bsize = 256;
   80     db->info.ffactor = 8;
   81     db->info.nelem = 25000;
   82     db->info.lorder = 0;
   83 
   84     db->btinfo.flags = 0;
   85     db->btinfo.cachesize = 0;
   86     db->btinfo.psize = 4096;
   87     db->btinfo.lorder = 0;
   88     db->btinfo.minkeypage = 0;
   89     db->btinfo.compare = NULL;
   90     db->btinfo.prefix = NULL;
   91     /*
   92      * A process is allowed to open the same database multiple times
   93      * and access it via different handles.  If the handles use
   94      * distinct lockinfo structures, things get confused: lock(A),
   95      * lock(B), release(B) will result in the kernel unlocking the
   96      * lock file but handle A will still think the file is locked.
   97      * Therefore, all handles using the same lock file must share a
   98      * single lockinfo structure.
   99      *
  100      * It is not sufficient to have a single lockinfo structure,
  101      * however, because a single process may also wish to open
  102      * multiple different databases simultaneously, with different
  103      * lock files.  This code used to use a single static lockinfo
  104      * structure, which means that the second database opened used
  105      * the first database's lock file.  This was Bad.
  106      *
  107      * We now maintain a linked list of lockinfo structures, keyed by
  108      * lockfilename.  An entry is added when this function is called
  109      * with a new lockfilename, and all subsequent calls with that
  110      * lockfilename use the existing entry, updating the refcnt.
  111      * When the database is closed with fini_db(), the refcnt is
  112      * decremented, and when it is zero the lockinfo structure is
  113      * freed and reset.  The entry in the linked list, however, is
  114      * never removed; it will just be reinitialized the next time
  115      * init_db is called with the right lockfilename.
  116      */
  117 
  118     /* find or create the lockinfo structure for lockfilename */
  119     lockp = locklist;
  120     while (lockp) {
  121         if (strcmp(lockp->lockinfo.filename, lockfilename) == 0)
  122             break;
  123         else
  124             lockp = lockp->next;
  125     }
  126     if (lockp == NULL) {
  127         /* doesn't exist, create it, add to list */
  128         lockp = (struct _locklist *) malloc(sizeof(*lockp));
  129         if (lockp == NULL) {
  130             free(db);
  131             return ENOMEM;
  132         }
  133         memset(lockp, 0, sizeof(*lockp));
  134         lockp->lockinfo.filename = strdup(lockfilename);
  135         if (lockp->lockinfo.filename == NULL) {
  136             free(lockp);
  137             free(db);
  138             return ENOMEM;
  139         }
  140         lockp->next = locklist;
  141         locklist = lockp;
  142     }
  143 
  144     /* now initialize lockp->lockinfo if necessary */
  145     if (lockp->lockinfo.lockfile == NULL) {
  146         if ((code = krb5int_init_context_kdc(&lockp->lockinfo.context))) {
  147             free(db);
  148             return((krb5_error_code) code);
  149         }
  150 
  151         /*
  152          * needs be open read/write so that write locking can work with
  153          * POSIX systems
  154          */
  155         if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) {
  156             /*
  157              * maybe someone took away write permission so we could only
  158              * get shared locks?
  159              */
  160             if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r"))
  161                 == NULL) {
  162                 free(db);
  163                 return OSA_ADB_NOLOCKFILE;
  164             }
  165         }
  166         set_cloexec_file(lockp->lockinfo.lockfile);
  167         lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0;
  168     }
  169 
  170     /* lockp is set, lockinfo is initialized, update the reference count */
  171     db->lock = &lockp->lockinfo;
  172     db->lock->refcnt++;
  173 
  174     db->opencnt = 0;
  175     db->filename = strdup(filename);
  176     db->magic = magic;
  177 
  178     *dbp = db;
  179 
  180     return OSA_ADB_OK;
  181 }
  182 
  183 krb5_error_code
  184 osa_adb_fini_db(osa_adb_db_t db, int magic)
  185 {
  186     if (db->magic != magic)
  187         return EINVAL;
  188     if (db->lock->refcnt == 0) {
  189         /* barry says this can't happen */
  190         return OSA_ADB_FAILURE;
  191     } else {
  192         db->lock->refcnt--;
  193     }
  194 
  195     if (db->lock->refcnt == 0) {
  196         /*
  197          * Don't free db->lock->filename, it is used as a key to
  198          * find the lockinfo entry in the linked list.  If the
  199          * lockfile doesn't exist, we must be closing the database
  200          * after trashing it.  This has to be allowed, so don't
  201          * generate an error.
  202          */
  203         if (db->lock->lockmode != KRB5_DB_LOCKMODE_PERMANENT)
  204             (void) fclose(db->lock->lockfile);
  205         db->lock->lockfile = NULL;
  206         krb5_free_context(db->lock->context);
  207     }
  208 
  209     db->magic = 0;
  210     free(db->filename);
  211     free(db);
  212     return OSA_ADB_OK;
  213 }
  214 
  215 krb5_error_code
  216 osa_adb_get_lock(osa_adb_db_t db, int mode)
  217 {
  218     int perm, krb5_mode, ret = 0;
  219 
  220     if (db->lock->lockmode >= mode) {
  221         /* No need to upgrade lock, just incr refcnt and return */
  222         db->lock->lockcnt++;
  223         return(OSA_ADB_OK);
  224     }
  225 
  226     perm = 0;
  227     switch (mode) {
  228     case KRB5_DB_LOCKMODE_PERMANENT:
  229         perm = 1;
  230     case KRB5_DB_LOCKMODE_EXCLUSIVE:
  231         krb5_mode = KRB5_LOCKMODE_EXCLUSIVE;
  232         break;
  233     case KRB5_DB_LOCKMODE_SHARED:
  234         krb5_mode = KRB5_LOCKMODE_SHARED;
  235         break;
  236     default:
  237         return(EINVAL);
  238     }
  239 
  240     ret = krb5_lock_file(db->lock->context, fileno(db->lock->lockfile),
  241                          krb5_mode);
  242     if (ret == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
  243         return OSA_ADB_NOEXCL_PERM;
  244     else if (ret == EACCES || ret == EAGAIN || ret == EWOULDBLOCK)
  245         return OSA_ADB_CANTLOCK_DB;
  246     else if (ret != 0)
  247         return ret;
  248 
  249     /*
  250      * If the file no longer exists, someone acquired a permanent
  251      * lock.  If that process terminates its exclusive lock is lost,
  252      * but if we already had the file open we can (probably) lock it
  253      * even though it has been unlinked.  So we need to insist that
  254      * it exist.
  255      */
  256     if (access(db->lock->filename, F_OK) < 0) {
  257         (void) krb5_lock_file(db->lock->context,
  258                               fileno(db->lock->lockfile),
  259                               KRB5_LOCKMODE_UNLOCK);
  260         return OSA_ADB_NOLOCKFILE;
  261     }
  262 
  263     /* we have the shared/exclusive lock */
  264 
  265     if (perm) {
  266         if (unlink(db->lock->filename) < 0) {
  267             /* somehow we can't delete the file, but we already */
  268             /* have the lock, so release it and return */
  269 
  270             ret = errno;
  271             (void) krb5_lock_file(db->lock->context,
  272                                   fileno(db->lock->lockfile),
  273                                   KRB5_LOCKMODE_UNLOCK);
  274 
  275             /* maybe we should return CANTLOCK_DB.. but that would */
  276             /* look just like the db was already locked */
  277             return ret;
  278         }
  279 
  280         /* this releases our exclusive lock.. which is okay because */
  281         /* now no one else can get one either */
  282         (void) fclose(db->lock->lockfile);
  283     }
  284 
  285     db->lock->lockmode = mode;
  286     db->lock->lockcnt++;
  287     return OSA_ADB_OK;
  288 }
  289 
  290 krb5_error_code
  291 osa_adb_release_lock(osa_adb_db_t db)
  292 {
  293     int ret, fd;
  294 
  295     if (!db->lock->lockcnt)            /* lock already unlocked */
  296         return OSA_ADB_NOTLOCKED;
  297 
  298     if (--db->lock->lockcnt == 0) {
  299         if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) {
  300             /* now we need to create the file since it does not exist */
  301             fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL,
  302                                 0600);
  303             if (fd < 0)
  304                 return OSA_ADB_NOLOCKFILE;
  305             set_cloexec_fd(fd);
  306             if ((db->lock->lockfile = fdopen(fd, "w+")) == NULL)
  307                 return OSA_ADB_NOLOCKFILE;
  308         } else if ((ret = krb5_lock_file(db->lock->context,
  309                                          fileno(db->lock->lockfile),
  310                                          KRB5_LOCKMODE_UNLOCK)))
  311             return ret;
  312 
  313         db->lock->lockmode = 0;
  314     }
  315     return OSA_ADB_OK;
  316 }
  317 
  318 krb5_error_code
  319 osa_adb_open_and_lock(osa_adb_princ_t db, int locktype)
  320 {
  321     int ret;
  322 
  323     ret = osa_adb_get_lock(db, locktype);
  324     if (ret != OSA_ADB_OK)
  325         return ret;
  326     if (db->opencnt)
  327         goto open_ok;
  328 
  329     db->db = dbopen(db->filename, O_RDWR, 0600, DB_BTREE, &db->btinfo);
  330     if (db->db != NULL)
  331         goto open_ok;
  332     if (IS_EFTYPE(errno)) {
  333         db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info);
  334         if (db->db != NULL)
  335             goto open_ok;
  336     } else {
  337         (void) osa_adb_release_lock(db);
  338         if (errno == EINVAL)
  339             return OSA_ADB_BAD_DB;
  340         return errno;
  341     }
  342 open_ok:
  343     db->opencnt++;
  344     return OSA_ADB_OK;
  345 }
  346 
  347 krb5_error_code
  348 osa_adb_close_and_unlock(osa_adb_princ_t db)
  349 {
  350     if (--db->opencnt)
  351         return osa_adb_release_lock(db);
  352     if(db->db != NULL && db->db->close(db->db) == -1) {
  353         (void) osa_adb_release_lock(db);
  354         return OSA_ADB_FAILURE;
  355     }
  356 
  357     db->db = NULL;
  358 
  359     return(osa_adb_release_lock(db));
  360 }