source: vendor/current/source3/lib/smbldap.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 49.5 KB
Line 
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
9
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.
14
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.
19
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/>.
22
23*/
24
25#include "includes.h"
26#include "smbldap.h"
27#include "../libcli/security/security.h"
28#include <tevent.h>
29#include "lib/param/loadparm.h"
30
31/* Try not to hit the up or down server forever */
32
33#define SMBLDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
34#define SMBLDAP_NUM_RETRIES 8 /* retry only 8 times */
35
36#define SMBLDAP_IDLE_TIME 150 /* After 2.5 minutes disconnect */
37
38
39/*******************************************************************
40 Search an attribute and return the first value found.
41******************************************************************/
42
43 bool smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
44 const char *attribute, char *value,
45 int max_len)
46{
47 char **values;
48 size_t size = 0;
49
50 if ( !attribute )
51 return False;
52
53 value[0] = '\0';
54
55 if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
56 DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
57
58 return False;
59 }
60
61 if (!convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, &size)) {
62 DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n",
63 attribute, values[0]));
64 ldap_value_free(values);
65 return False;
66 }
67
68 ldap_value_free(values);
69#ifdef DEBUG_PASSWORDS
70 DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
71#endif
72 return True;
73}
74
75 char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry,
76 const char *attribute,
77 TALLOC_CTX *mem_ctx)
78{
79 char **values;
80 char *result;
81 size_t converted_size;
82
83 if (attribute == NULL) {
84 return NULL;
85 }
86
87 values = ldap_get_values(ldap_struct, entry, attribute);
88
89 if (values == NULL) {
90 DEBUG(10, ("attribute %s does not exist\n", attribute));
91 return NULL;
92 }
93
94 if (ldap_count_values(values) != 1) {
95 DEBUG(10, ("attribute %s has %d values, expected only one\n",
96 attribute, ldap_count_values(values)));
97 ldap_value_free(values);
98 return NULL;
99 }
100
101 if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
102 DEBUG(10, ("pull_utf8_talloc failed\n"));
103 ldap_value_free(values);
104 return NULL;
105 }
106
107 ldap_value_free(values);
108
109#ifdef DEBUG_PASSWORDS
110 DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
111 attribute, result));
112#endif
113 return result;
114}
115
116 char * smbldap_talloc_first_attribute(LDAP *ldap_struct, LDAPMessage *entry,
117 const char *attribute,
118 TALLOC_CTX *mem_ctx)
119{
120 char **values;
121 char *result;
122 size_t converted_size;
123
124 if (attribute == NULL) {
125 return NULL;
126 }
127
128 values = ldap_get_values(ldap_struct, entry, attribute);
129
130 if (values == NULL) {
131 DEBUG(10, ("attribute %s does not exist\n", attribute));
132 return NULL;
133 }
134
135 if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
136 DEBUG(10, ("pull_utf8_talloc failed\n"));
137 ldap_value_free(values);
138 return NULL;
139 }
140
141 ldap_value_free(values);
142
143#ifdef DEBUG_PASSWORDS
144 DEBUG (100, ("smbldap_get_first_attribute: [%s] = [%s]\n",
145 attribute, result));
146#endif
147 return result;
148}
149
150 char * smbldap_talloc_smallest_attribute(LDAP *ldap_struct, LDAPMessage *entry,
151 const char *attribute,
152 TALLOC_CTX *mem_ctx)
153{
154 char **values;
155 char *result;
156 size_t converted_size;
157 int i, num_values;
158
159 if (attribute == NULL) {
160 return NULL;
161 }
162
163 values = ldap_get_values(ldap_struct, entry, attribute);
164
165 if (values == NULL) {
166 DEBUG(10, ("attribute %s does not exist\n", attribute));
167 return NULL;
168 }
169
170 if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
171 DEBUG(10, ("pull_utf8_talloc failed\n"));
172 ldap_value_free(values);
173 return NULL;
174 }
175
176 num_values = ldap_count_values(values);
177
178 for (i=1; i<num_values; i++) {
179 char *tmp;
180
181 if (!pull_utf8_talloc(mem_ctx, &tmp, values[i],
182 &converted_size)) {
183 DEBUG(10, ("pull_utf8_talloc failed\n"));
184 TALLOC_FREE(result);
185 ldap_value_free(values);
186 return NULL;
187 }
188
189 if (strcasecmp_m(tmp, result) < 0) {
190 TALLOC_FREE(result);
191 result = tmp;
192 } else {
193 TALLOC_FREE(tmp);
194 }
195 }
196
197 ldap_value_free(values);
198
199#ifdef DEBUG_PASSWORDS
200 DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
201 attribute, result));
202#endif
203 return result;
204}
205
206 bool smbldap_talloc_single_blob(TALLOC_CTX *mem_ctx, LDAP *ld,
207 LDAPMessage *msg, const char *attrib,
208 DATA_BLOB *blob)
209{
210 struct berval **values;
211
212 values = ldap_get_values_len(ld, msg, attrib);
213 if (!values) {
214 return false;
215 }
216
217 if (ldap_count_values_len(values) != 1) {
218 DEBUG(10, ("Expected one value for %s, got %d\n", attrib,
219 ldap_count_values_len(values)));
220 return false;
221 }
222
223 *blob = data_blob_talloc(mem_ctx, values[0]->bv_val,
224 values[0]->bv_len);
225 ldap_value_free_len(values);
226
227 return (blob->data != NULL);
228}
229
230 bool smbldap_pull_sid(LDAP *ld, LDAPMessage *msg, const char *attrib,
231 struct dom_sid *sid)
232{
233 DATA_BLOB blob;
234 bool ret;
235
236 if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib,
237 &blob)) {
238 return false;
239 }
240 ret = sid_parse(blob.data, blob.length, sid);
241 TALLOC_FREE(blob.data);
242 return ret;
243}
244
245 static int ldapmsg_destructor(LDAPMessage **result) {
246 ldap_msgfree(*result);
247 return 0;
248}
249
250 void smbldap_talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
251{
252 LDAPMessage **handle;
253
254 if (result == NULL) {
255 return;
256 }
257
258 handle = talloc(mem_ctx, LDAPMessage *);
259 SMB_ASSERT(handle != NULL);
260
261 *handle = result;
262 talloc_set_destructor(handle, ldapmsg_destructor);
263}
264
265 static int ldapmod_destructor(LDAPMod ***mod) {
266 ldap_mods_free(*mod, True);
267 return 0;
268}
269
270 void smbldap_talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
271{
272 LDAPMod ***handle;
273
274 if (mod == NULL) {
275 return;
276 }
277
278 handle = talloc(mem_ctx, LDAPMod **);
279 SMB_ASSERT(handle != NULL);
280
281 *handle = mod;
282 talloc_set_destructor(handle, ldapmod_destructor);
283}
284
285/************************************************************************
286 Routine to manage the LDAPMod structure array
287 manage memory used by the array, by each struct, and values
288 ***********************************************************************/
289
290static void smbldap_set_mod_internal(LDAPMod *** modlist, int modop, const char *attribute, const char *value, const DATA_BLOB *blob)
291{
292 LDAPMod **mods;
293 int i;
294 int j;
295
296 mods = *modlist;
297
298 /* sanity checks on the mod values */
299
300 if (attribute == NULL || *attribute == '\0') {
301 return;
302 }
303
304#if 0 /* commented out after discussion with abartlet. Do not re-enable.
305 left here so other do not re-add similar code --jerry */
306 if (value == NULL || *value == '\0')
307 return;
308#endif
309
310 if (mods == NULL) {
311 mods = SMB_MALLOC_P(LDAPMod *);
312 if (mods == NULL) {
313 smb_panic("smbldap_set_mod: out of memory!");
314 /* notreached. */
315 }
316 mods[0] = NULL;
317 }
318
319 for (i = 0; mods[i] != NULL; ++i) {
320 if (mods[i]->mod_op == modop && strequal(mods[i]->mod_type, attribute))
321 break;
322 }
323
324 if (mods[i] == NULL) {
325 mods = SMB_REALLOC_ARRAY (mods, LDAPMod *, i + 2);
326 if (mods == NULL) {
327 smb_panic("smbldap_set_mod: out of memory!");
328 /* notreached. */
329 }
330 mods[i] = SMB_MALLOC_P(LDAPMod);
331 if (mods[i] == NULL) {
332 smb_panic("smbldap_set_mod: out of memory!");
333 /* notreached. */
334 }
335 mods[i]->mod_op = modop;
336 mods[i]->mod_values = NULL;
337 mods[i]->mod_type = SMB_STRDUP(attribute);
338 mods[i + 1] = NULL;
339 }
340
341 if (blob && (modop & LDAP_MOD_BVALUES)) {
342 j = 0;
343 if (mods[i]->mod_bvalues != NULL) {
344 for (; mods[i]->mod_bvalues[j] != NULL; j++);
345 }
346 mods[i]->mod_bvalues = SMB_REALLOC_ARRAY(mods[i]->mod_bvalues, struct berval *, j + 2);
347
348 if (mods[i]->mod_bvalues == NULL) {
349 smb_panic("smbldap_set_mod: out of memory!");
350 /* notreached. */
351 }
352
353 mods[i]->mod_bvalues[j] = SMB_MALLOC_P(struct berval);
354 SMB_ASSERT(mods[i]->mod_bvalues[j] != NULL);
355
356 mods[i]->mod_bvalues[j]->bv_val = (char *)smb_memdup(blob->data, blob->length);
357 SMB_ASSERT(mods[i]->mod_bvalues[j]->bv_val != NULL);
358 mods[i]->mod_bvalues[j]->bv_len = blob->length;
359
360 mods[i]->mod_bvalues[j + 1] = NULL;
361 } else if (value != NULL) {
362 char *utf8_value = NULL;
363 size_t converted_size;
364
365 j = 0;
366 if (mods[i]->mod_values != NULL) {
367 for (; mods[i]->mod_values[j] != NULL; j++);
368 }
369 mods[i]->mod_values = SMB_REALLOC_ARRAY(mods[i]->mod_values, char *, j + 2);
370
371 if (mods[i]->mod_values == NULL) {
372 smb_panic("smbldap_set_mod: out of memory!");
373 /* notreached. */
374 }
375
376 if (!push_utf8_talloc(talloc_tos(), &utf8_value, value, &converted_size)) {
377 smb_panic("smbldap_set_mod: String conversion failure!");
378 /* notreached. */
379 }
380
381 mods[i]->mod_values[j] = SMB_STRDUP(utf8_value);
382 TALLOC_FREE(utf8_value);
383 SMB_ASSERT(mods[i]->mod_values[j] != NULL);
384
385 mods[i]->mod_values[j + 1] = NULL;
386 }
387 *modlist = mods;
388}
389
390 void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
391{
392 smbldap_set_mod_internal(modlist, modop, attribute, value, NULL);
393}
394
395 void smbldap_set_mod_blob(LDAPMod *** modlist, int modop, const char *attribute, const DATA_BLOB *value)
396{
397 smbldap_set_mod_internal(modlist, modop | LDAP_MOD_BVALUES, attribute, NULL, value);
398}
399
400/**********************************************************************
401 Set attribute to newval in LDAP, regardless of what value the
402 attribute had in LDAP before.
403*********************************************************************/
404
405static void smbldap_make_mod_internal(LDAP *ldap_struct, LDAPMessage *existing,
406 LDAPMod ***mods,
407 const char *attribute, int op,
408 const char *newval,
409 const DATA_BLOB *newblob)
410{
411 char oldval[2048]; /* current largest allowed value is mungeddial */
412 bool existed;
413 DATA_BLOB oldblob = data_blob_null;
414
415 if (existing != NULL) {
416 if (op & LDAP_MOD_BVALUES) {
417 existed = smbldap_talloc_single_blob(talloc_tos(), ldap_struct, existing, attribute, &oldblob);
418 } else {
419 existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
420 }
421 } else {
422 existed = False;
423 *oldval = '\0';
424 }
425
426 if (existed) {
427 bool equal = false;
428 if (op & LDAP_MOD_BVALUES) {
429 equal = (newblob && (data_blob_cmp(&oldblob, newblob) == 0));
430 } else {
431 /* all of our string attributes are case insensitive */
432 equal = (newval && (strcasecmp_m(oldval, newval) == 0));
433 }
434
435 if (equal) {
436 /* Believe it or not, but LDAP will deny a delete and
437 an add at the same time if the values are the
438 same... */
439 DEBUG(10,("smbldap_make_mod: attribute |%s| not changed.\n", attribute));
440 return;
441 }
442
443 /* There has been no value before, so don't delete it.
444 * Here's a possible race: We might end up with
445 * duplicate attributes */
446 /* By deleting exactly the value we found in the entry this
447 * should be race-free in the sense that the LDAP-Server will
448 * deny the complete operation if somebody changed the
449 * attribute behind our back. */
450 /* This will also allow modifying single valued attributes
451 * in Novell NDS. In NDS you have to first remove attribute and then
452 * you could add new value */
453
454 if (op & LDAP_MOD_BVALUES) {
455 DEBUG(10,("smbldap_make_mod: deleting attribute |%s| blob\n", attribute));
456 smbldap_set_mod_blob(mods, LDAP_MOD_DELETE, attribute, &oldblob);
457 } else {
458 DEBUG(10,("smbldap_make_mod: deleting attribute |%s| values |%s|\n", attribute, oldval));
459 smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval);
460 }
461 }
462
463 /* Regardless of the real operation (add or modify)
464 we add the new value here. We rely on deleting
465 the old value, should it exist. */
466
467 if (op & LDAP_MOD_BVALUES) {
468 if (newblob && newblob->length) {
469 DEBUG(10,("smbldap_make_mod: adding attribute |%s| blob\n", attribute));
470 smbldap_set_mod_blob(mods, LDAP_MOD_ADD, attribute, newblob);
471 }
472 } else {
473 if ((newval != NULL) && (strlen(newval) > 0)) {
474 DEBUG(10,("smbldap_make_mod: adding attribute |%s| value |%s|\n", attribute, newval));
475 smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
476 }
477 }
478}
479
480 void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
481 LDAPMod ***mods,
482 const char *attribute, const char *newval)
483{
484 smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
485 0, newval, NULL);
486}
487
488 void smbldap_make_mod_blob(LDAP *ldap_struct, LDAPMessage *existing,
489 LDAPMod ***mods,
490 const char *attribute, const DATA_BLOB *newblob)
491{
492 smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
493 LDAP_MOD_BVALUES, NULL, newblob);
494}
495
496/**********************************************************************
497 Some varients of the LDAP rebind code do not pass in the third 'arg'
498 pointer to a void*, so we try and work around it by assuming that the
499 value of the 'LDAP *' pointer is the same as the one we had passed in
500 **********************************************************************/
501
502struct smbldap_state_lookup {
503 LDAP *ld;
504 struct smbldap_state *smbldap_state;
505 struct smbldap_state_lookup *prev, *next;
506};
507
508static struct smbldap_state_lookup *smbldap_state_lookup_list;
509
510static struct smbldap_state *smbldap_find_state(LDAP *ld)
511{
512 struct smbldap_state_lookup *t;
513
514 for (t = smbldap_state_lookup_list; t; t = t->next) {
515 if (t->ld == ld) {
516 return t->smbldap_state;
517 }
518 }
519 return NULL;
520}
521
522static void smbldap_delete_state(struct smbldap_state *smbldap_state)
523{
524 struct smbldap_state_lookup *t;
525
526 for (t = smbldap_state_lookup_list; t; t = t->next) {
527 if (t->smbldap_state == smbldap_state) {
528 DLIST_REMOVE(smbldap_state_lookup_list, t);
529 SAFE_FREE(t);
530 return;
531 }
532 }
533}
534
535static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
536{
537 struct smbldap_state *tmp_ldap_state;
538 struct smbldap_state_lookup *t;
539
540 if ((tmp_ldap_state = smbldap_find_state(ld))) {
541 SMB_ASSERT(tmp_ldap_state == smbldap_state);
542 return;
543 }
544
545 t = SMB_XMALLOC_P(struct smbldap_state_lookup);
546 ZERO_STRUCTP(t);
547
548 DLIST_ADD_END(smbldap_state_lookup_list, t);
549 t->ld = ld;
550 t->smbldap_state = smbldap_state;
551}
552
553/********************************************************************
554 start TLS on an existing LDAP connection
555*******************************************************************/
556
557int smbldap_start_tls(LDAP *ldap_struct, int version)
558{
559#ifdef LDAP_OPT_X_TLS
560 int rc;
561#endif
562
563 if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
564 return LDAP_SUCCESS;
565 }
566
567#ifdef LDAP_OPT_X_TLS
568 if (version != LDAP_VERSION3) {
569 DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
570 return LDAP_OPERATIONS_ERROR;
571 }
572
573 if ((rc = ldap_start_tls_s (ldap_struct, NULL, NULL)) != LDAP_SUCCESS) {
574 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
575 ldap_err2string(rc)));
576 return rc;
577 }
578
579 DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
580 return LDAP_SUCCESS;
581#else
582 DEBUG(0,("StartTLS not supported by LDAP client libraries!\n"));
583 return LDAP_OPERATIONS_ERROR;
584#endif
585}
586
587/********************************************************************
588 setup a connection to the LDAP server based on a uri
589*******************************************************************/
590
591static int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri)
592{
593 int rc;
594
595 DEBUG(10, ("smb_ldap_setup_connection: %s\n", uri));
596
597#ifdef HAVE_LDAP_INITIALIZE
598
599 rc = ldap_initialize(ldap_struct, uri);
600 if (rc) {
601 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
602 return rc;
603 }
604
605 if (lp_ldap_follow_referral() != Auto) {
606 rc = ldap_set_option(*ldap_struct, LDAP_OPT_REFERRALS,
607 lp_ldap_follow_referral() ? LDAP_OPT_ON : LDAP_OPT_OFF);
608 if (rc != LDAP_SUCCESS)
609 DEBUG(0, ("Failed to set LDAP_OPT_REFERRALS: %s\n",
610 ldap_err2string(rc)));
611 }
612
613 return LDAP_SUCCESS;
614#else
615
616 /* Parse the string manually */
617
618 {
619 int port = 0;
620 fstring protocol;
621 fstring host;
622 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
623
624
625 /* skip leading "URL:" (if any) */
626 if ( strnequal( uri, "URL:", 4 ) ) {
627 uri += 4;
628 }
629
630 sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
631
632 if (port == 0) {
633 if (strequal(protocol, "ldap")) {
634 port = LDAP_PORT;
635 } else if (strequal(protocol, "ldaps")) {
636 port = LDAPS_PORT;
637 } else {
638 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
639 }
640 }
641
642 if ((*ldap_struct = ldap_init(host, port)) == NULL) {
643 DEBUG(0, ("ldap_init failed !\n"));
644 return LDAP_OPERATIONS_ERROR;
645 }
646
647 if (strequal(protocol, "ldaps")) {
648#ifdef LDAP_OPT_X_TLS
649 int tls = LDAP_OPT_X_TLS_HARD;
650 if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
651 {
652 DEBUG(0, ("Failed to setup a TLS session\n"));
653 }
654
655 DEBUG(3,("LDAPS option set...!\n"));
656#else
657 DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
658 return LDAP_OPERATIONS_ERROR;
659#endif /* LDAP_OPT_X_TLS */
660 }
661 }
662#endif /* HAVE_LDAP_INITIALIZE */
663
664 /* now set connection timeout */
665#ifdef LDAP_X_OPT_CONNECT_TIMEOUT /* Netscape */
666 {
667 int ct = lp_ldap_connection_timeout()*1000;
668 rc = ldap_set_option(*ldap_struct, LDAP_X_OPT_CONNECT_TIMEOUT, &ct);
669 if (rc != LDAP_SUCCESS) {
670 DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
671 ct, ldap_err2string(rc)));
672 }
673 }
674#elif defined (LDAP_OPT_NETWORK_TIMEOUT) /* OpenLDAP */
675 {
676 struct timeval ct;
677 ct.tv_usec = 0;
678 ct.tv_sec = lp_ldap_connection_timeout();
679 rc = ldap_set_option(*ldap_struct, LDAP_OPT_NETWORK_TIMEOUT, &ct);
680 if (rc != LDAP_SUCCESS) {
681 DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
682 (int)ct.tv_sec, ldap_err2string(rc)));
683 }
684 }
685#endif
686
687 return LDAP_SUCCESS;
688}
689
690/********************************************************************
691 try to upgrade to Version 3 LDAP if not already, in either case return current
692 version
693 *******************************************************************/
694
695static int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
696{
697 int version;
698 int rc;
699
700 /* assume the worst */
701 *new_version = LDAP_VERSION2;
702
703 rc = ldap_get_option(ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
704 if (rc) {
705 return rc;
706 }
707
708 if (version == LDAP_VERSION3) {
709 *new_version = LDAP_VERSION3;
710 return LDAP_SUCCESS;
711 }
712
713 /* try upgrade */
714 version = LDAP_VERSION3;
715 rc = ldap_set_option (ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
716 if (rc) {
717 return rc;
718 }
719
720 *new_version = LDAP_VERSION3;
721 return LDAP_SUCCESS;
722}
723
724/*******************************************************************
725 open a connection to the ldap server (just until the bind)
726 ******************************************************************/
727
728int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
729{
730 int rc, version;
731
732 rc = smb_ldap_setup_conn(ldap_struct, uri);
733 if (rc) {
734 return rc;
735 }
736
737 rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
738 if (rc) {
739 return rc;
740 }
741
742 rc = smbldap_start_tls(*ldap_struct, version);
743 if (rc) {
744 return rc;
745 }
746
747 return LDAP_SUCCESS;
748}
749
750/*******************************************************************
751 open a connection to the ldap server.
752******************************************************************/
753static int smbldap_open_connection (struct smbldap_state *ldap_state)
754
755{
756 int rc = LDAP_SUCCESS;
757 int version;
758 int deref;
759 LDAP **ldap_struct = &ldap_state->ldap_struct;
760
761 rc = smb_ldap_setup_conn(ldap_struct, ldap_state->uri);
762 if (rc) {
763 return rc;
764 }
765
766 /* Store the LDAP pointer in a lookup list */
767
768 smbldap_store_state(*ldap_struct, ldap_state);
769
770 /* Upgrade to LDAPv3 if possible */
771
772 rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
773 if (rc) {
774 return rc;
775 }
776
777 /* Start TLS if required */
778
779 rc = smbldap_start_tls(*ldap_struct, version);
780 if (rc) {
781 return rc;
782 }
783
784 /* Set alias dereferencing method */
785 deref = lp_ldap_deref();
786 if (deref != -1) {
787 if (ldap_set_option (*ldap_struct, LDAP_OPT_DEREF, &deref) != LDAP_OPT_SUCCESS) {
788 DEBUG(1,("smbldap_open_connection: Failed to set dereferencing method: %d\n", deref));
789 } else {
790 DEBUG(5,("Set dereferencing method: %d\n", deref));
791 }
792 }
793
794 DEBUG(2, ("smbldap_open_connection: connection opened\n"));
795 return rc;
796}
797
798/*******************************************************************
799 a rebind function for authenticated referrals
800 This version takes a void* that we can shove useful stuff in :-)
801******************************************************************/
802#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
803#else
804static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
805 int *methodp, int freeit, void *arg)
806{
807 struct smbldap_state *ldap_state = arg;
808 struct timespec ts;
809
810 /** @TODO Should we be doing something to check what servers we rebind to?
811 Could we get a referral to a machine that we don't want to give our
812 username and password to? */
813
814 if (freeit) {
815 SAFE_FREE(*whop);
816 if (*credp) {
817 memset(*credp, '\0', strlen(*credp));
818 }
819 SAFE_FREE(*credp);
820 } else {
821 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
822 ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
823
824 if (ldap_state->anonymous) {
825 *whop = NULL;
826 *credp = NULL;
827 } else {
828 *whop = SMB_STRDUP(ldap_state->bind_dn);
829 if (!*whop) {
830 return LDAP_NO_MEMORY;
831 }
832 *credp = SMB_STRDUP(ldap_state->bind_secret);
833 if (!*credp) {
834 SAFE_FREE(*whop);
835 return LDAP_NO_MEMORY;
836 }
837 }
838 *methodp = LDAP_AUTH_SIMPLE;
839 }
840
841 clock_gettime_mono(&ts);
842 ldap_state->last_rebind = convert_timespec_to_timeval(ts);
843
844 return 0;
845}
846#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
847
848/*******************************************************************
849 a rebind function for authenticated referrals
850 This version takes a void* that we can shove useful stuff in :-)
851 and actually does the connection.
852******************************************************************/
853#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
854static int rebindproc_connect_with_state (LDAP *ldap_struct,
855 LDAP_CONST char *url,
856 ber_tag_t request,
857 ber_int_t msgid, void *arg)
858{
859 struct smbldap_state *ldap_state =
860 (struct smbldap_state *)arg;
861 int rc;
862 struct timespec ts;
863 int version;
864
865 DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n",
866 url, ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
867
868 /* call START_TLS again (ldaps:// is handled by the OpenLDAP library
869 * itself) before rebinding to another LDAP server to avoid to expose
870 * our credentials. At least *try* to secure the connection - Guenther */
871
872 smb_ldap_upgrade_conn(ldap_struct, &version);
873 smbldap_start_tls(ldap_struct, version);
874
875 /** @TODO Should we be doing something to check what servers we rebind to?
876 Could we get a referral to a machine that we don't want to give our
877 username and password to? */
878
879 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
880
881 /* only set the last rebind timestamp when we did rebind after a
882 * non-read LDAP operation. That way we avoid the replication sleep
883 * after a simple redirected search operation - Guenther */
884
885 switch (request) {
886
887 case LDAP_REQ_MODIFY:
888 case LDAP_REQ_ADD:
889 case LDAP_REQ_DELETE:
890 case LDAP_REQ_MODDN:
891 case LDAP_REQ_EXTENDED:
892 DEBUG(10,("rebindproc_connect_with_state: "
893 "setting last_rebind timestamp "
894 "(req: 0x%02x)\n", (unsigned int)request));
895 clock_gettime_mono(&ts);
896 ldap_state->last_rebind = convert_timespec_to_timeval(ts);
897 break;
898 default:
899 ZERO_STRUCT(ldap_state->last_rebind);
900 break;
901 }
902
903 return rc;
904}
905#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
906
907/*******************************************************************
908 Add a rebind function for authenticated referrals
909******************************************************************/
910#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
911#else
912# if LDAP_SET_REBIND_PROC_ARGS == 2
913static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
914 int *method, int freeit )
915{
916 struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
917
918 return rebindproc_with_state(ldap_struct, whop, credp,
919 method, freeit, ldap_state);
920}
921# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
922#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
923
924/*******************************************************************
925 a rebind function for authenticated referrals
926 this also does the connection, but no void*.
927******************************************************************/
928#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
929# if LDAP_SET_REBIND_PROC_ARGS == 2
930static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
931 ber_int_t msgid)
932{
933 struct smbldap_state *ldap_state = smbldap_find_state(ld);
934
935 return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
936 ldap_state);
937}
938# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
939#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
940
941/*******************************************************************
942 connect to the ldap server under system privilege.
943******************************************************************/
944static int smbldap_connect_system(struct smbldap_state *ldap_state)
945{
946 LDAP *ldap_struct = ldap_state->ldap_struct;
947 int rc;
948 int version;
949
950 /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
951 (OpenLDAP) doesnt' seem to support it */
952
953 DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
954 ldap_state->uri, ldap_state->bind_dn));
955
956#ifdef HAVE_LDAP_SET_REBIND_PROC
957#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
958# if LDAP_SET_REBIND_PROC_ARGS == 2
959 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
960# endif
961# if LDAP_SET_REBIND_PROC_ARGS == 3
962 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
963# endif
964#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
965# if LDAP_SET_REBIND_PROC_ARGS == 2
966 ldap_set_rebind_proc(ldap_struct, &rebindproc);
967# endif
968# if LDAP_SET_REBIND_PROC_ARGS == 3
969 ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
970# endif
971#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
972#endif
973
974 /* When there is an alternative bind callback is set,
975 attempt to use it to perform the bind */
976 if (ldap_state->bind_callback != NULL) {
977 /* We have to allow bind callback to be run under become_root/unbecome_root
978 to make sure within smbd the callback has proper write access to its resources,
979 like credential cache. This is similar to passdb case where this callback is supposed
980 to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
981 */
982 become_root();
983 rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
984 unbecome_root();
985 } else {
986 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
987 }
988
989 if (rc != LDAP_SUCCESS) {
990 char *ld_error = NULL;
991 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
992 &ld_error);
993 DEBUG(ldap_state->num_failures ? 2 : 0,
994 ("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
995 ldap_state->uri,
996 ldap_state->bind_dn ? ldap_state->bind_dn : "[Anonymous bind]",
997 ldap_err2string(rc),
998 ld_error ? ld_error : "(unknown)"));
999 SAFE_FREE(ld_error);
1000 ldap_state->num_failures++;
1001 goto done;
1002 }
1003
1004 ldap_state->num_failures = 0;
1005 ldap_state->paged_results = False;
1006
1007 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
1008
1009 if (smbldap_has_control(ldap_state->ldap_struct, ADS_PAGE_CTL_OID) && version == 3) {
1010 ldap_state->paged_results = True;
1011 }
1012
1013 DEBUG(3, ("ldap_connect_system: successful connection to the LDAP server\n"));
1014 DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n",
1015 ldap_state->paged_results ? "does" : "does not"));
1016done:
1017 if (rc != 0) {
1018 ldap_unbind(ldap_struct);
1019 ldap_state->ldap_struct = NULL;
1020 }
1021 return rc;
1022}
1023
1024static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
1025 struct tevent_timer *te,
1026 struct timeval now_abs,
1027 void *private_data);
1028
1029/**********************************************************************
1030 Connect to LDAP server (called before every ldap operation)
1031*********************************************************************/
1032static int smbldap_open(struct smbldap_state *ldap_state)
1033{
1034 int rc, opt_rc;
1035 bool reopen = False;
1036 SMB_ASSERT(ldap_state);
1037
1038 if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time_mono(NULL))) {
1039
1040#ifdef HAVE_UNIXSOCKET
1041 struct sockaddr_un addr;
1042#else
1043 struct sockaddr addr;
1044#endif
1045 socklen_t len = sizeof(addr);
1046 int sd;
1047
1048 opt_rc = ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd);
1049 if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
1050 reopen = True;
1051
1052#ifdef HAVE_UNIXSOCKET
1053 if (opt_rc == 0 && addr.sun_family == AF_UNIX)
1054 reopen = True;
1055#endif
1056 if (reopen) {
1057 /* the other end has died. reopen. */
1058 ldap_unbind(ldap_state->ldap_struct);
1059 ldap_state->ldap_struct = NULL;
1060 ldap_state->last_ping = (time_t)0;
1061 } else {
1062 ldap_state->last_ping = time_mono(NULL);
1063 }
1064 }
1065
1066 if (ldap_state->ldap_struct != NULL) {
1067 DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
1068 return LDAP_SUCCESS;
1069 }
1070
1071 if ((rc = smbldap_open_connection(ldap_state))) {
1072 return rc;
1073 }
1074
1075 if ((rc = smbldap_connect_system(ldap_state))) {
1076 return rc;
1077 }
1078
1079
1080 ldap_state->last_ping = time_mono(NULL);
1081 ldap_state->pid = getpid();
1082
1083 TALLOC_FREE(ldap_state->idle_event);
1084
1085 if (ldap_state->tevent_context != NULL) {
1086 ldap_state->idle_event = tevent_add_timer(
1087 ldap_state->tevent_context, ldap_state,
1088 timeval_current_ofs(SMBLDAP_IDLE_TIME, 0),
1089 smbldap_idle_fn, ldap_state);
1090 }
1091
1092 DEBUG(4,("The LDAP server is successfully connected\n"));
1093
1094 return LDAP_SUCCESS;
1095}
1096
1097/**********************************************************************
1098Disconnect from LDAP server
1099*********************************************************************/
1100static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
1101{
1102 if (!ldap_state)
1103 return NT_STATUS_INVALID_PARAMETER;
1104
1105 if (ldap_state->ldap_struct != NULL) {
1106 ldap_unbind(ldap_state->ldap_struct);
1107 ldap_state->ldap_struct = NULL;
1108 }
1109
1110 smbldap_delete_state(ldap_state);
1111
1112 TALLOC_FREE(ldap_state->idle_event);
1113
1114 DEBUG(5,("The connection to the LDAP server was closed\n"));
1115 /* maybe free the results here --metze */
1116
1117 return NT_STATUS_OK;
1118}
1119
1120static SIG_ATOMIC_T got_alarm;
1121
1122static void gotalarm_sig(int dummy)
1123{
1124 got_alarm = 1;
1125}
1126
1127static time_t calc_ldap_abs_endtime(int ldap_to)
1128{
1129 if (ldap_to == 0) {
1130 /* No timeout - don't
1131 return a value for
1132 the alarm. */
1133 return (time_t)0;
1134 }
1135
1136 /* Make the alarm time one second beyond
1137 the timout we're setting for the
1138 remote search timeout, to allow that
1139 to fire in preference. */
1140
1141 return time_mono(NULL)+ldap_to+1;
1142}
1143
1144static int end_ldap_local_alarm(time_t absolute_endtime, int rc)
1145{
1146 if (absolute_endtime) {
1147 alarm(0);
1148 CatchSignal(SIGALRM, SIG_IGN);
1149 if (got_alarm) {
1150 /* Client timeout error code. */
1151 got_alarm = 0;
1152 return LDAP_TIMEOUT;
1153 }
1154 }
1155 return rc;
1156}
1157
1158static void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t absolute_endtime)
1159{
1160 time_t now = time_mono(NULL);
1161
1162 if (absolute_endtime) {
1163 got_alarm = 0;
1164 CatchSignal(SIGALRM, gotalarm_sig);
1165 alarm(absolute_endtime - now);
1166 }
1167
1168 if (ldap_state->pid != getpid()) {
1169 smbldap_close(ldap_state);
1170 }
1171}
1172
1173static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
1174{
1175 ldap_get_option(ldap_state->ldap_struct,
1176 LDAP_OPT_ERROR_NUMBER, p_ld_errno);
1177
1178 ldap_get_option(ldap_state->ldap_struct,
1179 LDAP_OPT_ERROR_STRING, pp_ld_error);
1180}
1181
1182static int get_cached_ldap_connect(struct smbldap_state *ldap_state, time_t abs_endtime)
1183{
1184 int attempts = 0;
1185
1186 while (1) {
1187 int rc;
1188 time_t now;
1189
1190 now = time_mono(NULL);
1191 ldap_state->last_use = now;
1192
1193 if (abs_endtime && now > abs_endtime) {
1194 smbldap_close(ldap_state);
1195 return LDAP_TIMEOUT;
1196 }
1197
1198 rc = smbldap_open(ldap_state);
1199
1200 if (rc == LDAP_SUCCESS) {
1201 return LDAP_SUCCESS;
1202 }
1203
1204 attempts++;
1205 DEBUG(1, ("Connection to LDAP server failed for the "
1206 "%d try!\n", attempts));
1207
1208 if (rc == LDAP_INSUFFICIENT_ACCESS) {
1209 /* The fact that we are non-root or any other
1210 * access-denied condition will not change in the next
1211 * round of trying */
1212 return rc;
1213 }
1214
1215 if (got_alarm) {
1216 smbldap_close(ldap_state);
1217 return LDAP_TIMEOUT;
1218 }
1219
1220 smb_msleep(1000);
1221
1222 if (got_alarm) {
1223 smbldap_close(ldap_state);
1224 return LDAP_TIMEOUT;
1225 }
1226 }
1227}
1228
1229/*********************************************************************
1230 ********************************************************************/
1231
1232static int smbldap_search_ext(struct smbldap_state *ldap_state,
1233 const char *base, int scope, const char *filter,
1234 const char *attrs[], int attrsonly,
1235 LDAPControl **sctrls, LDAPControl **cctrls,
1236 int sizelimit, LDAPMessage **res)
1237{
1238 int rc = LDAP_SERVER_DOWN;
1239 char *utf8_filter;
1240 int to = lp_ldap_timeout();
1241 time_t abs_endtime = calc_ldap_abs_endtime(to);
1242 struct timeval timeout;
1243 struct timeval *timeout_ptr = NULL;
1244 size_t converted_size;
1245
1246 SMB_ASSERT(ldap_state);
1247
1248 DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], "
1249 "scope => [%d]\n", base, filter, scope));
1250
1251 if (ldap_state->last_rebind.tv_sec > 0) {
1252 struct timeval tval;
1253 struct timespec ts;
1254 int64_t tdiff = 0;
1255 int sleep_time = 0;
1256
1257 clock_gettime_mono(&ts);
1258 tval = convert_timespec_to_timeval(ts);
1259
1260 tdiff = usec_time_diff(&tval, &ldap_state->last_rebind);
1261 tdiff /= 1000; /* Convert to milliseconds. */
1262
1263 sleep_time = lp_ldap_replication_sleep()-(int)tdiff;
1264 sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME);
1265
1266 if (sleep_time > 0) {
1267 /* we wait for the LDAP replication */
1268 DEBUG(5,("smbldap_search_ext: waiting %d milliseconds "
1269 "for LDAP replication.\n",sleep_time));
1270 smb_msleep(sleep_time);
1271 DEBUG(5,("smbldap_search_ext: go on!\n"));
1272 }
1273 ZERO_STRUCT(ldap_state->last_rebind);
1274 }
1275
1276 if (!push_utf8_talloc(talloc_tos(), &utf8_filter, filter, &converted_size)) {
1277 return LDAP_NO_MEMORY;
1278 }
1279
1280 /* Setup remote timeout for the ldap_search_ext_s call. */
1281 if (to) {
1282 timeout.tv_sec = to;
1283 timeout.tv_usec = 0;
1284 timeout_ptr = &timeout;
1285 }
1286
1287 setup_ldap_local_alarm(ldap_state, abs_endtime);
1288
1289 while (1) {
1290 char *ld_error = NULL;
1291 int ld_errno;
1292
1293 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1294 if (rc != LDAP_SUCCESS) {
1295 break;
1296 }
1297
1298 rc = ldap_search_ext_s(ldap_state->ldap_struct, base, scope,
1299 utf8_filter,
1300 discard_const_p(char *, attrs),
1301 attrsonly, sctrls, cctrls, timeout_ptr,
1302 sizelimit, res);
1303 if (rc == LDAP_SUCCESS) {
1304 break;
1305 }
1306
1307 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1308
1309 DEBUG(10, ("Failed search for base: %s, error: %d (%s) "
1310 "(%s)\n", base, ld_errno,
1311 ldap_err2string(rc),
1312 ld_error ? ld_error : "unknown"));
1313 SAFE_FREE(ld_error);
1314
1315 if (ld_errno != LDAP_SERVER_DOWN) {
1316 break;
1317 }
1318 ldap_unbind(ldap_state->ldap_struct);
1319 ldap_state->ldap_struct = NULL;
1320 }
1321
1322 TALLOC_FREE(utf8_filter);
1323 return end_ldap_local_alarm(abs_endtime, rc);
1324}
1325
1326int smbldap_search(struct smbldap_state *ldap_state,
1327 const char *base, int scope, const char *filter,
1328 const char *attrs[], int attrsonly,
1329 LDAPMessage **res)
1330{
1331 return smbldap_search_ext(ldap_state, base, scope, filter, attrs,
1332 attrsonly, NULL, NULL, LDAP_NO_LIMIT, res);
1333}
1334
1335int smbldap_search_paged(struct smbldap_state *ldap_state,
1336 const char *base, int scope, const char *filter,
1337 const char **attrs, int attrsonly, int pagesize,
1338 LDAPMessage **res, void **cookie)
1339{
1340 LDAPControl pr;
1341 LDAPControl **rcontrols;
1342 LDAPControl *controls[2] = { NULL, NULL};
1343 BerElement *cookie_be = NULL;
1344 struct berval *cookie_bv = NULL;
1345 int tmp = 0, i, rc;
1346 bool critical = True;
1347
1348 *res = NULL;
1349
1350 DEBUG(3,("smbldap_search_paged: base => [%s], filter => [%s],"
1351 "scope => [%d], pagesize => [%d]\n",
1352 base, filter, scope, pagesize));
1353
1354 cookie_be = ber_alloc_t(LBER_USE_DER);
1355 if (cookie_be == NULL) {
1356 DEBUG(0,("smbldap_create_page_control: ber_alloc_t returns "
1357 "NULL\n"));
1358 return LDAP_NO_MEMORY;
1359 }
1360
1361 /* construct cookie */
1362 if (*cookie != NULL) {
1363 ber_printf(cookie_be, "{iO}", (ber_int_t) pagesize, *cookie);
1364 ber_bvfree((struct berval *)*cookie); /* don't need it from last time */
1365 *cookie = NULL;
1366 } else {
1367 ber_printf(cookie_be, "{io}", (ber_int_t) pagesize, "", 0);
1368 }
1369 ber_flatten(cookie_be, &cookie_bv);
1370
1371 pr.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID);
1372 pr.ldctl_iscritical = (char) critical;
1373 pr.ldctl_value.bv_len = cookie_bv->bv_len;
1374 pr.ldctl_value.bv_val = cookie_bv->bv_val;
1375
1376 controls[0] = &pr;
1377 controls[1] = NULL;
1378
1379 rc = smbldap_search_ext(ldap_state, base, scope, filter, attrs,
1380 0, controls, NULL, LDAP_NO_LIMIT, res);
1381
1382 ber_free(cookie_be, 1);
1383 ber_bvfree(cookie_bv);
1384
1385 if (rc != 0) {
1386 DEBUG(3,("smbldap_search_paged: smbldap_search_ext(%s) "
1387 "failed with [%s]\n", filter, ldap_err2string(rc)));
1388 goto done;
1389 }
1390
1391 DEBUG(3,("smbldap_search_paged: search was successful\n"));
1392
1393 rc = ldap_parse_result(ldap_state->ldap_struct, *res, NULL, NULL,
1394 NULL, NULL, &rcontrols, 0);
1395 if (rc != 0) {
1396 DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
1397 "with [%s]\n", ldap_err2string(rc)));
1398 goto done;
1399 }
1400
1401 if (rcontrols == NULL)
1402 goto done;
1403
1404 for (i=0; rcontrols[i]; i++) {
1405
1406 if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) != 0)
1407 continue;
1408
1409 cookie_be = ber_init(&rcontrols[i]->ldctl_value);
1410 ber_scanf(cookie_be,"{iO}", &tmp, &cookie_bv);
1411 /* the berval is the cookie, but must be freed when it is all
1412 done */
1413 if (cookie_bv->bv_len)
1414 *cookie=ber_bvdup(cookie_bv);
1415 else
1416 *cookie=NULL;
1417 ber_bvfree(cookie_bv);
1418 ber_free(cookie_be, 1);
1419 break;
1420 }
1421 ldap_controls_free(rcontrols);
1422done:
1423 return rc;
1424}
1425
1426int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
1427{
1428 int rc = LDAP_SERVER_DOWN;
1429 char *utf8_dn;
1430 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1431 size_t converted_size;
1432
1433 SMB_ASSERT(ldap_state);
1434
1435 DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
1436
1437 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1438 return LDAP_NO_MEMORY;
1439 }
1440
1441 setup_ldap_local_alarm(ldap_state, abs_endtime);
1442
1443 while (1) {
1444 char *ld_error = NULL;
1445 int ld_errno;
1446
1447 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1448 if (rc != LDAP_SUCCESS) {
1449 break;
1450 }
1451
1452 rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
1453 if (rc == LDAP_SUCCESS) {
1454 break;
1455 }
1456
1457 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1458
1459 DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) "
1460 "(%s)\n", dn, ld_errno,
1461 ldap_err2string(rc),
1462 ld_error ? ld_error : "unknown"));
1463 SAFE_FREE(ld_error);
1464
1465 if (ld_errno != LDAP_SERVER_DOWN) {
1466 break;
1467 }
1468 ldap_unbind(ldap_state->ldap_struct);
1469 ldap_state->ldap_struct = NULL;
1470 }
1471
1472 TALLOC_FREE(utf8_dn);
1473 return end_ldap_local_alarm(abs_endtime, rc);
1474}
1475
1476int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
1477{
1478 int rc = LDAP_SERVER_DOWN;
1479 char *utf8_dn;
1480 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1481 size_t converted_size;
1482
1483 SMB_ASSERT(ldap_state);
1484
1485 DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
1486
1487 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1488 return LDAP_NO_MEMORY;
1489 }
1490
1491 setup_ldap_local_alarm(ldap_state, abs_endtime);
1492
1493 while (1) {
1494 char *ld_error = NULL;
1495 int ld_errno;
1496
1497 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1498 if (rc != LDAP_SUCCESS) {
1499 break;
1500 }
1501
1502 rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
1503 if (rc == LDAP_SUCCESS) {
1504 break;
1505 }
1506
1507 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1508
1509 DEBUG(10, ("Failed to add dn: %s, error: %d (%s) "
1510 "(%s)\n", dn, ld_errno,
1511 ldap_err2string(rc),
1512 ld_error ? ld_error : "unknown"));
1513 SAFE_FREE(ld_error);
1514
1515 if (ld_errno != LDAP_SERVER_DOWN) {
1516 break;
1517 }
1518 ldap_unbind(ldap_state->ldap_struct);
1519 ldap_state->ldap_struct = NULL;
1520 }
1521
1522 TALLOC_FREE(utf8_dn);
1523 return end_ldap_local_alarm(abs_endtime, rc);
1524}
1525
1526int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
1527{
1528 int rc = LDAP_SERVER_DOWN;
1529 char *utf8_dn;
1530 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1531 size_t converted_size;
1532
1533 SMB_ASSERT(ldap_state);
1534
1535 DEBUG(5,("smbldap_delete: dn => [%s]\n", dn ));
1536
1537 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1538 return LDAP_NO_MEMORY;
1539 }
1540
1541 setup_ldap_local_alarm(ldap_state, abs_endtime);
1542
1543 while (1) {
1544 char *ld_error = NULL;
1545 int ld_errno;
1546
1547 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1548 if (rc != LDAP_SUCCESS) {
1549 break;
1550 }
1551
1552 rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
1553 if (rc == LDAP_SUCCESS) {
1554 break;
1555 }
1556
1557 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1558
1559 DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) "
1560 "(%s)\n", dn, ld_errno,
1561 ldap_err2string(rc),
1562 ld_error ? ld_error : "unknown"));
1563 SAFE_FREE(ld_error);
1564
1565 if (ld_errno != LDAP_SERVER_DOWN) {
1566 break;
1567 }
1568 ldap_unbind(ldap_state->ldap_struct);
1569 ldap_state->ldap_struct = NULL;
1570 }
1571
1572 TALLOC_FREE(utf8_dn);
1573 return end_ldap_local_alarm(abs_endtime, rc);
1574}
1575
1576int smbldap_extended_operation(struct smbldap_state *ldap_state,
1577 LDAP_CONST char *reqoid, struct berval *reqdata,
1578 LDAPControl **serverctrls, LDAPControl **clientctrls,
1579 char **retoidp, struct berval **retdatap)
1580{
1581 int rc = LDAP_SERVER_DOWN;
1582 time_t abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
1583
1584 if (!ldap_state)
1585 return (-1);
1586
1587 setup_ldap_local_alarm(ldap_state, abs_endtime);
1588
1589 while (1) {
1590 char *ld_error = NULL;
1591 int ld_errno;
1592
1593 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
1594 if (rc != LDAP_SUCCESS) {
1595 break;
1596 }
1597
1598 rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid,
1599 reqdata, serverctrls,
1600 clientctrls, retoidp, retdatap);
1601 if (rc == LDAP_SUCCESS) {
1602 break;
1603 }
1604
1605 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
1606
1607 DEBUG(10, ("Extended operation failed with error: "
1608 "%d (%s) (%s)\n", ld_errno,
1609 ldap_err2string(rc),
1610 ld_error ? ld_error : "unknown"));
1611 SAFE_FREE(ld_error);
1612
1613 if (ld_errno != LDAP_SERVER_DOWN) {
1614 break;
1615 }
1616 ldap_unbind(ldap_state->ldap_struct);
1617 ldap_state->ldap_struct = NULL;
1618 }
1619
1620 return end_ldap_local_alarm(abs_endtime, rc);
1621}
1622
1623/*******************************************************************
1624 run the search by name.
1625******************************************************************/
1626int smbldap_search_suffix (struct smbldap_state *ldap_state,
1627 const char *filter, const char **search_attr,
1628 LDAPMessage ** result)
1629{
1630 return smbldap_search(ldap_state, lp_ldap_suffix(talloc_tos()),
1631 LDAP_SCOPE_SUBTREE,
1632 filter, search_attr, 0, result);
1633}
1634
1635static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
1636 struct tevent_timer *te,
1637 struct timeval now_abs,
1638 void *private_data)
1639{
1640 struct smbldap_state *state = (struct smbldap_state *)private_data;
1641
1642 TALLOC_FREE(state->idle_event);
1643
1644 if (state->ldap_struct == NULL) {
1645 DEBUG(10,("ldap connection not connected...\n"));
1646 return;
1647 }
1648
1649 if ((state->last_use+SMBLDAP_IDLE_TIME) > time_mono(NULL)) {
1650 DEBUG(10,("ldap connection not idle...\n"));
1651
1652 /* this needs to be made monotonic clock aware inside tevent: */
1653 state->idle_event = tevent_add_timer(
1654 tevent_ctx, state,
1655 timeval_add(&now_abs, SMBLDAP_IDLE_TIME, 0),
1656 smbldap_idle_fn,
1657 private_data);
1658 return;
1659 }
1660
1661 DEBUG(7,("ldap connection idle...closing connection\n"));
1662 smbldap_close(state);
1663}
1664
1665/**********************************************************************
1666 Housekeeping
1667 *********************************************************************/
1668
1669void smbldap_free_struct(struct smbldap_state **ldap_state)
1670{
1671 smbldap_close(*ldap_state);
1672
1673 if ((*ldap_state)->bind_secret) {
1674 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
1675 }
1676
1677 SAFE_FREE((*ldap_state)->bind_dn);
1678 SAFE_FREE((*ldap_state)->bind_secret);
1679 (*ldap_state)->bind_callback = NULL;
1680 (*ldap_state)->bind_callback_data = NULL;
1681
1682 TALLOC_FREE(*ldap_state);
1683
1684 /* No need to free any further, as it is talloc()ed */
1685}
1686
1687static int smbldap_state_destructor(struct smbldap_state *state)
1688{
1689 smbldap_free_struct(&state);
1690 return 0;
1691}
1692
1693
1694/**********************************************************************
1695 Intitalise the 'general' ldap structures, on which ldap operations may be conducted
1696 *********************************************************************/
1697
1698NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct tevent_context *tevent_ctx,
1699 const char *location,
1700 bool anon,
1701 const char *bind_dn,
1702 const char *bind_secret,
1703 struct smbldap_state **smbldap_state)
1704{
1705 *smbldap_state = talloc_zero(mem_ctx, struct smbldap_state);
1706 if (!*smbldap_state) {
1707 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
1708 return NT_STATUS_NO_MEMORY;
1709 }
1710
1711 if (location) {
1712 (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
1713 } else {
1714 (*smbldap_state)->uri = "ldap://localhost";
1715 }
1716
1717 (*smbldap_state)->tevent_context = tevent_ctx;
1718
1719 if (bind_dn && bind_secret) {
1720 smbldap_set_creds(*smbldap_state, anon, bind_dn, bind_secret);
1721 }
1722
1723 talloc_set_destructor(*smbldap_state, smbldap_state_destructor);
1724 return NT_STATUS_OK;
1725}
1726
1727 char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld,
1728 LDAPMessage *entry)
1729{
1730 char *utf8_dn, *unix_dn;
1731 size_t converted_size;
1732
1733 utf8_dn = ldap_get_dn(ld, entry);
1734 if (!utf8_dn) {
1735 DEBUG (5, ("smbldap_talloc_dn: ldap_get_dn failed\n"));
1736 return NULL;
1737 }
1738 if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
1739 DEBUG (0, ("smbldap_talloc_dn: String conversion failure utf8 "
1740 "[%s]\n", utf8_dn));
1741 return NULL;
1742 }
1743 ldap_memfree(utf8_dn);
1744 return unix_dn;
1745}
1746
1747/*******************************************************************
1748 Check if root-dse has a certain Control or Extension
1749********************************************************************/
1750
1751static bool smbldap_check_root_dse(LDAP *ld, const char **attrs, const char *value)
1752{
1753 LDAPMessage *msg = NULL;
1754 LDAPMessage *entry = NULL;
1755 char **values = NULL;
1756 int rc, num_result, num_values, i;
1757 bool result = False;
1758
1759 if (!attrs[0]) {
1760 DEBUG(3,("smbldap_check_root_dse: nothing to look for\n"));
1761 return False;
1762 }
1763
1764 if (!strequal(attrs[0], "supportedExtension") &&
1765 !strequal(attrs[0], "supportedControl") &&
1766 !strequal(attrs[0], "namingContexts")) {
1767 DEBUG(3,("smbldap_check_root_dse: no idea what to query root-dse for: %s ?\n", attrs[0]));
1768 return False;
1769 }
1770
1771 rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE,
1772 "(objectclass=*)", discard_const_p(char *, attrs), 0 , &msg);
1773
1774 if (rc != LDAP_SUCCESS) {
1775 DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n"));
1776 return False;
1777 }
1778
1779 num_result = ldap_count_entries(ld, msg);
1780
1781 if (num_result != 1) {
1782 DEBUG(3,("smbldap_check_root_dse: Expected one rootDSE, got %d\n", num_result));
1783 goto done;
1784 }
1785
1786 entry = ldap_first_entry(ld, msg);
1787
1788 if (entry == NULL) {
1789 DEBUG(3,("smbldap_check_root_dse: Could not retrieve rootDSE\n"));
1790 goto done;
1791 }
1792
1793 values = ldap_get_values(ld, entry, attrs[0]);
1794
1795 if (values == NULL) {
1796 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not support any %s\n", attrs[0]));
1797 goto done;
1798 }
1799
1800 num_values = ldap_count_values(values);
1801
1802 if (num_values == 0) {
1803 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not have any %s\n", attrs[0]));
1804 goto done;
1805 }
1806
1807 for (i=0; i<num_values; i++) {
1808 if (strcmp(values[i], value) == 0)
1809 result = True;
1810 }
1811
1812
1813 done:
1814 if (values != NULL)
1815 ldap_value_free(values);
1816 if (msg != NULL)
1817 ldap_msgfree(msg);
1818
1819 return result;
1820
1821}
1822
1823/*******************************************************************
1824 Check if LDAP-Server supports a certain Control (OID in string format)
1825********************************************************************/
1826
1827bool smbldap_has_control(LDAP *ld, const char *control)
1828{
1829 const char *attrs[] = { "supportedControl", NULL };
1830 return smbldap_check_root_dse(ld, attrs, control);
1831}
1832
1833/*******************************************************************
1834 Check if LDAP-Server supports a certain Extension (OID in string format)
1835********************************************************************/
1836
1837bool smbldap_has_extension(LDAP *ld, const char *extension)
1838{
1839 const char *attrs[] = { "supportedExtension", NULL };
1840 return smbldap_check_root_dse(ld, attrs, extension);
1841}
1842
1843/*******************************************************************
1844 Check if LDAP-Server holds a given namingContext
1845********************************************************************/
1846
1847bool smbldap_has_naming_context(LDAP *ld, const char *naming_context)
1848{
1849 const char *attrs[] = { "namingContexts", NULL };
1850 return smbldap_check_root_dse(ld, attrs, naming_context);
1851}
1852
1853bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *dn, const char *secret)
1854{
1855 ldap_state->anonymous = anon;
1856
1857 /* free any previously set credential */
1858
1859 SAFE_FREE(ldap_state->bind_dn);
1860 ldap_state->bind_callback = NULL;
1861 ldap_state->bind_callback_data = NULL;
1862
1863 if (ldap_state->bind_secret) {
1864 /* make sure secrets are zeroed out of memory */
1865 memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));
1866 SAFE_FREE(ldap_state->bind_secret);
1867 }
1868
1869 if ( ! anon) {
1870 ldap_state->bind_dn = SMB_STRDUP(dn);
1871 ldap_state->bind_secret = SMB_STRDUP(secret);
1872 }
1873
1874 return True;
1875}
Note: See TracBrowser for help on using the repository browser.