예제 #1
0
파일: kdb_log.c 프로젝트: wangweij/krb5
/* Get the last set of updates seen, (last+1) to n is returned. */
krb5_error_code
ulog_get_entries(krb5_context context, const 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;

    /* If another process terminated mid-update, reset the ulog and force full
     * resyncs. */
    if (ulog->kdb_state != KDB_STABLE)
        reset_header(ulog);

    /* 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 = 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 = 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);
    return retval;
}
예제 #2
0
/*
 * Print the update entry information
 */
static void
print_update(kdb_hlog_t *ulog, uint32_t entry, bool_t verbose)
{
	XDR		xdrs;
	uint32_t	start_sno, i, j, indx;
	char		*dbprinc;
	kdb_ent_header_t *indx_log;
	kdb_incr_update_t upd;

	if (entry && (entry < ulog->kdb_num))
		start_sno = ulog->kdb_last_sno - entry;
	else
		start_sno = ulog->kdb_first_sno - 1;

	for (i = start_sno; i < ulog->kdb_last_sno; i++) {
		indx = i % ulog->kdb_num;

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

		/*
		 * Check for corrupt update entry
		 */
		if (indx_log->kdb_umagic != KDB_UMAGIC) {
			(void) fprintf(stderr,
			    gettext("Corrupt update entry\n\n"));
			exit(1);
		}

		(void) memset((char *)&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) printf(gettext("Entry data decode failure\n\n"));
			exit(1);
		}

		(void) printf("---\n");
		(void) printf(gettext("Update Entry\n"));

		(void) printf(gettext("\tUpdate serial # : %u\n"),
		    indx_log->kdb_entry_sno);

		(void) printf(gettext("\tUpdate operation : "));
		if (upd.kdb_deleted)
			(void) printf(gettext("Delete\n"));
		else
			(void) printf(gettext("Add\n"));

		dbprinc = malloc(upd.kdb_princ_name.utf8str_t_len + 1);
		if (dbprinc == NULL) {
			(void) printf(gettext("Could not allocate "
			    "principal name\n\n"));
			exit(1);
		}
		(void) strlcpy(dbprinc, upd.kdb_princ_name.utf8str_t_val,
		    (upd.kdb_princ_name.utf8str_t_len + 1));
		(void) printf(gettext("\tUpdate principal : %s\n"), dbprinc);

		(void) printf(gettext("\tUpdate size : %u\n"),
		    indx_log->kdb_entry_size);

		(void) printf(gettext("\tUpdate committed : %s\n"),
		    indx_log->kdb_commit ? "True" : "False");

		if (indx_log->kdb_time.seconds == 0L)
			(void) printf(gettext("\tUpdate time stamp : None\n"));
		else
			(void) printf(gettext("\tUpdate time stamp : %s"),
			    ctime((time_t *)&(indx_log->kdb_time.seconds)));

		(void) printf(gettext("\tAttributes changed : %d\n"),
		    upd.kdb_update.kdbe_t_len);

		if (verbose)
			for (j = 0; j < upd.kdb_update.kdbe_t_len; j++)
				print_attr(
				    upd.kdb_update.kdbe_t_val[j].av_type);

		xdr_free(xdr_kdb_incr_update_t, (char *)&upd);
		if (dbprinc)
			free(dbprinc);
	} /* for */
}
예제 #3
0
파일: kdb_log.c 프로젝트: DirectXMan12/krb5
/* Get the last set of updates seen, (last+1) to n is returned. */
krb5_error_code
ulog_get_entries(krb5_context context, const 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 = lock_ulog(context, KRB5_LOCKMODE_SHARED);
    if (retval)
        return retval;

    /* If another process terminated mid-update, reset the ulog and force full
     * resyncs. */
    if (ulog->kdb_state != KDB_STABLE)
        reset_header(ulog);

    ulog_handle->ret = get_sno_status(log_ctx, last);
    if (ulog_handle->ret != UPDATE_OK)
        goto cleanup;

    sno = last->last_sno;
    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 = 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:
    unlock_ulog(context);
    return retval;
}
예제 #4
0
파일: kdb_log.c 프로젝트: wangweij/krb5
/*
 * Add an entry to the update log.  The layout of the update log looks like:
 *
 * header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
 */
krb5_error_code
ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
{
    XDR xdrs;
    kdbe_time_t ktime;
    kdb_ent_header_t *indx_log;
    unsigned int i, recsize;
    unsigned long upd_size;
    krb5_error_code retval;
    kdb_sno_t cur_sno;
    kdb_log_context *log_ctx;
    kdb_hlog_t *ulog = NULL;
    uint32_t ulogentries;
    int ulogfd;

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

    if (upd == NULL)
        return KRB5_LOG_ERROR;

    time_current(&ktime);

    upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);

    recsize = sizeof(kdb_ent_header_t) + upd_size;

    if (recsize > ulog->kdb_block) {
        retval = resize(ulog, ulogentries, ulogfd, recsize);
        if (retval)
            return retval;
    }

    /* If we have reached the last possible serial number, reinitialize the
     * ulog and start over.  Slaves will do a full resync. */
    if (ulog->kdb_last_sno == (kdb_sno_t)-1)
        reset_header(ulog);

    /* Get the next serial number and save it for finish_update() to index. */
    cur_sno = ulog->kdb_last_sno + 1;
    upd->kdb_entry_sno = cur_sno;

    i = (cur_sno - 1) % ulogentries;
    indx_log = INDEX(ulog, i);

    memset(indx_log, 0, ulog->kdb_block);
    indx_log->kdb_umagic = KDB_ULOG_MAGIC;
    indx_log->kdb_entry_size = upd_size;
    indx_log->kdb_entry_sno = cur_sno;
    indx_log->kdb_time = upd->kdb_time = ktime;
    indx_log->kdb_commit = upd->kdb_commit = FALSE;

    ulog->kdb_state = KDB_UNSTABLE;

    xdrmem_create(&xdrs, (char *)indx_log->entry_data,
                  indx_log->kdb_entry_size, XDR_ENCODE);
    if (!xdr_kdb_incr_update_t(&xdrs, upd))
        return KRB5_LOG_CONV;

    retval = sync_update(ulog, indx_log);
    if (retval)
        return retval;

    if (ulog->kdb_num < ulogentries)
        ulog->kdb_num++;

    ulog->kdb_last_sno = cur_sno;
    ulog->kdb_last_time = ktime;

    if (cur_sno > ulogentries) {
        /* Once we've circled, kdb_first_sno is the sno of the next entry. */
        i = upd->kdb_entry_sno % ulogentries;
        indx_log = INDEX(ulog, i);
        ulog->kdb_first_sno = indx_log->kdb_entry_sno;
        ulog->kdb_first_time = indx_log->kdb_time;
    } else if (cur_sno == 1) {
        /* This is the first update. */
        ulog->kdb_first_sno = 1;
        ulog->kdb_first_time = indx_log->kdb_time;
    }

    ulog_sync_header(ulog);
    return 0;
}
예제 #5
0
파일: kdb_log.c 프로젝트: DirectXMan12/krb5
/*
 * Add an update to the log.  The update's kdb_entry_sno and kdb_time fields
 * must already be set.  The layout of the update log looks like:
 *
 * header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
 */
static krb5_error_code
store_update(kdb_log_context *log_ctx, kdb_incr_update_t *upd)
{
    XDR xdrs;
    kdb_ent_header_t *indx_log;
    unsigned int i, recsize;
    unsigned long upd_size;
    krb5_error_code retval;
    kdb_hlog_t *ulog = log_ctx->ulog;
    uint32_t ulogentries = log_ctx->ulogentries;

    upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);

    recsize = sizeof(kdb_ent_header_t) + upd_size;

    if (recsize > ulog->kdb_block) {
        retval = resize(ulog, ulogentries, log_ctx->ulogfd, recsize);
        if (retval)
            return retval;
    }

    ulog->kdb_state = KDB_UNSTABLE;

    i = (upd->kdb_entry_sno - 1) % ulogentries;
    indx_log = INDEX(ulog, i);

    memset(indx_log, 0, ulog->kdb_block);
    indx_log->kdb_umagic = KDB_ULOG_MAGIC;
    indx_log->kdb_entry_size = upd_size;
    indx_log->kdb_entry_sno = upd->kdb_entry_sno;
    indx_log->kdb_time = upd->kdb_time;
    indx_log->kdb_commit = FALSE;

    xdrmem_create(&xdrs, (char *)indx_log->entry_data,
                  indx_log->kdb_entry_size, XDR_ENCODE);
    if (!xdr_kdb_incr_update_t(&xdrs, upd))
        return KRB5_LOG_CONV;

    indx_log->kdb_commit = TRUE;
    retval = sync_update(ulog, indx_log);
    if (retval)
        return retval;

    /* Modify the ulog header to reflect the new update. */
    ulog->kdb_last_sno = upd->kdb_entry_sno;
    ulog->kdb_last_time = upd->kdb_time;
    if (ulog->kdb_num == 0) {
        ulog->kdb_num = 1;
        ulog->kdb_first_sno = upd->kdb_entry_sno;
        ulog->kdb_first_time = upd->kdb_time;
    } else if (ulog->kdb_num < ulogentries) {
        ulog->kdb_num++;
    } else {
        /* We are circling; set kdb_first_sno and time to the next update. */
        i = upd->kdb_entry_sno % ulogentries;
        indx_log = INDEX(ulog, i);
        ulog->kdb_first_sno = indx_log->kdb_entry_sno;
        ulog->kdb_first_time = indx_log->kdb_time;
    }

    ulog->kdb_state = KDB_STABLE;
    sync_header(ulog);
    return 0;
}
예제 #6
0
파일: kdb_log.c 프로젝트: Kendra123/krb5
/*
 * Add an entry to the update log.  The layout of the update log looks like:
 *
 * header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
 */
krb5_error_code
ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
{
    XDR xdrs;
    kdbe_time_t ktime;
    kdb_ent_header_t *indx_log;
    unsigned int i, recsize;
    unsigned long upd_size;
    krb5_error_code retval;
    kdb_sno_t cur_sno;
    kdb_log_context *log_ctx;
    kdb_hlog_t *ulog = NULL;
    uint32_t ulogentries;
    int ulogfd;

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

    if (upd == NULL)
        return KRB5_LOG_ERROR;

    time_current(&ktime);

    upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);

    recsize = sizeof(kdb_ent_header_t) + upd_size;

    if (recsize > ulog->kdb_block) {
        retval = ulog_resize(ulog, ulogentries, ulogfd, recsize);
        if (retval)
            return retval;
    }

    cur_sno = ulog->kdb_last_sno;

    /*
     * If we need to, wrap our sno around to 1.  A slaves will do a full resync
     * since its sno will be out of range of the ulog (or in extreme cases,
     * its timestamp won't match).
     */
    if (cur_sno == (kdb_sno_t)-1)
        cur_sno = 1;
    else
        cur_sno++;

    /* Squirrel this away for finish_update() to index. */
    upd->kdb_entry_sno = cur_sno;

    i = (cur_sno - 1) % ulogentries;
    indx_log = (kdb_ent_header_t *)INDEX(ulog, i);

    memset(indx_log, 0, ulog->kdb_block);
    indx_log->kdb_umagic = KDB_ULOG_MAGIC;
    indx_log->kdb_entry_size = upd_size;
    indx_log->kdb_entry_sno = cur_sno;
    indx_log->kdb_time = upd->kdb_time = ktime;
    indx_log->kdb_commit = upd->kdb_commit = FALSE;

    ulog->kdb_state = KDB_UNSTABLE;

    xdrmem_create(&xdrs, (char *)indx_log->entry_data,
                  indx_log->kdb_entry_size, XDR_ENCODE);
    if (!xdr_kdb_incr_update_t(&xdrs, upd))
        return KRB5_LOG_CONV;

    retval = ulog_sync_update(ulog, indx_log);
    if (retval)
        return retval;

    if (ulog->kdb_num < ulogentries)
        ulog->kdb_num++;

    ulog->kdb_last_sno = cur_sno;
    ulog->kdb_last_time = ktime;

    if (cur_sno > ulogentries) {
        /* Once we've circled, kdb_first_sno is the sno of the next entry. */
        i = upd->kdb_entry_sno % ulogentries;
        indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
        ulog->kdb_first_sno = indx_log->kdb_entry_sno;
        ulog->kdb_first_time = indx_log->kdb_time;
    } else if (cur_sno == 1) {
        /* This is the first update, or we wrapped. */
        ulog->kdb_first_sno = 1;
        ulog->kdb_first_time = indx_log->kdb_time;
    }

    ulog_sync_header(ulog);
    return 0;
}
예제 #7
0
파일: kdb_log.c 프로젝트: Baalmart/krb5
/*
 * 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);
}
예제 #8
0
파일: kdb_log.c 프로젝트: Baalmart/krb5
/*
 * Validate the log file and resync any uncommitted update entries
 * to the principal database.
 *
 * Must be called with lock held.
 */
static krb5_error_code
ulog_check(krb5_context context, kdb_hlog_t *ulog, char **db_args)
{
    XDR                 xdrs;
    krb5_error_code     retval = 0;
    unsigned int        i;
    kdb_ent_header_t    *indx_log;
    kdb_incr_update_t   *upd = NULL;
    kdb_incr_result_t   *incr_ret = NULL;

    ulog->kdb_state = KDB_STABLE;

    for (i = 0; i < ulog->kdb_num; i++) {
        indx_log = (kdb_ent_header_t *)INDEX(ulog, i);

        if (indx_log->kdb_umagic != KDB_ULOG_MAGIC) {
            /*
             * Update entry corrupted we should scream and die
             */
            ulog->kdb_state = KDB_CORRUPT;
            retval = KRB5_LOG_CORRUPT;
            break;
        }

        if (indx_log->kdb_commit == FALSE) {
            ulog->kdb_state = KDB_UNSTABLE;

            incr_ret = (kdb_incr_result_t *)
                malloc(sizeof (kdb_incr_result_t));
            if (incr_ret == NULL) {
                retval = errno;
                goto error;
            }

            upd = (kdb_incr_update_t *)
                malloc(sizeof (kdb_incr_update_t));
            if (upd == NULL) {
                retval = errno;
                goto error;
            }

            (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)) {
                retval = KRB5_LOG_CONV;
                goto error;
            }

            incr_ret->updates.kdb_ulog_t_len = 1;
            incr_ret->updates.kdb_ulog_t_val = upd;

            upd->kdb_commit = TRUE;

            /*
             * We don't want to readd this update and just use the
             * existing update to be propagated later on
             */
            ulog_set_role(context, IPROP_NULL);
            retval = ulog_replay(context, incr_ret, db_args);

            /*
             * upd was freed by ulog_replay, we NULL
             * the pointer in case we subsequently break from loop.
             */
            upd = NULL;
            if (incr_ret) {
                free(incr_ret);
                incr_ret = NULL;
            }
            ulog_set_role(context, IPROP_MASTER);

            if (retval)
                goto error;

            /*
             * We flag this as committed since this was
             * the last entry before kadmind crashed, ergo
             * the slaves have not seen this update before
             */
            indx_log->kdb_commit = TRUE;
            retval = ulog_sync_update(ulog, indx_log);
            if (retval)
                goto error;

            ulog->kdb_state = KDB_STABLE;
        }
    }

error:
    if (upd)
        ulog_free_entries(upd, 1);

    free(incr_ret);

    ulog_sync_header(ulog);

    return (retval);
}
예제 #9
0
파일: kdb_log.c 프로젝트: Baalmart/krb5
/*
 * Adds an entry to the update log.
 * The layout of the update log looks like:
 *
 * header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
 */
krb5_error_code
ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
{
    XDR         xdrs;
    kdbe_time_t ktime;
    struct timeval      timestamp;
    kdb_ent_header_t *indx_log;
    uint_t              i, recsize;
    ulong_t             upd_size;
    krb5_error_code     retval;
    kdb_sno_t   cur_sno;
    kdb_log_context     *log_ctx;
    kdb_hlog_t  *ulog = NULL;
    uint32_t    ulogentries;
    int         ulogfd;

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

    if (upd == NULL)
        return (KRB5_LOG_ERROR);

    (void) gettimeofday(&timestamp, NULL);
    ktime.seconds = timestamp.tv_sec;
    ktime.useconds = timestamp.tv_usec;

    upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);

    recsize = sizeof (kdb_ent_header_t) + upd_size;

    if (recsize > ulog->kdb_block) {
        if ((retval = ulog_resize(ulog, ulogentries, ulogfd, recsize))) {
            /* Resize element array failed */
            return (retval);
        }
    }

    cur_sno = ulog->kdb_last_sno;

    /*
     * We need to overflow our sno, replicas will do full
     * resyncs once they see their sno > than the masters.
     */
    if (cur_sno == (kdb_sno_t)-1)
        cur_sno = 1;
    else
        cur_sno++;

    /*
     * We squirrel this away for finish_update() to index
     */
    upd->kdb_entry_sno = cur_sno;

    i = (cur_sno - 1) % ulogentries;

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

    (void) memset(indx_log, 0, ulog->kdb_block);

    indx_log->kdb_umagic = KDB_ULOG_MAGIC;
    indx_log->kdb_entry_size = upd_size;
    indx_log->kdb_entry_sno = cur_sno;
    indx_log->kdb_time = upd->kdb_time = ktime;
    indx_log->kdb_commit = upd->kdb_commit = FALSE;

    ulog->kdb_state = KDB_UNSTABLE;

    xdrmem_create(&xdrs, (char *)indx_log->entry_data,
                  indx_log->kdb_entry_size, XDR_ENCODE);
    if (!xdr_kdb_incr_update_t(&xdrs, upd))
        return (KRB5_LOG_CONV);

    if ((retval = ulog_sync_update(ulog, indx_log)))
        return (retval);

    if (ulog->kdb_num < ulogentries)
        ulog->kdb_num++;

    ulog->kdb_last_sno = cur_sno;
    ulog->kdb_last_time = ktime;

    /*
     * Since this is a circular array, once we circled, kdb_first_sno is
     * always kdb_entry_sno + 1.
     */
    if (cur_sno > ulogentries) {
        i = upd->kdb_entry_sno % ulogentries;
        indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
        ulog->kdb_first_sno = indx_log->kdb_entry_sno;
        ulog->kdb_first_time = indx_log->kdb_time;
    } else if (cur_sno == 1) {
        ulog->kdb_first_sno = 1;
        ulog->kdb_first_time = indx_log->kdb_time;
    }

    ulog_sync_header(ulog);

    return (0);
}