/* Unix SMB/CIFS implementation. idmap LDAP backend Copyright (C) Tim Potter 2000 Copyright (C) Anthony Liguori 2003 Copyright (C) Simo Sorce 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 2 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP #include #include struct ldap_idmap_state { LDAP *ldap_struct; time_t last_ping; const char *uri; char *bind_dn; char *bind_secret; unsigned int num_failures; struct ldap_idmap_state *prev, *next; }; #define LDAP_IDMAP_DONT_PING_TIME 10 /* ping only all 10 seconds */ #define LDAP_MAX_ALLOC_ID 128 /* number tries while allocating new id */ static struct ldap_idmap_state ldap_state; static int ldap_idmap_connect_system(struct ldap_idmap_state *state); static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type); static NTSTATUS ldap_idmap_close(void); /******************************************************************* find the ldap password ******************************************************************/ static BOOL fetch_ldapsam_pw(char **dn, char** pw) { char *key = NULL; size_t size; *dn = smb_xstrdup(lp_ldap_admin_dn()); if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) { SAFE_FREE(*dn); DEBUG(0, ("fetch_ldapsam_pw: asprintf failed!\n")); } *pw=secrets_fetch(key, &size); SAFE_FREE(key); if (!size) { /* Upgrade 2.2 style entry */ char *p; char* old_style_key = strdup(*dn); char *data; fstring old_style_pw; if (!old_style_key) { DEBUG(0, ("fetch_ldapsam_pw: strdup failed!\n")); return False; } for (p=old_style_key; *p; p++) if (*p == ',') *p = '/'; data=secrets_fetch(old_style_key, &size); if (!size && size < sizeof(old_style_pw)) { DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n")); SAFE_FREE(old_style_key); SAFE_FREE(*dn); return False; } strncpy(old_style_pw, data, size); old_style_pw[size] = 0; SAFE_FREE(data); if (!secrets_store_ldap_pw(*dn, old_style_pw)) { DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n")); SAFE_FREE(old_style_key); SAFE_FREE(*dn); return False; } if (!secrets_delete(old_style_key)) { DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n")); } SAFE_FREE(old_style_key); *pw = smb_xstrdup(old_style_pw); } return True; } /******************************************************************* open a connection to the ldap server. ******************************************************************/ static int ldap_idmap_open_connection(struct ldap_idmap_state *state) { int rc = LDAP_SUCCESS; int version; BOOL ldap_v3 = False; #ifdef HAVE_LDAP_INITIALIZE DEBUG(10, ("ldap_idmap_open_connection: %s\n", state->uri)); if ((rc = ldap_initialize(&state->ldap_struct, state->uri)) != LDAP_SUCCESS) { DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc))); return rc; } #else /* Parse the string manually */ { int port = 0; fstring protocol; fstring host; const char *p = state->uri; SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254); /* skip leading "URL:" (if any) */ if ( strncasecmp( p, "URL:", 4 ) == 0 ) { p += 4; } sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port); if (port == 0) { if (strequal(protocol, "ldap")) { port = LDAP_PORT; } else if (strequal(protocol, "ldaps")) { port = LDAPS_PORT; } else { DEBUG(0, ("unrecognised protocol (%s)!\n", protocol)); } } if ((state->ldap_struct = ldap_init(host, port)) == NULL) { DEBUG(0, ("ldap_init failed !\n")); return LDAP_OPERATIONS_ERROR; } if (strequal(protocol, "ldaps")) { #ifdef LDAP_OPT_X_TLS int tls = LDAP_OPT_X_TLS_HARD; if (ldap_set_option (state->ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { DEBUG(0, ("Failed to setup a TLS session\n")); } DEBUG(3,("LDAPS option set...!\n")); #else DEBUG(0,("ldap_idmap_open_connection: Secure " "connection not supported by LDAP client " "libraries!\n")); return LDAP_OPERATIONS_ERROR; #endif } } #endif if (ldap_get_option(state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) { if (version != LDAP_VERSION3) { version = LDAP_VERSION3; if (ldap_set_option(state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) { ldap_v3 = True; } } else { ldap_v3 = True; } } if (lp_ldap_ssl() == LDAP_SSL_START_TLS) { #ifdef LDAP_OPT_X_TLS if (ldap_v3) { if ((rc = ldap_start_tls_s(state->ldap_struct, NULL, NULL)) != LDAP_SUCCESS) { DEBUG(0,("Failed to issue the StartTLS " "instruction: %s\n", ldap_err2string(rc))); return rc; } DEBUG (3, ("StartTLS issued: using a TLS " "connection\n")); } else { DEBUG(0, ("Need LDAPv3 for Start TLS\n")); return LDAP_OPERATIONS_ERROR; } #else DEBUG(0,("ldap_idmap_open_connection: StartTLS not supported by " "LDAP client libraries!\n")); return LDAP_OPERATIONS_ERROR; #endif } DEBUG(2, ("ldap_idmap_open_connection: connection opened\n")); return rc; } /********************************************************************** Connect to LDAP server *********************************************************************/ static int ldap_idmap_open(struct ldap_idmap_state *state) { int rc; SMB_ASSERT(state); #ifndef NO_LDAP_SECURITY if (geteuid() != 0) { DEBUG(0, ("ldap_idmap_open: cannot access LDAP when not root\n")); return LDAP_INSUFFICIENT_ACCESS; } #endif if ((state->ldap_struct != NULL) && ((state->last_ping + LDAP_IDMAP_DONT_PING_TIME)ldap_struct, LDAP_OPT_DESC, &sd)&& getpeername(sd, (struct sockaddr *) &addr, &len) < 0) { /* the other end has died. reopen. */ ldap_unbind_ext(state->ldap_struct, NULL, NULL); state->ldap_struct = NULL; state->last_ping = (time_t)0; } else { state->last_ping = time(NULL); } } if (state->ldap_struct != NULL) { DEBUG(5,("ldap_idmap_open: already connected to the LDAP " "server\n")); return LDAP_SUCCESS; } if ((rc = ldap_idmap_open_connection(state))) { return rc; } if ((rc = ldap_idmap_connect_system(state))) { ldap_unbind_ext(state->ldap_struct, NULL, NULL); state->ldap_struct = NULL; return rc; } state->last_ping = time(NULL); DEBUG(4,("The LDAP server is succesful connected\n")); return LDAP_SUCCESS; } static int ldap_idmap_retry_open(struct ldap_idmap_state *state, int *attempts) { int rc; SMB_ASSERT(state && attempts); if (*attempts != 0) { unsigned int sleep_time; uint8 rand_byte = 128; /* a reasonable place to start */ generate_random_buffer(&rand_byte, 1, False); sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2; /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds on average. */ DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n", sleep_time)); msleep(sleep_time); } (*attempts)++; if ((rc = ldap_idmap_open(state))) { DEBUG(1,("Connection to LDAP Server failed for the %d try!\n", *attempts)); return rc; } return LDAP_SUCCESS; } /******************************************************************* a rebind function for authenticated referrals This version takes a void* that we can shove useful stuff in :-) ******************************************************************/ #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) #else static int rebindproc_with_state (LDAP * ld, char **whop, char **credp, int *methodp, int freeit, void *arg) { struct ldap_idmap_state *state = arg; /** @TODO Should we be doing something to check what servers we rebind to? Could we get a referral to a machine that we don't want to give our username and password to? */ if (freeit) { SAFE_FREE(*whop); memset(*credp, '\0', strlen(*credp)); SAFE_FREE(*credp); } else { DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n", state->bind_dn)); *whop = strdup(state->bind_dn); if (!*whop) { return LDAP_NO_MEMORY; } *credp = strdup(state->bind_secret); if (!*credp) { SAFE_FREE(*whop); return LDAP_NO_MEMORY; } *methodp = LDAP_AUTH_SIMPLE; } return 0; } #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ /******************************************************************* a rebind function for authenticated referrals This version takes a void* that we can shove useful stuff in :-) and actually does the connection. ******************************************************************/ #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) static int rebindproc_connect_with_state (LDAP *ldap_struct, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *arg) { struct ldap_idmap_state *state = arg; int rc; DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n", state->bind_dn)); /** @TODO Should we be doing something to check what servers we rebind to? Could we get a referral to a machine that we don't want to give our username and password to? */ rc = ldap_simple_bind_s(ldap_struct, state->bind_dn, state->bind_secret); return rc; } #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ /******************************************************************* Add a rebind function for authenticated referrals ******************************************************************/ #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) #else # if LDAP_SET_REBIND_PROC_ARGS == 2 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp, int *method, int freeit ) { return rebindproc_with_state(ldap_struct, whop, credp, method, freeit, &ldap_state); } # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/ #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ /******************************************************************* a rebind function for authenticated referrals this also does the connection, but no void*. ******************************************************************/ #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) # if LDAP_SET_REBIND_PROC_ARGS == 2 static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid) { return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid, &ldap_state); } # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/ #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ /******************************************************************* connect to the ldap server under system privilege. ******************************************************************/ static int ldap_idmap_connect_system(struct ldap_idmap_state *state) { int rc; char *ldap_dn; char *ldap_secret; /* get the password */ if (!fetch_ldapsam_pw(&ldap_dn, &ldap_secret)) { DEBUG(0, ("ldap_idmap_connect_system: Failed to retrieve " "password from secrets.tdb\n")); return LDAP_INVALID_CREDENTIALS; } state->bind_dn = ldap_dn; state->bind_secret = ldap_secret; /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite (OpenLDAP) doesnt' seem to support it */ DEBUG(10,("ldap_idmap_connect_system: Binding to ldap server %s as " "\"%s\"\n", state->uri, ldap_dn)); #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) # if LDAP_SET_REBIND_PROC_ARGS == 2 ldap_set_rebind_proc(state->ldap_struct, &rebindproc_connect); # endif # if LDAP_SET_REBIND_PROC_ARGS == 3 ldap_set_rebind_proc(state->ldap_struct, &rebindproc_connect_with_state, (void *)state); # endif #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ # if LDAP_SET_REBIND_PROC_ARGS == 2 ldap_set_rebind_proc(state->ldap_struct, &rebindproc); # endif # if LDAP_SET_REBIND_PROC_ARGS == 3 ldap_set_rebind_proc(state->ldap_struct, &rebindproc_with_state, (void *)state); # endif #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ rc = ldap_simple_bind_s(state->ldap_struct, ldap_dn, ldap_secret); if (rc != LDAP_SUCCESS) { char *ld_error = NULL; ldap_get_option(state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); DEBUG(state->num_failures ? 2 : 0, ("failed to bind to server with dn= %s Error: " "%s\n\t%s\n", ldap_dn ? ld_error : "(unknown)", ldap_err2string(rc), ld_error)); SAFE_FREE(ld_error); state->num_failures++; return rc; } state->num_failures = 0; DEBUG(3, ("ldap_idmap_connect_system: succesful connection to the " "LDAP server\n")); return rc; } static int ldap_idmap_search(struct ldap_idmap_state *state, const char *base, int scope, const char *filter, const char *attrs[], int attrsonly, LDAPMessage **res) { int rc = LDAP_SERVER_DOWN; int attempts = 0; char *utf8_filter; SMB_ASSERT(state); if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) { return LDAP_NO_MEMORY; } while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) { if ((rc = ldap_idmap_retry_open(state, &attempts)) != LDAP_SUCCESS) continue; rc = ldap_search_s(state->ldap_struct, base, scope, utf8_filter, (char**)attrs, attrsonly, res); } if (rc == LDAP_SERVER_DOWN) { DEBUG(0,("ldap_idmap_search: LDAP server is down!\n")); ldap_idmap_close(); } SAFE_FREE(utf8_filter); return rc; } /******************************************************************* search an attribute and return the first value found. ******************************************************************/ static BOOL ldap_idmap_attribute (struct ldap_idmap_state *state, LDAPMessage * entry, const char *attribute, pstring value) { char **values; value[0] = '\0'; if ((values = ldap_get_values (state->ldap_struct, entry, attribute)) == NULL) { DEBUG(10,("get_single_attribute: [%s] = []\n", attribute)); return False; } if (convert_string(CH_UTF8, CH_UNIX, values[0], -1, value, sizeof(pstring)) == (size_t)-1) { DEBUG(1, ("ldap_idmap_attribute: string conversion of [%s] = " "[%s] failed!\n", attribute, values[0])); ldap_value_free(values); return False; } ldap_value_free(values); return True; } static const char *attrs[] = {"objectClass", "uidNumber", "gidNumber", "ntSid", NULL}; static const char *pool_attr[] = {"uidNumber", "gidNumber", NULL}; static NTSTATUS ldap_allocate_id(unid_t *id, int id_type) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; int rc = LDAP_SERVER_DOWN; int count = 0; LDAPMessage *result = 0; LDAPMessage *entry = 0; pstring id_str, new_id_str; LDAPMod mod[2]; LDAPMod *mods[3]; const char *type = (id_type & ID_USERID) ? "uidNumber" : "gidNumber"; char *val[4]; char *dn; rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE, "(objectClass=unixIdPool)", pool_attr, 0, &result); if (rc != LDAP_SUCCESS) { DEBUG(0,("ldap_allocate_id: unixIdPool object not found\n")); goto out; } count = ldap_count_entries(ldap_state.ldap_struct, result); if (count != 1) { DEBUG(0,("ldap_allocate_id: single unixIdPool not found\n")); goto out; } dn = ldap_get_dn(ldap_state.ldap_struct, result); entry = ldap_first_entry(ldap_state.ldap_struct, result); if (!ldap_idmap_attribute(&ldap_state, entry, type, id_str)) { DEBUG(0,("ldap_allocate_id: %s attribute not found\n", type)); goto out; } if (id_type & ID_USERID) { id->uid = strtoul(id_str, NULL, 10); } else { id->gid = strtoul(id_str, NULL, 10); } mod[0].mod_op = LDAP_MOD_DELETE; mod[0].mod_type = strdup(type); val[0] = id_str; val[1] = NULL; mod[0].mod_values = val; pstr_sprintf(new_id_str, "%ud", ((id_type & ID_USERID) ? id->uid : id->gid) + 1); mod[1].mod_op = LDAP_MOD_ADD; mod[1].mod_type = strdup(type); val[3] = new_id_str; val[4] = NULL; mod[1].mod_values = val + 2; mods[0] = mod; mods[1] = mod + 1; mods[2] = NULL; rc = ldap_modify_s(ldap_state.ldap_struct, dn, mods); ldap_memfree(dn); if (rc == LDAP_SUCCESS) ret = NT_STATUS_OK; out: return ret; } /* Get a sid from an id */ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type) { LDAPMessage *result = 0; LDAPMessage *entry = 0; pstring sid_str; pstring filter; char type = (id_type & ID_USERID) ? 'u' : 'g'; int rc; int count; NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; pstr_sprintf(filter, "(&(%cidNumber=%ud)(objectClass=sambaAccount))", type, ((id_type & ID_USERID) ? id.uid : id.gid)); rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result); if (rc != LDAP_SUCCESS) { goto out; } count = ldap_count_entries(ldap_state.ldap_struct, result); if (count == 0) { pstr_sprintf(filter, "(&(objectClass=idmapEntry)(%cidNumber=%ud))", type, ((id_type & ID_USERID) ? id.uid : id.gid)); rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result); if (rc != LDAP_SUCCESS) { goto out; } count = ldap_count_entries(ldap_state.ldap_struct, result); } if (count != 1) { DEBUG(0,("ldap_get_sid_from_id: mapping not found for " "%cid: %ud\n", (id_type&ID_USERID)?'u':'g', ((id_type & ID_USERID) ? id.uid : id.gid))); goto out; } entry = ldap_first_entry(ldap_state.ldap_struct, result); if (!ldap_idmap_attribute(&ldap_state, entry, "ntSid", sid_str)) { goto out; } if (!string_to_sid(sid, sid_str)) { goto out; } ret = NT_STATUS_OK; out: return ret; } /* Get an id from a sid */ static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid) { LDAPMessage *result = 0; LDAPMessage *entry = 0; pstring sid_str; pstring filter; pstring id_str; const char *type = (*id_type & ID_USERID) ? "uidNumber" : "gidNumber"; const char *class = (*id_type & ID_USERID) ? "sambaAccount" : "sambaGroupMapping"; int rc; int count; NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; sid_to_string(sid_str, sid); pstr_sprintf(filter, "(&(objectClass=%s)(ntSid=%s)", class, sid_str); rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result); if (rc != LDAP_SUCCESS) { goto out; } count = ldap_count_entries(ldap_state.ldap_struct, result); if (count == 0) { pstr_sprintf(filter, "(&(objectClass=idmapEntry)(ntSid=%s))", sid_str); rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(), LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result); if (rc != LDAP_SUCCESS) { goto out; } count = ldap_count_entries(ldap_state.ldap_struct, result); } /* our search filters may 2 objects in the case that a user and group rid are the same */ if (count != 1 && count != 2) { DEBUG(0, ("ldap_get_id_from_sid: incorrect number of objects\n")); goto out; } entry = ldap_first_entry(ldap_state.ldap_struct, result); if (!ldap_idmap_attribute(&ldap_state, entry, type, id_str)) { entry = ldap_next_entry(ldap_state.ldap_struct, entry); if (!ldap_idmap_attribute(&ldap_state, entry, type, id_str)) { int i; for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) { ret = ldap_allocate_id(id, *id_type); if (NT_STATUS_IS_OK(ret)) { break; } } if (NT_STATUS_IS_OK(ret)) { ret = ldap_set_mapping(sid, *id, *id_type); } else { DEBUG(0,("ldap_allocate_id: cannot acquire id" " lock\n")); } } else { if ((*id_type & ID_USERID)) { id->uid = strtoul(id_str, NULL, 10); } else { id->gid = strtoul(id_str, NULL, 10); } ret = NT_STATUS_OK; } } else { if ((*id_type & ID_USERID)) { id->uid = strtoul(id_str, NULL, 10); } else { id->gid = strtoul(id_str, NULL, 10); } ret = NT_STATUS_OK; } out: return ret; } /* This function cannot be called to modify a mapping, only set a new one */ static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) { pstring dn, sid_str, id_str; const char *type = (id_type & ID_USERID) ? "uidNumber" : "gidNumber"; LDAPMod *mods[3]; LDAPMod mod[2]; char *val[4]; int rc; int attempts = 0; pstr_sprintf(id_str, "%ud", ((id_type & ID_USERID) ? id.uid : id.gid)); sid_to_string(sid_str, sid); pstr_sprintf(dn, "%s=%ud,%s", type, ((id_type & ID_USERID) ? id.uid : id.gid), lp_ldap_suffix()); mod[0].mod_op = LDAP_MOD_REPLACE; mod[0].mod_type = strdup(type); val[0] = id_str; val[1] = NULL; mod[0].mod_values = val; mod[1].mod_op = LDAP_MOD_REPLACE; mod[1].mod_type = strdup("ntSid"); val[2] = sid_str; val[3] = NULL; mod[1].mod_values = val + 2; mods[0] = mod; mods[1] = mod + 1; mods[2] = NULL; do { if ((rc = ldap_idmap_retry_open(&ldap_state, &attempts)) != LDAP_SUCCESS) continue; rc = ldap_modify_s(ldap_state.ldap_struct, dn, mods); } while ((rc == LDAP_SERVER_DOWN) && (attempts <= 8)); if (rc != LDAP_SUCCESS) { return NT_STATUS_UNSUCCESSFUL; } return NT_STATUS_OK; } /***************************************************************************** Initialise idmap database. *****************************************************************************/ static NTSTATUS ldap_idmap_init(void) { /* We wait for the first search request before we try to connect to the LDAP server. We may want to connect upon initialization though -- aliguori */ return NT_STATUS_OK; } /* End the LDAP session */ static NTSTATUS ldap_idmap_close(void) { if (ldap_state.ldap_struct != NULL) { ldap_unbind_ext(ldap_state.ldap_struct, NULL, NULL); ldap_state.ldap_struct = NULL; } DEBUG(5,("The connection to the LDAP server was closed\n")); /* maybe free the results here --metze */ return NT_STATUS_OK; } /* This function doesn't make as much sense in an LDAP world since the calling node doesn't really control the ID ranges */ static void ldap_idmap_status(void) { DEBUG(0, ("LDAP IDMAP Status not available\n")); } static struct idmap_methods ldap_methods = { ldap_idmap_init, ldap_get_sid_from_id, ldap_get_id_from_sid, ldap_set_mapping, ldap_idmap_close, ldap_idmap_status }; NTSTATUS idmap_ldap_init(void) { DEBUG(0,("idmap_reg_ldap: no LDAP support\n")); return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods); }