/* 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); }
/* 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; }
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", ®exp) != 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); }
/* 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; }
/* * 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(×tamp, 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); }