summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2008-01-31 13:05:36 +0100
committerGünther Deschner <gd@samba.org>2008-01-31 13:05:36 +0100
commit83b04c60fac76ccd2d5aecb14f8896a07d488b1f (patch)
treebe20f8e821fc62109081a4edafa1eabc7d4004a6
parent945bbd14bb1c8ec11365d52a7897ca17e95c9053 (diff)
downloadsamba-83b04c60fac76ccd2d5aecb14f8896a07d488b1f.tar.gz
Enable v3-0-test to successfully join a windows 2008 domain controller.
This is hand-merged from a couple of commits from 3-2-test, cherry-picking was hardly possible without importing all the ldap sign/seal work from metze. Guenther
-rw-r--r--source/include/ads.h3
-rw-r--r--source/libads/sasl.c140
-rw-r--r--source/libads/util.c57
-rw-r--r--source/libsmb/cliconnect.c3
4 files changed, 164 insertions, 39 deletions
diff --git a/source/include/ads.h b/source/include/ads.h
index fcaeb2069d2..24884f5e185 100644
--- a/source/include/ads.h
+++ b/source/include/ads.h
@@ -321,4 +321,7 @@ typedef struct {
int val;
int critical;
} ads_control;
+
+#define ADS_IGNORE_PRINCIPAL "not_defined_in_RFC4178@please_ignore"
+
#endif /* _INCLUDE_ADS_H_ */
diff --git a/source/libads/sasl.c b/source/libads/sasl.c
index 0067a19d3b6..40749be745c 100644
--- a/source/libads/sasl.c
+++ b/source/libads/sasl.c
@@ -137,10 +137,81 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
}
#ifdef HAVE_KRB5
+struct ads_service_principal {
+ char *string;
+#ifdef HAVE_GSSAPI
+ gss_name_t name;
+#endif
+};
+
+static void ads_free_service_principal(struct ads_service_principal *p)
+{
+ SAFE_FREE(p->string);
+
+#ifdef HAVE_GSSAPI
+ if (p->name) {
+ uint32 minor_status;
+ gss_release_name(&minor_status, &p->name);
+ }
+#endif
+ ZERO_STRUCTP(p);
+}
+
+static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
+ const char *given_principal,
+ struct ads_service_principal *p)
+{
+ ADS_STATUS status;
+#ifdef HAVE_GSSAPI
+ gss_buffer_desc input_name;
+ /* GSS_KRB5_NT_PRINCIPAL_NAME */
+ gss_OID_desc nt_principal =
+ {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
+ uint32 minor_status;
+ int gss_rc;
+#endif
+
+ ZERO_STRUCTP(p);
+
+ /* I've seen a child Windows 2000 domain not send
+ the principal name back in the first round of
+ the SASL bind reply. So we guess based on server
+ name and realm. --jerry */
+ /* Also try best guess when we get the w2k8 ignore
+ principal back - gd */
+
+ if (!given_principal ||
+ strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
+
+ status = ads_guess_service_principal(ads, &p->string);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ } else {
+ p->string = SMB_STRDUP(given_principal);
+ if (!p->string) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+#ifdef HAVE_GSSAPI
+ input_name.value = p->string;
+ input_name.length = strlen(p->string);
+
+ gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
+ if (gss_rc) {
+ ads_free_service_principal(p);
+ return ADS_ERROR_GSS(gss_rc, minor_status);
+ }
+#endif
+
+ return ADS_SUCCESS;
+}
+
/*
perform a LDAP/SASL/SPNEGO/KRB5 bind
*/
-static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *principal)
+static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
{
DATA_BLOB blob = data_blob(NULL, 0);
struct berval cred, *scred = NULL;
@@ -167,6 +238,13 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip
return ADS_ERROR(rc);
}
+
+static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
+ struct ads_service_principal *p)
+{
+ return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
+}
+
#endif
/*
@@ -178,7 +256,7 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
int rc, i;
ADS_STATUS status;
DATA_BLOB blob;
- char *principal = NULL;
+ char *given_principal = NULL;
char *OIDs[ASN1_MAX_OIDS];
#ifdef HAVE_KRB5
BOOL got_kerberos_mechanism = False;
@@ -201,7 +279,7 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
/* the server sent us the first part of the SPNEGO exchange in the negprot
reply */
- if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
+ if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
data_blob_free(&blob);
status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
goto failed;
@@ -219,42 +297,23 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
#endif
free(OIDs[i]);
}
- DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", principal));
+ DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
#ifdef HAVE_KRB5
if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
got_kerberos_mechanism)
{
- /* I've seen a child Windows 2000 domain not send
- the principal name back in the first round of
- the SASL bind reply. So we guess based on server
- name and realm. --jerry */
- if ( !principal ) {
- if ( ads->server.realm && ads->server.ldap_server ) {
- char *server, *server_realm;
-
- server = SMB_STRDUP( ads->server.ldap_server );
- server_realm = SMB_STRDUP( ads->server.realm );
-
- if ( !server || !server_realm )
- return ADS_ERROR(LDAP_NO_MEMORY);
-
- strlower_m( server );
- strupper_m( server_realm );
- asprintf( &principal, "ldap/%s@%s", server, server_realm );
-
- SAFE_FREE( server );
- SAFE_FREE( server_realm );
-
- if ( !principal )
- return ADS_ERROR(LDAP_NO_MEMORY);
- }
-
+ struct ads_service_principal p;
+
+ status = ads_generate_service_principal(ads, given_principal, &p);
+ SAFE_FREE(given_principal);
+ if (!ADS_ERR_OK(status)) {
+ return status;
}
-
- status = ads_sasl_spnego_krb5_bind(ads, principal);
+
+ status = ads_sasl_spnego_krb5_bind(ads, &p);
if (ADS_ERR_OK(status)) {
- SAFE_FREE(principal);
+ ads_free_service_principal(&p);
return status;
}
@@ -264,19 +323,26 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
status = ADS_ERROR_KRB5(ads_kinit_password(ads));
if (ADS_ERR_OK(status)) {
- status = ads_sasl_spnego_krb5_bind(ads, principal);
+ status = ads_sasl_spnego_krb5_bind(ads, &p);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0,("kinit succeeded but "
+ "ads_sasl_spnego_krb5_bind failed: %s\n",
+ ads_errstr(status)));
+ }
}
+ ads_free_service_principal(&p);
+
/* only fallback to NTLMSSP if allowed */
if (ADS_ERR_OK(status) ||
!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
- SAFE_FREE(principal);
return status;
}
- }
+ } else
#endif
-
- SAFE_FREE(principal);
+ {
+ SAFE_FREE(given_principal);
+ }
/* lets do NTLMSSP ... this has the big advantage that we don't need
to sync clocks, and we don't rely on special versions of the krb5
diff --git a/source/libads/util.c b/source/libads/util.c
index eb6dccb3afd..365f72e7da7 100644
--- a/source/libads/util.c
+++ b/source/libads/util.c
@@ -52,4 +52,61 @@ failed:
SAFE_FREE(password);
return ret;
}
+
+ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
+ char **returned_principal)
+{
+ char *princ = NULL;
+
+ if (ads->server.realm && ads->server.ldap_server) {
+ char *server, *server_realm;
+
+ server = SMB_STRDUP(ads->server.ldap_server);
+ server_realm = SMB_STRDUP(ads->server.realm);
+
+ if (!server || !server_realm) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ strlower_m(server);
+ strupper_m(server_realm);
+ asprintf(&princ, "ldap/%s@%s", server, server_realm);
+
+ SAFE_FREE(server);
+ SAFE_FREE(server_realm);
+
+ if (!princ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ } else if (ads->config.realm && ads->config.ldap_server_name) {
+ char *server, *server_realm;
+
+ server = SMB_STRDUP(ads->config.ldap_server_name);
+ server_realm = SMB_STRDUP(ads->config.realm);
+
+ if (!server || !server_realm) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ strlower_m(server);
+ strupper_m(server_realm);
+ asprintf(&princ, "ldap/%s@%s", server, server_realm);
+
+ SAFE_FREE(server);
+ SAFE_FREE(server_realm);
+
+ if (!princ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ }
+
+ if (!princ) {
+ return ADS_ERROR(LDAP_PARAM_ERROR);
+ }
+
+ *returned_principal = princ;
+
+ return ADS_SUCCESS;
+}
+
#endif
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
index 3168dd19e24..2f6606fafa5 100644
--- a/source/libsmb/cliconnect.c
+++ b/source/libsmb/cliconnect.c
@@ -866,8 +866,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
/* If we get a bad principal, try to guess it if
we have a valid host NetBIOS name.
*/
- if (strequal(principal,
- "not_defined_in_RFC4178@please_ignore")) {
+ if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
SAFE_FREE(principal);
}
if (principal == NULL &&