selftest: Fix flapping samba.dsdb test
[Samba.git] / source3 / lib / smbldap.c
blob71166f649bea844ceb084791c69752648ba2e86c
1 /*
2 Unix SMB/CIFS implementation.
3 LDAP protocol helper functions for SAMBA
4 Copyright (C) Jean François Micouleau 1998
5 Copyright (C) Gerald Carter 2001-2003
6 Copyright (C) Shahms King 2001
7 Copyright (C) Andrew Bartlett 2002-2003
8 Copyright (C) Stefan (metze) Metzmacher 2002-2003
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "smbldap.h"
27 #include "../libcli/security/security.h"
28 #include <tevent.h>
29 #include "lib/param/loadparm.h"
31 /* Try not to hit the up or down server forever */
33 #define SMBLDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
34 #define SMBLDAP_NUM_RETRIES 8 /* retry only 8 times */
36 #define SMBLDAP_IDLE_TIME 150 /* After 2.5 minutes disconnect */
38 struct smbldap_state {
39 LDAP *ldap_struct;
40 pid_t pid;
41 time_t last_ping; /* monotonic */
42 /* retrieve-once info */
43 const char *uri;
45 /* credentials */
46 bool anonymous;
47 char *bind_dn;
48 char *bind_secret;
49 smbldap_bind_callback_fn bind_callback;
50 void *bind_callback_data;
52 bool paged_results;
54 unsigned int num_failures;
56 time_t last_use; /* monotonic */
57 struct tevent_context *tevent_context;
58 struct tevent_timer *idle_event;
60 struct timeval last_rebind; /* monotonic */
63 LDAP *smbldap_get_ldap(struct smbldap_state *state)
65 return state->ldap_struct;
68 bool smbldap_get_paged_results(struct smbldap_state *state)
70 return state->paged_results;
73 void smbldap_set_paged_results(struct smbldap_state *state,
74 bool paged_results)
76 state->paged_results = paged_results;
79 void smbldap_set_bind_callback(struct smbldap_state *state,
80 smbldap_bind_callback_fn callback,
81 void *callback_data)
83 state->bind_callback = callback;
84 state->bind_callback_data = callback_data;
86 /*******************************************************************
87 Search an attribute and return the first value found.
88 ******************************************************************/
90 bool smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
91 const char *attribute, char *value,
92 int max_len)
94 char **values;
95 size_t size = 0;
97 if ( !attribute )
98 return False;
100 value[0] = '\0';
102 if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
103 DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
105 return False;
108 if (!convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, &size)) {
109 DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n",
110 attribute, values[0]));
111 ldap_value_free(values);
112 return False;
115 ldap_value_free(values);
116 #ifdef DEBUG_PASSWORDS
117 DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
118 #endif
119 return True;
122 char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry,
123 const char *attribute,
124 TALLOC_CTX *mem_ctx)
126 char **values;
127 char *result;
128 size_t converted_size;
130 if (attribute == NULL) {
131 return NULL;
134 values = ldap_get_values(ldap_struct, entry, attribute);
136 if (values == NULL) {
137 DEBUG(10, ("attribute %s does not exist\n", attribute));
138 return NULL;
141 if (ldap_count_values(values) != 1) {
142 DEBUG(10, ("attribute %s has %d values, expected only one\n",
143 attribute, ldap_count_values(values)));
144 ldap_value_free(values);
145 return NULL;
148 if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
149 DEBUG(10, ("pull_utf8_talloc failed\n"));
150 ldap_value_free(values);
151 return NULL;
154 ldap_value_free(values);
156 #ifdef DEBUG_PASSWORDS
157 DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
158 attribute, result));
159 #endif
160 return result;
163 char * smbldap_talloc_first_attribute(LDAP *ldap_struct, LDAPMessage *entry,
164 const char *attribute,
165 TALLOC_CTX *mem_ctx)
167 char **values;
168 char *result;
169 size_t converted_size;
171 if (attribute == NULL) {
172 return NULL;
175 values = ldap_get_values(ldap_struct, entry, attribute);
177 if (values == NULL) {
178 DEBUG(10, ("attribute %s does not exist\n", attribute));
179 return NULL;
182 if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
183 DEBUG(10, ("pull_utf8_talloc failed\n"));
184 ldap_value_free(values);
185 return NULL;
188 ldap_value_free(values);
190 #ifdef DEBUG_PASSWORDS
191 DEBUG (100, ("smbldap_get_first_attribute: [%s] = [%s]\n",
192 attribute, result));
193 #endif
194 return result;
197 char * smbldap_talloc_smallest_attribute(LDAP *ldap_struct, LDAPMessage *entry,
198 const char *attribute,
199 TALLOC_CTX *mem_ctx)
201 char **values;
202 char *result;
203 size_t converted_size;
204 int i, num_values;
206 if (attribute == NULL) {
207 return NULL;
210 values = ldap_get_values(ldap_struct, entry, attribute);
212 if (values == NULL) {
213 DEBUG(10, ("attribute %s does not exist\n", attribute));
214 return NULL;
217 if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
218 DEBUG(10, ("pull_utf8_talloc failed\n"));
219 ldap_value_free(values);
220 return NULL;
223 num_values = ldap_count_values(values);
225 for (i=1; i<num_values; i++) {
226 char *tmp;
228 if (!pull_utf8_talloc(mem_ctx, &tmp, values[i],
229 &converted_size)) {
230 DEBUG(10, ("pull_utf8_talloc failed\n"));
231 TALLOC_FREE(result);
232 ldap_value_free(values);
233 return NULL;
236 if (strcasecmp_m(tmp, result) < 0) {
237 TALLOC_FREE(result);
238 result = tmp;
239 } else {
240 TALLOC_FREE(tmp);
244 ldap_value_free(values);
246 #ifdef DEBUG_PASSWORDS
247 DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
248 attribute, result));
249 #endif
250 return result;
253 bool smbldap_talloc_single_blob(TALLOC_CTX *mem_ctx, LDAP *ld,
254 LDAPMessage *msg, const char *attrib,
255 DATA_BLOB *blob)
257 struct berval **values;
259 values = ldap_get_values_len(ld, msg, attrib);
260 if (!values) {
261 return false;
264 if (ldap_count_values_len(values) != 1) {
265 DEBUG(10, ("Expected one value for %s, got %d\n", attrib,
266 ldap_count_values_len(values)));
267 return false;
270 *blob = data_blob_talloc(mem_ctx, values[0]->bv_val,
271 values[0]->bv_len);
272 ldap_value_free_len(values);
274 return (blob->data != NULL);
277 bool smbldap_pull_sid(LDAP *ld, LDAPMessage *msg, const char *attrib,
278 struct dom_sid *sid)
280 DATA_BLOB blob;
281 bool ret;
283 if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib,
284 &blob)) {
285 return false;
287 ret = sid_parse(blob.data, blob.length, sid);
288 TALLOC_FREE(blob.data);
289 return ret;
292 static int ldapmsg_destructor(LDAPMessage **result) {
293 ldap_msgfree(*result);
294 return 0;
297 void smbldap_talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
299 LDAPMessage **handle;
301 if (result == NULL) {
302 return;
305 handle = talloc(mem_ctx, LDAPMessage *);
306 SMB_ASSERT(handle != NULL);
308 *handle = result;
309 talloc_set_destructor(handle, ldapmsg_destructor);
312 static int ldapmod_destructor(LDAPMod ***mod) {
313 ldap_mods_free(*mod, True);
314 return 0;
317 void smbldap_talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
319 LDAPMod ***handle;
321 if (mod == NULL) {
322 return;
325 handle = talloc(mem_ctx, LDAPMod **);
326 SMB_ASSERT(handle != NULL);
328 *handle = mod;
329 talloc_set_destructor(handle, ldapmod_destructor);
332 /************************************************************************
333 Routine to manage the LDAPMod structure array
334 manage memory used by the array, by each struct, and values
335 ***********************************************************************/
337 static void smbldap_set_mod_internal(LDAPMod *** modlist, int modop, const char *attribute, const char *value, const DATA_BLOB *blob)
339 LDAPMod **mods;
340 int i;
341 int j;
343 mods = *modlist;
345 /* sanity checks on the mod values */
347 if (attribute == NULL || *attribute == '\0') {
348 return;
351 #if 0 /* commented out after discussion with abartlet. Do not re-enable.
352 left here so other do not re-add similar code --jerry */
353 if (value == NULL || *value == '\0')
354 return;
355 #endif
357 if (mods == NULL) {
358 mods = SMB_MALLOC_P(LDAPMod *);
359 if (mods == NULL) {
360 smb_panic("smbldap_set_mod: out of memory!");
361 /* notreached. */
363 mods[0] = NULL;
366 for (i = 0; mods[i] != NULL; ++i) {
367 if (mods[i]->mod_op == modop && strequal(mods[i]->mod_type, attribute))
368 break;
371 if (mods[i] == NULL) {
372 mods = SMB_REALLOC_ARRAY (mods, LDAPMod *, i + 2);
373 if (mods == NULL) {
374 smb_panic("smbldap_set_mod: out of memory!");
375 /* notreached. */
377 mods[i] = SMB_MALLOC_P(LDAPMod);
378 if (mods[i] == NULL) {
379 smb_panic("smbldap_set_mod: out of memory!");
380 /* notreached. */
382 mods[i]->mod_op = modop;
383 mods[i]->mod_values = NULL;
384 mods[i]->mod_type = SMB_STRDUP(attribute);
385 mods[i + 1] = NULL;
388 if (blob && (modop & LDAP_MOD_BVALUES)) {
389 j = 0;
390 if (mods[i]->mod_bvalues != NULL) {
391 for (; mods[i]->mod_bvalues[j] != NULL; j++);
393 mods[i]->mod_bvalues = SMB_REALLOC_ARRAY(mods[i]->mod_bvalues, struct berval *, j + 2);
395 if (mods[i]->mod_bvalues == NULL) {
396 smb_panic("smbldap_set_mod: out of memory!");
397 /* notreached. */
400 mods[i]->mod_bvalues[j] = SMB_MALLOC_P(struct berval);
401 SMB_ASSERT(mods[i]->mod_bvalues[j] != NULL);
403 mods[i]->mod_bvalues[j]->bv_val = (char *)smb_memdup(blob->data, blob->length);
404 SMB_ASSERT(mods[i]->mod_bvalues[j]->bv_val != NULL);
405 mods[i]->mod_bvalues[j]->bv_len = blob->length;
407 mods[i]->mod_bvalues[j + 1] = NULL;
408 } else if (value != NULL) {
409 char *utf8_value = NULL;
410 size_t converted_size;
412 j = 0;
413 if (mods[i]->mod_values != NULL) {
414 for (; mods[i]->mod_values[j] != NULL; j++);
416 mods[i]->mod_values = SMB_REALLOC_ARRAY(mods[i]->mod_values, char *, j + 2);
418 if (mods[i]->mod_values == NULL) {
419 smb_panic("smbldap_set_mod: out of memory!");
420 /* notreached. */
423 if (!push_utf8_talloc(talloc_tos(), &utf8_value, value, &converted_size)) {
424 smb_panic("smbldap_set_mod: String conversion failure!");
425 /* notreached. */
428 mods[i]->mod_values[j] = SMB_STRDUP(utf8_value);
429 TALLOC_FREE(utf8_value);
430 SMB_ASSERT(mods[i]->mod_values[j] != NULL);
432 mods[i]->mod_values[j + 1] = NULL;
434 *modlist = mods;
437 void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
439 smbldap_set_mod_internal(modlist, modop, attribute, value, NULL);
442 void smbldap_set_mod_blob(LDAPMod *** modlist, int modop, const char *attribute, const DATA_BLOB *value)
444 smbldap_set_mod_internal(modlist, modop | LDAP_MOD_BVALUES, attribute, NULL, value);
447 /**********************************************************************
448 Set attribute to newval in LDAP, regardless of what value the
449 attribute had in LDAP before.
450 *********************************************************************/
452 static void smbldap_make_mod_internal(LDAP *ldap_struct, LDAPMessage *existing,
453 LDAPMod ***mods,
454 const char *attribute, int op,
455 const char *newval,
456 const DATA_BLOB *newblob)
458 char oldval[2048]; /* current largest allowed value is mungeddial */
459 bool existed;
460 DATA_BLOB oldblob = data_blob_null;
462 if (existing != NULL) {
463 if (op & LDAP_MOD_BVALUES) {
464 existed = smbldap_talloc_single_blob(talloc_tos(), ldap_struct, existing, attribute, &oldblob);
465 } else {
466 existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
468 } else {
469 existed = False;
470 *oldval = '\0';
473 if (existed) {
474 bool equal = false;
475 if (op & LDAP_MOD_BVALUES) {
476 equal = (newblob && (data_blob_cmp(&oldblob, newblob) == 0));
477 } else {
478 /* all of our string attributes are case insensitive */
479 equal = (newval && (strcasecmp_m(oldval, newval) == 0));
482 if (equal) {
483 /* Believe it or not, but LDAP will deny a delete and
484 an add at the same time if the values are the
485 same... */
486 DEBUG(10,("smbldap_make_mod: attribute |%s| not changed.\n", attribute));
487 return;
490 /* There has been no value before, so don't delete it.
491 * Here's a possible race: We might end up with
492 * duplicate attributes */
493 /* By deleting exactly the value we found in the entry this
494 * should be race-free in the sense that the LDAP-Server will
495 * deny the complete operation if somebody changed the
496 * attribute behind our back. */
497 /* This will also allow modifying single valued attributes
498 * in Novell NDS. In NDS you have to first remove attribute and then
499 * you could add new value */
501 if (op & LDAP_MOD_BVALUES) {
502 DEBUG(10,("smbldap_make_mod: deleting attribute |%s| blob\n", attribute));
503 smbldap_set_mod_blob(mods, LDAP_MOD_DELETE, attribute, &oldblob);
504 } else {
505 DEBUG(10,("smbldap_make_mod: deleting attribute |%s| values |%s|\n", attribute, oldval));
506 smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval);
510 /* Regardless of the real operation (add or modify)
511 we add the new value here. We rely on deleting
512 the old value, should it exist. */
514 if (op & LDAP_MOD_BVALUES) {
515 if (newblob && newblob->length) {
516 DEBUG(10,("smbldap_make_mod: adding attribute |%s| blob\n", attribute));
517 smbldap_set_mod_blob(mods, LDAP_MOD_ADD, attribute, newblob);
519 } else {
520 if ((newval != NULL) && (strlen(newval) > 0)) {
521 DEBUG(10,("smbldap_make_mod: adding attribute |%s| value |%s|\n", attribute, newval));
522 smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
527 void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
528 LDAPMod ***mods,
529 const char *attribute, const char *newval)
531 smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
532 0, newval, NULL);
535 void smbldap_make_mod_blob(LDAP *ldap_struct, LDAPMessage *existing,
536 LDAPMod ***mods,
537 const char *attribute, const DATA_BLOB *newblob)
539 smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
540 LDAP_MOD_BVALUES, NULL, newblob);
543 /**********************************************************************
544 Some varients of the LDAP rebind code do not pass in the third 'arg'
545 pointer to a void*, so we try and work around it by assuming that the
546 value of the 'LDAP *' pointer is the same as the one we had passed in
547 **********************************************************************/
549 struct smbldap_state_lookup {
550 LDAP *ld;
551 struct smbldap_state *smbldap_state;
552 struct smbldap_state_lookup *prev, *next;
555 static struct smbldap_state_lookup *smbldap_state_lookup_list;
557 static struct smbldap_state *smbldap_find_state(LDAP *ld)
559 struct smbldap_state_lookup *t;
561 for (t = smbldap_state_lookup_list; t; t = t->next) {
562 if (t->ld == ld) {
563 return t->smbldap_state;
566 return NULL;
569 static void smbldap_delete_state(struct smbldap_state *smbldap_state)
571 struct smbldap_state_lookup *t;
573 for (t = smbldap_state_lookup_list; t; t = t->next) {
574 if (t->smbldap_state == smbldap_state) {
575 DLIST_REMOVE(smbldap_state_lookup_list, t);
576 SAFE_FREE(t);
577 return;
582 static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
584 struct smbldap_state *tmp_ldap_state;
585 struct smbldap_state_lookup *t;
587 if ((tmp_ldap_state = smbldap_find_state(ld))) {
588 SMB_ASSERT(tmp_ldap_state == smbldap_state);
589 return;
592 t = SMB_XMALLOC_P(struct smbldap_state_lookup);
593 ZERO_STRUCTP(t);
595 DLIST_ADD_END(smbldap_state_lookup_list, t);
596 t->ld = ld;
597 t->smbldap_state = smbldap_state;
600 /********************************************************************
601 start TLS on an existing LDAP connection
602 *******************************************************************/
604 int smbldap_start_tls(LDAP *ldap_struct, int version)
606 #ifdef LDAP_OPT_X_TLS
607 int rc;
608 #endif
610 if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
611 return LDAP_SUCCESS;
614 #ifdef LDAP_OPT_X_TLS
615 if (version != LDAP_VERSION3) {
616 DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
617 return LDAP_OPERATIONS_ERROR;
620 if ((rc = ldap_start_tls_s (ldap_struct, NULL, NULL)) != LDAP_SUCCESS) {
621 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
622 ldap_err2string(rc)));
623 return rc;
626 DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
627 return LDAP_SUCCESS;
628 #else
629 DEBUG(0,("StartTLS not supported by LDAP client libraries!\n"));
630 return LDAP_OPERATIONS_ERROR;
631 #endif
634 /********************************************************************
635 setup a connection to the LDAP server based on a uri
636 *******************************************************************/
638 static int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri)
640 int rc;
642 DEBUG(10, ("smb_ldap_setup_connection: %s\n", uri));
644 #ifdef HAVE_LDAP_INITIALIZE
646 rc = ldap_initialize(ldap_struct, uri);
647 if (rc) {
648 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
649 return rc;
652 if (lp_ldap_follow_referral() != Auto) {
653 rc = ldap_set_option(*ldap_struct, LDAP_OPT_REFERRALS,
654 lp_ldap_follow_referral() ? LDAP_OPT_ON : LDAP_OPT_OFF);
655 if (rc != LDAP_SUCCESS)
656 DEBUG(0, ("Failed to set LDAP_OPT_REFERRALS: %s\n",
657 ldap_err2string(rc)));
660 return LDAP_SUCCESS;
661 #else
663 /* Parse the string manually */
666 int port = 0;
667 fstring protocol;
668 fstring host;
669 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
672 /* skip leading "URL:" (if any) */
673 if ( strnequal( uri, "URL:", 4 ) ) {
674 uri += 4;
677 sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
679 if (port == 0) {
680 if (strequal(protocol, "ldap")) {
681 port = LDAP_PORT;
682 } else if (strequal(protocol, "ldaps")) {
683 port = LDAPS_PORT;
684 } else {
685 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
689 if ((*ldap_struct = ldap_init(host, port)) == NULL) {
690 DEBUG(0, ("ldap_init failed !\n"));
691 return LDAP_OPERATIONS_ERROR;
694 if (strequal(protocol, "ldaps")) {
695 #ifdef LDAP_OPT_X_TLS
696 int tls = LDAP_OPT_X_TLS_HARD;
697 if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
699 DEBUG(0, ("Failed to setup a TLS session\n"));
702 DEBUG(3,("LDAPS option set...!\n"));
703 #else
704 DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
705 return LDAP_OPERATIONS_ERROR;
706 #endif /* LDAP_OPT_X_TLS */
709 #endif /* HAVE_LDAP_INITIALIZE */
711 /* now set connection timeout */
712 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT /* Netscape */
714 int ct = lp_ldap_connection_timeout()*1000;
715 rc = ldap_set_option(*ldap_struct, LDAP_X_OPT_CONNECT_TIMEOUT, &ct);
716 if (rc != LDAP_SUCCESS) {
717 DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
718 ct, ldap_err2string(rc)));
721 #elif defined (LDAP_OPT_NETWORK_TIMEOUT) /* OpenLDAP */
723 struct timeval ct;
724 ct.tv_usec = 0;
725 ct.tv_sec = lp_ldap_connection_timeout();
726 rc = ldap_set_option(*ldap_struct, LDAP_OPT_NETWORK_TIMEOUT, &ct);
727 if (rc != LDAP_SUCCESS) {
728 DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
729 (int)ct.tv_sec, ldap_err2string(rc)));
732 #endif
734 return LDAP_SUCCESS;
737 /********************************************************************
738 try to upgrade to Version 3 LDAP if not already, in either case return current
739 version
740 *******************************************************************/
742 static int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
744 int version;
745 int rc;
747 /* assume the worst */
748 *new_version = LDAP_VERSION2;
750 rc = ldap_get_option(ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
751 if (rc) {
752 return rc;
755 if (version == LDAP_VERSION3) {
756 *new_version = LDAP_VERSION3;
757 return LDAP_SUCCESS;
760 /* try upgrade */
761 version = LDAP_VERSION3;
762 rc = ldap_set_option (ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
763 if (rc) {
764 return rc;
767 *new_version = LDAP_VERSION3;
768 return LDAP_SUCCESS;
771 /*******************************************************************
772 open a connection to the ldap server (just until the bind)
773 ******************************************************************/
775 int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
777 int rc, version;
779 rc = smb_ldap_setup_conn(ldap_struct, uri);
780 if (rc) {
781 return rc;
784 rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
785 if (rc) {
786 return rc;
789 rc = smbldap_start_tls(*ldap_struct, version);
790 if (rc) {
791 return rc;
794 return LDAP_SUCCESS;
797 /*******************************************************************
798 open a connection to the ldap server.
799 ******************************************************************/
800 static int smbldap_open_connection (struct smbldap_state *ldap_state)
803 int rc = LDAP_SUCCESS;
804 int version;
805 int deref;
806 LDAP **ldap_struct = &ldap_state->ldap_struct;
808 rc = smb_ldap_setup_conn(ldap_struct, ldap_state->uri);
809 if (rc) {
810 return rc;
813 /* Store the LDAP pointer in a lookup list */
815 smbldap_store_state(*ldap_struct, ldap_state);
817 /* Upgrade to LDAPv3 if possible */
819 rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
820 if (rc) {
821 return rc;
824 /* Start TLS if required */
826 rc = smbldap_start_tls(*ldap_struct, version);
827 if (rc) {
828 return rc;
831 /* Set alias dereferencing method */
832 deref = lp_ldap_deref();
833 if (deref != -1) {
834 if (ldap_set_option (*ldap_struct, LDAP_OPT_DEREF, &deref) != LDAP_OPT_SUCCESS) {
835 DEBUG(1,("smbldap_open_connection: Failed to set dereferencing method: %d\n", deref));
836 } else {
837 DEBUG(5,("Set dereferencing method: %d\n", deref));
841 DEBUG(2, ("smbldap_open_connection: connection opened\n"));
842 return rc;
845 /*******************************************************************
846 a rebind function for authenticated referrals
847 This version takes a void* that we can shove useful stuff in :-)
848 ******************************************************************/
849 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
850 #else
851 static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
852 int *methodp, int freeit, void *arg)
854 struct smbldap_state *ldap_state = arg;
855 struct timespec ts;
857 /** @TODO Should we be doing something to check what servers we rebind to?
858 Could we get a referral to a machine that we don't want to give our
859 username and password to? */
861 if (freeit) {
862 SAFE_FREE(*whop);
863 if (*credp) {
864 memset(*credp, '\0', strlen(*credp));
866 SAFE_FREE(*credp);
867 } else {
868 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
869 ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
871 if (ldap_state->anonymous) {
872 *whop = NULL;
873 *credp = NULL;
874 } else {
875 *whop = SMB_STRDUP(ldap_state->bind_dn);
876 if (!*whop) {
877 return LDAP_NO_MEMORY;
879 *credp = SMB_STRDUP(ldap_state->bind_secret);
880 if (!*credp) {
881 SAFE_FREE(*whop);
882 return LDAP_NO_MEMORY;
885 *methodp = LDAP_AUTH_SIMPLE;
888 clock_gettime_mono(&ts);
889 ldap_state->last_rebind = convert_timespec_to_timeval(ts);
891 return 0;
893 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
895 /*******************************************************************
896 a rebind function for authenticated referrals
897 This version takes a void* that we can shove useful stuff in :-)
898 and actually does the connection.
899 ******************************************************************/
900 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
901 static int rebindproc_connect_with_state (LDAP *ldap_struct,
902 LDAP_CONST char *url,
903 ber_tag_t request,
904 ber_int_t msgid, void *arg)
906 struct smbldap_state *ldap_state =
907 (struct smbldap_state *)arg;
908 int rc;
909 struct timespec ts;
910 int version;
912 DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n",
913 url, ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
915 /* call START_TLS again (ldaps:// is handled by the OpenLDAP library
916 * itself) before rebinding to another LDAP server to avoid to expose
917 * our credentials. At least *try* to secure the connection - Guenther */
919 smb_ldap_upgrade_conn(ldap_struct, &version);
920 smbldap_start_tls(ldap_struct, version);
922 /** @TODO Should we be doing something to check what servers we rebind to?
923 Could we get a referral to a machine that we don't want to give our
924 username and password to? */
926 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
928 /* only set the last rebind timestamp when we did rebind after a
929 * non-read LDAP operation. That way we avoid the replication sleep
930 * after a simple redirected search operation - Guenther */
932 switch (request) {
934 case LDAP_REQ_MODIFY:
935 case LDAP_REQ_ADD:
936 case LDAP_REQ_DELETE:
937 case LDAP_REQ_MODDN:
938 case LDAP_REQ_EXTENDED:
939 DEBUG(10,("rebindproc_connect_with_state: "
940 "setting last_rebind timestamp "
941 "(req: 0x%02x)\n", (unsigned int)request));
942 clock_gettime_mono(&ts);
943 ldap_state->last_rebind = convert_timespec_to_timeval(ts);
944 break;
945 default:
946 ZERO_STRUCT(ldap_state->last_rebind);
947 break;
950 return rc;
952 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
954 /*******************************************************************
955 Add a rebind function for authenticated referrals
956 ******************************************************************/
957 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
958 #else
959 # if LDAP_SET_REBIND_PROC_ARGS == 2
960 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
961 int *method, int freeit )
963 struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
965 return rebindproc_with_state(ldap_struct, whop, credp,
966 method, freeit, ldap_state);
968 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
969 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
971 /*******************************************************************
972 a rebind function for authenticated referrals
973 this also does the connection, but no void*.
974 ******************************************************************/
975 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
976 # if LDAP_SET_REBIND_PROC_ARGS == 2
977 static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
978 ber_int_t msgid)
980 struct smbldap_state *ldap_state = smbldap_find_state(ld);
982 return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
983 ldap_state);
985 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
986 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
988 /*******************************************************************
989 connect to the ldap server under system privilege.
990 ******************************************************************/
991 static int smbldap_connect_system(struct smbldap_state *ldap_state)
993 LDAP *ldap_struct = smbldap_get_ldap(ldap_state);
994 int rc;
995 int version;
997 /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
998 (OpenLDAP) doesn't seem to support it */
1000 DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
1001 ldap_state->uri, ldap_state->bind_dn));
1003 #ifdef HAVE_LDAP_SET_REBIND_PROC
1004 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1005 # if LDAP_SET_REBIND_PROC_ARGS == 2
1006 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
1007 # endif
1008 # if LDAP_SET_REBIND_PROC_ARGS == 3
1009 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
1010 # endif
1011 #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
1012 # if LDAP_SET_REBIND_PROC_ARGS == 2
1013 ldap_set_rebind_proc(ldap_struct, &rebindproc);
1014 # endif
1015 # if LDAP_SET_REBIND_PROC_ARGS == 3
1016 ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
1017 # endif
1018 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
1019 #endif
1021 /* When there is an alternative bind callback is set,
1022 attempt to use it to perform the bind */
1023 if (ldap_state->bind_callback != NULL) {
1024 /* We have to allow bind callback to be run under become_root/unbecome_root
1025 to make sure within smbd the callback has proper write access to its resources,
1026 like credential cache. This is similar to passdb case where this callback is supposed
1027 to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
1029 become_root();
1030 rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
1031 unbecome_root();
1032 } else {
1033 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
1036 if (rc != LDAP_SUCCESS) {
1037 char *ld_error = NULL;
1038 ldap_get_option(smbldap_get_ldap(ldap_state),
1039 LDAP_OPT_ERROR_STRING,
1040 &ld_error);
1041 DEBUG(ldap_state->num_failures ? 2 : 0,
1042 ("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
1043 ldap_state->uri,
1044 ldap_state->bind_dn ? ldap_state->bind_dn : "[Anonymous bind]",
1045 ldap_err2string(rc),
1046 ld_error ? ld_error : "(unknown)"));
1047 SAFE_FREE(ld_error);
1048 ldap_state->num_failures++;
1049 goto done;
1052 ldap_state->num_failures = 0;
1053 ldap_state->paged_results = False;
1055 ldap_get_option(smbldap_get_ldap(ldap_state),
1056 LDAP_OPT_PROTOCOL_VERSION, &version);
1058 if (smbldap_has_control(smbldap_get_ldap(ldap_state), ADS_PAGE_CTL_OID)
1059 && version == 3) {
1060 ldap_state->paged_results = True;
1063 DEBUG(3, ("ldap_connect_system: successful connection to the LDAP server\n"));
1064 DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n",
1065 ldap_state->paged_results ? "does" : "does not"));
1066 done:
1067 if (rc != 0) {
1068 ldap_unbind(ldap_struct);
1069 ldap_state->ldap_struct = NULL;
1071 return rc;
1074 static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
1075 struct tevent_timer *te,
1076 struct timeval now_abs,
1077 void *private_data);
1079 /**********************************************************************
1080 Connect to LDAP server (called before every ldap operation)
1081 *********************************************************************/
1082 static int smbldap_open(struct smbldap_state *ldap_state)
1084 int rc, opt_rc;
1085 bool reopen = False;
1086 SMB_ASSERT(ldap_state);
1088 if ((smbldap_get_ldap(ldap_state) != NULL) &&
1089 ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) <
1090 time_mono(NULL))) {
1092 #ifdef HAVE_UNIXSOCKET
1093 struct sockaddr_un addr;
1094 #else
1095 struct sockaddr_storage addr;
1096 #endif
1097 socklen_t len = sizeof(addr);
1098 int sd;
1100 opt_rc = ldap_get_option(smbldap_get_ldap(ldap_state),
1101 LDAP_OPT_DESC, &sd);
1102 if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
1103 reopen = True;
1105 #ifdef HAVE_UNIXSOCKET
1106 if (opt_rc == 0 && addr.sun_family == AF_UNIX)
1107 reopen = True;
1108 #endif
1109 if (reopen) {
1110 /* the other end has died. reopen. */
1111 ldap_unbind(smbldap_get_ldap(ldap_state));
1112 ldap_state->ldap_struct = NULL;
1113 ldap_state->last_ping = (time_t)0;
1114 } else {
1115 ldap_state->last_ping = time_mono(NULL);
1119 if (smbldap_get_ldap(ldap_state) != NULL) {
1120 DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
1121 return LDAP_SUCCESS;
1124 if ((rc = smbldap_open_connection(ldap_state))) {
1125 return rc;
1128 if ((rc = smbldap_connect_system(ldap_state))) {
1129 return rc;
1133 ldap_state->last_ping = time_mono(NULL);
1134 ldap_state->pid = getpid();
1136 TALLOC_FREE(ldap_state->idle_event);
1138 if (ldap_state->tevent_context != NULL) {
1139 ldap_state->idle_event = tevent_add_timer(
1140 ldap_state->tevent_context, ldap_state,
1141 timeval_current_ofs(SMBLDAP_IDLE_TIME, 0),
1142 smbldap_idle_fn, ldap_state);
1145 DEBUG(4,("The LDAP server is successfully connected\n"));
1147 return LDAP_SUCCESS;
1150 /**********************************************************************
1151 Disconnect from LDAP server
1152 *********************************************************************/
1153 static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
1155 if (!ldap_state)
1156 return NT_STATUS_INVALID_PARAMETER;
1158 if (smbldap_get_ldap(ldap_state) != NULL) {
1159 ldap_unbind(smbldap_get_ldap(ldap_state));
1160 ldap_state->ldap_struct = NULL;
1163 smbldap_delete_state(ldap_state);
1165 TALLOC_FREE(ldap_state->idle_event);
1167 DEBUG(5,("The connection to the LDAP server was closed\n"));
1168 /* maybe free the results here --metze */
1170 return NT_STATUS_OK;
1173 static SIG_ATOMIC_T got_alarm;
1175 static void gotalarm_sig(int dummy)
1177 got_alarm = 1;
1180 static time_t calc_ldap_abs_endtime(int ldap_to)
1182 if (ldap_to == 0) {
1183 /* No timeout - don't
1184 return a value for
1185 the alarm. */
1186 return (time_t)0;
1189 /* Make the alarm time one second beyond
1190 the timout we're setting for the
1191 remote search timeout, to allow that
1192 to fire in preference. */
1194 return time_mono(NULL)+ldap_to+1;
1197 static int end_ldap_local_alarm(time_t absolute_endtime, int rc)
1199 if (absolute_endtime) {
1200 alarm(0);
1201 CatchSignal(SIGALRM, SIG_IGN);
1202 if (got_alarm) {
1203 /* Client timeout error code. */
1204 got_alarm = 0;
1205 return LDAP_TIMEOUT;
1208 return rc;
1211 static void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t absolute_endtime)
1213 time_t now = time_mono(NULL);
1215 if (absolute_endtime) {
1216 got_alarm = 0;
1217 CatchSignal(SIGALRM, gotalarm_sig);
1218 alarm(absolute_endtime - now);
1221 if (ldap_state->pid != getpid()) {
1222 smbldap_close(ldap_state);
1226 static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
1228 ldap_get_option(smbldap_get_ldap(ldap_state),
1229 LDAP_OPT_ERROR_NUMBER, p_ld_errno);
1231 ldap_get_option(smbldap_get_ldap(ldap_state),
1232 LDAP_OPT_ERROR_STRING, pp_ld_error);
1235 static int get_cached_ldap_connect(struct smbldap_state *ldap_state, time_t abs_endtime)
1237 int attempts = 0;
1239 while (1) {
1240 int rc;
1241 time_t now;
1243 now = time_mono(NULL);
1244 ldap_state->last_use = now;
1246 if (abs_endtime && now > abs_endtime) {
1247 smbldap_close(ldap_state);
1248 return LDAP_TIMEOUT;
1251 rc = smbldap_open(ldap_state);
1253 if (rc == LDAP_SUCCESS) {
1254 return LDAP_SUCCESS;
1257 attempts++;
1258 DEBUG(1, ("Connection to LDAP server failed for the "
1259 "%d try!\n", attempts));
1261 if (rc == LDAP_INSUFFICIENT_ACCESS) {
1262 /* The fact that we are non-root or any other
1263 * access-denied condition will not change in the next
1264 * round of trying */
1265 return rc;
1268 if (got_alarm) {
1269 smbldap_close(ldap_state);
1270 return LDAP_TIMEOUT;
1273 smb_msleep(1000);
1275 if (got_alarm) {
1276 smbldap_close(ldap_state);
1277 return LDAP_TIMEOUT;
1282 /*********************************************************************
1283 ********************************************************************/
1285 static int smbldap_search_ext(struct smbldap_state *ldap_state,
1286 const char *base, int scope, const char *filter,
1287 const char *attrs[], int attrsonly,
1288 LDAPControl **sctrls, LDAPControl **cctrls,
1289 int sizelimit, LDAPMessage **res)
1291 int rc = LDAP_SERVER_DOWN;
1292 char *utf8_filter;
1293 int to = lp_ldap_timeout();
1294 time_t abs_endtime = calc_ldap_abs_endtime(to);
1295 struct timeval timeout;
1296 struct timeval *timeout_ptr = NULL;
1297 size_t converted_size;
1299 SMB_ASSERT(ldap_state);
1301 DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], "
1302 "scope => [%d]\n", base, filter, scope));
1304 if (ldap_state->last_rebind.tv_sec > 0) {
1305 struct timeval tval;
1306 struct timespec ts;
1307 int64_t tdiff = 0;
1308 int sleep_time = 0;
1310 clock_gettime_mono(&ts);
1311 tval = convert_timespec_to_timeval(ts);
1313 tdiff = usec_time_diff(&tval, &ldap_state->last_rebind);
1314 tdiff /= 1000; /* Convert to milliseconds. */
1316 sleep_time = lp_ldap_replication_sleep()-(int)tdiff;
1317 sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME);
1319 if (sleep_time > 0) {
1320 /* we wait for the LDAP replication */
1321 DEBUG(5,("smbldap_search_ext: waiting %d milliseconds "
1322 "for LDAP replication.\n",sleep_time));
1323 smb_msleep(sleep_time);
1324 DEBUG(5,("smbldap_search_ext: go on!\n"));
1326 ZERO_STRUCT(ldap_state->last_rebind);
1329 if (!push_utf8_talloc(talloc_tos(), &utf8_filter, filter, &converted_size)) {
1330 return LDAP_NO_MEMORY;
1333 /* Setup remote timeout for the ldap_search_ext_s call. */
1334 if (to) {
1335 timeout.tv_sec = to;
1336 timeout.tv_usec = 0;
1337 timeout_ptr = &timeout;
1340 setup_ldap_local_alarm(ldap_state, abs_endtime);
1342 while (1) {
1343 char *ld_error = NULL;
1344 int ld_errno;
1346 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1347 if (rc != LDAP_SUCCESS) {
1348 break;
1351 rc = ldap_search_ext_s(smbldap_get_ldap(ldap_state),
1352 base, scope,
1353 utf8_filter,
1354 discard_const_p(char *, attrs),
1355 attrsonly, sctrls, cctrls, timeout_ptr,
1356 sizelimit, res);
1357 if (rc == LDAP_SUCCESS) {
1358 break;
1361 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1363 DEBUG(10, ("Failed search for base: %s, error: %d (%s) "
1364 "(%s)\n", base, ld_errno,
1365 ldap_err2string(rc),
1366 ld_error ? ld_error : "unknown"));
1367 SAFE_FREE(ld_error);
1369 if (ld_errno != LDAP_SERVER_DOWN) {
1370 break;
1372 ldap_unbind(smbldap_get_ldap(ldap_state));
1373 ldap_state->ldap_struct = NULL;
1376 TALLOC_FREE(utf8_filter);
1377 return end_ldap_local_alarm(abs_endtime, rc);
1380 int smbldap_search(struct smbldap_state *ldap_state,
1381 const char *base, int scope, const char *filter,
1382 const char *attrs[], int attrsonly,
1383 LDAPMessage **res)
1385 return smbldap_search_ext(ldap_state, base, scope, filter, attrs,
1386 attrsonly, NULL, NULL, LDAP_NO_LIMIT, res);
1389 int smbldap_search_paged(struct smbldap_state *ldap_state,
1390 const char *base, int scope, const char *filter,
1391 const char **attrs, int attrsonly, int pagesize,
1392 LDAPMessage **res, void **cookie)
1394 LDAPControl pr;
1395 LDAPControl **rcontrols;
1396 LDAPControl *controls[2] = { NULL, NULL};
1397 BerElement *cookie_be = NULL;
1398 struct berval *cookie_bv = NULL;
1399 int tmp = 0, i, rc;
1400 bool critical = True;
1402 *res = NULL;
1404 DEBUG(3,("smbldap_search_paged: base => [%s], filter => [%s],"
1405 "scope => [%d], pagesize => [%d]\n",
1406 base, filter, scope, pagesize));
1408 cookie_be = ber_alloc_t(LBER_USE_DER);
1409 if (cookie_be == NULL) {
1410 DEBUG(0,("smbldap_create_page_control: ber_alloc_t returns "
1411 "NULL\n"));
1412 return LDAP_NO_MEMORY;
1415 /* construct cookie */
1416 if (*cookie != NULL) {
1417 ber_printf(cookie_be, "{iO}", (ber_int_t) pagesize, *cookie);
1418 ber_bvfree((struct berval *)*cookie); /* don't need it from last time */
1419 *cookie = NULL;
1420 } else {
1421 ber_printf(cookie_be, "{io}", (ber_int_t) pagesize, "", 0);
1423 ber_flatten(cookie_be, &cookie_bv);
1425 pr.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID);
1426 pr.ldctl_iscritical = (char) critical;
1427 pr.ldctl_value.bv_len = cookie_bv->bv_len;
1428 pr.ldctl_value.bv_val = cookie_bv->bv_val;
1430 controls[0] = &pr;
1431 controls[1] = NULL;
1433 rc = smbldap_search_ext(ldap_state, base, scope, filter, attrs,
1434 0, controls, NULL, LDAP_NO_LIMIT, res);
1436 ber_free(cookie_be, 1);
1437 ber_bvfree(cookie_bv);
1439 if (rc != 0) {
1440 DEBUG(3,("smbldap_search_paged: smbldap_search_ext(%s) "
1441 "failed with [%s]\n", filter, ldap_err2string(rc)));
1442 goto done;
1445 DEBUG(3,("smbldap_search_paged: search was successful\n"));
1447 rc = ldap_parse_result(smbldap_get_ldap(ldap_state), *res, NULL, NULL,
1448 NULL, NULL, &rcontrols, 0);
1449 if (rc != 0) {
1450 DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
1451 "with [%s]\n", ldap_err2string(rc)));
1452 goto done;
1455 if (rcontrols == NULL)
1456 goto done;
1458 for (i=0; rcontrols[i]; i++) {
1460 if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) != 0)
1461 continue;
1463 cookie_be = ber_init(&rcontrols[i]->ldctl_value);
1464 ber_scanf(cookie_be,"{iO}", &tmp, &cookie_bv);
1465 /* the berval is the cookie, but must be freed when it is all
1466 done */
1467 if (cookie_bv->bv_len)
1468 *cookie=ber_bvdup(cookie_bv);
1469 else
1470 *cookie=NULL;
1471 ber_bvfree(cookie_bv);
1472 ber_free(cookie_be, 1);
1473 break;
1475 ldap_controls_free(rcontrols);
1476 done:
1477 return rc;
1480 int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
1482 int rc = LDAP_SERVER_DOWN;
1483 char *utf8_dn;
1484 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1485 size_t converted_size;
1487 SMB_ASSERT(ldap_state);
1489 DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
1491 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1492 return LDAP_NO_MEMORY;
1495 setup_ldap_local_alarm(ldap_state, abs_endtime);
1497 while (1) {
1498 char *ld_error = NULL;
1499 int ld_errno;
1501 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1502 if (rc != LDAP_SUCCESS) {
1503 break;
1506 rc = ldap_modify_s(smbldap_get_ldap(ldap_state), utf8_dn,
1507 attrs);
1508 if (rc == LDAP_SUCCESS) {
1509 break;
1512 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1514 DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) "
1515 "(%s)\n", dn, ld_errno,
1516 ldap_err2string(rc),
1517 ld_error ? ld_error : "unknown"));
1518 SAFE_FREE(ld_error);
1520 if (ld_errno != LDAP_SERVER_DOWN) {
1521 break;
1523 ldap_unbind(smbldap_get_ldap(ldap_state));
1524 ldap_state->ldap_struct = NULL;
1527 TALLOC_FREE(utf8_dn);
1528 return end_ldap_local_alarm(abs_endtime, rc);
1531 int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
1533 int rc = LDAP_SERVER_DOWN;
1534 char *utf8_dn;
1535 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1536 size_t converted_size;
1538 SMB_ASSERT(ldap_state);
1540 DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
1542 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1543 return LDAP_NO_MEMORY;
1546 setup_ldap_local_alarm(ldap_state, abs_endtime);
1548 while (1) {
1549 char *ld_error = NULL;
1550 int ld_errno;
1552 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1553 if (rc != LDAP_SUCCESS) {
1554 break;
1557 rc = ldap_add_s(smbldap_get_ldap(ldap_state), utf8_dn, attrs);
1558 if (rc == LDAP_SUCCESS) {
1559 break;
1562 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1564 DEBUG(10, ("Failed to add dn: %s, error: %d (%s) "
1565 "(%s)\n", dn, ld_errno,
1566 ldap_err2string(rc),
1567 ld_error ? ld_error : "unknown"));
1568 SAFE_FREE(ld_error);
1570 if (ld_errno != LDAP_SERVER_DOWN) {
1571 break;
1573 ldap_unbind(smbldap_get_ldap(ldap_state));
1574 ldap_state->ldap_struct = NULL;
1577 TALLOC_FREE(utf8_dn);
1578 return end_ldap_local_alarm(abs_endtime, rc);
1581 int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
1583 int rc = LDAP_SERVER_DOWN;
1584 char *utf8_dn;
1585 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1586 size_t converted_size;
1588 SMB_ASSERT(ldap_state);
1590 DEBUG(5,("smbldap_delete: dn => [%s]\n", dn ));
1592 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1593 return LDAP_NO_MEMORY;
1596 setup_ldap_local_alarm(ldap_state, abs_endtime);
1598 while (1) {
1599 char *ld_error = NULL;
1600 int ld_errno;
1602 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1603 if (rc != LDAP_SUCCESS) {
1604 break;
1607 rc = ldap_delete_s(smbldap_get_ldap(ldap_state), utf8_dn);
1608 if (rc == LDAP_SUCCESS) {
1609 break;
1612 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1614 DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) "
1615 "(%s)\n", dn, ld_errno,
1616 ldap_err2string(rc),
1617 ld_error ? ld_error : "unknown"));
1618 SAFE_FREE(ld_error);
1620 if (ld_errno != LDAP_SERVER_DOWN) {
1621 break;
1623 ldap_unbind(smbldap_get_ldap(ldap_state));
1624 ldap_state->ldap_struct = NULL;
1627 TALLOC_FREE(utf8_dn);
1628 return end_ldap_local_alarm(abs_endtime, rc);
1631 int smbldap_extended_operation(struct smbldap_state *ldap_state,
1632 LDAP_CONST char *reqoid, struct berval *reqdata,
1633 LDAPControl **serverctrls, LDAPControl **clientctrls,
1634 char **retoidp, struct berval **retdatap)
1636 int rc = LDAP_SERVER_DOWN;
1637 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1639 if (!ldap_state)
1640 return (-1);
1642 setup_ldap_local_alarm(ldap_state, abs_endtime);
1644 while (1) {
1645 char *ld_error = NULL;
1646 int ld_errno;
1648 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1649 if (rc != LDAP_SUCCESS) {
1650 break;
1653 rc = ldap_extended_operation_s(smbldap_get_ldap(ldap_state),
1654 reqoid,
1655 reqdata, serverctrls,
1656 clientctrls, retoidp, retdatap);
1657 if (rc == LDAP_SUCCESS) {
1658 break;
1661 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1663 DEBUG(10, ("Extended operation failed with error: "
1664 "%d (%s) (%s)\n", ld_errno,
1665 ldap_err2string(rc),
1666 ld_error ? ld_error : "unknown"));
1667 SAFE_FREE(ld_error);
1669 if (ld_errno != LDAP_SERVER_DOWN) {
1670 break;
1672 ldap_unbind(smbldap_get_ldap(ldap_state));
1673 ldap_state->ldap_struct = NULL;
1676 return end_ldap_local_alarm(abs_endtime, rc);
1679 /*******************************************************************
1680 run the search by name.
1681 ******************************************************************/
1682 int smbldap_search_suffix (struct smbldap_state *ldap_state,
1683 const char *filter, const char **search_attr,
1684 LDAPMessage ** result)
1686 return smbldap_search(ldap_state, lp_ldap_suffix(talloc_tos()),
1687 LDAP_SCOPE_SUBTREE,
1688 filter, search_attr, 0, result);
1691 static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
1692 struct tevent_timer *te,
1693 struct timeval now_abs,
1694 void *private_data)
1696 struct smbldap_state *state = (struct smbldap_state *)private_data;
1698 TALLOC_FREE(state->idle_event);
1700 if (smbldap_get_ldap(state) == NULL) {
1701 DEBUG(10,("ldap connection not connected...\n"));
1702 return;
1705 if ((state->last_use+SMBLDAP_IDLE_TIME) > time_mono(NULL)) {
1706 DEBUG(10,("ldap connection not idle...\n"));
1708 /* this needs to be made monotonic clock aware inside tevent: */
1709 state->idle_event = tevent_add_timer(
1710 tevent_ctx, state,
1711 timeval_add(&now_abs, SMBLDAP_IDLE_TIME, 0),
1712 smbldap_idle_fn,
1713 private_data);
1714 return;
1717 DEBUG(7,("ldap connection idle...closing connection\n"));
1718 smbldap_close(state);
1721 /**********************************************************************
1722 Housekeeping
1723 *********************************************************************/
1725 void smbldap_free_struct(struct smbldap_state **ldap_state)
1727 smbldap_close(*ldap_state);
1729 if ((*ldap_state)->bind_secret) {
1730 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
1733 SAFE_FREE((*ldap_state)->bind_dn);
1734 SAFE_FREE((*ldap_state)->bind_secret);
1735 smbldap_set_bind_callback(*ldap_state, NULL, NULL);
1737 TALLOC_FREE(*ldap_state);
1739 /* No need to free any further, as it is talloc()ed */
1742 static int smbldap_state_destructor(struct smbldap_state *state)
1744 smbldap_free_struct(&state);
1745 return 0;
1749 /**********************************************************************
1750 Intitalise the 'general' ldap structures, on which ldap operations may be conducted
1751 *********************************************************************/
1753 NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct tevent_context *tevent_ctx,
1754 const char *location,
1755 bool anon,
1756 const char *bind_dn,
1757 const char *bind_secret,
1758 struct smbldap_state **smbldap_state)
1760 *smbldap_state = talloc_zero(mem_ctx, struct smbldap_state);
1761 if (!*smbldap_state) {
1762 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
1763 return NT_STATUS_NO_MEMORY;
1766 if (location) {
1767 (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
1768 } else {
1769 (*smbldap_state)->uri = "ldap://localhost";
1772 (*smbldap_state)->tevent_context = tevent_ctx;
1774 if (bind_dn && bind_secret) {
1775 smbldap_set_creds(*smbldap_state, anon, bind_dn, bind_secret);
1778 talloc_set_destructor(*smbldap_state, smbldap_state_destructor);
1779 return NT_STATUS_OK;
1782 char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld,
1783 LDAPMessage *entry)
1785 char *utf8_dn, *unix_dn;
1786 size_t converted_size;
1788 utf8_dn = ldap_get_dn(ld, entry);
1789 if (!utf8_dn) {
1790 DEBUG (5, ("smbldap_talloc_dn: ldap_get_dn failed\n"));
1791 return NULL;
1793 if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
1794 DEBUG (0, ("smbldap_talloc_dn: String conversion failure utf8 "
1795 "[%s]\n", utf8_dn));
1796 return NULL;
1798 ldap_memfree(utf8_dn);
1799 return unix_dn;
1802 /*******************************************************************
1803 Check if root-dse has a certain Control or Extension
1804 ********************************************************************/
1806 static bool smbldap_check_root_dse(LDAP *ld, const char **attrs, const char *value)
1808 LDAPMessage *msg = NULL;
1809 LDAPMessage *entry = NULL;
1810 char **values = NULL;
1811 int rc, num_result, num_values, i;
1812 bool result = False;
1814 if (!attrs[0]) {
1815 DEBUG(3,("smbldap_check_root_dse: nothing to look for\n"));
1816 return False;
1819 if (!strequal(attrs[0], "supportedExtension") &&
1820 !strequal(attrs[0], "supportedControl") &&
1821 !strequal(attrs[0], "namingContexts")) {
1822 DEBUG(3,("smbldap_check_root_dse: no idea what to query root-dse for: %s ?\n", attrs[0]));
1823 return False;
1826 rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE,
1827 "(objectclass=*)", discard_const_p(char *, attrs), 0 , &msg);
1829 if (rc != LDAP_SUCCESS) {
1830 DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n"));
1831 return False;
1834 num_result = ldap_count_entries(ld, msg);
1836 if (num_result != 1) {
1837 DEBUG(3,("smbldap_check_root_dse: Expected one rootDSE, got %d\n", num_result));
1838 goto done;
1841 entry = ldap_first_entry(ld, msg);
1843 if (entry == NULL) {
1844 DEBUG(3,("smbldap_check_root_dse: Could not retrieve rootDSE\n"));
1845 goto done;
1848 values = ldap_get_values(ld, entry, attrs[0]);
1850 if (values == NULL) {
1851 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not support any %s\n", attrs[0]));
1852 goto done;
1855 num_values = ldap_count_values(values);
1857 if (num_values == 0) {
1858 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not have any %s\n", attrs[0]));
1859 goto done;
1862 for (i=0; i<num_values; i++) {
1863 if (strcmp(values[i], value) == 0)
1864 result = True;
1868 done:
1869 if (values != NULL)
1870 ldap_value_free(values);
1871 if (msg != NULL)
1872 ldap_msgfree(msg);
1874 return result;
1878 /*******************************************************************
1879 Check if LDAP-Server supports a certain Control (OID in string format)
1880 ********************************************************************/
1882 bool smbldap_has_control(LDAP *ld, const char *control)
1884 const char *attrs[] = { "supportedControl", NULL };
1885 return smbldap_check_root_dse(ld, attrs, control);
1888 /*******************************************************************
1889 Check if LDAP-Server supports a certain Extension (OID in string format)
1890 ********************************************************************/
1892 bool smbldap_has_extension(LDAP *ld, const char *extension)
1894 const char *attrs[] = { "supportedExtension", NULL };
1895 return smbldap_check_root_dse(ld, attrs, extension);
1898 /*******************************************************************
1899 Check if LDAP-Server holds a given namingContext
1900 ********************************************************************/
1902 bool smbldap_has_naming_context(LDAP *ld, const char *naming_context)
1904 const char *attrs[] = { "namingContexts", NULL };
1905 return smbldap_check_root_dse(ld, attrs, naming_context);
1908 bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *dn, const char *secret)
1910 ldap_state->anonymous = anon;
1912 /* free any previously set credential */
1914 SAFE_FREE(ldap_state->bind_dn);
1915 smbldap_set_bind_callback(ldap_state, NULL, NULL);
1917 if (ldap_state->bind_secret) {
1918 /* make sure secrets are zeroed out of memory */
1919 memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));
1920 SAFE_FREE(ldap_state->bind_secret);
1923 if ( ! anon) {
1924 ldap_state->bind_dn = SMB_STRDUP(dn);
1925 ldap_state->bind_secret = SMB_STRDUP(secret);
1928 return True;