From 73b1e1466cb3a2f3cadc2865b0226a48b3ff6f27 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 28 Jun 2011 14:46:49 +0200 Subject: s4:kdc: generate the S4U_DELEGATION_INFO in the regenerated pac metze --- source4/heimdal/kdc/krb5tgs.c | 6 +-- source4/kdc/mit_samba.c | 2 +- source4/kdc/pac-glue.c | 121 +++++++++++++++++++++++++++++++++++++++++- source4/kdc/pac-glue.h | 10 +++- source4/kdc/wdc-samba4.c | 29 ++++++++-- 5 files changed, 157 insertions(+), 11 deletions(-) (limited to 'source4') diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index f13da57e45..55d5d09ede 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -2068,10 +2068,8 @@ server_lookup: krb5_data_free(&rspac); /* - * generate the PAC for the user. - * - * TODO: pass in t->sname and t->realm and build - * a S4U_DELEGATION_INFO blob to the PAC. + * generate the PAC for the user and pass + * dp for the S4U_DELEGATION_INFO blob in the PAC. */ ret = check_PAC(context, config, tp, dp, client, server, krbtgt, diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c index 50b5d1d292..4905a19d99 100644 --- a/source4/kdc/mit_samba.c +++ b/source4/kdc/mit_samba.c @@ -255,7 +255,7 @@ static int mit_samba_update_pac_data(struct mit_samba_context *ctx, } nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context, - &pac, logon_blob); + pac, logon_blob); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Building PAC failed: %s\n", nt_errstr(nt_status))); diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index 38db41d837..e92a511d0f 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -72,9 +72,11 @@ NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx, krb5_error_code samba_make_krb5_pac(krb5_context context, DATA_BLOB *pac_blob, + DATA_BLOB *deleg_blob, krb5_pac *pac) { krb5_data pac_data; + krb5_data deleg_data; krb5_error_code ret; /* The user account may be set not to want the PAC */ @@ -87,18 +89,41 @@ krb5_error_code samba_make_krb5_pac(krb5_context context, return ret; } + ZERO_STRUCT(deleg_data); + if (deleg_blob) { + ret = krb5_data_copy(&deleg_data, + deleg_blob->data, + deleg_blob->length); + if (ret != 0) { + krb5_data_free(&pac_data); + return ret; + } + } + ret = krb5_pac_init(context, pac); if (ret != 0) { krb5_data_free(&pac_data); + krb5_data_free(&deleg_data); return ret; } ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &pac_data); krb5_data_free(&pac_data); if (ret != 0) { + krb5_data_free(&deleg_data); return ret; } + if (deleg_blob) { + ret = krb5_pac_add_buffer(context, *pac, + PAC_TYPE_CONSTRAINED_DELEGATION, + &deleg_data); + krb5_data_free(&deleg_data); + if (ret != 0) { + return ret; + } + } + return ret; } @@ -183,13 +208,13 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx, NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, krb5_context context, - krb5_pac *pac, DATA_BLOB *pac_blob) + const krb5_pac pac, DATA_BLOB *pac_blob) { struct auth_user_info_dc *user_info_dc; krb5_error_code ret; NTSTATUS nt_status; - ret = kerberos_pac_to_user_info_dc(mem_ctx, *pac, + ret = kerberos_pac_to_user_info_dc(mem_ctx, pac, context, &user_info_dc, NULL, NULL); if (ret) { return NT_STATUS_UNSUCCESSFUL; @@ -201,6 +226,98 @@ NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, return nt_status; } +NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx, + krb5_context context, + const krb5_pac pac, + const krb5_principal server_principal, + const krb5_principal proxy_principal, + DATA_BLOB *new_blob) +{ + krb5_data old_data; + DATA_BLOB old_blob; + krb5_error_code ret; + NTSTATUS nt_status; + enum ndr_err_code ndr_err; + union PAC_INFO info; + struct PAC_CONSTRAINED_DELEGATION _d; + struct PAC_CONSTRAINED_DELEGATION *d = NULL; + char *server = NULL; + char *proxy = NULL; + uint32_t i; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + if (tmp_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data); + if (ret == ENOENT) { + ZERO_STRUCT(old_data); + } else if (ret) { + talloc_free(tmp_ctx); + return NT_STATUS_UNSUCCESSFUL; + } + + old_blob.length = old_data.length; + old_blob.data = (uint8_t *)old_data.data; + + ZERO_STRUCT(info); + if (old_blob.length > 0) { + ndr_err = ndr_pull_union_blob(&old_blob, mem_ctx, + &info, PAC_TYPE_CONSTRAINED_DELEGATION, + (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + krb5_data_free(&old_data); + 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 nt_status; + } + } else { + ZERO_STRUCT(_d); + info.constrained_delegation.info = &_d; + } + krb5_data_free(&old_data); + + ret = krb5_unparse_name(context, server_principal, &server); + if (ret) { + talloc_free(tmp_ctx); + return NT_STATUS_INTERNAL_ERROR; + } + + ret = krb5_unparse_name_flags(context, proxy_principal, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &proxy); + if (ret) { + SAFE_FREE(server); + talloc_free(tmp_ctx); + return NT_STATUS_INTERNAL_ERROR; + } + + d = info.constrained_delegation.info; + i = d->num_transited_services; + d->proxy_target.string = server; + d->transited_services = talloc_realloc(mem_ctx, d->transited_services, + struct lsa_String, i + 1); + d->transited_services[i].string = proxy; + d->num_transited_services = i + 1; + + ndr_err = ndr_push_union_blob(new_blob, mem_ctx, + &info, PAC_TYPE_CONSTRAINED_DELEGATION, + (ndr_push_flags_fn_t)ndr_push_PAC_INFO); + SAFE_FREE(server); + SAFE_FREE(proxy); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + krb5_data_free(&old_data); + 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 nt_status; + } + + talloc_free(tmp_ctx); + return NT_STATUS_OK; +} + /* this function allocates 'data' using malloc. * The caller is responsible for freeing it */ void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data) diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h index c5cc661c43..66c20cdc1e 100644 --- a/source4/kdc/pac-glue.h +++ b/source4/kdc/pac-glue.h @@ -23,6 +23,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context, DATA_BLOB *pac_blob, + DATA_BLOB *deleg_blob, krb5_pac *pac); bool samba_princ_needs_pac(struct hdb_entry_ex *princ); @@ -35,7 +36,14 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx, NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, krb5_context context, - krb5_pac *pac, DATA_BLOB *pac_blob); + const krb5_pac pac, DATA_BLOB *pac_blob); + +NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx, + krb5_context context, + const krb5_pac pac, + const krb5_principal server_principal, + const krb5_principal proxy_principal, + DATA_BLOB *pac_blob); void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data); diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 56d01dbfde..99ad96a6b5 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -46,7 +46,7 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context, return EINVAL; } - ret = samba_make_krb5_pac(context, pac_blob, pac); + ret = samba_make_krb5_pac(context, pac_blob, NULL, pac); talloc_free(mem_ctx); return ret; @@ -56,6 +56,7 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context, static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, const krb5_principal client_principal, + const krb5_principal delegated_proxy_principal, struct hdb_entry_ex *client, struct hdb_entry_ex *server, struct hdb_entry_ex *krbtgt, @@ -64,6 +65,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, struct samba_kdc_entry *p = talloc_get_type(server->ctx, struct samba_kdc_entry); TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context"); DATA_BLOB *pac_blob; + DATA_BLOB *deleg_blob = NULL; krb5_error_code ret; NTSTATUS nt_status; @@ -97,7 +99,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, } nt_status = samba_kdc_update_pac_blob(mem_ctx, context, - pac, pac_blob); + *pac, pac_blob); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Building PAC failed: %s\n", nt_errstr(nt_status))); @@ -105,10 +107,31 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, return EINVAL; } } + + if (delegated_proxy_principal) { + deleg_blob = talloc_zero(mem_ctx, DATA_BLOB); + if (!deleg_blob) { + talloc_free(mem_ctx); + return ENOMEM; + } + + nt_status = samba_kdc_update_delegation_info_blob(mem_ctx, + context, *pac, + server->entry.principal, + delegated_proxy_principal, + deleg_blob); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("Building PAC failed: %s\n", + nt_errstr(nt_status))); + talloc_free(mem_ctx); + return EINVAL; + } + } + /* We now completely regenerate this pac */ krb5_pac_free(context, *pac); - ret = samba_make_krb5_pac(context, pac_blob, pac); + ret = samba_make_krb5_pac(context, pac_blob, deleg_blob, pac); talloc_free(mem_ctx); return ret; -- cgit