summaryrefslogtreecommitdiff
path: root/source3/libads
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libads')
-rw-r--r--source3/libads/ads_status.c48
-rw-r--r--source3/libads/kerberos.c8
-rw-r--r--source3/libads/krb5_setpw.c14
-rw-r--r--source3/libads/ldap.c94
-rw-r--r--source3/libads/ldap_printer.c2
-rw-r--r--source3/libads/sasl.c254
-rw-r--r--source3/libads/util.c2
7 files changed, 356 insertions, 66 deletions
diff --git a/source3/libads/ads_status.c b/source3/libads/ads_status.c
index 2d1830435f..d85f9c9b58 100644
--- a/source3/libads/ads_status.c
+++ b/source3/libads/ads_status.c
@@ -30,19 +30,49 @@ ADS_STATUS ads_build_error(enum ads_error_type etype,
int rc, int minor_status)
{
ADS_STATUS ret;
- ret.error_type = etype;
- ret.rc = rc;
+
+ if (etype == ADS_ERROR_NT) {
+ DEBUG(0,("don't use ads_build_error with ADS_ERROR_NT!\n"));
+ ret.err.rc = -1;
+ ret.error_type = ADS_ERROR_SYSTEM;
+ ret.minor_status = 0;
+ return ret;
+ }
+
+ ret.err.rc = rc;
+ ret.error_type = etype;
ret.minor_status = minor_status;
return ret;
}
+ADS_STATUS ads_build_nt_error(enum ads_error_type etype,
+ NTSTATUS nt_status)
+{
+ ADS_STATUS ret;
+
+ if (etype != ADS_ERROR_NT) {
+ DEBUG(0,("don't use ads_build_nt_error without ADS_ERROR_NT!\n"));
+ ret.err.rc = -1;
+ ret.error_type = ADS_ERROR_SYSTEM;
+ ret.minor_status = 0;
+ return ret;
+ }
+ ret.err.nt_status = nt_status;
+ ret.error_type = etype;
+ ret.minor_status = 0;
+ return ret;
+}
+
/*
do a rough conversion between ads error codes and NT status codes
we'll need to fill this in more
*/
-NTSTATUS ads_ntstatus(ADS_STATUS rc)
+NTSTATUS ads_ntstatus(ADS_STATUS status)
{
- if (ADS_ERR_OK(rc)) return NT_STATUS_OK;
+ if (status.error_type == ADS_ERROR_NT){
+ return status.err.nt_status;
+ }
+ if (ADS_ERR_OK(status)) return NT_STATUS_OK;
return NT_STATUS_UNSUCCESSFUL;
}
@@ -59,14 +89,14 @@ const char *ads_errstr(ADS_STATUS status)
switch (status.error_type) {
case ADS_ERROR_SYSTEM:
- return strerror(status.rc);
+ return strerror(status.err.rc);
#ifdef HAVE_LDAP
case ADS_ERROR_LDAP:
- return ldap_err2string(status.rc);
+ return ldap_err2string(status.err.rc);
#endif
#ifdef HAVE_KRB5
case ADS_ERROR_KRB5:
- return error_message(status.rc);
+ return error_message(status.err.rc);
#endif
#ifdef HAVE_GSSAPI
case ADS_ERROR_GSS:
@@ -76,7 +106,7 @@ const char *ads_errstr(ADS_STATUS status)
gss_buffer_desc msg1, msg2;
msg1.value = NULL;
msg2.value = NULL;
- gss_display_status(&minor, status.rc, GSS_C_GSS_CODE,
+ gss_display_status(&minor, status.err.rc, GSS_C_GSS_CODE,
GSS_C_NULL_OID, &msg_ctx, &msg1);
gss_display_status(&minor, status.minor_status, GSS_C_MECH_CODE,
GSS_C_NULL_OID, &msg_ctx, &msg2);
@@ -86,6 +116,8 @@ const char *ads_errstr(ADS_STATUS status)
return ret;
}
#endif
+ case ADS_ERROR_NT:
+ return nt_errstr(ads_ntstatus(status));
default:
return "Unknown ADS error type!? (not compiled in?)";
}
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 9a486237c9..a80837cf4d 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -50,7 +50,7 @@ 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 kerberos_kinit_password(const char *principal, const char *password, int time_offset)
{
krb5_context ctx;
krb5_error_code code = 0;
@@ -60,6 +60,10 @@ int kerberos_kinit_password(const char *principal, const char *password)
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);
@@ -111,7 +115,7 @@ int ads_kinit_password(ADS_STRUCT *ads)
int ret;
asprintf(&s, "%s@%s", ads->auth.user_name, ads->auth.realm);
- ret = kerberos_kinit_password(s, ads->auth.password);
+ ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset);
if (ret) {
DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c
index ec79a8658f..a49b6cbe3b 100644
--- a/source3/libads/krb5_setpw.c
+++ b/source3/libads/krb5_setpw.c
@@ -248,7 +248,8 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
return 0;
}
-ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw)
+ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw,
+ int time_offset)
{
krb5_context context;
krb5_auth_context auth_context = NULL;
@@ -268,6 +269,10 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
return ADS_ERROR_KRB5(ret);
}
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
ret = krb5_cc_default(context, &ccache);
if (ret) {
krb5_free_context(context);
@@ -452,16 +457,17 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
ADS_STATUS kerberos_set_password(const char *kpasswd_server,
const char *auth_principal, const char *auth_password,
- const char *target_principal, const char *new_password)
+ const char *target_principal, const char *new_password,
+ int time_offset)
{
int ret;
- if ((ret = kerberos_kinit_password(auth_principal, auth_password))) {
+ if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset))) {
DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
- return krb5_set_password(kpasswd_server, target_principal, new_password);
+ return krb5_set_password(kpasswd_server, target_principal, new_password, time_offset);
}
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 2672489482..7a0afb1a81 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -63,6 +63,7 @@ static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
ads->ldap_port = port;
ads->ldap_ip = *interpret_addr2(srv);
free(srv);
+
return True;
}
@@ -204,7 +205,6 @@ static BOOL ads_try_netbios(ADS_STRUCT *ads)
ADS_STATUS ads_connect(ADS_STRUCT *ads)
{
int version = LDAP_VERSION3;
- int code;
ADS_STATUS status;
ads->last_attempt = time(NULL);
@@ -226,7 +226,7 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
/* try via DNS */
if (ads_try_dns(ads)) {
goto got_connection;
- }
+ }
/* try via netbios lookups */
if (!lp_disable_netbios() && ads_try_netbios(ads)) {
@@ -274,12 +274,7 @@ got_connection:
}
#endif
- if (ads->auth.password) {
- if ((code = ads_kinit_password(ads)))
- return ADS_ERROR_KRB5(code);
- }
-
- if (ads->auth.no_bind) {
+ if (ads->auth.flags & ADS_AUTH_NO_BIND) {
return ADS_SUCCESS;
}
@@ -613,14 +608,17 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
char *utf8_exp, *utf8_path, **search_attrs = NULL;
TALLOC_CTX *ctx;
- if (!(ctx = talloc_init()))
+ if (!(ctx = talloc_init())) {
+ DEBUG(1,("ads_do_search: talloc_init() failed!"));
return ADS_ERROR(LDAP_NO_MEMORY);
+ }
/* 0 means the conversion worked but the result was empty
so we only fail if it's negative. In any case, it always
at least nulls out the dest */
if ((push_utf8_talloc(ctx, &utf8_exp, exp) < 0) ||
(push_utf8_talloc(ctx, &utf8_path, bind_path) < 0)) {
+ DEBUG(1,("ads_do_search: push_utf8_talloc() failed!"));
rc = LDAP_NO_MEMORY;
goto done;
}
@@ -632,6 +630,7 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
if (!(str_list_copy(&search_attrs, attrs)))
{
+ DEBUG(1,("ads_do_search: str_list_copy() failed!"));
rc = LDAP_NO_MEMORY;
goto done;
}
@@ -826,7 +825,11 @@ static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods,
const char *name, const char *val)
{
- const char *values[2] = {val, NULL};
+ const char *values[2];
+
+ values[0] = val;
+ values[1] = NULL;
+
if (!val)
return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE, name,
@@ -861,7 +864,10 @@ ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
const char *name, const struct berval *val)
{
- const struct berval *values[2] = {val, NULL};
+ const struct berval *values[2];
+
+ values[0] = val;
+ values[1] = NULL;
if (!val)
return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES,
@@ -884,7 +890,7 @@ ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
non-existent attribute (but allowable for the object) to run
*/
LDAPControl PermitModify = {
- "1.2.840.113556.1.4.1413",
+ ADS_PERMIT_MODIFY_OID,
{0, NULL},
(char) 1};
LDAPControl *controls[2];
@@ -1410,7 +1416,7 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
*/
asprintf(&principal, "%s$@%s", host, ads->auth.realm);
- status = krb5_set_password(ads->auth.kdc_server, principal, password);
+ status = krb5_set_password(ads->auth.kdc_server, principal, password, ads->auth.time_offset);
free(host);
free(principal);
@@ -1616,6 +1622,26 @@ ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
return ADS_SUCCESS;
}
+/* parse a ADS timestring - typical string is
+ '20020917091222.0Z0' which means 09:12.22 17th September
+ 2002, timezone 0 */
+static time_t ads_parse_time(const char *str)
+{
+ struct tm tm;
+
+ ZERO_STRUCT(tm);
+
+ if (sscanf(str, "%4d%2d%2d%2d%2d%2d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
/**
* Find the servers name and realm - this can be done before authentication
@@ -1626,22 +1652,37 @@ ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
**/
ADS_STATUS ads_server_info(ADS_STRUCT *ads)
{
- const char *attrs[] = {"ldapServiceName", NULL};
+ const char *attrs[] = {"ldapServiceName", "currentTime", NULL};
ADS_STATUS status;
void *res;
- char **values;
+ char *value;
char *p;
+ char *timestr;
+ TALLOC_CTX *ctx;
+
+ if (!(ctx = talloc_init())) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
if (!ADS_ERR_OK(status)) return status;
- values = ldap_get_values(ads->ld, res, "ldapServiceName");
- if (!values || !values[0]) return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ value = ads_pull_string(ads, ctx, res, "ldapServiceName");
+ if (!value) {
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ timestr = ads_pull_string(ads, ctx, res, "currentTime");
+ if (!timestr) {
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ ldap_msgfree(res);
- p = strchr(values[0], ':');
+ p = strchr(value, ':');
if (!p) {
- ldap_value_free(values);
- ldap_msgfree(res);
+ talloc_destroy(ctx);
+ DEBUG(1, ("ads_server_info: returned ldap server name did not contain a ':' so was deemed invalid\n"));
return ADS_ERROR(LDAP_DECODING_ERROR);
}
@@ -1650,9 +1691,9 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
ads->config.ldap_server_name = strdup(p+1);
p = strchr(ads->config.ldap_server_name, '$');
if (!p || p[1] != '@') {
- ldap_value_free(values);
- ldap_msgfree(res);
+ talloc_destroy(ctx);
SAFE_FREE(ads->config.ldap_server_name);
+ DEBUG(1, ("ads_server_info: returned ldap server name did not contain '$@' so was deemed invalid\n"));
return ADS_ERROR(LDAP_DECODING_ERROR);
}
@@ -1667,6 +1708,15 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
DEBUG(3,("got ldap server name %s@%s\n",
ads->config.ldap_server_name, ads->config.realm));
+ ads->config.current_time = ads_parse_time(timestr);
+
+ if (ads->config.current_time != 0) {
+ ads->auth.time_offset = ads->config.current_time - time(NULL);
+ DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
+ }
+
+ talloc_destroy(ctx);
+
return ADS_SUCCESS;
}
diff --git a/source3/libads/ldap_printer.c b/source3/libads/ldap_printer.c
index 64ae8252c8..66984477b8 100644
--- a/source3/libads/ldap_printer.c
+++ b/source3/libads/ldap_printer.c
@@ -28,7 +28,7 @@
results can be used. It should be freed using ads_msgfree.
*/
ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, void **res,
- char *printer, char *servername)
+ const char *printer, char *servername)
{
ADS_STATUS status;
char *srv_dn, **srv_cn, *exp;
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index 81dedb0a81..f7dd01084a 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -22,37 +22,198 @@
#ifdef HAVE_ADS
-#if USE_CYRUS_SASL
-/*
- this is a minimal interact function, just enough for SASL to talk
- GSSAPI/kerberos to W2K
- Error handling is a bit of a problem. I can't see how to get Cyrus-sasl
- to give sensible errors
+/*
+ perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
+ we fit on one socket??)
*/
-static int sasl_interact(LDAP *ld,unsigned flags,void *defaults,void *in)
+static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
{
- sasl_interact_t *interact = in;
+ const char *mechs[] = {OID_NTLMSSP, NULL};
+ DATA_BLOB msg1;
+ DATA_BLOB blob, chal1, chal2, auth;
+ uint8 challenge[8];
+ uint8 nthash[24], lmhash[24], sess_key[16];
+ uint32 neg_flags;
+ struct berval cred, *scred;
+ ADS_STATUS status;
+ extern pstring global_myname;
+ int rc;
- while (interact->id != SASL_CB_LIST_END) {
- interact->result = strdup("");
- interact->len = strlen(interact->result);
- interact++;
+ if (!ads->auth.password) {
+ /* No password, don't segfault below... */
+ return ADS_ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
-
- return LDAP_SUCCESS;
+
+ neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_NTLM;
+
+ memset(sess_key, 0, 16);
+
+ /* generate the ntlmssp negotiate packet */
+ msrpc_gen(&blob, "CddB",
+ "NTLMSSP",
+ NTLMSSP_NEGOTIATE,
+ neg_flags,
+ sess_key, 16);
+
+ /* and wrap it in a SPNEGO wrapper */
+ msg1 = gen_negTokenTarg(mechs, blob);
+ data_blob_free(&blob);
+
+ cred.bv_val = msg1.data;
+ cred.bv_len = msg1.length;
+
+ rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
+ if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
+ status = ADS_ERROR(rc);
+ goto failed;
+ }
+
+ blob = data_blob(scred->bv_val, scred->bv_len);
+
+ /* the server gives us back two challenges */
+ if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
+ DEBUG(3,("Failed to parse challenges\n"));
+ status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ goto failed;
+ }
+
+ data_blob_free(&blob);
+
+ /* encrypt the password with the challenge */
+ memcpy(challenge, chal1.data + 24, 8);
+ SMBencrypt(ads->auth.password, challenge,lmhash);
+ SMBNTencrypt(ads->auth.password, challenge,nthash);
+
+ data_blob_free(&chal1);
+ data_blob_free(&chal2);
+
+ /* this generates the actual auth packet */
+ msrpc_gen(&blob, "CdBBUUUBd",
+ "NTLMSSP",
+ NTLMSSP_AUTH,
+ lmhash, 24,
+ nthash, 24,
+ lp_workgroup(),
+ ads->auth.user_name,
+ global_myname,
+ sess_key, 16,
+ neg_flags);
+
+ /* wrap it in SPNEGO */
+ auth = spnego_gen_auth(blob);
+
+ data_blob_free(&blob);
+
+ /* now send the auth packet and we should be done */
+ cred.bv_val = auth.data;
+ cred.bv_len = auth.length;
+
+ rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
+
+ return ADS_ERROR(rc);
+
+failed:
+ return status;
}
+
+/*
+ perform a LDAP/SASL/SPNEGO/KRB5 bind
+*/
+static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *principal)
+{
+ DATA_BLOB blob;
+ struct berval cred, *scred;
+ int rc;
+
+ blob = spnego_gen_negTokenTarg(principal, ads->auth.time_offset);
+
+ if (!blob.data) {
+ return ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ }
+
+ /* now send the auth packet and we should be done */
+ cred.bv_val = blob.data;
+ cred.bv_len = blob.length;
+
+ rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
+
+ data_blob_free(&blob);
+
+ return ADS_ERROR(rc);
+}
+
+/*
+ this performs a SASL/SPNEGO bind
+*/
+static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
+{
+ struct berval *scred=NULL;
+ int rc, i;
+ ADS_STATUS status;
+ DATA_BLOB blob;
+ char *principal;
+ char *OIDs[ASN1_MAX_OIDS];
+ BOOL got_kerberos_mechanism = False;
+
+ rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
+
+ if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
+ status = ADS_ERROR(rc);
+ goto failed;
+ }
+
+ blob = data_blob(scred->bv_val, scred->bv_len);
+
+#if 0
+ file_save("sasl_spnego.dat", blob.data, blob.length);
#endif
+ /* the server sent us the first part of the SPNEGO exchange in the negprot
+ reply */
+ if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
+ data_blob_free(&blob);
+ status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ goto failed;
+ }
+ data_blob_free(&blob);
+
+ /* make sure the server understands kerberos */
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+ strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+ got_kerberos_mechanism = True;
+ }
+ free(OIDs[i]);
+ }
+ DEBUG(3,("got principal=%s\n", principal));
+ if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
+ got_kerberos_mechanism && ads_kinit_password(ads) == 0) {
+ return ads_sasl_spnego_krb5_bind(ads, 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
+ library for HMAC_MD4 encryption */
+ return ads_sasl_spnego_ntlmssp_bind(ads);
+
+failed:
+ return status;
+}
+
+#ifdef HAVE_GSSAPI
#define MAX_GSS_PASSES 3
/* this performs a SASL/gssapi bind
we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
is very dependent on correctly configured DNS whereas
this routine is much less fragile
- see RFC2078 for details
+ see RFC2078 and RFC2222 for details
*/
-ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
+static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
{
int minor_status;
gss_name_t serv_name;
@@ -68,6 +229,7 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
uint8 *p;
uint32 max_msg_size;
char *sname;
+ unsigned sec_layer;
ADS_STATUS status;
krb5_principal principal;
krb5_context ctx;
@@ -159,22 +321,25 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
p = (uint8 *)output_token.value;
+ file_save("sasl_gssapi.dat", output_token.value, output_token.length);
+
max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
+ sec_layer = *p;
gss_release_buffer(&minor_status, &output_token);
output_token.value = malloc(strlen(ads->config.bind_path) + 8);
p = output_token.value;
- *p++ = 1; /* no sign or seal */
+ *p++ = 1; /* no sign & seal selection */
/* choose the same size as the server gave us */
*p++ = max_msg_size>>16;
*p++ = max_msg_size>>8;
*p++ = max_msg_size;
snprintf(p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
- p += strlen(ads->config.bind_path);
+ p += strlen(p);
- output_token.length = strlen(ads->config.bind_path) + 8;
+ output_token.length = PTR_DIFF(p, output_token.value);
gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
&output_token, &conf_state,
@@ -198,18 +363,51 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
failed:
return status;
}
+#endif
+
+/* mapping between SASL mechanisms and functions */
+static struct {
+ const char *name;
+ ADS_STATUS (*fn)(ADS_STRUCT *);
+} sasl_mechanisms[] = {
+ {"GSS-SPNEGO", ads_sasl_spnego_bind},
+#ifdef HAVE_GSSAPI
+ {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
+#endif
+ {NULL, NULL}
+};
ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
{
-#if USE_CYRUS_SASL
- int rc;
- rc = ldap_sasl_interactive_bind_s(ads->ld, NULL, NULL, NULL, NULL,
- LDAP_SASL_QUIET,
- sasl_interact, NULL);
- return ADS_ERROR(rc);
-#else
- return ads_sasl_gssapi_bind(ads);
-#endif
+ const char *attrs[] = {"supportedSASLMechanisms", NULL};
+ char **values;
+ ADS_STATUS status;
+ int i, j;
+ void *res;
+
+ /* get a list of supported SASL mechanisms */
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) return status;
+
+ values = ldap_get_values(ads->ld, res, "supportedSASLMechanisms");
+
+ /* try our supported mechanisms in order */
+ for (i=0;sasl_mechanisms[i].name;i++) {
+ /* see if the server supports it */
+ 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]));
+ status = sasl_mechanisms[i].fn(ads);
+ ldap_value_free(values);
+ ldap_msgfree(res);
+ return status;
+ }
+ }
+ }
+
+ ldap_value_free(values);
+ ldap_msgfree(res);
+ return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
}
#endif
diff --git a/source3/libads/util.c b/source3/libads/util.c
index b10b130a31..021f2d93e4 100644
--- a/source3/libads/util.c
+++ b/source3/libads/util.c
@@ -40,7 +40,7 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
asprintf(&service_principal, "HOST/%s", host_principal);
ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password,
- service_principal, new_password);
+ service_principal, new_password, ads->auth.time_offset);
if (!secrets_store_machine_password(new_password)) {
DEBUG(1,("Failed to save machine password\n"));