r1475: More kerberos work
authorAndrew Bartlett <abartlet@samba.org>
Tue, 13 Jul 2004 05:14:59 +0000 (05:14 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:57:34 +0000 (12:57 -0500)
- We can now connect to hosts that follow the SPNEGO RFC, and *do not*
give us their principal name in the mechListMIC.
 - The client code now remembers the hostname it connects to

- We now kinit for a user, if there is not valid ticket already

- Re-introduce clock skew compensation

TODO:
 - See if the username in the ccache matches the username specified
 - Use a private ccache, rather then the global one, for a 'new' kinit
 - Determine 'default' usernames.
  - The default for Krb5 is the one in the ccache, then $USER
  - For NTLMSSP, it's just $USER

Andrew Bartlett
(This used to be commit de5da669397db4ac87c6da08d3533ca3030da2b0)

source4/include/cli_context.h
source4/libcli/auth/gensec.c
source4/libcli/auth/gensec.h
source4/libcli/auth/gensec_krb5.c
source4/libcli/auth/kerberos.c
source4/libcli/auth/kerberos.h
source4/libcli/auth/spnego.c
source4/libcli/raw/clisession.c
source4/libcli/raw/clisocket.c
source4/librpc/rpc/dcerpc_spnego.c

index cddc6aadf542e93be861a1846629c601c6634051..b2a68de0cb338614f4de835867590303126d2faa 100644 (file)
@@ -79,6 +79,8 @@ struct cli_socket {
        int reference_count;
 
        struct in_addr dest_ip;
+       /* dest hostname (which may or may not be a DNS name) */
+       char *hostname;
 
        /* the port used */
        int port;
index f4aeedf6923cabb43a45179ae575df2cb93810ab..e91497bee4f0118df90ea2a46524237c52883d52 100644 (file)
@@ -106,6 +106,14 @@ static NTSTATUS gensec_start(struct gensec_security **gensec_security)
        (*gensec_security)->mem_ctx = mem_ctx;
        (*gensec_security)->ops = NULL;
 
+       ZERO_STRUCT((*gensec_security)->user);
+       ZERO_STRUCT((*gensec_security)->target);
+       ZERO_STRUCT((*gensec_security)->default_user);
+
+       (*gensec_security)->default_user.name = "";
+       (*gensec_security)->default_user.domain = talloc_strdup(mem_ctx, lp_workgroup());
+       (*gensec_security)->default_user.realm = talloc_strdup(mem_ctx, lp_realm());
+
        (*gensec_security)->subcontext = False;
        return NT_STATUS_OK;
 }
@@ -163,6 +171,9 @@ NTSTATUS gensec_server_start(struct gensec_security **gensec_security)
 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
 {
        NTSTATUS status;
+       DEBUG(5, ("Starting GENSEC %smechanism %s\n", 
+                 gensec_security->subcontext ? "sub" : "", 
+                 gensec_security->ops->name));
        switch (gensec_security->gensec_role) {
        case GENSEC_CLIENT:
                if (gensec_security->ops->client_start) {
@@ -337,6 +348,61 @@ void gensec_end(struct gensec_security **gensec_security)
        gensec_security = NULL;
 }
 
+/** 
+ * Set a username on a GENSEC context - ensures it is talloc()ed 
+ *
+ */
+
+NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user) 
+{
+       char *p;
+       char *u = talloc_strdup(gensec_security->mem_ctx, user);
+       if (!u) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       p = strchr_m(user, '@');
+       
+       if (p) {
+               *p = '\0';
+               gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, u);
+               if (!gensec_security->user.name) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               
+               gensec_security->user.realm = talloc_strdup(gensec_security->mem_ctx, p+1);
+               if (!gensec_security->user.realm) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               return NT_STATUS_OK;
+       } 
+
+       p = strchr_m(user, '\\');
+       if (!p) {
+               p = strchr_m(user, '/');
+       }
+       
+       if (p) {
+               *p = '\0';
+               gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, u);
+               if (!gensec_security->user.domain) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, p+1);
+               if (!gensec_security->user.name) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               
+               return NT_STATUS_OK;
+       } 
+       
+       gensec_security->user.name = u;
+       if (!gensec_security->user.name) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
 /** 
  * Set a username on a GENSEC context - ensures it is talloc()ed 
  *
@@ -351,6 +417,19 @@ NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char
        return NT_STATUS_OK;
 }
 
+/** 
+ * Set a username on a GENSEC context - ensures it is talloc()ed 
+ *
+ */
+
+const char *gensec_get_username(struct gensec_security *gensec_security) 
+{
+       if (gensec_security->user.name) {
+               return gensec_security->user.name;
+       }
+       return gensec_security->default_user.name;
+}
+
 /** 
  * Set a domain on a GENSEC context - ensures it is talloc()ed 
  *
@@ -366,19 +445,18 @@ NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *
 }
 
 /** 
- * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
- * not do a callback
+ * Return the NT domain for this GENSEC context
  *
  */
 
-NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
-                            const char *password) 
+const char *gensec_get_domain(struct gensec_security *gensec_security) 
 {
-       gensec_security->user.password = talloc_strdup(gensec_security->mem_ctx, password);
-       if (!gensec_security->user.password) {
-               return NT_STATUS_NO_MEMORY;
+       if (gensec_security->user.domain) {
+               return gensec_security->user.domain;
+       } else if (gensec_security->user.realm) {
+               return gensec_security->user.realm;
        }
-       return NT_STATUS_OK;
+       return gensec_security->default_user.domain;
 }
 
 /** 
@@ -395,6 +473,54 @@ NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *r
        return NT_STATUS_OK;
 }
 
+/** 
+ * Return the Krb5 realm for this context
+ *
+ */
+
+const char *gensec_get_realm(struct gensec_security *gensec_security) 
+{
+       if (gensec_security->user.realm) {
+               return gensec_security->user.realm;
+       } else if (gensec_security->user.domain) {
+               return gensec_security->user.domain;
+       }
+       return gensec_security->default_user.realm;
+}
+
+/** 
+ * Return a kerberos principal for this context, if one has been set 
+ *
+ */
+
+char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx) 
+{
+       const char *realm = gensec_get_realm(gensec_security);
+       if (realm) {
+               return talloc_asprintf(mem_ctx, "%s@%s", 
+                                      gensec_get_username(gensec_security), 
+                                      gensec_get_realm(gensec_security));
+       } else {
+               return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
+       }
+}
+
+/** 
+ * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
+ * not do a callback
+ *
+ */
+
+NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
+                            const char *password) 
+{
+       gensec_security->user.password = talloc_strdup(gensec_security->mem_ctx, password);
+       if (!gensec_security->user.password) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
 /** 
  * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed 
  *
@@ -409,6 +535,53 @@ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, co
        return NT_STATUS_OK;
 }
 
+/** 
+ * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
+ *
+ */
+
+NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
+{
+       gensec_security->target.service = talloc_strdup(gensec_security->mem_ctx, service);
+       if (!gensec_security->target.service) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
+ *
+ */
+
+NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
+{
+       gensec_security->target.hostname = talloc_strdup(gensec_security->mem_ctx, hostname);
+       if (!gensec_security->target.hostname) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
+{
+       if (gensec_security->target.hostname) {
+               return gensec_security->target.hostname;
+       }
+
+       /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
+       return NULL;
+}
+
+const char *gensec_get_target_service(struct gensec_security *gensec_security) 
+{
+       if (gensec_security->target.service) {
+               return gensec_security->target.service;
+       }
+
+       return "host";
+}
+
 /** 
  * Set a password callback, if the gensec module we use demands a password
  */
index 7cd56936d27dcaef881f96fa6b78ea9016746357..8e2787530c20e811facfcdaf6b692eab16be79ea 100644 (file)
@@ -34,6 +34,7 @@ struct gensec_target {
        const char *principal;
        const char *hostname;
        const struct sock_addr *addr;
+       const char *service;
 };
                
 
@@ -79,6 +80,7 @@ struct gensec_security {
        const struct gensec_security_ops *ops;
        void *private_data;
        struct gensec_user user;
+       struct gensec_user default_user;
        struct gensec_target target;
        enum gensec_role gensec_role;
        BOOL subcontext;
index 3a4f995937d538c486df40013f3749ad2bb90dbb..78b6e334a70ef3e354fcc3cb1613ee07ecb9180a 100644 (file)
@@ -43,6 +43,7 @@ struct gensec_krb5_state {
        krb5_context krb5_context;
        krb5_auth_context krb5_auth_context;
        krb5_ccache krb5_ccache;
+       krb5_data ticket;
 };
 
 static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
@@ -68,6 +69,7 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
        gensec_krb5_state->krb5_context = NULL;
        gensec_krb5_state->krb5_auth_context = NULL;
        gensec_krb5_state->krb5_ccache = NULL;
+       ZERO_STRUCT(gensec_krb5_state->ticket);
        gensec_krb5_state->session_key = data_blob(NULL, 0);
 
        ret = krb5_init_context(&gensec_krb5_state->krb5_context);
@@ -114,6 +116,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
        struct gensec_krb5_state *gensec_krb5_state;
        krb5_error_code ret;
        NTSTATUS nt_status;
+
        nt_status = gensec_krb5_start(gensec_security);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
@@ -122,6 +125,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
        gensec_krb5_state = gensec_security->private_data;
        gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START;
 
+       /* TODO: This is effecivly a static/global variable... */ 
        ret = krb5_cc_default(gensec_krb5_state->krb5_context, &gensec_krb5_state->krb5_ccache);
        if (ret) {
                DEBUG(1,("krb5_cc_default failed (%s)\n",
@@ -129,13 +133,101 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
                return NT_STATUS_INTERNAL_ERROR;
        }
        
-       return NT_STATUS_OK;
+       while (1) {
+               if (gensec_security->target.principal) {
+                       DEBUG(5, ("Finding ticket for target [%s]\n", gensec_security->target.principal));
+                       ret = ads_krb5_mk_req(gensec_krb5_state->krb5_context, 
+                                             &gensec_krb5_state->krb5_auth_context,
+                                             AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED,
+                                             gensec_security->target.principal,
+                                             gensec_krb5_state->krb5_ccache, 
+                                             &gensec_krb5_state->ticket);
+                       if (ret) {
+                               DEBUG(1,("ads_krb5_mk_req failed (%s)\n", 
+                                        error_message(ret)));
+                       }
+               } else {
+                       krb5_data in_data;
+                       in_data.length = 0;
+                       const char *hostname = gensec_get_target_hostname(gensec_security);
+                       if (!hostname) {
+                               DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+                       ret = krb5_mk_req(gensec_krb5_state->krb5_context, 
+                                         &gensec_krb5_state->krb5_auth_context,
+                                         AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED,
+                                         gensec_get_target_service(gensec_security),
+                                         hostname,
+                                         &in_data, gensec_krb5_state->krb5_ccache, 
+                                         &gensec_krb5_state->ticket);
+                       if (ret) {
+                               DEBUG(1,("krb5_mk_req failed (%s)\n", 
+                                        error_message(ret)));
+                       }
+                       
+               }
+               switch (ret) {
+               case 0:
+                       return NT_STATUS_OK;
+               case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
+                       DEBUG(3, ("Server is not registered with our KDC: %s\n", 
+                                 error_message(ret)));
+                       return NT_STATUS_ACCESS_DENIED;
+               case KRB5KDC_ERR_PREAUTH_FAILED:
+               case KRB5KRB_AP_ERR_TKT_EXPIRED:
+               case KRB5_CC_END:
+               case KRB5_FCC_NOFILE:
+               case KRB5_CC_NOTFOUND:
+               {
+                       char *password;
+                       time_t kdc_time;
+                       DEBUG(3, ("kerberos: %s\n", 
+                                 error_message(ret)));
+                       nt_status = gensec_get_password(gensec_security, 
+                                                       gensec_security->mem_ctx, 
+                                                       &password);
+                       if (!NT_STATUS_IS_OK(nt_status)) {
+                               return nt_status;
+                       }
+
+                       ret = kerberos_kinit_password_cc(gensec_krb5_state->krb5_context, gensec_krb5_state->krb5_ccache, 
+                                                        gensec_get_client_principal(gensec_security, gensec_security->mem_ctx), 
+                                                        password, NULL, &kdc_time);
+
+                       /* cope with ticket being in the future due to clock skew */
+                       if ((unsigned)kdc_time > time(NULL)) {
+                               time_t t = time(NULL);
+                               int time_offset =(unsigned)kdc_time-t;
+                               DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
+                               krb5_set_real_time(gensec_krb5_state->krb5_context, t + time_offset + 1, 0);
+                       }
+       
+                       if (ret) {
+                               DEBUG(1,("kinit failed (%s)\n", 
+                                        error_message(ret)));
+                               return NT_STATUS_WRONG_PASSWORD;
+                       }
+                       break;
+               }
+               default:
+                       DEBUG(0, ("kerberos: %s\n", 
+                                 error_message(ret)));
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+       }
 }
 
 static void gensec_krb5_end(struct gensec_security *gensec_security)
 {
        struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
 
+       if (gensec_krb5_state->ticket.length) { 
+       /* Hmm, heimdal dooesn't have this - what's the correct call? */
+#ifdef HAVE_KRB5_FREE_DATA_CONTENTS
+               krb5_free_data_contents(gensec_krb5_state->krb5_context, &gensec_krb5_state->ticket); 
+#endif
+       }
        if (gensec_krb5_state->krb5_ccache) {
                /* Removed by jra. They really need to fix their kerberos so we don't leak memory. 
                   JERRY -- disabled since it causes heimdal 0.6.1rc3 to die
@@ -182,33 +274,17 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, TALL
        switch (gensec_krb5_state->state_position) {
        case GENSEC_KRB5_CLIENT_START:
        {
-               krb5_data packet;
-               
-#if 0 /* When we get some way to input the time offset */
-               if (time_offset != 0) {
-                       krb5_set_real_time(context, time(NULL) + time_offset, 0);
-               }
-#endif
-
-               ret = ads_krb5_mk_req(gensec_krb5_state->krb5_context, 
-                                     &gensec_krb5_state->krb5_auth_context, 
-                                     AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED,
-                                     gensec_security->target.principal,
-                                     gensec_krb5_state->krb5_ccache, &packet);
                if (ret) {
                        DEBUG(1,("ads_krb5_mk_req (request ticket) failed (%s)\n",
                                 error_message(ret)));
                        nt_status = NT_STATUS_LOGON_FAILURE;
                } else {
                        DATA_BLOB unwrapped_out;
-                       unwrapped_out = data_blob_talloc(out_mem_ctx, packet.data, packet.length);
+                       unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length);
                        
                        /* wrap that up in a nice GSS-API wrapping */
                        *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ);
-                       /* Hmm, heimdal dooesn't have this - what's the correct call? */
-#ifdef HAVE_KRB5_FREE_DATA_CONTENTS
-                       krb5_free_data_contents(gensec_krb5_state->krb5_context, &packet); 
-#endif
+
                        gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH;
                        nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
                }
index 97b895a2418a976b272512da720c528c2e3beacb..b08c7f505c22b23f19c4df3c352ccd1ca2e32c81 100644 (file)
@@ -54,28 +54,13 @@ kerb_prompter(krb5_context ctx, void *data,
   simulate a kinit, putting the tgt in the default cache location
   remus@snapserver.com
 */
-int kerberos_kinit_password(const char *principal, const char *password, int time_offset, time_t *expire_time)
+ int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, const char *principal, const char *password, time_t *expire_time, time_t *kdc_time)
 {
-       krb5_context ctx = NULL;
        krb5_error_code code = 0;
-       krb5_ccache cc = NULL;
        krb5_principal me;
        krb5_creds my_creds;
 
-       if ((code = krb5_init_context(&ctx)))
-               return code;
-
-       if (time_offset != 0) {
-               krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
-       }
-       
-       if ((code = krb5_cc_default(ctx, &cc))) {
-               krb5_free_context(ctx);
-               return code;
-       }
-       
        if ((code = krb5_parse_name(ctx, principal, &me))) {
-               krb5_free_context(ctx); 
                return code;
        }
        
@@ -83,32 +68,63 @@ int kerberos_kinit_password(const char *principal, const char *password, int tim
                                                 kerb_prompter, 
                                                 NULL, 0, NULL, NULL))) {
                krb5_free_principal(ctx, me);
-               krb5_free_context(ctx);         
                return code;
        }
        
        if ((code = krb5_cc_initialize(ctx, cc, me))) {
                krb5_free_cred_contents(ctx, &my_creds);
                krb5_free_principal(ctx, me);
-               krb5_free_context(ctx);         
                return code;
        }
        
        if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
-               krb5_cc_close(ctx, cc);
                krb5_free_cred_contents(ctx, &my_creds);
                krb5_free_principal(ctx, me);
-               krb5_free_context(ctx);         
                return code;
        }
        
-       if (expire_time)
+       if (expire_time) {
                *expire_time = (time_t) my_creds.times.endtime;
+       }
+
+       if (kdc_time) {
+               *kdc_time = (time_t) my_creds.times.starttime;
+       }
 
-       krb5_cc_close(ctx, cc);
        krb5_free_cred_contents(ctx, &my_creds);
        krb5_free_principal(ctx, me);
-       krb5_free_context(ctx);         
+       
+       return 0;
+}
+
+
+/*
+  simulate a kinit, putting the tgt in the default cache location
+  remus@snapserver.com
+*/
+int kerberos_kinit_password(const char *principal, const char *password, int time_offset, time_t *expire_time, time_t *kdc_time)
+{
+       krb5_context ctx = NULL;
+       krb5_error_code code = 0;
+       krb5_ccache cc = NULL;
+
+       if ((code = krb5_init_context(&ctx)))
+               return code;
+
+       if (time_offset != 0) {
+               krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
+       }
+       
+       if ((code = krb5_cc_default(ctx, &cc))) {
+               krb5_free_context(ctx);
+               return code;
+       }
+
+       if ((code = kerberos_kinit_password_cc(ctx, cc, principal, password, expire_time, kdc_time))) {
+               krb5_cc_close(ctx, cc);
+               krb5_free_context(ctx);
+               return code;
+       }
        
        return 0;
 }
@@ -129,7 +145,7 @@ int ads_kinit_password(ADS_STRUCT *ads)
                return KRB5_LIBOS_CANTREADPWD;
        }
        
-       ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset, &ads->auth.expire);
+       ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset, &ads->auth.expire, NULL);
 
        if (ret) {
                DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
index 4a9d82acf107685185dcaeda21c801c65f3eaa4b..ca796d0c86de590680e307def301ed0252cb5a9c 100644 (file)
@@ -69,5 +69,6 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
                           const char *realm, const DATA_BLOB *ticket, 
                           char **principal, DATA_BLOB *auth_data,
                           DATA_BLOB *ap_rep);
+int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, const char *principal, const char *password, time_t *expire_time, time_t *kdc_time);
 #endif /* HAVE_KRB5 */
 
index 32846cf5803e0d93579b44cd8e9b411c7e3dd7ef..d4910eb92f95e4fa44437b812111b654745934cf 100644 (file)
@@ -256,7 +256,7 @@ static NTSTATUS gensec_spnego_client_netTokenInit(struct gensec_security *gensec
                        return nt_status;
        }
        nt_status = gensec_update(spnego_state->sub_sec_security,
-                                                 out_mem_ctx, in, &unwrapped_out);
+                                 out_mem_ctx, in, &unwrapped_out);
        if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                struct spnego_data spnego_out;
                spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
@@ -349,6 +349,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
                }
 
                if (spnego.negTokenInit.targetPrincipal) {
+                       DEBUG(5, ("Server claims it's principal name is %s\n", spnego.negTokenInit.targetPrincipal));
                        nt_status = gensec_set_target_principal(gensec_security, 
                                                                spnego.negTokenInit.targetPrincipal);
                        if (!NT_STATUS_IS_OK(nt_status)) {
index 5aaceb103a2a9637e6792eaffde42a187a257748..e31cf07bf819ca845f739c05e961e63e07a63f68 100644 (file)
@@ -424,6 +424,13 @@ static NTSTATUS smb_raw_session_setup_generic_spnego(struct cli_session *session
                goto done;
        }
 
+       status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
+                         nt_errstr(status)));
+               goto done;
+       }
+
        status = gensec_start_mech_by_oid(session->gensec, OID_SPNEGO);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
index 4dae7d517dba50bd8f9a0429b55989c589051103..5cd6f33689afb8a8620ab66f65027465839efa45 100644 (file)
@@ -45,6 +45,8 @@ struct cli_socket *cli_sock_init(void)
        /* 20 second default timeout */
        sock->timeout = 20000;
 
+       sock->hostname = NULL;
+
        return sock;
 }
 
@@ -140,6 +142,7 @@ BOOL cli_sock_connect_byname(struct cli_socket *sock, const char *host, int port
        struct in_addr ip;
        TALLOC_CTX *mem_ctx;
        char *name, *p;
+       BOOL ret;
 
        if (getenv("LIBSMB_PROG")) {
                sock->fd = sock_exec(getenv("LIBSMB_PROG"));
@@ -162,7 +165,13 @@ BOOL cli_sock_connect_byname(struct cli_socket *sock, const char *host, int port
                return False;
        }
 
+       ret = cli_sock_connect(sock, &ip, port);
+
+       if (ret) {
+               sock->hostname = talloc_steal(mem_ctx, sock->mem_ctx, name);
+       }
+
        talloc_destroy(mem_ctx);
 
-       return cli_sock_connect(sock, &ip, port);
+       return ret;
 }
index 37f2c75b654586300fb6ff347caf51e14f442585..7ccc0cf422425f927ac3d6f2d4d0c53f6ea3e558 100644 (file)
@@ -60,6 +60,13 @@ NTSTATUS dcerpc_bind_auth_spnego(struct dcerpc_pipe *p,
                return status;
        }
 
+       status = gensec_set_target_hostname(p->security_state.generic_state, p->transport.peer_name(p));
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
+                         nt_errstr(status)));
+               return status;
+       }
+
        status = gensec_start_mech_by_authtype(p->security_state.generic_state, DCERPC_AUTH_TYPE_SPNEGO);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",