#include "smbldap.h"
#include "../libcli/security/security.h"
#include <tevent.h>
+#include "lib/param/loadparm.h"
/* Try not to hit the up or down server forever */
#define SMBLDAP_IDLE_TIME 150 /* After 2.5 minutes disconnect */
+struct smbldap_state {
+ LDAP *ldap_struct;
+ pid_t pid;
+ time_t last_ping; /* monotonic */
+ /* retrieve-once info */
+ const char *uri;
+ /* credentials */
+ bool anonymous;
+ char *bind_dn;
+ char *bind_secret;
+ smbldap_bind_callback_fn bind_callback;
+ void *bind_callback_data;
+
+ bool paged_results;
+
+ unsigned int num_failures;
+
+ time_t last_use; /* monotonic */
+ struct tevent_context *tevent_context;
+ struct tevent_timer *idle_event;
+
+ struct timeval last_rebind; /* monotonic */
+};
+
+LDAP *smbldap_get_ldap(struct smbldap_state *state)
+{
+ return state->ldap_struct;
+}
+
+bool smbldap_get_paged_results(struct smbldap_state *state)
+{
+ return state->paged_results;
+}
+
+void smbldap_set_paged_results(struct smbldap_state *state,
+ bool paged_results)
+{
+ state->paged_results = paged_results;
+}
+
+void smbldap_set_bind_callback(struct smbldap_state *state,
+ smbldap_bind_callback_fn callback,
+ void *callback_data)
+{
+ state->bind_callback = callback;
+ state->bind_callback_data = callback_data;
+}
/*******************************************************************
Search an attribute and return the first value found.
******************************************************************/
struct dom_sid *sid)
{
DATA_BLOB blob;
- bool ret;
+ struct sid_parse_ret ret;
if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib,
&blob)) {
return false;
}
- ret = sid_parse((char *)blob.data, blob.length, sid);
+ ret = sid_parse(blob.data, blob.length, sid);
TALLOC_FREE(blob.data);
- return ret;
+ return (ret.len != -1);
}
static int ldapmsg_destructor(LDAPMessage **result) {
return 0;
}
- void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
+ void smbldap_talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
{
LDAPMessage **handle;
return 0;
}
- void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
+ void smbldap_talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
{
LDAPMod ***handle;
return;
}
-#if 0 /* commented out after discussion with abartlet. Do not reenable.
+#if 0 /* commented out after discussion with abartlet. Do not re-enable.
left here so other do not re-add similar code --jerry */
if (value == NULL || *value == '\0')
return;
mods[i]->mod_bvalues[j] = SMB_MALLOC_P(struct berval);
SMB_ASSERT(mods[i]->mod_bvalues[j] != NULL);
- mods[i]->mod_bvalues[j]->bv_val = (char *)memdup(blob->data, blob->length);
+ mods[i]->mod_bvalues[j]->bv_val = (char *)smb_memdup(blob->data, blob->length);
SMB_ASSERT(mods[i]->mod_bvalues[j]->bv_val != NULL);
mods[i]->mod_bvalues[j]->bv_len = blob->length;
bool existed;
DATA_BLOB oldblob = data_blob_null;
- if (attribute == NULL) {
- /* This can actually happen for ldapsam_compat where we for
- * example don't have a password history */
- return;
- }
-
if (existing != NULL) {
if (op & LDAP_MOD_BVALUES) {
existed = smbldap_talloc_single_blob(talloc_tos(), ldap_struct, existing, attribute, &oldblob);
t = SMB_XMALLOC_P(struct smbldap_state_lookup);
ZERO_STRUCTP(t);
- DLIST_ADD_END(smbldap_state_lookup_list, t, struct smbldap_state_lookup *);
+ DLIST_ADD_END(smbldap_state_lookup_list, t);
t->ld = ld;
t->smbldap_state = smbldap_state;
}
start TLS on an existing LDAP connection
*******************************************************************/
-int smb_ldap_start_tls(LDAP *ldap_struct, int version)
+int smbldap_start_tls(LDAP *ldap_struct, int version)
{
#ifdef LDAP_OPT_X_TLS
- int rc;
+ int rc,tls;
#endif
if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
}
#ifdef LDAP_OPT_X_TLS
+ /* check if we use ldaps already */
+ ldap_get_option(ldap_struct, LDAP_OPT_X_TLS, &tls);
+ if (tls == LDAP_OPT_X_TLS_HARD) {
+ return LDAP_SUCCESS;
+ }
+
if (version != LDAP_VERSION3) {
DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
return LDAP_OPERATIONS_ERROR;
open a connection to the ldap server (just until the bind)
******************************************************************/
-int smb_ldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
+int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
{
int rc, version;
return rc;
}
- rc = smb_ldap_start_tls(*ldap_struct, version);
+ rc = smbldap_start_tls(*ldap_struct, version);
if (rc) {
return rc;
}
/* Start TLS if required */
- rc = smb_ldap_start_tls(*ldap_struct, version);
+ rc = smbldap_start_tls(*ldap_struct, version);
if (rc) {
return rc;
}
* our credentials. At least *try* to secure the connection - Guenther */
smb_ldap_upgrade_conn(ldap_struct, &version);
- smb_ldap_start_tls(ldap_struct, version);
+ smbldap_start_tls(ldap_struct, version);
/** @TODO Should we be doing something to check what servers we rebind to?
Could we get a referral to a machine that we don't want to give our
******************************************************************/
static int smbldap_connect_system(struct smbldap_state *ldap_state)
{
- LDAP *ldap_struct = ldap_state->ldap_struct;
+ LDAP *ldap_struct = smbldap_get_ldap(ldap_state);
int rc;
int version;
/* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
- (OpenLDAP) doesnt' seem to support it */
+ (OpenLDAP) doesn't seem to support it */
DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
ldap_state->uri, ldap_state->bind_dn));
#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
#endif
- rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+ /* When there is an alternative bind callback is set,
+ attempt to use it to perform the bind */
+ if (ldap_state->bind_callback != NULL) {
+ /* We have to allow bind callback to be run under become_root/unbecome_root
+ to make sure within smbd the callback has proper write access to its resources,
+ like credential cache. This is similar to passdb case where this callback is supposed
+ to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
+ */
+ become_root();
+ rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
+ unbecome_root();
+ } else {
+ rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+ }
if (rc != LDAP_SUCCESS) {
char *ld_error = NULL;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_ERROR_STRING,
&ld_error);
DEBUG(ldap_state->num_failures ? 2 : 0,
("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
ldap_state->num_failures = 0;
ldap_state->paged_results = False;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_PROTOCOL_VERSION, &version);
- if (smbldap_has_control(ldap_state->ldap_struct, ADS_PAGE_CTL_OID) && version == 3) {
+ if (smbldap_has_control(smbldap_get_ldap(ldap_state), ADS_PAGE_CTL_OID)
+ && version == 3) {
ldap_state->paged_results = True;
}
}
static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
- struct timed_event *te,
+ struct tevent_timer *te,
struct timeval now_abs,
void *private_data);
bool reopen = False;
SMB_ASSERT(ldap_state);
- if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time_mono(NULL))) {
+ if ((smbldap_get_ldap(ldap_state) != NULL) &&
+ ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) <
+ time_mono(NULL))) {
#ifdef HAVE_UNIXSOCKET
struct sockaddr_un addr;
#else
- struct sockaddr addr;
+ struct sockaddr_storage addr;
#endif
socklen_t len = sizeof(addr);
int sd;
- opt_rc = ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd);
+ opt_rc = ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_DESC, &sd);
if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
reopen = True;
#endif
if (reopen) {
/* the other end has died. reopen. */
- ldap_unbind(ldap_state->ldap_struct);
- ldap_state->ldap_struct = NULL;
+ ldap_unbind(smbldap_get_ldap(ldap_state));
+ ldap_state->ldap_struct = NULL;
ldap_state->last_ping = (time_t)0;
} else {
ldap_state->last_ping = time_mono(NULL);
}
}
- if (ldap_state->ldap_struct != NULL) {
+ if (smbldap_get_ldap(ldap_state) != NULL) {
DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
return LDAP_SUCCESS;
}
ldap_state->last_ping = time_mono(NULL);
- ldap_state->pid = sys_getpid();
+ ldap_state->pid = getpid();
TALLOC_FREE(ldap_state->idle_event);
if (!ldap_state)
return NT_STATUS_INVALID_PARAMETER;
- if (ldap_state->ldap_struct != NULL) {
- ldap_unbind(ldap_state->ldap_struct);
+ if (smbldap_get_ldap(ldap_state) != NULL) {
+ ldap_unbind(smbldap_get_ldap(ldap_state));
ldap_state->ldap_struct = NULL;
}
alarm(absolute_endtime - now);
}
- if (ldap_state->pid != sys_getpid()) {
+ if (ldap_state->pid != getpid()) {
smbldap_close(ldap_state);
}
}
static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
{
- ldap_get_option(ldap_state->ldap_struct,
+ ldap_get_option(smbldap_get_ldap(ldap_state),
LDAP_OPT_ERROR_NUMBER, p_ld_errno);
- ldap_get_option(ldap_state->ldap_struct,
+ ldap_get_option(smbldap_get_ldap(ldap_state),
LDAP_OPT_ERROR_STRING, pp_ld_error);
}
break;
}
- rc = ldap_search_ext_s(ldap_state->ldap_struct, base, scope,
+ rc = ldap_search_ext_s(smbldap_get_ldap(ldap_state),
+ base, scope,
utf8_filter,
discard_const_p(char *, attrs),
attrsonly, sctrls, cctrls, timeout_ptr,
if (ld_errno != LDAP_SERVER_DOWN) {
break;
}
- ldap_unbind(ldap_state->ldap_struct);
+ ldap_unbind(smbldap_get_ldap(ldap_state));
ldap_state->ldap_struct = NULL;
}
DEBUG(3,("smbldap_search_paged: search was successful\n"));
- rc = ldap_parse_result(ldap_state->ldap_struct, *res, NULL, NULL,
+ rc = ldap_parse_result(smbldap_get_ldap(ldap_state), *res, NULL, NULL,
NULL, NULL, &rcontrols, 0);
if (rc != 0) {
DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
break;
}
- rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
+ rc = ldap_modify_s(smbldap_get_ldap(ldap_state), utf8_dn,
+ attrs);
if (rc == LDAP_SUCCESS) {
break;
}
if (ld_errno != LDAP_SERVER_DOWN) {
break;
}
- ldap_unbind(ldap_state->ldap_struct);
+ ldap_unbind(smbldap_get_ldap(ldap_state));
ldap_state->ldap_struct = NULL;
}
break;
}
- rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
+ rc = ldap_add_s(smbldap_get_ldap(ldap_state), utf8_dn, attrs);
if (rc == LDAP_SUCCESS) {
break;
}
if (ld_errno != LDAP_SERVER_DOWN) {
break;
}
- ldap_unbind(ldap_state->ldap_struct);
+ ldap_unbind(smbldap_get_ldap(ldap_state));
ldap_state->ldap_struct = NULL;
}
break;
}
- rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
+ rc = ldap_delete_s(smbldap_get_ldap(ldap_state), utf8_dn);
if (rc == LDAP_SUCCESS) {
break;
}
if (ld_errno != LDAP_SERVER_DOWN) {
break;
}
- ldap_unbind(ldap_state->ldap_struct);
+ ldap_unbind(smbldap_get_ldap(ldap_state));
ldap_state->ldap_struct = NULL;
}
break;
}
- rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid,
+ rc = ldap_extended_operation_s(smbldap_get_ldap(ldap_state),
+ reqoid,
reqdata, serverctrls,
clientctrls, retoidp, retdatap);
if (rc == LDAP_SUCCESS) {
if (ld_errno != LDAP_SERVER_DOWN) {
break;
}
- ldap_unbind(ldap_state->ldap_struct);
+ ldap_unbind(smbldap_get_ldap(ldap_state));
ldap_state->ldap_struct = NULL;
}
const char *filter, const char **search_attr,
LDAPMessage ** result)
{
- return smbldap_search(ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE,
+ return smbldap_search(ldap_state, lp_ldap_suffix(talloc_tos()),
+ LDAP_SCOPE_SUBTREE,
filter, search_attr, 0, result);
}
static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
- struct timed_event *te,
+ struct tevent_timer *te,
struct timeval now_abs,
void *private_data)
{
TALLOC_FREE(state->idle_event);
- if (state->ldap_struct == NULL) {
+ if (smbldap_get_ldap(state) == NULL) {
DEBUG(10,("ldap connection not connected...\n"));
return;
}
SAFE_FREE((*ldap_state)->bind_dn);
SAFE_FREE((*ldap_state)->bind_secret);
+ smbldap_set_bind_callback(*ldap_state, NULL, NULL);
TALLOC_FREE(*ldap_state);
/* free any previously set credential */
SAFE_FREE(ldap_state->bind_dn);
+ smbldap_set_bind_callback(ldap_state, NULL, NULL);
+
if (ldap_state->bind_secret) {
/* make sure secrets are zeroed out of memory */
memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));