lib: Make sid_parse return the parsed length
[samba.git] / source3 / lib / smbldap.c
index b333f3063d0a73c8c86afeb7cc862c56fecdaf11..cdd350fffa1e23051594b7efbedc197456472085 100644 (file)
@@ -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 */
 
 
 #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                    }
-};
-
-/* 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                    },
-};
+       unsigned int num_failures;
 
-/* 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                    }       
-};
+       time_t last_use; /* monotonic */
+       struct tevent_context *tevent_context;
+       struct tevent_timer *idle_event;
 
-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                    }       
+       struct timeval last_rebind; /* monotonic */
 };
 
-/**********************************************************************
- 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;
-       }
-
-       i = 0;
-       while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
-               names[i] = talloc_strdup( names, table[i].name );
-               i++;
-       }
-       names[i] = NULL;
+       return state->paged_results;
+}
 
-       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.
 ******************************************************************/
@@ -450,15 +278,15 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = {
                       struct dom_sid *sid)
 {
        DATA_BLOB blob;
-       bool ret;
+       struct sid_parse_ret ret;
 
        if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib,
                                        &blob)) {
                return false;
        }
-       ret = sid_parse((char *)blob.data, blob.length, sid);
+       ret = sid_parse(blob.data, blob.length, sid);
        TALLOC_FREE(blob.data);
-       return ret;
+       return (ret.len != -1);
 }
 
  static int ldapmsg_destructor(LDAPMessage **result) {
@@ -466,7 +294,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;
 
@@ -486,7 +314,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;
 
@@ -520,7 +348,7 @@ static void smbldap_set_mod_internal(LDAPMod *** modlist, int modop, const char
                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;
@@ -572,7 +400,7 @@ static void smbldap_set_mod_internal(LDAPMod *** modlist, int modop, const char
                mods[i]->mod_bvalues[j] = SMB_MALLOC_P(struct berval);
                SMB_ASSERT(mods[i]->mod_bvalues[j] != NULL);
 
-               mods[i]->mod_bvalues[j]->bv_val = (char *)memdup(blob->data, blob->length);
+               mods[i]->mod_bvalues[j]->bv_val = (char *)smb_memdup(blob->data, blob->length);
                SMB_ASSERT(mods[i]->mod_bvalues[j]->bv_val != NULL);
                mods[i]->mod_bvalues[j]->bv_len = blob->length;
 
@@ -631,12 +459,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);
@@ -770,7 +592,7 @@ static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
        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;
 }
@@ -779,10 +601,10 @@ 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;
+       int rc,tls;
 #endif
 
        if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
@@ -790,6 +612,12 @@ int smb_ldap_start_tls(LDAP *ldap_struct, int version)
        }
 
 #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;
@@ -950,7 +778,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;
 
@@ -964,7 +792,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;
        }
@@ -1001,7 +829,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;
        }
@@ -1095,7 +923,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
@@ -1168,28 +996,12 @@ static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
 ******************************************************************/
 static int smbldap_connect_system(struct smbldap_state *ldap_state)
 {
-       LDAP *ldap_struct = ldap_state->ldap_struct;
+       LDAP *ldap_struct = smbldap_get_ldap(ldap_state);
        int rc;
        int version;
 
-       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 */
+          (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));
@@ -1212,11 +1024,25 @@ 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;
-               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",
@@ -1232,9 +1058,11 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state)
        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;
        }
 
@@ -1249,8 +1077,8 @@ done:
        return rc;
 }
 
-static void smbldap_idle_fn(struct event_context *event_ctx,
-                           struct timed_event *te,
+static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
+                           struct tevent_timer *te,
                            struct timeval now_abs,
                            void *private_data);
 
@@ -1263,17 +1091,20 @@ static int smbldap_open(struct smbldap_state *ldap_state)
        bool reopen = False;
        SMB_ASSERT(ldap_state);
 
-       if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time_mono(NULL))) {
+       if ((smbldap_get_ldap(ldap_state) != NULL) &&
+           ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) <
+            time_mono(NULL))) {
 
 #ifdef HAVE_UNIXSOCKET
                struct sockaddr_un addr;
 #else
-               struct sockaddr addr;
+               struct sockaddr_storage addr;
 #endif
                socklen_t len = sizeof(addr);
                int sd;
 
-               opt_rc = ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd);
+               opt_rc = ldap_get_option(smbldap_get_ldap(ldap_state),
+                                        LDAP_OPT_DESC, &sd);
                if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
                        reopen = True;
 
@@ -1283,15 +1114,15 @@ static int smbldap_open(struct smbldap_state *ldap_state)
 #endif
                if (reopen) {
                        /* the other end has died. reopen. */
-                       ldap_unbind(ldap_state->ldap_struct);
-                       ldap_state->ldap_struct = NULL;
+                       ldap_unbind(smbldap_get_ldap(ldap_state));
+                       ldap_state->ldap_struct = NULL;
                        ldap_state->last_ping = (time_t)0;
                } else {
                        ldap_state->last_ping = time_mono(NULL);
                } 
        }
 
-       if (ldap_state->ldap_struct != NULL) {
+       if (smbldap_get_ldap(ldap_state) != NULL) {
                DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
                return LDAP_SUCCESS;
        }
@@ -1306,13 +1137,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);
        }
@@ -1330,8 +1161,8 @@ 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(ldap_state->ldap_struct);
+       if (smbldap_get_ldap(ldap_state) != NULL) {
+               ldap_unbind(smbldap_get_ldap(ldap_state));
                ldap_state->ldap_struct = NULL;
        }
 
@@ -1393,17 +1224,17 @@ static void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t abso
                alarm(absolute_endtime - now);
        }
 
-       if (ldap_state->pid != sys_getpid()) {
+       if (ldap_state->pid != getpid()) {
                smbldap_close(ldap_state);
        }
 }
 
 static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
 {
-       ldap_get_option(ldap_state->ldap_struct,
+       ldap_get_option(smbldap_get_ldap(ldap_state),
                        LDAP_OPT_ERROR_NUMBER, p_ld_errno);
 
-       ldap_get_option(ldap_state->ldap_struct,
+       ldap_get_option(smbldap_get_ldap(ldap_state),
                        LDAP_OPT_ERROR_STRING, pp_ld_error);
 }
 
@@ -1523,7 +1354,8 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state,
                        break;
                }
 
-               rc = ldap_search_ext_s(ldap_state->ldap_struct, base, scope, 
+               rc = ldap_search_ext_s(smbldap_get_ldap(ldap_state),
+                                      base, scope,
                                       utf8_filter,
                                       discard_const_p(char *, attrs),
                                       attrsonly, sctrls, cctrls, timeout_ptr,
@@ -1543,7 +1375,7 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state,
                if (ld_errno != LDAP_SERVER_DOWN) {
                        break;
                }
-               ldap_unbind(ldap_state->ldap_struct);
+               ldap_unbind(smbldap_get_ldap(ldap_state));
                ldap_state->ldap_struct = NULL;
        }
 
@@ -1618,7 +1450,7 @@ int smbldap_search_paged(struct smbldap_state *ldap_state,
 
        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 " \
@@ -1677,7 +1509,8 @@ int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *at
                        break;
                }
 
-               rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
+               rc = ldap_modify_s(smbldap_get_ldap(ldap_state), utf8_dn,
+                                  attrs);
                if (rc == LDAP_SUCCESS) {
                        break;
                }
@@ -1693,7 +1526,7 @@ int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *at
                if (ld_errno != LDAP_SERVER_DOWN) {
                        break;
                }
-               ldap_unbind(ldap_state->ldap_struct);
+               ldap_unbind(smbldap_get_ldap(ldap_state));
                ldap_state->ldap_struct = NULL;
        }
 
@@ -1727,7 +1560,7 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs
                        break;
                }
 
-               rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
+               rc = ldap_add_s(smbldap_get_ldap(ldap_state), utf8_dn, attrs);
                if (rc == LDAP_SUCCESS) {
                        break;
                }
@@ -1743,7 +1576,7 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs
                if (ld_errno != LDAP_SERVER_DOWN) {
                        break;
                }
-               ldap_unbind(ldap_state->ldap_struct);
+               ldap_unbind(smbldap_get_ldap(ldap_state));
                ldap_state->ldap_struct = NULL;
        }
 
@@ -1777,7 +1610,7 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
                        break;
                }
 
-               rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
+               rc = ldap_delete_s(smbldap_get_ldap(ldap_state), utf8_dn);
                if (rc == LDAP_SUCCESS) {
                        break;
                }
@@ -1793,7 +1626,7 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
                if (ld_errno != LDAP_SERVER_DOWN) {
                        break;
                }
-               ldap_unbind(ldap_state->ldap_struct);
+               ldap_unbind(smbldap_get_ldap(ldap_state));
                ldap_state->ldap_struct = NULL;
        }
 
@@ -1823,7 +1656,8 @@ int smbldap_extended_operation(struct smbldap_state *ldap_state,
                        break;
                }
 
-               rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid,
+               rc = ldap_extended_operation_s(smbldap_get_ldap(ldap_state),
+                                              reqoid,
                                               reqdata, serverctrls,
                                               clientctrls, retoidp, retdatap);
                if (rc == LDAP_SUCCESS) {
@@ -1841,7 +1675,7 @@ int smbldap_extended_operation(struct smbldap_state *ldap_state,
                if (ld_errno != LDAP_SERVER_DOWN) {
                        break;
                }
-               ldap_unbind(ldap_state->ldap_struct);
+               ldap_unbind(smbldap_get_ldap(ldap_state));
                ldap_state->ldap_struct = NULL;
        }
 
@@ -1855,12 +1689,13 @@ 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,
-                           struct timed_event *te,
+static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
+                           struct tevent_timer *te,
                            struct timeval now_abs,
                            void *private_data)
 {
@@ -1868,7 +1703,7 @@ static void smbldap_idle_fn(struct event_context *event_ctx,
 
        TALLOC_FREE(state->idle_event);
 
-       if (state->ldap_struct == NULL) {
+       if (smbldap_get_ldap(state) == NULL) {
                DEBUG(10,("ldap connection not connected...\n"));
                return;
        }
@@ -1877,8 +1712,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);
@@ -1903,6 +1738,7 @@ void smbldap_free_struct(struct smbldap_state **ldap_state)
 
        SAFE_FREE((*ldap_state)->bind_dn);
        SAFE_FREE((*ldap_state)->bind_secret);
+       smbldap_set_bind_callback(*ldap_state, NULL, NULL);
 
        TALLOC_FREE(*ldap_state);
 
@@ -1920,8 +1756,11 @@ 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(mem_ctx, struct smbldap_state);
@@ -1936,7 +1775,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;
@@ -2075,6 +1918,8 @@ bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *
        /* 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));