summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-11-07 02:29:37 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:45:52 -0500
commit918c7634c21deb0aa89388bb3d9e147bfc8576c8 (patch)
tree4c56c62cda7f8f72f3eb808e26029c87f8479ef0 /source4
parentf7ca7308490c5bb41c6e42e7fe52f6b2586d3d5d (diff)
downloadsamba-918c7634c21deb0aa89388bb3d9e147bfc8576c8.tar.gz
samba-918c7634c21deb0aa89388bb3d9e147bfc8576c8.tar.bz2
samba-918c7634c21deb0aa89388bb3d9e147bfc8576c8.zip
r11543: A major upgrade to our KDC and PAC handling.
We now put the PAC in the AS-REP, so that the client has it in the TGT. We then validate it (and re-sign it) on a TGS-REQ, ie when the client wants a ticket. This should also allow us to interop with windows KDCs. If we get an invalid PAC at the TGS stage, we just drop it. I'm slowly trying to move the application logic out of hdb-ldb.c, and back in with the rest of Samba's auth system, for consistancy. This continues that trend. Andrew Bartlett (This used to be commit 36973b1eef7db5983cce76ba241e54d5f925c69c)
Diffstat (limited to 'source4')
-rw-r--r--source4/auth/auth_sam.c70
-rw-r--r--source4/auth/gensec/gensec_gssapi.c2
-rw-r--r--source4/auth/gensec/gensec_krb5.c2
-rw-r--r--source4/auth/kerberos/kerberos.h6
-rw-r--r--source4/auth/kerberos/kerberos_pac.c32
-rw-r--r--source4/heimdal/kdc/kerberos5.c108
-rw-r--r--source4/heimdal/lib/hdb/hdb.h11
-rw-r--r--source4/heimdal/lib/krb5/krb5-private.h8
-rw-r--r--source4/heimdal/lib/krb5/mk_req.c2
-rw-r--r--source4/heimdal/lib/krb5/ticket.c27
-rw-r--r--source4/kdc/hdb-ldb.c131
-rw-r--r--source4/kdc/pac-glue.c317
-rw-r--r--source4/kdc/pac-glue.h52
-rw-r--r--source4/torture/auth/pac.c15
14 files changed, 545 insertions, 238 deletions
diff --git a/source4/auth/auth_sam.c b/source4/auth/auth_sam.c
index 58adb60a5f..56e61ea2a3 100644
--- a/source4/auth/auth_sam.c
+++ b/source4/auth/auth_sam.c
@@ -151,8 +151,8 @@ static NTSTATUS authsam_password_ok(struct auth_context *auth_context,
NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
struct ldb_context *sam_ctx,
uint32_t logon_parameters,
- struct ldb_message **msgs,
- struct ldb_message **msgs_domain_ref,
+ struct ldb_message *msg,
+ struct ldb_message *msg_domain_ref,
const char *logon_workstation,
const char *name_for_logs)
{
@@ -162,20 +162,20 @@ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
NTTIME must_change_time;
NTTIME last_set_time;
- struct ldb_dn *domain_dn = samdb_result_dn(mem_ctx, msgs_domain_ref[0], "nCName", ldb_dn_new(mem_ctx));
+ struct ldb_dn *domain_dn = samdb_result_dn(mem_ctx, msg_domain_ref, "nCName", ldb_dn_new(mem_ctx));
NTTIME now;
DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
- acct_flags = samdb_result_acct_flags(msgs[0], "userAccountControl");
+ acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
- acct_expiry = samdb_result_nttime(msgs[0], "accountExpires", 0);
+ acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
- domain_dn, msgs[0],
+ domain_dn, msg,
"pwdLastSet");
- last_set_time = samdb_result_nttime(msgs[0], "pwdLastSet", 0);
+ last_set_time = samdb_result_nttime(msg, "pwdLastSet", 0);
- workstation_list = samdb_result_string(msgs[0], "userWorkstations", NULL);
+ workstation_list = samdb_result_string(msg, "userWorkstations", NULL);
/* Quit if the account was disabled. */
if (acct_flags & ACB_DISABLED) {
@@ -412,17 +412,17 @@ static NTSTATUS authsam_authenticate(struct auth_context *auth_context,
nt_status = authsam_account_ok(mem_ctx, sam_ctx,
user_info->logon_parameters,
- msgs,
- msgs_domain_ref,
+ msgs[0],
+ msgs_domain_ref[0],
user_info->workstation_name,
user_info->mapped.account_name);
return nt_status;
}
-static NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
- struct ldb_message **msgs,
- struct ldb_message **msgs_domain,
+NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
+ struct ldb_message *msg,
+ struct ldb_message *msg_domain_ref,
DATA_BLOB user_sess_key, DATA_BLOB lm_sess_key,
struct auth_serversupplied_info **_server_info)
{
@@ -443,7 +443,7 @@ static NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context
group_ret = gendb_search(sam_ctx,
tmp_ctx, NULL, &group_msgs, group_attrs,
"(&(member=%s)(sAMAccountType=*))",
- ldb_dn_linearize(tmp_ctx, msgs[0]->dn));
+ ldb_dn_linearize(tmp_ctx, msg->dn));
if (group_ret == -1) {
talloc_free(tmp_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
@@ -466,13 +466,13 @@ static NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context
talloc_free(tmp_ctx);
- account_sid = samdb_result_dom_sid(server_info, msgs[0], "objectSid");
+ account_sid = samdb_result_dom_sid(server_info, msg, "objectSid");
NT_STATUS_HAVE_NO_MEMORY(account_sid);
primary_group_sid = dom_sid_dup(server_info, account_sid);
NT_STATUS_HAVE_NO_MEMORY(primary_group_sid);
- rid = samdb_result_uint(msgs[0], "primaryGroupID", ~0);
+ rid = samdb_result_uint(msg, "primaryGroupID", ~0);
if (rid == ~0) {
if (group_ret > 0) {
primary_group_sid = groupSIDs[0];
@@ -489,49 +489,49 @@ static NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context
server_info->n_domain_groups = group_ret;
server_info->domain_groups = groupSIDs;
- server_info->account_name = talloc_steal(server_info, samdb_result_string(msgs[0], "sAMAccountName", NULL));
+ server_info->account_name = talloc_steal(server_info, samdb_result_string(msg, "sAMAccountName", NULL));
- server_info->domain_name = talloc_steal(server_info, samdb_result_string(msgs_domain[0], "nETBIOSName", NULL));
+ server_info->domain_name = talloc_steal(server_info, samdb_result_string(msg_domain_ref, "nETBIOSName", NULL));
- str = samdb_result_string(msgs[0], "displayName", "");
+ str = samdb_result_string(msg, "displayName", "");
server_info->full_name = talloc_strdup(server_info, str);
NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
- str = samdb_result_string(msgs[0], "scriptPath", "");
+ str = samdb_result_string(msg, "scriptPath", "");
server_info->logon_script = talloc_strdup(server_info, str);
NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
- str = samdb_result_string(msgs[0], "profilePath", "");
+ str = samdb_result_string(msg, "profilePath", "");
server_info->profile_path = talloc_strdup(server_info, str);
NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
- str = samdb_result_string(msgs[0], "homeDirectory", "");
+ str = samdb_result_string(msg, "homeDirectory", "");
server_info->home_directory = talloc_strdup(server_info, str);
NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
- str = samdb_result_string(msgs[0], "homeDrive", "");
+ str = samdb_result_string(msg, "homeDrive", "");
server_info->home_drive = talloc_strdup(server_info, str);
NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
server_info->logon_server = talloc_strdup(server_info, lp_netbios_name());
NT_STATUS_HAVE_NO_MEMORY(server_info->logon_server);
- server_info->last_logon = samdb_result_nttime(msgs[0], "lastLogon", 0);
- server_info->last_logoff = samdb_result_nttime(msgs[0], "lastLogoff", 0);
- server_info->acct_expiry = samdb_result_nttime(msgs[0], "accountExpires", 0);
- server_info->last_password_change = samdb_result_nttime(msgs[0], "pwdLastSet", 0);
+ server_info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
+ server_info->last_logoff = samdb_result_nttime(msg, "lastLogoff", 0);
+ server_info->acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
+ server_info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0);
- ncname = samdb_result_dn(mem_ctx, msgs_domain[0], "nCName", ldb_dn_new(mem_ctx));
+ ncname = samdb_result_dn(mem_ctx, msg_domain_ref, "nCName", ldb_dn_new(mem_ctx));
server_info->allow_password_change = samdb_result_allow_password_change(sam_ctx, mem_ctx,
- ncname, msgs[0], "pwdLastSet");
+ ncname, msg, "pwdLastSet");
server_info->force_password_change = samdb_result_force_password_change(sam_ctx, mem_ctx,
- ncname, msgs[0], "pwdLastSet");
+ ncname, msg, "pwdLastSet");
- server_info->logon_count = samdb_result_uint(msgs[0], "logonCount", 0);
- server_info->bad_password_count = samdb_result_uint(msgs[0], "badPwdCount", 0);
+ server_info->logon_count = samdb_result_uint(msg, "logonCount", 0);
+ server_info->bad_password_count = samdb_result_uint(msg, "badPwdCount", 0);
- server_info->acct_flags = samdb_result_acct_flags(msgs[0], "userAccountControl");
+ server_info->acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
server_info->user_session_key = user_sess_key;
server_info->lm_session_key = lm_sess_key;
@@ -614,7 +614,7 @@ NTSTATUS sam_get_server_info_principal(TALLOC_CTX *mem_ctx, const char *principa
return nt_status;
}
- nt_status = authsam_make_server_info(mem_ctx, sam_ctx, msgs, msgs_domain_ref,
+ nt_status = authsam_make_server_info(mem_ctx, sam_ctx, msgs[0], msgs_domain_ref[0],
user_sess_key, lm_sess_key,
server_info);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -654,7 +654,7 @@ static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx
&user_sess_key, &lm_sess_key);
NT_STATUS_NOT_OK_RETURN(nt_status);
- nt_status = authsam_make_server_info(mem_ctx, sam_ctx, msgs, domain_ref_msgs,
+ nt_status = authsam_make_server_info(mem_ctx, sam_ctx, msgs[0], domain_ref_msgs[0],
user_sess_key, lm_sess_key,
server_info);
NT_STATUS_NOT_OK_RETURN(nt_status);
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 08e2298c1a..c8a57234e3 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -891,7 +891,7 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
/* decode and verify the pac */
nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
gensec_gssapi_state->smb_krb5_context->krb5_context,
- NULL, keyblock, principal, authtime);
+ NULL, keyblock, principal, authtime, NULL);
krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
if (NT_STATUS_IS_OK(nt_status)) {
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index d5a2fd9a8f..c8640dde8c 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -521,7 +521,7 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
gensec_krb5_state->smb_krb5_context->krb5_context,
NULL, gensec_krb5_state->keyblock,
client_principal,
- gensec_krb5_state->ticket->ticket.authtime);
+ gensec_krb5_state->ticket->ticket.authtime, NULL);
krb5_free_principal(context, client_principal);
if (NT_STATUS_IS_OK(nt_status)) {
diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h
index 9813290650..46bf300229 100644
--- a/source4/auth/kerberos/kerberos.h
+++ b/source4/auth/kerberos/kerberos.h
@@ -137,7 +137,8 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
krb5_keyblock *krbtgt_keyblock,
krb5_keyblock *service_keyblock,
krb5_const_principal client_principal,
- time_t tgs_authtime);
+ time_t tgs_authtime,
+ krb5_error_code *k5ret);
NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx,
struct PAC_LOGON_INFO **logon_info,
DATA_BLOB blob,
@@ -145,7 +146,8 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
krb5_keyblock *krbtgt_keyblock,
krb5_keyblock *service_keyblock,
krb5_const_principal client_principal,
- time_t tgs_authtime);
+ time_t tgs_authtime,
+ krb5_error_code *k5ret);
krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
struct PAC_DATA *pac_data,
krb5_context context,
diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c
index 9be9df133a..55805f0c4a 100644
--- a/source4/auth/kerberos/kerberos_pac.c
+++ b/source4/auth/kerberos/kerberos_pac.c
@@ -74,7 +74,8 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
krb5_keyblock *krbtgt_keyblock,
krb5_keyblock *service_keyblock,
krb5_const_principal client_principal,
- time_t tgs_authtime)
+ time_t tgs_authtime,
+ krb5_error_code *k5ret)
{
krb5_error_code ret;
NTSTATUS status;
@@ -87,19 +88,28 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
struct PAC_DATA *pac_data;
struct PAC_DATA_RAW *pac_data_raw;
- DATA_BLOB *srv_sig_blob;
- DATA_BLOB *kdc_sig_blob;
+ DATA_BLOB *srv_sig_blob = NULL;
+ DATA_BLOB *kdc_sig_blob = NULL;
DATA_BLOB modified_pac_blob;
NTTIME tgs_authtime_nttime;
krb5_principal client_principal_pac;
int i;
+ krb5_clear_error_string(context);
+
+ if (k5ret) {
+ *k5ret = KRB5_PARSE_MALFORMED;
+ }
+
pac_data = talloc(mem_ctx, struct PAC_DATA);
pac_data_raw = talloc(mem_ctx, struct PAC_DATA_RAW);
kdc_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
srv_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) {
+ if (k5ret) {
+ *k5ret = ENOMEM;
+ }
return NT_STATUS_NO_MEMORY;
}
@@ -242,6 +252,9 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
if (ret) {
DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n",
smb_get_krb5_error_message(context, ret, mem_ctx)));
+ if (k5ret) {
+ *k5ret = ret;
+ }
return NT_STATUS_ACCESS_DENIED;
}
@@ -252,6 +265,9 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
if (ret) {
DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n",
smb_get_krb5_error_message(context, ret, mem_ctx)));
+ if (k5ret) {
+ *k5ret = ret;
+ }
return NT_STATUS_ACCESS_DENIED;
}
}
@@ -271,6 +287,9 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n",
logon_name->account_name,
smb_get_krb5_error_message(context, ret, mem_ctx)));
+ if (k5ret) {
+ *k5ret = ret;
+ }
return NT_STATUS_INVALID_PARAMETER;
}
@@ -302,19 +321,20 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
krb5_keyblock *krbtgt_keyblock,
krb5_keyblock *service_keyblock,
krb5_const_principal client_principal,
- time_t tgs_authtime)
+ time_t tgs_authtime,
+ krb5_error_code *k5ret)
{
NTSTATUS nt_status;
struct PAC_DATA *pac_data;
int i;
-
nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
blob,
context,
krbtgt_keyblock,
service_keyblock,
client_principal,
- tgs_authtime);
+ tgs_authtime,
+ k5ret);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
index 0df090eef3..a1a607329a 100644
--- a/source4/heimdal/kdc/kerberos5.c
+++ b/source4/heimdal/kdc/kerberos5.c
@@ -32,9 +32,6 @@
*/
#include "kdc_locl.h"
-#ifdef _SAMBA_BUILD_
-#include "kdc/pac-glue.h"
-#endif
RCSID("$Id: kerberos5.c,v 1.177 2005/06/15 11:34:53 lha Exp $");
@@ -1355,6 +1352,18 @@ _kdc_as_rep(krb5_context context,
rep.padata = NULL;
}
+ /* Add the PAC, via a HDB abstraction */
+ if (client->authz_data_as_req) {
+ ret = client->authz_data_as_req(context, client,
+ req->padata,
+ et.authtime,
+ &skey->key,
+ &et.key,
+ &et.authorization_data);
+ if (ret)
+ goto out;
+ }
+
log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime,
et.endtime, et.renew_till);
@@ -1640,7 +1649,7 @@ tgs_make_reply(krb5_context context,
EncTicketPart *adtkt,
AuthorizationData *auth_data,
krb5_ticket *tgs_ticket,
- hdb_entry *server,
+ hdb_entry_ex *server,
hdb_entry *client,
krb5_principal client_principal,
hdb_entry *krbtgt,
@@ -1657,6 +1666,7 @@ tgs_make_reply(krb5_context context,
krb5_enctype etype;
Key *skey;
EncryptionKey *ekey;
+ AuthorizationData *new_auth_data = NULL;
if(adtkt) {
int i;
@@ -1674,7 +1684,7 @@ tgs_make_reply(krb5_context context,
etype = b->etype.val[i];
}else{
ret = find_keys(context, config,
- NULL, server, NULL, NULL, &skey, &etype,
+ NULL, &server->entry, NULL, NULL, &skey, &etype,
b->etype.val, b->etype.len);
if(ret) {
kdc_log(context, config, 0, "Server has no support for etypes");
@@ -1728,14 +1738,14 @@ tgs_make_reply(krb5_context context,
GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
&tgt->transited, &et,
*krb5_princ_realm(context, client_principal),
- *krb5_princ_realm(context, server->principal),
+ *krb5_princ_realm(context, server->entry.principal),
*krb5_princ_realm(context, krbtgt->principal));
if(ret)
goto out;
- copy_Realm(krb5_princ_realm(context, server->principal),
+ copy_Realm(krb5_princ_realm(context, server->entry.principal),
&rep.ticket.realm);
- _krb5_principal2principalname(&rep.ticket.sname, server->principal);
+ _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal);
copy_Realm(&tgt->crealm, &rep.crealm);
if (f.request_anonymous)
make_anonymous_principalname (&tgt->cname);
@@ -1752,8 +1762,8 @@ tgs_make_reply(krb5_context context,
life = et.endtime - *et.starttime;
if(client && client->max_life)
life = min(life, *client->max_life);
- if(server->max_life)
- life = min(life, *server->max_life);
+ if(server->entry.max_life)
+ life = min(life, *server->entry.max_life);
et.endtime = *et.starttime + life;
}
if(f.renewable_ok && tgt->flags.renewable &&
@@ -1767,8 +1777,8 @@ tgs_make_reply(krb5_context context,
renew = *et.renew_till - et.authtime;
if(client && client->max_renew)
renew = min(renew, *client->max_renew);
- if(server->max_renew)
- renew = min(renew, *server->max_renew);
+ if(server->entry.max_renew)
+ renew = min(renew, *server->entry.max_renew);
*et.renew_till = et.authtime + renew;
}
@@ -1793,61 +1803,28 @@ tgs_make_reply(krb5_context context,
et.flags.pre_authent = tgt->flags.pre_authent;
et.flags.hw_authent = tgt->flags.hw_authent;
et.flags.anonymous = tgt->flags.anonymous;
- et.flags.ok_as_delegate = server->flags.ok_as_delegate;
+ et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
-#ifdef _SAMBA_BUILD_
-
- {
-
- unsigned char *buf;
- size_t buf_size;
- size_t len;
-
- krb5_data pac;
- AD_IF_RELEVANT *if_relevant;
- ALLOC(if_relevant);
- if_relevant->len = 1;
- if_relevant->val = malloc(sizeof(*if_relevant->val));
- 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;
-
- /* Get PAC from Samba */
- ret = samba_get_pac(context, config,
- client->principal,
- tgtkey,
- ekey,
- tgs_ticket->ticket.authtime,
- &pac);
- if (ret) {
- free_AuthorizationData(if_relevant);
- goto out;
- }
-
- /* 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;
+
+ krb5_generate_random_keyblock(context, etype, &et.key);
- ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, if_relevant, &len, ret);
- free_AuthorizationData(if_relevant);
-
- auth_data = NULL;
- ALLOC(auth_data);
- auth_data->len = 1;
- auth_data->val = malloc(sizeof(*auth_data->val));
- 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;
+ if (server->authz_data_tgs_req) {
+ ret = server->authz_data_tgs_req(context, server,
+ client_principal,
+ tgs_ticket->ticket.authorization_data,
+ tgs_ticket->ticket.authtime,
+ tgtkey,
+ ekey,
+ &et.key,
+ &new_auth_data);
if (ret) {
- goto out;
+ new_auth_data = NULL;
}
}
-#endif
/* XXX Check enc-authorization-data */
- et.authorization_data = auth_data;
+ et.authorization_data = new_auth_data;
- krb5_generate_random_keyblock(context, etype, &et.key);
et.crealm = tgt->crealm;
et.cname = tgt->cname;
@@ -1878,7 +1855,7 @@ tgs_make_reply(krb5_context context,
etype list, even if we don't want a session key with
DES3? */
ret = encode_reply(context, config,
- &rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
+ &rep, &et, &ek, etype, adtkt ? 0 : server->entry.kvno, ekey,
0, &tgt->key, e_text, reply);
out:
free_TGS_REP(&rep);
@@ -2228,7 +2205,8 @@ tgs_rep2(krb5_context context,
PrincipalName *s;
Realm r;
char *spn = NULL, *cpn = NULL;
- hdb_entry *server = NULL, *client = NULL;
+ hdb_entry_ex *server = NULL;
+ hdb_entry *client = NULL;
int nloop = 0;
EncTicketPart adtkt;
char opt_str[128];
@@ -2295,7 +2273,7 @@ tgs_rep2(krb5_context context,
kdc_log(context, config, 0,
"TGS-REQ %s from %s for %s", cpn, from, spn);
server_lookup:
- ret = _kdc_db_fetch(context, config, sp, HDB_ENT_TYPE_SERVER, &server);
+ ret = _kdc_db_fetch_ex(context, config, sp, HDB_ENT_TYPE_SERVER, &server);
if(ret){
const char *new_rlm;
@@ -2376,7 +2354,7 @@ tgs_rep2(krb5_context context,
ret = _kdc_check_flags(context, config,
client, cpn,
- server, spn,
+ &server->entry, spn,
FALSE);
if(ret)
goto out;
@@ -2384,7 +2362,7 @@ tgs_rep2(krb5_context context,
if((b->kdc_options.validate || b->kdc_options.renew) &&
!krb5_principal_compare(context,
krbtgt->principal,
- server->principal)){
+ server->entry.principal)){
kdc_log(context, config, 0, "Inconsistent request.");
ret = KRB5KDC_ERR_SERVER_NOMATCH;
goto out;
@@ -2417,7 +2395,7 @@ tgs_rep2(krb5_context context,
free(cpn);
if(server)
- _kdc_free_ent(context, server);
+ _kdc_free_ent_ex(context, server);
if(client)
_kdc_free_ent(context, client);
}
diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h
index 41cc03cf36..45ea5a9f30 100644
--- a/source4/heimdal/lib/hdb/hdb.h
+++ b/source4/heimdal/lib/hdb/hdb.h
@@ -61,14 +61,19 @@ typedef struct hdb_entry_ex {
krb5_error_code (*free_private)(krb5_context, struct hdb_entry_ex *);
krb5_error_code (*check_client_access)(krb5_context, struct hdb_entry_ex *, HostAddresses *);
krb5_error_code (*authz_data_as_req)(krb5_context, struct hdb_entry_ex *,
- AuthorizationData *in,
+ METHOD_DATA* pa_data_seq,
+ time_t authtime,
EncryptionKey *tgtkey,
- AuthorizationData *out);
+ EncryptionKey *sessionkey,
+ AuthorizationData **out);
krb5_error_code (*authz_data_tgs_req)(krb5_context, struct hdb_entry_ex *,
+ krb5_principal client,
AuthorizationData *in,
+ time_t authtime,
EncryptionKey *tgtkey,
EncryptionKey *servicekey,
- AuthorizationData *out);
+ EncryptionKey *sessionkey,
+ AuthorizationData **out);
} hdb_entry_ex;
typedef struct HDB{
diff --git a/source4/heimdal/lib/krb5/krb5-private.h b/source4/heimdal/lib/krb5/krb5-private.h
index 07d9329337..2645c29fe7 100644
--- a/source4/heimdal/lib/krb5/krb5-private.h
+++ b/source4/heimdal/lib/krb5/krb5-private.h
@@ -399,4 +399,12 @@ _krb5_xunlock (
krb5_context /*context*/,
int /*fd*/);
+int
+_krb5_find_type_in_ad(krb5_context context,
+ int type,
+ krb5_data *data,
+ int *found,
+ krb5_keyblock *sessionkey,
+ const AuthorizationData *ad);
+
#endif /* __krb5_private_h__ */
diff --git a/source4/heimdal/lib/krb5/mk_req.c b/source4/heimdal/lib/krb5/mk_req.c
index adc077e13f..44e5d9c222 100644
--- a/source4/heimdal/lib/krb5/mk_req.c
+++ b/source4/heimdal/lib/krb5/mk_req.c
@@ -64,7 +64,9 @@ krb5_mk_req_exact(krb5_context context,
if (auth_context && *auth_context && (*auth_context)->keytype)
this_cred.session.keytype = (*auth_context)->keytype;
+ /* This is the network contact with the KDC */
ret = krb5_get_credentials (context, 0, ccache, &this_cred, &cred);
+
krb5_free_cred_contents(context, &this_cred);
if (ret)
return ret;
diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c
index 7dae26acf2..b3efeb39d3 100644
--- a/source4/heimdal/lib/krb5/ticket.c
+++ b/source4/heimdal/lib/krb5/ticket.c
@@ -101,8 +101,8 @@ static int
find_type_in_ad(krb5_context context,
int type,
krb5_data *data,
- int *found,
- int failp,
+ krb5_boolean *found,
+ krb5_boolean failp,
krb5_keyblock *sessionkey,
const AuthorizationData *ad,
int level)
@@ -129,7 +129,7 @@ find_type_in_ad(krb5_context context,
krb5_set_error_string(context, "malloc - out of memory");
goto out;
}
- *found = 1;
+ *found = TRUE;
continue;
}
switch (ad->val[i].ad_type) {
@@ -228,6 +228,19 @@ out:
return ret;
}
+int
+_krb5_find_type_in_ad(krb5_context context,
+ int type,
+ krb5_data *data,
+ krb5_boolean *found,
+ krb5_keyblock *sessionkey,
+ const AuthorizationData *ad)
+{
+ krb5_data_zero(data);
+ return find_type_in_ad(context, type, data, found, TRUE, sessionkey, ad, 0);
+}
+
+
/*
* Extract the authorization data type of `type' from the
* 'ticket'. Store the field in `data'. This function is to use for
@@ -242,9 +255,7 @@ krb5_ticket_get_authorization_data_type(krb5_context context,
{
AuthorizationData *ad;
krb5_error_code ret;
- int found = 0;
-
- krb5_data_zero(data);
+ krb5_boolean found = 0;
ad = ticket->ticket.authorization_data;
if (ticket->ticket.authorization_data == NULL) {
@@ -252,8 +263,8 @@ krb5_ticket_get_authorization_data_type(krb5_context context,
return ENOENT; /* XXX */
}
- ret = find_type_in_ad(context, type, data, &found, 1, &ticket->ticket.key,
- ticket->ticket.authorization_data, 0);
+ ret = _krb5_find_type_in_ad(context, type, data, &found, &ticket->ticket.key,
+ ticket->ticket.authorization_data);
if (ret)
return ret;
if (!found) {
diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c
index 87e8273898..8b61914dae 100644
--- a/source4/kdc/hdb-ldb.c
+++ b/source4/kdc/hdb-ldb.c
@@ -73,12 +73,6 @@ static const char *realm_ref_attrs[] = {
NULL
};
-struct hdb_ldb_private {
- struct ldb_context *samdb;
- struct ldb_message **msg;
- struct ldb_message **realm_ref_msg;
-};
-
static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, KerberosTime default_val)
{
const char *tmp;
@@ -177,13 +171,10 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h
if (userAccountControl & UF_SMARTCARD_REQUIRED) {
flags.require_hwauth = 1;
}
- if (flags.server && (userAccountControl & UF_TRUSTED_FOR_DELEGATION)) {
- flags.forwardable = 1;
- flags.proxiable = 1;
- } else if (flags.client && (userAccountControl & UF_NOT_DELEGATED)) {
- flags.forwardable = 0;
- flags.proxiable = 0;
- } else {
+ if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
+ flags.ok_as_delegate = 1;
+ }
+ if (!(userAccountControl & UF_NOT_DELEGATED)) {
flags.forwardable = 1;
flags.proxiable = 1;
}
@@ -205,6 +196,12 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h
return flags;
}
+static krb5_error_code hdb_ldb_free_private(krb5_context context, hdb_entry_ex *entry_ex)
+{
+ talloc_free(entry_ex->private);
+ return 0;
+}
+
/*
* Construct an hdb_entry from a directory entry.
*/
@@ -213,15 +210,17 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db,
enum hdb_ldb_ent_type ent_type,
struct ldb_message *msg,
struct ldb_message *realm_ref_msg,
- hdb_entry *ent)
+ hdb_entry_ex *entry_ex)
{
const char *unicodePwd;
- int userAccountControl;
+ unsigned int userAccountControl;
int i;
krb5_error_code ret = 0;
const char *dnsdomain = ldb_msg_find_string(realm_ref_msg, "dnsRoot", NULL);
char *realm = strupper_talloc(mem_ctx, dnsdomain);
+ struct hdb_ldb_private *private;
+ hdb_entry *ent = &entry_ex->entry;
memset(ent, 0, sizeof(*ent));
@@ -233,7 +232,7 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db,
goto out;
}
- userAccountControl = ldb_msg_find_int(msg, "userAccountControl", 0);
+ userAccountControl = ldb_msg_find_uint(msg, "userAccountControl", 0);
ent->principal = malloc(sizeof(*(ent->principal)));
if (ent_type == HDB_LDB_ENT_TYPE_ANY && principal == NULL) {
@@ -279,6 +278,7 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db,
if (ent_type == HDB_LDB_ENT_TYPE_KRBTGT) {
ent->flags.invalid = 0;
ent->flags.server = 1;
+ ent->flags.forwardable = 1;
}
if (lp_parm_bool(-1, "kdc", "require spn for service", True)) {
@@ -399,7 +399,7 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db,
} else {
ret = krb5_data_alloc (&keyvalue, 16);
if (ret) {
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_clear_error_string(context);
ret = ENOMEM;
goto out;
}
@@ -409,7 +409,7 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db,
ent->keys.val = malloc(sizeof(ent->keys.val[0]));
if (ent->keys.val == NULL) {
krb5_data_free(&keyvalue);
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_clear_error_string(context);
ret = ENOMEM;
goto out;
}
@@ -425,14 +425,14 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db,
ent->etypes = malloc(sizeof(*(ent->etypes)));
if (ent->etypes == NULL) {
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_clear_error_string(context);
ret = ENOMEM;
goto out;
}
ent->etypes->len = ent->keys.len;
ent->etypes->val = calloc(ent->etypes->len, sizeof(int));
if (ent->etypes->val == NULL) {
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_clear_error_string(context);
ret = ENOMEM;
goto out;
}
@@ -440,10 +440,27 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db,
ent->etypes->val[i] = ent->keys.val[i].key.keytype;
}
+
+ private = talloc(db, struct hdb_ldb_private);
+ if (!private) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ private->msg = talloc_steal(private, msg);
+ private->realm_ref_msg = talloc_steal(private, realm_ref_msg);
+ private->samdb = (struct ldb_context *)db->hdb_db;
+
+ entry_ex->private = private;
+ entry_ex->free_private = hdb_ldb_free_private;
+ 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) {
- /* I don't think this frees ent itself. */
- hdb_free_entry(context, ent);
+ /* This doesn't free ent itself, that is for the eventual caller to do */
+ hdb_free_entry(context, &entry_ex->entry);
}
return ret;
@@ -618,44 +635,6 @@ static krb5_error_code LDB_rename(krb5_context context, HDB *db, const char *new
return HDB_ERR_DB_INUSE;
}
-static krb5_error_code hdb_ldb_free_private(krb5_context context, hdb_entry_ex *entry_ex)
-{
- talloc_free(entry_ex->private);
- return 0;
-}
-
-static krb5_error_code hdb_ldb_check_client_access(krb5_context context, hdb_entry_ex *entry_ex,
- HostAddresses *addresses)
-{
- krb5_error_code ret;
- NTSTATUS nt_status;
- TALLOC_CTX *tmp_ctx = talloc_new(entry_ex->private);
- struct hdb_ldb_private *private = entry_ex->private;
- char *name, *workstation = NULL;
- if (!tmp_ctx) {
- return ENOMEM;
- }
-
- ret = krb5_unparse_name(context, entry_ex->entry.principal, &name);
- if (ret != 0) {
- talloc_free(tmp_ctx);
- }
- nt_status = authsam_account_ok(tmp_ctx,
- private->samdb,
- MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
- private->msg,
- private->realm_ref_msg,
- workstation,
- name);
- free(name);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- return KRB5KDC_ERR_POLICY;
- }
- return 0;
-}
-
-
static krb5_error_code LDB_fetch_ex(krb5_context context, HDB *db, unsigned flags,
krb5_const_principal principal,
enum hdb_ent_type ent_type,
@@ -703,22 +682,7 @@ static krb5_error_code LDB_fetch_ex(krb5_context context, HDB *db, unsigned flag
ret = LDB_message2entry(context, db, mem_ctx,
principal, ldb_ent_type,
- msg[0], realm_ref_msg[0], &entry_ex->entry);
-
- if (ret == 0) {
- struct hdb_ldb_private *private = talloc(db, struct hdb_ldb_private);
- if (!private) {
- hdb_free_entry(context, &entry_ex->entry);
- ret = ENOMEM;
- }
- private->msg = talloc_steal(private, msg);
- private->realm_ref_msg = talloc_steal(private, realm_ref_msg);
- private->samdb = (struct ldb_context *)db->hdb_db;
-
- entry_ex->private = private;
- entry_ex->free_private = hdb_ldb_free_private;
- entry_ex->check_client_access = hdb_ldb_check_client_access;
- }
+ msg[0], realm_ref_msg[0], entry_ex);
talloc_free(mem_ctx);
return ret;
@@ -802,7 +766,7 @@ static krb5_error_code LDB_fetch_ex(krb5_context context, HDB *db, unsigned flag
ret = LDB_message2entry(context, db, mem_ctx,
principal, ldb_ent_type,
- msg[0], realm_ref_msg[0], &entry_ex->entry);
+ msg[0], realm_ref_msg[0], entry_ex);
talloc_free(mem_ctx);
return ret;
@@ -845,7 +809,7 @@ static krb5_error_code LDB_fetch_ex(krb5_context context, HDB *db, unsigned flag
} else {
ret = LDB_message2entry(context, db, mem_ctx,
principal, ldb_ent_type,
- msg[0], realm_ref_msg[0], &entry_ex->entry);
+ msg[0], realm_ref_msg[0], entry_ex);
if (ret != 0) {
krb5_warnx(context, "LDB_fetch: message2entry failed\n");
}
@@ -898,6 +862,9 @@ static krb5_error_code LDB_seq(krb5_context context, HDB *db, unsigned flags, hd
krb5_error_code ret;
struct hdb_ldb_seq *priv = (struct hdb_ldb_seq *)db->hdb_openp;
TALLOC_CTX *mem_ctx;
+ hdb_entry_ex entry_ex;
+ memset(&entry_ex, '\0', sizeof(entry_ex));
+
if (!priv) {
return HDB_ERR_NOENTRY;
}
@@ -913,7 +880,13 @@ static krb5_error_code LDB_seq(krb5_context context, HDB *db, unsigned flags, hd
ret = LDB_message2entry(context, db, mem_ctx,
NULL, HDB_LDB_ENT_TYPE_ANY,
priv->msgs[priv->index++],
- priv->realm_ref_msgs[0], entry);
+ priv->realm_ref_msgs[0], &entry_ex);
+ if (ret == 0) {
+ if (entry_ex.free_private) {
+ entry_ex.free_private(context, &entry_ex);
+ }
+ *entry = entry_ex.entry;
+ }
} else {
ret = HDB_ERR_NOENTRY;
}
diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c
index ae306b4062..03b53fa3af 100644
--- a/source4/kdc/pac-glue.c
+++ b/source4/kdc/pac-glue.c
@@ -23,42 +23,41 @@
#include "includes.h"
#include "kdc/kdc.h"
-#include "kdc/pac-glue.h" /* Ensure we don't get this prototype wrong, as that could be painful */
-
- krb5_error_code samba_get_pac(krb5_context context,
- struct krb5_kdc_configuration *config,
- krb5_principal client,
- krb5_keyblock *krbtgt_keyblock,
- krb5_keyblock *server_keyblock,
- time_t tgs_authtime,
- krb5_data *pac)
+#include "include/ads.h"
+#include "lib/ldb/include/ldb.h"
+#include "heimdal/lib/krb5/krb5_locl.h"
+#include "librpc/gen_ndr/krb5pac.h"
+#include "auth/auth.h"
+
+/* 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,
+ krb5_keyblock *krbtgt_keyblock,
+ krb5_keyblock *server_keyblock,
+ time_t tgs_authtime,
+ krb5_data *pac)
{
krb5_error_code ret;
NTSTATUS nt_status;
struct auth_serversupplied_info *server_info;
DATA_BLOB tmp_blob;
- char *principal_string;
- TALLOC_CTX *mem_ctx = talloc_named(config, 0, "samba_get_pac context");
+ TALLOC_CTX *mem_ctx = talloc_named(private, 0, "samba_get_pac context");
+
if (!mem_ctx) {
return ENOMEM;
}
- ret = krb5_unparse_name(context, client, &principal_string);
-
- if (ret != 0) {
- krb5_set_error_string(context, "get pac: could not unparse principal");
- krb5_warnx(context, "get pac: could not unparse principal");
- talloc_free(mem_ctx);
- return ret;
- }
-
- nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
- &server_info);
- free(principal_string);
+ 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 EINVAL;
+ return ENOMEM;
}
ret = kerberos_create_pac(mem_ctx, server_info,
@@ -80,3 +79,273 @@
talloc_free(mem_ctx);
return ret;
}
+
+/* Wrap the PAC in the right ASN.1. Will always free 'pac', on success or failure */
+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;
+ }
+
+ 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;
+ 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;
+}
+
+
+/* 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,
+ EncryptionKey *tgtkey,
+ EncryptionKey *sessionkey,
+ AuthorizationData **out)
+{
+ krb5_error_code ret;
+ int i;
+ krb5_data pac;
+ krb5_boolean pac_wanted = TRUE;
+ unsigned int userAccountControl;
+ struct PA_PAC_REQUEST pac_request;
+ struct hdb_ldb_private *private = talloc_get_type(entry_ex->private, struct hdb_ldb_private);
+
+ /* The user account may be set not to want the PAC */
+ userAccountControl = ldb_msg_find_uint(private->msg, "userAccountControl", 0);
+ if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
+ *out = 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;
+ }
+ }
+
+ 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);
+}
+
+/* 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,
+ EncryptionKey *tgtkey,
+ EncryptionKey *servicekey,
+ EncryptionKey *sessionkey,
+ AuthorizationData **out)
+{
+ NTSTATUS nt_status;
+ krb5_error_code ret;
+
+ unsigned int userAccountControl;
+
+ struct hdb_ldb_private *private = talloc_get_type(entry_ex->private, struct hdb_ldb_private);
+ krb5_data k5pac_in, k5pac_out;
+ DATA_BLOB pac_in, pac_out;
+
+ struct PAC_LOGON_INFO *logon_info;
+ union netr_Validation validation;
+ struct auth_serversupplied_info *server_info_out;
+
+ krb5_boolean found = FALSE;
+ TALLOC_CTX *mem_ctx;
+
+ /* The service account may be set not to want the PAC */
+ userAccountControl = ldb_msg_find_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;
+ return 0;
+ }
+
+ mem_ctx = talloc_new(private);
+ if (!mem_ctx) {
+ krb5_data_free(&k5pac_in);
+ *out = NULL;
+ return ENOMEM;
+ }
+
+ 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)));
+ talloc_free(mem_ctx);
+ *out = NULL;
+ return ret;
+ }
+
+ /* Pull this right into the normal auth sysstem structures */
+ 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)) {
+ 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);
+
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ *out = NULL;
+ return ret;
+ }
+
+ 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);
+}
+
+/* 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 ret;
+ NTSTATUS nt_status;
+ TALLOC_CTX *tmp_ctx = talloc_new(entry_ex->private);
+ struct hdb_ldb_private *private = talloc_get_type(entry_ex->private, struct hdb_ldb_private);
+ char *name, *workstation = NULL;
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = krb5_unparse_name(context, entry_ex->entry.principal, &name);
+ if (ret != 0) {
+ talloc_free(tmp_ctx);
+ }
+ nt_status = authsam_account_ok(tmp_ctx,
+ private->samdb,
+ MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
+ private->msg,
+ private->realm_ref_msg,
+ workstation,
+ name);
+ free(name);
+
+ /* TODO: Need a more complete mapping of NTSTATUS to krb5kdc errors */
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return KRB5KDC_ERR_POLICY;
+ }
+ return 0;
+}
+
diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h
index 69490bb7f3..953ddae815 100644
--- a/source4/kdc/pac-glue.h
+++ b/source4/kdc/pac-glue.h
@@ -1,8 +1,46 @@
+/*
+ Unix SMB/CIFS implementation.
- krb5_error_code samba_get_pac(krb5_context context,
- struct krb5_kdc_configuration *config,
- krb5_principal client,
- krb5_keyblock *krbtgt_keyblock,
- krb5_keyblock *server_keyblock,
- time_t tgs_authtime,
- krb5_data *pac);
+ 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;
+ };
+
+ 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,
+ EncryptionKey *tgtkey,
+ 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,
+ EncryptionKey *tgtkey,
+ EncryptionKey *servicekey,
+ EncryptionKey *sessionkey,
+ AuthorizationData **out);
+ krb5_error_code hdb_ldb_check_client_access(krb5_context context, hdb_entry_ex *entry_ex,
+ HostAddresses *addresses);
diff --git a/source4/torture/auth/pac.c b/source4/torture/auth/pac.c
index 221454280e..0674d55574 100644
--- a/source4/torture/auth/pac.c
+++ b/source4/torture/auth/pac.c
@@ -147,7 +147,7 @@ static BOOL torture_pac_self_check(void)
&krbtgt_keyblock,
&server_keyblock,
client_principal,
- logon_time);
+ logon_time, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
@@ -170,7 +170,8 @@ static BOOL torture_pac_self_check(void)
&krbtgt_keyblock,
&server_keyblock,
client_principal,
- logon_time);
+ logon_time,
+ NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
@@ -398,7 +399,7 @@ static BOOL torture_pac_saved_check(void)
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
&server_keyblock,
- client_principal, authtime);
+ client_principal, authtime, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("(saved test) PAC decoding failed: %s\n",
nt_errstr(nt_status)));
@@ -419,7 +420,7 @@ static BOOL torture_pac_saved_check(void)
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
&server_keyblock,
- client_principal, authtime);
+ client_principal, authtime, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
@@ -612,7 +613,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock,
&server_keyblock,
client_principal,
- authtime + 1);
+ authtime + 1, NULL);
if (NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)\n"));
@@ -648,7 +649,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock,
&server_keyblock,
client_principal,
- authtime);
+ authtime, NULL);
if (NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("(saved test) PAC decoding DID NOT fail on modified principal\n"));
@@ -669,7 +670,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock,
&server_keyblock,
client_principal,
- authtime);
+ authtime, NULL);
if (NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("(saved test) PAC decoding DID NOT fail on broken checksum\n"));