1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Mozilla Communicator client code, released
15 * March 31, 1998.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-1999
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37 /*
38 * Copyright (c) 1995 Regents of the University of Michigan.
39 * All rights reserved.
40 */
41 /*
42 * open.c
43 */
44
45 #if 0
46 # ifndef lint
47 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
48 # endif
49 #endif
50
51 #include "ldap-int.h"
52 #ifdef LDAP_SASLIO_HOOKS
53 /* Valid for any ANSI C compiler */
54 # include <limits.h>
55 extern sasl_callback_t client_callbacks[];
56 #endif
57
58 #define VI_PRODUCTVERSION 3
59
60 #ifndef INADDR_LOOPBACK
61 # define INADDR_LOOPBACK ((unsigned long)0x7f000001)
62 #endif
63
64 #ifdef LDAP_DEBUG
65 int ldap_debug = 0;
66 #endif
67
68 #ifdef _WINDOWS
69 # define USE_WINDOWS_TLS /* thread local storage */
70 #endif
71
72 /*
73 * global defaults for callbacks are stored here. callers of the API set
74 * these by passing a NULL "ld" to ldap_set_option(). Everything in
75 * nsldapi_ld_defaults can be overridden on a per-ld basis as well (the
76 * memory allocation functions are global to all ld's).
77 */
78 struct ldap nsldapi_ld_defaults;
79 struct ldap_memalloc_fns nsldapi_memalloc_fns = {0, 0, 0, 0};
80 int nsldapi_initialized = 0;
81
82 #ifdef USE_PTHREADS
83 # include <pthread.h>
84 # ifdef VMS
85 /*
86 ** pthread_self() is not a routine on OpenVMS; it's inline assembler code.
87 ** Since we need a real address which we can stuff away into a table, we need
88 ** to make sure that pthread_self maps to the real pthread_self routine (yes,
89 ** we do have one fortunately).
90 */
91 # undef pthread_self
92 # define pthread_self PTHREAD_SELF
93 extern pthread_t pthread_self(void);
94 # endif
95 static pthread_key_t nsldapi_key;
96 static pthread_mutex_t nsldapi_init_mutex = PTHREAD_MUTEX_INITIALIZER;
97
98 struct nsldapi_ldap_error {
99 int le_errno;
100 char* le_matched;
101 char* le_errmsg;
102 };
103 #elif defined(USE_WINDOWS_TLS)
104 static DWORD dwTlsIndex;
105 struct nsldapi_ldap_error {
106 int le_errno;
107 char* le_matched;
108 char* le_errmsg;
109 };
110 #elif defined(_WINDOWS) /* use static tls */
111 __declspec(thread) int nsldapi_gldaperrno;
112 __declspec(thread) char* nsldapi_gmatched = NULL;
113 __declspec(thread) char* nsldapi_gldaperror = NULL;
114 #endif /* USE_WINDOWS_TLS */
115
116 #ifdef _WINDOWS
117 # define LDAP_MUTEX_T HANDLE
118 static LDAP_MUTEX_T nsldapi_init_mutex;
119
pthread_mutex_init(LDAP_MUTEX_T * mp,void * attr)120 int pthread_mutex_init(LDAP_MUTEX_T* mp, void* attr) {
121 if ((*mp = CreateMutex(NULL, FALSE, NULL)) == NULL)
122 return (1);
123 else
124 return (0);
125 }
126
pthread_mutex_alloc(void)127 static void* pthread_mutex_alloc(void) {
128 LDAP_MUTEX_T* mutexp;
129
130 if ((mutexp = malloc(sizeof(LDAP_MUTEX_T))) != NULL) {
131 pthread_mutex_init(mutexp, NULL);
132 }
133 return (mutexp);
134 }
135
pthread_mutex_destroy(LDAP_MUTEX_T * mp)136 int pthread_mutex_destroy(LDAP_MUTEX_T* mp) {
137 if (!(CloseHandle(*mp)))
138 return (1);
139 else
140 return (0);
141 }
142
pthread_mutex_free(void * mutexp)143 static void pthread_mutex_free(void* mutexp) {
144 pthread_mutex_destroy((LDAP_MUTEX_T*)mutexp);
145 free(mutexp);
146 }
147
pthread_mutex_lock(LDAP_MUTEX_T * mp)148 int pthread_mutex_lock(LDAP_MUTEX_T* mp) {
149 if ((WaitForSingleObject(*mp, INFINITE) != WAIT_OBJECT_0))
150 return (1);
151 else
152 return (0);
153 }
154
pthread_mutex_unlock(LDAP_MUTEX_T * mp)155 int pthread_mutex_unlock(LDAP_MUTEX_T* mp) {
156 if (!(ReleaseMutex(*mp)))
157 return (1);
158 else
159 return (0);
160 }
161
get_errno(void)162 static int get_errno(void) { return errno; }
163
set_errno(int Errno)164 static void set_errno(int Errno) { errno = Errno; }
165
166 # ifdef USE_WINDOWS_TLS
set_ld_error(int err,char * matched,char * errmsg,void * dummy)167 static void set_ld_error(int err, char* matched, char* errmsg, void* dummy) {
168 struct nsldapi_ldap_error* le;
169 void* tsd;
170
171 le = TlsGetValue(dwTlsIndex);
172
173 if (le == NULL) {
174 tsd = (void*)calloc(1, sizeof(struct nsldapi_ldap_error));
175 TlsSetValue(dwTlsIndex, tsd);
176 }
177
178 le = TlsGetValue(dwTlsIndex);
179
180 if (le == NULL) return;
181
182 le->le_errno = err;
183
184 if (le->le_matched != NULL) {
185 ldap_memfree(le->le_matched);
186 }
187 le->le_matched = matched;
188
189 if (le->le_errmsg != NULL) {
190 ldap_memfree(le->le_errmsg);
191 }
192 le->le_errmsg = errmsg;
193 }
194
get_ld_error(char ** matched,char ** errmsg,void * dummy)195 static int get_ld_error(char** matched, char** errmsg, void* dummy) {
196 struct nsldapi_ldap_error* le;
197
198 le = TlsGetValue(dwTlsIndex);
199 if (matched != NULL) {
200 *matched = le->le_matched;
201 }
202
203 if (errmsg != NULL) {
204 *errmsg = le->le_errmsg;
205 }
206
207 return (le->le_errno);
208 }
209 # else
get_ld_error(char ** LDMatched,char ** LDError,void * Args)210 static int get_ld_error(char** LDMatched, char** LDError, void* Args) {
211 if (LDMatched != NULL) {
212 *LDMatched = nsldapi_gmatched;
213 }
214 if (LDError != NULL) {
215 *LDError = nsldapi_gldaperror;
216 }
217 return nsldapi_gldaperrno;
218 }
219
set_ld_error(int LDErrno,char * LDMatched,char * LDError,void * Args)220 static void set_ld_error(int LDErrno, char* LDMatched, char* LDError,
221 void* Args) {
222 /* Clean up any previous string storage. */
223 if (nsldapi_gmatched != NULL) {
224 ldap_memfree(nsldapi_gmatched);
225 }
226 if (nsldapi_gldaperror != NULL) {
227 ldap_memfree(nsldapi_gldaperror);
228 }
229
230 nsldapi_gldaperrno = LDErrno;
231 nsldapi_gmatched = LDMatched;
232 nsldapi_gldaperror = LDError;
233 }
234 # endif /* USE_WINDOWS_TLS */
235 #endif /* ! _WINDOWS */
236
237 #ifdef USE_PTHREADS
pthread_mutex_alloc(void)238 static void* pthread_mutex_alloc(void) {
239 pthread_mutex_t* mutexp;
240
241 if ((mutexp = malloc(sizeof(pthread_mutex_t))) != NULL) {
242 pthread_mutex_init(mutexp, NULL);
243 }
244 return (mutexp);
245 }
246
pthread_mutex_free(void * mutexp)247 static void pthread_mutex_free(void* mutexp) {
248 pthread_mutex_destroy((pthread_mutex_t*)mutexp);
249 free(mutexp);
250 }
251
set_ld_error(int err,char * matched,char * errmsg,void * dummy)252 static void set_ld_error(int err, char* matched, char* errmsg, void* dummy) {
253 struct nsldapi_ldap_error* le;
254 void* tsd;
255
256 le = pthread_getspecific(nsldapi_key);
257
258 if (le == NULL) {
259 tsd = (void*)calloc(1, sizeof(struct nsldapi_ldap_error));
260 pthread_setspecific(nsldapi_key, tsd);
261 }
262
263 le = pthread_getspecific(nsldapi_key);
264
265 if (le == NULL) return;
266
267 le->le_errno = err;
268
269 if (le->le_matched != NULL) {
270 ldap_memfree(le->le_matched);
271 }
272 le->le_matched = matched;
273
274 if (le->le_errmsg != NULL) {
275 ldap_memfree(le->le_errmsg);
276 }
277 le->le_errmsg = errmsg;
278 }
279
get_ld_error(char ** matched,char ** errmsg,void * dummy)280 static int get_ld_error(char** matched, char** errmsg, void* dummy) {
281 struct nsldapi_ldap_error* le;
282
283 le = pthread_getspecific(nsldapi_key);
284
285 if (le == NULL) return (LDAP_SUCCESS);
286
287 if (matched != NULL) {
288 *matched = le->le_matched;
289 }
290 if (errmsg != NULL) {
291 *errmsg = le->le_errmsg;
292 }
293 return (le->le_errno);
294 }
295
set_errno(int err)296 static void set_errno(int err) { errno = err; }
297
get_errno(void)298 static int get_errno(void) { return (errno); }
299 #endif /* use_pthreads */
300
301 #if defined(USE_PTHREADS) || defined(_WINDOWS)
302 static struct ldap_thread_fns nsldapi_default_thread_fns = {
303 (void* (*)(void))pthread_mutex_alloc,
304 (void (*)(void*))pthread_mutex_free,
305 (int (*)(void*))pthread_mutex_lock,
306 (int (*)(void*))pthread_mutex_unlock,
307 (int (*)(void))get_errno,
308 (void (*)(int))set_errno,
309 (int (*)(char**, char**, void*))get_ld_error,
310 (void (*)(int, char*, char*, void*))set_ld_error,
311 0};
312
313 static struct ldap_extra_thread_fns nsldapi_default_extra_thread_fns = {0, 0, 0,
314 0, 0,
315 # ifdef _WINDOWS
316 0
317 # else
318 (void *(*)(void))pthread_self
319 # endif /* _WINDOWS */
320 };
321 #endif /* use_pthreads || _windows */
322
nsldapi_initialize_defaults(void)323 void nsldapi_initialize_defaults(void) {
324 #ifdef _WINDOWS
325 pthread_mutex_init(&nsldapi_init_mutex, NULL);
326 #endif /* _WINDOWS */
327
328 #if defined(USE_PTHREADS) || defined(_WINDOWS)
329 pthread_mutex_lock(&nsldapi_init_mutex);
330
331 if (nsldapi_initialized) {
332 pthread_mutex_unlock(&nsldapi_init_mutex);
333 return;
334 }
335 #else
336 if (nsldapi_initialized) {
337 return;
338 }
339 #endif /* use_pthreads || _windows */
340
341 #ifdef USE_PTHREADS
342 if (pthread_key_create(&nsldapi_key, free) != 0) {
343 perror("pthread_key_create");
344 }
345 #elif defined(USE_WINDOWS_TLS)
346 dwTlsIndex = TlsAlloc();
347 #endif /* USE_WINDOWS_TLS */
348
349 memset(&nsldapi_memalloc_fns, 0, sizeof(nsldapi_memalloc_fns));
350 memset(&nsldapi_ld_defaults, 0, sizeof(nsldapi_ld_defaults));
351 nsldapi_ld_defaults.ld_options = LDAP_BITOPT_REFERRALS;
352 nsldapi_ld_defaults.ld_version = LDAP_VERSION3;
353 nsldapi_ld_defaults.ld_lberoptions = LBER_OPT_USE_DER;
354 nsldapi_ld_defaults.ld_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
355
356 #ifdef LDAP_SASLIO_HOOKS
357 /* SASL default option settings */
358 nsldapi_ld_defaults.ld_def_sasl_mech = NULL;
359 nsldapi_ld_defaults.ld_def_sasl_realm = NULL;
360 nsldapi_ld_defaults.ld_def_sasl_authcid = NULL;
361 nsldapi_ld_defaults.ld_def_sasl_authzid = NULL;
362 /* SASL Security properties */
363 nsldapi_ld_defaults.ld_sasl_secprops.max_ssf = UINT_MAX;
364 nsldapi_ld_defaults.ld_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE;
365 nsldapi_ld_defaults.ld_sasl_secprops.security_flags =
366 SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS;
367
368 /* SASL mutex function callbacks */
369 sasl_set_mutex(
370 (sasl_mutex_alloc_t*)nsldapi_default_thread_fns.ltf_mutex_alloc,
371 (sasl_mutex_lock_t*)nsldapi_default_thread_fns.ltf_mutex_lock,
372 (sasl_mutex_unlock_t*)nsldapi_default_thread_fns.ltf_mutex_unlock,
373 (sasl_mutex_free_t*)nsldapi_default_thread_fns.ltf_mutex_free);
374
375 /* SASL memory allocation function callbacks */
376 sasl_set_alloc((sasl_malloc_t*)ldap_x_malloc, (sasl_calloc_t*)ldap_x_calloc,
377 (sasl_realloc_t*)ldap_x_realloc, (sasl_free_t*)ldap_x_free);
378
379 /* SASL library initialization */
380 if (sasl_client_init(client_callbacks) != SASL_OK) {
381 nsldapi_initialized = 0;
382 pthread_mutex_unlock(&nsldapi_init_mutex);
383 return;
384 }
385 #endif
386
387 #if defined(STR_TRANSLATION) && defined(LDAP_DEFAULT_CHARSET)
388 nsldapi_ld_defaults.ld_lberoptions |= LBER_OPT_TRANSLATE_STRINGS;
389 # if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
390 ldap_set_string_translators(&nsldapi_ld_defaults, ldap_8859_to_t61,
391 ldap_t61_to_8859);
392 # endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
393 #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
394
395 /* set default connect timeout (in milliseconds) */
396 /* this was picked as it is the standard tcp timeout as well */
397 nsldapi_ld_defaults.ld_connect_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
398
399 #if defined(USE_PTHREADS) || defined(_WINDOWS)
400 /* load up default platform specific locking routines */
401 if (ldap_set_option(&nsldapi_ld_defaults, LDAP_OPT_THREAD_FN_PTRS,
402 (void*)&nsldapi_default_thread_fns) != LDAP_SUCCESS) {
403 nsldapi_initialized = 0;
404 pthread_mutex_unlock(&nsldapi_init_mutex);
405 return;
406 }
407
408 # ifndef _WINDOWS
409 /* load up default threadid function */
410 if (ldap_set_option(&nsldapi_ld_defaults, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
411 (void*)&nsldapi_default_extra_thread_fns) !=
412 LDAP_SUCCESS) {
413 nsldapi_initialized = 0;
414 pthread_mutex_unlock(&nsldapi_init_mutex);
415 return;
416 }
417 # endif /* _WINDOWS */
418 nsldapi_initialized = 1;
419 pthread_mutex_unlock(&nsldapi_init_mutex);
420 #else
421 nsldapi_initialized = 1;
422 #endif /* use_pthreads || _windows */
423 }
424
425 /*
426 * ldap_version - report version levels for important properties
427 * This function is deprecated. Use ldap_get_option( ..., LDAP_OPT_API_INFO,
428 * ... ) instead.
429 *
430 * Example:
431 * LDAPVersion ver;
432 * ldap_version(&ver);
433 * if ((ver.sdk_version < 100) || (ver.SSL_version < 300))
434 * fprintf(stderr, "LDAP SDK level insufficient\n");
435 *
436 * or:
437 * if (ldap_version(NULL) < 100)
438 * fprintf(stderr, "LDAP SDK level insufficient\n");
439 */
440
ldap_version(LDAPVersion * ver)441 int LDAP_CALL ldap_version(LDAPVersion* ver) {
442 if (NULL != ver) {
443 memset(ver, 0, sizeof(*ver));
444 ver->sdk_version = (int)(VI_PRODUCTVERSION * 100);
445 ver->protocol_version = LDAP_VERSION_MAX * 100;
446 ver->SSL_version = SSL_VERSION * 100;
447 /*
448 * set security to none by default
449 */
450
451 ver->security_level = LDAP_SECURITY_NONE;
452 #if defined(LINK_SSL)
453 # if defined(NS_DOMESTIC)
454 ver->security_level = 128;
455 # elif defined(NSS_EXPORT)
456 ver->security_level = 40;
457 # endif
458 #endif
459 }
460 return (int)(VI_PRODUCTVERSION * 100);
461 }
462
463 /*
464 * ldap_open - initialize and connect to an ldap server. A magic cookie to
465 * be used for future communication is returned on success, NULL on failure.
466 * "host" may be a space-separated list of hosts or IP addresses
467 *
468 * Example:
469 * LDAP *ld;
470 * ld = ldap_open(hostname, port);
471 */
472
ldap_open(const char * host,int port)473 LDAP* LDAP_CALL ldap_open(const char* host, int port) {
474 LDAP* ld;
475
476 LDAPDebug(LDAP_DEBUG_TRACE, "ldap_open\n");
477
478 if ((ld = ldap_init(host, port)) == NULL) {
479 return (NULL);
480 }
481
482 LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK);
483 if (nsldapi_open_ldap_defconn(ld) < 0) {
484 LDAP_MUTEX_UNLOCK(ld, LDAP_CONN_LOCK);
485 ldap_ld_free(ld, NULL, NULL, 0);
486 return (NULL);
487 }
488
489 LDAP_MUTEX_UNLOCK(ld, LDAP_CONN_LOCK);
490 LDAPDebug(LDAP_DEBUG_TRACE, "ldap_open successful, ld_host is %s\n",
491 (ld->ld_host == NULL) ? "(null)" : ld->ld_host);
492
493 return (ld);
494 }
495
496 /*
497 * ldap_init - initialize the LDAP library. A magic cookie to be used for
498 * future communication is returned on success, NULL on failure.
499 * "defhost" may be a space-separated list of hosts or IP addresses
500 *
501 * NOTE: If you want to use IPv6, you must use prldap creating a LDAP handle
502 * with prldap_init instead of ldap_init. Or install the NSPR functions
503 * by calling prldap_install_routines. (See the nspr samples in examples)
504 *
505 * Example:
506 * LDAP *ld;
507 * ld = ldap_init(default_hostname, default_port);
508 */
ldap_init(const char * defhost,int defport)509 LDAP* LDAP_CALL ldap_init(const char* defhost, int defport) {
510 LDAP* ld;
511
512 if (!nsldapi_initialized) {
513 nsldapi_initialize_defaults();
514 }
515
516 if (defport < 0 || defport > LDAP_PORT_MAX) {
517 LDAPDebug(LDAP_DEBUG_ANY,
518 "ldap_init: port %d is invalid (port numbers must range from 1 "
519 "to %d)\n",
520 defport, LDAP_PORT_MAX);
521 #if !defined(macintosh) && !defined(DOS) && !defined(BEOS)
522 errno = EINVAL;
523 #endif
524 return (NULL);
525 }
526
527 LDAPDebug(LDAP_DEBUG_TRACE, "ldap_init\n");
528
529 if ((ld = (LDAP*)NSLDAPI_MALLOC(sizeof(struct ldap))) == NULL) {
530 return (NULL);
531 }
532
533 /* copy defaults */
534 SAFEMEMCPY(ld, &nsldapi_ld_defaults, sizeof(struct ldap));
535 if (nsldapi_ld_defaults.ld_io_fns_ptr != NULL) {
536 if ((ld->ld_io_fns_ptr = (struct ldap_io_fns*)NSLDAPI_MALLOC(
537 sizeof(struct ldap_io_fns))) == NULL) {
538 NSLDAPI_FREE((char*)ld);
539 return (NULL);
540 }
541 /* struct copy */
542 *(ld->ld_io_fns_ptr) = *(nsldapi_ld_defaults.ld_io_fns_ptr);
543 }
544
545 /* call the new handle I/O callback if one is defined */
546 if (ld->ld_extnewhandle_fn != NULL) {
547 /*
548 * We always pass the session extended I/O argument to
549 * the new handle callback.
550 */
551 if (ld->ld_extnewhandle_fn(ld, ld->ld_ext_session_arg) != LDAP_SUCCESS) {
552 NSLDAPI_FREE((char*)ld);
553 return (NULL);
554 }
555 }
556
557 /* allocate session-specific resources */
558 if ((ld->ld_sbp = ber_sockbuf_alloc()) == NULL ||
559 (defhost != NULL && (ld->ld_defhost = nsldapi_strdup(defhost)) == NULL) ||
560 ((ld->ld_mutex = (void**)NSLDAPI_CALLOC(LDAP_MAX_LOCK, sizeof(void*))) ==
561 NULL)) {
562 if (ld->ld_sbp != NULL) {
563 ber_sockbuf_free(ld->ld_sbp);
564 }
565 if (ld->ld_mutex != NULL) {
566 NSLDAPI_FREE(ld->ld_mutex);
567 }
568 NSLDAPI_FREE((char*)ld);
569 return (NULL);
570 }
571
572 /* install Sockbuf I/O functions if set in LDAP * */
573 if (ld->ld_extread_fn != NULL || ld->ld_extwrite_fn != NULL) {
574 struct lber_x_ext_io_fns lberiofns;
575
576 memset(&lberiofns, 0, sizeof(lberiofns));
577
578 lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
579 lberiofns.lbextiofn_read = ld->ld_extread_fn;
580 lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
581 lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
582 lberiofns.lbextiofn_socket_arg = NULL;
583 ber_sockbuf_set_option(ld->ld_sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
584 (void*)&lberiofns);
585 }
586
587 /* allocate mutexes */
588 nsldapi_mutex_alloc_all(ld);
589
590 /* set default port */
591 ld->ld_defport = (defport == 0) ? LDAP_PORT : defport;
592
593 return (ld);
594 }
595
nsldapi_mutex_alloc_all(LDAP * ld)596 void nsldapi_mutex_alloc_all(LDAP* ld) {
597 int i;
598
599 if (ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL) {
600 for (i = 0; i < LDAP_MAX_LOCK; i++) {
601 ld->ld_mutex[i] = LDAP_MUTEX_ALLOC(ld);
602 ld->ld_mutex_threadid[i] = (void*)-1;
603 ld->ld_mutex_refcnt[i] = 0;
604 }
605 }
606 }
607
nsldapi_mutex_free_all(LDAP * ld)608 void nsldapi_mutex_free_all(LDAP* ld) {
609 int i;
610
611 if (ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL) {
612 for (i = 0; i < LDAP_MAX_LOCK; i++) {
613 LDAP_MUTEX_FREE(ld, ld->ld_mutex[i]);
614 }
615 }
616 }
617
618 /* returns 0 if connection opened and -1 if an error occurs */
nsldapi_open_ldap_defconn(LDAP * ld)619 int nsldapi_open_ldap_defconn(LDAP* ld) {
620 LDAPServer* srv;
621
622 if ((srv = (LDAPServer*)NSLDAPI_CALLOC(1, sizeof(LDAPServer))) == NULL ||
623 (ld->ld_defhost != NULL &&
624 (srv->lsrv_host = nsldapi_strdup(ld->ld_defhost)) == NULL)) {
625 LDAP_SET_LDERRNO(ld, LDAP_NO_MEMORY, NULL, NULL);
626 return (-1);
627 }
628 srv->lsrv_port = ld->ld_defport;
629
630 if ((ld->ld_options & LDAP_BITOPT_SSL) != 0) {
631 srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
632 }
633
634 if ((ld->ld_defconn = nsldapi_new_connection(ld, &srv, 1, 1, 0)) == NULL) {
635 if (ld->ld_defhost != NULL) {
636 NSLDAPI_FREE(srv->lsrv_host);
637 }
638 NSLDAPI_FREE((char*)srv);
639 return (-1);
640 }
641 ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
642
643 return (0);
644 }
645
646 struct ldap_x_hostlist_status {
647 char* lhs_hostlist;
648 char* lhs_nexthost;
649 int lhs_defport;
650 };
651
652 /*
653 * Return the first host and port in hostlist (setting *hostp and *portp).
654 * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
655 * Note that a NULL or zero-length hostlist causes the host "127.0.0.1" to
656 * be returned.
657 */
ldap_x_hostlist_first(const char * hostlist,int defport,char ** hostp,int * portp,struct ldap_x_hostlist_status ** statusp)658 int LDAP_CALL ldap_x_hostlist_first(const char* hostlist, int defport,
659 char** hostp, int* portp,
660 struct ldap_x_hostlist_status** statusp) {
661 if (NULL == hostp || NULL == portp || NULL == statusp) {
662 return (LDAP_PARAM_ERROR);
663 }
664
665 if (NULL == hostlist || *hostlist == '\0') {
666 *hostp = nsldapi_strdup("127.0.0.1");
667 if (NULL == *hostp) {
668 return (LDAP_NO_MEMORY);
669 }
670 *portp = defport;
671 *statusp = NULL;
672 return (LDAP_SUCCESS);
673 }
674
675 *statusp = NSLDAPI_CALLOC(1, sizeof(struct ldap_x_hostlist_status));
676 if (NULL == *statusp) {
677 return (LDAP_NO_MEMORY);
678 }
679 (*statusp)->lhs_hostlist = nsldapi_strdup(hostlist);
680 if (NULL == (*statusp)->lhs_hostlist) {
681 return (LDAP_NO_MEMORY);
682 }
683 (*statusp)->lhs_nexthost = (*statusp)->lhs_hostlist;
684 (*statusp)->lhs_defport = defport;
685 return (ldap_x_hostlist_next(hostp, portp, *statusp));
686 }
687
688 /*
689 * Return the next host and port in hostlist (setting *hostp and *portp).
690 * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
691 * If no more hosts are available, LDAP_SUCCESS is returned but *hostp is set
692 * to NULL.
693 */
ldap_x_hostlist_next(char ** hostp,int * portp,struct ldap_x_hostlist_status * status)694 int LDAP_CALL ldap_x_hostlist_next(char** hostp, int* portp,
695 struct ldap_x_hostlist_status* status) {
696 char* q;
697 int squarebrackets = 0;
698
699 if (NULL == hostp || NULL == portp) {
700 return (LDAP_PARAM_ERROR);
701 }
702
703 if (NULL == status || NULL == status->lhs_nexthost) {
704 *hostp = NULL;
705 return (LDAP_SUCCESS);
706 }
707
708 /*
709 * skip past leading '[' if present (IPv6 addresses may be surrounded
710 * with square brackets, e.g., [fe80::a00:20ff:fee5:c0b4]:389
711 */
712 if (status->lhs_nexthost[0] == '[') {
713 ++status->lhs_nexthost;
714 squarebrackets = 1;
715 }
716
717 /* copy host into *hostp */
718 if (NULL != (q = strchr(status->lhs_nexthost, ' '))) {
719 size_t len = q - status->lhs_nexthost;
720 *hostp = NSLDAPI_MALLOC(len + 1);
721 if (NULL == *hostp) {
722 return (LDAP_NO_MEMORY);
723 }
724 strncpy(*hostp, status->lhs_nexthost, len);
725 (*hostp)[len] = '\0';
726 status->lhs_nexthost += (len + 1);
727 } else { /* last host */
728 *hostp = nsldapi_strdup(status->lhs_nexthost);
729 if (NULL == *hostp) {
730 return (LDAP_NO_MEMORY);
731 }
732 status->lhs_nexthost = NULL;
733 }
734
735 /*
736 * Look for closing ']' and skip past it before looking for port.
737 */
738 if (squarebrackets && NULL != (q = strchr(*hostp, ']'))) {
739 *q++ = '\0';
740 } else {
741 q = *hostp;
742 }
743
744 /* determine and set port */
745 if (NULL != (q = strchr(q, ':'))) {
746 *q++ = '\0';
747 *portp = atoi(q);
748 } else {
749 *portp = status->lhs_defport;
750 }
751
752 return (LDAP_SUCCESS);
753 }
754
755 void LDAP_CALL
ldap_x_hostlist_statusfree(struct ldap_x_hostlist_status * status)756 ldap_x_hostlist_statusfree(struct ldap_x_hostlist_status* status) {
757 if (NULL != status) {
758 if (NULL != status->lhs_hostlist) {
759 NSLDAPI_FREE(status->lhs_hostlist);
760 }
761 NSLDAPI_FREE(status);
762 }
763 }
764
765 /*
766 * memory allocation functions. we include these in open.c since every
767 * LDAP application is likely to pull the rest of the code in this file
768 * in anyways.
769 */
ldap_x_malloc(size_t size)770 void* ldap_x_malloc(size_t size) {
771 return (nsldapi_memalloc_fns.ldapmem_malloc == NULL
772 ? malloc(size)
773 : nsldapi_memalloc_fns.ldapmem_malloc(size));
774 }
775
ldap_x_calloc(size_t nelem,size_t elsize)776 void* ldap_x_calloc(size_t nelem, size_t elsize) {
777 return (nsldapi_memalloc_fns.ldapmem_calloc == NULL
778 ? calloc(nelem, elsize)
779 : nsldapi_memalloc_fns.ldapmem_calloc(nelem, elsize));
780 }
781
ldap_x_realloc(void * ptr,size_t size)782 void* ldap_x_realloc(void* ptr, size_t size) {
783 return (nsldapi_memalloc_fns.ldapmem_realloc == NULL
784 ? realloc(ptr, size)
785 : nsldapi_memalloc_fns.ldapmem_realloc(ptr, size));
786 }
787
ldap_x_free(void * ptr)788 void ldap_x_free(void* ptr) {
789 if (nsldapi_memalloc_fns.ldapmem_free == NULL) {
790 free(ptr);
791 } else {
792 nsldapi_memalloc_fns.ldapmem_free(ptr);
793 }
794 }
795
796 /* if s is NULL, returns NULL */
nsldapi_strdup(const char * s)797 char* nsldapi_strdup(const char* s) {
798 char* p;
799
800 if (s == NULL || (p = (char*)NSLDAPI_MALLOC(strlen(s) + 1)) == NULL)
801 return (NULL);
802
803 strcpy(p, s);
804
805 return (p);
806 }
807