static int ipv4_mask_boundary(krb5_context context, const krb5_address *inaddr, unsigned long len, krb5_address *low, krb5_address *high) { unsigned long ia; uint32_t l, h, m = 0xffffffff; if (len > 32) { krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, N_("IPv4 prefix too large (%ld)", "len"), len); return KRB5_PROG_ATYPE_NOSUPP; } m = m << (32 - len); _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length); l = ia & m; h = l | ~m; low->addr_type = KRB5_ADDRESS_INET; if(krb5_data_alloc(&low->address, 4) != 0) return -1; _krb5_put_int(low->address.data, l, low->address.length); high->addr_type = KRB5_ADDRESS_INET; if(krb5_data_alloc(&high->address, 4) != 0) { krb5_free_address(context, low); return -1; } _krb5_put_int(high->address.data, h, high->address.length); return 0; }
static int send_and_recv_tcp(krb5_socket_t fd, time_t tmout, const krb5_data *req, krb5_data *rep) { unsigned char len[4]; unsigned long rep_len; krb5_data len_data; _krb5_put_int(len, req->length, 4); if(net_write (fd, len, sizeof(len)) < 0) return -1; if(net_write (fd, req->data, req->length) < 0) return -1; if (recv_loop (fd, tmout, 0, 4, &len_data) < 0) return -1; if (len_data.length != 4) { krb5_data_free (&len_data); return -1; } _krb5_get_int(len_data.data, &rep_len, 4); krb5_data_free (&len_data); if (recv_loop (fd, tmout, 0, rep_len, rep) < 0) return -1; if(rep->length != rep_len) { krb5_data_free (rep); return -1; } return 0; }
static int ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr) { const char *p; struct in_addr a; p = strchr(address, ':'); if(p) { p++; if(strncasecmp(address, "ip:", p - address) != 0 && strncasecmp(address, "ip4:", p - address) != 0 && strncasecmp(address, "ipv4:", p - address) != 0 && strncasecmp(address, "inet:", p - address) != 0) return -1; } else p = address; #ifdef HAVE_INET_ATON if(inet_aton(p, &a) == 0) return -1; #elif defined(HAVE_INET_ADDR) a.s_addr = inet_addr(p); if(a.s_addr == INADDR_NONE) return -1; #else return -1; #endif addr->addr_type = KRB5_ADDRESS_INET; if(krb5_data_alloc(&addr->address, 4) != 0) return -1; _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); return 0; }
ssize_t do_write (int fd, void *buf, size_t sz, void *ivec) { if (do_encrypt) { #ifdef KRB5 if(auth_method == AUTH_KRB5) { krb5_error_code status; krb5_data data; unsigned char len[4]; int ret; _krb5_put_int(len, sz, 4); if(ivec != NULL) { unsigned char *tmp = malloc(sz + 4); if(tmp == NULL) err(1, "malloc"); _krb5_put_int(tmp, sz, 4); memcpy(tmp + 4, buf, sz); status = krb5_encrypt_ivec(context, crypto, key_usage, tmp, sz + 4, &data, ivec); free(tmp); } else status = krb5_encrypt_ivec(context, crypto, key_usage, buf, sz, &data, ivec); if (status) krb5_err(context, 1, status, "encrypting data"); ret = krb5_net_write (context, &fd, len, 4); if (ret != 4) return ret; ret = krb5_net_write (context, &fd, data.data, data.length); if (ret != data.length) return ret; free (data.data); return sz; } else #endif /* KRB5 */ abort(); } else return write (fd, buf, sz); }
static krb5_error_code krb5_store_int(krb5_storage *sp, int32_t value, size_t len) { int ret; unsigned char v[16]; if(len > sizeof(v)) return EINVAL; _krb5_put_int(v, value, len); ret = sp->store(sp, v, len); if (ret != len) return (ret<0)?errno:sp->eof_code; return 0; }
kadm5_ret_t kadm5_s_get_principal(void *server_handle, krb5_principal princ, kadm5_principal_ent_t out, uint32_t mask) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); if(ret) return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_ALL_KVNOS| HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if (!context->keep_open) context->db->hdb_close(context->context, context->db); if(ret) return _kadm5_error_code(ret); memset(out, 0, sizeof(*out)); if(mask & KADM5_PRINCIPAL) ret = krb5_copy_principal(context->context, ent.entry.principal, &out->principal); if(ret) goto out; if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end) out->princ_expire_time = *ent.entry.valid_end; if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end) out->pw_expiration = *ent.entry.pw_end; if(mask & KADM5_LAST_PWD_CHANGE) hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change); if(mask & KADM5_ATTRIBUTES){ out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; } if(mask & KADM5_MAX_LIFE) { if(ent.entry.max_life) out->max_life = *ent.entry.max_life; else out->max_life = INT_MAX; } if(mask & KADM5_MOD_TIME) { if(ent.entry.modified_by) out->mod_date = ent.entry.modified_by->time; else out->mod_date = ent.entry.created_by.time; } if(mask & KADM5_MOD_NAME) { if(ent.entry.modified_by) { if (ent.entry.modified_by->principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.modified_by->principal, &out->mod_name); } else if(ent.entry.created_by.principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.created_by.principal, &out->mod_name); else out->mod_name = NULL; } if(ret) goto out; if(mask & KADM5_KVNO) out->kvno = ent.entry.kvno; if(mask & KADM5_MKVNO) { size_t n; out->mkvno = 0; /* XXX */ for(n = 0; n < ent.entry.keys.len; n++) if(ent.entry.keys.val[n].mkvno) { out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */ break; } } #if 0 /* XXX implement */ if(mask & KADM5_AUX_ATTRIBUTES) ; if(mask & KADM5_LAST_SUCCESS) ; if(mask & KADM5_LAST_FAILED) ; if(mask & KADM5_FAIL_AUTH_COUNT) ; #endif if(mask & KADM5_POLICY) { HDB_extension *ext; ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_policy); if (ext == NULL) { out->policy = strdup("default"); /* It's OK if we retun NULL instead of "default" */ } else { out->policy = strdup(ext->data.u.policy); if (out->policy == NULL) { ret = ENOMEM; goto out; } } } if(mask & KADM5_MAX_RLIFE) { if(ent.entry.max_renew) out->max_renewable_life = *ent.entry.max_renew; else out->max_renewable_life = INT_MAX; } if(mask & KADM5_KEY_DATA){ size_t i; size_t n_keys = ent.entry.keys.len; krb5_salt salt; HDB_extension *ext; HDB_Ext_KeySet *hist_keys = NULL; ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys); if (ext != NULL) hist_keys = &ext->data.u.hist_keys; krb5_get_pw_salt(context->context, ent.entry.principal, &salt); for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) n_keys += hist_keys->val[i].keys.len; out->key_data = malloc(n_keys * sizeof(*out->key_data)); if (out->key_data == NULL && n_keys != 0) { ret = ENOMEM; goto out; } out->n_key_data = 0; ret = copy_keyset_to_kadm5(context, ent.entry.kvno, ent.entry.keys.len, ent.entry.keys.val, &salt, out); if (ret) goto out; for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) { ret = copy_keyset_to_kadm5(context, hist_keys->val[i].kvno, hist_keys->val[i].keys.len, hist_keys->val[i].keys.val, &salt, out); if (ret) goto out; } krb5_free_salt(context->context, salt); assert( out->n_key_data == n_keys ); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } if(mask & KADM5_TL_DATA) { time_t last_pw_expire; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_Aliases *aliases; ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire); if (ret == 0 && last_pw_expire) { unsigned char buf[4]; _krb5_put_int(buf, last_pw_expire, sizeof(buf)); ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } /* * If the client was allowed to get key data, let it have the * password too. */ if(mask & KADM5_KEY_DATA) { heim_utf8_string pw; ret = hdb_entry_get_password(context->context, context->db, &ent.entry, &pw); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); free(pw); } krb5_clear_error_message(context->context); } ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl); if (ret == 0 && acl) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length, acl, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } ret = hdb_entry_get_aliases(&ent.entry, &aliases); if (ret == 0 && aliases) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length, aliases, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } } out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
static krb5_error_code make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, Key *key) { ent->etype = key->key.keytype; if(key->salt) { ALLOC(ent->salt); if (ent->salt == NULL) return ENOMEM; *ent->salt = malloc(key->salt->salt.length + 1); if (*ent->salt == NULL) { free(ent->salt); ent->salt = NULL; return ENOMEM; } memcpy(*ent->salt, key->salt->salt.data, key->salt->salt.length); (*ent->salt)[key->salt->salt.length] = '\0'; } else ent->salt = NULL; ent->s2kparams = NULL; switch (key->key.keytype) { case ETYPE_AES128_CTS_HMAC_SHA1_96: case ETYPE_AES256_CTS_HMAC_SHA1_96: ALLOC(ent->s2kparams); if (ent->s2kparams == NULL) return ENOMEM; ent->s2kparams->length = 4; ent->s2kparams->data = malloc(ent->s2kparams->length); if (ent->s2kparams->data == NULL) { free(ent->s2kparams); ent->s2kparams = NULL; return ENOMEM; } _krb5_put_int(ent->s2kparams->data, _krb5_AES_string_to_default_iterator, ent->s2kparams->length); break; case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD4: case ETYPE_DES_CBC_MD5: /* Check if this was a AFS3 salted key */ if(key->salt && key->salt->type == hdb_afs3_salt){ ALLOC(ent->s2kparams); if (ent->s2kparams == NULL) return ENOMEM; ent->s2kparams->length = 1; ent->s2kparams->data = malloc(ent->s2kparams->length); if (ent->s2kparams->data == NULL) { free(ent->s2kparams); ent->s2kparams = NULL; return ENOMEM; } _krb5_put_int(ent->s2kparams->data, 1, ent->s2kparams->length); } break; default: break; } return 0; }
static int string_to_key_test(krb5_context context) { krb5_data password, opaque; krb5_error_code ret; krb5_salt salt; int val = 0; char iter[4]; size_t i; for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) { password.data = keys[i].password; password.length = strlen(password.data); salt.salttype = KRB5_PW_SALT; salt.saltvalue.data = keys[i].salt; if (keys[i].saltlen == -1) salt.saltvalue.length = strlen(salt.saltvalue.data); else salt.saltvalue.length = keys[i].saltlen; opaque.data = iter; opaque.length = sizeof(iter); _krb5_put_int(iter, keys[i].iterations, 4); if (keys[i].pbkdf2) { unsigned char keyout[32]; if (keys[i].keylen > sizeof(keyout)) abort(); PKCS5_PBKDF2_HMAC_SHA1(password.data, password.length, salt.saltvalue.data, salt.saltvalue.length, keys[i].iterations, keys[i].keylen, keyout); if (memcmp(keyout, keys[i].pbkdf2, keys[i].keylen) != 0) { krb5_warnx(context, "%d: pbkdf2", (int)i); val = 1; continue; } if (verbose) { printf("PBKDF2:\n"); hex_dump_data(keyout, keys[i].keylen); } } { krb5_keyblock key; ret = krb5_string_to_key_data_salt_opaque (context, keys[i].enctype, password, salt, opaque, &key); if (ret) { krb5_warn(context, ret, "%d: string_to_key_data_salt_opaque", (int)i); val = 1; continue; } if (key.keyvalue.length != keys[i].keylen) { krb5_warnx(context, "%d: key wrong length (%lu/%lu)", (int)i, (unsigned long)key.keyvalue.length, (unsigned long)keys[i].keylen); val = 1; continue; } if (memcmp(key.keyvalue.data, keys[i].key, keys[i].keylen) != 0) { krb5_warnx(context, "%d: key wrong", (int)i); val = 1; continue; } if (verbose) { printf("key:\n"); hex_dump_data(key.keyvalue.data, key.keyvalue.length); } krb5_free_keyblock_contents(context, &key); } } return val; }
static krb5_error_code setpw_send_request (krb5_context context, krb5_auth_context *auth_context, krb5_creds *creds, krb5_principal targprinc, int is_stream, int sock, char *passwd, const char *host) { krb5_error_code ret; krb5_data ap_req_data; krb5_data krb_priv_data; krb5_data pwd_data; ChangePasswdDataMS chpw; size_t len; u_char header[4 + 6]; u_char *p; struct iovec iov[3]; struct msghdr msghdr; krb5_data_zero (&ap_req_data); ret = krb5_mk_req_extended (context, auth_context, AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, NULL, /* in_data */ creds, &ap_req_data); if (ret) return ret; chpw.newpasswd.length = strlen(passwd); chpw.newpasswd.data = passwd; if (targprinc) { chpw.targname = &targprinc->name; chpw.targrealm = &targprinc->realm; } else { chpw.targname = NULL; chpw.targrealm = NULL; } ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length, &chpw, &len, ret); if (ret) { krb5_data_free (&ap_req_data); return ret; } if(pwd_data.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); ret = krb5_mk_priv (context, *auth_context, &pwd_data, &krb_priv_data, NULL); if (ret) goto out2; len = 6 + ap_req_data.length + krb_priv_data.length; p = header; if (is_stream) { _krb5_put_int(p, len, 4); p += 4; } *p++ = (len >> 8) & 0xFF; *p++ = (len >> 0) & 0xFF; *p++ = 0xff; *p++ = 0x80; *p++ = (ap_req_data.length >> 8) & 0xFF; *p++ = (ap_req_data.length >> 0) & 0xFF; memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = iov; msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov); #if 0 msghdr.msg_control = NULL; msghdr.msg_controllen = 0; #endif iov[0].iov_base = (void*)header; if (is_stream) iov[0].iov_len = 10; else iov[0].iov_len = 6; iov[1].iov_base = ap_req_data.data; iov[1].iov_len = ap_req_data.length; iov[2].iov_base = krb_priv_data.data; iov[2].iov_len = krb_priv_data.length; if (sendmsg (sock, &msghdr, 0) < 0) { ret = errno; krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret)); } krb5_data_free (&krb_priv_data); out2: krb5_data_free (&ap_req_data); krb5_data_free (&pwd_data); return ret; }
krb5_error_code _krb5_pk_kdf(krb5_context context, const struct AlgorithmIdentifier *ai, const void *dhdata, size_t dhsize, krb5_const_principal client, krb5_const_principal server, krb5_enctype enctype, const krb5_data *as_req, const krb5_data *pk_as_rep, const Ticket *ticket, krb5_keyblock *key) { struct _krb5_encryption_type *et; krb5_error_code ret; krb5_data other; size_t keylen, offset; uint32_t counter; unsigned char *keydata; unsigned char shaoutput[SHA512_DIGEST_LENGTH]; const EVP_MD *md; EVP_MD_CTX *m; if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) == 0) { md = EVP_sha1(); } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha256, &ai->algorithm) == 0) { md = EVP_sha256(); } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha512, &ai->algorithm) == 0) { md = EVP_sha512(); } else { krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, N_("KDF not supported", "")); return KRB5_PROG_ETYPE_NOSUPP; } if (ai->parameters != NULL && (ai->parameters->length != 2 || memcmp(ai->parameters->data, "\x05\x00", 2) != 0)) { krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, N_("kdf params not NULL or the NULL-type", "")); return KRB5_PROG_ETYPE_NOSUPP; } et = _krb5_find_enctype(enctype); if(et == NULL) { krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, N_("encryption type %d not supported", ""), enctype); return KRB5_PROG_ETYPE_NOSUPP; } keylen = (et->keytype->bits + 7) / 8; keydata = malloc(keylen); if (keydata == NULL) { krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } ret = encode_otherinfo(context, ai, client, server, enctype, as_req, pk_as_rep, ticket, &other); if (ret) { free(keydata); return ret; } m = EVP_MD_CTX_create(); if (m == NULL) { free(keydata); free(other.data); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } offset = 0; counter = 1; do { unsigned char cdata[4]; EVP_DigestInit_ex(m, md, NULL); _krb5_put_int(cdata, counter, 4); EVP_DigestUpdate(m, cdata, 4); EVP_DigestUpdate(m, dhdata, dhsize); EVP_DigestUpdate(m, other.data, other.length); EVP_DigestFinal_ex(m, shaoutput, NULL); memcpy((unsigned char *)keydata + offset, shaoutput, min(keylen - offset, EVP_MD_CTX_size(m))); offset += EVP_MD_CTX_size(m); counter++; } while(offset < keylen); memset(shaoutput, 0, sizeof(shaoutput)); EVP_MD_CTX_destroy(m); free(other.data); ret = krb5_random_to_key(context, enctype, keydata, keylen, key); memset(keydata, 0, sizeof(keylen)); free(keydata); return ret; }
kadm5_ret_t kadm5_s_get_principal(void *server_handle, krb5_principal princ, kadm5_principal_ent_t out, uint32_t mask) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); context->db->hdb_close(context->context, context->db); if(ret) return _kadm5_error_code(ret); memset(out, 0, sizeof(*out)); if(mask & KADM5_PRINCIPAL) ret = krb5_copy_principal(context->context, ent.entry.principal, &out->principal); if(ret) goto out; if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end) out->princ_expire_time = *ent.entry.valid_end; if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end) out->pw_expiration = *ent.entry.pw_end; if(mask & KADM5_LAST_PWD_CHANGE) hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change); if(mask & KADM5_ATTRIBUTES){ out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; } if(mask & KADM5_MAX_LIFE) { if(ent.entry.max_life) out->max_life = *ent.entry.max_life; else out->max_life = INT_MAX; } if(mask & KADM5_MOD_TIME) { if(ent.entry.modified_by) out->mod_date = ent.entry.modified_by->time; else out->mod_date = ent.entry.created_by.time; } if(mask & KADM5_MOD_NAME) { if(ent.entry.modified_by) { if (ent.entry.modified_by->principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.modified_by->principal, &out->mod_name); } else if(ent.entry.created_by.principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.created_by.principal, &out->mod_name); else out->mod_name = NULL; } if(ret) goto out; if(mask & KADM5_KVNO) out->kvno = ent.entry.kvno; if(mask & KADM5_MKVNO) { size_t n; out->mkvno = 0; /* XXX */ for(n = 0; n < ent.entry.keys.len; n++) if(ent.entry.keys.val[n].mkvno) { out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */ break; } } #if 0 /* XXX implement */ if(mask & KADM5_AUX_ATTRIBUTES) ; if(mask & KADM5_LAST_SUCCESS) ; if(mask & KADM5_LAST_FAILED) ; if(mask & KADM5_FAIL_AUTH_COUNT) ; #endif if(mask & KADM5_POLICY) out->policy = NULL; if(mask & KADM5_MAX_RLIFE) { if(ent.entry.max_renew) out->max_renewable_life = *ent.entry.max_renew; else out->max_renewable_life = INT_MAX; } if(mask & KADM5_KEY_DATA){ size_t i; Key *key; krb5_key_data *kd; krb5_salt salt; krb5_data *sp; krb5_get_pw_salt(context->context, ent.entry.principal, &salt); out->key_data = malloc(ent.entry.keys.len * sizeof(*out->key_data)); if (out->key_data == NULL && ent.entry.keys.len != 0) { ret = ENOMEM; goto out; } for(i = 0; i < ent.entry.keys.len; i++){ key = &ent.entry.keys.val[i]; kd = &out->key_data[i]; kd->key_data_ver = 2; kd->key_data_kvno = ent.entry.kvno; kd->key_data_type[0] = key->key.keytype; if(key->salt) kd->key_data_type[1] = key->salt->type; else kd->key_data_type[1] = KRB5_PADATA_PW_SALT; /* setup key */ kd->key_data_length[0] = key->key.keyvalue.length; kd->key_data_contents[0] = malloc(kd->key_data_length[0]); if(kd->key_data_contents[0] == NULL && kd->key_data_length[0] != 0){ ret = ENOMEM; break; } memcpy(kd->key_data_contents[0], key->key.keyvalue.data, kd->key_data_length[0]); /* setup salt */ if(key->salt) sp = &key->salt->salt; else sp = &salt.saltvalue; kd->key_data_length[1] = sp->length; kd->key_data_contents[1] = malloc(kd->key_data_length[1]); if(kd->key_data_length[1] != 0 && kd->key_data_contents[1] == NULL) { memset(kd->key_data_contents[0], 0, kd->key_data_length[0]); ret = ENOMEM; break; } memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]); out->n_key_data = i + 1; } krb5_free_salt(context->context, salt); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } if(mask & KADM5_TL_DATA) { time_t last_pw_expire; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_Aliases *aliases; ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire); if (ret == 0 && last_pw_expire) { unsigned char buf[4]; _krb5_put_int(buf, last_pw_expire, sizeof(buf)); ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } /* * If the client was allowed to get key data, let it have the * password too. */ if(mask & KADM5_KEY_DATA) { heim_utf8_string pw; ret = hdb_entry_get_password(context->context, context->db, &ent.entry, &pw); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); free(pw); } krb5_clear_error_message(context->context); } ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl); if (ret == 0 && acl) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length, acl, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } ret = hdb_entry_get_aliases(&ent.entry, &aliases); if (ret == 0 && aliases) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length, aliases, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } } out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }