The functions are unchanged. Next step is to make idmap_ldap use them.
Andrew Bartlett
$(LIB_SMBD_OBJ) $(SAM_OBJ) $(REGISTRY_OBJ) $(POPT_LIB_OBJ) \
$(RPC_LSA_OBJ) $(RPC_NETLOG_OBJ) $(RPC_SAMR_OBJ) $(RPC_REG_OBJ) \
$(RPC_SVC_OBJ) $(RPC_WKS_OBJ) $(RPC_DFS_OBJ) $(RPC_SPOOLSS_OBJ) \
- $(IDMAP_OBJ) $(RPC_ECHO_OBJ)
+ $(IDMAP_OBJ) $(RPC_ECHO_OBJ) $(SMBLDAP_OBJ)
WINBIND_WINS_NSS_OBJ = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) \
$(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
*/
-#ifdef HAVE_LDAP
-
#ifndef _SMBLDAP_H
#define _SMBLDAP_H
+#ifdef HAVE_LDAP
+
/* specify schema versions between 2.2. and 3.0 */
#define SCHEMAVER_SAMBAACCOUNT 1
} ATTRIB_MAP_ENTRY;
-struct smbldap_state {
- LDAP *ldap_struct;
- time_t last_ping;
- /* retrive-once info */
- const char *uri;
- char *bind_dn;
- char *bind_secret;
-
- unsigned int num_failures;
-};
-
/* structures */
extern ATTRIB_MAP_ENTRY attrib_map_v22[];
const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key );
char** get_attr_list( ATTRIB_MAP_ENTRY table[] );
void free_attr_list( char **list );
-BOOL fetch_ldap_pw(char **dn, char** pw);
void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value);
+void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
+ LDAPMod ***mods,
+ const char *attribute, const char *newval);
-#endif /* _SMBLDAP_H */
+/**
+ * Struct to keep the state for all the ldap stuff
+ *
+ */
+
+struct smbldap_state {
+ LDAP *ldap_struct;
+ time_t last_ping;
+ /* retrive-once info */
+ const char *uri;
+ char *bind_dn;
+ char *bind_secret;
+
+ unsigned int num_failures;
+};
#endif /* HAVE_LDAP */
+
+struct smbldap_state;
+
+#endif /* _SMBLDAP_H */
+
/*
Unix SMB/CIFS mplementation.
LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
Copyright (C) Gerald Carter 2001-2003
+ Copyright (C) Shahms King 2001
+ Copyright (C) Andrew Bartlett 2002-2003
+ Copyright (C) Stefan (metze) Metzmacher 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "includes.h"
#include "smbldap.h"
+#ifndef LDAP_OPT_SUCCESS
+#define LDAP_OPT_SUCCESS 0
+#endif
+
+/* Try not to hit the up or down server forever */
+
+#define SMBLDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
+#define SMBLDAP_NUM_RETRIES 8 /* retry only 8 times */
+
+
/* attributes used by Samba 2.2 */
ATTRIB_MAP_ENTRY attrib_map_v22[] = {
perform a simple table lookup and return the attribute name
**********************************************************************/
-const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key )
+ const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key )
{
int i = 0;
Return the list of attribute names from a mapping table
**********************************************************************/
-char** get_attr_list( ATTRIB_MAP_ENTRY table[] )
+ char** get_attr_list( ATTRIB_MAP_ENTRY table[] )
{
char **names;
int i = 0;
Cleanup
********************************************************************/
-void free_attr_list( char **list )
+ void free_attr_list( char **list )
{
int i = 0;
manage memory used by the array, by each struct, and values
***********************************************************************/
-void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
+ void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
{
LDAPMod **mods;
int i;
}
+/**********************************************************************
+ Set attribute to newval in LDAP, regardless of what value the
+ attribute had in LDAP before.
+*********************************************************************/
+ void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
+ LDAPMod ***mods,
+ const char *attribute, const char *newval)
+{
+ char **values = NULL;
+
+ if (existing != NULL) {
+ values = ldap_get_values(ldap_struct, existing, attribute);
+ }
+
+ /* all of our string attributes are case insensitive */
+
+ if ((values != NULL) && (values[0] != NULL) &&
+ StrCaseCmp(values[0], newval) == 0)
+ {
+
+ /* Believe it or not, but LDAP will deny a delete and
+ an add at the same time if the values are the
+ same... */
+
+ ldap_value_free(values);
+ return;
+ }
+
+ /* Regardless of the real operation (add or modify)
+ we add the new value here. We rely on deleting
+ the old value, should it exist. */
+
+ if ((newval != NULL) && (strlen(newval) > 0)) {
+ smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
+ }
+
+ if (values == NULL) {
+ /* There has been no value before, so don't delete it.
+ Here's a possible race: We might end up with
+ duplicate attributes */
+ return;
+ }
+
+ /* By deleting exactly the value we found in the entry this
+ should be race-free in the sense that the LDAP-Server will
+ deny the complete operation if somebody changed the
+ attribute behind our back. */
+
+ smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, values[0]);
+ ldap_value_free(values);
+}
+
+
+/**********************************************************************
+ Some varients of the LDAP rebind code do not pass in the third 'arg'
+ pointer to a void*, so we try and work around it by assuming that the
+ value of the 'LDAP *' pointer is the same as the one we had passed in
+ **********************************************************************/
+
+struct smbldap_state_lookup {
+ LDAP *ld;
+ struct smbldap_state *smbldap_state;
+ struct smbldap_state_lookup *prev, *next;
+};
+
+static struct smbldap_state_lookup *smbldap_state_lookup_list;
+
+static struct smbldap_state *smbldap_find_state(LDAP *ld)
+{
+ struct smbldap_state_lookup *t;
+
+ for (t = smbldap_state_lookup_list; t; t = t->next) {
+ if (t->ld == ld) {
+ return t->smbldap_state;
+ }
+ }
+ return NULL;
+}
+
+static void smbldap_delete_state(struct smbldap_state *smbldap_state)
+{
+ struct smbldap_state_lookup *t;
+
+ for (t = smbldap_state_lookup_list; t; t = t->next) {
+ if (t->smbldap_state == smbldap_state) {
+ DLIST_REMOVE(smbldap_state_lookup_list, t);
+ SAFE_FREE(t);
+ return;
+ }
+ }
+}
+
+static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
+{
+ struct smbldap_state *tmp_ldap_state;
+ struct smbldap_state_lookup *t;
+ struct smbldap_state_lookup *tmp;
+
+ if ((tmp_ldap_state = smbldap_find_state(ld))) {
+ SMB_ASSERT(tmp_ldap_state == smbldap_state);
+ return;
+ }
+
+ t = smb_xmalloc(sizeof(*t));
+ ZERO_STRUCTP(t);
+
+ DLIST_ADD_END(smbldap_state_lookup_list, t, tmp);
+ t->ld = ld;
+ t->smbldap_state = smbldap_state;
+}
+
+/*******************************************************************
+ open a connection to the ldap server.
+******************************************************************/
+static int smbldap_open_connection (struct smbldap_state *ldap_state)
+
+{
+ int rc = LDAP_SUCCESS;
+ int version;
+ BOOL ldap_v3 = False;
+ LDAP **ldap_struct = &ldap_state->ldap_struct;
+
+#ifdef HAVE_LDAP_INITIALIZE
+ DEBUG(10, ("smbldap_open_connection: %s\n", ldap_state->uri));
+
+ if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
+ DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
+ return rc;
+ }
+#else
+
+ /* Parse the string manually */
+
+ {
+ int port = 0;
+ fstring protocol;
+ fstring host;
+ const char *p = ldap_state->uri;
+ SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
+
+ /* skip leading "URL:" (if any) */
+ if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
+ p += 4;
+ }
+
+ sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
+
+ if (port == 0) {
+ if (strequal(protocol, "ldap")) {
+ port = LDAP_PORT;
+ } else if (strequal(protocol, "ldaps")) {
+ port = LDAPS_PORT;
+ } else {
+ DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
+ }
+ }
+
+ if ((*ldap_struct = ldap_init(host, port)) == NULL) {
+ DEBUG(0, ("ldap_init failed !\n"));
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (strequal(protocol, "ldaps")) {
+#ifdef LDAP_OPT_X_TLS
+ int tls = LDAP_OPT_X_TLS_HARD;
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Failed to setup a TLS session\n"));
+ }
+
+ DEBUG(3,("LDAPS option set...!\n"));
+#else
+ DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
+ return LDAP_OPERATIONS_ERROR;
+#endif
+ }
+ }
+#endif
+
+ /* Store the LDAP pointer in a lookup list */
+
+ smbldap_store_state(*ldap_struct, ldap_state);
+
+ /* Upgrade to LDAPv3 if possible */
+
+ if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version != LDAP_VERSION3)
+ {
+ version = LDAP_VERSION3;
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
+ ldap_v3 = True;
+ }
+ } else {
+ ldap_v3 = True;
+ }
+ }
+
+ if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
+#ifdef LDAP_OPT_X_TLS
+ if (ldap_v3) {
+ if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
+ {
+ DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
+ ldap_err2string(rc)));
+ return rc;
+ }
+ DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
+ } else {
+
+ DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
+ return LDAP_OPERATIONS_ERROR;
+ }
+#else
+ DEBUG(0,("smbldap_open_connection: StartTLS not supported by LDAP client libraries!\n"));
+ return LDAP_OPERATIONS_ERROR;
+#endif
+ }
+
+ DEBUG(2, ("smbldap_open_connection: connection opened\n"));
+ return rc;
+}
+
+
+/*******************************************************************
+ a rebind function for authenticated referrals
+ This version takes a void* that we can shove useful stuff in :-)
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+#else
+static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
+ int *methodp, int freeit, void *arg)
+{
+ struct smbldap_state *ldap_state = arg;
+
+ /** @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
+ username and password to? */
+
+ if (freeit) {
+ SAFE_FREE(*whop);
+ memset(*credp, '\0', strlen(*credp));
+ SAFE_FREE(*credp);
+ } else {
+ DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
+ ldap_state->bind_dn));
+
+ *whop = strdup(ldap_state->bind_dn);
+ if (!*whop) {
+ return LDAP_NO_MEMORY;
+ }
+ *credp = strdup(ldap_state->bind_secret);
+ if (!*credp) {
+ SAFE_FREE(*whop);
+ return LDAP_NO_MEMORY;
+ }
+ *methodp = LDAP_AUTH_SIMPLE;
+ }
+ return 0;
+}
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ a rebind function for authenticated referrals
+ This version takes a void* that we can shove useful stuff in :-)
+ and actually does the connection.
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+static int rebindproc_connect_with_state (LDAP *ldap_struct,
+ LDAP_CONST char *url,
+ ber_tag_t request,
+ ber_int_t msgid, void *arg)
+{
+ struct smbldap_state *ldap_state = arg;
+ int rc;
+ DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n",
+ ldap_state->bind_dn));
+
+ /** @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
+ username and password to? */
+
+ rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+
+ return rc;
+}
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ Add a rebind function for authenticated referrals
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+#else
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
+ int *method, int freeit )
+{
+ struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
+
+ return rebindproc_with_state(ldap_struct, whop, credp,
+ method, freeit, ldap_state);
+
+}
+# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ a rebind function for authenticated referrals
+ this also does the connection, but no void*.
+******************************************************************/
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
+ ber_int_t msgid)
+{
+ struct smbldap_state *ldap_state = smbldap_find_state(ld);
+
+ return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
+ ldap_state);
+}
+# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+/*******************************************************************
+ connect to the ldap server under system privilege.
+******************************************************************/
+static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_struct)
+{
+ int rc;
+ char *ldap_dn;
+ char *ldap_secret;
+
+ /* get the password */
+ if (!fetch_ldap_pw(&ldap_dn, &ldap_secret))
+ {
+ DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
+ return LDAP_INVALID_CREDENTIALS;
+ }
+
+ ldap_state->bind_dn = ldap_dn;
+ ldap_state->bind_secret = ldap_secret;
+
+ /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
+ (OpenLDAP) doesnt' seem to support it */
+
+ DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
+ ldap_state->uri, ldap_dn));
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+ ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
+# endif
+# if LDAP_SET_REBIND_PROC_ARGS == 3
+ ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
+# endif
+#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+# if LDAP_SET_REBIND_PROC_ARGS == 2
+ ldap_set_rebind_proc(ldap_struct, &rebindproc);
+# endif
+# if LDAP_SET_REBIND_PROC_ARGS == 3
+ ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
+# endif
+#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
+
+ rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
+
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(ldap_state->num_failures ? 2 : 0,
+ ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
+ ldap_dn ? ldap_dn : "(unknown)", ldap_err2string(rc),
+ ld_error ? ld_error : "(unknown)"));
+ SAFE_FREE(ld_error);
+ ldap_state->num_failures++;
+ return rc;
+ }
+
+ ldap_state->num_failures = 0;
+
+ DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
+ return rc;
+}
+
+/**********************************************************************
+Connect to LDAP server (called before every ldap operation)
+*********************************************************************/
+static int smbldap_open(struct smbldap_state *ldap_state)
+{
+ int rc;
+ SMB_ASSERT(ldap_state);
+
+#ifndef NO_LDAP_SECURITY
+ if (geteuid() != 0) {
+ DEBUG(0, ("smbldap_open: cannot access LDAP when not root..\n"));
+ return LDAP_INSUFFICIENT_ACCESS;
+ }
+#endif
+
+ if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time(NULL))) {
+ struct sockaddr_un addr;
+ socklen_t len = sizeof(addr);
+ int sd;
+ if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
+ getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
+ /* the other end has died. reopen. */
+ ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
+ ldap_state->ldap_struct = NULL;
+ ldap_state->last_ping = (time_t)0;
+ } else {
+ ldap_state->last_ping = time(NULL);
+ }
+ }
+
+ if (ldap_state->ldap_struct != NULL) {
+ DEBUG(5,("smbldap_open: already connected to the LDAP server\n"));
+ return LDAP_SUCCESS;
+ }
+
+ if ((rc = smbldap_open_connection(ldap_state))) {
+ return rc;
+ }
+
+ if ((rc = smbldap_connect_system(ldap_state, ldap_state->ldap_struct))) {
+ ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
+ ldap_state->ldap_struct = NULL;
+ return rc;
+ }
+
+
+ ldap_state->last_ping = time(NULL);
+ DEBUG(4,("The LDAP server is succesful connected\n"));
+
+ return LDAP_SUCCESS;
+}
+
+/**********************************************************************
+Disconnect from LDAP server
+*********************************************************************/
+static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
+{
+ if (!ldap_state)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if (ldap_state->ldap_struct != NULL) {
+ ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
+ ldap_state->ldap_struct = NULL;
+ }
+
+ smbldap_delete_state(ldap_state);
+
+ DEBUG(5,("The connection to the LDAP server was closed\n"));
+ /* maybe free the results here --metze */
+
+
+
+ return NT_STATUS_OK;
+}
+
+static int smbldap_retry_open(struct smbldap_state *ldap_state, int *attempts)
+{
+ int rc;
+
+ SMB_ASSERT(ldap_state && attempts);
+
+ if (*attempts != 0) {
+ unsigned int sleep_time;
+ uint8 rand_byte;
+
+ /* Sleep for a random timeout */
+ rand_byte = (char)(sys_random());
+
+ sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2;
+ /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
+ on average.
+ */
+ DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n",
+ sleep_time));
+ msleep(sleep_time);
+ }
+ (*attempts)++;
+
+ if ((rc = smbldap_open(ldap_state))) {
+ DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts));
+ return rc;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+
+/*********************************************************************
+ ********************************************************************/
+
+int smbldap_search(struct smbldap_state *ldap_state,
+ const char *base, int scope, const char *filter,
+ char *attrs[], int attrsonly,
+ LDAPMessage **res)
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_filter;
+
+ SMB_ASSERT(ldap_state);
+
+ if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
+ return LDAP_NO_MEMORY;
+ }
+
+ while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
+
+ if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
+ continue;
+
+ rc = ldap_search_s(ldap_state->ldap_struct, base, scope,
+ utf8_filter, attrs, attrsonly, res);
+ }
+
+ if (rc == LDAP_SERVER_DOWN) {
+ DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
+ smbldap_close(ldap_state);
+ }
+
+ SAFE_FREE(utf8_filter);
+ return rc;
+}
+
+int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_dn;
+
+ SMB_ASSERT(ldap_state);
+
+ if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
+ return LDAP_NO_MEMORY;
+ }
+
+ while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
+
+ if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
+ continue;
+
+ rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
+ }
+
+ if (rc == LDAP_SERVER_DOWN) {
+ DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
+ smbldap_close(ldap_state);
+ }
+
+ SAFE_FREE(utf8_dn);
+ return rc;
+}
+
+int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_dn;
+
+ SMB_ASSERT(ldap_state);
+
+ if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
+ return LDAP_NO_MEMORY;
+ }
+
+ while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
+
+ if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
+ continue;
+
+ rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
+ }
+
+ if (rc == LDAP_SERVER_DOWN) {
+ DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
+ smbldap_close(ldap_state);
+ }
+
+ SAFE_FREE(utf8_dn);
+ return rc;
+}
+
+int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+ char *utf8_dn;
+
+ SMB_ASSERT(ldap_state);
+
+ if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
+ return LDAP_NO_MEMORY;
+ }
+
+ while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
+
+ if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
+ continue;
+
+ rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
+ }
+
+ if (rc == LDAP_SERVER_DOWN) {
+ DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
+ smbldap_close(ldap_state);
+ }
+
+ SAFE_FREE(utf8_dn);
+ return rc;
+}
+
+int smbldap_extended_operation(struct smbldap_state *ldap_state,
+ LDAP_CONST char *reqoid, struct berval *reqdata,
+ LDAPControl **serverctrls, LDAPControl **clientctrls,
+ char **retoidp, struct berval **retdatap)
+{
+ int rc = LDAP_SERVER_DOWN;
+ int attempts = 0;
+
+ if (!ldap_state)
+ return (-1);
+
+ while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
+
+ if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
+ continue;
+
+ rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata,
+ serverctrls, clientctrls, retoidp, retdatap);
+ }
+
+ if (rc == LDAP_SERVER_DOWN) {
+ DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
+ smbldap_close(ldap_state);
+ }
+
+ return rc;
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+int smbldap_search_suffix (struct smbldap_state *ldap_state, const char *filter,
+ char **search_attr, LDAPMessage ** result)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ int rc;
+
+ DEBUG(2, ("smbldap_search_suffix: searching for:[%s]\n", filter));
+
+ rc = smbldap_search(ldap_state, lp_ldap_suffix(), scope, filter, search_attr, 0, result);
+
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,("smbldap_search_suffix: Problem during the LDAP search: %s (%s)\n",
+ ld_error?ld_error:"(unknown)", ldap_err2string (rc)));
+ DEBUG(3,("smbldap_search_suffix: Query was: %s, %s\n", lp_ldap_suffix(),
+ filter));
+ SAFE_FREE(ld_error);
+ }
+
+ return rc;
+}
+
+/**********************************************************************
+ Housekeeping
+ *********************************************************************/
+
+void smbldap_free_struct(struct smbldap_state **ldap_state)
+{
+ smbldap_close(*ldap_state);
+
+ if ((*ldap_state)->bind_secret) {
+ memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
+ }
+
+ SAFE_FREE((*ldap_state)->bind_dn);
+ SAFE_FREE((*ldap_state)->bind_secret);
+
+ *ldap_state = NULL;
+
+ /* No need to free any further, as it is talloc()ed */
+}
+
+
+/**********************************************************************
+ Intitalise the 'general' ldap structures, on which ldap operations may be conducted
+ *********************************************************************/
+
+NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, const char *location, struct smbldap_state **smbldap_state)
+{
+ *smbldap_state = talloc_zero(mem_ctx, sizeof(**smbldap_state));
+ if (!*smbldap_state) {
+ DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (location) {
+ (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
+ } else {
+ (*smbldap_state)->uri = "ldap://localhost";
+ }
+ return NT_STATUS_OK;
+}
+
Copyright (C) Jean François Micouleau 1998
Copyright (C) Gerald Carter 2001-2003
Copyright (C) Shahms King 2001
- Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Andrew Bartlett 2002-2003
Copyright (C) Stefan (metze) Metzmacher 2002
This program is free software; you can redistribute it and/or modify
#include <lber.h>
#include <ldap.h>
-#ifndef LDAP_OPT_SUCCESS
-#define LDAP_OPT_SUCCESS 0
-#endif
+/*
+ * Work around versions of the LDAP client libs that don't have the OIDs
+ * defined, or have them defined under the old name.
+ * This functionality is really a factor of the server, not the client
+ *
+ */
#if defined(LDAP_EXOP_X_MODIFY_PASSWD) && !defined(LDAP_EXOP_MODIFY_PASSWD)
#define LDAP_EXOP_MODIFY_PASSWD LDAP_EXOP_X_MODIFY_PASSWD
#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U)
#endif
+
#ifndef SAM_ACCOUNT
#define SAM_ACCOUNT struct sam_passwd
#endif
};
-#define SMBLDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
-#define SMBLDAP_NUM_RETRIES 8 /* retry only 8 times */
-
/**********************************************************************
get the attribute name given a user schame version
**********************************************************************/
return NULL;
}
-
-/**********************************************************************
- Some varients of the LDAP rebind code do not pass in the third 'arg'
- pointer to a void*, so we try and work around it by assuming that the
- value of the 'LDAP *' pointer is the same as the one we had passed in
- **********************************************************************/
-
-struct smbldap_state_lookup {
- LDAP *ld;
- struct smbldap_state *smbldap_state;
- struct smbldap_state_lookup *prev, *next;
-};
-
-static struct smbldap_state_lookup *smbldap_state_lookup_list;
-
-static struct smbldap_state *smbldap_find_state(LDAP *ld)
-{
- struct smbldap_state_lookup *t;
-
- for (t = smbldap_state_lookup_list; t; t = t->next) {
- if (t->ld == ld) {
- return t->smbldap_state;
- }
- }
- return NULL;
-}
-
-static void smbldap_delete_state(struct smbldap_state *smbldap_state)
-{
- struct smbldap_state_lookup *t;
-
- for (t = smbldap_state_lookup_list; t; t = t->next) {
- if (t->smbldap_state == smbldap_state) {
- DLIST_REMOVE(smbldap_state_lookup_list, t);
- SAFE_FREE(t);
- return;
- }
- }
-}
-
-static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
-{
- struct smbldap_state *tmp_ldap_state;
- struct smbldap_state_lookup *t;
- struct smbldap_state_lookup *tmp;
-
- if ((tmp_ldap_state = smbldap_find_state(ld))) {
- SMB_ASSERT(tmp_ldap_state == smbldap_state);
- return;
- }
-
- t = smb_xmalloc(sizeof(*t));
- ZERO_STRUCTP(t);
-
- DLIST_ADD_END(smbldap_state_lookup_list, t, tmp);
- t->ld = ld;
- t->smbldap_state = smbldap_state;
-}
-
-/*******************************************************************
- open a connection to the ldap server.
-******************************************************************/
-static int smbldap_open_connection (struct smbldap_state *ldap_state)
-
-{
- int rc = LDAP_SUCCESS;
- int version;
- BOOL ldap_v3 = False;
- LDAP **ldap_struct = &ldap_state->ldap_struct;
-
-#ifdef HAVE_LDAP_INITIALIZE
- DEBUG(10, ("smbldap_open_connection: %s\n", ldap_state->uri));
-
- if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
- DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
- return rc;
- }
-#else
-
- /* Parse the string manually */
-
- {
- int port = 0;
- fstring protocol;
- fstring host;
- const char *p = ldap_state->uri;
- SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
-
- /* skip leading "URL:" (if any) */
- if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
- p += 4;
- }
-
- sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
-
- if (port == 0) {
- if (strequal(protocol, "ldap")) {
- port = LDAP_PORT;
- } else if (strequal(protocol, "ldaps")) {
- port = LDAPS_PORT;
- } else {
- DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
- }
- }
-
- if ((*ldap_struct = ldap_init(host, port)) == NULL) {
- DEBUG(0, ("ldap_init failed !\n"));
- return LDAP_OPERATIONS_ERROR;
- }
-
- if (strequal(protocol, "ldaps")) {
-#ifdef LDAP_OPT_X_TLS
- int tls = LDAP_OPT_X_TLS_HARD;
- if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
- {
- DEBUG(0, ("Failed to setup a TLS session\n"));
- }
-
- DEBUG(3,("LDAPS option set...!\n"));
-#else
- DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
- return LDAP_OPERATIONS_ERROR;
-#endif
- }
- }
-#endif
-
- /* Store the LDAP pointer in a lookup list */
-
- smbldap_store_state(*ldap_struct, ldap_state);
-
- /* Upgrade to LDAPv3 if possible */
-
- if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
- {
- if (version != LDAP_VERSION3)
- {
- version = LDAP_VERSION3;
- if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
- ldap_v3 = True;
- }
- } else {
- ldap_v3 = True;
- }
- }
-
- if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
-#ifdef LDAP_OPT_X_TLS
- if (ldap_v3) {
- if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
- {
- DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
- ldap_err2string(rc)));
- return rc;
- }
- DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
- } else {
-
- DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
- return LDAP_OPERATIONS_ERROR;
- }
-#else
- DEBUG(0,("smbldap_open_connection: StartTLS not supported by LDAP client libraries!\n"));
- return LDAP_OPERATIONS_ERROR;
-#endif
- }
-
- DEBUG(2, ("smbldap_open_connection: connection opened\n"));
- return rc;
-}
-
-
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
- int *methodp, int freeit, void *arg)
-{
- struct smbldap_state *ldap_state = arg;
-
- /** @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
- username and password to? */
-
- if (freeit) {
- SAFE_FREE(*whop);
- memset(*credp, '\0', strlen(*credp));
- SAFE_FREE(*credp);
- } else {
- DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
- ldap_state->bind_dn));
-
- *whop = strdup(ldap_state->bind_dn);
- if (!*whop) {
- return LDAP_NO_MEMORY;
- }
- *credp = strdup(ldap_state->bind_secret);
- if (!*credp) {
- SAFE_FREE(*whop);
- return LDAP_NO_MEMORY;
- }
- *methodp = LDAP_AUTH_SIMPLE;
- }
- return 0;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
- and actually does the connection.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-static int rebindproc_connect_with_state (LDAP *ldap_struct,
- LDAP_CONST char *url,
- ber_tag_t request,
- ber_int_t msgid, void *arg)
-{
- struct smbldap_state *ldap_state = arg;
- int rc;
- DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n",
- ldap_state->bind_dn));
-
- /** @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
- username and password to? */
-
- rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
-
- return rc;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- Add a rebind function for authenticated referrals
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
- int *method, int freeit )
-{
- struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
-
- return rebindproc_with_state(ldap_struct, whop, credp,
- method, freeit, ldap_state);
-
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- this also does the connection, but no void*.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
- ber_int_t msgid)
-{
- struct smbldap_state *ldap_state = smbldap_find_state(ld);
-
- return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
- ldap_state);
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- connect to the ldap server under system privilege.
-******************************************************************/
-static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_struct)
-{
- int rc;
- char *ldap_dn;
- char *ldap_secret;
-
- /* get the password */
- if (!fetch_ldap_pw(&ldap_dn, &ldap_secret))
- {
- DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
- return LDAP_INVALID_CREDENTIALS;
- }
-
- ldap_state->bind_dn = ldap_dn;
- ldap_state->bind_secret = ldap_secret;
-
- /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
- (OpenLDAP) doesnt' seem to support it */
-
- DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
- ldap_state->uri, ldap_dn));
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
-# endif
-#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-# if LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc(ldap_struct, &rebindproc);
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
-# endif
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
- rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
-
- if (rc != LDAP_SUCCESS) {
- char *ld_error = NULL;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
- &ld_error);
- DEBUG(ldap_state->num_failures ? 2 : 0,
- ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
- ldap_dn ? ldap_dn : "(unknown)", ldap_err2string(rc),
- ld_error ? ld_error : "(unknown)"));
- SAFE_FREE(ld_error);
- ldap_state->num_failures++;
- return rc;
- }
-
- ldap_state->num_failures = 0;
-
- DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
- return rc;
-}
-
-/**********************************************************************
-Connect to LDAP server (called before every ldap operation)
-*********************************************************************/
-static int smbldap_open(struct smbldap_state *ldap_state)
-{
- int rc;
- SMB_ASSERT(ldap_state);
-
-#ifndef NO_LDAP_SECURITY
- if (geteuid() != 0) {
- DEBUG(0, ("smbldap_open: cannot access LDAP when not root..\n"));
- return LDAP_INSUFFICIENT_ACCESS;
- }
-#endif
-
- if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time(NULL))) {
- struct sockaddr_un addr;
- socklen_t len = sizeof(addr);
- int sd;
- if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
- getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
- /* the other end has died. reopen. */
- ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
- ldap_state->ldap_struct = NULL;
- ldap_state->last_ping = (time_t)0;
- } else {
- ldap_state->last_ping = time(NULL);
- }
- }
-
- if (ldap_state->ldap_struct != NULL) {
- DEBUG(5,("smbldap_open: already connected to the LDAP server\n"));
- return LDAP_SUCCESS;
- }
-
- if ((rc = smbldap_open_connection(ldap_state))) {
- return rc;
- }
-
- if ((rc = smbldap_connect_system(ldap_state, ldap_state->ldap_struct))) {
- ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
- ldap_state->ldap_struct = NULL;
- return rc;
- }
-
-
- ldap_state->last_ping = time(NULL);
- DEBUG(4,("The LDAP server is succesful connected\n"));
-
- return LDAP_SUCCESS;
-}
-
-/**********************************************************************
-Disconnect from LDAP server
-*********************************************************************/
-static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
-{
- if (!ldap_state)
- return NT_STATUS_INVALID_PARAMETER;
-
- if (ldap_state->ldap_struct != NULL) {
- ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
- ldap_state->ldap_struct = NULL;
- }
-
- smbldap_delete_state(ldap_state);
-
- DEBUG(5,("The connection to the LDAP server was closed\n"));
- /* maybe free the results here --metze */
-
-
-
- return NT_STATUS_OK;
-}
-
-static int smbldap_retry_open(struct smbldap_state *ldap_state, int *attempts)
-{
- int rc;
-
- SMB_ASSERT(ldap_state && attempts);
-
- if (*attempts != 0) {
- unsigned int sleep_time;
- uint8 rand_byte;
-
- /* Sleep for a random timeout */
- rand_byte = (char)(sys_random());
-
- sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2;
- /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
- on average.
- */
- DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n",
- sleep_time));
- msleep(sleep_time);
- }
- (*attempts)++;
-
- if ((rc = smbldap_open(ldap_state))) {
- DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts));
- return rc;
- }
-
- return LDAP_SUCCESS;
-}
-
-
-/*********************************************************************
- ********************************************************************/
-
-static int smbldap_search(struct smbldap_state *ldap_state,
- const char *base, int scope, const char *filter,
- char *attrs[], int attrsonly,
- LDAPMessage **res)
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_filter;
-
- SMB_ASSERT(ldap_state);
-
- if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_search_s(ldap_state->ldap_struct, base, scope,
- utf8_filter, attrs, attrsonly, res);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- SAFE_FREE(utf8_filter);
- return rc;
-}
-
-static int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_dn;
-
- SMB_ASSERT(ldap_state);
-
- if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- SAFE_FREE(utf8_dn);
- return rc;
-}
-
-static int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_dn;
-
- SMB_ASSERT(ldap_state);
-
- if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- SAFE_FREE(utf8_dn);
- return rc;
-}
-
-static int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_dn;
-
- SMB_ASSERT(ldap_state);
-
- if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- SAFE_FREE(utf8_dn);
- return rc;
-}
-
-static int smbldap_extended_operation(struct smbldap_state *ldap_state,
- LDAP_CONST char *reqoid, struct berval *reqdata,
- LDAPControl **serverctrls, LDAPControl **clientctrls,
- char **retoidp, struct berval **retdatap)
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
-
- if (!ldap_state)
- return (-1);
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata,
- serverctrls, clientctrls, retoidp, retdatap);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- return rc;
-}
-
-/*******************************************************************
- run the search by name.
-******************************************************************/
-static int smbldap_search_suffix (struct smbldap_state *ldap_state, const char *filter,
- char **search_attr, LDAPMessage ** result)
-{
- int scope = LDAP_SCOPE_SUBTREE;
- int rc;
-
- DEBUG(2, ("smbldap_search_suffix: searching for:[%s]\n", filter));
-
- rc = smbldap_search(ldap_state, lp_ldap_suffix(), scope, filter, search_attr, 0, result);
-
- if (rc != LDAP_SUCCESS) {
- char *ld_error = NULL;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
- &ld_error);
- DEBUG(0,("smbldap_search_suffix: Problem during the LDAP search: %s (%s)\n",
- ld_error?ld_error:"(unknown)", ldap_err2string (rc)));
- DEBUG(3,("smbldap_search_suffix: Query was: %s, %s\n", lp_ldap_suffix(),
- filter));
- SAFE_FREE(ld_error);
- }
-
- return rc;
-}
-
/*******************************************************************
generate the LDAP search filter for the objectclass based on the
version of the schema we are using
return True;
}
-/**********************************************************************
- Set attribute to newval in LDAP, regardless of what value the
- attribute had in LDAP before.
-*********************************************************************/
-static void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
- LDAPMod ***mods,
- const char *attribute, const char *newval)
-{
- char **values = NULL;
-
- if (existing != NULL) {
- values = ldap_get_values(ldap_struct, existing, attribute);
- }
-
- /* all of our string attributes are case insensitive */
-
- if ((values != NULL) && (values[0] != NULL) &&
- StrCaseCmp(values[0], newval) == 0)
- {
-
- /* Believe it or not, but LDAP will deny a delete and
- an add at the same time if the values are the
- same... */
-
- ldap_value_free(values);
- return;
- }
-
- /* Regardless of the real operation (add or modify)
- we add the new value here. We rely on deleting
- the old value, should it exist. */
-
- if ((newval != NULL) && (strlen(newval) > 0)) {
- smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
- }
-
- if (values == NULL) {
- /* There has been no value before, so don't delete it.
- Here's a possible race: We might end up with
- duplicate attributes */
- return;
- }
-
- /* By deleting exactly the value we found in the entry this
- should be race-free in the sense that the LDAP-Server will
- deny the complete operation if somebody changed the
- attribute behind our back. */
-
- smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, values[0]);
- ldap_value_free(values);
-}
-
/*******************************************************************
Delete complete object or objectclass and attrs from
object found in search_result depending on lp_ldap_delete_dn
return NT_STATUS_OK;
}
-/**********************************************************************
- Housekeeping
- *********************************************************************/
-
-static void smbldap_free_struct(struct smbldap_state **ldap_state)
-{
- smbldap_close(*ldap_state);
-
- if ((*ldap_state)->bind_secret) {
- memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
- }
-
- SAFE_FREE((*ldap_state)->bind_dn);
- SAFE_FREE((*ldap_state)->bind_secret);
-
- *ldap_state = NULL;
-
- /* No need to free any further, as it is talloc()ed */
-}
-
-
/**********************************************************************
Housekeeping
*********************************************************************/
return NT_STATUS_OK;
}
-/**********************************************************************
- Intitalise the 'general' ldap structures, on which ldap operations may be conducted
- *********************************************************************/
-
-static NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, const char *location, struct smbldap_state **smbldap_state)
-{
- *smbldap_state = talloc_zero(mem_ctx, sizeof(**smbldap_state));
- if (!*smbldap_state) {
- DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- if (location) {
- (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
- } else {
- (*smbldap_state)->uri = "ldap://localhost";
- }
- return NT_STATUS_OK;
-}
-
/**********************************************************************
Intitalise the parts of the pdb_context that are common to all pdb_ldap modes
*********************************************************************/