auth/gensec: Remove unneeded cli_credentials_set_conf() call
[nivanova/samba-autobuild/.git] / source4 / auth / gensec / gensec_gssapi.c
index 55610f57425ee69308e80e493e47f2027b070c7f..3ec1cd495d4895f4875eba9772a52fe17e94fe4e 100644 (file)
 #include "includes.h"
 #include "lib/events/events.h"
 #include "system/kerberos.h"
+#include "system/gssapi.h"
 #include "auth/kerberos/kerberos.h"
 #include "librpc/gen_ndr/krb5pac.h"
 #include "auth/auth.h"
 #include <ldb.h>
 #include "auth/auth_sam.h"
-#include "librpc/rpc/dcerpc.h"
+#include "librpc/gen_ndr/dcerpc.h"
 #include "auth/credentials/credentials.h"
 #include "auth/credentials/credentials_krb5.h"
 #include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_internal.h"
 #include "auth/gensec/gensec_proto.h"
 #include "auth/gensec/gensec_toplevel_proto.h"
 #include "param/param.h"
 #include "auth/session_proto.h"
-#include <gssapi/gssapi.h>
-#include <gssapi/gssapi_krb5.h>
-#include <gssapi/gssapi_spnego.h>
-#include "auth/gensec/gensec_gssapi.h"
+#include "gensec_gssapi.h"
 #include "lib/util/util_net.h"
+#include "auth/kerberos/pac_utils.h"
+#include "auth/kerberos/gssapi_helper.h"
+
+#ifndef gss_mech_spnego
+gss_OID_desc spnego_mech_oid_desc =
+               { 6, discard_const_p(void, "\x2b\x06\x01\x05\x05\x02") };
+#define gss_mech_spnego (&spnego_mech_oid_desc)
+#endif
 
 _PUBLIC_ NTSTATUS gensec_gssapi_init(void);
 
 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
+static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size);
 
 static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_state)
 {
-       OM_uint32 maj_stat, min_stat;
-       
+       OM_uint32 min_stat;
+
        if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
-               maj_stat = gss_release_cred(&min_stat, 
-                                           &gensec_gssapi_state->delegated_cred_handle);
+               gss_release_cred(&min_stat,
+                                &gensec_gssapi_state->delegated_cred_handle);
        }
 
        if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
-               maj_stat = gss_delete_sec_context (&min_stat,
-                                                  &gensec_gssapi_state->gssapi_context,
-                                                  GSS_C_NO_BUFFER);
+               gss_delete_sec_context(&min_stat,
+                                      &gensec_gssapi_state->gssapi_context,
+                                      GSS_C_NO_BUFFER);
        }
 
        if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
-               maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
+               gss_release_name(&min_stat,
+                                &gensec_gssapi_state->server_name);
        }
        if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
-               maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
-       }
-
-       if (gensec_gssapi_state->lucid) {
-               gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
+               gss_release_name(&min_stat,
+                                &gensec_gssapi_state->client_name);
        }
 
        return 0;
 }
 
-static NTSTATUS gensec_gssapi_init_lucid(struct gensec_gssapi_state *gensec_gssapi_state)
-{
-       OM_uint32 maj_stat, min_stat;
-
-       if (gensec_gssapi_state->lucid) {
-               return NT_STATUS_OK;
-       }
-
-       maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
-                                                    &gensec_gssapi_state->gssapi_context,
-                                                    1,
-                                                    (void **)&gensec_gssapi_state->lucid);
-       if (maj_stat != GSS_S_COMPLETE) {
-               DEBUG(0,("gensec_gssapi_init_lucid: %s\n",
-                       gssapi_error_string(gensec_gssapi_state,
-                                           maj_stat, min_stat,
-                                           gensec_gssapi_state->gss_oid)));
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       if (gensec_gssapi_state->lucid->version != 1) {
-               DEBUG(0,("gensec_gssapi_init_lucid: lucid version[%d] != 1\n",
-                       gensec_gssapi_state->lucid->version));
-               gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
-               gensec_gssapi_state->lucid = NULL;
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       return NT_STATUS_OK;
-}
-
 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 {
        struct gensec_gssapi_state *gensec_gssapi_state;
        krb5_error_code ret;
+#ifdef SAMBA4_USES_HEIMDAL
        const char *realm;
+#endif
 
        gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state);
        if (!gensec_gssapi_state) {
@@ -129,35 +106,37 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        gensec_gssapi_state->server_name = GSS_C_NO_NAME;
        gensec_gssapi_state->client_name = GSS_C_NO_NAME;
        
-       gensec_gssapi_state->want_flags = 0;
+       gensec_gssapi_state->gss_want_flags = 0;
+       gensec_gssapi_state->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
 
        if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation_by_kdc_policy", true)) {
-               gensec_gssapi_state->want_flags |= GSS_C_DELEG_POLICY_FLAG;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_POLICY_FLAG;
        }
        if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "mutual", true)) {
-               gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_MUTUAL_FLAG;
        }
-       if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation", true)) {
-               gensec_gssapi_state->want_flags |= GSS_C_DELEG_FLAG;
+       if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation", false)) {
+               gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_FLAG;
        }
        if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "replay", true)) {
-               gensec_gssapi_state->want_flags |= GSS_C_REPLAY_FLAG;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_REPLAY_FLAG;
        }
        if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "sequence", true)) {
-               gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_SEQUENCE_FLAG;
        }
 
        if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
-               gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG;
        }
        if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
-               gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_CONF_FLAG;
        }
        if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
-               gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
+               gensec_gssapi_state->gss_want_flags |= GSS_C_DCE_STYLE;
        }
 
-       gensec_gssapi_state->got_flags = 0;
+       gensec_gssapi_state->gss_got_flags = 0;
 
        switch (gensec_security->ops->auth_type) {
        case DCERPC_AUTH_TYPE_SPNEGO:
@@ -165,16 +144,16 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
                break;
        case DCERPC_AUTH_TYPE_KRB5:
        default:
-               gensec_gssapi_state->gss_oid = gss_mech_krb5;
+               gensec_gssapi_state->gss_oid =
+                       discard_const_p(void, gss_mech_krb5);
                break;
        }
 
        ret = smb_krb5_init_context(gensec_gssapi_state,
-                                   NULL,
                                    gensec_security->settings->lp_ctx,
                                    &gensec_gssapi_state->smb_krb5_context);
        if (ret) {
-               DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
+               DEBUG(1,("gensec_gssapi_start: smb_krb5_init_context failed (%s)\n",
                         error_message(ret)));
                talloc_free(gensec_gssapi_state);
                return NT_STATUS_INTERNAL_ERROR;
@@ -183,8 +162,6 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        gensec_gssapi_state->client_cred = NULL;
        gensec_gssapi_state->server_cred = NULL;
 
-       gensec_gssapi_state->lucid = NULL;
-
        gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
 
        gensec_gssapi_state->sasl = false;
@@ -198,11 +175,12 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 
        talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor);
 
+#ifdef SAMBA4_USES_HEIMDAL
        realm = lpcfg_realm(gensec_security->settings->lp_ctx);
        if (realm != NULL) {
                ret = gsskrb5_set_default_realm(realm);
                if (ret) {
-                       DEBUG(1,("gensec_krb5_start: gsskrb5_set_default_realm failed\n"));
+                       DEBUG(1,("gensec_gssapi_start: gsskrb5_set_default_realm failed\n"));
                        talloc_free(gensec_gssapi_state);
                        return NT_STATUS_INTERNAL_ERROR;
                }
@@ -211,11 +189,11 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        /* don't do DNS lookups of any kind, it might/will fail for a netbios name */
        ret = gsskrb5_set_dns_canonicalize(gensec_setting_bool(gensec_security->settings, "krb5", "set_dns_canonicalize", false));
        if (ret) {
-               DEBUG(1,("gensec_krb5_start: gsskrb5_set_dns_canonicalize failed\n"));
+               DEBUG(1,("gensec_gssapi_start: gsskrb5_set_dns_canonicalize failed\n"));
                talloc_free(gensec_gssapi_state);
                return NT_STATUS_INTERNAL_ERROR;
        }
-
+#endif
        return NT_STATUS_OK;
 }
 
@@ -267,21 +245,72 @@ static NTSTATUS gensec_gssapi_sasl_server_start(struct gensec_security *gensec_s
        return nt_status;
 }
 
+static NTSTATUS gensec_gssapi_client_creds(struct gensec_security *gensec_security,
+                                          struct tevent_context *ev)
+{
+       struct gensec_gssapi_state *gensec_gssapi_state;
+       struct gssapi_creds_container *gcc;
+       struct cli_credentials *creds = gensec_get_credentials(gensec_security);
+       const char *error_string;
+       int ret;
+
+       gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
+
+       /* Only run this the first time the update() call is made */
+       if (gensec_gssapi_state->client_cred) {
+               return NT_STATUS_OK;
+       }
+
+       ret = cli_credentials_get_client_gss_creds(creds,
+                                                  ev,
+                                                  gensec_security->settings->lp_ctx, &gcc, &error_string);
+       switch (ret) {
+       case 0:
+               break;
+       case EINVAL:
+               DEBUG(3, ("Cannot obtain client GSS credentials we need to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
+               return NT_STATUS_INVALID_PARAMETER;
+       case KRB5KDC_ERR_PREAUTH_FAILED:
+       case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
+       case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+               DEBUG(1, ("Wrong username or password: %s\n", error_string));
+               return NT_STATUS_LOGON_FAILURE;
+       case KRB5KDC_ERR_CLIENT_REVOKED:
+               DEBUG(1, ("Account locked out: %s\n", error_string));
+               return NT_STATUS_ACCOUNT_LOCKED_OUT;
+       case KRB5_REALM_UNKNOWN:
+       case KRB5_KDC_UNREACH:
+               DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
+               return NT_STATUS_NO_LOGON_SERVERS;
+       case KRB5_CC_NOTFOUND:
+       case KRB5_CC_END:
+               DEBUG(2, ("Error obtaining ticket we require to contact %s: (possibly due to clock skew between us and the KDC) %s\n", gensec_gssapi_state->target_principal, error_string));
+               return NT_STATUS_TIME_DIFFERENCE_AT_DC;
+       default:
+               DEBUG(1, ("Aquiring initiator credentials failed: %s\n", error_string));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       gensec_gssapi_state->client_cred = gcc;
+       if (!talloc_reference(gensec_gssapi_state, gcc)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
 {
        struct gensec_gssapi_state *gensec_gssapi_state;
        struct cli_credentials *creds = gensec_get_credentials(gensec_security);
-       krb5_error_code ret;
        NTSTATUS nt_status;
        gss_buffer_desc name_token;
        gss_OID name_type;
        OM_uint32 maj_stat, min_stat;
        const char *hostname = gensec_get_target_hostname(gensec_security);
-       struct gssapi_creds_container *gcc;
-       const char *error_string;
 
        if (!hostname) {
-               DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
+               DEBUG(3, ("No hostname for target computer passed in, cannot use kerberos for this connection\n"));
                return NT_STATUS_INVALID_PARAMETER;
        }
        if (is_ipaddress(hostname)) {
@@ -301,7 +330,7 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
 
        if (cli_credentials_get_impersonate_principal(creds)) {
-               gensec_gssapi_state->want_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
+               gensec_gssapi_state->gss_want_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
        }
 
        gensec_gssapi_state->target_principal = gensec_get_target_principal(gensec_security);
@@ -310,7 +339,7 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        } else {
                gensec_gssapi_state->target_principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s",
                                            gensec_get_target_service(gensec_security), 
-                                           hostname, lpcfg_realm(gensec_security->settings->lp_ctx));
+                                           hostname, cli_credentials_get_realm(creds));
 
                name_type = GSS_C_NT_USER_NAME;
        }
@@ -329,33 +358,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       ret = cli_credentials_get_client_gss_creds(creds, 
-                                                  gensec_security->event_ctx, 
-                                                  gensec_security->settings->lp_ctx, &gcc, &error_string);
-       switch (ret) {
-       case 0:
-               break;
-       case KRB5KDC_ERR_PREAUTH_FAILED:
-       case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
-               DEBUG(1, ("Wrong username or password: %s\n", error_string));
-               return NT_STATUS_LOGON_FAILURE;
-       case KRB5_KDC_UNREACH:
-               DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
-               return NT_STATUS_NO_LOGON_SERVERS;
-       case KRB5_CC_NOTFOUND:
-       case KRB5_CC_END:
-               DEBUG(2, ("Error obtaining ticket we require to contact %s: (possibly due to clock skew between us and the KDC) %s\n", gensec_gssapi_state->target_principal, error_string));
-               return NT_STATUS_TIME_DIFFERENCE_AT_DC;
-       default:
-               DEBUG(1, ("Aquiring initiator credentials failed: %s\n", error_string));
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       gensec_gssapi_state->client_cred = gcc;
-       if (!talloc_reference(gensec_gssapi_state, gcc)) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       
        return NT_STATUS_OK;
 }
 
@@ -373,26 +375,6 @@ static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_s
 }
 
 
-/**
- * Check if the packet is one for this mechansim
- * 
- * @param gensec_security GENSEC state
- * @param in The request, as a DATA_BLOB
- * @return Error, INVALID_PARAMETER if it's not a packet for us
- *                or NT_STATUS_OK if the packet is ok. 
- */
-
-static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security, 
-                                   const DATA_BLOB *in) 
-{
-       if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
-               return NT_STATUS_OK;
-       } else {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-}
-
-
 /**
  * Next state function for the GSSAPI GENSEC mechanism
  * 
@@ -405,16 +387,27 @@ static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security,
  */
 
 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
-                                  TALLOC_CTX *out_mem_ctx, 
-                                  const DATA_BLOB in, DATA_BLOB *out) 
+                                    TALLOC_CTX *out_mem_ctx,
+                                    struct tevent_context *ev,
+                                    const DATA_BLOB in, DATA_BLOB *out)
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
        NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
        OM_uint32 maj_stat, min_stat;
        OM_uint32 min_stat2;
-       gss_buffer_desc input_token, output_token;
+       gss_buffer_desc input_token = { 0, NULL };
+       gss_buffer_desc output_token = { 0, NULL };
+
        gss_OID gss_oid_p = NULL;
+       OM_uint32 time_req = 0;
+       OM_uint32 time_rec = 0;
+       struct timeval tv;
+
+       time_req = gensec_setting_int(gensec_security->settings,
+                                     "gensec_gssapi", "requested_life_time",
+                                     time_req);
+
        input_token.length = in.length;
        input_token.value = in.data;
 
@@ -424,43 +417,53 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                switch (gensec_security->gensec_role) {
                case GENSEC_CLIENT:
                {
+#ifdef SAMBA4_USES_HEIMDAL
                        struct gsskrb5_send_to_kdc send_to_kdc;
                        krb5_error_code ret;
+#endif
+
+                       nt_status = gensec_gssapi_client_creds(gensec_security, ev);
+                       if (!NT_STATUS_IS_OK(nt_status)) {
+                               return nt_status;
+                       }
+
+#ifdef SAMBA4_USES_HEIMDAL
                        send_to_kdc.func = smb_krb5_send_and_recv_func;
-                       send_to_kdc.ptr = gensec_security->event_ctx;
+                       send_to_kdc.ptr = ev;
 
                        min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
                        if (min_stat) {
-                               DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
+                               DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
                                return NT_STATUS_INTERNAL_ERROR;
                        }
-
+#endif
                        maj_stat = gss_init_sec_context(&min_stat, 
                                                        gensec_gssapi_state->client_cred->creds,
                                                        &gensec_gssapi_state->gssapi_context, 
                                                        gensec_gssapi_state->server_name, 
                                                        gensec_gssapi_state->gss_oid,
-                                                       gensec_gssapi_state->want_flags, 
-                                                       0, 
+                                                       gensec_gssapi_state->gss_want_flags, 
+                                                       time_req,
                                                        gensec_gssapi_state->input_chan_bindings,
                                                        &input_token, 
                                                        &gss_oid_p,
                                                        &output_token, 
-                                                       &gensec_gssapi_state->got_flags, /* ret flags */
-                                                       NULL);
+                                                       &gensec_gssapi_state->gss_got_flags, /* ret flags */
+                                                       &time_rec);
                        if (gss_oid_p) {
                                gensec_gssapi_state->gss_oid = gss_oid_p;
                        }
 
+#ifdef SAMBA4_USES_HEIMDAL
                        send_to_kdc.func = smb_krb5_send_and_recv_func;
                        send_to_kdc.ptr = NULL;
 
                        ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
                        if (ret) {
-                               DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
+                               DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
                                return NT_STATUS_INTERNAL_ERROR;
                        }
-
+#endif
                        break;
                }
                case GENSEC_SERVER:
@@ -473,8 +476,8 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                                          &gensec_gssapi_state->client_name, 
                                                          &gss_oid_p,
                                                          &output_token, 
-                                                         &gensec_gssapi_state->got_flags, 
-                                                         NULL, 
+                                                         &gensec_gssapi_state->gss_got_flags, 
+                                                         &time_rec,
                                                          &gensec_gssapi_state->delegated_cred_handle);
                        if (gss_oid_p) {
                                gensec_gssapi_state->gss_oid = gss_oid_p;
@@ -492,12 +495,16 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
                        gss_release_buffer(&min_stat2, &output_token);
                        
-                       if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
+                       if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
+                           gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
                                DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
                        } else {
                                DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
                        }
 
+                       tv = timeval_current_ofs(time_rec, 0);
+                       gensec_gssapi_state->expire_time = timeval_to_nttime(&tv);
+
                        /* We may have been invoked as SASL, so there
                         * is more work to do */
                        if (gensec_gssapi_state->sasl) {
@@ -522,7 +529,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        
                        return NT_STATUS_MORE_PROCESSING_REQUIRED;
                } else if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
-                       gss_cred_id_t creds;
+                       gss_cred_id_t creds = NULL;
                        gss_name_t name;
                        gss_buffer_desc buffer;
                        OM_uint32 lifetime = 0;
@@ -537,9 +544,11 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        case GENSEC_CLIENT:
                                creds = gensec_gssapi_state->client_cred->creds;
                                role = "client";
+                               break;
                        case GENSEC_SERVER:
                                creds = gensec_gssapi_state->server_cred->creds;
                                role = "server";
+                               break;
                        }
 
                        maj_stat = gss_inquire_cred(&min_stat, 
@@ -547,7 +556,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                                    &name, &lifetime, &usage, NULL);
 
                        if (maj_stat == GSS_S_COMPLETE) {
-                               const char *usage_string;
+                               const char *usage_string = NULL;
                                switch (usage) {
                                case GSS_C_BOTH:
                                        usage_string = "GSS_C_BOTH";
@@ -580,7 +589,8 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                        }
                        return NT_STATUS_INVALID_PARAMETER;
-               } else if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
+               } else if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
+                                            gss_mech_krb5)) {
                        switch (min_stat) {
                        case KRB5KRB_AP_ERR_TKT_NYV:
                                DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
@@ -593,7 +603,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                                return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
                        case KRB5_KDC_UNREACH:
-                               DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticetk to %s: %s\n",
+                               DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticket to %s: %s\n",
                                          gensec_gssapi_state->target_principal,
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                                return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
@@ -610,14 +620,14 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                          gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
                                          gensec_gssapi_state->gss_exchange_count,
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-                               return nt_status;
+                               return NT_STATUS_LOGON_FAILURE;
                        }
                } else {
                        DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
                                  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
                                  gensec_gssapi_state->gss_exchange_count,
                                  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-                       return nt_status;
+                       return NT_STATUS_LOGON_FAILURE;
                }
                break;
        }
@@ -966,7 +976,7 @@ static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_securi
                                       &max_input_size);
        if (GSS_ERROR(maj_stat)) {
                TALLOC_CTX *mem_ctx = talloc_new(NULL); 
-               DEBUG(1, ("gensec_gssapi_max_input_size: determinaing signature size with gss_wrap_size_limit failed: %s\n", 
+               DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
                          gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                talloc_free(mem_ctx);
                return 0;
@@ -990,47 +1000,30 @@ static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_securit
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       OM_uint32 maj_stat, min_stat;
-       gss_buffer_desc input_token, output_token;
-       int conf_state;
-       ssize_t sig_length;
-
-       input_token.length = length;
-       input_token.value = data;
-       
-       maj_stat = gss_wrap(&min_stat, 
-                           gensec_gssapi_state->gssapi_context,
-                           gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
-                           GSS_C_QOP_DEFAULT,
-                           &input_token,
-                           &conf_state,
-                           &output_token);
-       if (GSS_ERROR(maj_stat)) {
-               DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n", 
-                         gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-               return NT_STATUS_ACCESS_DENIED;
-       }
+       bool hdr_signing = false;
+       size_t sig_size = 0;
+       NTSTATUS status;
 
-       if (output_token.length < input_token.length) {
-               DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] *less* than caller length [%ld]\n", 
-                         (long)output_token.length, (long)length));
-               return NT_STATUS_INTERNAL_ERROR;
+       if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+               hdr_signing = true;
        }
-       sig_length = output_token.length - input_token.length;
-
-       memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
-       *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
 
-       dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
-       dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
-       dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
-
-       gss_release_buffer(&min_stat, &output_token);
+       sig_size = gensec_gssapi_sig_size(gensec_security, length);
 
-       if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
-           && !conf_state) {
-               return NT_STATUS_ACCESS_DENIED;
+       status = gssapi_seal_packet(gensec_gssapi_state->gssapi_context,
+                                   gensec_gssapi_state->gss_oid,
+                                   hdr_signing, sig_size,
+                                   data, length,
+                                   whole_pdu, pdu_length,
+                                   mem_ctx, sig);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
+                         "data=%zu,pdu=%zu) failed: %s\n",
+                         hdr_signing, sig_size, length, pdu_length,
+                         nt_errstr(status)));
+               return status;
        }
+
        return NT_STATUS_OK;
 }
 
@@ -1041,49 +1034,27 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       OM_uint32 maj_stat, min_stat;
-       gss_buffer_desc input_token, output_token;
-       int conf_state;
-       gss_qop_t qop_state;
-       DATA_BLOB in;
-
-       dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
-
-       in = data_blob_talloc(gensec_security, NULL, sig->length + length);
-
-       memcpy(in.data, sig->data, sig->length);
-       memcpy(in.data + sig->length, data, length);
+       bool hdr_signing = false;
+       NTSTATUS status;
 
-       input_token.length = in.length;
-       input_token.value = in.data;
-       
-       maj_stat = gss_unwrap(&min_stat, 
-                             gensec_gssapi_state->gssapi_context, 
-                             &input_token,
-                             &output_token, 
-                             &conf_state,
-                             &qop_state);
-       talloc_free(in.data);
-       if (GSS_ERROR(maj_stat)) {
-               char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
-               DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", 
-                         error_string));
-               talloc_free(error_string);
-               return NT_STATUS_ACCESS_DENIED;
+       if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+               hdr_signing = true;
        }
 
-       if (output_token.length != length) {
-               return NT_STATUS_INTERNAL_ERROR;
+       status = gssapi_unseal_packet(gensec_gssapi_state->gssapi_context,
+                                     gensec_gssapi_state->gss_oid,
+                                     hdr_signing,
+                                     data, length,
+                                     whole_pdu, pdu_length,
+                                     sig);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
+                         "data=%zu,pdu=%zu) failed: %s\n",
+                         hdr_signing, sig->length, length, pdu_length,
+                         nt_errstr(status)));
+               return status;
        }
 
-       memcpy(data, output_token.value, length);
-
-       gss_release_buffer(&min_stat, &output_token);
-       
-       if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
-           && !conf_state) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
        return NT_STATUS_OK;
 }
 
@@ -1095,34 +1066,27 @@ static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_securit
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       OM_uint32 maj_stat, min_stat;
-       gss_buffer_desc input_token, output_token;
+       bool hdr_signing = false;
+       NTSTATUS status;
 
        if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
-               input_token.length = pdu_length;
-               input_token.value = discard_const_p(uint8_t *, whole_pdu);
-       } else {
-               input_token.length = length;
-               input_token.value = discard_const_p(uint8_t *, data);
+               hdr_signing = true;
        }
 
-       maj_stat = gss_get_mic(&min_stat,
-                           gensec_gssapi_state->gssapi_context,
-                           GSS_C_QOP_DEFAULT,
-                           &input_token,
-                           &output_token);
-       if (GSS_ERROR(maj_stat)) {
-               DEBUG(1, ("GSS GetMic failed: %s\n",
-                         gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-               return NT_STATUS_ACCESS_DENIED;
+       status = gssapi_sign_packet(gensec_gssapi_state->gssapi_context,
+                                   gensec_gssapi_state->gss_oid,
+                                   hdr_signing,
+                                   data, length,
+                                   whole_pdu, pdu_length,
+                                   mem_ctx, sig);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
+                         "data=%zu,pdu=%zu) failed: %s\n",
+                         hdr_signing, length, pdu_length,
+                         nt_errstr(status)));
+               return status;
        }
 
-       *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
-
-       dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
-
-       gss_release_buffer(&min_stat, &output_token);
-
        return NT_STATUS_OK;
 }
 
@@ -1133,35 +1097,25 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       OM_uint32 maj_stat, min_stat;
-       gss_buffer_desc input_token;
-       gss_buffer_desc input_message;
-       gss_qop_t qop_state;
-
-       dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
+       bool hdr_signing = false;
+       NTSTATUS status;
 
        if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
-               input_message.length = pdu_length;
-               input_message.value = discard_const(whole_pdu);
-       } else {
-               input_message.length = length;
-               input_message.value = discard_const(data);
+               hdr_signing = true;
        }
 
-       input_token.length = sig->length;
-       input_token.value = sig->data;
-
-       maj_stat = gss_verify_mic(&min_stat,
-                             gensec_gssapi_state->gssapi_context, 
-                             &input_message,
-                             &input_token,
-                             &qop_state);
-       if (GSS_ERROR(maj_stat)) {
-               char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
-               DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
-               talloc_free(error_string);
-
-               return NT_STATUS_ACCESS_DENIED;
+       status = gssapi_check_packet(gensec_gssapi_state->gssapi_context,
+                                    gensec_gssapi_state->gss_oid,
+                                    hdr_signing,
+                                    data, length,
+                                    whole_pdu, pdu_length,
+                                    sig);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu,"
+                         "data=%zu,pdu=%zu) failed: %s\n",
+                         hdr_signing, sig->length, length, pdu_length,
+                         nt_errstr(status)));
+               return status;
        }
 
        return NT_STATUS_OK;
@@ -1178,32 +1132,34 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
                if (gensec_gssapi_state->sasl 
                    && gensec_gssapi_state->sasl_state == STAGE_DONE) {
                        return ((gensec_gssapi_state->sasl_protection & NEG_SIGN) 
-                               && (gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG));
+                               && (gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG));
                }
-               return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
+               return gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG;
        }
        if (feature & GENSEC_FEATURE_SEAL) {
                /* If we are going GSSAPI SASL, then we honour the second negotiation */
                if (gensec_gssapi_state->sasl 
                    && gensec_gssapi_state->sasl_state == STAGE_DONE) {
                        return ((gensec_gssapi_state->sasl_protection & NEG_SEAL) 
-                                && (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG));
+                                && (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG));
                }
-               return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
+               return gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG;
        }
        if (feature & GENSEC_FEATURE_SESSION_KEY) {
                /* Only for GSSAPI/Krb5 */
-               if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
+               if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
+                                     gss_mech_krb5)) {
                        return true;
                }
        }
        if (feature & GENSEC_FEATURE_DCE_STYLE) {
-               return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
+               return gensec_gssapi_state->gss_got_flags & GSS_C_DCE_STYLE;
        }
        if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
                NTSTATUS status;
+               uint32_t keytype;
 
-               if (!(gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG)) {
+               if (!(gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)) {
                        return false;
                }
 
@@ -1214,24 +1170,55 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
                        return false;
                }
 
-               status = gensec_gssapi_init_lucid(gensec_gssapi_state);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return false;
+               status = gssapi_get_session_key(gensec_gssapi_state,
+                                               gensec_gssapi_state->gssapi_context, NULL, &keytype);
+               /* 
+                * We should do a proper sig on the mechListMic unless
+                * we know we have to be backwards compatible with
+                * earlier windows versions.  
+                * 
+                * Negotiating a non-krb5
+                * mech for example should be regarded as having
+                * NEW_SPNEGO
+                */
+               if (NT_STATUS_IS_OK(status)) {
+                       switch (keytype) {
+                       case ENCTYPE_DES_CBC_CRC:
+                       case ENCTYPE_DES_CBC_MD5:
+                       case ENCTYPE_ARCFOUR_HMAC:
+                       case ENCTYPE_DES3_CBC_SHA1:
+                               return false;
+                       }
+               }
+               return true;
+       }
+       /* We can always do async (rather than strict request/reply) packets.  */
+       if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
+               return true;
+       }
+       if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+               if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
+                       return true;
                }
 
-               if (gensec_gssapi_state->lucid->protocol == 1) {
+               if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
                        return true;
                }
 
                return false;
        }
-       /* We can always do async (rather than strict request/reply) packets.  */
-       if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
-               return true;
-       }
        return false;
 }
 
+static NTTIME gensec_gssapi_expire_time(struct gensec_security *gensec_security)
+{
+       struct gensec_gssapi_state *gensec_gssapi_state =
+               talloc_get_type_abort(gensec_security->private_data,
+               struct gensec_gssapi_state);
+
+       return gensec_gssapi_state->expire_time;
+}
+
 /*
  * Extract the 'sesssion key' needed by SMB signing and ncacn_np 
  * (for encrypting some passwords).
@@ -1244,61 +1231,53 @@ static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_securit
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       OM_uint32 maj_stat, min_stat;
-       krb5_keyblock *subkey;
-
-       if (gensec_gssapi_state->sasl_state != STAGE_DONE) {
-               return NT_STATUS_NO_USER_SESSION_KEY;
-       }
-
-       maj_stat = gsskrb5_get_subkey(&min_stat,
-                                     gensec_gssapi_state->gssapi_context,
-                                     &subkey);
-       if (maj_stat != 0) {
-               DEBUG(1, ("NO session key for this mech\n"));
-               return NT_STATUS_NO_USER_SESSION_KEY;
-       }
-       
-       DEBUG(10, ("Got KRB5 session key of length %d%s\n",
-                  (int)KRB5_KEY_LENGTH(subkey),
-                  (gensec_gssapi_state->sasl_state == STAGE_DONE)?" (done)":""));
-       *session_key = data_blob_talloc(mem_ctx,
-                                       KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
-       krb5_free_keyblock(gensec_gssapi_state->smb_krb5_context->krb5_context, subkey);
-       dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
-
-       return NT_STATUS_OK;
+       return gssapi_get_session_key(mem_ctx, gensec_gssapi_state->gssapi_context, session_key, NULL);
 }
 
 /* Get some basic (and authorization) information about the user on
  * this session.  This uses either the PAC (if present) or a local
  * database lookup */
 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
-                                          TALLOC_CTX *mem_ctx_out,
+                                          TALLOC_CTX *mem_ctx,
                                           struct auth_session_info **_session_info) 
 {
        NTSTATUS nt_status;
-       TALLOC_CTX *mem_ctx;
+       TALLOC_CTX *tmp_ctx;
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       struct auth_user_info_dc *user_info_dc = NULL;
        struct auth_session_info *session_info = NULL;
        OM_uint32 maj_stat, min_stat;
-       DATA_BLOB pac_blob;
-       struct PAC_SIGNATURE_DATA *pac_srv_sig = NULL;
-       struct PAC_SIGNATURE_DATA *pac_kdc_sig = NULL;
+       DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
+
+       gss_buffer_desc name_token;
+       char *principal_string;
        
-       if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
-           || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
-                      gensec_gssapi_state->gss_oid->length) != 0)) {
-               DEBUG(1, ("NO session info available for this mech\n"));
-               return NT_STATUS_INVALID_PARAMETER;
+       tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       maj_stat = gss_display_name (&min_stat,
+                                    gensec_gssapi_state->client_name,
+                                    &name_token,
+                                    NULL);
+       if (GSS_ERROR(maj_stat)) {
+               DEBUG(1, ("GSS display_name failed: %s\n",
+                         gssapi_error_string(tmp_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
+               talloc_free(tmp_ctx);
+               return NT_STATUS_FOOBAR;
        }
-               
-       mem_ctx = talloc_named(mem_ctx_out, 0, "gensec_gssapi_session_info context");
-       NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
 
-       nt_status = gssapi_obtain_pac_blob(mem_ctx,  gensec_gssapi_state->gssapi_context,
+       principal_string = talloc_strndup(tmp_ctx,
+                                         (const char *)name_token.value,
+                                         name_token.length);
+
+       gss_release_buffer(&min_stat, &name_token);
+
+       if (!principal_string) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       nt_status = gssapi_obtain_pac_blob(tmp_ctx,  gensec_gssapi_state->gssapi_context,
                                           gensec_gssapi_state->client_name,
                                           &pac_blob);
        
@@ -1307,118 +1286,49 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
         * kind... 
         */
        if (NT_STATUS_IS_OK(nt_status)) {
-               pac_srv_sig = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
-               if (!pac_srv_sig) {
-                       talloc_free(mem_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-               pac_kdc_sig = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
-               if (!pac_kdc_sig) {
-                       talloc_free(mem_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
-                                                             pac_blob,
-                                                             gensec_gssapi_state->smb_krb5_context->krb5_context,
-                                                             &user_info_dc,
-                                                             pac_srv_sig,
-                                                             pac_kdc_sig);
-               if (!NT_STATUS_IS_OK(nt_status)) {
-                       talloc_free(mem_ctx);
-                       return nt_status;
-               }
-       } else {
-               gss_buffer_desc name_token;
-               char *principal_string;
-
-               maj_stat = gss_display_name (&min_stat,
-                                            gensec_gssapi_state->client_name,
-                                            &name_token,
-                                            NULL);
-               if (GSS_ERROR(maj_stat)) {
-                       DEBUG(1, ("GSS display_name failed: %s\n", 
-                                 gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-                       talloc_free(mem_ctx);
-                       return NT_STATUS_FOOBAR;
-               }
-               
-               principal_string = talloc_strndup(mem_ctx, 
-                                                 (const char *)name_token.value, 
-                                                 name_token.length);
-               
-               gss_release_buffer(&min_stat, &name_token);
-               
-               if (!principal_string) {
-                       talloc_free(mem_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               if (gensec_security->auth_context && 
-                   !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
-                       DEBUG(1, ("Unable to find PAC, resorting to local user lookup: %s\n",
-                                 gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-                       nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx,
-                                                                                            gensec_security->auth_context, 
-                                                                                            principal_string,
-                                                                                            NULL,
-                                                                                            &user_info_dc);
-                       
-                       if (!NT_STATUS_IS_OK(nt_status)) {
-                               talloc_free(mem_ctx);
-                               return nt_status;
-                       }
-               } else {
-                       DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s\n",
-                                 principal_string,
-                                 gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-       }
-
-       /* references the user_info_dc into the session_info */
-       nt_status = gensec_generate_session_info(mem_ctx, gensec_security,
-                                                user_info_dc, &session_info);
+               pac_blob_ptr = &pac_blob;
+       }
+       nt_status = gensec_generate_session_info_pac(tmp_ctx,
+                                                    gensec_security,
+                                                    gensec_gssapi_state->smb_krb5_context,
+                                                    pac_blob_ptr, principal_string,
+                                                    gensec_get_remote_address(gensec_security),
+                                                    &session_info);
        if (!NT_STATUS_IS_OK(nt_status)) {
-               talloc_free(mem_ctx);
+               talloc_free(tmp_ctx);
                return nt_status;
        }
 
        nt_status = gensec_gssapi_session_key(gensec_security, session_info, &session_info->session_key);
        if (!NT_STATUS_IS_OK(nt_status)) {
-               talloc_free(mem_ctx);
+               talloc_free(tmp_ctx);
                return nt_status;
        }
 
-       /* Allow torture tests to check the PAC signatures */
-       if (session_info->torture) {
-               session_info->torture->pac_srv_sig = talloc_steal(session_info->torture, pac_srv_sig);
-               session_info->torture->pac_kdc_sig = talloc_steal(session_info->torture, pac_kdc_sig);
-       }
-
-       if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
-               DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
-       } else {
+       if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
+           gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
                krb5_error_code ret;
                const char *error_string;
 
                DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
-               session_info->credentials = cli_credentials_init(session_info);
-               if (!session_info->credentials) {
-                       talloc_free(mem_ctx);
+
+               /*
+                * Create anonymous credentials for now.
+                *
+                * We will update them with the provided client gss creds.
+                */
+               session_info->credentials = cli_credentials_init_anon(session_info);
+               if (session_info->credentials == NULL) {
+                       talloc_free(tmp_ctx);
                        return NT_STATUS_NO_MEMORY;
                }
 
-               cli_credentials_set_conf(session_info->credentials, gensec_security->settings->lp_ctx);
-               /* Just so we don't segfault trying to get at a username */
-               cli_credentials_set_anonymous(session_info->credentials);
-               
                ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
                                                           gensec_security->settings->lp_ctx,
                                                           gensec_gssapi_state->delegated_cred_handle,
                                                           CRED_SPECIFIED, &error_string);
                if (ret) {
-                       talloc_free(mem_ctx);
+                       talloc_free(tmp_ctx);
                        DEBUG(2,("Failed to get gss creds: %s\n", error_string));
                        return NT_STATUS_NO_MEMORY;
                }
@@ -1428,9 +1338,12 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
 
                /* It has been taken from this place... */
                gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+       } else {
+               DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
        }
-       *_session_info = talloc_steal(mem_ctx_out, session_info);
-       talloc_free(mem_ctx);
+
+       *_session_info = talloc_steal(mem_ctx, session_info);
+       talloc_free(tmp_ctx);
 
        return NT_STATUS_OK;
 }
@@ -1439,54 +1352,18 @@ static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, si
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       NTSTATUS status;
+       size_t sig_size;
 
-       if (gensec_gssapi_state->sig_size) {
+       if (gensec_gssapi_state->sig_size > 0) {
                return gensec_gssapi_state->sig_size;
        }
 
-       if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
-               gensec_gssapi_state->sig_size = 45;
-       } else {
-               gensec_gssapi_state->sig_size = 37;
-       }
-
-       status = gensec_gssapi_init_lucid(gensec_gssapi_state);
-       if (!NT_STATUS_IS_OK(status)) {
-               return gensec_gssapi_state->sig_size;
-       }
-
-       if (gensec_gssapi_state->lucid->protocol == 1) {
-               if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
-                       /*
-                        * TODO: windows uses 76 here, but we don't know
-                        *       gss_wrap works with aes keys yet
-                        */
-                       gensec_gssapi_state->sig_size = 76;
-               } else {
-                       gensec_gssapi_state->sig_size = 28;
-               }
-       } else if (gensec_gssapi_state->lucid->protocol == 0) {
-               switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) {
-               case KEYTYPE_DES:
-               case KEYTYPE_ARCFOUR:
-               case KEYTYPE_ARCFOUR_56:
-                       if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
-                               gensec_gssapi_state->sig_size = 45;
-                       } else {
-                               gensec_gssapi_state->sig_size = 37;
-                       }
-                       break;
-               case KEYTYPE_DES3:
-                       if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
-                               gensec_gssapi_state->sig_size = 57;
-                       } else {
-                               gensec_gssapi_state->sig_size = 49;
-                       }
-                       break;
-               }
-       }
+       sig_size = gssapi_get_sig_size(gensec_gssapi_state->gssapi_context,
+                                      gensec_gssapi_state->gss_oid,
+                                      gensec_gssapi_state->gss_got_flags,
+                                      data_size);
 
+       gensec_gssapi_state->sig_size = sig_size;
        return gensec_gssapi_state->sig_size;
 }
 
@@ -1509,7 +1386,7 @@ static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
        .oid            = gensec_gssapi_spnego_oids,
        .client_start   = gensec_gssapi_client_start,
        .server_start   = gensec_gssapi_server_start,
-       .magic          = gensec_gssapi_magic,
+       .magic          = gensec_magic_check_krb5_oid,
        .update         = gensec_gssapi_update,
        .session_key    = gensec_gssapi_session_key,
        .session_info   = gensec_gssapi_session_info,
@@ -1517,9 +1394,12 @@ static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
        .check_packet   = gensec_gssapi_check_packet,
        .seal_packet    = gensec_gssapi_seal_packet,
        .unseal_packet  = gensec_gssapi_unseal_packet,
+       .max_input_size   = gensec_gssapi_max_input_size,
+       .max_wrapped_size = gensec_gssapi_max_wrapped_size,
        .wrap           = gensec_gssapi_wrap,
        .unwrap         = gensec_gssapi_unwrap,
        .have_feature   = gensec_gssapi_have_feature,
+       .expire_time    = gensec_gssapi_expire_time,
        .enabled        = false,
        .kerberos       = true,
        .priority       = GENSEC_GSSAPI
@@ -1532,7 +1412,7 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
        .oid            = gensec_gssapi_krb5_oids,
        .client_start   = gensec_gssapi_client_start,
        .server_start   = gensec_gssapi_server_start,
-       .magic          = gensec_gssapi_magic,
+       .magic          = gensec_magic_check_krb5_oid,
        .update         = gensec_gssapi_update,
        .session_key    = gensec_gssapi_session_key,
        .session_info   = gensec_gssapi_session_info,
@@ -1541,9 +1421,12 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
        .check_packet   = gensec_gssapi_check_packet,
        .seal_packet    = gensec_gssapi_seal_packet,
        .unseal_packet  = gensec_gssapi_unseal_packet,
+       .max_input_size   = gensec_gssapi_max_input_size,
+       .max_wrapped_size = gensec_gssapi_max_wrapped_size,
        .wrap           = gensec_gssapi_wrap,
        .unwrap         = gensec_gssapi_unwrap,
        .have_feature   = gensec_gssapi_have_feature,
+       .expire_time    = gensec_gssapi_expire_time,
        .enabled        = true,
        .kerberos       = true,
        .priority       = GENSEC_GSSAPI
@@ -1563,6 +1446,7 @@ static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
        .wrap             = gensec_gssapi_wrap,
        .unwrap           = gensec_gssapi_unwrap,
        .have_feature     = gensec_gssapi_have_feature,
+       .expire_time      = gensec_gssapi_expire_time,
        .enabled          = true,
        .kerberos         = true,
        .priority         = GENSEC_GSSAPI