r11543: A major upgrade to our KDC and PAC handling.
authorAndrew Bartlett <abartlet@samba.org>
Mon, 7 Nov 2005 02:29:37 +0000 (02:29 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:45:52 +0000 (13:45 -0500)
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)

14 files changed:
source4/auth/auth_sam.c
source4/auth/gensec/gensec_gssapi.c
source4/auth/gensec/gensec_krb5.c
source4/auth/kerberos/kerberos.h
source4/auth/kerberos/kerberos_pac.c
source4/heimdal/kdc/kerberos5.c
source4/heimdal/lib/hdb/hdb.h
source4/heimdal/lib/krb5/krb5-private.h
source4/heimdal/lib/krb5/mk_req.c
source4/heimdal/lib/krb5/ticket.c
source4/kdc/hdb-ldb.c
source4/kdc/pac-glue.c
source4/kdc/pac-glue.h
source4/torture/auth/pac.c

index 58adb60a5f5fad8fd527d1fc07e539847159d033..56e61ea2a30dec7b1b819f4dff8f960fff801353 100644 (file)
@@ -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);
index 08e2298c1a9d3bb631cc9342d7aacb23bf428c51..c8a57234e3b5a8f9fa4b77708577c72e1eea1f6f 100644 (file)
@@ -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)) {
index d5a2fd9a8f8a2d1c4eb6b96c44c0f04ed8a8430a..c8640dde8c66a24a183d9b22a5b70fb31af9f867 100644 (file)
@@ -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)) {
index 98132906506f775bda240c3fa12ab0789b72a751..46bf300229afb12625dd4a42a82ba17c2d45dd87 100644 (file)
@@ -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,
index 9be9df133a2bf83e6ca48346c019391851292d89..55805f0c4a5346559566ff77f3054f2b3982e44a 100644 (file)
@@ -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;
        }
index 0df090eef3fe678195f71a15fd1314a91ae21d28..a1a607329a1abd3a338fd27956b35521036835f5 100644 (file)
@@ -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);
     }
index 41cc03cf3679ed1703cf9bb4663beb99b3dbb7ff..45ea5a9f30ff7a13c70b6effebf7b35de78ca7b0 100644 (file)
@@ -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{
index 07d9329337cf712809afb3e6d9b99fbad482c85d..2645c29fe7b0f94e6df2931c752abd7c792740b6 100644 (file)
@@ -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__ */
index adc077e13fa071ffd0fbd1b1b2835b40e4401865..44e5d9c2225b29402a75674223ae598a99870ced 100644 (file)
@@ -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;
index 7dae26acf244dd5bd1a0e234989f6d591192bfab..b3efeb39d3ae25ee93938d9c75259512801cfc20 100644 (file)
@@ -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) {
index 87e82738983321dd10c0143c07d2f19da0487c44..8b61914daefb10a50fc2c4ff28f9b82f65a3567d 100644 (file)
@@ -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;
        }
index ae306b4062e7e1677926f1f677fa14cb6d27c71f..03b53fa3af07c5f30ab8b65860084d89015737ba 100644 (file)
 
 #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, 
        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;
+}
+
index 69490bb7f3cad2bb42e637b92d29a8370798f695..953ddae815f3ef03d7595cc296485f66e58e70ba 100644 (file)
@@ -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);
index 221454280eaeb08f4d1c20697a61045609f95f8a..0674d5557436ffe7013e3eb1fc3178a6d443c3e0 100644 (file)
@@ -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"));