*/
#include "includes.h"
+#include "../libcli/auth/spnego.h"
+#include "../libcli/auth/ntlmssp.h"
+#include "ads.h"
+#include "smb_krb5.h"
#ifdef HAVE_LDAP
ADS_STATUS status;
NTSTATUS nt_status;
DATA_BLOB sig;
+ TALLOC_CTX *frame;
uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
+ frame = talloc_stackframe();
/* copy the data to the right location */
memcpy(dptr, buf, len);
/* create the signature and may encrypt the data */
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
nt_status = ntlmssp_seal_packet(ntlmssp_state,
+ frame,
dptr, len,
dptr, len,
&sig);
} else {
nt_status = ntlmssp_sign_packet(ntlmssp_state,
+ frame,
dptr, len,
dptr, len,
&sig);
memcpy(ads->ldap.out.buf + 4,
sig.data, NTLMSSP_SIG_SIZE);
- data_blob_free(&sig);
+ TALLOC_FREE(frame);
/* set how many bytes must be written to the underlying socket */
ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
struct ntlmssp_state *ntlmssp_state =
(struct ntlmssp_state *)ads->ldap.wrap_private_data;
- ntlmssp_end(&ntlmssp_state);
+ TALLOC_FREE(ntlmssp_state);
ads->ldap.wrap_ops = NULL;
ads->ldap.wrap_private_data = NULL;
struct berval cred, *scred = NULL;
int rc;
NTSTATUS nt_status;
+ ADS_STATUS status;
int turn = 1;
uint32 features = 0;
struct ntlmssp_state *ntlmssp_state;
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
+ nt_status = ntlmssp_client_start(NULL,
+ global_myname(),
+ lp_workgroup(),
+ lp_client_ntlmv2_auth(),
+ &ntlmssp_state);
+ if (!NT_STATUS_IS_OK(nt_status)) {
return ADS_ERROR_NT(nt_status);
}
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
|| NT_STATUS_IS_OK(nt_status))
&& blob_out.length) {
if (turn == 1) {
+ const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
/* and wrap it in a SPNEGO wrapper */
- msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
+ msg1 = spnego_gen_negTokenInit(talloc_tos(),
+ OIDs_ntlm, &blob_out, NULL);
} else {
/* wrap it in SPNEGO */
- msg1 = spnego_gen_auth(blob_out);
+ msg1 = spnego_gen_auth(talloc_tos(), blob_out);
}
data_blob_free(&blob_out);
ber_bvfree(scred);
}
- ntlmssp_end(&ntlmssp_state);
+ TALLOC_FREE(ntlmssp_state);
return ADS_ERROR(rc);
}
if (scred) {
} else {
- ntlmssp_end(&ntlmssp_state);
+ TALLOC_FREE(ntlmssp_state);
data_blob_free(&blob_out);
return ADS_ERROR_NT(nt_status);
}
(rc == LDAP_SASL_BIND_IN_PROGRESS)) {
DATA_BLOB tmp_blob = data_blob_null;
/* the server might give us back two challenges */
- if (!spnego_parse_challenge(blob, &blob_in,
+ if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
&tmp_blob)) {
- ntlmssp_end(&ntlmssp_state);
+ TALLOC_FREE(ntlmssp_state);
data_blob_free(&blob);
DEBUG(3,("Failed to parse challenges\n"));
return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
data_blob_free(&tmp_blob);
} else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
- if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
+ if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
&blob_in)) {
- ntlmssp_end(&ntlmssp_state);
+ TALLOC_FREE(ntlmssp_state);
data_blob_free(&blob);
DEBUG(3,("Failed to parse auth response\n"));
return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
then the state will be kept by the signing engine */
if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
- ads->ldap.out.min = 4;
- ads->ldap.out.max = 0x0FFFFFFF - NTLMSSP_SIG_SIZE;
+ ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
- ads->ldap.in.min = 4;
- ads->ldap.in.max = 0x0FFFFFFF;
- ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
+ ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
+ ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
+ status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
+ ads_errstr(status)));
+ TALLOC_FREE(ntlmssp_state);
+ return status;
+ }
} else {
- ntlmssp_end(&ntlmssp_state);
+ TALLOC_FREE(ntlmssp_state);
}
return ADS_ERROR(rc);
#ifdef HAVE_GSSAPI
static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
{
- gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
+ gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
ADS_STATUS status;
int gss_rc;
uint32 minor_status;
static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
{
- gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
+ gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
ADS_STATUS status;
int gss_rc;
uint32 minor_status;
return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
}
- if (wrapped.length < wrapped.length) {
+ if (wrapped.length < unwrapped.length) {
return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
}
static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
{
- gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
+ gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
uint32 minor_status;
gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
{
ADS_STATUS status;
- BOOL ok;
+ bool ok;
uint32 minor_status;
int gss_rc, rc;
gss_OID_desc krb5_mech_type =
/* and wrap that in a shiny SPNEGO wrapper */
unwrapped = data_blob_const(output_token.value, output_token.length);
- wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
+ wrapped = spnego_gen_negTokenInit(talloc_tos(),
+ spnego_mechs, &unwrapped, NULL);
gss_release_buffer(&minor_status, &output_token);
if (unwrapped.length > wrapped.length) {
status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
wrapped = data_blob_null;
}
- ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
+ ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
OID_KERBEROS5_OLD,
&unwrapped);
if (scred) ber_bvfree(scred);
}
if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
- uint32 max_msg_size = 0x0A000000;
+ uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
(ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
GSS_C_QOP_DEFAULT,
- max_msg_size, &ads->ldap.out.max);
+ max_msg_size, &ads->ldap.out.max_unwrapped);
if (gss_rc) {
status = ADS_ERROR_GSS(gss_rc, minor_status);
goto failed;
}
- ads->ldap.out.min = 4;
- ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max;
- ads->ldap.in.min = 4;
- ads->ldap.in.max = max_msg_size;
- ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
+ ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
+ ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
+ ads->ldap.in.max_wrapped = max_msg_size;
+ status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
+ ads_errstr(status)));
+ goto failed;
+ }
/* make sure we don't free context_handle */
context_handle = GSS_C_NO_CONTEXT;
}
+ status = ADS_SUCCESS;
+
failed:
if (context_handle != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
return status;
}
-#endif
+#endif /* HAVE_GSSAPI */
#ifdef HAVE_KRB5
struct ads_service_principal {
- krb5_context ctx;
char *string;
- krb5_principal principal;
#ifdef HAVE_GSSAPI
gss_name_t name;
#endif
gss_release_name(&minor_status, &p->name);
}
#endif
- if (p->principal) {
- krb5_free_principal(p->ctx, p->principal);
- }
-
- if (p->ctx) {
- krb5_free_context(p->ctx);
- }
-
ZERO_STRUCTP(p);
}
struct ads_service_principal *p)
{
ADS_STATUS status;
- krb5_enctype enc_types[] = {
-#ifdef ENCTYPE_ARCFOUR_HMAC
- ENCTYPE_ARCFOUR_HMAC,
-#endif
- ENCTYPE_DES_CBC_MD5,
- ENCTYPE_NULL};
#ifdef HAVE_GSSAPI
gss_buffer_desc input_name;
- gss_OID_desc nt_principal =
- {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
+ /* 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
+ /* 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 (given_principal) {
- p->string = SMB_STRDUP(given_principal);
- if (!p->string) {
- return ADS_ERROR(LDAP_NO_MEMORY);
- }
- } else if (ads->server.realm && ads->server.ldap_server) {
- char *server, *server_realm;
+ /* Also try best guess when we get the w2k8 ignore principal
+ back, or when we are configured to ignore it - gd,
+ abartlet */
- server = SMB_STRDUP(ads->server.ldap_server);
- server_realm = SMB_STRDUP(ads->server.realm);
+ if (!lp_client_use_spnego_principal() ||
+ !given_principal ||
+ strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
- if (!server || !server_realm) {
- return ADS_ERROR(LDAP_NO_MEMORY);
- }
-
- strlower_m(server);
- strupper_m(server_realm);
- asprintf(&p->string, "ldap/%s@%s", server, server_realm);
-
- SAFE_FREE(server);
- SAFE_FREE(server_realm);
-
- if (!p->string) {
- 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);
+ status = ads_guess_service_principal(ads, &p->string);
+ if (!ADS_ERR_OK(status)) {
+ return status;
}
-
- strlower_m(server);
- strupper_m(server_realm);
- asprintf(&p->string, "ldap/%s@%s", server, server_realm);
-
- SAFE_FREE(server);
- SAFE_FREE(server_realm);
-
+ } else {
+ p->string = SMB_STRDUP(given_principal);
if (!p->string) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
}
- initialize_krb5_error_table();
- status = ADS_ERROR_KRB5(krb5_init_context(&p->ctx));
- if (!ADS_ERR_OK(status)) {
- ads_free_service_principal(p);
- return status;
- }
- status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(p->ctx, enc_types));
- if (!ADS_ERR_OK(status)) {
- ads_free_service_principal(p);
- return status;
- }
- status = ADS_ERROR_KRB5(smb_krb5_parse_name(p->ctx, p->string, &p->principal));
- if (!ADS_ERR_OK(status)) {
- ads_free_service_principal(p);
- return status;
- }
-
#ifdef HAVE_GSSAPI
- /*
- * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
- * to point to the *address* of the krb5_principal, and the gss libraries
- * to a shallow copy of the krb5_principal pointer - so we need to keep
- * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
- * Just one more way in which MIT engineers screwed me over.... JRA.
- *
- * That's the reason for principal not beeing a local var in this function
- */
- input_name.value = &p->principal;
- input_name.length = sizeof(p->principal);
+ 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) {
}
#endif
- return status;
+ return ADS_SUCCESS;
}
/*
return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
}
- rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
+ rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
+ ads->auth.time_offset, &blob, &session_key, 0,
&ads->auth.tgs_expire);
if (rc) {
#endif
return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
}
-#endif
+#endif /* HAVE_KRB5 */
/*
this performs a SASL/SPNEGO bind
char *given_principal = NULL;
char *OIDs[ASN1_MAX_OIDS];
#ifdef HAVE_KRB5
- BOOL got_kerberos_mechanism = False;
+ bool got_kerberos_mechanism = False;
#endif
rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
/* the server sent us the first part of the SPNEGO exchange in the negprot
reply */
- if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
+ if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
+ OIDs[0] == NULL) {
data_blob_free(&blob);
status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
goto failed;
got_kerberos_mechanism = True;
}
#endif
- free(OIDs[i]);
+ talloc_free(OIDs[i]);
}
DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
struct ads_service_principal p;
status = ads_generate_service_principal(ads, given_principal, &p);
- SAFE_FREE(given_principal);
+ TALLOC_FREE(given_principal);
if (!ADS_ERR_OK(status)) {
return status;
}
if (ADS_ERR_OK(status)) {
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);
} else
#endif
{
- SAFE_FREE(given_principal);
+ TALLOC_FREE(given_principal);
}
/* lets do NTLMSSP ... this has the big advantage that we don't need
this routine is much less fragile
see RFC2078 and RFC2222 for details
*/
-static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
+static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
{
uint32 minor_status;
- gss_name_t serv_name;
- gss_buffer_desc input_name;
gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
gss_OID mech_type = GSS_C_NULL_OID;
gss_buffer_desc output_token, input_token;
int i=0;
int gss_rc, rc;
uint8 *p;
- uint32 max_msg_size = 0;
- char *sname = NULL;
+ uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
+ uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
ADS_STATUS status;
- krb5_principal principal = NULL;
- krb5_context ctx = NULL;
- krb5_enctype enc_types[] = {
-#ifdef ENCTYPE_ARCFOUR_HMAC
- ENCTYPE_ARCFOUR_HMAC,
-#endif
- ENCTYPE_DES_CBC_MD5,
- ENCTYPE_NULL};
- gss_OID_desc nt_principal =
- {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
-
- /* we need to fetch a service ticket as the ldap user in the
- servers realm, regardless of our realm */
- asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);
-
- initialize_krb5_error_table();
- status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
- if (!ADS_ERR_OK(status)) {
- SAFE_FREE(sname);
- return status;
- }
- status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
- if (!ADS_ERR_OK(status)) {
- SAFE_FREE(sname);
- krb5_free_context(ctx);
- return status;
- }
- status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
- if (!ADS_ERR_OK(status)) {
- SAFE_FREE(sname);
- krb5_free_context(ctx);
- return status;
- }
-
- input_name.value = &principal;
- input_name.length = sizeof(principal);
-
- gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);
-
- /*
- * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
- * to point to the *address* of the krb5_principal, and the gss libraries
- * to a shallow copy of the krb5_principal pointer - so we need to keep
- * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
- * Just one more way in which MIT engineers screwed me over.... JRA.
- */
-
- SAFE_FREE(sname);
-
- if (gss_rc) {
- krb5_free_principal(ctx, principal);
- krb5_free_context(ctx);
- return ADS_ERROR_GSS(gss_rc, minor_status);
- }
input_token.value = NULL;
input_token.length = 0;
- req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
- switch (ads->ldap.wrap_type) {
- case ADS_SASLWRAP_TYPE_SEAL:
- req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
- break;
- case ADS_SASLWRAP_TYPE_SIGN:
- req_flags |= GSS_C_INTEG_FLAG;
- break;
- case ADS_SASLWRAP_TYPE_PLAIN:
- break;
- }
+ /*
+ * Note: here we always ask the gssapi for sign and seal
+ * as this is negotiated later after the mutal
+ * authentication
+ */
+ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
for (i=0; i < MAX_GSS_PASSES; i++) {
gss_rc = gss_init_sec_context(&minor_status,
&output_token,
&ret_flags,
NULL);
-
- if (input_token.value) {
- gss_release_buffer(&minor_status, &input_token);
+ if (scred) {
+ ber_bvfree(scred);
+ scred = NULL;
}
-
if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
status = ADS_ERROR_GSS(gss_rc, minor_status);
goto failed;
gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
&conf_state,NULL);
+ if (scred) {
+ ber_bvfree(scred);
+ scred = NULL;
+ }
if (gss_rc) {
status = ADS_ERROR_GSS(gss_rc, minor_status);
goto failed;
}
- gss_release_buffer(&minor_status, &input_token);
-
p = (uint8 *)output_token.value;
#if 0
#endif
if (p) {
- max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
+ wrap_type = CVAL(p,0);
+ SCVAL(p,0,0);
+ max_msg_size = RIVAL(p,0);
}
gss_release_buffer(&minor_status, &output_token);
+ if (!(wrap_type & ads->ldap.wrap_type)) {
+ /*
+ * the server doesn't supports the wrap
+ * type we want :-(
+ */
+ DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
+ ads->ldap.wrap_type, wrap_type));
+ DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
+ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ goto failed;
+ }
+
+ /* 0x58 is the minimum windows accepts */
+ if (max_msg_size < 0x58) {
+ max_msg_size = 0x58;
+ }
+
output_token.length = 4;
output_token.value = SMB_MALLOC(output_token.length);
+ if (!output_token.value) {
+ output_token.length = 0;
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto failed;
+ }
p = (uint8 *)output_token.value;
- *p++ = ads->ldap.wrap_type;
- /* choose the same size as the server gave us */
- *p++ = max_msg_size>>16;
- *p++ = max_msg_size>>8;
- *p++ = max_msg_size;
+ RSIVAL(p,0,max_msg_size);
+ SCVAL(p,0,ads->ldap.wrap_type);
+
/*
* we used to add sprintf("dn:%s", ads->config.bind_path) here.
* but using ads->config.bind_path is the wrong! It should be
*/
gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
- &output_token, &conf_state,
- &input_token);
+ &output_token, /* used as *input* here. */
+ &conf_state,
+ &input_token); /* Used as *output* here. */
if (gss_rc) {
status = ADS_ERROR_GSS(gss_rc, minor_status);
+ output_token.length = 0;
+ SAFE_FREE(output_token.value);
goto failed;
}
- free(output_token.value);
+ /* We've finished with output_token. */
+ SAFE_FREE(output_token.value);
+ output_token.length = 0;
cred.bv_val = (char *)input_token.value;
cred.bv_len = input_token.length;
gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
(ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
GSS_C_QOP_DEFAULT,
- max_msg_size, &ads->ldap.out.max);
+ max_msg_size, &ads->ldap.out.max_unwrapped);
if (gss_rc) {
status = ADS_ERROR_GSS(gss_rc, minor_status);
goto failed;
}
- ads->ldap.out.min = 4;
- ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max;
- ads->ldap.in.min = 4;
- ads->ldap.in.max = max_msg_size;
- ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
+ ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
+ ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
+ ads->ldap.in.max_wrapped = max_msg_size;
+ status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
+ ads_errstr(status)));
+ goto failed;
+ }
/* make sure we don't free context_handle */
context_handle = GSS_C_NO_CONTEXT;
}
+
failed:
- gss_release_name(&minor_status, &serv_name);
if (context_handle != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
- krb5_free_principal(ctx, principal);
- krb5_free_context(ctx);
if(scred)
ber_bvfree(scred);
return status;
}
-#endif /* HAVE_GGSAPI */
+
+static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
+{
+ ADS_STATUS status;
+ struct ads_service_principal p;
+
+ status = ads_generate_service_principal(ads, NULL, &p);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ status = ads_sasl_gssapi_do_bind(ads, p.name);
+ if (ADS_ERR_OK(status)) {
+ ads_free_service_principal(&p);
+ return status;
+ }
+
+ DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
+ "calling kinit\n", ads_errstr(status)));
+
+ status = ADS_ERROR_KRB5(ads_kinit_password(ads));
+
+ if (ADS_ERR_OK(status)) {
+ status = ads_sasl_gssapi_do_bind(ads, p.name);
+ }
+
+ ads_free_service_principal(&p);
+
+ return status;
+}
+
+#endif /* HAVE_GSSAPI */
/* mapping between SASL mechanisms and functions */
static struct {
for (j=0;values && values[j];j++) {
if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
DEBUG(4,("Found SASL mechanism %s\n", values[j]));
+retry:
status = sasl_mechanisms[i].fn(ads);
+ if (status.error_type == ENUM_ADS_ERROR_LDAP &&
+ status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
+ ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
+ {
+ DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
+ "retrying with signing enabled\n"));
+ ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
+ goto retry;
+ }
ldap_value_free(values);
ldap_msgfree(res);
return status;