Copyright (C) Shahms King 2001
Copyright (C) Andrew Bartlett 2002-2003
Copyright (C) Stefan (metze) Metzmacher 2002-2003
-
+
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
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-
+
*/
#include "includes.h"
#include "smbldap.h"
-
-#ifndef LDAP_OPT_SUCCESS
-#define LDAP_OPT_SUCCESS 0
-#endif
+#include "../libcli/security/security.h"
+#include <tevent.h>
+#include "lib/param/loadparm.h"
/* Try not to hit the up or down server forever */
#define SMBLDAP_IDLE_TIME 150 /* After 2.5 minutes disconnect */
+struct smbldap_state {
+ LDAP *ldap_struct;
+ pid_t pid;
+ time_t last_ping; /* monotonic */
+ /* retrieve-once info */
+ const char *uri;
-/* 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 }
-};
+ /* credentials */
+ bool anonymous;
+ char *bind_dn;
+ char *bind_secret;
+ smbldap_bind_callback_fn bind_callback;
+ void *bind_callback_data;
-/* 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 }
-};
+ bool paged_results;
-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 }
-};
+ unsigned int num_failures;
-/* 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 },
-};
+ time_t last_use; /* monotonic */
+ struct tevent_context *tevent_context;
+ struct tevent_timer *idle_event;
-/* 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 }
+ struct timeval last_rebind; /* monotonic */
};
-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 )
+LDAP *smbldap_get_ldap(struct smbldap_state *state)
{
- int i = 0;
-
- while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
- if ( table[i].attrib == key )
- return table[i].name;
- i++;
- }
-
- return NULL;
+ return state->ldap_struct;
}
-
-/**********************************************************************
- Return the list of attribute names from a mapping table
- **********************************************************************/
-
- const char** get_attr_list( TALLOC_CTX *mem_ctx, ATTRIB_MAP_ENTRY table[] )
+bool smbldap_get_paged_results(struct smbldap_state *state)
{
- 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;
- }
+ return state->paged_results;
+}
- i = 0;
- while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
- names[i] = talloc_strdup( names, table[i].name );
- i++;
- }
- names[i] = NULL;
-
- return names;
+void smbldap_set_paged_results(struct smbldap_state *state,
+ bool paged_results)
+{
+ state->paged_results = paged_results;
}
+void smbldap_set_bind_callback(struct smbldap_state *state,
+ smbldap_bind_callback_fn callback,
+ void *callback_data)
+{
+ state->bind_callback = callback;
+ state->bind_callback_data = callback_data;
+}
/*******************************************************************
Search an attribute and return the first value found.
******************************************************************/
int max_len)
{
char **values;
-
+ size_t size = 0;
+
if ( !attribute )
return False;
-
+
value[0] = '\0';
if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
-
+
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);
return False;
}
-
+
ldap_value_free(values);
#ifdef DEBUG_PASSWORDS
DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
return result;
}
+ char * smbldap_talloc_first_attribute(LDAP *ldap_struct, LDAPMessage *entry,
+ const char *attribute,
+ TALLOC_CTX *mem_ctx)
+{
+ char **values;
+ char *result;
+ size_t converted_size;
+
+ if (attribute == NULL) {
+ return NULL;
+ }
+
+ values = ldap_get_values(ldap_struct, entry, attribute);
+
+ if (values == NULL) {
+ DEBUG(10, ("attribute %s does not exist\n", attribute));
+ return NULL;
+ }
+
+ if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
+ DEBUG(10, ("pull_utf8_talloc failed\n"));
+ ldap_value_free(values);
+ return NULL;
+ }
+
+ ldap_value_free(values);
+
+#ifdef DEBUG_PASSWORDS
+ DEBUG (100, ("smbldap_get_first_attribute: [%s] = [%s]\n",
+ attribute, result));
+#endif
+ return result;
+}
+
+ char * smbldap_talloc_smallest_attribute(LDAP *ldap_struct, LDAPMessage *entry,
+ const char *attribute,
+ TALLOC_CTX *mem_ctx)
+{
+ char **values;
+ char *result;
+ size_t converted_size;
+ int i, num_values;
+
+ if (attribute == NULL) {
+ return NULL;
+ }
+
+ values = ldap_get_values(ldap_struct, entry, attribute);
+
+ if (values == NULL) {
+ DEBUG(10, ("attribute %s does not exist\n", attribute));
+ return NULL;
+ }
+
+ if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
+ DEBUG(10, ("pull_utf8_talloc failed\n"));
+ ldap_value_free(values);
+ return NULL;
+ }
+
+ num_values = ldap_count_values(values);
+
+ for (i=1; i<num_values; i++) {
+ char *tmp;
+
+ if (!pull_utf8_talloc(mem_ctx, &tmp, values[i],
+ &converted_size)) {
+ DEBUG(10, ("pull_utf8_talloc failed\n"));
+ TALLOC_FREE(result);
+ ldap_value_free(values);
+ return NULL;
+ }
+
+ if (strcasecmp_m(tmp, result) < 0) {
+ TALLOC_FREE(result);
+ result = tmp;
+ } else {
+ TALLOC_FREE(tmp);
+ }
+ }
+
+ ldap_value_free(values);
+
+#ifdef DEBUG_PASSWORDS
+ DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
+ attribute, result));
+#endif
+ return result;
+}
+
+ bool smbldap_talloc_single_blob(TALLOC_CTX *mem_ctx, LDAP *ld,
+ LDAPMessage *msg, const char *attrib,
+ DATA_BLOB *blob)
+{
+ struct berval **values;
+
+ values = ldap_get_values_len(ld, msg, attrib);
+ if (!values) {
+ return false;
+ }
+
+ if (ldap_count_values_len(values) != 1) {
+ DEBUG(10, ("Expected one value for %s, got %d\n", attrib,
+ ldap_count_values_len(values)));
+ return false;
+ }
+
+ *blob = data_blob_talloc(mem_ctx, values[0]->bv_val,
+ values[0]->bv_len);
+ ldap_value_free_len(values);
+
+ return (blob->data != NULL);
+}
+
+ bool smbldap_pull_sid(LDAP *ld, LDAPMessage *msg, const char *attrib,
+ struct dom_sid *sid)
+{
+ DATA_BLOB blob;
+ struct sid_parse_ret ret;
+
+ if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib,
+ &blob)) {
+ return false;
+ }
+ ret = sid_parse(blob.data, blob.length, sid);
+ TALLOC_FREE(blob.data);
+ return (ret.len != -1);
+}
+
static int ldapmsg_destructor(LDAPMessage **result) {
ldap_msgfree(*result);
return 0;
}
- void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
+ void smbldap_talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
{
LDAPMessage **handle;
return;
}
- handle = TALLOC_P(mem_ctx, LDAPMessage *);
+ handle = talloc(mem_ctx, LDAPMessage *);
SMB_ASSERT(handle != NULL);
*handle = result;
return 0;
}
- void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
+ void smbldap_talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
{
LDAPMod ***handle;
return;
}
- handle = TALLOC_P(mem_ctx, LDAPMod **);
+ handle = talloc(mem_ctx, LDAPMod **);
SMB_ASSERT(handle != NULL);
*handle = mod;
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)
+static void smbldap_set_mod_internal(LDAPMod *** modlist, int modop, const char *attribute, const char *value, const DATA_BLOB *blob)
{
LDAPMod **mods;
int i;
return;
}
-#if 0 /* commented out after discussion with abartlet. Do not reenable.
+#if 0 /* commented out after discussion with abartlet. Do not re-enable.
left here so other do not re-add similar code --jerry */
if (value == NULL || *value == '\0')
return;
mods[i + 1] = NULL;
}
- if (value != NULL) {
+ if (blob && (modop & LDAP_MOD_BVALUES)) {
+ j = 0;
+ if (mods[i]->mod_bvalues != NULL) {
+ for (; mods[i]->mod_bvalues[j] != NULL; j++);
+ }
+ mods[i]->mod_bvalues = SMB_REALLOC_ARRAY(mods[i]->mod_bvalues, struct berval *, j + 2);
+
+ if (mods[i]->mod_bvalues == NULL) {
+ smb_panic("smbldap_set_mod: out of memory!");
+ /* notreached. */
+ }
+
+ mods[i]->mod_bvalues[j] = SMB_MALLOC_P(struct berval);
+ SMB_ASSERT(mods[i]->mod_bvalues[j] != NULL);
+
+ mods[i]->mod_bvalues[j]->bv_val = (char *)smb_memdup(blob->data, blob->length);
+ SMB_ASSERT(mods[i]->mod_bvalues[j]->bv_val != NULL);
+ mods[i]->mod_bvalues[j]->bv_len = blob->length;
+
+ mods[i]->mod_bvalues[j + 1] = NULL;
+ } else if (value != NULL) {
char *utf8_value = NULL;
size_t converted_size;
for (; mods[i]->mod_values[j] != NULL; j++);
}
mods[i]->mod_values = SMB_REALLOC_ARRAY(mods[i]->mod_values, char *, j + 2);
-
+
if (mods[i]->mod_values == NULL) {
smb_panic("smbldap_set_mod: out of memory!");
/* notreached. */
}
- if (!push_utf8_allocate(&utf8_value, value, &converted_size)) {
+ if (!push_utf8_talloc(talloc_tos(), &utf8_value, value, &converted_size)) {
smb_panic("smbldap_set_mod: String conversion failure!");
/* notreached. */
}
- mods[i]->mod_values[j] = utf8_value;
+ mods[i]->mod_values[j] = SMB_STRDUP(utf8_value);
+ TALLOC_FREE(utf8_value);
+ SMB_ASSERT(mods[i]->mod_values[j] != NULL);
mods[i]->mod_values[j + 1] = NULL;
}
*modlist = mods;
}
+ void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
+{
+ smbldap_set_mod_internal(modlist, modop, attribute, value, NULL);
+}
+
+ void smbldap_set_mod_blob(LDAPMod *** modlist, int modop, const char *attribute, const DATA_BLOB *value)
+{
+ smbldap_set_mod_internal(modlist, modop | LDAP_MOD_BVALUES, attribute, NULL, value);
+}
+
/**********************************************************************
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)
+static void smbldap_make_mod_internal(LDAP *ldap_struct, LDAPMessage *existing,
+ LDAPMod ***mods,
+ const char *attribute, int op,
+ const char *newval,
+ const DATA_BLOB *newblob)
{
char oldval[2048]; /* current largest allowed value is mungeddial */
bool existed;
-
- if (attribute == NULL) {
- /* This can actually happen for ldapsam_compat where we for
- * example don't have a password history */
- return;
- }
+ DATA_BLOB oldblob = data_blob_null;
if (existing != NULL) {
- existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
+ if (op & LDAP_MOD_BVALUES) {
+ existed = smbldap_talloc_single_blob(talloc_tos(), ldap_struct, existing, attribute, &oldblob);
+ } else {
+ existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
+ }
} else {
existed = False;
*oldval = '\0';
}
- /* all of our string attributes are case insensitive */
-
- if (existed && newval && (StrCaseCmp(oldval, 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... */
- DEBUG(10,("smbldap_make_mod: attribute |%s| not changed.\n", attribute));
- return;
- }
-
if (existed) {
+ bool equal = false;
+ if (op & LDAP_MOD_BVALUES) {
+ equal = (newblob && (data_blob_cmp(&oldblob, newblob) == 0));
+ } else {
+ /* all of our string attributes are case insensitive */
+ equal = (newval && (strcasecmp_m(oldval, newval) == 0));
+ }
+
+ if (equal) {
+ /* Believe it or not, but LDAP will deny a delete and
+ an add at the same time if the values are the
+ same... */
+ DEBUG(10,("smbldap_make_mod: attribute |%s| not changed.\n", attribute));
+ return;
+ }
+
/* There has been no value before, so don't delete it.
* Here's a possible race: We might end up with
* duplicate attributes */
/* This will also allow modifying single valued attributes
* in Novell NDS. In NDS you have to first remove attribute and then
* you could add new value */
-
- DEBUG(10,("smbldap_make_mod: deleting attribute |%s| values |%s|\n", attribute, oldval));
- smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval);
+
+ if (op & LDAP_MOD_BVALUES) {
+ DEBUG(10,("smbldap_make_mod: deleting attribute |%s| blob\n", attribute));
+ smbldap_set_mod_blob(mods, LDAP_MOD_DELETE, attribute, &oldblob);
+ } else {
+ DEBUG(10,("smbldap_make_mod: deleting attribute |%s| values |%s|\n", attribute, oldval));
+ smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval);
+ }
}
/* 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)) {
- DEBUG(10,("smbldap_make_mod: adding attribute |%s| value |%s|\n", attribute, newval));
- smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
+ if (op & LDAP_MOD_BVALUES) {
+ if (newblob && newblob->length) {
+ DEBUG(10,("smbldap_make_mod: adding attribute |%s| blob\n", attribute));
+ smbldap_set_mod_blob(mods, LDAP_MOD_ADD, attribute, newblob);
+ }
+ } else {
+ if ((newval != NULL) && (strlen(newval) > 0)) {
+ DEBUG(10,("smbldap_make_mod: adding attribute |%s| value |%s|\n", attribute, newval));
+ smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
+ }
}
}
+ void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
+ LDAPMod ***mods,
+ const char *attribute, const char *newval)
+{
+ smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
+ 0, newval, NULL);
+}
+
+ void smbldap_make_mod_blob(LDAP *ldap_struct, LDAPMessage *existing,
+ LDAPMod ***mods,
+ const char *attribute, const DATA_BLOB *newblob)
+{
+ smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
+ LDAP_MOD_BVALUES, NULL, newblob);
+}
+
/**********************************************************************
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
{
struct smbldap_state *tmp_ldap_state;
struct smbldap_state_lookup *t;
-
+
if ((tmp_ldap_state = smbldap_find_state(ld))) {
SMB_ASSERT(tmp_ldap_state == smbldap_state);
return;
t = SMB_XMALLOC_P(struct smbldap_state_lookup);
ZERO_STRUCTP(t);
-
- DLIST_ADD_END(smbldap_state_lookup_list, t, struct smbldap_state_lookup *);
+
+ DLIST_ADD_END(smbldap_state_lookup_list, t);
t->ld = ld;
t->smbldap_state = smbldap_state;
}
start TLS on an existing LDAP connection
*******************************************************************/
-int smb_ldap_start_tls(LDAP *ldap_struct, int version)
+int smbldap_start_tls(LDAP *ldap_struct, int version)
{
#ifdef LDAP_OPT_X_TLS
- int rc;
+ int rc,tls;
#endif
-
+
if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
return LDAP_SUCCESS;
}
-
+
#ifdef LDAP_OPT_X_TLS
+ /* check if we use ldaps already */
+ ldap_get_option(ldap_struct, LDAP_OPT_X_TLS, &tls);
+ if (tls == LDAP_OPT_X_TLS_HARD) {
+ return LDAP_SUCCESS;
+ }
+
if (version != LDAP_VERSION3) {
DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
return LDAP_OPERATIONS_ERROR;
setup a connection to the LDAP server based on a uri
*******************************************************************/
-int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri)
+static int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri)
{
int rc;
DEBUG(10, ("smb_ldap_setup_connection: %s\n", uri));
-
+
#ifdef HAVE_LDAP_INITIALIZE
-
+
rc = ldap_initialize(ldap_struct, uri);
if (rc) {
DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
+ return rc;
}
- return rc;
+ if (lp_ldap_follow_referral() != Auto) {
+ rc = ldap_set_option(*ldap_struct, LDAP_OPT_REFERRALS,
+ lp_ldap_follow_referral() ? LDAP_OPT_ON : LDAP_OPT_OFF);
+ if (rc != LDAP_SUCCESS)
+ DEBUG(0, ("Failed to set LDAP_OPT_REFERRALS: %s\n",
+ ldap_err2string(rc)));
+ }
+
+ return LDAP_SUCCESS;
#else
/* Parse the string manually */
if ( strnequal( uri, "URL:", 4 ) ) {
uri += 4;
}
-
+
sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
-
+
if (port == 0) {
if (strequal(protocol, "ldap")) {
port = LDAP_PORT;
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;
{
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"));
}
#endif /* HAVE_LDAP_INITIALIZE */
-
/* now set connection timeout */
#ifdef LDAP_X_OPT_CONNECT_TIMEOUT /* Netscape */
{
version
*******************************************************************/
-int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
+static int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
{
int version;
int rc;
-
+
/* assume the worst */
*new_version = LDAP_VERSION2;
if (rc) {
return rc;
}
-
+
*new_version = LDAP_VERSION3;
return LDAP_SUCCESS;
}
open a connection to the ldap server (just until the bind)
******************************************************************/
-int smb_ldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
+int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
{
int rc, version;
return rc;
}
- rc = smb_ldap_start_tls(*ldap_struct, version);
+ rc = smbldap_start_tls(*ldap_struct, version);
if (rc) {
return rc;
}
{
int rc = LDAP_SUCCESS;
int version;
+ int deref;
LDAP **ldap_struct = &ldap_state->ldap_struct;
rc = smb_ldap_setup_conn(ldap_struct, ldap_state->uri);
/* Start TLS if required */
- rc = smb_ldap_start_tls(*ldap_struct, version);
+ rc = smbldap_start_tls(*ldap_struct, version);
if (rc) {
return rc;
}
-
+
+ /* Set alias dereferencing method */
+ deref = lp_ldap_deref();
+ if (deref != -1) {
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_DEREF, &deref) != LDAP_OPT_SUCCESS) {
+ DEBUG(1,("smbldap_open_connection: Failed to set dereferencing method: %d\n", deref));
+ } else {
+ DEBUG(5,("Set dereferencing method: %d\n", deref));
+ }
+ }
+
DEBUG(2, ("smbldap_open_connection: connection opened\n"));
return rc;
}
int *methodp, int freeit, void *arg)
{
struct smbldap_state *ldap_state = arg;
-
+ struct timespec ts;
+
/** @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);
if (*credp) {
*methodp = LDAP_AUTH_SIMPLE;
}
- GetTimeOfDay(&ldap_state->last_rebind);
-
+ clock_gettime_mono(&ts);
+ ldap_state->last_rebind = convert_timespec_to_timeval(ts);
+
return 0;
}
#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
struct smbldap_state *ldap_state =
(struct smbldap_state *)arg;
int rc;
+ struct timespec ts;
int version;
DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n",
* 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
DEBUG(10,("rebindproc_connect_with_state: "
"setting last_rebind timestamp "
"(req: 0x%02x)\n", (unsigned int)request));
- GetTimeOfDay(&ldap_state->last_rebind);
+ clock_gettime_mono(&ts);
+ ldap_state->last_rebind = convert_timespec_to_timeval(ts);
break;
default:
ZERO_STRUCT(ldap_state->last_rebind);
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)*/
/*******************************************************************
connect to the ldap server under system privilege.
******************************************************************/
-static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_struct)
+static int smbldap_connect_system(struct smbldap_state *ldap_state)
{
+ LDAP *ldap_struct = smbldap_get_ldap(ldap_state);
int rc;
int version;
- if (!ldap_state->anonymous && !ldap_state->bind_dn) {
-
- /* get the default dn and password only if they are not set already */
- if (!fetch_ldap_pw(&ldap_state->bind_dn, &ldap_state->bind_secret)) {
- DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
- return LDAP_INVALID_CREDENTIALS;
- }
- }
-
/* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
- (OpenLDAP) doesnt' seem to support it */
-
+ (OpenLDAP) doesn't seem to support it */
+
DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
ldap_state->uri, ldap_state->bind_dn));
#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
#endif
- rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+ /* When there is an alternative bind callback is set,
+ attempt to use it to perform the bind */
+ if (ldap_state->bind_callback != NULL) {
+ /* We have to allow bind callback to be run under become_root/unbecome_root
+ to make sure within smbd the callback has proper write access to its resources,
+ like credential cache. This is similar to passdb case where this callback is supposed
+ to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
+ */
+ become_root();
+ rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
+ unbecome_root();
+ } else {
+ rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
+ }
if (rc != LDAP_SUCCESS) {
char *ld_error = NULL;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_ERROR_STRING,
&ld_error);
DEBUG(ldap_state->num_failures ? 2 : 0,
("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
ld_error ? ld_error : "(unknown)"));
SAFE_FREE(ld_error);
ldap_state->num_failures++;
- return rc;
+ goto done;
}
ldap_state->num_failures = 0;
ldap_state->paged_results = False;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_PROTOCOL_VERSION, &version);
- if (smbldap_has_control(ldap_state->ldap_struct, ADS_PAGE_CTL_OID) && version == 3) {
+ if (smbldap_has_control(smbldap_get_ldap(ldap_state), ADS_PAGE_CTL_OID)
+ && version == 3) {
ldap_state->paged_results = True;
}
DEBUG(3, ("ldap_connect_system: successful connection to the LDAP server\n"));
DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n",
ldap_state->paged_results ? "does" : "does not"));
+done:
+ if (rc != 0) {
+ ldap_unbind(ldap_struct);
+ ldap_state->ldap_struct = NULL;
+ }
return rc;
}
-static void smbldap_idle_fn(struct event_context *event_ctx,
- struct timed_event *te,
- struct timeval now,
+static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
+ struct tevent_timer *te,
+ struct timeval now_abs,
void *private_data);
/**********************************************************************
bool reopen = False;
SMB_ASSERT(ldap_state);
- if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time(NULL))) {
+ if ((smbldap_get_ldap(ldap_state) != NULL) &&
+ ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) <
+ time_mono(NULL))) {
#ifdef HAVE_UNIXSOCKET
struct sockaddr_un addr;
#else
- struct sockaddr addr;
+ struct sockaddr_storage addr;
#endif
socklen_t len = sizeof(addr);
int sd;
- opt_rc = ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd);
+ opt_rc = ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_DESC, &sd);
if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
reopen = True;
#endif
if (reopen) {
/* the other end has died. reopen. */
- ldap_unbind(ldap_state->ldap_struct);
- ldap_state->ldap_struct = NULL;
+ ldap_unbind(smbldap_get_ldap(ldap_state));
+ ldap_state->ldap_struct = NULL;
ldap_state->last_ping = (time_t)0;
} else {
- ldap_state->last_ping = time(NULL);
+ ldap_state->last_ping = time_mono(NULL);
}
}
- if (ldap_state->ldap_struct != NULL) {
+ if (smbldap_get_ldap(ldap_state) != NULL) {
DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
return LDAP_SUCCESS;
}
return rc;
}
- if ((rc = smbldap_connect_system(ldap_state, ldap_state->ldap_struct))) {
- ldap_unbind(ldap_state->ldap_struct);
- ldap_state->ldap_struct = NULL;
+ if ((rc = smbldap_connect_system(ldap_state))) {
return rc;
}
- ldap_state->last_ping = time(NULL);
- ldap_state->pid = sys_getpid();
+ ldap_state->last_ping = time_mono(NULL);
+ 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, NULL,
+ 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);
}
{
if (!ldap_state)
return NT_STATUS_INVALID_PARAMETER;
-
- if (ldap_state->ldap_struct != NULL) {
- ldap_unbind(ldap_state->ldap_struct);
+
+ if (smbldap_get_ldap(ldap_state) != NULL) {
+ ldap_unbind(smbldap_get_ldap(ldap_state));
ldap_state->ldap_struct = NULL;
}
smbldap_delete_state(ldap_state);
-
+
+ TALLOC_FREE(ldap_state->idle_event);
+
DEBUG(5,("The connection to the LDAP server was closed\n"));
/* maybe free the results here --metze */
-
+
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 int another_ldap_try(struct smbldap_state *ldap_state, int *rc,
- int *attempts, time_t endtime)
+static time_t calc_ldap_abs_endtime(int ldap_to)
{
- time_t now = time(NULL);
- int open_rc = LDAP_SERVER_DOWN;
+ if (ldap_to == 0) {
+ /* No timeout - don't
+ return a value for
+ the alarm. */
+ return (time_t)0;
+ }
- if (*rc != LDAP_SERVER_DOWN)
- goto no_next;
+ /* Make the alarm time one second beyond
+ the timout we're setting for the
+ remote search timeout, to allow that
+ to fire in preference. */
- if (now >= endtime) {
- smbldap_close(ldap_state);
- *rc = LDAP_TIMEOUT;
- goto no_next;
+ 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 void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t absolute_endtime)
+{
+ time_t now = time_mono(NULL);
- if (*attempts == 0) {
- got_alarm = False;
- old_handler = CatchSignal(SIGALRM, gotalarm_sig);
- alarm(endtime - now);
+ if (absolute_endtime) {
+ got_alarm = 0;
+ CatchSignal(SIGALRM, gotalarm_sig);
+ alarm(absolute_endtime - now);
+ }
- if (ldap_state->pid != sys_getpid())
- smbldap_close(ldap_state);
+ if (ldap_state->pid != getpid()) {
+ smbldap_close(ldap_state);
}
+}
+
+static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
+{
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ LDAP_OPT_ERROR_NUMBER, p_ld_errno);
+
+ ldap_get_option(smbldap_get_ldap(ldap_state),
+ 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;
}
/*********************************************************************
int sizelimit, LDAPMessage **res)
{
int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
char *utf8_filter;
- time_t endtime = time(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);
-
+
DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], "
"scope => [%d]\n", base, filter, scope));
if (ldap_state->last_rebind.tv_sec > 0) {
struct timeval tval;
+ struct timespec ts;
int64_t tdiff = 0;
int sleep_time = 0;
- ZERO_STRUCT(tval);
- GetTimeOfDay(&tval);
+ clock_gettime_mono(&ts);
+ tval = convert_timespec_to_timeval(ts);
tdiff = usec_time_diff(&tval, &ldap_state->last_rebind);
tdiff /= 1000; /* Convert to milliseconds. */
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, SIGNAL_CAST 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,
+ rc = ldap_search_ext_s(smbldap_get_ldap(ldap_state),
+ 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, SIGNAL_CAST 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(smbldap_get_ldap(ldap_state));
+ 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,
}
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;
goto done;
}
- DEBUG(3,("smbldap_search_paged: search was successfull\n"));
+ DEBUG(3,("smbldap_search_paged: search was successful\n"));
- rc = ldap_parse_result(ldap_state->ldap_struct, *res, NULL, NULL,
+ rc = ldap_parse_result(smbldap_get_ldap(ldap_state), *res, NULL, NULL,
NULL, NULL, &rcontrols, 0);
if (rc != 0) {
DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
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(NULL)+lp_ldap_timeout();
+ time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
size_t converted_size;
SMB_ASSERT(ldap_state);
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(smbldap_get_ldap(ldap_state), 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(smbldap_get_ldap(ldap_state));
+ 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(NULL)+lp_ldap_timeout();
+ time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
size_t converted_size;
-
+
SMB_ASSERT(ldap_state);
DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
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(smbldap_get_ldap(ldap_state), 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(smbldap_get_ldap(ldap_state));
+ 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(NULL)+lp_ldap_timeout();
+ time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
size_t converted_size;
-
+
SMB_ASSERT(ldap_state);
DEBUG(5,("smbldap_delete: dn => [%s]\n", 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(smbldap_get_ldap(ldap_state), 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(smbldap_get_ldap(ldap_state));
+ 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,
char **retoidp, struct berval **retdatap)
{
int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- time_t endtime = time(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)) {
- rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid,
+ 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(smbldap_get_ldap(ldap_state),
+ 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(smbldap_get_ldap(ldap_state));
+ ldap_state->ldap_struct = NULL;
}
-
- return rc;
+
+ return end_ldap_local_alarm(abs_endtime, rc);
}
/*******************************************************************
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,
- struct timed_event *te,
- struct timeval now,
+static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
+ struct tevent_timer *te,
+ struct timeval now_abs,
void *private_data)
{
struct smbldap_state *state = (struct smbldap_state *)private_data;
TALLOC_FREE(state->idle_event);
- if (state->ldap_struct == NULL) {
+ if (smbldap_get_ldap(state) == NULL) {
DEBUG(10,("ldap connection not connected...\n"));
return;
}
-
- if ((state->last_use+SMBLDAP_IDLE_TIME) > now.tv_sec) {
+
+ if ((state->last_use+SMBLDAP_IDLE_TIME) > time_mono(NULL)) {
DEBUG(10,("ldap connection not idle...\n"));
- state->idle_event = event_add_timed(
- event_ctx, NULL,
- timeval_add(&now, SMBLDAP_IDLE_TIME, 0),
+ /* this needs to be made monotonic clock aware inside tevent: */
+ state->idle_event = tevent_add_timer(
+ tevent_ctx, state,
+ timeval_add(&now_abs, SMBLDAP_IDLE_TIME, 0),
smbldap_idle_fn,
private_data);
return;
}
-
+
DEBUG(7,("ldap connection idle...closing connection\n"));
smbldap_close(state);
}
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);
+ smbldap_set_bind_callback(*ldap_state, NULL, NULL);
- TALLOC_FREE((*ldap_state)->idle_event);
-
- *ldap_state = NULL;
+ TALLOC_FREE(*ldap_state);
/* No need to free any further, as it is talloc()ed */
}
+static int smbldap_state_destructor(struct smbldap_state *state)
+{
+ smbldap_free_struct(&state);
+ return 0;
+}
+
/**********************************************************************
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;
(*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;
}
}
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"));
/* free any previously set credential */
SAFE_FREE(ldap_state->bind_dn);
+ smbldap_set_bind_callback(ldap_state, NULL, NULL);
+
if (ldap_state->bind_secret) {
/* make sure secrets are zeroed out of memory */
memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));