diff options
Diffstat (limited to 'source3/lib/smbldap.c')
-rw-r--r-- | source3/lib/smbldap.c | 731 |
1 files changed, 284 insertions, 447 deletions
diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index 1d507fb696..5dd6d8d65b 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -24,8 +24,9 @@ #include "includes.h" #include "smbldap.h" -#include "secrets.h" #include "../libcli/security/security.h" +#include <tevent.h> +#include "lib/param/loadparm.h" /* Try not to hit the up or down server forever */ @@ -35,226 +36,6 @@ #define SMBLDAP_IDLE_TIME 150 /* After 2.5 minutes disconnect */ -/* attributes used by Samba 2.2 */ - -ATTRIB_MAP_ENTRY attrib_map_v22[] = { - { LDAP_ATTR_UID, "uid" }, - { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER}, - { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER}, - { LDAP_ATTR_UNIX_HOME, "homeDirectory" }, - { LDAP_ATTR_PWD_LAST_SET, "pwdLastSet" }, - { LDAP_ATTR_PWD_CAN_CHANGE, "pwdCanChange" }, - { LDAP_ATTR_PWD_MUST_CHANGE, "pwdMustChange" }, - { LDAP_ATTR_LOGON_TIME, "logonTime" }, - { LDAP_ATTR_LOGOFF_TIME, "logoffTime" }, - { LDAP_ATTR_KICKOFF_TIME, "kickoffTime" }, - { LDAP_ATTR_CN, "cn" }, - { LDAP_ATTR_SN, "sn" }, - { LDAP_ATTR_DISPLAY_NAME, "displayName" }, - { LDAP_ATTR_HOME_PATH, "smbHome" }, - { LDAP_ATTR_HOME_DRIVE, "homeDrive" }, - { LDAP_ATTR_LOGON_SCRIPT, "scriptPath" }, - { LDAP_ATTR_PROFILE_PATH, "profilePath" }, - { LDAP_ATTR_DESC, "description" }, - { LDAP_ATTR_USER_WKS, "userWorkstations"}, - { LDAP_ATTR_USER_RID, "rid" }, - { LDAP_ATTR_PRIMARY_GROUP_RID, "primaryGroupID"}, - { LDAP_ATTR_LMPW, "lmPassword" }, - { LDAP_ATTR_NTPW, "ntPassword" }, - { LDAP_ATTR_DOMAIN, "domain" }, - { LDAP_ATTR_OBJCLASS, "objectClass" }, - { LDAP_ATTR_ACB_INFO, "acctFlags" }, - { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -ATTRIB_MAP_ENTRY attrib_map_to_delete_v22[] = { - { LDAP_ATTR_PWD_LAST_SET, "pwdLastSet" }, - { LDAP_ATTR_PWD_CAN_CHANGE, "pwdCanChange" }, - { LDAP_ATTR_PWD_MUST_CHANGE, "pwdMustChange" }, - { LDAP_ATTR_LOGON_TIME, "logonTime" }, - { LDAP_ATTR_LOGOFF_TIME, "logoffTime" }, - { LDAP_ATTR_KICKOFF_TIME, "kickoffTime" }, - { LDAP_ATTR_DISPLAY_NAME, "displayName" }, - { LDAP_ATTR_HOME_PATH, "smbHome" }, - { LDAP_ATTR_HOME_DRIVE, "homeDrives" }, - { LDAP_ATTR_LOGON_SCRIPT, "scriptPath" }, - { LDAP_ATTR_PROFILE_PATH, "profilePath" }, - { LDAP_ATTR_USER_WKS, "userWorkstations"}, - { LDAP_ATTR_USER_RID, "rid" }, - { LDAP_ATTR_PRIMARY_GROUP_RID, "primaryGroupID"}, - { LDAP_ATTR_LMPW, "lmPassword" }, - { LDAP_ATTR_NTPW, "ntPassword" }, - { LDAP_ATTR_DOMAIN, "domain" }, - { LDAP_ATTR_ACB_INFO, "acctFlags" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -/* attributes used by Samba 3.0's sambaSamAccount */ - -ATTRIB_MAP_ENTRY attrib_map_v30[] = { - { LDAP_ATTR_UID, "uid" }, - { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER}, - { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER}, - { LDAP_ATTR_UNIX_HOME, "homeDirectory" }, - { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" }, - { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" }, - { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" }, - { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" }, - { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" }, - { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" }, - { LDAP_ATTR_CN, "cn" }, - { LDAP_ATTR_SN, "sn" }, - { LDAP_ATTR_DISPLAY_NAME, "displayName" }, - { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" }, - { LDAP_ATTR_HOME_PATH, "sambaHomePath" }, - { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" }, - { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" }, - { LDAP_ATTR_DESC, "description" }, - { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" }, - { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID }, - { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" }, - { LDAP_ATTR_LMPW, "sambaLMPassword" }, - { LDAP_ATTR_NTPW, "sambaNTPassword" }, - { LDAP_ATTR_DOMAIN, "sambaDomainName" }, - { LDAP_ATTR_OBJCLASS, "objectClass" }, - { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" }, - { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" }, - { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" }, - { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" }, - { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" }, - { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" }, - { LDAP_ATTR_LOGON_HOURS, "sambaLogonHours" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[] = { - { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" }, - { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" }, - { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" }, - { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" }, - { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" }, - { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" }, - { LDAP_ATTR_DISPLAY_NAME, "displayName" }, - { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" }, - { LDAP_ATTR_HOME_PATH, "sambaHomePath" }, - { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" }, - { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" }, - { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" }, - { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID }, - { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" }, - { LDAP_ATTR_LMPW, "sambaLMPassword" }, - { LDAP_ATTR_NTPW, "sambaNTPassword" }, - { LDAP_ATTR_DOMAIN, "sambaDomainName" }, - { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" }, - { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" }, - { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" }, - { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" }, - { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" }, - { LDAP_ATTR_LOGON_HOURS, "sambaLogonHours" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -/* attributes used for allocating RIDs */ - -ATTRIB_MAP_ENTRY dominfo_attr_list[] = { - { LDAP_ATTR_DOMAIN, "sambaDomainName" }, - { LDAP_ATTR_NEXT_RID, "sambaNextRid" }, - { LDAP_ATTR_NEXT_USERRID, "sambaNextUserRid" }, - { LDAP_ATTR_NEXT_GROUPRID, "sambaNextGroupRid" }, - { LDAP_ATTR_DOM_SID, LDAP_ATTRIBUTE_SID }, - { LDAP_ATTR_ALGORITHMIC_RID_BASE,"sambaAlgorithmicRidBase"}, - { LDAP_ATTR_OBJCLASS, "objectClass" }, - { LDAP_ATTR_LIST_END, NULL }, -}; - -/* Samba 3.0 group mapping attributes */ - -ATTRIB_MAP_ENTRY groupmap_attr_list[] = { - { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER}, - { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID }, - { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" }, - { LDAP_ATTR_SID_LIST, "sambaSIDList" }, - { LDAP_ATTR_DESC, "description" }, - { LDAP_ATTR_DISPLAY_NAME, "displayName" }, - { LDAP_ATTR_CN, "cn" }, - { LDAP_ATTR_OBJCLASS, "objectClass" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[] = { - { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID }, - { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" }, - { LDAP_ATTR_DESC, "description" }, - { LDAP_ATTR_DISPLAY_NAME, "displayName" }, - { LDAP_ATTR_SID_LIST, "sambaSIDList" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -/* idmap_ldap sambaUnixIdPool */ - -ATTRIB_MAP_ENTRY idpool_attr_list[] = { - { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER}, - { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER}, - { LDAP_ATTR_OBJCLASS, "objectClass" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -ATTRIB_MAP_ENTRY sidmap_attr_list[] = { - { LDAP_ATTR_SID, LDAP_ATTRIBUTE_SID }, - { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER}, - { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER}, - { LDAP_ATTR_OBJCLASS, "objectClass" }, - { LDAP_ATTR_LIST_END, NULL } -}; - -/********************************************************************** - perform a simple table lookup and return the attribute name - **********************************************************************/ - - const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key ) -{ - int i = 0; - - while ( table[i].attrib != LDAP_ATTR_LIST_END ) { - if ( table[i].attrib == key ) - return table[i].name; - i++; - } - - return NULL; -} - - -/********************************************************************** - Return the list of attribute names from a mapping table - **********************************************************************/ - - const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] ) -{ - const char **names; - int i = 0; - - while ( table[i].attrib != LDAP_ATTR_LIST_END ) - i++; - i++; - - names = TALLOC_ARRAY( mem_ctx, const char*, i ); - if ( !names ) { - DEBUG(0,("get_attr_list: out of memory\n")); - return NULL; - } - - i = 0; - while ( table[i].attrib != LDAP_ATTR_LIST_END ) { - names[i] = talloc_strdup( names, table[i].name ); - i++; - } - names[i] = NULL; - - return names; -} - /******************************************************************* Search an attribute and return the first value found. ******************************************************************/ @@ -264,6 +45,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { int max_len) { char **values; + size_t size = 0; if ( !attribute ) return False; @@ -276,7 +58,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return False; } - if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, False) == (size_t)-1) { + if (!convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, &size)) { DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n", attribute, values[0])); ldap_value_free(values); @@ -404,7 +186,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return NULL; } - if (StrCaseCmp(tmp, result) < 0) { + if (strcasecmp_m(tmp, result) < 0) { TALLOC_FREE(result); result = tmp; } else { @@ -465,7 +247,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return 0; } - void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result) + void smbldap_talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result) { LDAPMessage **handle; @@ -473,7 +255,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return; } - handle = TALLOC_P(mem_ctx, LDAPMessage *); + handle = talloc(mem_ctx, LDAPMessage *); SMB_ASSERT(handle != NULL); *handle = result; @@ -485,7 +267,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return 0; } - void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod) + void smbldap_talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod) { LDAPMod ***handle; @@ -493,7 +275,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { return; } - handle = TALLOC_P(mem_ctx, LDAPMod **); + handle = talloc(mem_ctx, LDAPMod **); SMB_ASSERT(handle != NULL); *handle = mod; @@ -630,12 +412,6 @@ static void smbldap_make_mod_internal(LDAP *ldap_struct, LDAPMessage *existing, bool existed; DATA_BLOB oldblob = data_blob_null; - if (attribute == NULL) { - /* This can actually happen for ldapsam_compat where we for - * example don't have a password history */ - return; - } - if (existing != NULL) { if (op & LDAP_MOD_BVALUES) { existed = smbldap_talloc_single_blob(talloc_tos(), ldap_struct, existing, attribute, &oldblob); @@ -653,7 +429,7 @@ static void smbldap_make_mod_internal(LDAP *ldap_struct, LDAPMessage *existing, equal = (newblob && (data_blob_cmp(&oldblob, newblob) == 0)); } else { /* all of our string attributes are case insensitive */ - equal = (newval && (StrCaseCmp(oldval, newval) == 0)); + equal = (newval && (strcasecmp_m(oldval, newval) == 0)); } if (equal) { @@ -778,7 +554,7 @@ static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state) start TLS on an existing LDAP connection *******************************************************************/ -int smb_ldap_start_tls(LDAP *ldap_struct, int version) +int smbldap_start_tls(LDAP *ldap_struct, int version) { #ifdef LDAP_OPT_X_TLS int rc; @@ -949,7 +725,7 @@ static int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version) open a connection to the ldap server (just until the bind) ******************************************************************/ -int smb_ldap_setup_full_conn(LDAP **ldap_struct, const char *uri) +int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri) { int rc, version; @@ -963,7 +739,7 @@ int smb_ldap_setup_full_conn(LDAP **ldap_struct, const char *uri) return rc; } - rc = smb_ldap_start_tls(*ldap_struct, version); + rc = smbldap_start_tls(*ldap_struct, version); if (rc) { return rc; } @@ -1000,7 +776,7 @@ static int smbldap_open_connection (struct smbldap_state *ldap_state) /* Start TLS if required */ - rc = smb_ldap_start_tls(*ldap_struct, version); + rc = smbldap_start_tls(*ldap_struct, version); if (rc) { return rc; } @@ -1094,7 +870,7 @@ static int rebindproc_connect_with_state (LDAP *ldap_struct, * our credentials. At least *try* to secure the connection - Guenther */ smb_ldap_upgrade_conn(ldap_struct, &version); - smb_ldap_start_tls(ldap_struct, version); + smbldap_start_tls(ldap_struct, version); /** @TODO Should we be doing something to check what servers we rebind to? Could we get a referral to a machine that we don't want to give our @@ -1171,22 +947,6 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state) int rc; int version; - if (!ldap_state->anonymous && !ldap_state->bind_dn) { - char *bind_dn = NULL; - char *bind_secret = NULL; - - /* get the default dn and password only if they are not set already */ - if (!fetch_ldap_pw(&bind_dn, &bind_secret)) { - DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n")); - rc = LDAP_INVALID_CREDENTIALS; - goto done; - } - smbldap_set_creds(ldap_state, false, bind_dn, bind_secret); - SAFE_FREE(bind_dn); - memset(bind_secret, '\0', strlen(bind_secret)); - SAFE_FREE(bind_secret); - } - /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite (OpenLDAP) doesnt' seem to support it */ @@ -1211,7 +971,20 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state) #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ #endif - rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret); + /* When there is an alternative bind callback is set, + attempt to use it to perform the bind */ + if (ldap_state->bind_callback != NULL) { + /* We have to allow bind callback to be run under become_root/unbecome_root + to make sure within smbd the callback has proper write access to its resources, + like credential cache. This is similar to passdb case where this callback is supposed + to be used. When used outside smbd, become_root()/unbecome_root() are no-op. + */ + become_root(); + rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data); + unbecome_root(); + } else { + rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret); + } if (rc != LDAP_SUCCESS) { char *ld_error = NULL; @@ -1248,7 +1021,7 @@ done: return rc; } -static void smbldap_idle_fn(struct event_context *event_ctx, +static void smbldap_idle_fn(struct tevent_context *tevent_ctx, struct timed_event *te, struct timeval now_abs, void *private_data); @@ -1305,13 +1078,13 @@ static int smbldap_open(struct smbldap_state *ldap_state) ldap_state->last_ping = time_mono(NULL); - ldap_state->pid = sys_getpid(); + ldap_state->pid = getpid(); TALLOC_FREE(ldap_state->idle_event); - if (ldap_state->event_context != NULL) { - ldap_state->idle_event = event_add_timed( - ldap_state->event_context, ldap_state, + if (ldap_state->tevent_context != NULL) { + ldap_state->idle_event = tevent_add_timer( + ldap_state->tevent_context, ldap_state, timeval_current_ofs(SMBLDAP_IDLE_TIME, 0), smbldap_idle_fn, ldap_state); } @@ -1344,77 +1117,113 @@ static NTSTATUS smbldap_close(struct smbldap_state *ldap_state) return NT_STATUS_OK; } -static bool got_alarm; - -static void (*old_handler)(int); +static SIG_ATOMIC_T got_alarm; static void gotalarm_sig(int dummy) { - got_alarm = True; + got_alarm = 1; +} + +static time_t calc_ldap_abs_endtime(int ldap_to) +{ + if (ldap_to == 0) { + /* No timeout - don't + return a value for + the alarm. */ + return (time_t)0; + } + + /* Make the alarm time one second beyond + the timout we're setting for the + remote search timeout, to allow that + to fire in preference. */ + + return time_mono(NULL)+ldap_to+1; +} + +static int end_ldap_local_alarm(time_t absolute_endtime, int rc) +{ + if (absolute_endtime) { + alarm(0); + CatchSignal(SIGALRM, SIG_IGN); + if (got_alarm) { + /* Client timeout error code. */ + got_alarm = 0; + return LDAP_TIMEOUT; + } + } + return rc; } -static int another_ldap_try(struct smbldap_state *ldap_state, int *rc, - int *attempts, time_t endtime) +static void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t absolute_endtime) { time_t now = time_mono(NULL); - int open_rc = LDAP_SERVER_DOWN; - if (*rc != LDAP_SERVER_DOWN) - goto no_next; + if (absolute_endtime) { + got_alarm = 0; + CatchSignal(SIGALRM, gotalarm_sig); + alarm(absolute_endtime - now); + } - if (now >= endtime) { + if (ldap_state->pid != getpid()) { smbldap_close(ldap_state); - *rc = LDAP_TIMEOUT; - goto no_next; } +} - if (*attempts == 0) { - got_alarm = False; - old_handler = CatchSignal(SIGALRM, gotalarm_sig); - alarm(endtime - now); +static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno) +{ + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_NUMBER, p_ld_errno); - if (ldap_state->pid != sys_getpid()) - smbldap_close(ldap_state); - } + ldap_get_option(ldap_state->ldap_struct, + LDAP_OPT_ERROR_STRING, pp_ld_error); +} + +static int get_cached_ldap_connect(struct smbldap_state *ldap_state, time_t abs_endtime) +{ + int attempts = 0; while (1) { + int rc; + time_t now; - if (*attempts != 0) - smb_msleep(1000); + now = time_mono(NULL); + ldap_state->last_use = now; - *attempts += 1; + if (abs_endtime && now > abs_endtime) { + smbldap_close(ldap_state); + return LDAP_TIMEOUT; + } - open_rc = smbldap_open(ldap_state); + rc = smbldap_open(ldap_state); - if (open_rc == LDAP_SUCCESS) { - ldap_state->last_use = now; - return True; + if (rc == LDAP_SUCCESS) { + return LDAP_SUCCESS; } - if (open_rc == LDAP_INSUFFICIENT_ACCESS) { + attempts++; + DEBUG(1, ("Connection to LDAP server failed for the " + "%d try!\n", attempts)); + + if (rc == LDAP_INSUFFICIENT_ACCESS) { /* The fact that we are non-root or any other * access-denied condition will not change in the next * round of trying */ - *rc = open_rc; - break; + return rc; } if (got_alarm) { - *rc = LDAP_TIMEOUT; - break; + smbldap_close(ldap_state); + return LDAP_TIMEOUT; } - if (open_rc != LDAP_SUCCESS) { - DEBUG(1, ("Connection to LDAP server failed for the " - "%d try!\n", *attempts)); + smb_msleep(1000); + + if (got_alarm) { + smbldap_close(ldap_state); + return LDAP_TIMEOUT; } } - - no_next: - CatchSignal(SIGALRM, old_handler); - alarm(0); - ldap_state->last_use = now; - return False; } /********************************************************************* @@ -1427,10 +1236,11 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state, int sizelimit, LDAPMessage **res) { int rc = LDAP_SERVER_DOWN; - int attempts = 0; char *utf8_filter; - time_t endtime = time_mono(NULL)+lp_ldap_timeout(); + int to = lp_ldap_timeout(); + time_t abs_endtime = calc_ldap_abs_endtime(to); struct timeval timeout; + struct timeval *timeout_ptr = NULL; size_t converted_size; SMB_ASSERT(ldap_state); @@ -1467,60 +1277,50 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state, return LDAP_NO_MEMORY; } - /* Setup timeout for the ldap_search_ext_s call - local and remote. */ - timeout.tv_sec = lp_ldap_timeout(); - timeout.tv_usec = 0; + /* Setup remote timeout for the ldap_search_ext_s call. */ + if (to) { + timeout.tv_sec = to; + timeout.tv_usec = 0; + timeout_ptr = &timeout; + } - /* Setup alarm timeout.... Do we need both of these ? JRA. - * Yes, I think we do need both of these. The server timeout only - * covers the case where the server's operation takes too long. It - * does not cover the case where the request hangs on its way to the - * server. The server side timeout is not strictly necessary, it's - * just a bit more kind to the server. VL. */ + setup_ldap_local_alarm(ldap_state, abs_endtime); - got_alarm = 0; - CatchSignal(SIGALRM, gotalarm_sig); - alarm(lp_ldap_timeout()); - /* End setup timeout. */ + while (1) { + char *ld_error = NULL; + int ld_errno; + + rc = get_cached_ldap_connect(ldap_state, abs_endtime); + if (rc != LDAP_SUCCESS) { + break; + } - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { rc = ldap_search_ext_s(ldap_state->ldap_struct, base, scope, utf8_filter, - CONST_DISCARD(char **, attrs), - attrsonly, sctrls, cctrls, &timeout, + discard_const_p(char *, attrs), + attrsonly, sctrls, cctrls, timeout_ptr, sizelimit, res); - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - int ld_errno; - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_NUMBER, &ld_errno); - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(10, ("Failed search for base: %s, error: %d (%s) " - "(%s)\n", base, ld_errno, - ldap_err2string(rc), - ld_error ? ld_error : "unknown")); - SAFE_FREE(ld_error); - - if (ld_errno == LDAP_SERVER_DOWN) { - ldap_unbind(ldap_state->ldap_struct); - ldap_state->ldap_struct = NULL; - } + if (rc == LDAP_SUCCESS) { + break; } - } - TALLOC_FREE(utf8_filter); + get_ldap_errs(ldap_state, &ld_error, &ld_errno); - /* Teardown timeout. */ - CatchSignal(SIGALRM, SIG_IGN); - alarm(0); + DEBUG(10, ("Failed search for base: %s, error: %d (%s) " + "(%s)\n", base, ld_errno, + ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); - if (got_alarm != 0) - return LDAP_TIMELIMIT_EXCEEDED; + if (ld_errno != LDAP_SERVER_DOWN) { + break; + } + ldap_unbind(ldap_state->ldap_struct); + ldap_state->ldap_struct = NULL; + } - return rc; + TALLOC_FREE(utf8_filter); + return end_ldap_local_alarm(abs_endtime, rc); } int smbldap_search(struct smbldap_state *ldap_state, @@ -1568,7 +1368,7 @@ int smbldap_search_paged(struct smbldap_state *ldap_state, } ber_flatten(cookie_be, &cookie_bv); - pr.ldctl_oid = CONST_DISCARD(char *, ADS_PAGE_CTL_OID); + pr.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID); pr.ldctl_iscritical = (char) critical; pr.ldctl_value.bv_len = cookie_bv->bv_len; pr.ldctl_value.bv_val = cookie_bv->bv_val; @@ -1626,9 +1426,8 @@ done: int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[]) { int rc = LDAP_SERVER_DOWN; - int attempts = 0; char *utf8_dn; - time_t endtime = time_mono(NULL)+lp_ldap_timeout(); + time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout()); size_t converted_size; SMB_ASSERT(ldap_state); @@ -1639,40 +1438,46 @@ int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *at return LDAP_NO_MEMORY; } - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { - rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs); + setup_ldap_local_alarm(ldap_state, abs_endtime); + + while (1) { + char *ld_error = NULL; + int ld_errno; + + rc = get_cached_ldap_connect(ldap_state, abs_endtime); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - int ld_errno; - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_NUMBER, &ld_errno); - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) " - "(%s)\n", dn, ld_errno, - ldap_err2string(rc), - ld_error ? ld_error : "unknown")); - SAFE_FREE(ld_error); - - if (ld_errno == LDAP_SERVER_DOWN) { - ldap_unbind(ldap_state->ldap_struct); - ldap_state->ldap_struct = NULL; - } + break; } + + rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs); + if (rc == LDAP_SUCCESS) { + break; + } + + get_ldap_errs(ldap_state, &ld_error, &ld_errno); + + DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) " + "(%s)\n", dn, ld_errno, + ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + + if (ld_errno != LDAP_SERVER_DOWN) { + break; + } + ldap_unbind(ldap_state->ldap_struct); + ldap_state->ldap_struct = NULL; } TALLOC_FREE(utf8_dn); - return rc; + return end_ldap_local_alarm(abs_endtime, 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; - time_t endtime = time_mono(NULL)+lp_ldap_timeout(); + time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout()); size_t converted_size; SMB_ASSERT(ldap_state); @@ -1683,40 +1488,46 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs return LDAP_NO_MEMORY; } - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { - rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs); + setup_ldap_local_alarm(ldap_state, abs_endtime); + + while (1) { + char *ld_error = NULL; + int ld_errno; + + rc = get_cached_ldap_connect(ldap_state, abs_endtime); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - int ld_errno; - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_NUMBER, &ld_errno); - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(10, ("Failed to add dn: %s, error: %d (%s) " - "(%s)\n", dn, ld_errno, - ldap_err2string(rc), - ld_error ? ld_error : "unknown")); - SAFE_FREE(ld_error); - - if (ld_errno == LDAP_SERVER_DOWN) { - ldap_unbind(ldap_state->ldap_struct); - ldap_state->ldap_struct = NULL; - } + break; + } + + rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs); + if (rc == LDAP_SUCCESS) { + break; + } + + get_ldap_errs(ldap_state, &ld_error, &ld_errno); + + DEBUG(10, ("Failed to add dn: %s, error: %d (%s) " + "(%s)\n", dn, ld_errno, + ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + + if (ld_errno != LDAP_SERVER_DOWN) { + break; } + ldap_unbind(ldap_state->ldap_struct); + ldap_state->ldap_struct = NULL; } TALLOC_FREE(utf8_dn); - return rc; + return end_ldap_local_alarm(abs_endtime, rc); } int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) { int rc = LDAP_SERVER_DOWN; - int attempts = 0; char *utf8_dn; - time_t endtime = time_mono(NULL)+lp_ldap_timeout(); + time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout()); size_t converted_size; SMB_ASSERT(ldap_state); @@ -1727,32 +1538,39 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) return LDAP_NO_MEMORY; } - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { - rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn); + setup_ldap_local_alarm(ldap_state, abs_endtime); + + while (1) { + char *ld_error = NULL; + int ld_errno; + + rc = get_cached_ldap_connect(ldap_state, abs_endtime); if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - int ld_errno; - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_NUMBER, &ld_errno); - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) " - "(%s)\n", dn, ld_errno, - ldap_err2string(rc), - ld_error ? ld_error : "unknown")); - SAFE_FREE(ld_error); - - if (ld_errno == LDAP_SERVER_DOWN) { - ldap_unbind(ldap_state->ldap_struct); - ldap_state->ldap_struct = NULL; - } + break; + } + + rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn); + if (rc == LDAP_SUCCESS) { + break; + } + + get_ldap_errs(ldap_state, &ld_error, &ld_errno); + + DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) " + "(%s)\n", dn, ld_errno, + ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + + if (ld_errno != LDAP_SERVER_DOWN) { + break; } + ldap_unbind(ldap_state->ldap_struct); + ldap_state->ldap_struct = NULL; } TALLOC_FREE(utf8_dn); - return rc; + return end_ldap_local_alarm(abs_endtime, rc); } int smbldap_extended_operation(struct smbldap_state *ldap_state, @@ -1761,39 +1579,45 @@ int smbldap_extended_operation(struct smbldap_state *ldap_state, char **retoidp, struct berval **retdatap) { int rc = LDAP_SERVER_DOWN; - int attempts = 0; - time_t endtime = time_mono(NULL)+lp_ldap_timeout(); + time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout()); if (!ldap_state) return (-1); - while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) { + setup_ldap_local_alarm(ldap_state, abs_endtime); + + while (1) { + char *ld_error = NULL; + int ld_errno; + + rc = get_cached_ldap_connect(ldap_state, abs_endtime); + if (rc != LDAP_SUCCESS) { + break; + } + rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata, serverctrls, clientctrls, retoidp, retdatap); - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - int ld_errno; - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_NUMBER, &ld_errno); - - ldap_get_option(ldap_state->ldap_struct, - LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(10, ("Extended operation failed with error: " - "%d (%s) (%s)\n", ld_errno, - ldap_err2string(rc), - ld_error ? ld_error : "unknown")); - SAFE_FREE(ld_error); - - if (ld_errno == LDAP_SERVER_DOWN) { - ldap_unbind(ldap_state->ldap_struct); - ldap_state->ldap_struct = NULL; - } + if (rc == LDAP_SUCCESS) { + break; } + + get_ldap_errs(ldap_state, &ld_error, &ld_errno); + + DEBUG(10, ("Extended operation failed with error: " + "%d (%s) (%s)\n", ld_errno, + ldap_err2string(rc), + ld_error ? ld_error : "unknown")); + SAFE_FREE(ld_error); + + if (ld_errno != LDAP_SERVER_DOWN) { + break; + } + ldap_unbind(ldap_state->ldap_struct); + ldap_state->ldap_struct = NULL; } - return rc; + return end_ldap_local_alarm(abs_endtime, rc); } /******************************************************************* @@ -1803,11 +1627,12 @@ int smbldap_search_suffix (struct smbldap_state *ldap_state, const char *filter, const char **search_attr, LDAPMessage ** result) { - return smbldap_search(ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE, + return smbldap_search(ldap_state, lp_ldap_suffix(talloc_tos()), + LDAP_SCOPE_SUBTREE, filter, search_attr, 0, result); } -static void smbldap_idle_fn(struct event_context *event_ctx, +static void smbldap_idle_fn(struct tevent_context *tevent_ctx, struct timed_event *te, struct timeval now_abs, void *private_data) @@ -1825,8 +1650,8 @@ static void smbldap_idle_fn(struct event_context *event_ctx, DEBUG(10,("ldap connection not idle...\n")); /* this needs to be made monotonic clock aware inside tevent: */ - state->idle_event = event_add_timed( - event_ctx, state, + state->idle_event = tevent_add_timer( + tevent_ctx, state, timeval_add(&now_abs, SMBLDAP_IDLE_TIME, 0), smbldap_idle_fn, private_data); @@ -1851,6 +1676,8 @@ void smbldap_free_struct(struct smbldap_state **ldap_state) SAFE_FREE((*ldap_state)->bind_dn); SAFE_FREE((*ldap_state)->bind_secret); + (*ldap_state)->bind_callback = NULL; + (*ldap_state)->bind_callback_data = NULL; TALLOC_FREE(*ldap_state); @@ -1868,11 +1695,14 @@ static int smbldap_state_destructor(struct smbldap_state *state) Intitalise the 'general' ldap structures, on which ldap operations may be conducted *********************************************************************/ -NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, +NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct tevent_context *tevent_ctx, const char *location, + bool anon, + const char *bind_dn, + const char *bind_secret, struct smbldap_state **smbldap_state) { - *smbldap_state = TALLOC_ZERO_P(mem_ctx, struct smbldap_state); + *smbldap_state = talloc_zero(mem_ctx, struct smbldap_state); if (!*smbldap_state) { DEBUG(0, ("talloc() failed for ldapsam private_data!\n")); return NT_STATUS_NO_MEMORY; @@ -1884,7 +1714,11 @@ NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, (*smbldap_state)->uri = "ldap://localhost"; } - (*smbldap_state)->event_context = event_ctx; + (*smbldap_state)->tevent_context = tevent_ctx; + + if (bind_dn && bind_secret) { + smbldap_set_creds(*smbldap_state, anon, bind_dn, bind_secret); + } talloc_set_destructor(*smbldap_state, smbldap_state_destructor); return NT_STATUS_OK; @@ -1935,7 +1769,7 @@ static bool smbldap_check_root_dse(LDAP *ld, const char **attrs, const char *val } rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE, - "(objectclass=*)", CONST_DISCARD(char **, attrs), 0 , &msg); + "(objectclass=*)", discard_const_p(char *, attrs), 0 , &msg); if (rc != LDAP_SUCCESS) { DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n")); @@ -2023,6 +1857,9 @@ bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char * /* free any previously set credential */ SAFE_FREE(ldap_state->bind_dn); + ldap_state->bind_callback = NULL; + ldap_state->bind_callback_data = NULL; + if (ldap_state->bind_secret) { /* make sure secrets are zeroed out of memory */ memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret)); |