kadm5_ret_t kadm5_log_previous (krb5_storage *sp, u_int32_t *ver, time_t *timestamp, enum kadm_ops *op, u_int32_t *len) { off_t off; int32_t tmp; krb5_storage_seek(sp, -8, SEEK_CUR); krb5_ret_int32 (sp, &tmp); *len = tmp; krb5_ret_int32 (sp, &tmp); *ver = tmp; off = 24 + *len; krb5_storage_seek(sp, -off, SEEK_CUR); krb5_ret_int32 (sp, &tmp); assert(tmp == *ver); krb5_ret_int32 (sp, &tmp); *timestamp = tmp; krb5_ret_int32 (sp, &tmp); *op = tmp; krb5_ret_int32 (sp, &tmp); assert(tmp == *len); return 0; }
kadm5_ret_t _kadm5_client_send(kadm5_client_context *context, krb5_storage *sp) { krb5_data msg, out; krb5_error_code ret; size_t len; krb5_storage *sock; assert(context->sock != -1); len = krb5_storage_seek(sp, 0, SEEK_CUR); ret = krb5_data_alloc(&msg, len); if (ret) return ret; krb5_storage_seek(sp, 0, SEEK_SET); krb5_storage_read(sp, msg.data, msg.length); ret = krb5_mk_priv(context->context, context->ac, &msg, &out, NULL); krb5_data_free(&msg); if(ret) return ret; sock = krb5_storage_from_fd(context->sock); if(sock == NULL) { krb5_data_free(&out); return ENOMEM; } ret = krb5_store_data(sock, out); krb5_storage_free(sock); krb5_data_free(&out); return ret; }
krb5_error_code kcm_dispatch(krb5_context context, kcm_client *client, krb5_data *req_data, krb5_data *resp_data) { krb5_error_code ret; kcm_method method; krb5_storage *req_sp = NULL; krb5_storage *resp_sp = NULL; u_int16_t opcode; resp_sp = krb5_storage_emem(); if (resp_sp == NULL) { return ENOMEM; } if (client->pid == -1) { kcm_log(0, "Client had invalid process number"); ret = KRB5_FCC_INTERNAL; goto out; } req_sp = krb5_storage_from_data(req_data); if (req_sp == NULL) { kcm_log(0, "Process %d: failed to initialize storage from data", client->pid); ret = KRB5_CC_IO; goto out; } krb5_ret_int16(req_sp, &opcode); if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) { kcm_log(0, "Process %d: invalid operation code %d", client->pid, opcode); ret = KRB5_FCC_INTERNAL; goto out; } method = kcm_ops[opcode].method; /* seek past place for status code */ krb5_storage_seek(resp_sp, 4, SEEK_SET); ret = (*method)(context, client, opcode, req_sp, resp_sp); out: if (req_sp != NULL) { krb5_storage_free(req_sp); } krb5_storage_seek(resp_sp, 0, SEEK_SET); krb5_store_int32(resp_sp, ret); ret = krb5_storage_to_data(resp_sp, resp_data); krb5_storage_free(resp_sp); return ret; }
static krb5_error_code KRB5_CALLCONV akf_next_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor) { struct akf_data *d = id->data; int32_t kvno; off_t pos; int ret; pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); if ((pos - 4) / (4 + 8) >= d->num_entries) return KRB5_KT_END; ret = krb5_make_principal (context, &entry->principal, d->realm, "afs", d->cell, NULL); if (ret) goto out; ret = krb5_ret_int32(cursor->sp, &kvno); if (ret) { krb5_free_principal (context, entry->principal); goto out; } entry->vno = kvno; if (cursor->data) entry->keyblock.keytype = ETYPE_DES_CBC_MD5; else entry->keyblock.keytype = ETYPE_DES_CBC_CRC; entry->keyblock.keyvalue.length = 8; entry->keyblock.keyvalue.data = malloc (8); if (entry->keyblock.keyvalue.data == NULL) { krb5_free_principal (context, entry->principal); ret = krb5_enomem(context); goto out; } ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8); if(ret != 8) ret = (ret < 0) ? errno : KRB5_KT_END; else ret = 0; entry->timestamp = time(NULL); entry->flags = 0; entry->aliases = NULL; out: if (cursor->data) { krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET); cursor->data = NULL; } else cursor->data = cursor; return ret; }
static krb5_error_code fkt_next_entry_int(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor, off_t *start, off_t *end) { int32_t len; int ret; int8_t tmp8; int32_t tmp32; off_t pos, curpos; pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); loop: ret = krb5_ret_int32(cursor->sp, &len); if (ret) return ret; if(len < 0) { pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR); goto loop; } ret = krb5_kt_ret_principal (context, cursor->sp, &entry->principal); if (ret) goto out; ret = krb5_ret_int32(cursor->sp, &tmp32); entry->timestamp = tmp32; if (ret) goto out; ret = krb5_ret_int8(cursor->sp, &tmp8); if (ret) goto out; entry->vno = tmp8; ret = krb5_kt_ret_keyblock (context, cursor->sp, &entry->keyblock); if (ret) goto out; /* there might be a 32 bit kvno here * if it's zero, assume that the 8bit one was right, * otherwise trust the new value */ curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); if(len + 4 + pos - curpos == 4) { ret = krb5_ret_int32(cursor->sp, &tmp32); if (ret == 0 && tmp32 != 0) { entry->vno = tmp32; } } if(start) *start = pos; if(end) *end = *start + 4 + len; out: krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET); return ret; }
static int addrport_print_addr (const krb5_address *addr, char *str, size_t len) { krb5_error_code ret; krb5_address addr1, addr2; uint16_t port = 0; size_t ret_len = 0, l, size = 0; krb5_storage *sp; sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address)); if (sp == NULL) return ENOMEM; /* for totally obscure reasons, these are not in network byteorder */ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */ krb5_ret_address(sp, &addr1); krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */ krb5_ret_address(sp, &addr2); krb5_storage_free(sp); if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) { unsigned long value; _krb5_get_int(addr2.address.data, &value, 2); port = value; } l = strlcpy(str, "ADDRPORT:", len); ret_len += l; if (len > l) size += l; else size = len; ret = krb5_print_address(&addr1, str + size, len - size, &l); if (ret) return ret; ret_len += l; if (len - size > l) size += l; else size = len; ret = snprintf(str + size, len - size, ",PORT=%u", port); if (ret < 0) return EINVAL; ret_len += ret; return ret_len; }
kadm5_ret_t kadm5_log_foreach (kadm5_server_context *context, void (*func)(kadm5_server_context *server_context, u_int32_t ver, time_t timestamp, enum kadm_ops op, u_int32_t len, krb5_storage *sp)) { int fd = context->log_context.log_fd; krb5_storage *sp; lseek (fd, 0, SEEK_SET); sp = krb5_storage_from_fd (fd); for (;;) { int32_t ver, timestamp, op, len; if(krb5_ret_int32 (sp, &ver) != 0) break; krb5_ret_int32 (sp, ×tamp); krb5_ret_int32 (sp, &op); krb5_ret_int32 (sp, &len); (*func)(context, ver, timestamp, op, len, sp); krb5_storage_seek(sp, 8, SEEK_CUR); } return 0; }
static void apply_entry(kadm5_server_context *server_context, uint32_t ver, time_t timestamp, enum kadm_ops op, uint32_t len, krb5_storage *sp, void *ctx) { struct replay_options *opt = ctx; krb5_error_code ret; if((opt->start_version_integer != -1 && ver < (uint32_t)opt->start_version_integer) || (opt->end_version_integer != -1 && ver > (uint32_t)opt->end_version_integer)) { /* XXX skip this entry */ krb5_storage_seek(sp, len, SEEK_CUR); return; } printf ("ver %u... ", ver); fflush (stdout); ret = kadm5_log_replay (server_context, op, ver, len, sp); if (ret) krb5_warn (server_context->context, ret, "kadm5_log_replay"); printf ("done\n"); }
static kadm5_ret_t kadm5_log_replay_rename (kadm5_server_context *context, uint32_t ver, uint32_t len, krb5_storage *sp) { krb5_error_code ret; krb5_principal source; hdb_entry_ex target_ent; krb5_data value; off_t off; size_t princ_len, data_len; memset(&target_ent, 0, sizeof(target_ent)); off = krb5_storage_seek(sp, 0, SEEK_CUR); ret = krb5_ret_principal (sp, &source); if (ret) { krb5_set_error_message(context->context, ret, "Failed to read renamed " "principal in log, version: %ld", (long)ver); return ret; } princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off; data_len = len - princ_len; ret = krb5_data_alloc (&value, data_len); if (ret) { krb5_free_principal (context->context, source); return ret; } krb5_storage_read (sp, value.data, data_len); ret = hdb_value2entry (context->context, &value, &target_ent.entry); krb5_data_free(&value); if (ret) { krb5_free_principal (context->context, source); return ret; } ret = context->db->hdb_store (context->context, context->db, 0, &target_ent); hdb_free_entry (context->context, &target_ent); if (ret) { krb5_free_principal (context->context, source); return ret; } ret = context->db->hdb_remove (context->context, context->db, source); krb5_free_principal (context->context, source); return ret; }
krb5_storage * kadm5_log_goto_end (int fd) { krb5_storage *sp; sp = krb5_storage_from_fd (fd); krb5_storage_seek(sp, 0, SEEK_END); return sp; }
kadm5_ret_t kadm5_log_delete (kadm5_server_context *context, krb5_principal princ) { krb5_storage *sp; kadm5_ret_t ret; off_t off; off_t len; kadm5_log_context *log_context = &context->log_context; sp = krb5_storage_emem(); if (sp == NULL) return ENOMEM; ret = kadm5_log_preamble (context, sp, kadm_delete); if (ret) goto out; ret = krb5_store_int32 (sp, 0); if (ret) goto out; off = krb5_storage_seek (sp, 0, SEEK_CUR); ret = krb5_store_principal (sp, princ); if (ret) goto out; len = krb5_storage_seek (sp, 0, SEEK_CUR) - off; krb5_storage_seek(sp, -(len + 4), SEEK_CUR); ret = krb5_store_int32 (sp, len); if (ret) goto out; krb5_storage_seek(sp, len, SEEK_CUR); ret = krb5_store_int32 (sp, len); if (ret) goto out; ret = kadm5_log_postamble (log_context, sp); if (ret) goto out; ret = kadm5_log_flush (log_context, sp); if (ret) goto out; ret = kadm5_log_end (context); out: krb5_storage_free (sp); return ret; }
kadm5_ret_t kadm5_log_replay_rename (kadm5_server_context *context, u_int32_t ver, u_int32_t len, krb5_storage *sp) { krb5_error_code ret; krb5_principal source; hdb_entry source_ent, target_ent; krb5_data value; off_t off; size_t princ_len, data_len; off = krb5_storage_seek(sp, 0, SEEK_CUR); krb5_ret_principal (sp, &source); princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off; data_len = len - princ_len; ret = krb5_data_alloc (&value, data_len); if (ret) { krb5_free_principal (context->context, source); return ret; } krb5_storage_read (sp, value.data, data_len); ret = hdb_value2entry (context->context, &value, &target_ent); krb5_data_free(&value); if (ret) { krb5_free_principal (context->context, source); return ret; } ret = context->db->hdb_store (context->context, context->db, 0, &target_ent); hdb_free_entry (context->context, &target_ent); if (ret) { krb5_free_principal (context->context, source); return ret; } source_ent.principal = source; ret = context->db->hdb_remove (context->context, context->db, &source_ent); krb5_free_principal (context->context, source); return ret; }
kadm5_ret_t kadm5_log_previous (krb5_context context, krb5_storage *sp, uint32_t *ver, time_t *timestamp, enum kadm_ops *op, uint32_t *len) { krb5_error_code ret; off_t off, oldoff; int32_t tmp; oldoff = krb5_storage_seek(sp, 0, SEEK_CUR); krb5_storage_seek(sp, -8, SEEK_CUR); ret = krb5_ret_int32 (sp, &tmp); if (ret) goto end_of_storage; *len = tmp; ret = krb5_ret_int32 (sp, &tmp); *ver = tmp; off = 24 + *len; krb5_storage_seek(sp, -off, SEEK_CUR); ret = krb5_ret_int32 (sp, &tmp); if (ret) goto end_of_storage; if (tmp != *ver) { krb5_storage_seek(sp, oldoff, SEEK_SET); krb5_set_error_string(context, "kadm5_log_previous: log entry " "have consistency failure, version number wrong"); return KADM5_BAD_DB; } ret = krb5_ret_int32 (sp, &tmp); if (ret) goto end_of_storage; *timestamp = tmp; ret = krb5_ret_int32 (sp, &tmp); *op = tmp; ret = krb5_ret_int32 (sp, &tmp); if (ret) goto end_of_storage; if (tmp != *len) { krb5_storage_seek(sp, oldoff, SEEK_SET); krb5_set_error_string(context, "kadm5_log_previous: log entry " "have consistency failure, length wrong"); return KADM5_BAD_DB; } return 0; end_of_storage: krb5_storage_seek(sp, oldoff, SEEK_SET); krb5_set_error_string(context, "kadm5_log_previous: end of storage " "reached before end"); return ret; }
static void check_too_large(krb5_context context, krb5_storage *sp) { uint32_t too_big_sizes[] = { INT_MAX, INT_MAX / 2, INT_MAX / 4, INT_MAX / 8 + 1}; krb5_error_code ret; krb5_data data; size_t n; for (n = 0; n < sizeof(too_big_sizes) / sizeof(too_big_sizes); n++) { krb5_storage_truncate(sp, 0); krb5_store_uint32(sp, too_big_sizes[n]); krb5_storage_seek(sp, 0, SEEK_SET); ret = krb5_ret_data(sp, &data); if (ret != HEIM_ERR_TOO_BIG) errx(1, "not too big: %lu", (unsigned long)n); } }
static krb5_error_code KRB5_CALLCONV fkt_remove_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { krb5_keytab_entry e; krb5_kt_cursor cursor; off_t pos_start, pos_end; int found = 0; krb5_error_code ret; ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor); if(ret != 0) goto out; /* return other error here? */ while(fkt_next_entry_int(context, id, &e, &cursor, &pos_start, &pos_end) == 0) { if(krb5_kt_compare(context, &e, entry->principal, entry->vno, entry->keyblock.keytype)) { int32_t len; unsigned char buf[128]; found = 1; krb5_storage_seek(cursor.sp, pos_start, SEEK_SET); len = pos_end - pos_start - 4; krb5_store_int32(cursor.sp, -len); memset(buf, 0, sizeof(buf)); while(len > 0) { krb5_storage_write(cursor.sp, buf, min((size_t)len, sizeof(buf))); len -= min((size_t)len, sizeof(buf)); } } krb5_kt_free_entry(context, &e); } krb5_kt_end_seq_get(context, id, &cursor); out: if (!found) { krb5_clear_error_message (context); return KRB5_KT_NOTFOUND; } return 0; }
static krb5_error_code storage_to_etext(krb5_context context, krb5_storage *sp, const krb5_keyblock *key, krb5_data *enc_data) { krb5_error_code ret; krb5_crypto crypto; krb5_ssize_t size; krb5_data data; /* multiple of eight bytes */ size = krb5_storage_seek(sp, 0, SEEK_END); if (size < 0) return EINVAL; size = 8 - (size & 7); ret = krb5_storage_write(sp, eightzeros, size); if (ret != size) return EINVAL; ret = krb5_storage_to_data(sp, &data); if (ret) return ret; ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto); if (ret) { krb5_data_free(&data); return ret; } ret = krb5_encrypt(context, crypto, 0, data.data, data.length, enc_data); krb5_data_free(&data); krb5_crypto_destroy(context, crypto); return ret; }
kadm5_ret_t kadm5_log_get_version_fd (int fd, u_int32_t *ver) { int ret; krb5_storage *sp; int32_t old_version; ret = lseek (fd, 0, SEEK_END); if(ret < 0) return errno; if(ret == 0) { *ver = 0; return 0; } sp = krb5_storage_from_fd (fd); krb5_storage_seek(sp, -4, SEEK_CUR); krb5_ret_int32 (sp, &old_version); *ver = old_version; krb5_storage_free(sp); lseek (fd, 0, SEEK_END); return 0; }
static void test_int32(krb5_context context, krb5_storage *sp) { krb5_error_code ret; int i; int32_t val[] = { 0, 1, -1, 2147483647, -2147483646 }, v; krb5_storage_truncate(sp, 0); for (i = 0; i < sizeof(val[0])/sizeof(val); i++) { ret = krb5_store_int32(sp, val[i]); if (ret) krb5_err(context, 1, ret, "krb5_store_int32"); krb5_storage_seek(sp, 0, SEEK_SET); ret = krb5_ret_int32(sp, &v); if (ret) krb5_err(context, 1, ret, "krb5_ret_int32"); if (v != val[i]) krb5_errx(context, 1, "store and ret mismatch"); } }
static void test_uint16(krb5_context context, krb5_storage *sp) { krb5_error_code ret; int i; uint16_t val[] = { 0, 1, 65535 }, v; krb5_storage_truncate(sp, 0); for (i = 0; i < sizeof(val[0])/sizeof(val); i++) { ret = krb5_store_uint16(sp, val[i]); if (ret) krb5_err(context, 1, ret, "krb5_store_uint16"); krb5_storage_seek(sp, 0, SEEK_SET); ret = krb5_ret_uint16(sp, &v); if (ret) krb5_err(context, 1, ret, "krb5_ret_uint16"); if (v != val[i]) krb5_errx(context, 1, "store and ret mismatch"); } }
static krb5_error_code create_reply_ticket (krb5_context context, struct rx_header *hdr, Key *skey, char *name, char *instance, char *realm, struct sockaddr_in *addr, int life, int kvno, int32_t max_seq_len, const char *sname, const char *sinstance, uint32_t challenge, const char *label, krb5_keyblock *key, krb5_data *reply) { krb5_error_code ret; krb5_data ticket; krb5_keyblock session; krb5_storage *sp; krb5_data enc_data; struct rx_header reply_hdr; char zero[8]; size_t pad; unsigned fyrtiosjuelva; /* create the ticket */ krb5_generate_random_keyblock(context, ETYPE_DES_PCBC_NONE, &session); _krb5_krb_create_ticket(context, 0, name, instance, realm, addr->sin_addr.s_addr, &session, life, kdc_time, sname, sinstance, &skey->key, &ticket); /* create the encrypted part of the reply */ sp = krb5_storage_emem (); krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva)); fyrtiosjuelva &= 0xffffffff; krb5_store_int32 (sp, fyrtiosjuelva); krb5_store_int32 (sp, challenge); krb5_storage_write (sp, session.keyvalue.data, 8); krb5_free_keyblock_contents(context, &session); krb5_store_int32 (sp, kdc_time); krb5_store_int32 (sp, kdc_time + _krb5_krb_life_to_time (0, life)); krb5_store_int32 (sp, kvno); krb5_store_int32 (sp, ticket.length); krb5_store_stringz (sp, name); krb5_store_stringz (sp, instance); #if 1 /* XXX - Why shouldn't the realm go here? */ krb5_store_stringz (sp, ""); #else krb5_store_stringz (sp, realm); #endif krb5_store_stringz (sp, sname); krb5_store_stringz (sp, sinstance); krb5_storage_write (sp, ticket.data, ticket.length); krb5_storage_write (sp, label, strlen(label)); /* pad to DES block */ memset (zero, 0, sizeof(zero)); pad = (8 - krb5_storage_seek (sp, 0, SEEK_CUR) % 8) % 8; krb5_storage_write (sp, zero, pad); krb5_storage_to_data (sp, &enc_data); krb5_storage_free (sp); if (enc_data.length > max_seq_len) { krb5_data_free (&enc_data); make_error_reply (hdr, KAANSWERTOOLONG, reply); return 0; } /* encrypt it */ { DES_key_schedule schedule; DES_cblock deskey; memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); DES_set_key_unchecked (&deskey, &schedule); DES_pcbc_encrypt (enc_data.data, enc_data.data, enc_data.length, &schedule, &deskey, DES_ENCRYPT); memset (&schedule, 0, sizeof(schedule)); memset (&deskey, 0, sizeof(deskey)); } /* create the reply packet */ init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST); sp = krb5_storage_emem (); ret = encode_rx_header (&reply_hdr, sp); krb5_store_int32 (sp, max_seq_len); krb5_store_xdr_data (sp, enc_data); krb5_data_free (&enc_data); krb5_storage_to_data (sp, reply); krb5_storage_free (sp); return 0; }
krb5_error_code _kdc_do_524(krb5_context context, krb5_kdc_configuration *config, const Ticket *t, krb5_data *reply, const char *from, struct sockaddr *addr) { krb5_error_code ret = 0; krb5_crypto crypto; hdb_entry_ex *server = NULL; Key *skey; krb5_data et_data; EncTicketPart et; EncryptedData ticket; krb5_storage *sp; char *spn = NULL; unsigned char buf[MAX_KTXT_LEN + 4 * 4]; size_t len; int kvno = 0; if(!config->enable_524) { ret = KRB5KDC_ERR_POLICY; kdc_log(context, config, 0, "Rejected ticket conversion request from %s", from); goto out; } ret = fetch_server (context, config, t, &spn, &server, from); if (ret) { goto out; } ret = hdb_enctype2key(context, &server->entry, t->enc_part.etype, &skey); if(ret){ kdc_log(context, config, 0, "No suitable key found for server (%s) from %s", spn, from); goto out; } ret = krb5_crypto_init(context, &skey->key, 0, &crypto); if (ret) { kdc_log(context, config, 0, "krb5_crypto_init failed: %s", krb5_get_err_text(context, ret)); goto out; } ret = krb5_decrypt_EncryptedData (context, crypto, KRB5_KU_TICKET, &t->enc_part, &et_data); krb5_crypto_destroy(context, crypto); if(ret){ kdc_log(context, config, 0, "Failed to decrypt ticket from %s for %s", from, spn); goto out; } ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length, &et, &len); krb5_data_free(&et_data); if(ret){ kdc_log(context, config, 0, "Failed to decode ticket from %s for %s", from, spn); goto out; } ret = log_524 (context, config, &et, from, spn); if (ret) { free_EncTicketPart(&et); goto out; } ret = verify_flags (context, config, &et, spn); if (ret) { free_EncTicketPart(&et); goto out; } ret = set_address (context, config, &et, addr, from); if (ret) { free_EncTicketPart(&et); goto out; } ret = encode_524_response(context, config, spn, et, t, server, &ticket, &kvno); free_EncTicketPart(&et); out: /* make reply */ memset(buf, 0, sizeof(buf)); sp = krb5_storage_from_mem(buf, sizeof(buf)); if (sp) { krb5_store_int32(sp, ret); if(ret == 0){ krb5_store_int32(sp, kvno); krb5_store_data(sp, ticket.cipher); /* Aargh! This is coded as a KTEXT_ST. */ krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR); krb5_store_int32(sp, 0); /* mbz */ free_EncryptedData(&ticket); } ret = krb5_storage_to_data(sp, reply); reply->length = krb5_storage_seek(sp, 0, SEEK_CUR); krb5_storage_free(sp); } else krb5_data_zero(reply); if(spn) free(spn); if(server) _kdc_free_ent (context, server); return ret; }
kadm5_ret_t kadm5_log_rename (kadm5_server_context *context, krb5_principal source, hdb_entry *ent) { krb5_storage *sp; kadm5_ret_t ret; off_t off; off_t len; krb5_data value; kadm5_log_context *log_context = &context->log_context; krb5_data_zero(&value); sp = krb5_storage_emem(); ret = hdb_entry2value (context->context, ent, &value); if (ret) goto failed; ret = kadm5_log_preamble (context, sp, kadm_rename); if (ret) goto failed; ret = krb5_store_int32 (sp, 0); if (ret) goto failed; off = krb5_storage_seek (sp, 0, SEEK_CUR); ret = krb5_store_principal (sp, source); if (ret) goto failed; krb5_storage_write(sp, value.data, value.length); len = krb5_storage_seek (sp, 0, SEEK_CUR) - off; krb5_storage_seek(sp, -(len + 4), SEEK_CUR); ret = krb5_store_int32 (sp, len); if (ret) goto failed; krb5_storage_seek(sp, len, SEEK_CUR); ret = krb5_store_int32 (sp, len); if (ret) goto failed; ret = kadm5_log_postamble (log_context, sp); if (ret) goto failed; ret = kadm5_log_flush (log_context, sp); if (ret) goto failed; krb5_storage_free (sp); krb5_data_free (&value); return kadm5_log_end (context); failed: krb5_data_free(&value); krb5_storage_free(sp); return ret; }
static void receive_loop (krb5_context context, krb5_storage *sp, kadm5_server_context *server_context) { int ret; off_t left, right; void *buf; int32_t vers, vers2; ssize_t sret; /* * Seek to the current version of the local database. */ do { int32_t len, timestamp, tmp; enum kadm_ops op; if(krb5_ret_int32 (sp, &vers) != 0) return; krb5_ret_int32 (sp, ×tamp); krb5_ret_int32 (sp, &tmp); op = tmp; krb5_ret_int32 (sp, &len); if (vers <= server_context->log_context.version) krb5_storage_seek(sp, len + 8, SEEK_CUR); } while(vers <= server_context->log_context.version); /* * Read up rest of the entires into the memory... */ left = krb5_storage_seek (sp, -16, SEEK_CUR); right = krb5_storage_seek (sp, 0, SEEK_END); buf = malloc (right - left); if (buf == NULL && (right - left) != 0) krb5_errx (context, 1, "malloc: no memory"); /* * ...and then write them out to the on-disk log. */ krb5_storage_seek (sp, left, SEEK_SET); krb5_storage_read (sp, buf, right - left); sret = write (server_context->log_context.log_fd, buf, right-left); if (sret != right - left) krb5_err(context, 1, errno, "Failed to write log to disk"); ret = fsync (server_context->log_context.log_fd); if (ret) krb5_err(context, 1, errno, "Failed to sync log to disk"); free (buf); /* * Go back to the startpoint and start to commit the entires to * the database. */ krb5_storage_seek (sp, left, SEEK_SET); for(;;) { int32_t len, len2, timestamp, tmp; off_t cur, cur2; enum kadm_ops op; if(krb5_ret_int32 (sp, &vers) != 0) break; ret = krb5_ret_int32 (sp, ×tamp); if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers); ret = krb5_ret_int32 (sp, &tmp); if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers); op = tmp; ret = krb5_ret_int32 (sp, &len); if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers); if (len < 0) krb5_errx(context, 1, "log is corrupted, " "negative length of entry version %ld: %ld", (long)vers, (long)len); cur = krb5_storage_seek(sp, 0, SEEK_CUR); krb5_warnx (context, "replaying entry %d", (int)vers); ret = kadm5_log_replay (server_context, op, vers, len, sp); if (ret) { const char *s = krb5_get_error_message(server_context->context, ret); krb5_warnx (context, "kadm5_log_replay: %ld. Lost entry entry, " "Database out of sync ?: %s (%d)", (long)vers, s ? s : "unknown error", ret); krb5_free_error_message(context, s); } { /* * Make sure the krb5_log_replay does the right thing wrt * reading out data from the sp. */ cur2 = krb5_storage_seek(sp, 0, SEEK_CUR); if (cur + len != cur2) krb5_errx(context, 1, "kadm5_log_reply version: %ld didn't read the whole entry", (long)vers); } if (krb5_ret_int32 (sp, &len2) != 0) krb5_errx(context, 1, "entry %ld: postamble too short", (long)vers); if(krb5_ret_int32 (sp, &vers2) != 0) krb5_errx(context, 1, "entry %ld: postamble too short", (long)vers); if (len != len2) krb5_errx(context, 1, "entry %ld: len != len2", (long)vers); if (vers != vers2) krb5_errx(context, 1, "entry %ld: vers != vers2", (long)vers); } /* * Update version */ server_context->log_context.version = vers; }
static krb5_error_code KRB5_CALLCONV fkt_add_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { int ret; int fd; krb5_storage *sp; struct fkt_data *d = id->data; krb5_data keytab; int32_t len; fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC); if (fd < 0) { fd = open (d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600); if (fd < 0) { ret = errno; krb5_set_error_message(context, ret, N_("open(%s): %s", ""), d->filename, strerror(ret)); return ret; } rk_cloexec(fd); ret = _krb5_xlock(context, fd, 1, d->filename); if (ret) { close(fd); return ret; } sp = krb5_storage_from_fd(fd); krb5_storage_set_eof_code(sp, KRB5_KT_END); ret = fkt_setup_keytab(context, id, sp); if(ret) { goto out; } storage_set_flags(context, sp, id->version); } else { int8_t pvno, tag; rk_cloexec(fd); ret = _krb5_xlock(context, fd, 1, d->filename); if (ret) { close(fd); return ret; } sp = krb5_storage_from_fd(fd); krb5_storage_set_eof_code(sp, KRB5_KT_END); ret = krb5_ret_int8(sp, &pvno); if(ret) { /* we probably have a zero byte file, so try to set it up properly */ ret = fkt_setup_keytab(context, id, sp); if(ret) { krb5_set_error_message(context, ret, N_("%s: keytab is corrupted: %s", ""), d->filename, strerror(ret)); goto out; } storage_set_flags(context, sp, id->version); } else { if(pvno != 5) { ret = KRB5_KEYTAB_BADVNO; krb5_set_error_message(context, ret, N_("Bad version in keytab %s", ""), d->filename); goto out; } ret = krb5_ret_int8 (sp, &tag); if (ret) { krb5_set_error_message(context, ret, N_("failed reading tag from " "keytab %s", ""), d->filename); goto out; } id->version = tag; storage_set_flags(context, sp, id->version); } } { krb5_storage *emem; emem = krb5_storage_emem(); if(emem == NULL) { ret = krb5_enomem(context); goto out; } ret = krb5_kt_store_principal(context, emem, entry->principal); if(ret) { krb5_set_error_message(context, ret, N_("Failed storing principal " "in keytab %s", ""), d->filename); krb5_storage_free(emem); goto out; } ret = krb5_store_int32 (emem, entry->timestamp); if(ret) { krb5_set_error_message(context, ret, N_("Failed storing timpstamp " "in keytab %s", ""), d->filename); krb5_storage_free(emem); goto out; } ret = krb5_store_int8 (emem, entry->vno % 256); if(ret) { krb5_set_error_message(context, ret, N_("Failed storing kvno " "in keytab %s", ""), d->filename); krb5_storage_free(emem); goto out; } ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock); if(ret) { krb5_storage_free(emem); goto out; } if ((d->flags & KRB5_KT_FL_JAVA) == 0) { ret = krb5_store_int32 (emem, entry->vno); if (ret) { krb5_set_error_message(context, ret, N_("Failed storing extended kvno " "in keytab %s", ""), d->filename); krb5_storage_free(emem); goto out; } ret = krb5_store_uint32 (emem, entry->flags); if (ret) { krb5_set_error_message(context, ret, N_("Failed storing extended kvno " "in keytab %s", ""), d->filename); krb5_storage_free(emem); goto out; } } ret = krb5_storage_to_data(emem, &keytab); krb5_storage_free(emem); if(ret) { krb5_set_error_message(context, ret, N_("Failed converting keytab entry " "to memory block for keytab %s", ""), d->filename); goto out; } } while(1) { ret = krb5_ret_int32(sp, &len); if(ret == KRB5_KT_END) { len = keytab.length; break; } if(len < 0) { len = -len; if(len >= (int)keytab.length) { krb5_storage_seek(sp, -4, SEEK_CUR); break; } } krb5_storage_seek(sp, len, SEEK_CUR); } ret = krb5_store_int32(sp, len); if(krb5_storage_write(sp, keytab.data, keytab.length) < 0) { ret = errno; krb5_set_error_message(context, ret, N_("Failed writing keytab block " "in keytab %s: %s", ""), d->filename, strerror(ret)); } memset(keytab.data, 0, keytab.length); krb5_data_free(&keytab); out: krb5_storage_free(sp); _krb5_xunlock(context, fd); close(fd); return ret; }
static int send_diffs (krb5_context context, slave *s, int log_fd, const char *database, u_int32_t current_version) { krb5_storage *sp; u_int32_t ver; time_t timestamp; enum kadm_ops op; u_int32_t len; off_t right, left; krb5_data data; int ret = 0; if (s->version == current_version) return 0; if (s->flags & SLAVE_F_DEAD) return 0; sp = kadm5_log_goto_end (log_fd); right = krb5_storage_seek(sp, 0, SEEK_CUR); for (;;) { if (kadm5_log_previous (sp, &ver, ×tamp, &op, &len)) abort (); left = krb5_storage_seek(sp, -16, SEEK_CUR); if (ver == s->version) return 0; if (ver == s->version + 1) break; if (left == 0) return send_complete (context, s, database, current_version); } ret = krb5_data_alloc (&data, right - left + 4); if (ret) { krb5_warn (context, ret, "send_diffs: krb5_data_alloc"); slave_dead(s); return 1; } krb5_storage_read (sp, (char *)data.data + 4, data.length - 4); krb5_storage_free(sp); sp = krb5_storage_from_data (&data); if (sp == NULL) { krb5_warnx (context, "send_diffs: krb5_storage_from_data"); slave_dead(s); return 1; } krb5_store_int32 (sp, FOR_YOU); krb5_storage_free(sp); ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); krb5_data_free(&data); if (ret) { krb5_warn (context, ret, "send_diffs: krb5_write_priv_message"); slave_dead(s); return 1; } slave_seen(s); return 0; }
static krb5_error_code verify_checksum(krb5_context context, const struct PAC_INFO_BUFFER *sig, const krb5_data *data, void *ptr, size_t len, const krb5_keyblock *key) { krb5_storage *sp = NULL; uint32_t type; krb5_error_code ret; Checksum cksum; memset(&cksum, 0, sizeof(cksum)); sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo, sig->buffersize); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &type), out); cksum.cksumtype = type; cksum.checksum.length = sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR); cksum.checksum.data = malloc(cksum.checksum.length); if (cksum.checksum.data == NULL) { ret = krb5_enomem(context); goto out; } ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length); if (ret != cksum.checksum.length) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC checksum missing checksum"); goto out; } if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) { ret = EINVAL; krb5_set_error_message(context, ret, "Checksum type %d not keyed", cksum.cksumtype); goto out; } /* If the checksum is HMAC-MD5, the checksum type is not tied to * the key type, instead the HMAC-MD5 checksum is applied blindly * on whatever key is used for this connection, avoiding issues * with unkeyed checksums on des-cbc-md5 and des-cbc-crc. See * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743 * for the same issue in MIT, and * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx * for Microsoft's explaination */ if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5) { Checksum local_checksum; memset(&local_checksum, 0, sizeof(local_checksum)); ret = HMAC_MD5_any_checksum(context, key, ptr, len, KRB5_KU_OTHER_CKSUM, &local_checksum); if (ret != 0 || krb5_data_ct_cmp(&local_checksum.checksum, &cksum.checksum) != 0) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; krb5_set_error_message(context, ret, N_("PAC integrity check failed for " "hmac-md5 checksum", "")); } krb5_data_free(&local_checksum.checksum); } else { krb5_crypto crypto = NULL; ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) goto out; ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, ptr, len, &cksum); krb5_crypto_destroy(context, crypto); } free(cksum.checksum.data); krb5_storage_free(sp); return ret; out: if (cksum.checksum.data) free(cksum.checksum.data); if (sp) krb5_storage_free(sp); return ret; }
static int send_complete (krb5_context context, slave *s, const char *database, uint32_t current_version, uint32_t oldest_version, uint32_t initial_log_tstamp) { krb5_error_code ret; krb5_storage *dump = NULL; uint32_t vno = 0; krb5_data data; int fd = -1; struct stat st; char *dfn; ret = asprintf(&dfn, "%s/ipropd.dumpfile", hdb_db_dir(context)); if (ret == -1 || !dfn) { krb5_warn(context, ENOMEM, "Cannot allocate memory"); return ENOMEM; } fd = open(dfn, O_CREAT|O_RDWR, 0600); if (fd == -1) { ret = errno; krb5_warn(context, ret, "Cannot open/create iprop dumpfile %s", dfn); free(dfn); return ret; } free(dfn); dump = krb5_storage_from_fd(fd); if (!dump) { ret = errno; krb5_warn(context, ret, "krb5_storage_from_fd"); goto done; } for (;;) { ret = flock(fd, LOCK_SH); if (ret == -1) { ret = errno; krb5_warn(context, ret, "flock(fd, LOCK_SH)"); goto done; } if (krb5_storage_seek(dump, 0, SEEK_SET) == (off_t)-1) { ret = errno; krb5_warn(context, ret, "krb5_storage_seek(dump, 0, SEEK_SET)"); goto done; } vno = 0; ret = krb5_ret_uint32(dump, &vno); if (ret && ret != HEIM_ERR_EOF) { krb5_warn(context, ret, "krb5_ret_uint32(dump, &vno)"); goto done; } if (fstat(fd, &st) == -1) { ret = errno; krb5_warn(context, ret, "send_complete: could not stat dump file"); goto done; } /* * If the current dump has an appropriate version, then we can * break out of the loop and send the file below. */ if (ret == 0 && vno != 0 && st.st_mtime > initial_log_tstamp && vno >= oldest_version && vno <= current_version) break; if (verbose) krb5_warnx(context, "send_complete: dumping HDB"); /* * Otherwise, we may need to write a new dump file. We * obtain an exclusive lock on the fd. Because this is * not guaranteed to be an upgrade of our existing shared * lock, someone else may have written a new dumpfile while * we were waiting and so we must first check the vno of * the dump to see if that happened. If it did, we need * to go back to the top of the loop so that we can downgrade * our lock to a shared one. */ ret = flock(fd, LOCK_EX); if (ret == -1) { ret = errno; krb5_warn(context, ret, "flock(fd, LOCK_EX)"); goto done; } ret = krb5_storage_seek(dump, 0, SEEK_SET); if (ret == -1) { ret = errno; krb5_warn(context, ret, "krb5_storage_seek(dump, 0, SEEK_SET)"); goto done; } vno = 0; ret = krb5_ret_uint32(dump, &vno); if (ret && ret != HEIM_ERR_EOF) { krb5_warn(context, ret, "krb5_ret_uint32(dump, &vno)"); goto done; } if (fstat(fd, &st) == -1) { ret = errno; krb5_warn(context, ret, "send_complete: could not stat dump file"); goto done; } /* check if someone wrote a better version for us */ if (ret == 0 && vno != 0 && st.st_mtime > initial_log_tstamp && vno >= oldest_version && vno <= current_version) continue; /* Now, we know that we must write a new dump file. */ ret = write_dump(context, dump, database, current_version); if (ret) goto done; /* * And we must continue to the top of the loop so that we can * downgrade to a shared lock. */ } /* * Leaving the above loop, dump should have a ptr right after the initial * 4 byte DB version number and we should have a shared lock on the file * (which we may have just created), so we are reading to simply blast * the data down the wire. */ for (;;) { ret = krb5_ret_data(dump, &data); if (ret == HEIM_ERR_EOF) { ret = 0; /* EOF is not an error, it's success */ goto done; } if (ret) { krb5_warn(context, ret, "krb5_ret_data(dump, &data)"); slave_dead(context, s); goto done; } ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); krb5_data_free(&data); if (ret) { krb5_warn (context, ret, "krb5_write_priv_message"); slave_dead(context, s); goto done; } } done: if (!ret) { s->version = vno; slave_seen(s); } if (fd != -1) close(fd); if (dump) krb5_storage_free(dump); return ret; }
static int write_dump (krb5_context context, krb5_storage *dump, const char *database, uint32_t current_version) { krb5_error_code ret; krb5_storage *sp; HDB *db; krb5_data data; char buf[8]; /* we assume that the caller has obtained an exclusive lock */ ret = krb5_storage_truncate(dump, 0); if (ret) return ret; if (krb5_storage_seek(dump, 0, SEEK_SET) != 0) return errno; /* * First we store zero as the HDB version, this will indicate to a * later reader that the dumpfile is invalid. We later write the * correct version in the file after we have written all of the * messages. A dump with a zero version will not be considered * to be valid. */ ret = krb5_store_uint32(dump, 0); ret = hdb_create (context, &db, database); if (ret) krb5_err (context, IPROPD_RESTART, ret, "hdb_create: %s", database); ret = db->hdb_open (context, db, O_RDONLY, 0); if (ret) krb5_err (context, IPROPD_RESTART, ret, "db->open"); sp = krb5_storage_from_mem (buf, 4); if (sp == NULL) krb5_errx (context, IPROPD_RESTART, "krb5_storage_from_mem"); krb5_store_uint32 (sp, TELL_YOU_EVERYTHING); krb5_storage_free (sp); data.data = buf; data.length = 4; ret = krb5_store_data(dump, data); if (ret) { krb5_warn (context, ret, "write_dump"); return ret; } ret = hdb_foreach (context, db, HDB_F_ADMIN_DATA, dump_one, dump); if (ret) { krb5_warn (context, ret, "write_dump: hdb_foreach"); return ret; } (*db->hdb_close)(context, db); (*db->hdb_destroy)(context, db); sp = krb5_storage_from_mem (buf, 8); if (sp == NULL) krb5_errx (context, IPROPD_RESTART, "krb5_storage_from_mem"); ret = krb5_store_uint32(sp, NOW_YOU_HAVE); if (ret == 0) krb5_store_uint32(sp, current_version); krb5_storage_free (sp); data.length = 8; if (ret == 0) ret = krb5_store_data(dump, data); /* * We must ensure that the entire valid dump is written to disk * before we write the current version at the front thus making * it a valid dump file. If we crash around here, this can be * important upon reboot. */ if (ret == 0) ret = krb5_storage_fsync(dump); if (ret == 0 && krb5_storage_seek(dump, 0, SEEK_SET) == -1) ret = errno; /* Write current version at the front making the dump valid */ if (ret == 0) ret = krb5_store_uint32(dump, current_version); /* * We don't need to fsync(2) after the real version is written as * it is not a disaster if it doesn't make it to disk if we crash. * After all, we'll just create a new dumpfile. */ if (ret == 0) krb5_warnx(context, "wrote new dumpfile (version %u)", current_version); else krb5_warn(context, ret, "failed to write new dumpfile (version %u)", current_version); return ret; }
static int send_diffs (kadm5_server_context *server_context, slave *s, int log_fd, const char *database, uint32_t current_version, uint32_t current_tstamp) { krb5_context context = server_context->context; krb5_storage *sp; uint32_t ver, initial_version, initial_version2; uint32_t initial_tstamp, initial_tstamp2; enum kadm_ops op; uint32_t len; off_t right, left; krb5_ssize_t bytes; krb5_data data; int ret = 0; if (s->flags & SLAVE_F_DEAD) { krb5_warnx(context, "not sending diffs to dead slave %s", s->name); return 0; } if (s->version == current_version) { char buf[4]; sp = krb5_storage_from_mem(buf, 4); if (sp == NULL) krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_mem"); ret = krb5_store_uint32(sp, YOU_HAVE_LAST_VERSION); krb5_storage_free(sp); data.data = buf; data.length = 4; if (ret == 0) { ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); if (ret) { krb5_warn(context, ret, "send_diffs: failed to send to slave"); slave_dead(context, s); } krb5_warnx(context, "slave %s in sync already at version %ld", s->name, (long)s->version); } return ret; } if (verbose) krb5_warnx(context, "sending diffs to live-seeming slave %s", s->name); /* * XXX The code that makes the diffs should be made a separate function, * then error handling (send_are_you_there() or slave_dead()) can be done * here. */ if (flock(log_fd, LOCK_SH) == -1) { krb5_warn(context, errno, "could not obtain shared lock on log file"); send_are_you_there(context, s); return errno; } ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST, &initial_version, &initial_tstamp); sp = kadm5_log_goto_end(server_context, log_fd); flock(log_fd, LOCK_UN); if (ret) { if (sp != NULL) krb5_storage_free(sp); krb5_warn(context, ret, "send_diffs: failed to read log"); send_are_you_there(context, s); return ret; } if (sp == NULL) { send_are_you_there(context, s); krb5_warn(context, errno ? errno : EINVAL, "send_diffs: failed to read log"); return errno ? errno : EINVAL; } /* * We're not holding any locks here, so we can't prevent truncations. * * We protect against this by re-checking that the initial version and * timestamp are the same before and after this loop. */ right = krb5_storage_seek(sp, 0, SEEK_CUR); if (right == (off_t)-1) { krb5_storage_free(sp); send_are_you_there(context, s); return errno; } for (;;) { ret = kadm5_log_previous (context, sp, &ver, NULL, &op, &len); if (ret) krb5_err(context, IPROPD_RESTART, ret, "send_diffs: failed to find previous entry"); left = krb5_storage_seek(sp, -16, SEEK_CUR); if (left == (off_t)-1) { krb5_storage_free(sp); send_are_you_there(context, s); return errno; } if (ver == s->version + 1) break; /* * We don't expect to reach the slave's version, except when it is * starting empty with the uber record. */ if (ver == s->version && !(ver == 0 && op == kadm_nop)) { /* * This shouldn't happen, but recall we're not holding a lock on * the log. */ krb5_storage_free(sp); krb5_warnx(context, "iprop log truncated while sending diffs to " "slave?? ver = %lu", (unsigned long)ver); send_are_you_there(context, s); return 0; } /* If we've reached the uber record, send the complete database */ if (left == 0 || (ver == 0 && op == kadm_nop)) { krb5_storage_free(sp); krb5_warnx(context, "slave %s (version %lu) out of sync with master " "(first version in log %lu), sending complete database", s->name, (unsigned long)s->version, (unsigned long)ver); return send_complete (context, s, database, current_version, ver, initial_tstamp); } } assert(ver == s->version + 1); krb5_warnx(context, "syncing slave %s from version %lu to version %lu", s->name, (unsigned long)s->version, (unsigned long)current_version); ret = krb5_data_alloc (&data, right - left + 4); if (ret) { krb5_storage_free(sp); krb5_warn (context, ret, "send_diffs: krb5_data_alloc"); send_are_you_there(context, s); return 1; } bytes = krb5_storage_read(sp, (char *)data.data + 4, data.length - 4); krb5_storage_free(sp); if (bytes != data.length - 4) { krb5_warnx(context, "iprop log truncated while sending diffs to " "slave?? ver = %lu", (unsigned long)ver); send_are_you_there(context, s); return 1; } /* * Check that we have the same log initial version and timestamp now as * when we dropped the shared lock on the log file! Else we could be * sending garbage to the slave. */ if (flock(log_fd, LOCK_SH) == -1) { krb5_warn(context, errno, "could not obtain shared lock on log file"); send_are_you_there(context, s); return 1; } ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST, &initial_version2, &initial_tstamp2); flock(log_fd, LOCK_UN); if (ret) { krb5_warn(context, ret, "send_diffs: failed to read log while producing diffs"); send_are_you_there(context, s); return 1; } if (initial_version != initial_version2 || initial_tstamp != initial_tstamp2) { krb5_warn(context, ret, "send_diffs: log truncated while producing diffs"); send_are_you_there(context, s); return 1; } sp = krb5_storage_from_data (&data); if (sp == NULL) { krb5_warnx (context, "send_diffs: krb5_storage_from_data"); send_are_you_there(context, s); return 1; } krb5_store_uint32 (sp, FOR_YOU); krb5_storage_free(sp); ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); krb5_data_free(&data); if (ret) { krb5_warn (context, ret, "send_diffs: krb5_write_priv_message"); slave_dead(context, s); return 1; } slave_seen(s); s->version = current_version; krb5_warnx(context, "slave %s is now up to date (%u)", s->name, s->version); return 0; }
static krb5_error_code fkt_next_entry_int(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor, off_t *start, off_t *end) { struct fkt_data *d = id->data; int32_t len; int ret; int8_t tmp8; int32_t tmp32; uint32_t utmp32; off_t pos, curpos; pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); loop: ret = krb5_ret_int32(cursor->sp, &len); if (ret) return ret; if(len < 0) { pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR); goto loop; } ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal); if (ret) goto out; ret = krb5_ret_uint32(cursor->sp, &utmp32); entry->timestamp = utmp32; if (ret) goto out; ret = krb5_ret_int8(cursor->sp, &tmp8); if (ret) goto out; entry->vno = tmp8; ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock); if (ret) goto out; /* there might be a 32 bit kvno here * if it's zero, assume that the 8bit one was right, * otherwise trust the new value */ curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); if(len + 4 + pos - curpos >= 4) { ret = krb5_ret_int32(cursor->sp, &tmp32); if (ret == 0 && tmp32 != 0) entry->vno = tmp32; } /* there might be a flags field here */ if(len + 4 + pos - curpos >= 8) { ret = krb5_ret_uint32(cursor->sp, &utmp32); if (ret == 0) entry->flags = utmp32; } else entry->flags = 0; entry->aliases = NULL; if(start) *start = pos; if(end) *end = pos + 4 + len; out: if (ret) krb5_kt_free_entry(context, entry); krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET); return ret; }