diff options
Diffstat (limited to 'source4/kdc')
-rw-r--r-- | source4/kdc/config.mk | 1 | ||||
-rw-r--r-- | source4/kdc/hdb-ldb.c | 8 | ||||
-rw-r--r-- | source4/kdc/kdc.c | 34 | ||||
-rw-r--r-- | source4/kdc/kdc.h | 12 | ||||
-rw-r--r-- | source4/kdc/pac-glue.c | 316 | ||||
-rw-r--r-- | source4/kdc/pac-glue.h | 47 |
6 files changed, 153 insertions, 265 deletions
diff --git a/source4/kdc/config.mk b/source4/kdc/config.mk index 5632ddc795..07a3a58ce9 100644 --- a/source4/kdc/config.mk +++ b/source4/kdc/config.mk @@ -17,6 +17,7 @@ PUBLIC_DEPENDENCIES = \ # Start SUBSYSTEM KDC [SUBSYSTEM::HDB_LDB] CFLAGS = -Iheimdal/kdc -Iheimdal/lib/hdb +PUBLIC_PROTO_HEADER = pac_glue.h OBJ_FILES = \ hdb-ldb.o \ pac-glue.o diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c index a05295205b..ff15772f73 100644 --- a/source4/kdc/hdb-ldb.c +++ b/source4/kdc/hdb-ldb.c @@ -434,10 +434,6 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db, private->realm_ref_msg = talloc_steal(private, realm_ref_msg); private->samdb = (struct ldb_context *)db->hdb_db; - entry_ex->check_client_access = hdb_ldb_check_client_access; - entry_ex->authz_data_tgs_req = hdb_ldb_authz_data_tgs_req; - entry_ex->authz_data_as_req = hdb_ldb_authz_data_as_req; - out: if (ret != 0) { /* This doesn't free ent itself, that is for the eventual caller to do */ @@ -1029,8 +1025,8 @@ NTSTATUS kdc_hdb_ldb_create(TALLOC_CTX *mem_ctx, krb5_error_code hdb_ldb_create(krb5_context context, struct HDB **db, const char *arg) { NTSTATUS nt_status; - /* Disgusting, ugly hack, but it means one less private hook */ - nt_status = kdc_hdb_ldb_create(context->mem_ctx, context, db, arg); + /* The global kdc_mem_ctx, Disgusting, ugly hack, but it means one less private hook */ + nt_status = kdc_hdb_ldb_create(kdc_mem_ctx, context, db, arg); if (NT_STATUS_IS_OK(nt_status)) { return 0; diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c index ce7c1f57cb..64911a0988 100644 --- a/source4/kdc/kdc.c +++ b/source4/kdc/kdc.c @@ -36,6 +36,13 @@ #include "lib/stream/packet.h" #include "librpc/gen_ndr/samr.h" #include "lib/socket/netif.h" +#include "heimdal/kdc/windc_plugin.h" +#include "heimdal/lib/krb5/krb5_locl.h" +#include "heimdal/kdc/kdc_locl.h" + + +/* Disgusting hack to get a mem_ctx into the hdb plugin, when used as a keytab */ +TALLOC_CTX *kdc_mem_ctx; /* hold all the info needed to send a reply */ struct kdc_reply { @@ -527,6 +534,16 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc) return NT_STATUS_OK; } +static struct krb5plugin_windc_ftable windc_plugin_table = { + .minor_version = KRB5_WINDC_PLUGING_MINOR, + .init = samba_kdc_plugin_init, + .fini = samba_kdc_plugin_fini, + .pac_generate = samba_kdc_get_pac, + .pac_verify = samba_kdc_reget_pac, + .client_access = samba_kdc_check_client_access, +}; + + /* startup the kdc task */ @@ -571,6 +588,9 @@ static void kdc_task_init(struct task_server *task) } krb5_kdc_default_config(kdc->config); + kdc->config->enable_pkinit = lp_parm_bool(-1, "kdc", "pkinit", True); + kdc->config->enable_pkinit_princ_in_cert = lp_parm_bool(-1, "kdc", "pkinit_princ_in_cert", True); + initialize_krb5_error_table(); ret = smb_krb5_init_context(kdc, &kdc->smb_krb5_context); @@ -603,6 +623,20 @@ static void kdc_task_init(struct task_server *task) task_server_terminate(task, "kdc: failed to register hdb keytab"); return; } + + kdc_mem_ctx = kdc->smb_krb5_context; + + /* Registar 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 hdb keytab"); + return; + } + + _kdc_windc_init(kdc->smb_krb5_context->krb5_context); + /* start listening on the configured network interfaces */ status = kdc_startup_interfaces(kdc); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/kdc/kdc.h b/source4/kdc/kdc.h index 9cd51f1d97..31d8fbb035 100644 --- a/source4/kdc/kdc.h +++ b/source4/kdc/kdc.h @@ -25,13 +25,13 @@ #include "auth/kerberos/kerberos.h" #include "heimdal/kdc/kdc.h" #include "heimdal/lib/hdb/hdb.h" -#include "kdc/pac-glue.h" +#include "kdc/pac_glue.h" struct kdc_server; struct socket_address; -NTSTATUS kdc_hdb_ldb_create(TALLOC_CTX *mem_ctx, - krb5_context context, struct HDB **db, const char *arg); +extern TALLOC_CTX *kdc_mem_ctx; + BOOL kpasswdd_process(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, DATA_BLOB *input, @@ -50,3 +50,9 @@ struct kdc_server { }; +struct hdb_ldb_private { + struct ldb_context *samdb; + struct ldb_message *msg; + struct ldb_message *realm_ref_msg; + hdb_entry_ex *entry_ex; +}; diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index da920c5fd6..e7db7e7aad 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -25,6 +25,7 @@ #include "kdc/kdc.h" #include "dsdb/common/flags.h" #include "lib/ldb/include/ldb.h" +#include "librpc/gen_ndr/ndr_krb5pac.h" #include "librpc/gen_ndr/krb5pac.h" #include "auth/auth.h" #include "auth/auth_sam.h" @@ -32,303 +33,200 @@ struct krb5_dh_moduli; struct _krb5_krb_auth_data; -#include "heimdal/lib/krb5/krb5_locl.h" +krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr) +{ + *ptr = NULL; + return 0; +} -/* Given the right private pointer from hdb_ldb, get a PAC from the attached ldb messages */ -static krb5_error_code samba_get_pac(krb5_context context, - struct hdb_ldb_private *private, - krb5_principal client, - const krb5_keyblock *krbtgt_keyblock, - const krb5_keyblock *server_keyblock, - time_t tgs_authtime, - krb5_data *pac) +void samba_kdc_plugin_fini(void *ptr) { - krb5_error_code ret; + return; +} + +static krb5_error_code make_pac(krb5_context context, + TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *server_info, + krb5_pac *pac) +{ + struct PAC_LOGON_INFO_CTR logon_info; + struct netr_SamInfo3 *info3; + krb5_data pac_data; NTSTATUS nt_status; - struct auth_serversupplied_info *server_info; - DATA_BLOB tmp_blob; - TALLOC_CTX *mem_ctx = talloc_named(private, 0, "samba_get_pac context"); + DATA_BLOB pac_out; + krb5_error_code ret; + + ZERO_STRUCT(logon_info); + + nt_status = auth_convert_server_info_saminfo3(mem_ctx, server_info, &info3); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status))); + return EINVAL; + } + logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO); if (!mem_ctx) { return ENOMEM; } - nt_status = authsam_make_server_info(mem_ctx, private->samdb, - private->msg, - private->realm_ref_msg, - data_blob(NULL, 0), - data_blob(NULL, 0), - &server_info); + logon_info.info->info3 = *info3; + + nt_status = ndr_push_struct_blob(&pac_out, mem_ctx, &logon_info, + (ndr_push_flags_fn_t)ndr_push_PAC_LOGON_INFO_CTR); if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("Getting user info for PAC failed: %s\n", - nt_errstr(nt_status))); - return ENOMEM; + DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status))); + return EINVAL; } - ret = kerberos_create_pac(mem_ctx, server_info, - context, - krbtgt_keyblock, - server_keyblock, - client, - tgs_authtime, - &tmp_blob); - - if (ret) { - DEBUG(1, ("PAC encoding failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - talloc_free(mem_ctx); + ret = krb5_data_copy(&pac_data, pac_out.data, pac_out.length); + if (ret != 0) { return ret; } - ret = krb5_data_copy(pac, tmp_blob.data, tmp_blob.length); - talloc_free(mem_ctx); - return ret; -} - -/* Wrap the PAC in the right ASN.1. Will always free 'pac', on success or failure */ -static krb5_error_code wrap_pac(krb5_context context, krb5_data *pac, AuthorizationData **out) -{ - krb5_error_code ret; - - unsigned char *buf; - size_t buf_size; - size_t len; - - AD_IF_RELEVANT if_relevant; - AuthorizationData *auth_data; - - if_relevant.len = 1; - if_relevant.val = malloc(sizeof(*if_relevant.val)); - if (!if_relevant.val) { - krb5_data_free(pac); - *out = NULL; - return ENOMEM; + ret = krb5_pac_init(context, pac); + if (ret != 0) { + krb5_data_free(&pac_data); + return ret; } - if_relevant.val[0].ad_type = KRB5_AUTHDATA_WIN2K_PAC; - if_relevant.val[0].ad_data.data = NULL; - if_relevant.val[0].ad_data.length = 0; - - /* pac.data will be freed with this */ - if_relevant.val[0].ad_data.data = pac->data; - if_relevant.val[0].ad_data.length = pac->length; - - ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, &if_relevant, &len, ret); - free_AuthorizationData(&if_relevant); - if (ret) { - *out = NULL; - return ret; - } - - auth_data = malloc(sizeof(*auth_data)); - if (!auth_data) { - free(buf); - *out = NULL; - return ret; - } - auth_data->len = 1; - auth_data->val = malloc(sizeof(*auth_data->val)); - if (!auth_data->val) { - free(buf); - free(auth_data); - *out = NULL; + ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &pac_data); + krb5_data_free(&pac_data); + if (ret != 0) { return ret; } - auth_data->val[0].ad_type = KRB5_AUTHDATA_IF_RELEVANT; - auth_data->val[0].ad_data.length = len; - auth_data->val[0].ad_data.data = buf; - *out = auth_data; - return 0; + return ret; } - -/* Given a hdb_entry, create a PAC out of the private data - - Don't create it if the client has the UF_NO_AUTH_DATA_REQUIRED bit - set, or if they specificaly asked not to get it. -*/ - -krb5_error_code hdb_ldb_authz_data_as_req(krb5_context context, struct hdb_entry_ex *entry_ex, - METHOD_DATA* pa_data_seq, - time_t authtime, - const EncryptionKey *tgtkey, - const EncryptionKey *sessionkey, - AuthorizationData **out) +/* Given the right private pointer from hdb_ldb, get a PAC from the attached ldb messages */ +krb5_error_code samba_kdc_get_pac(void *priv, + krb5_context context, + struct hdb_entry_ex *client, + krb5_pac *pac) { krb5_error_code ret; - int i; - krb5_data pac; - krb5_boolean pac_wanted = TRUE; + NTSTATUS nt_status; + struct auth_serversupplied_info *server_info; + struct hdb_ldb_private *private = talloc_get_type(client->ctx, struct hdb_ldb_private); + TALLOC_CTX *mem_ctx = talloc_named(private, 0, "samba_get_pac context"); unsigned int userAccountControl; - struct PA_PAC_REQUEST pac_request; - struct hdb_ldb_private *private = talloc_get_type(entry_ex->ctx, struct hdb_ldb_private); - + + if (!mem_ctx) { + return ENOMEM; + } + /* The user account may be set not to want the PAC */ userAccountControl = ldb_msg_find_attr_as_uint(private->msg, "userAccountControl", 0); if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) { - *out = NULL; + *pac = NULL; return 0; } - /* The user may not want a PAC */ - for (i=0; i<pa_data_seq->len; i++) { - if (pa_data_seq->val[i].padata_type == KRB5_PADATA_PA_PAC_REQUEST) { - ret = decode_PA_PAC_REQUEST(pa_data_seq->val[i].padata_value.data, - pa_data_seq->val[i].padata_value.length, - &pac_request, NULL); - if (ret == 0) { - pac_wanted = !!pac_request.include_pac; - } - free_PA_PAC_REQUEST(&pac_request); - break; - } + nt_status = authsam_make_server_info(mem_ctx, private->samdb, + private->msg, + private->realm_ref_msg, + data_blob(NULL, 0), + data_blob(NULL, 0), + &server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("Getting user info for PAC failed: %s\n", + nt_errstr(nt_status))); + return ENOMEM; } - if (!pac_wanted) { - *out = NULL; - return 0; - } - - /* Get PAC from Samba */ - ret = samba_get_pac(context, - private, - entry_ex->entry.principal, - tgtkey, - tgtkey, - authtime, - &pac); - - if (ret) { - *out = NULL; - return ret; - } - - return wrap_pac(context, &pac, out); + ret = make_pac(context, mem_ctx, server_info, pac); + + talloc_free(mem_ctx); + return ret; } /* Resign (and reform, including possibly new groups) a PAC */ -krb5_error_code hdb_ldb_authz_data_tgs_req(krb5_context context, struct hdb_entry_ex *entry_ex, - krb5_principal client, - AuthorizationData *in, - time_t authtime, - const EncryptionKey *tgtkey, - const EncryptionKey *servicekey, - const EncryptionKey *sessionkey, - AuthorizationData **out) +krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context, + const krb5_principal client_principal, + struct hdb_entry_ex *client, + struct hdb_entry_ex *server, krb5_pac *pac) { NTSTATUS nt_status; krb5_error_code ret; unsigned int userAccountControl; - struct hdb_ldb_private *private = talloc_get_type(entry_ex->ctx, struct hdb_ldb_private); - krb5_data k5pac_in, k5pac_out; - DATA_BLOB pac_in, pac_out; + struct hdb_ldb_private *private = talloc_get_type(server->ctx, struct hdb_ldb_private); + krb5_data k5pac_in; + DATA_BLOB pac_in; - struct PAC_LOGON_INFO *logon_info; + struct PAC_LOGON_INFO_CTR logon_info; union netr_Validation validation; struct auth_serversupplied_info *server_info_out; - krb5_boolean found = FALSE; - TALLOC_CTX *mem_ctx; + TALLOC_CTX *mem_ctx = talloc_named(private, 0, "samba_get_pac context"); + if (!mem_ctx) { + return ENOMEM; + } + /* The service account may be set not to want the PAC */ userAccountControl = ldb_msg_find_attr_as_uint(private->msg, "userAccountControl", 0); if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) { - *out = NULL; - return 0; - } - - ret = _krb5_find_type_in_ad(context, KRB5_AUTHDATA_WIN2K_PAC, - &k5pac_in, &found, sessionkey, in); - if (ret || !found) { - *out = NULL; + *pac = NULL; return 0; } - mem_ctx = talloc_new(private); - if (!mem_ctx) { - krb5_data_free(&k5pac_in); - *out = NULL; - return ENOMEM; + ret = krb5_pac_get_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &k5pac_in); + if (ret != 0) { + return ret; } pac_in = data_blob_talloc(mem_ctx, k5pac_in.data, k5pac_in.length); krb5_data_free(&k5pac_in); if (!pac_in.data) { talloc_free(mem_ctx); - *out = NULL; return ENOMEM; } - /* Parse the PAC again, for the logon info */ - nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, - pac_in, - context, - tgtkey, - tgtkey, - client, authtime, - &ret); - - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("Failed to parse PAC in TGT: %s/%s\n", - nt_errstr(nt_status), error_message(ret))); + nt_status = ndr_pull_struct_blob(&pac_in, mem_ctx, &logon_info, + (ndr_pull_flags_fn_t)ndr_pull_PAC_LOGON_INFO_CTR); + if (!NT_STATUS_IS_OK(nt_status) || !logon_info.info) { talloc_free(mem_ctx); - *out = NULL; - return ret; + DEBUG(0,("can't parse the PAC LOGON_INFO\n")); + return EINVAL; } /* Pull this right into the normal auth sysstem structures */ - validation.sam3 = &logon_info->info3; + validation.sam3 = &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(mem_ctx); - *out = NULL; return ENOMEM; } - /* And make a new PAC, possibly containing new groups */ - ret = kerberos_create_pac(mem_ctx, - server_info_out, - context, - tgtkey, - servicekey, - client, - authtime, - &pac_out); + /* We will compleatly regenerate this pac */ + krb5_pac_free(context, *pac); - if (ret != 0) { - talloc_free(mem_ctx); - *out = NULL; - return ret; - } + ret = make_pac(context, mem_ctx, server_info_out, pac); - ret = krb5_data_copy(&k5pac_out, pac_out.data, pac_out.length); - if (ret != 0) { - talloc_free(mem_ctx); - *out = NULL; - return ret; - } - - return wrap_pac(context, &k5pac_out, out); + talloc_free(mem_ctx); + return ret; } /* Given an hdb entry (and in particular it's private member), consult * the account_ok routine in auth/auth_sam.c for consistancy */ -krb5_error_code hdb_ldb_check_client_access(krb5_context context, hdb_entry_ex *entry_ex, - HostAddresses *addresses) + +krb5_error_code samba_kdc_check_client_access(void *priv, + krb5_context context, hdb_entry_ex *entry_ex, + KDC_REQ *req) { krb5_error_code ret; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(entry_ex->ctx); struct hdb_ldb_private *private = talloc_get_type(entry_ex->ctx, struct hdb_ldb_private); char *name, *workstation = NULL; + HostAddresses *addresses = req->req_body.addresses; int i; if (!tmp_ctx) { diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h deleted file mode 100644 index 1cda3e4d55..0000000000 --- a/source4/kdc/pac-glue.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - PAC Glue between Samba and the KDC - - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - struct hdb_ldb_private { - struct ldb_context *samdb; - struct ldb_message *msg; - struct ldb_message *realm_ref_msg; - hdb_entry_ex *entry_ex; - }; - - krb5_error_code hdb_ldb_authz_data_as_req(krb5_context context, struct hdb_entry_ex *entry_ex, - METHOD_DATA* pa_data_seq, - time_t authtime, - const EncryptionKey *tgtkey, - const EncryptionKey *sessionkey, - AuthorizationData **out); - - krb5_error_code hdb_ldb_authz_data_tgs_req(krb5_context context, struct hdb_entry_ex *entry_ex, - krb5_principal client, - AuthorizationData *in, - time_t authtime, - const EncryptionKey *tgtkey, - const EncryptionKey *servicekey, - const EncryptionKey *sessionkey, - AuthorizationData **out); - krb5_error_code hdb_ldb_check_client_access(krb5_context context, hdb_entry_ex *entry_ex, - HostAddresses *addresses); |