script/autobuild.py: add support git worktree
[Samba.git] / source3 / lib / smbldap.c
blob34c841f92434753096747cbd0488b598ca0f10b3
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 ssize_t 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 != -1);
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,tls;
608 #endif
610 if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
611 return LDAP_SUCCESS;
614 #ifdef LDAP_OPT_X_TLS
615 /* check if we use ldaps already */
616 ldap_get_option(ldap_struct, LDAP_OPT_X_TLS, &tls);
617 if (tls == LDAP_OPT_X_TLS_HARD) {
618 return LDAP_SUCCESS;
621 if (version != LDAP_VERSION3) {
622 DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
623 return LDAP_OPERATIONS_ERROR;
626 if ((rc = ldap_start_tls_s (ldap_struct, NULL, NULL)) != LDAP_SUCCESS) {
627 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
628 ldap_err2string(rc)));
629 return rc;
632 DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
633 return LDAP_SUCCESS;
634 #else
635 DEBUG(0,("StartTLS not supported by LDAP client libraries!\n"));
636 return LDAP_OPERATIONS_ERROR;
637 #endif
640 /********************************************************************
641 setup a connection to the LDAP server based on a uri
642 *******************************************************************/
644 static int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri)
646 int rc;
648 DEBUG(10, ("smb_ldap_setup_connection: %s\n", uri));
650 #ifdef HAVE_LDAP_INITIALIZE
652 rc = ldap_initialize(ldap_struct, uri);
653 if (rc) {
654 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
655 return rc;
658 if (lp_ldap_follow_referral() != Auto) {
659 rc = ldap_set_option(*ldap_struct, LDAP_OPT_REFERRALS,
660 lp_ldap_follow_referral() ? LDAP_OPT_ON : LDAP_OPT_OFF);
661 if (rc != LDAP_SUCCESS)
662 DEBUG(0, ("Failed to set LDAP_OPT_REFERRALS: %s\n",
663 ldap_err2string(rc)));
666 return LDAP_SUCCESS;
667 #else
669 /* Parse the string manually */
672 int port = 0;
673 fstring protocol;
674 fstring host;
675 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
678 /* skip leading "URL:" (if any) */
679 if ( strnequal( uri, "URL:", 4 ) ) {
680 uri += 4;
683 sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
685 if (port == 0) {
686 if (strequal(protocol, "ldap")) {
687 port = LDAP_PORT;
688 } else if (strequal(protocol, "ldaps")) {
689 port = LDAPS_PORT;
690 } else {
691 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
695 if ((*ldap_struct = ldap_init(host, port)) == NULL) {
696 DEBUG(0, ("ldap_init failed !\n"));
697 return LDAP_OPERATIONS_ERROR;
700 if (strequal(protocol, "ldaps")) {
701 #ifdef LDAP_OPT_X_TLS
702 int tls = LDAP_OPT_X_TLS_HARD;
703 if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
705 DEBUG(0, ("Failed to setup a TLS session\n"));
708 DEBUG(3,("LDAPS option set...!\n"));
709 #else
710 DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
711 return LDAP_OPERATIONS_ERROR;
712 #endif /* LDAP_OPT_X_TLS */
715 #endif /* HAVE_LDAP_INITIALIZE */
717 /* now set connection timeout */
718 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT /* Netscape */
720 int ct = lp_ldap_connection_timeout()*1000;
721 rc = ldap_set_option(*ldap_struct, LDAP_X_OPT_CONNECT_TIMEOUT, &ct);
722 if (rc != LDAP_SUCCESS) {
723 DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
724 ct, ldap_err2string(rc)));
727 #elif defined (LDAP_OPT_NETWORK_TIMEOUT) /* OpenLDAP */
729 struct timeval ct;
730 ct.tv_usec = 0;
731 ct.tv_sec = lp_ldap_connection_timeout();
732 rc = ldap_set_option(*ldap_struct, LDAP_OPT_NETWORK_TIMEOUT, &ct);
733 if (rc != LDAP_SUCCESS) {
734 DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
735 (int)ct.tv_sec, ldap_err2string(rc)));
738 #endif
740 return LDAP_SUCCESS;
743 /********************************************************************
744 try to upgrade to Version 3 LDAP if not already, in either case return current
745 version
746 *******************************************************************/
748 static int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
750 int version;
751 int rc;
753 /* assume the worst */
754 *new_version = LDAP_VERSION2;
756 rc = ldap_get_option(ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
757 if (rc) {
758 return rc;
761 if (version == LDAP_VERSION3) {
762 *new_version = LDAP_VERSION3;
763 return LDAP_SUCCESS;
766 /* try upgrade */
767 version = LDAP_VERSION3;
768 rc = ldap_set_option (ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
769 if (rc) {
770 return rc;
773 *new_version = LDAP_VERSION3;
774 return LDAP_SUCCESS;
777 /*******************************************************************
778 open a connection to the ldap server (just until the bind)
779 ******************************************************************/
781 int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
783 int rc, version;
785 rc = smb_ldap_setup_conn(ldap_struct, uri);
786 if (rc) {
787 return rc;
790 rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
791 if (rc) {
792 return rc;
795 rc = smbldap_start_tls(*ldap_struct, version);
796 if (rc) {
797 return rc;
800 return LDAP_SUCCESS;
803 /*******************************************************************
804 open a connection to the ldap server.
805 ******************************************************************/
806 static int smbldap_open_connection (struct smbldap_state *ldap_state)
809 int rc = LDAP_SUCCESS;
810 int version;
811 int deref;
812 LDAP **ldap_struct = &ldap_state->ldap_struct;
814 rc = smb_ldap_setup_conn(ldap_struct, ldap_state->uri);
815 if (rc) {
816 return rc;
819 /* Store the LDAP pointer in a lookup list */
821 smbldap_store_state(*ldap_struct, ldap_state);
823 /* Upgrade to LDAPv3 if possible */
825 rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
826 if (rc) {
827 return rc;
830 /* Start TLS if required */
832 rc = smbldap_start_tls(*ldap_struct, version);
833 if (rc) {
834 return rc;
837 /* Set alias dereferencing method */
838 deref = lp_ldap_deref();
839 if (deref != -1) {
840 if (ldap_set_option (*ldap_struct, LDAP_OPT_DEREF, &deref) != LDAP_OPT_SUCCESS) {
841 DEBUG(1,("smbldap_open_connection: Failed to set dereferencing method: %d\n", deref));
842 } else {
843 DEBUG(5,("Set dereferencing method: %d\n", deref));
847 DEBUG(2, ("smbldap_open_connection: connection opened\n"));
848 return rc;
851 /*******************************************************************
852 a rebind function for authenticated referrals
853 This version takes a void* that we can shove useful stuff in :-)
854 ******************************************************************/
855 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
856 #else
857 static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
858 int *methodp, int freeit, void *arg)
860 struct smbldap_state *ldap_state = arg;
861 struct timespec ts;
863 /** @TODO Should we be doing something to check what servers we rebind to?
864 Could we get a referral to a machine that we don't want to give our
865 username and password to? */
867 if (freeit) {
868 SAFE_FREE(*whop);
869 if (*credp) {
870 memset(*credp, '\0', strlen(*credp));
872 SAFE_FREE(*credp);
873 } else {
874 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
875 ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
877 if (ldap_state->anonymous) {
878 *whop = NULL;
879 *credp = NULL;
880 } else {
881 *whop = SMB_STRDUP(ldap_state->bind_dn);
882 if (!*whop) {
883 return LDAP_NO_MEMORY;
885 *credp = SMB_STRDUP(ldap_state->bind_secret);
886 if (!*credp) {
887 SAFE_FREE(*whop);
888 return LDAP_NO_MEMORY;
891 *methodp = LDAP_AUTH_SIMPLE;
894 clock_gettime_mono(&ts);
895 ldap_state->last_rebind = convert_timespec_to_timeval(ts);
897 return 0;
899 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
901 /*******************************************************************
902 a rebind function for authenticated referrals
903 This version takes a void* that we can shove useful stuff in :-)
904 and actually does the connection.
905 ******************************************************************/
906 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
907 static int rebindproc_connect_with_state (LDAP *ldap_struct,
908 LDAP_CONST char *url,
909 ber_tag_t request,
910 ber_int_t msgid, void *arg)
912 struct smbldap_state *ldap_state =
913 (struct smbldap_state *)arg;
914 int rc;
915 struct timespec ts;
916 int version;
918 DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n",
919 url, ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
921 /* call START_TLS again (ldaps:// is handled by the OpenLDAP library
922 * itself) before rebinding to another LDAP server to avoid to expose
923 * our credentials. At least *try* to secure the connection - Guenther */
925 smb_ldap_upgrade_conn(ldap_struct, &version);
926 smbldap_start_tls(ldap_struct, version);
928 /** @TODO Should we be doing something to check what servers we rebind to?
929 Could we get a referral to a machine that we don't want to give our
930 username and password to? */
932 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
934 /* only set the last rebind timestamp when we did rebind after a
935 * non-read LDAP operation. That way we avoid the replication sleep
936 * after a simple redirected search operation - Guenther */
938 switch (request) {
940 case LDAP_REQ_MODIFY:
941 case LDAP_REQ_ADD:
942 case LDAP_REQ_DELETE:
943 case LDAP_REQ_MODDN:
944 case LDAP_REQ_EXTENDED:
945 DEBUG(10,("rebindproc_connect_with_state: "
946 "setting last_rebind timestamp "
947 "(req: 0x%02x)\n", (unsigned int)request));
948 clock_gettime_mono(&ts);
949 ldap_state->last_rebind = convert_timespec_to_timeval(ts);
950 break;
951 default:
952 ZERO_STRUCT(ldap_state->last_rebind);
953 break;
956 return rc;
958 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
960 /*******************************************************************
961 Add a rebind function for authenticated referrals
962 ******************************************************************/
963 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
964 #else
965 # if LDAP_SET_REBIND_PROC_ARGS == 2
966 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
967 int *method, int freeit )
969 struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
971 return rebindproc_with_state(ldap_struct, whop, credp,
972 method, freeit, ldap_state);
974 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
975 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
977 /*******************************************************************
978 a rebind function for authenticated referrals
979 this also does the connection, but no void*.
980 ******************************************************************/
981 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
982 # if LDAP_SET_REBIND_PROC_ARGS == 2
983 static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
984 ber_int_t msgid)
986 struct smbldap_state *ldap_state = smbldap_find_state(ld);
988 return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
989 ldap_state);
991 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
992 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
994 /*******************************************************************
995 connect to the ldap server under system privilege.
996 ******************************************************************/
997 static int smbldap_connect_system(struct smbldap_state *ldap_state)
999 LDAP *ldap_struct = smbldap_get_ldap(ldap_state);
1000 int rc;
1001 int version;
1003 /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
1004 (OpenLDAP) doesn't seem to support it */
1006 DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
1007 ldap_state->uri, ldap_state->bind_dn));
1009 #ifdef HAVE_LDAP_SET_REBIND_PROC
1010 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1011 # if LDAP_SET_REBIND_PROC_ARGS == 2
1012 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
1013 # endif
1014 # if LDAP_SET_REBIND_PROC_ARGS == 3
1015 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
1016 # endif
1017 #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
1018 # if LDAP_SET_REBIND_PROC_ARGS == 2
1019 ldap_set_rebind_proc(ldap_struct, &rebindproc);
1020 # endif
1021 # if LDAP_SET_REBIND_PROC_ARGS == 3
1022 ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
1023 # endif
1024 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
1025 #endif
1027 /* When there is an alternative bind callback is set,
1028 attempt to use it to perform the bind */
1029 if (ldap_state->bind_callback != NULL) {
1030 /* We have to allow bind callback to be run under become_root/unbecome_root
1031 to make sure within smbd the callback has proper write access to its resources,
1032 like credential cache. This is similar to passdb case where this callback is supposed
1033 to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
1035 become_root();
1036 rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
1037 unbecome_root();
1038 } else {
1039 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
1042 if (rc != LDAP_SUCCESS) {
1043 char *ld_error = NULL;
1044 ldap_get_option(smbldap_get_ldap(ldap_state),
1045 LDAP_OPT_ERROR_STRING,
1046 &ld_error);
1047 DEBUG(ldap_state->num_failures ? 2 : 0,
1048 ("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
1049 ldap_state->uri,
1050 ldap_state->bind_dn ? ldap_state->bind_dn : "[Anonymous bind]",
1051 ldap_err2string(rc),
1052 ld_error ? ld_error : "(unknown)"));
1053 SAFE_FREE(ld_error);
1054 ldap_state->num_failures++;
1055 goto done;
1058 ldap_state->num_failures = 0;
1059 ldap_state->paged_results = False;
1061 ldap_get_option(smbldap_get_ldap(ldap_state),
1062 LDAP_OPT_PROTOCOL_VERSION, &version);
1064 if (smbldap_has_control(smbldap_get_ldap(ldap_state), ADS_PAGE_CTL_OID)
1065 && version == 3) {
1066 ldap_state->paged_results = True;
1069 DEBUG(3, ("ldap_connect_system: successful connection to the LDAP server\n"));
1070 DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n",
1071 ldap_state->paged_results ? "does" : "does not"));
1072 done:
1073 if (rc != 0) {
1074 ldap_unbind(ldap_struct);
1075 ldap_state->ldap_struct = NULL;
1077 return rc;
1080 static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
1081 struct tevent_timer *te,
1082 struct timeval now_abs,
1083 void *private_data);
1085 /**********************************************************************
1086 Connect to LDAP server (called before every ldap operation)
1087 *********************************************************************/
1088 static int smbldap_open(struct smbldap_state *ldap_state)
1090 int rc, opt_rc;
1091 bool reopen = False;
1092 SMB_ASSERT(ldap_state);
1094 if ((smbldap_get_ldap(ldap_state) != NULL) &&
1095 ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) <
1096 time_mono(NULL))) {
1098 #ifdef HAVE_UNIXSOCKET
1099 struct sockaddr_un addr;
1100 #else
1101 struct sockaddr_storage addr;
1102 #endif
1103 socklen_t len = sizeof(addr);
1104 int sd;
1106 opt_rc = ldap_get_option(smbldap_get_ldap(ldap_state),
1107 LDAP_OPT_DESC, &sd);
1108 if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
1109 reopen = True;
1111 #ifdef HAVE_UNIXSOCKET
1112 if (opt_rc == 0 && addr.sun_family == AF_UNIX)
1113 reopen = True;
1114 #endif
1115 if (reopen) {
1116 /* the other end has died. reopen. */
1117 ldap_unbind(smbldap_get_ldap(ldap_state));
1118 ldap_state->ldap_struct = NULL;
1119 ldap_state->last_ping = (time_t)0;
1120 } else {
1121 ldap_state->last_ping = time_mono(NULL);
1125 if (smbldap_get_ldap(ldap_state) != NULL) {
1126 DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
1127 return LDAP_SUCCESS;
1130 if ((rc = smbldap_open_connection(ldap_state))) {
1131 return rc;
1134 if ((rc = smbldap_connect_system(ldap_state))) {
1135 return rc;
1139 ldap_state->last_ping = time_mono(NULL);
1140 ldap_state->pid = getpid();
1142 TALLOC_FREE(ldap_state->idle_event);
1144 if (ldap_state->tevent_context != NULL) {
1145 ldap_state->idle_event = tevent_add_timer(
1146 ldap_state->tevent_context, ldap_state,
1147 timeval_current_ofs(SMBLDAP_IDLE_TIME, 0),
1148 smbldap_idle_fn, ldap_state);
1151 DEBUG(4,("The LDAP server is successfully connected\n"));
1153 return LDAP_SUCCESS;
1156 /**********************************************************************
1157 Disconnect from LDAP server
1158 *********************************************************************/
1159 static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
1161 if (!ldap_state)
1162 return NT_STATUS_INVALID_PARAMETER;
1164 if (smbldap_get_ldap(ldap_state) != NULL) {
1165 ldap_unbind(smbldap_get_ldap(ldap_state));
1166 ldap_state->ldap_struct = NULL;
1169 smbldap_delete_state(ldap_state);
1171 TALLOC_FREE(ldap_state->idle_event);
1173 DEBUG(5,("The connection to the LDAP server was closed\n"));
1174 /* maybe free the results here --metze */
1176 return NT_STATUS_OK;
1179 static SIG_ATOMIC_T got_alarm;
1181 static void gotalarm_sig(int dummy)
1183 got_alarm = 1;
1186 static time_t calc_ldap_abs_endtime(int ldap_to)
1188 if (ldap_to == 0) {
1189 /* No timeout - don't
1190 return a value for
1191 the alarm. */
1192 return (time_t)0;
1195 /* Make the alarm time one second beyond
1196 the timout we're setting for the
1197 remote search timeout, to allow that
1198 to fire in preference. */
1200 return time_mono(NULL)+ldap_to+1;
1203 static int end_ldap_local_alarm(time_t absolute_endtime, int rc)
1205 if (absolute_endtime) {
1206 alarm(0);
1207 CatchSignal(SIGALRM, SIG_IGN);
1208 if (got_alarm) {
1209 /* Client timeout error code. */
1210 got_alarm = 0;
1211 return LDAP_TIMEOUT;
1214 return rc;
1217 static void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t absolute_endtime)
1219 time_t now = time_mono(NULL);
1221 if (absolute_endtime) {
1222 got_alarm = 0;
1223 CatchSignal(SIGALRM, gotalarm_sig);
1224 alarm(absolute_endtime - now);
1227 if (ldap_state->pid != getpid()) {
1228 smbldap_close(ldap_state);
1232 static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
1234 ldap_get_option(smbldap_get_ldap(ldap_state),
1235 LDAP_OPT_ERROR_NUMBER, p_ld_errno);
1237 ldap_get_option(smbldap_get_ldap(ldap_state),
1238 LDAP_OPT_ERROR_STRING, pp_ld_error);
1241 static int get_cached_ldap_connect(struct smbldap_state *ldap_state, time_t abs_endtime)
1243 int attempts = 0;
1245 while (1) {
1246 int rc;
1247 time_t now;
1249 now = time_mono(NULL);
1250 ldap_state->last_use = now;
1252 if (abs_endtime && now > abs_endtime) {
1253 smbldap_close(ldap_state);
1254 return LDAP_TIMEOUT;
1257 rc = smbldap_open(ldap_state);
1259 if (rc == LDAP_SUCCESS) {
1260 return LDAP_SUCCESS;
1263 attempts++;
1264 DEBUG(1, ("Connection to LDAP server failed for the "
1265 "%d try!\n", attempts));
1267 if (rc == LDAP_INSUFFICIENT_ACCESS) {
1268 /* The fact that we are non-root or any other
1269 * access-denied condition will not change in the next
1270 * round of trying */
1271 return rc;
1274 if (got_alarm) {
1275 smbldap_close(ldap_state);
1276 return LDAP_TIMEOUT;
1279 smb_msleep(1000);
1281 if (got_alarm) {
1282 smbldap_close(ldap_state);
1283 return LDAP_TIMEOUT;
1288 /*********************************************************************
1289 ********************************************************************/
1291 static int smbldap_search_ext(struct smbldap_state *ldap_state,
1292 const char *base, int scope, const char *filter,
1293 const char *attrs[], int attrsonly,
1294 LDAPControl **sctrls, LDAPControl **cctrls,
1295 int sizelimit, LDAPMessage **res)
1297 int rc = LDAP_SERVER_DOWN;
1298 char *utf8_filter;
1299 int to = lp_ldap_timeout();
1300 time_t abs_endtime = calc_ldap_abs_endtime(to);
1301 struct timeval timeout;
1302 struct timeval *timeout_ptr = NULL;
1303 size_t converted_size;
1305 SMB_ASSERT(ldap_state);
1307 DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], "
1308 "scope => [%d]\n", base, filter, scope));
1310 if (ldap_state->last_rebind.tv_sec > 0) {
1311 struct timeval tval;
1312 struct timespec ts;
1313 int64_t tdiff = 0;
1314 int sleep_time = 0;
1316 clock_gettime_mono(&ts);
1317 tval = convert_timespec_to_timeval(ts);
1319 tdiff = usec_time_diff(&tval, &ldap_state->last_rebind);
1320 tdiff /= 1000; /* Convert to milliseconds. */
1322 sleep_time = lp_ldap_replication_sleep()-(int)tdiff;
1323 sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME);
1325 if (sleep_time > 0) {
1326 /* we wait for the LDAP replication */
1327 DEBUG(5,("smbldap_search_ext: waiting %d milliseconds "
1328 "for LDAP replication.\n",sleep_time));
1329 smb_msleep(sleep_time);
1330 DEBUG(5,("smbldap_search_ext: go on!\n"));
1332 ZERO_STRUCT(ldap_state->last_rebind);
1335 if (!push_utf8_talloc(talloc_tos(), &utf8_filter, filter, &converted_size)) {
1336 return LDAP_NO_MEMORY;
1339 /* Setup remote timeout for the ldap_search_ext_s call. */
1340 if (to) {
1341 timeout.tv_sec = to;
1342 timeout.tv_usec = 0;
1343 timeout_ptr = &timeout;
1346 setup_ldap_local_alarm(ldap_state, abs_endtime);
1348 while (1) {
1349 char *ld_error = NULL;
1350 int ld_errno;
1352 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1353 if (rc != LDAP_SUCCESS) {
1354 break;
1357 rc = ldap_search_ext_s(smbldap_get_ldap(ldap_state),
1358 base, scope,
1359 utf8_filter,
1360 discard_const_p(char *, attrs),
1361 attrsonly, sctrls, cctrls, timeout_ptr,
1362 sizelimit, res);
1363 if (rc == LDAP_SUCCESS) {
1364 break;
1367 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1369 DEBUG(10, ("Failed search for base: %s, error: %d (%s) "
1370 "(%s)\n", base, ld_errno,
1371 ldap_err2string(rc),
1372 ld_error ? ld_error : "unknown"));
1373 SAFE_FREE(ld_error);
1375 if (ld_errno != LDAP_SERVER_DOWN) {
1376 break;
1378 ldap_unbind(smbldap_get_ldap(ldap_state));
1379 ldap_state->ldap_struct = NULL;
1382 TALLOC_FREE(utf8_filter);
1383 return end_ldap_local_alarm(abs_endtime, rc);
1386 int smbldap_search(struct smbldap_state *ldap_state,
1387 const char *base, int scope, const char *filter,
1388 const char *attrs[], int attrsonly,
1389 LDAPMessage **res)
1391 return smbldap_search_ext(ldap_state, base, scope, filter, attrs,
1392 attrsonly, NULL, NULL, LDAP_NO_LIMIT, res);
1395 int smbldap_search_paged(struct smbldap_state *ldap_state,
1396 const char *base, int scope, const char *filter,
1397 const char **attrs, int attrsonly, int pagesize,
1398 LDAPMessage **res, void **cookie)
1400 LDAPControl pr;
1401 LDAPControl **rcontrols;
1402 LDAPControl *controls[2] = { NULL, NULL};
1403 BerElement *cookie_be = NULL;
1404 struct berval *cookie_bv = NULL;
1405 int tmp = 0, i, rc;
1406 bool critical = True;
1408 *res = NULL;
1410 DEBUG(3,("smbldap_search_paged: base => [%s], filter => [%s],"
1411 "scope => [%d], pagesize => [%d]\n",
1412 base, filter, scope, pagesize));
1414 cookie_be = ber_alloc_t(LBER_USE_DER);
1415 if (cookie_be == NULL) {
1416 DEBUG(0,("smbldap_create_page_control: ber_alloc_t returns "
1417 "NULL\n"));
1418 return LDAP_NO_MEMORY;
1421 /* construct cookie */
1422 if (*cookie != NULL) {
1423 ber_printf(cookie_be, "{iO}", (ber_int_t) pagesize, *cookie);
1424 ber_bvfree((struct berval *)*cookie); /* don't need it from last time */
1425 *cookie = NULL;
1426 } else {
1427 ber_printf(cookie_be, "{io}", (ber_int_t) pagesize, "", 0);
1429 ber_flatten(cookie_be, &cookie_bv);
1431 pr.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID);
1432 pr.ldctl_iscritical = (char) critical;
1433 pr.ldctl_value.bv_len = cookie_bv->bv_len;
1434 pr.ldctl_value.bv_val = cookie_bv->bv_val;
1436 controls[0] = &pr;
1437 controls[1] = NULL;
1439 rc = smbldap_search_ext(ldap_state, base, scope, filter, attrs,
1440 0, controls, NULL, LDAP_NO_LIMIT, res);
1442 ber_free(cookie_be, 1);
1443 ber_bvfree(cookie_bv);
1445 if (rc != 0) {
1446 DEBUG(3,("smbldap_search_paged: smbldap_search_ext(%s) "
1447 "failed with [%s]\n", filter, ldap_err2string(rc)));
1448 goto done;
1451 DEBUG(3,("smbldap_search_paged: search was successful\n"));
1453 rc = ldap_parse_result(smbldap_get_ldap(ldap_state), *res, NULL, NULL,
1454 NULL, NULL, &rcontrols, 0);
1455 if (rc != 0) {
1456 DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
1457 "with [%s]\n", ldap_err2string(rc)));
1458 goto done;
1461 if (rcontrols == NULL)
1462 goto done;
1464 for (i=0; rcontrols[i]; i++) {
1466 if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) != 0)
1467 continue;
1469 cookie_be = ber_init(&rcontrols[i]->ldctl_value);
1470 ber_scanf(cookie_be,"{iO}", &tmp, &cookie_bv);
1471 /* the berval is the cookie, but must be freed when it is all
1472 done */
1473 if (cookie_bv->bv_len)
1474 *cookie=ber_bvdup(cookie_bv);
1475 else
1476 *cookie=NULL;
1477 ber_bvfree(cookie_bv);
1478 ber_free(cookie_be, 1);
1479 break;
1481 ldap_controls_free(rcontrols);
1482 done:
1483 return rc;
1486 int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
1488 int rc = LDAP_SERVER_DOWN;
1489 char *utf8_dn;
1490 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1491 size_t converted_size;
1493 SMB_ASSERT(ldap_state);
1495 DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
1497 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1498 return LDAP_NO_MEMORY;
1501 setup_ldap_local_alarm(ldap_state, abs_endtime);
1503 while (1) {
1504 char *ld_error = NULL;
1505 int ld_errno;
1507 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1508 if (rc != LDAP_SUCCESS) {
1509 break;
1512 rc = ldap_modify_s(smbldap_get_ldap(ldap_state), utf8_dn,
1513 attrs);
1514 if (rc == LDAP_SUCCESS) {
1515 break;
1518 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1520 DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) "
1521 "(%s)\n", dn, ld_errno,
1522 ldap_err2string(rc),
1523 ld_error ? ld_error : "unknown"));
1524 SAFE_FREE(ld_error);
1526 if (ld_errno != LDAP_SERVER_DOWN) {
1527 break;
1529 ldap_unbind(smbldap_get_ldap(ldap_state));
1530 ldap_state->ldap_struct = NULL;
1533 TALLOC_FREE(utf8_dn);
1534 return end_ldap_local_alarm(abs_endtime, rc);
1537 int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
1539 int rc = LDAP_SERVER_DOWN;
1540 char *utf8_dn;
1541 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1542 size_t converted_size;
1544 SMB_ASSERT(ldap_state);
1546 DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
1548 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1549 return LDAP_NO_MEMORY;
1552 setup_ldap_local_alarm(ldap_state, abs_endtime);
1554 while (1) {
1555 char *ld_error = NULL;
1556 int ld_errno;
1558 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1559 if (rc != LDAP_SUCCESS) {
1560 break;
1563 rc = ldap_add_s(smbldap_get_ldap(ldap_state), utf8_dn, attrs);
1564 if (rc == LDAP_SUCCESS) {
1565 break;
1568 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1570 DEBUG(10, ("Failed to add dn: %s, error: %d (%s) "
1571 "(%s)\n", dn, ld_errno,
1572 ldap_err2string(rc),
1573 ld_error ? ld_error : "unknown"));
1574 SAFE_FREE(ld_error);
1576 if (ld_errno != LDAP_SERVER_DOWN) {
1577 break;
1579 ldap_unbind(smbldap_get_ldap(ldap_state));
1580 ldap_state->ldap_struct = NULL;
1583 TALLOC_FREE(utf8_dn);
1584 return end_ldap_local_alarm(abs_endtime, rc);
1587 int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
1589 int rc = LDAP_SERVER_DOWN;
1590 char *utf8_dn;
1591 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1592 size_t converted_size;
1594 SMB_ASSERT(ldap_state);
1596 DEBUG(5,("smbldap_delete: dn => [%s]\n", dn ));
1598 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1599 return LDAP_NO_MEMORY;
1602 setup_ldap_local_alarm(ldap_state, abs_endtime);
1604 while (1) {
1605 char *ld_error = NULL;
1606 int ld_errno;
1608 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1609 if (rc != LDAP_SUCCESS) {
1610 break;
1613 rc = ldap_delete_s(smbldap_get_ldap(ldap_state), utf8_dn);
1614 if (rc == LDAP_SUCCESS) {
1615 break;
1618 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1620 DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) "
1621 "(%s)\n", dn, ld_errno,
1622 ldap_err2string(rc),
1623 ld_error ? ld_error : "unknown"));
1624 SAFE_FREE(ld_error);
1626 if (ld_errno != LDAP_SERVER_DOWN) {
1627 break;
1629 ldap_unbind(smbldap_get_ldap(ldap_state));
1630 ldap_state->ldap_struct = NULL;
1633 TALLOC_FREE(utf8_dn);
1634 return end_ldap_local_alarm(abs_endtime, rc);
1637 int smbldap_extended_operation(struct smbldap_state *ldap_state,
1638 LDAP_CONST char *reqoid, struct berval *reqdata,
1639 LDAPControl **serverctrls, LDAPControl **clientctrls,
1640 char **retoidp, struct berval **retdatap)
1642 int rc = LDAP_SERVER_DOWN;
1643 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1645 if (!ldap_state)
1646 return (-1);
1648 setup_ldap_local_alarm(ldap_state, abs_endtime);
1650 while (1) {
1651 char *ld_error = NULL;
1652 int ld_errno;
1654 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1655 if (rc != LDAP_SUCCESS) {
1656 break;
1659 rc = ldap_extended_operation_s(smbldap_get_ldap(ldap_state),
1660 reqoid,
1661 reqdata, serverctrls,
1662 clientctrls, retoidp, retdatap);
1663 if (rc == LDAP_SUCCESS) {
1664 break;
1667 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1669 DEBUG(10, ("Extended operation failed with error: "
1670 "%d (%s) (%s)\n", ld_errno,
1671 ldap_err2string(rc),
1672 ld_error ? ld_error : "unknown"));
1673 SAFE_FREE(ld_error);
1675 if (ld_errno != LDAP_SERVER_DOWN) {
1676 break;
1678 ldap_unbind(smbldap_get_ldap(ldap_state));
1679 ldap_state->ldap_struct = NULL;
1682 return end_ldap_local_alarm(abs_endtime, rc);
1685 /*******************************************************************
1686 run the search by name.
1687 ******************************************************************/
1688 int smbldap_search_suffix (struct smbldap_state *ldap_state,
1689 const char *filter, const char **search_attr,
1690 LDAPMessage ** result)
1692 return smbldap_search(ldap_state, lp_ldap_suffix(),
1693 LDAP_SCOPE_SUBTREE,
1694 filter, search_attr, 0, result);
1697 static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
1698 struct tevent_timer *te,
1699 struct timeval now_abs,
1700 void *private_data)
1702 struct smbldap_state *state = (struct smbldap_state *)private_data;
1704 TALLOC_FREE(state->idle_event);
1706 if (smbldap_get_ldap(state) == NULL) {
1707 DEBUG(10,("ldap connection not connected...\n"));
1708 return;
1711 if ((state->last_use+SMBLDAP_IDLE_TIME) > time_mono(NULL)) {
1712 DEBUG(10,("ldap connection not idle...\n"));
1714 /* this needs to be made monotonic clock aware inside tevent: */
1715 state->idle_event = tevent_add_timer(
1716 tevent_ctx, state,
1717 timeval_add(&now_abs, SMBLDAP_IDLE_TIME, 0),
1718 smbldap_idle_fn,
1719 private_data);
1720 return;
1723 DEBUG(7,("ldap connection idle...closing connection\n"));
1724 smbldap_close(state);
1727 /**********************************************************************
1728 Housekeeping
1729 *********************************************************************/
1731 void smbldap_free_struct(struct smbldap_state **ldap_state)
1733 smbldap_close(*ldap_state);
1735 if ((*ldap_state)->bind_secret) {
1736 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
1739 SAFE_FREE((*ldap_state)->bind_dn);
1740 SAFE_FREE((*ldap_state)->bind_secret);
1741 smbldap_set_bind_callback(*ldap_state, NULL, NULL);
1743 TALLOC_FREE(*ldap_state);
1745 /* No need to free any further, as it is talloc()ed */
1748 static int smbldap_state_destructor(struct smbldap_state *state)
1750 smbldap_free_struct(&state);
1751 return 0;
1755 /**********************************************************************
1756 Intitalise the 'general' ldap structures, on which ldap operations may be conducted
1757 *********************************************************************/
1759 NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct tevent_context *tevent_ctx,
1760 const char *location,
1761 bool anon,
1762 const char *bind_dn,
1763 const char *bind_secret,
1764 struct smbldap_state **smbldap_state)
1766 *smbldap_state = talloc_zero(mem_ctx, struct smbldap_state);
1767 if (!*smbldap_state) {
1768 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
1769 return NT_STATUS_NO_MEMORY;
1772 if (location) {
1773 (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
1774 } else {
1775 (*smbldap_state)->uri = "ldap://localhost";
1778 (*smbldap_state)->tevent_context = tevent_ctx;
1780 if (bind_dn && bind_secret) {
1781 smbldap_set_creds(*smbldap_state, anon, bind_dn, bind_secret);
1784 talloc_set_destructor(*smbldap_state, smbldap_state_destructor);
1785 return NT_STATUS_OK;
1788 char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld,
1789 LDAPMessage *entry)
1791 char *utf8_dn, *unix_dn;
1792 size_t converted_size;
1794 utf8_dn = ldap_get_dn(ld, entry);
1795 if (!utf8_dn) {
1796 DEBUG (5, ("smbldap_talloc_dn: ldap_get_dn failed\n"));
1797 return NULL;
1799 if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
1800 DEBUG (0, ("smbldap_talloc_dn: String conversion failure utf8 "
1801 "[%s]\n", utf8_dn));
1802 return NULL;
1804 ldap_memfree(utf8_dn);
1805 return unix_dn;
1808 /*******************************************************************
1809 Check if root-dse has a certain Control or Extension
1810 ********************************************************************/
1812 static bool smbldap_check_root_dse(LDAP *ld, const char **attrs, const char *value)
1814 LDAPMessage *msg = NULL;
1815 LDAPMessage *entry = NULL;
1816 char **values = NULL;
1817 int rc, num_result, num_values, i;
1818 bool result = False;
1820 if (!attrs[0]) {
1821 DEBUG(3,("smbldap_check_root_dse: nothing to look for\n"));
1822 return False;
1825 if (!strequal(attrs[0], "supportedExtension") &&
1826 !strequal(attrs[0], "supportedControl") &&
1827 !strequal(attrs[0], "namingContexts")) {
1828 DEBUG(3,("smbldap_check_root_dse: no idea what to query root-dse for: %s ?\n", attrs[0]));
1829 return False;
1832 rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE,
1833 "(objectclass=*)", discard_const_p(char *, attrs), 0 , &msg);
1835 if (rc != LDAP_SUCCESS) {
1836 DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n"));
1837 return False;
1840 num_result = ldap_count_entries(ld, msg);
1842 if (num_result != 1) {
1843 DEBUG(3,("smbldap_check_root_dse: Expected one rootDSE, got %d\n", num_result));
1844 goto done;
1847 entry = ldap_first_entry(ld, msg);
1849 if (entry == NULL) {
1850 DEBUG(3,("smbldap_check_root_dse: Could not retrieve rootDSE\n"));
1851 goto done;
1854 values = ldap_get_values(ld, entry, attrs[0]);
1856 if (values == NULL) {
1857 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not support any %s\n", attrs[0]));
1858 goto done;
1861 num_values = ldap_count_values(values);
1863 if (num_values == 0) {
1864 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not have any %s\n", attrs[0]));
1865 goto done;
1868 for (i=0; i<num_values; i++) {
1869 if (strcmp(values[i], value) == 0)
1870 result = True;
1874 done:
1875 if (values != NULL)
1876 ldap_value_free(values);
1877 if (msg != NULL)
1878 ldap_msgfree(msg);
1880 return result;
1884 /*******************************************************************
1885 Check if LDAP-Server supports a certain Control (OID in string format)
1886 ********************************************************************/
1888 bool smbldap_has_control(LDAP *ld, const char *control)
1890 const char *attrs[] = { "supportedControl", NULL };
1891 return smbldap_check_root_dse(ld, attrs, control);
1894 /*******************************************************************
1895 Check if LDAP-Server supports a certain Extension (OID in string format)
1896 ********************************************************************/
1898 bool smbldap_has_extension(LDAP *ld, const char *extension)
1900 const char *attrs[] = { "supportedExtension", NULL };
1901 return smbldap_check_root_dse(ld, attrs, extension);
1904 /*******************************************************************
1905 Check if LDAP-Server holds a given namingContext
1906 ********************************************************************/
1908 bool smbldap_has_naming_context(LDAP *ld, const char *naming_context)
1910 const char *attrs[] = { "namingContexts", NULL };
1911 return smbldap_check_root_dse(ld, attrs, naming_context);
1914 bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *dn, const char *secret)
1916 ldap_state->anonymous = anon;
1918 /* free any previously set credential */
1920 SAFE_FREE(ldap_state->bind_dn);
1921 smbldap_set_bind_callback(ldap_state, NULL, NULL);
1923 if (ldap_state->bind_secret) {
1924 /* make sure secrets are zeroed out of memory */
1925 memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));
1926 SAFE_FREE(ldap_state->bind_secret);
1929 if ( ! anon) {
1930 ldap_state->bind_dn = SMB_STRDUP(dn);
1931 ldap_state->bind_secret = SMB_STRDUP(secret);
1934 return True;