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