r11452: Update Heimdal to current lorikeet, including removing the ccache side
authorAndrew Bartlett <abartlet@samba.org>
Wed, 2 Nov 2005 00:31:22 +0000 (00:31 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:45:38 +0000 (13:45 -0500)
of the gsskrb5_acquire_cred hack.

Add support for delegated credentials into the auth and credentials
subsystem, and specifically into gensec_gssapi.

Add the CIFS NTVFS handler as a consumer of delegated credentials,
when no user/domain/password is specified.

Andrew Bartlett
(This used to be commit 55b89899adb692d90e63873ccdf80b9f94a6b448)

17 files changed:
source4/auth/auth.h
source4/auth/auth_util.c
source4/auth/credentials/credentials.c
source4/auth/credentials/credentials.h
source4/auth/credentials/credentials_krb5.c
source4/auth/gensec/gensec_gssapi.c
source4/auth/kerberos/kerberos.h
source4/heimdal/lib/gssapi/accept_sec_context.c
source4/heimdal/lib/gssapi/acquire_cred.c
source4/heimdal/lib/gssapi/copy_ccache.c
source4/heimdal/lib/gssapi/delete_sec_context.c
source4/heimdal/lib/gssapi/gssapi.h
source4/heimdal/lib/gssapi/gssapi_locl.h
source4/heimdal/lib/gssapi/init_sec_context.c
source4/heimdal/lib/gssapi/release_cred.c
source4/heimdal/lib/krb5/ticket.c
source4/ntvfs/cifs/vfs_cifs.c

index 9f2e0b6a078c1dbc64c1d033ad9a8c54c148c766..58f72aa8af48d016409959c526dd94ceb4798b4f 100644 (file)
@@ -118,6 +118,7 @@ struct auth_session_info {
        struct security_token *security_token;
        struct auth_serversupplied_info *server_info;
        DATA_BLOB session_key;
+       struct cli_credentials *credentials;
 };
 
 struct auth_method_context;
index 753f680fb12dfb2a6e7520cb1b9b7e5bbce10d59..df4e510c2f42a1c1f6f14c8131d5db7cb58a4851 100644 (file)
@@ -526,6 +526,8 @@ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
                                          &session_info->security_token);
        NT_STATUS_NOT_OK_RETURN(nt_status);
 
+       session_info->credentials = NULL;
+
        *_session_info = session_info;
        return NT_STATUS_OK;
 }
index 5d2c5c553e9b1e8bcf480b30f13b86b35a933a05..86a3df0077e155534fba6a3e6491332abb722fb5 100644 (file)
@@ -46,6 +46,7 @@ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx)
        cred->domain_obtained = CRED_UNINITIALISED;
        cred->realm_obtained = CRED_UNINITIALISED;
        cred->ccache_obtained = CRED_UNINITIALISED;
+       cred->gss_creds_obtained = CRED_UNINITIALISED;
        cred->keytab_obtained = CRED_UNINITIALISED;
        cred->principal_obtained = CRED_UNINITIALISED;
 
index b85337bd1885eb7dc393e7ee2d6b7d50732c9dd3..3e84db52a57a2738ec553b16f1b90ee87c74956f 100644 (file)
@@ -47,6 +47,7 @@ struct cli_credentials {
        enum credentials_obtained domain_obtained;
        enum credentials_obtained realm_obtained;
        enum credentials_obtained ccache_obtained;
+       enum credentials_obtained gss_creds_obtained;
        enum credentials_obtained principal_obtained;
        enum credentials_obtained keytab_obtained;
 
@@ -62,6 +63,7 @@ struct cli_credentials {
        struct samr_Password *nt_hash;
 
        struct ccache_container *ccache;
+       struct gssapi_creds_container *gssapi_creds;
        struct keytab_container *keytab;
 
        const char *(*workstation_cb) (struct cli_credentials *);
index abb8418748150f202b659d3677a572a7b17399b4..a3761e8359782987bda8a38bb13522ab8a30ad87 100644 (file)
@@ -85,7 +85,7 @@ int cli_credentials_set_from_ccache(struct cli_credentials *cred,
        return 0;
 }
 
-
+/* Free a memory ccache */
 static int free_mccache(void *ptr) {
        struct ccache_container *ccc = ptr;
        krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
@@ -93,6 +93,7 @@ static int free_mccache(void *ptr) {
        return 0;
 }
 
+/* Free a disk-based ccache */
 static int free_dccache(void *ptr) {
        struct ccache_container *ccc = ptr;
        krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
@@ -163,7 +164,7 @@ int cli_credentials_set_ccache(struct cli_credentials *cred,
 }
 
 
-int cli_credentials_new_ccache(struct cli_credentials *cred)
+int cli_credentials_new_ccache(struct cli_credentials *cred, struct ccache_container **_ccc)
 {
        krb5_error_code ret;
        char *rand_string;
@@ -211,6 +212,10 @@ int cli_credentials_new_ccache(struct cli_credentials *cred)
        talloc_steal(cred, ccc);
        talloc_free(ccache_name);
 
+       if (_ccc) {
+               *_ccc = ccc;
+       }
+
        return ret;
 }
 
@@ -228,7 +233,7 @@ int cli_credentials_get_ccache(struct cli_credentials *cred,
                return EINVAL;
        }
 
-       ret = cli_credentials_new_ccache(cred);
+       ret = cli_credentials_new_ccache(cred, NULL);
        if (ret) {
                return ret;
        }
@@ -245,6 +250,108 @@ int cli_credentials_get_ccache(struct cli_credentials *cred,
        return ret;
 }
 
+static int free_gssapi_creds(void *ptr) {
+       OM_uint32 min_stat, maj_stat;
+       struct gssapi_creds_container *gcc = ptr;
+       maj_stat = gss_release_cred(&min_stat, 
+                                   &gcc->creds);
+       return 0;
+}
+
+int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, 
+                                        struct gssapi_creds_container **_gcc) 
+{
+       int ret = 0;
+       OM_uint32 maj_stat, min_stat;
+       struct gssapi_creds_container *gcc;
+       struct ccache_container *ccache;
+       if (cred->gss_creds_obtained >= (MAX(cred->ccache_obtained, 
+                                            MAX(cred->principal_obtained, 
+                                                cred->username_obtained)))) {
+               *_gcc = cred->gssapi_creds;
+               return 0;
+       }
+       ret = cli_credentials_get_ccache(cred, 
+                                        &ccache);
+       if (ret) {
+               DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
+               return ret;
+       }
+
+       gcc = talloc(cred, struct gssapi_creds_container);
+       if (!gcc) {
+               return ENOMEM;
+       }
+
+       maj_stat = gss_krb5_import_ccache(&min_stat, ccache->ccache, 
+                                          &gcc->creds);
+       if (maj_stat) {
+               if (min_stat) {
+                       ret = min_stat;
+               } else {
+                       ret = EINVAL;
+               }
+       }
+       if (ret == 0) {
+               cred->gss_creds_obtained = cred->ccache_obtained;
+               talloc_set_destructor(gcc, free_gssapi_creds);
+               cred->gssapi_creds = gcc;
+               *_gcc = gcc;
+       }
+       return ret;
+}
+
+/**
+   Set a gssapi cred_id_t into the credentails system.
+
+   This grabs the credentials both 'intact' and getting the krb5
+   ccache out of it.  This routine can be generalised in future for
+   the case where we deal with GSSAPI mechs other than krb5.
+
+   On sucess, the caller must not free gssapi_cred, as it now belongs
+   to the credentials system.
+*/
+
+ int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, 
+                                         gss_cred_id_t gssapi_cred,
+                                         enum credentials_obtained obtained) 
+{
+       int ret;
+       OM_uint32 maj_stat, min_stat;
+       struct ccache_container *ccc;
+       struct gssapi_creds_container *gcc = talloc(cred, struct gssapi_creds_container);
+       if (!gcc) {
+               return ENOMEM;
+       }
+
+       ret = cli_credentials_new_ccache(cred, &ccc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       maj_stat = gss_krb5_copy_ccache(&min_stat, 
+                                       gssapi_cred, ccc->ccache);
+       if (maj_stat) {
+               if (min_stat) {
+                       ret = min_stat;
+               } else {
+                       ret = EINVAL;
+               }
+       }
+
+       if (ret == 0) {
+               ret = cli_credentials_set_from_ccache(cred, obtained);
+       }
+       if (ret == 0) {
+               gcc->creds = gssapi_cred;
+               talloc_set_destructor(gcc, free_gssapi_creds);
+               
+               cred->gss_creds_obtained = obtained;
+               cred->gssapi_creds = gcc;
+       }
+       return ret;
+}
+
 int cli_credentials_get_keytab(struct cli_credentials *cred, 
                               struct keytab_container **_ktc)
 {
index d59d19c6366ab13d25c60cfe73b3148807499746..4608b62db5fe797ad81dcd31565b2caa958b1b53 100644 (file)
@@ -44,8 +44,10 @@ struct gensec_gssapi_state {
        krb5_ccache ccache;
        const char *ccache_name;
        struct keytab_container *keytab;
+       struct gssapi_creds_container *client_cred;
 
        gss_cred_id_t cred;
+       gss_cred_id_t delegated_cred_handle;
 };
 
 static char *gssapi_error_string(TALLOC_CTX *mem_ctx, 
@@ -83,6 +85,10 @@ static int gensec_gssapi_destory(void *ptr)
                maj_stat = gss_release_cred(&min_stat, 
                                            &gensec_gssapi_state->cred);
        }
+       if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
+               maj_stat = 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,
@@ -118,13 +124,14 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
        /* TODO: Fill in channel bindings */
        gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
        
-       gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG;
+       gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG;
        gensec_gssapi_state->got_flags = 0;
 
        gensec_gssapi_state->session_key = data_blob(NULL, 0);
        gensec_gssapi_state->pac = data_blob(NULL, 0);
 
        gensec_gssapi_state->cred = GSS_C_NO_CREDENTIAL;
+       gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
 
        talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); 
 
@@ -205,7 +212,7 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi
        }
 
        maj_stat = gsskrb5_acquire_cred(&min_stat, 
-                                       gensec_gssapi_state->keytab->keytab, NULL,
+                                       gensec_gssapi_state->keytab->keytab, 
                                        gensec_gssapi_state->server_name,
                                        GSS_C_INDEFINITE,
                                        GSS_C_NULL_OID_SET,
@@ -227,7 +234,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
 {
        struct gensec_gssapi_state *gensec_gssapi_state;
        struct cli_credentials *creds = gensec_get_credentials(gensec_security);
-       struct ccache_container *ccache;
        krb5_error_code ret;
        NTSTATUS nt_status;
        gss_buffer_desc name_token;
@@ -235,6 +241,7 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        OM_uint32 maj_stat, min_stat;
        const char *hostname = gensec_get_target_hostname(gensec_security);
        const char *principal;
+       struct gssapi_creds_container *gcc;
 
        if (!hostname) {
                DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
@@ -256,29 +263,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
 
        gensec_gssapi_state = gensec_security->private_data;
 
-       ret = cli_credentials_get_ccache(creds, 
-                                        &ccache);
-       if (ret) {
-               DEBUG(1, ("Failed to get CCACHE for gensec_gssapi: %s\n", error_message(ret)));
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       principal = cli_credentials_get_principal(creds, 
-                                                 gensec_gssapi_state);
-       name_token.value  = discard_const_p(uint8_t, principal);
-       name_token.length = strlen(principal);
-
-       maj_stat = gss_import_name (&min_stat,
-                                   &name_token,
-                                   GSS_C_NT_USER_NAME,
-                                   &gensec_gssapi_state->client_name);
-       if (maj_stat) {
-               DEBUG(2, ("GSS Import name of %s failed: %s\n",
-                         (char *)name_token.value,
-                         gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
        principal = gensec_get_target_principal(gensec_security);
        if (principal && lp_client_use_spnego_principal()) {
                name_token.value  = discard_const_p(uint8_t, principal);
@@ -307,28 +291,20 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       maj_stat = gsskrb5_acquire_cred(&min_stat, 
-                                       NULL, ccache->ccache,
-                                       gensec_gssapi_state->client_name,
-                                       GSS_C_INDEFINITE,
-                                       GSS_C_NULL_OID_SET,
-                                       GSS_C_INITIATE,
-                                       &gensec_gssapi_state->cred,
-                                       NULL, 
-                                       NULL);
-       if (maj_stat) {
-               switch (min_stat) {
-               case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
-                       DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", 
-                                 hostname, gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
-                       return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
-               default:
-                       DEBUG(1, ("Aquiring initiator credentails failed: %s\n", 
-                                 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
+       ret = cli_credentials_get_client_gss_creds(creds, &gcc);
+       switch (ret) {
+       case 0:
+               break;
+       case KRB5_KDC_UNREACH:
+               DEBUG(3, ("Cannot reach a KDC we require\n"));
+               return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
+       default:
+               DEBUG(1, ("Aquiring initiator credentails failed\n"));
+               return NT_STATUS_UNSUCCESSFUL;
        }
 
+       gensec_gssapi_state->client_cred = gcc;
+
        return NT_STATUS_OK;
 }
 
@@ -369,7 +345,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                   const DATA_BLOB in, DATA_BLOB *out) 
 {
        struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
-       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
        OM_uint32 maj_stat, min_stat;
        OM_uint32 min_stat2;
        gss_buffer_desc input_token, output_token;
@@ -381,7 +357,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
        case GENSEC_CLIENT:
        {
                maj_stat = gss_init_sec_context(&min_stat, 
-                                               gensec_gssapi_state->cred,
+                                               gensec_gssapi_state->client_cred->creds,
                                                &gensec_gssapi_state->gssapi_context, 
                                                gensec_gssapi_state->server_name, 
                                                discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
@@ -407,7 +383,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                                  &output_token, 
                                                  &gensec_gssapi_state->got_flags, 
                                                  NULL, 
-                                                 NULL);
+                                                 &gensec_gssapi_state->delegated_cred_handle);
                gensec_gssapi_state->gss_oid = gss_oid_p;
                break;
        }
@@ -420,6 +396,12 @@ 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) {
+                       DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
+               } else {
+                       DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
+               }
+
                return NT_STATUS_OK;
        } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
                *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
@@ -941,6 +923,27 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
        nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
        NT_STATUS_NOT_OK_RETURN(nt_status);
 
+       if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
+               DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client"));
+       } else {
+               krb5_error_code ret;
+               DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
+               session_info->credentials = cli_credentials_init(session_info);
+               if (!session_info->credentials) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               cli_credentials_set_conf(session_info->credentials);
+               
+               ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
+                                                          gensec_gssapi_state->delegated_cred_handle,
+                                                          CRED_SPECIFIED);
+               if (ret) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               /* It has been taken from this place... */
+               gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+       }
        *_session_info = session_info;
 
        return NT_STATUS_OK;
index 070293df68b87caf14107589e14beb1ea1028d11..98132906506f775bda240c3fa12ab0789b72a751 100644 (file)
@@ -29,6 +29,11 @@ struct ccache_container {
 };
 
 
+struct gssapi_creds_container {
+       gss_cred_id_t creds;
+};
+
+
 struct keytab_container {
        struct smb_krb5_context *smb_krb5_context;
        krb5_keytab keytab;
@@ -155,5 +160,10 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
                                     krb5_principal client_principal,
                                     time_t tgs_authtime,
                                     DATA_BLOB *pac);
+
+ int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, 
+                                         gss_cred_id_t gssapi_cred,
+                                         enum credentials_obtained obtained); 
+
 #endif /* HAVE_KRB5 */
 
index 8e354c313609b94abd1a9516bb1b53eeda45ab0e..5d43cdcb436441250888ed5d2e37836e943b7507 100644 (file)
@@ -239,7 +239,7 @@ gsskrb5_acceptor_ready(
        OM_uint32 ret;
        int32_t seq_number;
        int is_cfx = 0;
-       u_int32_t flags = (*context_handle)->flags;
+       u_int32_t *flags = &(*context_handle)->flags;
 
        krb5_auth_getremoteseqnumber (gssapi_krb5_context,
                                      (*context_handle)->auth_context,
@@ -249,11 +249,11 @@ gsskrb5_acceptor_ready(
 
        ret = _gssapi_msg_order_create(minor_status,
                                       &(*context_handle)->order,
-                                      _gssapi_msg_order_f(flags),
+                                      _gssapi_msg_order_f(*flags),
                                       seq_number, 0, is_cfx);
        if (ret) return ret;
 
-       if (!(flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(flags)) {
+       if (!(*flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(*flags)) {
                krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
                                                (*context_handle)->auth_context,
                                                seq_number);
@@ -262,11 +262,14 @@ gsskrb5_acceptor_ready(
        /*
         * We should handle the delegation ticket, in case it's there
         */
-       if ((*context_handle)->fwd_data.length > 0 && (flags & GSS_C_DELEG_FLAG)) {
+       if ((*context_handle)->fwd_data.length > 0 && (*flags & GSS_C_DELEG_FLAG)) {
                ret = gsskrb5_accept_delegated_token(minor_status,
                                                     context_handle,
                                                     delegated_cred_handle);
                if (ret) return ret;
+       } else {
+               /* Well, looks like it wasn't there after all */
+               *flags &= ~GSS_C_DELEG_FLAG;
        }
 
        (*context_handle)->state        = ACCEPTOR_READY;
@@ -297,10 +300,9 @@ gsskrb5_acceptor_start
     krb5_ticket *ticket = NULL;
     krb5_keytab keytab = NULL;
     krb5_keyblock *keyblock = NULL;
-    krb5_data fwd_data;
     int is_cfx = 0;
 
-    krb5_data_zero (&fwd_data);
+    krb5_data_zero (&(*context_handle)->fwd_data);
 
     /*
      * We may, or may not, have an escapsulation.
@@ -415,7 +417,7 @@ gsskrb5_acceptor_start
                                               input_chan_bindings,
                                               authenticator->cksum,
                                               &flags,
-                                              &fwd_data);
+                                              &(*context_handle)->fwd_data);
        krb5_free_authenticator(gssapi_krb5_context, &authenticator);
        if (ret) {
            return ret;
@@ -461,15 +463,9 @@ gsskrb5_acceptor_start
            }
     }
     
-    /*
-     * We need to send the flags back to the caller
-     */
     flags |= GSS_C_TRANS_FLAG;
 
-    if (ret_flags)
-       *ret_flags = flags;
-    
-    /* And remember them for later */
+    /* Remember the flags */
     
     (*context_handle)->lifetime = ticket->ticket.endtime;
     (*context_handle)->flags = flags;
@@ -491,11 +487,23 @@ gsskrb5_acceptor_start
      * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client
      */
     if (flags & GSS_C_DCE_STYLE) {
+           if (ret_flags) {
+                   /* Return flags to caller, but we haven't processed delgations yet */
+                   *ret_flags = flags & ~GSS_C_DELEG_FLAG;
+           }
+    
            (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
            return GSS_S_CONTINUE_NEEDED;
     }
 
-    return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
+    ret = gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
+
+    /*
+     * We need to send the flags back to the caller
+     */
+    
+    *ret_flags = (*context_handle)->flags;
+    return ret;
 }
 
 static OM_uint32
index 23c26033529dad435fa7b9ac434b9ba9aa911c4d..d67b4009202c46c76c480d2d3e2a226f69570445 100644 (file)
 
 #include "gssapi_locl.h"
 
-RCSID("$Id: acquire_cred.c,v 1.23 2005/10/21 12:44:08 lha Exp $");
+RCSID("$Id: acquire_cred.c,v 1.24 2005/10/26 11:25:16 lha Exp $");
+
+OM_uint32
+_gssapi_krb5_ccache_lifetime(OM_uint32 *minor_status,
+                            krb5_ccache id,
+                            krb5_principal principal,
+                            OM_uint32 *lifetime)
+{
+    krb5_creds in_cred, *out_cred;
+    krb5_const_realm realm;
+    krb5_error_code kret;
+
+    memset(&in_cred, 0, sizeof(in_cred));
+    in_cred.client = principal;
+       
+    realm = krb5_principal_get_realm(gssapi_krb5_context,  principal);
+    if (realm == NULL) {
+       gssapi_krb5_clear_status ();
+       *minor_status = KRB5_PRINC_NOMATCH; /* XXX */
+       return GSS_S_FAILURE;
+    }
+
+    kret = krb5_make_principal(gssapi_krb5_context, &in_cred.server, 
+                              realm, KRB5_TGS_NAME, realm, NULL);
+    if (kret) {
+       gssapi_krb5_set_error_string();
+       *minor_status = kret;
+       return GSS_S_FAILURE;
+    }
+
+    kret = krb5_get_credentials(gssapi_krb5_context, 0, 
+                               id, &in_cred, &out_cred);
+    krb5_free_principal(gssapi_krb5_context, in_cred.server);
+    if (kret) {
+       gssapi_krb5_set_error_string();
+       *minor_status = kret;
+       return GSS_S_FAILURE;
+    }
+
+    *lifetime = out_cred->times.endtime;
+    krb5_free_creds(gssapi_krb5_context, out_cred);
+
+    return GSS_S_COMPLETE;
+}
+
+
+
 
 static krb5_error_code
 get_keytab(krb5_context context, krb5_keytab *keytab)
@@ -61,7 +107,6 @@ static OM_uint32 acquire_initiator_cred
                  (OM_uint32 * minor_status,
                   krb5_context context,
                   krb5_keytab keytab,
-                  krb5_ccache ccache,
                   const gss_name_t desired_name,
                   OM_uint32 time_req,
                   const gss_OID_set desired_mechs,
@@ -75,10 +120,11 @@ static OM_uint32 acquire_initiator_cred
     krb5_creds cred;
     krb5_principal def_princ;
     krb5_get_init_creds_opt *opt;
+    krb5_ccache ccache;
     krb5_error_code kret;
-    krb5_boolean made_ccache = FALSE;
     krb5_boolean made_keytab = FALSE;
 
+    ccache = NULL;
     def_princ = NULL;
     ret = GSS_S_FAILURE;
     memset(&cred, 0, sizeof(cred));
@@ -86,29 +132,22 @@ static OM_uint32 acquire_initiator_cred
     /* If we have a preferred principal, lets try to find it in all
      * caches, otherwise, fall back to default cache.  Ignore
      * errors. */
-    if (ccache == NULL && handle->principal) {
+    if (handle->principal)
        kret = krb5_cc_cache_match (gssapi_krb5_context,
                                    handle->principal,
                                    NULL,
                                    &ccache);
-       if (kret) {
-           ccache = NULL;
-       } else {
-           made_ccache = TRUE;
-       }
-    }
+    
     if (ccache == NULL) {
        kret = krb5_cc_default(gssapi_krb5_context, &ccache);
        if (kret)
            goto end;
-        made_ccache = TRUE;
     }
     kret = krb5_cc_get_principal(context, ccache,
        &def_princ);
     if (kret != 0) {
        /* we'll try to use a keytab below */
        krb5_cc_destroy(context, ccache);
-       made_ccache = FALSE;
        ccache = NULL;
        kret = 0;
     } else if (handle->principal == NULL)  {
@@ -133,65 +172,41 @@ static OM_uint32 acquire_initiator_cred
            if (kret)
                goto end;
        }
-       if (keytab != NULL) {
-           kret = get_keytab(context, &keytab);
-           if (kret)
-               goto end;
-            made_keytab = TRUE;
-       }
-       kret = krb5_get_init_creds_opt_alloc(context, &opt);
+       kret = get_keytab(context, &keytab);
+       if (kret)
+           goto end;
+       kret = krb5_get_init_creds_opt_alloc(gssapi_krb5_context, &opt);
        if (kret)
            goto end;
-       kret = krb5_get_init_creds_keytab(context, &cred,
+       kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred,
            handle->principal, keytab, 0, NULL, opt);
        krb5_get_init_creds_opt_free(opt);
        if (kret)
            goto end;
-       if (ccache == NULL) {
-           kret = krb5_cc_gen_new(context, &krb5_mcc_ops,
-                                  &ccache);
-           if (kret)
-               goto end;
-            made_ccache = TRUE;
-       }
-       kret = krb5_cc_initialize(context, ccache, cred.client);
+       kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops,
+               &ccache);
        if (kret)
            goto end;
-       kret = krb5_cc_store_cred(context, ccache, &cred);
+       kret = krb5_cc_initialize(gssapi_krb5_context, ccache, cred.client);
        if (kret)
            goto end;
-       handle->lifetime = cred.times.endtime;
-    } else {
-       krb5_creds in_cred, *out_cred;
-       krb5_const_realm realm;
-
-       memset(&in_cred, 0, sizeof(in_cred));
-       in_cred.client = handle->principal;
-       
-       realm = krb5_principal_get_realm(context, 
-                                        handle->principal);
-       if (realm == NULL) {
-           kret = KRB5_PRINC_NOMATCH; /* XXX */
-           goto end;
-       }
-
-       kret = krb5_make_principal(context, &in_cred.server, 
-                                  realm, KRB5_TGS_NAME, realm, NULL);
+       kret = krb5_cc_store_cred(gssapi_krb5_context, ccache, &cred);
        if (kret)
            goto end;
+       handle->lifetime = cred.times.endtime;
+       handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
+    } else {
 
-       kret = krb5_get_credentials(context, 0, 
-                                   ccache, &in_cred, &out_cred);
-       krb5_free_principal(context, in_cred.server);
-       if (kret)
+       ret = _gssapi_krb5_ccache_lifetime(minor_status,
+                                          ccache,
+                                          handle->principal,
+                                          &handle->lifetime);
+       if (ret != GSS_S_COMPLETE)
            goto end;
-
-       handle->lifetime = out_cred->times.endtime;
-       krb5_free_creds(context, out_cred);
+       kret = 0;
     }
 
     handle->ccache = ccache;
-    handle->made_ccache = made_ccache;
     ret = GSS_S_COMPLETE;
 
 end:
@@ -202,8 +217,8 @@ end:
     if (made_keytab)
        krb5_kt_close(context, keytab);
     if (ret != GSS_S_COMPLETE) {
-       if (made_ccache)
-           krb5_cc_close(context, ccache);
+       if (ccache != NULL)
+           krb5_cc_close(gssapi_krb5_context, ccache);
        if (kret != 0) {
            *minor_status = kret;
            gssapi_krb5_set_error_string ();
@@ -255,7 +270,6 @@ end:
 OM_uint32 gsskrb5_acquire_cred
            (OM_uint32 * minor_status,
            struct krb5_keytab_data *keytab,
-           struct krb5_ccache_data *ccache,
             const gss_name_t desired_name,
             OM_uint32 time_req,
             const gss_OID_set desired_mechs,
@@ -314,7 +328,7 @@ OM_uint32 gsskrb5_acquire_cred
     }
     if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
        ret = acquire_initiator_cred(minor_status, gssapi_krb5_context, 
-                                    keytab, ccache, 
+                                    keytab, 
                                     desired_name, time_req,
                                     desired_mechs, cred_usage, 
                                     handle, actual_mechs, time_rec);
@@ -379,7 +393,7 @@ OM_uint32 gss_acquire_cred
            )
 {
        return gsskrb5_acquire_cred(minor_status,
-                                   NULL, NULL,
+                                   NULL, 
                                    desired_name,
                                    time_req,
                                    desired_mechs,
index 828ca64156984937ae077e02230db8897c70792b..0f2f155870164c541a6b0a1594902e581c530715 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "gssapi_locl.h"
 
-RCSID("$Id: copy_ccache.c,v 1.7 2003/09/01 15:11:09 lha Exp $");
+RCSID("$Id: copy_ccache.c,v 1.9 2005/10/31 16:02:08 lha Exp $");
 
 OM_uint32
 gss_krb5_copy_ccache(OM_uint32 *minor_status,
@@ -61,6 +61,94 @@ gss_krb5_copy_ccache(OM_uint32 *minor_status,
     return GSS_S_COMPLETE;
 }
 
+
+OM_uint32
+gss_krb5_import_ccache(OM_uint32 *minor_status,
+                      krb5_ccache in,
+                      gss_cred_id_t *cred)
+{
+    krb5_error_code kret;
+    gss_cred_id_t handle;
+    OM_uint32 ret;
+
+    *cred = NULL;
+
+    GSSAPI_KRB5_INIT ();
+
+    handle = (gss_cred_id_t)calloc(1, sizeof(*handle));
+    if (handle == GSS_C_NO_CREDENTIAL) {
+       gssapi_krb5_clear_status ();
+       *minor_status = ENOMEM;
+        return (GSS_S_FAILURE);
+    }
+    HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
+
+    handle->usage = GSS_C_INITIATE;
+
+    kret = krb5_cc_get_principal(gssapi_krb5_context, in, &handle->principal);
+    if (kret) {
+       free(handle);
+       gssapi_krb5_set_error_string ();
+       *minor_status = kret;
+       return GSS_S_FAILURE;
+    }
+
+    ret = _gssapi_krb5_ccache_lifetime(minor_status,
+                                      in,
+                                      handle->principal,
+                                      &handle->lifetime);
+    if (ret != GSS_S_COMPLETE) {
+       krb5_free_principal(gssapi_krb5_context, handle->principal);
+       free(handle);
+       return ret;
+    }
+
+    ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
+    if (ret == GSS_S_COMPLETE)
+       ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+                                    &handle->mechanisms);
+    if (ret != GSS_S_COMPLETE) {
+       krb5_free_principal(gssapi_krb5_context, handle->principal);
+       free(handle);
+       *minor_status = kret;
+       return GSS_S_FAILURE;
+    }
+
+    {
+       const char *type, *name;
+       char *str;
+
+       type = krb5_cc_get_type(gssapi_krb5_context, in);
+       name = krb5_cc_get_name(gssapi_krb5_context, in);
+       
+       if (asprintf(&str, "%s:%s", type, name) == -1) {
+           krb5_set_error_string(gssapi_krb5_context,
+                                 "malloc - out of memory");
+           kret = ENOMEM;
+           goto out;
+       }
+
+       kret = krb5_cc_resolve(gssapi_krb5_context, str, &handle->ccache);
+       free(str);
+       if (kret)
+           goto out;
+    }
+
+    *minor_status = 0;
+    *cred = handle;
+    return GSS_S_COMPLETE;
+
+out:
+    gssapi_krb5_set_error_string ();
+    if (handle->principal)
+       krb5_free_principal(gssapi_krb5_context, handle->principal);
+    HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+    free(handle);
+    *minor_status = kret;
+    return GSS_S_FAILURE;
+}
+
+
 OM_uint32
 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
                                            gss_ctx_id_t context_handle,
index 83658fa76c7cd4af039b0e7e35b14aa35ecfeb10..301197aa4c66b47da62baf68e93d235ff1c3ce11 100644 (file)
@@ -66,6 +66,8 @@ OM_uint32 gss_delete_sec_context
                          (*context_handle)->service_keyblock);
     if((*context_handle)->order)
        _gssapi_msg_order_destroy(&(*context_handle)->order);
+    if ((*context_handle)->fwd_data.length > 0)
+       free((*context_handle)->fwd_data.data);
 
     HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
     HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
index 4bf6780daa555b941f829bd275b5cc3beb2e7e71..64a31d1eeec0e3218411123a0073609da6dd5e4b 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE. 
  */
 
-/* $Id: gssapi.h,v 1.37 2005/02/21 08:48:15 lukeh Exp $ */
+/* $Id: gssapi.h,v 1.38 2005/10/26 11:22:13 lha Exp $ */
 
 #ifndef GSSAPI_H_
 #define GSSAPI_H_
@@ -778,7 +778,6 @@ OM_uint32 gss_unseal
 OM_uint32 gsskrb5_acquire_cred
            (OM_uint32 * minor_status,
            struct krb5_keytab_data *keytab,
-           struct krb5_ccache_data *ccache,
             const gss_name_t desired_name,
             OM_uint32 time_req,
             const gss_OID_set desired_mechs,
@@ -806,6 +805,11 @@ OM_uint32 gss_krb5_copy_service_keyblock
         gss_ctx_id_t context_handle,
         struct EncryptionKey **out);
 
+OM_uint32
+gss_krb5_import_ccache(OM_uint32 */*minor*/,
+                      struct krb5_ccache_data * /*in*/,
+                      gss_cred_id_t */*out*/);
+
 OM_uint32 gss_krb5_get_tkt_flags
        (OM_uint32 */*minor*/,
         gss_ctx_id_t /*context_handle*/,
index 1d22099877ca5c10465f5a5598feab018490626e..aa663e87a6a4fc892dd68afe2bd86842eefbec83 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden). 
  * All rights reserved. 
  *
@@ -31,7 +31,7 @@
  * SUCH DAMAGE. 
  */
 
-/* $Id: gssapi_locl.h,v 1.41 2005/10/12 15:20:37 lha Exp $ */
+/* $Id: gssapi_locl.h,v 1.42 2005/10/26 11:23:48 lha Exp $ */
 
 #ifndef GSSAPI_LOCL_H
 #define GSSAPI_LOCL_H
@@ -79,12 +79,13 @@ typedef struct gss_ctx_id_t_desc_struct {
 
 typedef struct gss_cred_id_t_desc_struct {
   gss_name_t principal;
+  int cred_flags;
+#define GSS_CF_DESTROY_CRED_ON_RELEASE 1
   krb5_boolean made_keytab;
   struct krb5_keytab_data *keytab;
   OM_uint32 lifetime;
   gss_cred_usage_t usage;
   gss_OID_set mechanisms;
-  krb5_boolean made_ccache;
   struct krb5_ccache_data *ccache;
   HEIMDAL_MUTEX cred_id_mutex;
 } gss_cred_id_t_desc;
@@ -108,7 +109,6 @@ struct gssapi_thr_context {
  */
 
 krb5_error_code gssapi_krb5_init (void);
-krb5_error_code gssapi_krb5_init_ev (void *event_context);
 
 #define GSSAPI_KRB5_INIT() do {                                        \
     krb5_error_code kret_gss_init;                             \
@@ -271,6 +271,10 @@ _gss_check_compat(OM_uint32 *, gss_name_t, const char *,
 OM_uint32
 gssapi_lifetime_left(OM_uint32 *, OM_uint32, OM_uint32 *);
 
+OM_uint32
+_gssapi_krb5_ccache_lifetime(OM_uint32 *, krb5_ccache, 
+                            krb5_principal, OM_uint32 *);
+
 /* sequence */
 
 OM_uint32
index 93e8d44c860b6324bcfe644e36dc66b2873eb47d..b8eb748bf5dc2ac370d933a899f20acdcaeb5d0d 100644 (file)
@@ -162,7 +162,7 @@ _gsskrb5_create_ctx(
 static OM_uint32
 gsskrb5_get_creds(
        OM_uint32 * minor_status,
-       const gss_cred_id_t initiator_cred_handle,
+       krb5_ccache ccache,
        gss_ctx_id_t * context_handle,
        const gss_name_t target_name,
        OM_uint32 time_req,
@@ -172,22 +172,10 @@ gsskrb5_get_creds(
        OM_uint32 ret;
        krb5_error_code kret;
        krb5_creds this_cred;
-       krb5_ccache ccache = NULL;
        OM_uint32 lifetime_rec;
 
        *cred = NULL;
 
-       if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
-               kret = krb5_cc_default (gssapi_krb5_context, &ccache);
-               if (kret) {
-                       gssapi_krb5_set_error_string ();
-                       *minor_status = kret;
-                       return GSS_S_FAILURE;
-               }
-       } else {
-               ccache = initiator_cred_handle->ccache;
-       }
-
        kret = krb5_cc_get_principal(gssapi_krb5_context,
                                     ccache,
                                     &(*context_handle)->source);
@@ -246,10 +234,6 @@ gsskrb5_get_creds(
 
        if (time_rec) *time_rec = lifetime_rec;
 
-       if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
-               krb5_cc_close(gssapi_krb5_context, ccache);
-       }
-
        return GSS_S_COMPLETE;
 }
 
@@ -351,7 +335,7 @@ do_delegation (krb5_auth_context ac,
 static OM_uint32
 gsskrb5_initiator_start
 (OM_uint32 * minor_status,
const gss_cred_id_t initiator_cred_handle,
krb5_ccache ccache,
  gss_ctx_id_t * context_handle,
  const gss_name_t target_name,
  const gss_OID mech_type,
@@ -369,7 +353,6 @@ gsskrb5_initiator_start
     krb5_flags ap_options;
     krb5_creds *cred = NULL;
     krb5_data outbuf;
-    krb5_ccache ccache = NULL;
     u_int32_t flags;
     krb5_data authenticator;
     Checksum cksum;
@@ -383,7 +366,7 @@ gsskrb5_initiator_start
 
        /* We need to get the credentials for the requested target */
        ret = gsskrb5_get_creds(minor_status,
-                               initiator_cred_handle,
+                               ccache, 
                                context_handle,
                                target_name,
                                time_req,
@@ -543,7 +526,7 @@ gsskrb5_initiator_start
 static OM_uint32
 gsskrb5_initiator_wait_for_mutual(
        OM_uint32 * minor_status,
-       const gss_cred_id_t initiator_cred_handle,
+       krb5_ccache ccache,
        gss_ctx_id_t * context_handle,
        const gss_name_t target_name,
        const gss_OID mech_type,
@@ -697,6 +680,8 @@ gsskrb5_init_sec_context
           )
 {
        OM_uint32 ret;
+       krb5_error_code kret;
+       krb5_ccache ccache = NULL;
 
        if (*context_handle == GSS_C_NO_CONTEXT) {
                ret = _gsskrb5_create_ctx(minor_status,
@@ -708,12 +693,23 @@ gsskrb5_init_sec_context
 
        if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM;
 
+       if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
+               kret = krb5_cc_default (gssapi_krb5_context, &ccache);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       } else {
+               ccache = initiator_cred_handle->ccache;
+       }
+
        HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
 
        switch ((*context_handle)->state) {
        case INITIATOR_START:
                ret = gsskrb5_initiator_start(minor_status,
-                                             initiator_cred_handle,
+                                             ccache,
                                              context_handle,
                                              target_name,
                                              mech_type,
@@ -727,7 +723,7 @@ gsskrb5_init_sec_context
                break;
        case INITIATOR_WAIT_FOR_MUTAL:
                ret = gsskrb5_initiator_wait_for_mutual(minor_status,
-                                                       initiator_cred_handle,
+                                                       ccache,
                                                        context_handle,
                                                        target_name,
                                                        mech_type,
@@ -771,6 +767,10 @@ gsskrb5_init_sec_context
                break;
        }
 
+       if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
+               krb5_cc_close(gssapi_krb5_context, ccache);
+       }
+
        HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
 
        return ret;
index 8ae65dd528decb6e8fc0142193785a4a18f5cb5c..ddd80c144b8695a609b891ace8f0df99911cc45d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden). 
  * All rights reserved. 
  *
@@ -54,10 +54,10 @@ OM_uint32 gss_release_cred
         krb5_free_principal(gssapi_krb5_context, (*cred_handle)->principal);
     if ((*cred_handle)->made_keytab)
        krb5_kt_close(gssapi_krb5_context, (*cred_handle)->keytab);
-    if ((*cred_handle)->made_ccache) {
+    if ((*cred_handle)->ccache != NULL) {
        const krb5_cc_ops *ops;
        ops = krb5_cc_get_ops(gssapi_krb5_context, (*cred_handle)->ccache);
-       if (ops == &krb5_mcc_ops)
+       if ((*cred_handle)->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE)
            krb5_cc_destroy(gssapi_krb5_context, (*cred_handle)->ccache);
        else 
            krb5_cc_close(gssapi_krb5_context, (*cred_handle)->ccache);
index 8f4f8fb152d903a2ae08227b37851f0e3d9ed9a1..7dae26acf244dd5bd1a0e234989f6d591192bfab 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "krb5_locl.h"
 
-RCSID("$Id: ticket.c,v 1.12 2004/05/25 21:44:47 lha Exp $");
+RCSID("$Id: ticket.c,v 1.14 2005/10/27 13:21:42 lha Exp $");
 
 krb5_error_code KRB5_LIB_FUNCTION
 krb5_free_ticket(krb5_context context,
@@ -151,6 +151,7 @@ find_type_in_ad(krb5_context context,
                goto out;
            break;
        }
+#if 0 /* XXX test */
        case KRB5_AUTHDATA_KDC_ISSUED: {
            AD_KDCIssued child;
 
@@ -199,6 +200,7 @@ find_type_in_ad(krb5_context context,
                goto out;
            break;
        }
+#endif
        case KRB5_AUTHDATA_AND_OR:
            if (!failp)
                break;
@@ -229,7 +231,7 @@ out:
 /*
  * Extract the authorization data type of `type' from the
  * 'ticket'. Store the field in `data'. This function is to use for
- * kerberos applications
+ * kerberos applications.
  */
 
 krb5_error_code KRB5_LIB_FUNCTION
index cb6fbb38808c39687f4e43c9f7bb3e18df47cf87..5d0576e8f9aff9f510335e2ef4e79e507fd6984b 100644 (file)
@@ -32,6 +32,7 @@
 #include "libcli/smb_composite/smb_composite.h"
 #include "smb_server/smb_server.h"
 #include "smbd/service_stream.h"
+#include "auth/auth.h"
 
 /* this is stored in ntvfs_private */
 struct cvfs_private {
@@ -106,11 +107,6 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
                remote_share = sharename;
        }
 
-       if (!host || !user || !pass || !domain) {
-               DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-       
        private = talloc(req->tcon, struct cvfs_private);
        if (!private) {
                return NT_STATUS_NO_MEMORY;
@@ -119,11 +115,23 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
 
        ntvfs->private_data = private;
 
-       credentials = cli_credentials_init(private);
-       cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
-       cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
-       cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
-       cli_credentials_set_workstation(credentials, "vfs_cifs", CRED_SPECIFIED);
+       if (!host) {
+               DEBUG(1,("CIFS backend: You must supply server\n"));
+               return NT_STATUS_INVALID_PARAMETER;
+       } 
+       
+       if (user && pass && domain) {
+               credentials = cli_credentials_init(private);
+               cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
+               cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
+               cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
+               cli_credentials_set_workstation(credentials, "vfs_cifs", CRED_SPECIFIED);
+       } else if (req->session->session_info->credentials) {
+               credentials = req->session->session_info->credentials;
+       } else {
+               DEBUG(1,("CIFS backend: You must supply server, user, password and domain or have delegated credentials\n"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
        /* connect to the server, using the smbd event context */
        io.in.dest_host = host;