static krb5_error_code mspac_get_attribute(krb5_context kcontext, krb5_authdata_context context, void *plugin_context, void *request_context, const krb5_data *attribute, krb5_boolean *authenticated, krb5_boolean *complete, krb5_data *value, krb5_data *display_value, int *more) { struct mspac_context *pacctx = (struct mspac_context *)request_context; krb5_error_code code; krb5_ui_4 type; if (display_value != NULL) { display_value->data = NULL; display_value->length = 0; } if (*more != -1 || pacctx->pac == NULL) return ENOENT; /* If it didn't verify, pretend it didn't exist. */ if (!pacctx->pac->verified) { TRACE_MSPAC_DISCARD_UNVERF(kcontext); return ENOENT; } code = mspac_attr2type(attribute, &type); if (code != 0) return code; /* -1 is a magic type that refers to the entire PAC */ if (type == (krb5_ui_4)-1) { if (value != NULL) code = krb5int_copy_data_contents(kcontext, &pacctx->pac->data, value); else code = 0; } else { if (value != NULL) code = krb5_pac_get_buffer(kcontext, pacctx->pac, type, value); else code = k5_pac_locate_buffer(kcontext, pacctx->pac, type, NULL); } if (code == 0) { *authenticated = pacctx->pac->verified; *complete = TRUE; } *more = 0; return code; }
static krb5_error_code pac_verify(void *ctx, krb5_context context, const krb5_principal client_principal, struct hdb_entry_ex *client, struct hdb_entry_ex *server, krb5_pac *pac) { krb5_error_code ret; krb5_data data; krb5_warnx(context, "pac_verify"); ret = krb5_pac_get_buffer(context, *pac, 1, &data); if (ret) return ret; krb5_data_free(&data); return 0; }
krb5_error_code kerberos_pac_to_user_info_dc(TALLOC_CTX *mem_ctx, krb5_pac pac, krb5_context context, struct auth_user_info_dc **user_info_dc, struct PAC_SIGNATURE_DATA *pac_srv_sig, struct PAC_SIGNATURE_DATA *pac_kdc_sig) { NTSTATUS nt_status; enum ndr_err_code ndr_err; krb5_error_code ret; DATA_BLOB pac_logon_info_in, pac_srv_checksum_in, pac_kdc_checksum_in; krb5_data k5pac_logon_info_in, k5pac_srv_checksum_in, k5pac_kdc_checksum_in; DATA_BLOB pac_upn_dns_info_in; krb5_data k5pac_upn_dns_info_in; union PAC_INFO info; union PAC_INFO _upn_dns_info; const struct PAC_UPN_DNS_INFO *upn_dns_info = NULL; struct auth_user_info_dc *user_info_dc_out; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return ENOMEM; } ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_LOGON_INFO, &k5pac_logon_info_in); if (ret != 0) { talloc_free(tmp_ctx); return EINVAL; } pac_logon_info_in = data_blob_const(k5pac_logon_info_in.data, k5pac_logon_info_in.length); ndr_err = ndr_pull_union_blob(&pac_logon_info_in, tmp_ctx, &info, PAC_TYPE_LOGON_INFO, (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO); smb_krb5_free_data_contents(context, &k5pac_logon_info_in); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { nt_status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status))); talloc_free(tmp_ctx); return EINVAL; } if (info.logon_info.info == NULL) { DEBUG(0,("can't parse the PAC LOGON_INFO: missing info pointer\n")); talloc_free(tmp_ctx); return EINVAL; } ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_UPN_DNS_INFO, &k5pac_upn_dns_info_in); if (ret == ENOENT) { ZERO_STRUCT(k5pac_upn_dns_info_in); ret = 0; } if (ret != 0) { talloc_free(tmp_ctx); return EINVAL; } pac_upn_dns_info_in = data_blob_const(k5pac_upn_dns_info_in.data, k5pac_upn_dns_info_in.length); if (pac_upn_dns_info_in.length != 0) { ndr_err = ndr_pull_union_blob(&pac_upn_dns_info_in, tmp_ctx, &_upn_dns_info, PAC_TYPE_UPN_DNS_INFO, (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO); smb_krb5_free_data_contents(context, &k5pac_upn_dns_info_in); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { nt_status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC UPN_DNS_INFO: %s\n", nt_errstr(nt_status))); talloc_free(tmp_ctx); return EINVAL; } upn_dns_info = &_upn_dns_info.upn_dns_info; } /* Pull this right into the normal auth sysstem structures */ nt_status = make_user_info_dc_pac(mem_ctx, info.logon_info.info, upn_dns_info, &user_info_dc_out); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return EINVAL; } if (pac_srv_sig) { ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_SRV_CHECKSUM, &k5pac_srv_checksum_in); if (ret != 0) { talloc_free(tmp_ctx); return ret; } pac_srv_checksum_in = data_blob_const(k5pac_srv_checksum_in.data, k5pac_srv_checksum_in.length); ndr_err = ndr_pull_struct_blob(&pac_srv_checksum_in, pac_srv_sig, pac_srv_sig, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); smb_krb5_free_data_contents(context, &k5pac_srv_checksum_in); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { nt_status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the KDC signature: %s\n", nt_errstr(nt_status))); return EINVAL; } } if (pac_kdc_sig) { ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_KDC_CHECKSUM, &k5pac_kdc_checksum_in); if (ret != 0) { talloc_free(tmp_ctx); return ret; } pac_kdc_checksum_in = data_blob_const(k5pac_kdc_checksum_in.data, k5pac_kdc_checksum_in.length); ndr_err = ndr_pull_struct_blob(&pac_kdc_checksum_in, pac_kdc_sig, pac_kdc_sig, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); smb_krb5_free_data_contents(context, &k5pac_kdc_checksum_in); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { nt_status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the KDC signature: %s\n", nt_errstr(nt_status))); return EINVAL; } } *user_info_dc = user_info_dc_out; return 0; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_pac pac; krb5_data data; krb5_principal p, p2; ret = krb5_init_context(&context); if (ret) errx(1, "krb5_init_contex"); krb5_enctype_enable(context, ETYPE_DES_CBC_MD5); ret = krb5_parse_name_flags(context, user, KRB5_PRINCIPAL_PARSE_NO_REALM, &p); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_pac_parse(context, saved_pac, sizeof(saved_pac), &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify"); ret = _krb5_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_data_free(&data); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse 2"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify 2"); /* make a copy and try to reproduce it */ { uint32_t *list; size_t len, i; krb5_pac pac2; ret = krb5_pac_init(context, &pac2); if (ret) krb5_err(context, 1, ret, "krb5_pac_init"); /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_types"); for (i = 0; i < len; i++) { /* skip server_cksum, privsvr_cksum, and logon_name */ if (list[i] == 6 || list[i] == 7 || list[i] == 10) continue; ret = krb5_pac_get_buffer(context, pac, list[i], &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (list[i] == 1) { if (type_1_length != data.length) krb5_errx(context, 1, "type 1 have wrong length: %lu", (unsigned long)data.length); } else krb5_errx(context, 1, "unknown type %lu", (unsigned long)list[i]); ret = krb5_pac_add_buffer(context, pac2, list[i], &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_add_buffer"); krb5_data_free(&data); } free(list); ret = _krb5_pac_sign(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign 4"); krb5_pac_free(context, pac2); ret = krb5_pac_parse(context, data.data, data.length, &pac2); krb5_data_free(&data); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse 4"); ret = krb5_pac_verify(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify 4"); krb5_pac_free(context, pac2); } krb5_pac_free(context, pac); /* * check pac from Christian */ ret = krb5_parse_name_flags(context, user2, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_pac_parse(context, saved_pac2, sizeof(saved_pac2) -1, &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse"); ret = krb5_pac_verify(context, pac, authtime2, p2, &member_keyblock2, NULL); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify c1"); krb5_pac_free(context, pac); krb5_free_principal(context, p2); /* * Test empty free */ ret = krb5_pac_init(context, &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_init"); krb5_pac_free(context, pac); /* * Test add remove buffer */ ret = krb5_pac_init(context, &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_init"); { const krb5_data cdata = { 2, "\x00\x01" } ; ret = krb5_pac_add_buffer(context, pac, 1, &cdata); if (ret) krb5_err(context, 1, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) krb5_errx(context, 1, "krb5_pac_get_buffer data not the same"); krb5_data_free(&data); } { const krb5_data cdata = { 2, "\x02\x00" } ; ret = krb5_pac_add_buffer(context, pac, 2, &cdata); if (ret) krb5_err(context, 1, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) krb5_errx(context, 1, "krb5_pac_get_buffer data not the same"); krb5_data_free(&data); /* */ ret = krb5_pac_get_buffer(context, pac, 2, &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x02\x00", 2) != 0) krb5_errx(context, 1, "krb5_pac_get_buffer data not the same"); krb5_data_free(&data); } ret = _krb5_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_data_free(&data); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse 3"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify 3"); { uint32_t *list; size_t len; /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_types"); if (len != 5) krb5_errx(context, 1, "list wrong length"); free(list); } krb5_pac_free(context, pac); krb5_free_principal(context, p); krb5_free_context(context); return 0; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_pac pac; krb5_data data; krb5_principal p; ret = krb5_init_context(&context); if (ret) err(NULL, 0, "krb5_init_contex"); krb5_set_default_realm(context, "WIN2K3.THINKER.LOCAL"); ret = krb5_parse_name(context, user, &p); if (ret) err(context, ret, "krb5_parse_name"); ret = krb5_pac_parse(context, saved_pac, sizeof(saved_pac), &pac); if (ret) err(context, ret, "krb5_pac_parse"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify"); ret = krb5int_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) err(context, ret, "krb5int_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_free_data_contents(context, &data); if (ret) err(context, ret, "krb5_pac_parse 2"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify 2"); /* make a copy and try to reproduce it */ { uint32_t *list; size_t len, i; krb5_pac pac2; ret = krb5_pac_init(context, &pac2); if (ret) err(context, ret, "krb5_pac_init"); /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) err(context, ret, "krb5_pac_get_types"); for (i = 0; i < len; i++) { /* skip server_cksum, privsvr_cksum, and logon_name */ if (list[i] == 6 || list[i] == 7 || list[i] == 10) continue; ret = krb5_pac_get_buffer(context, pac, list[i], &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (list[i] == 1) { if (type_1_length != data.length) err(context, 0, "type 1 have wrong length: %lu", (unsigned long)data.length); } else err(context, 0, "unknown type %lu", (unsigned long)list[i]); ret = krb5_pac_add_buffer(context, pac2, list[i], &data); if (ret) err(context, ret, "krb5_pac_add_buffer"); krb5_free_data_contents(context, &data); } free(list); ret = krb5int_pac_sign(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) err(context, ret, "krb5int_pac_sign 4"); krb5_pac_free(context, pac2); ret = krb5_pac_parse(context, data.data, data.length, &pac2); if (ret) err(context, ret, "krb5_pac_parse 4"); ret = krb5_pac_verify(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify 4"); krb5_free_data_contents(context, &data); krb5_pac_free(context, pac2); } krb5_pac_free(context, pac); /* * Test empty free */ ret = krb5_pac_init(context, &pac); if (ret) err(context, ret, "krb5_pac_init"); krb5_pac_free(context, pac); /* * Test add remove buffer */ ret = krb5_pac_init(context, &pac); if (ret) err(context, ret, "krb5_pac_init"); { const krb5_data cdata = { 0, 2, "\x00\x01" } ; ret = krb5_pac_add_buffer(context, pac, 1, &cdata); if (ret) err(context, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) err(context, 0, "krb5_pac_get_buffer data not the same"); krb5_free_data_contents(context, &data); } { const krb5_data cdata = { 0, 2, "\x02\x00" } ; ret = krb5_pac_add_buffer(context, pac, 2, &cdata); if (ret) err(context, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) err(context, 0, "krb5_pac_get_buffer data not the same"); krb5_free_data_contents(context, &data); /* */ ret = krb5_pac_get_buffer(context, pac, 2, &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x02\x00", 2) != 0) err(context, 0, "krb5_pac_get_buffer data not the same"); krb5_free_data_contents(context, &data); } ret = krb5int_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) err(context, ret, "krb5int_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_free_data_contents(context, &data); if (ret) err(context, ret, "krb5_pac_parse 3"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify 3"); { uint32_t *list; size_t len; /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) err(context, ret, "krb5_pac_get_types"); if (len != 5) err(context, 0, "list wrong length"); free(list); } krb5_pac_free(context, pac); krb5_free_principal(context, p); krb5_free_context(context); return 0; }
krb5_error_code kerberos_pac_to_server_info(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, krb5_pac pac, krb5_context context, struct auth_serversupplied_info **server_info) { NTSTATUS nt_status; enum ndr_err_code ndr_err; krb5_error_code ret; DATA_BLOB pac_logon_info_in, pac_srv_checksum_in, pac_kdc_checksum_in; krb5_data k5pac_logon_info_in, k5pac_srv_checksum_in, k5pac_kdc_checksum_in; union PAC_INFO info; union netr_Validation validation; struct auth_serversupplied_info *server_info_out; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return ENOMEM; } ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_LOGON_INFO, &k5pac_logon_info_in); if (ret != 0) { talloc_free(tmp_ctx); return EINVAL; } pac_logon_info_in = data_blob_const(k5pac_logon_info_in.data, k5pac_logon_info_in.length); ndr_err = ndr_pull_union_blob(&pac_logon_info_in, tmp_ctx, iconv_convenience, &info, PAC_TYPE_LOGON_INFO, (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO); krb5_data_free(&k5pac_logon_info_in); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err) || !info.logon_info.info) { nt_status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status))); talloc_free(tmp_ctx); return EINVAL; } /* Pull this right into the normal auth sysstem structures */ validation.sam3 = &info.logon_info.info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return EINVAL; } ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_SRV_CHECKSUM, &k5pac_srv_checksum_in); if (ret != 0) { talloc_free(tmp_ctx); return ret; } pac_srv_checksum_in = data_blob_const(k5pac_srv_checksum_in.data, k5pac_srv_checksum_in.length); ndr_err = ndr_pull_struct_blob(&pac_srv_checksum_in, server_info_out, iconv_convenience, &server_info_out->pac_srv_sig, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); krb5_data_free(&k5pac_srv_checksum_in); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { nt_status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the KDC signature: %s\n", nt_errstr(nt_status))); return EINVAL; } ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_KDC_CHECKSUM, &k5pac_kdc_checksum_in); if (ret != 0) { talloc_free(tmp_ctx); return ret; } pac_kdc_checksum_in = data_blob_const(k5pac_kdc_checksum_in.data, k5pac_kdc_checksum_in.length); ndr_err = ndr_pull_struct_blob(&pac_kdc_checksum_in, server_info_out, iconv_convenience, &server_info_out->pac_kdc_sig, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); krb5_data_free(&k5pac_kdc_checksum_in); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { nt_status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the KDC signature: %s\n", nt_errstr(nt_status))); return EINVAL; } *server_info = server_info_out; return 0; }