#include "lib/param/loadparm.h"
#include "libsmb/namequery.h"
#include "../librpc/gen_ndr/ndr_ads.h"
+#include "auth/credentials/credentials.h"
+#include "passdb.h"
#ifdef HAVE_LDAP
* In case of LDAP we use get_dc_name() as that
* creates the custom krb5.conf file
*/
- if (!(ads->auth.flags & ADS_AUTH_NO_BIND)) {
+ if (ads->auth.flags & ADS_AUTH_GENERATE_KRB5_CONFIG) {
fstring srv_name;
struct sockaddr_storage ip_out;
c_realm, c_domain, nt_errstr(status)));
return status;
}
+
/**
* Connect to the LDAP server
* @param ads Pointer to an existing ADS_STRUCT
* @return status of connection
**/
-ADS_STATUS ads_connect(ADS_STRUCT *ads)
+static ADS_STATUS ads_connect_internal(ADS_STRUCT *ads,
+ struct cli_credentials *creds)
{
int version = LDAP_VERSION3;
ADS_STATUS status;
NTSTATUS ntstatus;
char addr[INET6_ADDRSTRLEN];
struct sockaddr_storage existing_ss;
+ bool tls = false;
+ bool start_tls = false;
zero_sockaddr(&existing_ss);
+ if (!(ads->auth.flags & ADS_AUTH_NO_BIND)) {
+ SMB_ASSERT(creds != NULL);
+ }
+
+ if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
+ /*
+ * Simple anonyous binds are only
+ * allowed for anonymous credentials
+ */
+ SMB_ASSERT(cli_credentials_is_anonymous(creds));
+ }
+
+ if (!(ads->auth.flags & (ADS_AUTH_NO_BIND|ADS_AUTH_ANON_BIND))) {
+ ads->auth.flags |= ADS_AUTH_GENERATE_KRB5_CONFIG;
+ }
+
/*
* ads_connect can be passed in a reused ADS_STRUCT
* with an existing non-zero ads->ldap.ss IP address
}
ads_zero_ldap(ads);
+ ZERO_STRUCT(ads->ldap_tls_data);
ZERO_STRUCT(ads->ldap_wrap_data);
ads->ldap.last_attempt = time_mono(NULL);
ads->ldap_wrap_data.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
DEBUG(3,("Successfully contacted LDAP server %s\n", addr));
- if (!ads->auth.user_name) {
- /* Must use the userPrincipalName value here or sAMAccountName
- and not servicePrincipalName; found by Guenther Deschner */
- ads->auth.user_name = talloc_asprintf(ads,
- "%s$",
- lp_netbios_name());
- if (ads->auth.user_name == NULL) {
- DBG_ERR("talloc_asprintf failed\n");
- status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- goto out;
- }
- }
-
- if (ads->auth.realm == NULL) {
- ads->auth.realm = talloc_strdup(ads, ads->config.realm);
- if (ads->auth.realm == NULL) {
- status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- goto out;
- }
- }
-
if (!ads->auth.kdc_server) {
print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
ads->auth.kdc_server = talloc_strdup(ads, addr);
goto out;
}
+ ads->ldap_tls_data.mem_ctx = talloc_init("ads LDAP TLS connection memory");
+ if (!ads->ldap_tls_data.mem_ctx) {
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto out;
+ }
+
ads->ldap_wrap_data.mem_ctx = talloc_init("ads LDAP connection memory");
if (!ads->ldap_wrap_data.mem_ctx) {
status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
/* Otherwise setup the TCP LDAP session */
+ if (ads->auth.flags & ADS_AUTH_SASL_LDAPS) {
+ tls = true;
+ ads->ldap.port = 636;
+ } else if (ads->auth.flags & ADS_AUTH_SASL_STARTTLS) {
+ tls = true;
+ start_tls = true;
+ ads->ldap.port = 389;
+ } else {
+ ads->ldap.port = 389;
+ }
+
ads->ldap.ld = ldap_open_with_timeout(ads->config.ldap_server_name,
&ads->ldap.ss,
ads->ldap.port, lp_ldap_timeout());
}
DEBUG(3,("Connected to LDAP server %s\n", ads->config.ldap_server_name));
+ ldap_set_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ if (start_tls) {
+ unsigned int to = lp_ldap_connection_timeout();
+ struct berval *rspdata = NULL;
+ char *rspoid = NULL;
+ int rc;
+
+ if (to) {
+ /* Setup timeout */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, gotalarm_sig);
+ alarm(to);
+ /* End setup timeout. */
+ }
+
+ rc = ldap_extended_operation_s(ads->ldap.ld,
+ LDAP_EXOP_START_TLS,
+ NULL,
+ NULL,
+ NULL,
+ &rspoid,
+ &rspdata);
+ if (gotalarm != 0 && rc == LDAP_SUCCESS) {
+ rc = LDAP_TIMEOUT;
+ }
+
+ if (to) {
+ /* Teardown timeout. */
+ alarm(0);
+ CatchSignal(SIGALRM, SIG_IGN);
+ }
+
+ if (rspoid != NULL) {
+ ldap_memfree(rspoid);
+ }
+
+ if (rspdata != NULL) {
+ ber_bvfree(rspdata);
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ status = ADS_ERROR_LDAP(rc);
+ goto out;
+ }
+ }
+
+ if (tls) {
+ unsigned int to = lp_ldap_connection_timeout();
+
+ if (to) {
+ /* Setup timeout */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, gotalarm_sig);
+ alarm(to);
+ /* End setup timeout. */
+ }
+
+ status = ads_setup_tls_wrapping(&ads->ldap_tls_data,
+ ads->ldap.ld,
+ ads->config.ldap_server_name);
+
+ if (to) {
+ /* Teardown timeout. */
+ alarm(0);
+ CatchSignal(SIGALRM, SIG_IGN);
+ }
+
+ if ( !ADS_ERR_OK(status) ) {
+ goto out;
+ }
+ }
+
/* cache the successful connection for workgroup and realm */
if (ads_closest_dc(ads)) {
saf_store( ads->server.workgroup, ads->config.ldap_server_name);
saf_store( ads->server.realm, ads->config.ldap_server_name);
}
- ldap_set_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
-
/* fill in the current time and offsets */
status = ads_current_time( ads );
goto out;
}
- if (ads->auth.flags & ADS_AUTH_SIMPLE_BIND) {
- status = ADS_ERROR(ldap_simple_bind_s(ads->ldap.ld, ads->auth.user_name, ads->auth.password));
- goto out;
- }
-
- status = ads_sasl_bind(ads);
+ status = ads_sasl_bind(ads, creds);
out:
if (DEBUGLEVEL >= 11) {
}
/**
- * Connect to the LDAP server using given credentials
+ * Connect to the LDAP server using without a bind
+ * and without a tcp connection at all
+ *
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ **/
+ADS_STATUS ads_connect_cldap_only(ADS_STRUCT *ads)
+{
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
+ return ads_connect_internal(ads, NULL);
+}
+
+/**
+ * Connect to the LDAP server
* @param ads Pointer to an existing ADS_STRUCT
* @return status of connection
**/
-ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads)
+ADS_STATUS ads_connect_creds(ADS_STRUCT *ads, struct cli_credentials *creds)
{
- ads->auth.flags |= ADS_AUTH_USER_CREDS;
+ SMB_ASSERT(creds != NULL);
+
+ /*
+ * We allow upgrades from
+ * ADS_AUTH_NO_BIND if credentials
+ * are specified
+ */
+ ads->auth.flags &= ~ADS_AUTH_NO_BIND;
- return ads_connect(ads);
+ /*
+ * We allow upgrades from ADS_AUTH_ANON_BIND,
+ * as we don't want to use simple binds with
+ * non-anon credentials
+ */
+ if (!cli_credentials_is_anonymous(creds)) {
+ ads->auth.flags &= ~ADS_AUTH_ANON_BIND;
+ }
+
+ return ads_connect_internal(ads, creds);
}
/**
+ * Connect to the LDAP server using anonymous credentials
+ * using a simple bind without username/password
+ *
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ **/
+ADS_STATUS ads_connect_simple_anon(ADS_STRUCT *ads)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct cli_credentials *creds = NULL;
+ ADS_STATUS status;
+
+ creds = cli_credentials_init_anon(frame);
+ if (creds == NULL) {
+ TALLOC_FREE(frame);
+ return ADS_ERROR_SYSTEM(errno);
+ }
+
+ ads->auth.flags |= ADS_AUTH_ANON_BIND;
+ status = ads_connect_creds(ads, creds);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/**
+ * Connect to the LDAP server using the machine account
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ **/
+ADS_STATUS ads_connect_machine(ADS_STRUCT *ads)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct cli_credentials *creds = NULL;
+ ADS_STATUS status;
+ NTSTATUS ntstatus;
+
+ ntstatus = pdb_get_trust_credentials(ads->server.workgroup,
+ ads->server.realm,
+ frame,
+ &creds);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ TALLOC_FREE(frame);
+ return ADS_ERROR_NT(ntstatus);
+ }
+
+ status = ads_connect_creds(ads, creds);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/*
* Zero out the internal ads->ldap struct and initialize the address to zero IP.
* @param ads Pointer to an existing ADS_STRUCT
*
ldap_unbind(ads->ldap.ld);
ads->ldap.ld = NULL;
}
+ if (ads->ldap_tls_data.mem_ctx) {
+ talloc_free(ads->ldap_tls_data.mem_ctx);
+ }
if (ads->ldap_wrap_data.wrap_ops &&
ads->ldap_wrap_data.wrap_ops->disconnect) {
ads->ldap_wrap_data.wrap_ops->disconnect(&ads->ldap_wrap_data);
talloc_free(ads->ldap_wrap_data.mem_ctx);
}
ads_zero_ldap(ads);
+ ZERO_STRUCT(ads->ldap_tls_data);
ZERO_STRUCT(ads->ldap_wrap_data);
}
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,
- name, (const void **) values);
+ name, (const void *) values);
}
static void ads_print_error(int ret, LDAP *ld)
*/
ads_s->config.flags = 0;
- ads_s->auth.flags = ADS_AUTH_ANON_BIND;
- status = ads_connect( ads_s );
+ status = ads_connect_simple_anon(ads_s);
if ( !ADS_ERR_OK(status))
goto done;
}
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,("KDC time offset is %d seconds\n", ads->auth.time_offset));
+ ads->config.time_offset = ads->config.current_time - time(NULL);
+ DBG_INFO("server time offset is %d seconds\n",
+ ads->config.time_offset);
+ } else {
+ ads->config.time_offset = 0;
}
+ DBG_INFO("server time offset is %d seconds\n",
+ ads->config.time_offset);
+
ads_msgfree(ads, res);
status = ADS_SUCCESS;
*/
ads_s->config.flags = 0;
- ads_s->auth.flags = ADS_AUTH_ANON_BIND;
- status = ads_connect( ads_s );
+ status = ads_connect_simple_anon(ads_s);
if ( !ADS_ERR_OK(status))
goto done;
}