From eb61c8238298e97644202139e6d7f55e46eb9c26 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 25 Jun 2003 12:51:58 +0000 Subject: Patch to move functions directly from pdb_ldap.c into lib/smbldap.c The functions are unchanged. Next step is to make idmap_ldap use them. Andrew Bartlett (This used to be commit 57617a0f8c84f9ced4df2901811ce5a5a5ae005e) --- source3/Makefile.in | 2 +- source3/include/smbldap.h | 40 ++- source3/lib/smbldap.c | 733 +++++++++++++++++++++++++++++++++++++++++++++- source3/passdb/pdb_ldap.c | 726 +-------------------------------------------- 4 files changed, 763 insertions(+), 738 deletions(-) diff --git a/source3/Makefile.in b/source3/Makefile.in index 7cf07c15b4..c96a87ebc7 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -562,7 +562,7 @@ PROTO_OBJ = $(SMBD_OBJ_MAIN) \ $(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) diff --git a/source3/include/smbldap.h b/source3/include/smbldap.h index 31f8d33b88..5f3606aa32 100644 --- a/source3/include/smbldap.h +++ b/source3/include/smbldap.h @@ -19,11 +19,11 @@ */ -#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 @@ -93,17 +93,6 @@ typedef struct _attrib_map_entry { } 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[]; @@ -120,9 +109,30 @@ extern ATTRIB_MAP_ENTRY sidmap_attr_list[]; 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 */ + diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index b627134446..8401787317 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -1,7 +1,11 @@ /* 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 @@ -22,6 +26,16 @@ #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[] = { @@ -133,7 +147,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { 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; @@ -151,7 +165,7 @@ const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key ) 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; @@ -180,7 +194,7 @@ char** get_attr_list( ATTRIB_MAP_ENTRY table[] ) Cleanup ********************************************************************/ -void free_attr_list( char **list ) + void free_attr_list( char **list ) { int i = 0; @@ -262,7 +276,7 @@ BOOL fetch_ldap_pw(char **dn, char** pw) 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; @@ -345,3 +359,714 @@ void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, con } +/********************************************************************** + 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; +} + diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index 1149a92a99..ec164a7e7b 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -4,7 +4,7 @@ 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 @@ -51,9 +51,12 @@ #include #include -#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 @@ -73,6 +76,7 @@ #define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U) #endif + #ifndef SAM_ACCOUNT #define SAM_ACCOUNT struct sam_passwd #endif @@ -103,9 +107,6 @@ struct ldapsam_privates { }; -#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 **********************************************************************/ @@ -147,624 +148,6 @@ static char** get_userattr_list( int schema_ver ) 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 @@ -900,58 +283,6 @@ static BOOL get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry, 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 @@ -2758,27 +2089,6 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO 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 *********************************************************************/ @@ -3340,26 +2650,6 @@ static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods, 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 *********************************************************************/ -- cgit