static krb5_error_code receive_everything(krb5_context context, int fd, kadm5_server_context *server_context, krb5_auth_context auth_context) { int ret; krb5_data data; uint32_t vno = 0; uint32_t opcode; krb5_storage *sp; char *dbname; HDB *mydb; krb5_warnx(context, "receive complete database"); ret = asprintf(&dbname, "%s-NEW", server_context->db->hdb_name); if (ret == -1) krb5_err(context, IPROPD_RESTART, ENOMEM, "asprintf"); ret = hdb_create(context, &mydb, dbname); if(ret) krb5_err(context, IPROPD_RESTART, ret, "hdb_create"); free(dbname); ret = hdb_set_master_keyfile(context, mydb, server_context->config.stash_file); if(ret) krb5_err(context, IPROPD_RESTART, ret, "hdb_set_master_keyfile"); /* I really want to use O_EXCL here, but given that I can't easily clean up on error, I won't */ ret = mydb->hdb_open(context, mydb, O_RDWR | O_CREAT | O_TRUNC, 0600); if (ret) krb5_err(context, IPROPD_RESTART, ret, "db->open"); (void) mydb->hdb_set_sync(context, mydb, 0); sp = NULL; krb5_data_zero(&data); do { ret = krb5_read_priv_message(context, auth_context, &fd, &data); if (ret) { krb5_warn(context, ret, "krb5_read_priv_message"); goto cleanup; } sp = krb5_storage_from_data(&data); if (sp == NULL) krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_data"); krb5_ret_uint32(sp, &opcode); if (opcode == ONE_PRINC) { krb5_data fake_data; hdb_entry_ex entry; krb5_storage_free(sp); fake_data.data = (char *)data.data + 4; fake_data.length = data.length - 4; memset(&entry, 0, sizeof(entry)); ret = hdb_value2entry(context, &fake_data, &entry.entry); if (ret) krb5_err(context, IPROPD_RESTART, ret, "hdb_value2entry"); ret = mydb->hdb_store(server_context->context, mydb, 0, &entry); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "hdb_store"); hdb_free_entry(context, &entry); krb5_data_free(&data); } else if (opcode == NOW_YOU_HAVE) ; else krb5_errx(context, 1, "strange opcode %d", opcode); } while (opcode == ONE_PRINC); if (opcode != NOW_YOU_HAVE) krb5_errx(context, IPROPD_RESTART_SLOW, "receive_everything: strange %d", opcode); krb5_ret_uint32(sp, &vno); krb5_storage_free(sp); reinit_log(context, server_context, vno); ret = mydb->hdb_set_sync(context, mydb, 1); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "failed to sync the received HDB"); ret = mydb->hdb_close(context, mydb); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close"); ret = mydb->hdb_rename(context, mydb, server_context->db->hdb_name); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->rename"); return 0; cleanup: krb5_data_free(&data); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close"); ret = mydb->hdb_destroy(context, mydb); if (ret) krb5_err(context, IPROPD_RESTART, ret, "db->destroy"); krb5_warnx(context, "receive complete database, version %ld", (long)vno); return ret; }