Ejemplo n.º 1
0
/* Child process: acquire and release a write lock on the KDB, synchronized
 * with parent. */
static int
locker(int inpipe, int outpipe, char **db_args)
{
    krb5_error_code retval;
    unsigned char c = '\0';
    krb5_context ctx;

    retval = krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_KDC, &ctx);
    if (retval)
        goto cleanup;

    retval = krb5_db_open(ctx, db_args,
                          KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
    if (retval)
        goto cleanup;

    if (syncpair_wr("first", inpipe, outpipe, &c) < 0) {
        retval = errno;
        goto cleanup;
    }
    printf("locker: acquiring lock...\n");
    retval = krb5_db_lock(ctx, KRB5_DB_LOCKMODE_EXCLUSIVE);
    if (retval)
        goto cleanup;
    printf("locker: acquired lock\n");
    if (syncpair_wr("second", inpipe, outpipe, &c) < 0) {
        retval = errno;
        goto cleanup;
    }
    krb5_db_unlock(ctx);
    printf("locker: released lock\n");
    printf("locker: writing final sync byte\n");
    if (write(outpipe, &c, 1) < 0) {
        retval = errno;
        goto cleanup;
    }
    retval = krb5_db_fini(ctx);
cleanup:
    if (retval)
        com_err("locker", retval, "");

    krb5_free_context(ctx);
    exit(retval != 0);
}
Ejemplo n.º 2
0
/* Used by the slave to update its hash db from the incr update log. */
krb5_error_code
ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
{
    krb5_db_entry *entry = NULL;
    kdb_incr_update_t *upd = NULL, *fupd;
    int i, no_of_updates;
    krb5_error_code retval;
    krb5_principal dbprinc;
    char *dbprincstr;
    kdb_log_context *log_ctx;
    kdb_hlog_t *ulog = NULL;

    INIT_ULOG(context);

    /* Lock the DB before the ulog to avoid deadlock. */
    retval = krb5_db_open(context, db_args,
                          KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
    if (retval)
        return retval;
    retval = krb5_db_lock(context, KRB5_DB_LOCKMODE_EXCLUSIVE);
    if (retval)
        return retval;
    retval = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
    if (retval) {
        krb5_db_unlock(context);
        return retval;
    }

    no_of_updates = incr_ret->updates.kdb_ulog_t_len;
    upd = incr_ret->updates.kdb_ulog_t_val;
    fupd = upd;

    for (i = 0; i < no_of_updates; i++) {
        if (!upd->kdb_commit)
            continue;

        /* If (unexpectedly) this update does not follow the last one we
         * stored, discard any previous ulog state. */
        if (ulog->kdb_num != 0 && upd->kdb_entry_sno != ulog->kdb_last_sno + 1)
            reset_header(ulog);

        if (upd->kdb_deleted) {
            dbprincstr = k5memdup0(upd->kdb_princ_name.utf8str_t_val,
                                   upd->kdb_princ_name.utf8str_t_len, &retval);
            if (dbprincstr == NULL)
                goto cleanup;

            retval = krb5_parse_name(context, dbprincstr, &dbprinc);
            free(dbprincstr);
            if (retval)
                goto cleanup;

            retval = krb5int_delete_principal_no_log(context, dbprinc);
            krb5_free_principal(context, dbprinc);
            if (retval == KRB5_KDB_NOENTRY)
                retval = 0;
            if (retval)
                goto cleanup;
        } else {
            entry = k5alloc(sizeof(krb5_db_entry), &retval);
            if (entry == NULL)
                goto cleanup;

            retval = ulog_conv_2dbentry(context, &entry, upd);
            if (retval)
                goto cleanup;

            retval = krb5int_put_principal_no_log(context, entry);
            krb5_db_free_principal(context, entry);
            if (retval)
                goto cleanup;
        }

        retval = store_update(log_ctx, upd);
        if (retval)
            goto cleanup;

        upd++;
    }

cleanup:
    if (fupd)
        ulog_free_entries(fupd, no_of_updates);
    if (retval) {
        reset_header(ulog);
        sync_header(ulog);
    }
    unlock_ulog(context);
    krb5_db_unlock(context);
    return retval;
}
Ejemplo n.º 3
0
void
kdb5_update_princ_encryption(int argc, char *argv[])
{
    struct update_enc_mkvno data = { 0 };
    char *name_pattern = NULL;
    int force = 0;
    int optchar;
    krb5_error_code retval;
    krb5_actkvno_node *actkvno_list = 0;
    krb5_db_entry *master_entry;
    char *mkey_fullname = 0;
#ifdef BSD_REGEXPS
    char *msg;
#endif
    char *regexp = NULL;
    krb5_keyblock *act_mkey;
    krb5_keylist_node *master_keylist = krb5_db_mkey_list_alias(util_context);

    while ((optchar = getopt(argc, argv, "fnv")) != -1) {
        switch (optchar) {
        case 'f':
            force = 1;
            break;
        case 'n':
            data.dry_run = 1;
            break;
        case 'v':
            data.verbose = 1;
            break;
        case '?':
        case ':':
        default:
            usage();
        }
    }
    if (argv[optind] != NULL) {
        name_pattern = argv[optind];
        if (argv[optind+1] != NULL)
            usage();
    }

    retval = krb5_unparse_name(util_context, master_princ, &mkey_fullname);
    if (retval) {
        com_err(progname, retval, _("while formatting master principal name"));
        exit_status++;
        goto cleanup;
    }

    if (master_keylist == NULL) {
        com_err(progname, retval, _("master keylist not initialized"));
        exit_status++;
        goto cleanup;
    }

    /* The glob_to_regexp code only cares if the "realm" parameter is
       NULL or not; the string data is irrelevant.  */
    if (name_pattern == NULL)
        name_pattern = "*";
    if (glob_to_regexp(name_pattern, "hi", &regexp) != 0) {
        com_err(progname, ENOMEM,
                _("converting glob pattern '%s' to regular expression"),
                name_pattern);
        exit_status++;
        goto cleanup;
    }

    if (
#ifdef SOLARIS_REGEXPS
        ((data.expbuf = compile(regexp, NULL, NULL)) == NULL)
#endif
#ifdef POSIX_REGEXPS
        ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0)
#endif
#ifdef BSD_REGEXPS
        ((msg = (char *) re_comp(regexp)) != NULL)
#endif
    ) {
        /* XXX syslog msg or regerr(regerrno) */
        com_err(progname, 0, _("error compiling converted regexp '%s'"),
                regexp);
        exit_status++;
        goto cleanup;
    }

    retval = krb5_db_get_principal(util_context, master_princ, 0,
                                   &master_entry);
    if (retval != 0) {
        com_err(progname, retval, _("while getting master key principal %s"),
                mkey_fullname);
        exit_status++;
        goto cleanup;
    }

    retval = krb5_dbe_lookup_actkvno(util_context, master_entry, &actkvno_list);
    if (retval != 0) {
        com_err(progname, retval, _("while looking up active kvno list"));
        exit_status++;
        goto cleanup;
    }

    retval = krb5_dbe_find_act_mkey(util_context, actkvno_list, &new_mkvno,
                                    &act_mkey);
    if (retval) {
        com_err(progname, retval, _("while looking up active master key"));
        exit_status++;
        goto cleanup;
    }
    new_master_keyblock = *act_mkey;

    if (!force &&
        !data.dry_run &&
        !are_you_sure(_("Re-encrypt all keys not using master key vno %u?"),
                      new_mkvno)) {
        printf(_("OK, doing nothing.\n"));
        exit_status++;
        goto cleanup;
    }
    if (data.verbose) {
        if (data.dry_run) {
            printf(_("Principals whose keys WOULD BE re-encrypted to master "
                     "key vno %u:\n"), new_mkvno);
        } else {
            printf(_("Principals whose keys are being re-encrypted to master "
                     "key vno %u if necessary:\n"), new_mkvno);
        }
    }

    if (!data.dry_run) {
        /* Grab a write lock so we don't have to upgrade to a write lock and
         * reopen the DB while iterating. */
        retval = krb5_db_lock(util_context, KRB5_DB_LOCKMODE_EXCLUSIVE);
        if (retval != 0 && retval != KRB5_PLUGIN_OP_NOTSUPP) {
            com_err(progname, retval, _("trying to lock database"));
            exit_status++;
        }
    }

    retval = krb5_db_iterate(util_context, name_pattern,
                             update_princ_encryption_1, &data);
    /* If exit_status is set, then update_princ_encryption_1 already
       printed a message.  */
    if (retval != 0 && exit_status == 0) {
        com_err(progname, retval, _("trying to process principal database"));
        exit_status++;
    }
    if (!data.dry_run)
        (void)krb5_db_unlock(util_context);
    (void) krb5_db_fini(util_context);
    if (data.dry_run) {
        printf(_("%u principals processed: %u would be updated, %u already "
                 "current\n"),
               data.re_match_count, data.updated, data.already_current);
    } else {
        printf(_("%u principals processed: %u updated, %u already current\n"),
               data.re_match_count, data.updated, data.already_current);
    }

cleanup:
    free(regexp);
    memset(&new_master_keyblock, 0, sizeof(new_master_keyblock));
    krb5_free_unparsed_name(util_context, mkey_fullname);
    krb5_dbe_free_actkvno_list(util_context, actkvno_list);
}
Ejemplo n.º 4
0
/* Get the last set of updates seen, (last+1) to n is returned. */
krb5_error_code
ulog_get_entries(krb5_context context, kdb_last_t last,
                 kdb_incr_result_t *ulog_handle)
{
    XDR xdrs;
    kdb_ent_header_t *indx_log;
    kdb_incr_update_t *upd;
    unsigned int indx, count;
    uint32_t sno;
    krb5_error_code retval;
    kdb_log_context *log_ctx;
    kdb_hlog_t *ulog = NULL;
    uint32_t ulogentries;

    INIT_ULOG(context);
    ulogentries = log_ctx->ulogentries;

    retval = ulog_lock(context, KRB5_LOCKMODE_SHARED);
    if (retval)
        return retval;

    /* Check to make sure we don't have a corrupt ulog first. */
    if (ulog->kdb_state == KDB_CORRUPT) {
        ulog_handle->ret = UPDATE_ERROR;
        (void)ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
        return KRB5_LOG_CORRUPT;
    }

    /*
     * We need to lock out other processes here, such as kadmin.local, since we
     * are looking at the last_sno and looking up updates.  So we can share
     * with other readers.
     */
    retval = krb5_db_lock(context, KRB5_LOCKMODE_SHARED);
    if (retval) {
        (void)ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
        return retval;
    }

    /* If we have the same sno and timestamp, return a nil update.  If a
     * different timestamp, the sno was reused and we need a full resync. */
    if (last.last_sno == ulog->kdb_last_sno) {
        ulog_handle->ret = time_equal(&last.last_time, &ulog->kdb_last_time) ?
            UPDATE_NIL : UPDATE_FULL_RESYNC_NEEDED;
        goto cleanup;
    }

    /* We may have overflowed the update log or shrunk the log, or the client
     * may have created its ulog. */
    if (last.last_sno > ulog->kdb_last_sno ||
        last.last_sno < ulog->kdb_first_sno) {
        ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
        ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
        goto cleanup;
    }

    sno = last.last_sno;
    indx = (sno - 1) % ulogentries;
    indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);

    if (!time_equal(&indx_log->kdb_time, &last.last_time)) {
        /* We have time stamp mismatch or we no longer have the slave's last
         * sno, so we brute force it. */
        ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
        goto cleanup;
    }

    count = ulog->kdb_last_sno - sno;
    upd = calloc(count, sizeof(kdb_incr_update_t));
    if (upd == NULL) {
        ulog_handle->ret = UPDATE_ERROR;
        retval = ENOMEM;
        goto cleanup;
    }
    ulog_handle->updates.kdb_ulog_t_val = upd;

    for (; sno < ulog->kdb_last_sno; sno++) {
        indx = sno % ulogentries;
        indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);

        memset(upd, 0, sizeof(kdb_incr_update_t));
        xdrmem_create(&xdrs, (char *)indx_log->entry_data,
                      indx_log->kdb_entry_size, XDR_DECODE);
        if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
            ulog_handle->ret = UPDATE_ERROR;
            retval = KRB5_LOG_CONV;
            goto cleanup;
        }

        /* Mark commitment since we didn't want to decode and encode the incr
         * update record the first time. */
        upd->kdb_commit = indx_log->kdb_commit;
        upd++;
    }

    ulog_handle->updates.kdb_ulog_t_len = count;

    ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
    ulog_handle->lastentry.last_time.seconds = ulog->kdb_last_time.seconds;
    ulog_handle->lastentry.last_time.useconds = ulog->kdb_last_time.useconds;
    ulog_handle->ret = UPDATE_OK;

cleanup:
    (void)ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
    (void)krb5_db_unlock(context);
    return retval;
}
Ejemplo n.º 5
0
/*
 * Get the last set of updates seen, (last+1) to n is returned.
 */
krb5_error_code
ulog_get_entries(krb5_context context,          /* input - krb5 lib config */
                 kdb_last_t last,               /* input - slave's last sno */
                 kdb_incr_result_t *ulog_handle) /* output - incr result for slave */
{
    XDR                 xdrs;
    kdb_ent_header_t    *indx_log;
    kdb_incr_update_t   *upd;
    uint_t              indx, count, tdiff;
    uint32_t            sno;
    krb5_error_code     retval;
    struct timeval      timestamp;
    kdb_log_context     *log_ctx;
    kdb_hlog_t          *ulog = NULL;
    uint32_t            ulogentries;

    INIT_ULOG(context);
    ulogentries = log_ctx->ulogentries;

    retval = ulog_lock(context, KRB5_LOCKMODE_SHARED);
    if (retval)
        return retval;

    /*
     * Check to make sure we don't have a corrupt ulog first.
     */
    if (ulog->kdb_state == KDB_CORRUPT) {
        ulog_handle->ret = UPDATE_ERROR;
        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
        return (KRB5_LOG_CORRUPT);
    }

    gettimeofday(&timestamp, NULL);

    tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;
    if (tdiff <= ULOG_IDLE_TIME) {
        ulog_handle->ret = UPDATE_BUSY;
        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
        return (0);
    }

    /*
     * We need to lock out other processes here, such as kadmin.local,
     * since we are looking at the last_sno and looking up updates.  So
     * we can share with other readers.
     */
    retval = krb5_db_lock(context, KRB5_LOCKMODE_SHARED);
    if (retval) {
        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
        return (retval);
    }

    /*
     * We may have overflowed the update log or we shrunk the log, or
     * the client's ulog has just been created.
     */
    if ((last.last_sno > ulog->kdb_last_sno) ||
        (last.last_sno < ulog->kdb_first_sno) ||
        (last.last_sno == 0)) {
        ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
        (void) krb5_db_unlock(context);
        ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
        return (0);
    } else if (last.last_sno <= ulog->kdb_last_sno) {
        sno = last.last_sno;

        indx = (sno - 1) % ulogentries;

        indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);

        /*
         * Validate the time stamp just to make sure it was the same sno
         */
        if ((indx_log->kdb_time.seconds == last.last_time.seconds) &&
            (indx_log->kdb_time.useconds == last.last_time.useconds)) {

            /*
             * If we have the same sno we return success
             */
            if (last.last_sno == ulog->kdb_last_sno) {
                (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
                (void) krb5_db_unlock(context);
                ulog_handle->ret = UPDATE_NIL;
                return (0);
            }

            count = ulog->kdb_last_sno - sno;

            ulog_handle->updates.kdb_ulog_t_val =
                (kdb_incr_update_t *)malloc(
                    sizeof (kdb_incr_update_t) * count);

            upd = ulog_handle->updates.kdb_ulog_t_val;

            if (upd == NULL) {
                (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
                (void) krb5_db_unlock(context);
                ulog_handle->ret = UPDATE_ERROR;
                return (errno);
            }

            while (sno < ulog->kdb_last_sno) {
                indx = sno % ulogentries;

                indx_log = (kdb_ent_header_t *)
                    INDEX(ulog, indx);

                (void) memset(upd, 0,
                              sizeof (kdb_incr_update_t));
                xdrmem_create(&xdrs,
                              (char *)indx_log->entry_data,
                              indx_log->kdb_entry_size, XDR_DECODE);
                if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
                    (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
                    (void) krb5_db_unlock(context);
                    ulog_handle->ret = UPDATE_ERROR;
                    return (KRB5_LOG_CONV);
                }
                /*
                 * Mark commitment since we didn't
                 * want to decode and encode the
                 * incr update record the first time.
                 */
                upd->kdb_commit = indx_log->kdb_commit;

                upd++;
                sno++;
            } /* while */

            ulog_handle->updates.kdb_ulog_t_len = count;

            ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
            ulog_handle->lastentry.last_time.seconds =
                ulog->kdb_last_time.seconds;
            ulog_handle->lastentry.last_time.useconds =
                ulog->kdb_last_time.useconds;
            ulog_handle->ret = UPDATE_OK;

            (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
            (void) krb5_db_unlock(context);

            return (0);
        } else {
            /*
             * We have time stamp mismatch or we no longer have
             * the slave's last sno, so we brute force it
             */
            (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
            (void) krb5_db_unlock(context);
            ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;

            return (0);
        }
    }

    /*
     * Should never get here, return error
     */
    (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
    ulog_handle->ret = UPDATE_ERROR;
    return (KRB5_LOG_ERROR);
}