static bool torture_krb5_init_context(struct torture_context *tctx, enum torture_krb5_test test, struct smb_krb5_context **smb_krb5_context) { const char *host = torture_setting_string(tctx, "host", NULL); krb5_error_code k5ret; bool ok; struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context); torture_assert(tctx, test_context != NULL, "Failed to allocate"); test_context->test = test; test_context->tctx = tctx; k5ret = smb_krb5_init_context(tctx, tctx->lp_ctx, smb_krb5_context); torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed"); ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST); torture_assert(tctx, ok, "Failed to parse target server"); talloc_set_destructor(test_context, test_context_destructor); set_sockaddr_port(test_context->server->ai_addr, 88); k5ret = krb5_set_send_to_kdc_func((*smb_krb5_context)->krb5_context, smb_krb5_send_and_recv_func_override, test_context); torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed"); return true; }
NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r) { krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; const char *from_keytab; /* Register hdb-samba4 hooks for use as a keytab */ struct samba_kdc_base_context *base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context); if (!base_ctx) { return NT_STATUS_NO_MEMORY; } base_ctx->ev_ctx = ctx->event_ctx; base_ctx->lp_ctx = ctx->lp_ctx; from_keytab = talloc_asprintf(base_ctx, "HDB:samba4&%p", base_ctx); if (!from_keytab) { return NT_STATUS_NO_MEMORY; } ret = smb_krb5_init_context(ctx, ctx->event_ctx, ctx->lp_ctx, &smb_krb5_context); if (ret) { return NT_STATUS_NO_MEMORY; } ret = krb5_plugin_register(smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "hdb", &hdb_samba4); if(ret) { return NT_STATUS_NO_MEMORY; } ret = krb5_kt_register(smb_krb5_context->krb5_context, &hdb_kt_ops); if(ret) { return NT_STATUS_NO_MEMORY; } unlink(r->in.keytab_name); ret = kt_copy(smb_krb5_context->krb5_context, from_keytab, r->in.keytab_name); if(ret) { r->out.error_string = smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx); return NT_STATUS_UNSUCCESSFUL; } return NT_STATUS_OK; }
int cli_credentials_get_krb5_context(struct cli_credentials *cred, struct smb_krb5_context **smb_krb5_context) { int ret; if (cred->smb_krb5_context) { *smb_krb5_context = cred->smb_krb5_context; return 0; } ret = smb_krb5_init_context(cred, &cred->smb_krb5_context); if (ret) { return ret; } *smb_krb5_context = cred->smb_krb5_context; return 0; }
_PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred, struct loadparm_context *lp_ctx, struct smb_krb5_context **smb_krb5_context) { int ret; if (cred->smb_krb5_context) { *smb_krb5_context = cred->smb_krb5_context; return 0; } ret = smb_krb5_init_context(cred, lp_ctx, &cred->smb_krb5_context); if (ret) { cred->smb_krb5_context = NULL; return ret; } *smb_krb5_context = cred->smb_krb5_context; return 0; }
/* startup the kdc task */ static void kdc_task_init(struct task_server *task) { struct kdc_server *kdc; krb5_kdc_configuration *kdc_config = NULL; NTSTATUS status; krb5_error_code ret; struct interface *ifaces; int ldb_ret; switch (lpcfg_server_role(task->lp_ctx)) { case ROLE_STANDALONE: task_server_terminate(task, "kdc: no KDC required in standalone configuration", false); return; case ROLE_DOMAIN_MEMBER: task_server_terminate(task, "kdc: no KDC required in member server configuration", false); return; case ROLE_DOMAIN_PDC: case ROLE_DOMAIN_BDC: task_server_terminate(task, "Cannot start KDC as a 'classic Samba' DC", true); return; case ROLE_ACTIVE_DIRECTORY_DC: /* Yes, we want a KDC */ break; } load_interface_list(task, task->lp_ctx, &ifaces); if (iface_list_count(ifaces) == 0) { task_server_terminate(task, "kdc: no network interfaces configured", false); return; } task_server_set_title(task, "task[kdc]"); kdc = talloc_zero(task, struct kdc_server); if (kdc == NULL) { task_server_terminate(task, "kdc: out of memory", true); return; } kdc->task = task; /* get a samdb connection */ kdc->samdb = samdb_connect(kdc, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(kdc->task->lp_ctx), NULL, 0); if (!kdc->samdb) { DEBUG(1,("kdc_task_init: unable to connect to samdb\n")); task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true); return; } ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc); if (ldb_ret != LDB_SUCCESS) { DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n", ldb_errstring(kdc->samdb))); task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true); return; } kdc->proxy_timeout = lpcfg_parm_int(kdc->task->lp_ctx, NULL, "kdc", "proxy timeout", 5); initialize_krb5_error_table(); ret = smb_krb5_init_context(kdc, task->lp_ctx, &kdc->smb_krb5_context); if (ret) { DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", error_message(ret))); task_server_terminate(task, "kdc: krb5_init_context failed", true); return; } krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r); ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, &kdc_config); if(ret) { task_server_terminate(task, "kdc: failed to get KDC configuration", true); return; } kdc_config->logf = (krb5_log_facility *)kdc->smb_krb5_context->pvt_log_data; kdc_config->db = talloc(kdc, struct HDB *); if (!kdc_config->db) { task_server_terminate(task, "kdc: out of memory", true); return; } kdc_config->num_db = 1; /* * This restores the behavior before * commit 255e3e18e00f717d99f3bc57c8a8895ff624f3c3 * s4:heimdal: import lorikeet-heimdal-201107150856 * (commit 48936803fae4a2fb362c79365d31f420c917b85b) * * as_use_strongest_session_key,preauth_use_strongest_session_key * and tgs_use_strongest_session_key are input to the * _kdc_find_etype() function. The old bahavior is in * the use_strongest_session_key=FALSE code path. * (The only remaining difference in _kdc_find_etype() * is the is_preauth parameter.) * * The old behavior in the _kdc_get_preferred_key() * function is use_strongest_server_key=TRUE. */ kdc_config->as_use_strongest_session_key = false; kdc_config->preauth_use_strongest_session_key = false; kdc_config->tgs_use_strongest_session_key = false; kdc_config->use_strongest_server_key = true; kdc_config->autodetect_referrals = false; /* Register hdb-samba4 hooks for use as a keytab */ kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context); if (!kdc->base_ctx) { task_server_terminate(task, "kdc: out of memory", true); return; } kdc->base_ctx->ev_ctx = task->event_ctx; kdc->base_ctx->lp_ctx = task->lp_ctx; kdc->base_ctx->msg_ctx = task->msg_ctx; status = hdb_samba4_create_kdc(kdc->base_ctx, kdc->smb_krb5_context->krb5_context, &kdc_config->db[0]); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true); return; } ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "hdb", &hdb_samba4_interface); if(ret) { task_server_terminate(task, "kdc: failed to register hdb plugin", true); return; } ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops); if(ret) { task_server_terminate(task, "kdc: failed to register keytab plugin", true); return; } kdc->keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx); if (kdc->keytab_name == NULL) { task_server_terminate(task, "kdc: Failed to set keytab name", true); return; } /* Register WinDC hooks */ ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "windc", &windc_plugin_table); if(ret) { task_server_terminate(task, "kdc: failed to register windc plugin", true); return; } ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context); if(ret) { task_server_terminate(task, "kdc: failed to init windc plugin", true); return; } ret = krb5_kdc_pkinit_config(kdc->smb_krb5_context->krb5_context, kdc_config); if(ret) { task_server_terminate(task, "kdc: failed to init kdc pkinit subsystem", true); return; } kdc->private_data = kdc_config; /* start listening on the configured network interfaces */ status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces, task->model_ops); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "kdc failed to setup interfaces", true); return; } status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, kdc_check_generic_kerberos, kdc); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "kdc failed to setup monitoring", true); return; } irpc_add_name(task->msg_ctx, "kdc_server"); }
NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r) { krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; const char *from_keytab; /* Register hdb-samba4 hooks for use as a keytab */ struct samba_kdc_base_context *base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context); if (!base_ctx) { return NT_STATUS_NO_MEMORY; } base_ctx->ev_ctx = ctx->event_ctx; base_ctx->lp_ctx = ctx->lp_ctx; from_keytab = talloc_asprintf(base_ctx, "HDB:samba4&%p", base_ctx); if (!from_keytab) { return NT_STATUS_NO_MEMORY; } ret = smb_krb5_init_context(ctx, ctx->event_ctx, ctx->lp_ctx, &smb_krb5_context); if (ret) { return NT_STATUS_NO_MEMORY; } ret = krb5_plugin_register(smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "hdb", &hdb_samba4_interface); if(ret) { return NT_STATUS_NO_MEMORY; } ret = krb5_kt_register(smb_krb5_context->krb5_context, &hdb_kt_ops); if(ret) { return NT_STATUS_NO_MEMORY; } if (r->in.principal) { /* TODO: Find a way not to have to use a fixed list */ krb5_enctype enctypes[] = { KRB5_ENCTYPE_DES_CBC_CRC, KRB5_ENCTYPE_DES_CBC_MD5, KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 }; ret = kt_copy_one_principal(smb_krb5_context->krb5_context, from_keytab, r->in.keytab_name, r->in.principal, 0, enctypes); } else { unlink(r->in.keytab_name); ret = kt_copy(smb_krb5_context->krb5_context, from_keytab, r->in.keytab_name); } if(ret) { r->out.error_string = smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx); if (ret == KRB5_KT_NOTFOUND) { return NT_STATUS_NO_SUCH_USER; } else { return NT_STATUS_UNSUCCESSFUL; } } return NT_STATUS_OK; }
static bool torture_pac_self_check(struct torture_context *tctx) { NTSTATUS nt_status; DATA_BLOB tmp_blob; struct PAC_DATA *pac_data; struct PAC_LOGON_INFO *logon_info; union netr_Validation validation; /* Generate a nice, arbitary keyblock */ uint8_t server_bytes[16]; uint8_t krbtgt_bytes[16]; krb5_keyblock server_keyblock; krb5_keyblock krbtgt_keyblock; krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; struct auth_serversupplied_info *server_info; struct auth_serversupplied_info *server_info_out; krb5_principal client_principal; time_t logon_time = time(NULL); TALLOC_CTX *mem_ctx = tctx; torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL, tctx->lp_ctx, &smb_krb5_context), "smb_krb5_init_context"); generate_random_buffer(server_bytes, 16); generate_random_buffer(krbtgt_bytes, 16); ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, server_bytes, sizeof(server_bytes), &server_keyblock); torture_assert(tctx, !ret, talloc_asprintf(tctx, "(self test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbtgt_bytes, sizeof(krbtgt_bytes), &krbtgt_keyblock); if (ret) { char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(self test) KRBTGT Keyblock encoding failed: %s", err)); } /* We need an input, and this one requires no underlying database */ nt_status = auth_anonymous_server_info(mem_ctx, lp_netbios_name(tctx->lp_ctx), &server_info); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); torture_fail(tctx, "auth_anonymous_server_info"); } ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, server_info->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); torture_fail(tctx, "krb5_parse_name_flags(norealm)"); } /* OK, go ahead and make a PAC */ ret = kerberos_create_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), server_info, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, &tmp_blob); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } dump_data(10,tmp_blob.data,tmp_blob.length); /* Now check that we can read it back (using full decode and validate) */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding failed: %s", nt_errstr(nt_status))); } /* Now check we can read it back (using Heimdal's pac parsing) */ nt_status = kerberos_pac_blob_to_server_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), tmp_blob, smb_krb5_context->krb5_context, &server_info_out); if (!dom_sid_equal(server_info->account_sid, server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC Decode resulted in *different* domain SID: %s != %s", dom_sid_string(mem_ctx, server_info->account_sid), dom_sid_string(mem_ctx, server_info_out->account_sid))); } talloc_free(server_info_out); /* Now check that we can read it back (yet again) */ nt_status = kerberos_pac_logon_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &logon_info, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding (for logon info) failed: %s", nt_errstr(nt_status))); } krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); /* And make a server info from the samba-parsed PAC */ validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding (make server info) failed: %s", nt_errstr(nt_status))); } if (!dom_sid_equal(server_info->account_sid, server_info_out->account_sid)) { torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC Decode resulted in *different* domain SID: %s != %s", dom_sid_string(mem_ctx, server_info->account_sid), dom_sid_string(mem_ctx, server_info_out->account_sid))); } return true; }
/* Check with a known 'well formed' PAC, from my test server */ static bool torture_pac_saved_check(struct torture_context *tctx) { NTSTATUS nt_status; enum ndr_err_code ndr_err; DATA_BLOB tmp_blob, validate_blob; struct PAC_DATA *pac_data, pac_data2; struct PAC_LOGON_INFO *logon_info; union netr_Validation validation; const char *pac_file, *pac_kdc_key, *pac_member_key; struct auth_serversupplied_info *server_info_out; krb5_keyblock server_keyblock; krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p; struct samr_Password *krbtgt_bytes, *krbsrv_bytes; krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; const char *principal_string; char *broken_principal_string; krb5_principal client_principal; const char *authtime_string; time_t authtime; TALLOC_CTX *mem_ctx = tctx; torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL, tctx->lp_ctx, &smb_krb5_context), "smb_krb5_init_context"); pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key", "B286757148AF7FD252C53603A150B7E7"); pac_member_key = torture_setting_string(tctx, "pac_member_key", "D217FAEAE5E6B5F95CCC94077AB8A5FC"); torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key); torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key); /* The krbtgt key in use when the above PAC was generated. * This is an arcfour-hmac-md5 key, extracted with our 'net * samdump' tool. */ if (*pac_kdc_key == 0) { krbtgt_bytes = NULL; } else { krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key); if (!krbtgt_bytes) { torture_fail(tctx, "(saved test) Could not interpret krbtgt key"); } } krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key); if (!krbsrv_bytes) { torture_fail(tctx, "(saved test) Could not interpret krbsrv key"); } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash), &server_keyblock); torture_assert(tctx, !ret, talloc_asprintf(tctx, "(saved test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); if (krbtgt_bytes) { ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash), &krbtgt_keyblock); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } krbtgt_keyblock_p = &krbtgt_keyblock; } else { krbtgt_keyblock_p = NULL; } pac_file = torture_setting_string(tctx, "pac_file", NULL); if (pac_file) { tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx); torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file); } else { tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac)); } dump_data(10,tmp_blob.data,tmp_blob.length); principal_string = torture_setting_string(tctx, "pac_client_principal", "[email protected]"); authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609"); authtime = strtoull(authtime_string, NULL, 0); ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) parsing of client principal [%s] failed: %s", principal_string, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } /* Decode and verify the signaure on the PAC */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding failed: %s", nt_errstr(nt_status))); } /* Now check we can read it back (using Heimdal's pac parsing) */ nt_status = kerberos_pac_blob_to_server_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), tmp_blob, smb_krb5_context->krb5_context, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Heimdal PAC decoding failed: %s", nt_errstr(nt_status))); } if (!pac_file && !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"), server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s", "S-1-5-21-3048156945-3961193616-3706469200-1005", dom_sid_string(mem_ctx, server_info_out->account_sid))); } talloc_free(server_info_out); /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */ nt_status = kerberos_pac_logon_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &logon_info, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding (for logon info) failed: %s", nt_errstr(nt_status))); } validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding (make server info) failed: %s", nt_errstr(nt_status))); } if (!pac_file && !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"), server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC Decode resulted in *different* domain SID: %s != %s", "S-1-5-21-3048156945-3961193616-3706469200-1005", dom_sid_string(mem_ctx, server_info_out->account_sid))); } if (krbtgt_bytes == NULL) { torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n"); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); return true; } ret = kerberos_encode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), pac_data, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, &validate_blob); if (ret != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) PAC push failed"); } dump_data(10, validate_blob.data, validate_blob.length); /* compare both the length and the data bytes after a * pull/push cycle. This ensures we use the exact same * pointer, padding etc algorithms as win2k3. */ if (tmp_blob.length != validate_blob.length) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]", (unsigned)tmp_blob.length, (unsigned)validate_blob.length)); } if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("tmp_data:\n")); dump_data(0, tmp_blob.data, tmp_blob.length); DEBUG(0, ("validate_blob:\n")); dump_data(0, validate_blob.data, validate_blob.length); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length)); } ret = kerberos_create_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), server_info_out, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, &validate_blob); if (ret != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) regnerated PAC create failed"); } dump_data(10,validate_blob.data,validate_blob.length); /* compare both the length and the data bytes after a * pull/push cycle. This ensures we use the exact same * pointer, padding etc algorithms as win2k3. */ if (tmp_blob.length != validate_blob.length) { ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data2, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); nt_status = ndr_map_error2ntstatus(ndr_err); torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC"); NDR_PRINT_DEBUG(PAC_DATA, pac_data); NDR_PRINT_DEBUG(PAC_DATA, &pac_data2); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]", (unsigned)tmp_blob.length, (unsigned)validate_blob.length)); } if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) { ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data2, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); nt_status = ndr_map_error2ntstatus(ndr_err); torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC"); NDR_PRINT_DEBUG(PAC_DATA, pac_data); NDR_PRINT_DEBUG(PAC_DATA, &pac_data2); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("tmp_data:\n")); dump_data(0, tmp_blob.data, tmp_blob.length); DEBUG(0, ("validate_blob:\n")); dump_data(0, validate_blob.data, validate_blob.length); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length)); } /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime + 1, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)"); } /* Break the client principal */ krb5_free_principal(smb_krb5_context->krb5_context, client_principal); broken_principal_string = talloc_strdup(mem_ctx, principal_string); broken_principal_string[0]++; ret = krb5_parse_name(smb_krb5_context->krb5_context, broken_principal_string, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) parsing of broken client principal failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal"); } /* Finally... Bugger up the signature, and check we fail the checksum */ tmp_blob.data[tmp_blob.length - 2]++; nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum"); } krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); return true; }
static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) { struct gensec_gssapi_state *gensec_gssapi_state; krb5_error_code ret; #ifdef SAMBA4_USES_HEIMDAL const char *realm; #endif gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state); if (!gensec_gssapi_state) { return NT_STATUS_NO_MEMORY; } gensec_security->private_data = gensec_gssapi_state; gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT; /* TODO: Fill in channel bindings */ gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; gensec_gssapi_state->server_name = GSS_C_NO_NAME; gensec_gssapi_state->client_name = GSS_C_NO_NAME; gensec_gssapi_state->gss_want_flags = 0; gensec_gssapi_state->expire_time = GENSEC_EXPIRE_TIME_INFINITY; if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation_by_kdc_policy", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_POLICY_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "mutual", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_MUTUAL_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "replay", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_REPLAY_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "sequence", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_SEQUENCE_FLAG; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG; } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG; gensec_gssapi_state->gss_want_flags |= GSS_C_CONF_FLAG; } if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) { gensec_gssapi_state->gss_want_flags |= GSS_C_DCE_STYLE; } gensec_gssapi_state->gss_got_flags = 0; switch (gensec_security->ops->auth_type) { case DCERPC_AUTH_TYPE_SPNEGO: gensec_gssapi_state->gss_oid = gss_mech_spnego; break; case DCERPC_AUTH_TYPE_KRB5: default: gensec_gssapi_state->gss_oid = discard_const_p(void, gss_mech_krb5); break; } ret = smb_krb5_init_context(gensec_gssapi_state, gensec_security->settings->lp_ctx, &gensec_gssapi_state->smb_krb5_context); if (ret) { DEBUG(1,("gensec_gssapi_start: smb_krb5_init_context failed (%s)\n", error_message(ret))); talloc_free(gensec_gssapi_state); return NT_STATUS_INTERNAL_ERROR; } gensec_gssapi_state->client_cred = NULL; gensec_gssapi_state->server_cred = NULL; gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL; gensec_gssapi_state->sasl = false; gensec_gssapi_state->sasl_state = STAGE_GSS_NEG; gensec_gssapi_state->sasl_protection = 0; gensec_gssapi_state->max_wrap_buf_size = gensec_setting_int(gensec_security->settings, "gensec_gssapi", "max wrap buf size", 65536); gensec_gssapi_state->gss_exchange_count = 0; gensec_gssapi_state->sig_size = 0; talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor); #ifdef SAMBA4_USES_HEIMDAL realm = lpcfg_realm(gensec_security->settings->lp_ctx); if (realm != NULL) { ret = gsskrb5_set_default_realm(realm); if (ret) { DEBUG(1,("gensec_gssapi_start: gsskrb5_set_default_realm failed\n")); talloc_free(gensec_gssapi_state); return NT_STATUS_INTERNAL_ERROR; } } /* don't do DNS lookups of any kind, it might/will fail for a netbios name */ ret = gsskrb5_set_dns_canonicalize(gensec_setting_bool(gensec_security->settings, "krb5", "set_dns_canonicalize", false)); if (ret) { DEBUG(1,("gensec_gssapi_start: gsskrb5_set_dns_canonicalize failed\n")); talloc_free(gensec_gssapi_state); return NT_STATUS_INTERNAL_ERROR; } #endif return NT_STATUS_OK; }
WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, const char *name, struct drsuapi_DsNameInfo1 *info1) { krb5_error_code ret; const char *domain_filter = NULL; const char *result_filter = NULL; struct ldb_dn *name_dn = NULL; struct smb_krb5_context *smb_krb5_context = NULL; info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; info1->dns_domain_name = NULL; info1->result_name = NULL; if (!name) { return WERR_INVALID_PARAM; } /* TODO: - fill the correct names in all cases! * - handle format_flags */ /* here we need to set the domain_filter and/or the result_filter */ switch (format_offered) { case DRSUAPI_DS_NAME_FORMAT_UNKNOWN: { int i; enum drsuapi_DsNameFormat formats[] = { DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL, DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY, DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL, DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY, DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX }; WERROR werr; for (i=0; i < ARRAY_SIZE(formats); i++) { werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1); if (!W_ERROR_IS_OK(werr)) { return werr; } if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) { return werr; } } return werr; } case DRSUAPI_DS_NAME_FORMAT_CANONICAL: case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: { char *str, *s, *account; if (strlen(name) == 0) { info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } str = talloc_strdup(mem_ctx, name); W_ERROR_HAVE_NO_MEMORY(str); if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) { /* Look backwards for the \n, and replace it with / */ s = strrchr(str, '\n'); if (!s) { info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } s[0] = '/'; } s = strchr(str, '/'); if (!s) { /* there must be at least one / */ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } s[0] = '\0'; s++; domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))", ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str))); W_ERROR_HAVE_NO_MEMORY(domain_filter); /* There may not be anything after the domain component (search for the domain itself) */ if (s[0]) { account = strrchr(s, '/'); if (!account) { account = s; } else { account++; } account = ldb_binary_encode_string(mem_ctx, account); W_ERROR_HAVE_NO_MEMORY(account); result_filter = talloc_asprintf(mem_ctx, "(name=%s)", account); W_ERROR_HAVE_NO_MEMORY(result_filter); } break; } case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: { char *p; char *domain; const char *account = NULL; domain = talloc_strdup(mem_ctx, name); W_ERROR_HAVE_NO_MEMORY(domain); p = strchr(domain, '\\'); if (!p) { /* invalid input format */ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } p[0] = '\0'; if (p[1]) { account = &p[1]; } domain_filter = talloc_asprintf(mem_ctx, "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", ldb_binary_encode_string(mem_ctx, domain)); W_ERROR_HAVE_NO_MEMORY(domain_filter); if (account) { result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)", ldb_binary_encode_string(mem_ctx, account)); W_ERROR_HAVE_NO_MEMORY(result_filter); } talloc_free(domain); break; } /* A LDAP DN as a string */ case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: { domain_filter = NULL; name_dn = ldb_dn_new(mem_ctx, sam_ctx, name); if (! ldb_dn_validate(name_dn)) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } break; } /* A GUID as a string */ case DRSUAPI_DS_NAME_FORMAT_GUID: { struct GUID guid; char *ldap_guid; NTSTATUS nt_status; domain_filter = NULL; nt_status = GUID_from_string(name, &guid); if (!NT_STATUS_IS_OK(nt_status)) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid); if (!ldap_guid) { return WERR_NOMEM; } result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)", ldap_guid); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } case DRSUAPI_DS_NAME_FORMAT_DISPLAY: { domain_filter = NULL; result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))", ldb_binary_encode_string(mem_ctx, name), ldb_binary_encode_string(mem_ctx, name)); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } /* A S-1234-5678 style string */ case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: { struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name); char *ldap_sid; domain_filter = NULL; if (!sid) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx, sid); if (!ldap_sid) { return WERR_NOMEM; } result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", ldap_sid); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: { krb5_principal principal; char *unparsed_name; ret = smb_krb5_init_context(mem_ctx, ldb_get_event_context(sam_ctx), (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), &smb_krb5_context); if (ret) { return WERR_NOMEM; } /* Ensure we reject compleate junk first */ ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal); if (ret) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } domain_filter = NULL; /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */ ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name); if (ret) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } krb5_free_principal(smb_krb5_context->krb5_context, principal); /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))", ldb_binary_encode_string(mem_ctx, unparsed_name)); free(unparsed_name); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: { krb5_principal principal; char *unparsed_name_short; char *service; ret = smb_krb5_init_context(mem_ctx, ldb_get_event_context(sam_ctx), (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), &smb_krb5_context); if (ret) { return WERR_NOMEM; } ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal); if (ret == 0 && principal->name.name_string.len < 2) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_OK; } ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal); if (ret) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return dns_domain_from_principal(mem_ctx, smb_krb5_context, name, info1); } domain_filter = NULL; ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short); if (ret) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } service = principal->name.name_string.val[0]; if ((principal->name.name_string.len == 2) && (strcasecmp(service, "host") == 0)) { /* the 'cn' attribute is just the leading part of the name */ char *computer_name; computer_name = talloc_strndup(mem_ctx, principal->name.name_string.val[1], strcspn(principal->name.name_string.val[1], ".")); if (computer_name == NULL) { return WERR_NOMEM; } result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))", ldb_binary_encode_string(mem_ctx, unparsed_name_short), ldb_binary_encode_string(mem_ctx, computer_name)); } else { result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))", ldb_binary_encode_string(mem_ctx, unparsed_name_short)); } krb5_free_principal(smb_krb5_context->krb5_context, principal); free(unparsed_name_short); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } default: { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } } if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) { return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired, name_dn, name, info1); } return DsCrackNameOneFilter(sam_ctx, mem_ctx, smb_krb5_context, format_flags, format_offered, format_desired, name_dn, name, domain_filter, result_filter, info1); }
/* called to initialise the driver */ _PUBLIC_ isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata, ...) { struct dlz_bind9_data *state; const char *helper_name; va_list ap; isc_result_t result; struct ldb_dn *dn; NTSTATUS nt_status; state = talloc_zero(NULL, struct dlz_bind9_data); if (state == NULL) { return ISC_R_NOMEMORY; } talloc_set_destructor(state, dlz_state_debug_unregister); /* fill in the helper functions */ va_start(ap, dbdata); while ((helper_name = va_arg(ap, const char *)) != NULL) { b9_add_helper(state, helper_name, va_arg(ap, void*)); } va_end(ap); /* Do not install samba signal handlers */ fault_setup_disable(); /* Start logging (to the bind9 logs) */ debug_set_callback(state, b9_debug); state->ev_ctx = s4_event_context_init(state); if (state->ev_ctx == NULL) { result = ISC_R_NOMEMORY; goto failed; } result = parse_options(state, argc, argv, &state->options); if (result != ISC_R_SUCCESS) { goto failed; } state->lp = loadparm_init_global(true); if (state->lp == NULL) { result = ISC_R_NOMEMORY; goto failed; } if (state->options.debug) { lpcfg_do_global_parameter(state->lp, "log level", state->options.debug); } else { lpcfg_do_global_parameter(state->lp, "log level", "0"); } if (smb_krb5_init_context(state, state->ev_ctx, state->lp, &state->smb_krb5_ctx) != 0) { result = ISC_R_NOMEMORY; goto failed; } nt_status = gensec_init(); if (!NT_STATUS_IS_OK(nt_status)) { result = ISC_R_NOMEMORY; goto failed; } state->auth_context = talloc_zero(state, struct auth4_context); if (state->auth_context == NULL) { result = ISC_R_NOMEMORY; goto failed; } if (state->options.url == NULL) { state->options.url = lpcfg_private_path(state, state->lp, "dns/sam.ldb"); if (state->options.url == NULL) { result = ISC_R_NOMEMORY; goto failed; } } state->samdb = samdb_connect_url(state, state->ev_ctx, state->lp, system_session(state->lp), 0, state->options.url); if (state->samdb == NULL) { state->log(ISC_LOG_ERROR, "samba_dlz: Failed to connect to %s", state->options.url); result = ISC_R_FAILURE; goto failed; } dn = ldb_get_default_basedn(state->samdb); if (dn == NULL) { state->log(ISC_LOG_ERROR, "samba_dlz: Unable to get basedn for %s - %s", state->options.url, ldb_errstring(state->samdb)); result = ISC_R_FAILURE; goto failed; } state->log(ISC_LOG_INFO, "samba_dlz: started for DN %s", ldb_dn_get_linearized(dn)); state->auth_context->event_ctx = state->ev_ctx; state->auth_context->lp_ctx = state->lp; state->auth_context->sam_ctx = state->samdb; state->auth_context->generate_session_info_pac = b9_generate_session_info_pac; *dbdata = state; return ISC_R_SUCCESS; failed: talloc_free(state); return result; }