summaryrefslogtreecommitdiffstats
path: root/ldap/c-sdk/libldap/ldap-int.h
blob: f64d1b3d3a9021d29b08fb203084ebb6ce702b2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 * 
 * The contents of this file are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this file except in compliance with 
 * the License. You may obtain a copy of the License at 
 * http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 * 
 * The Original Code is Mozilla Communicator client code, released
 * March 31, 1998.
 * 
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998-1999
 * the Initial Developer. All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK ***** */
#ifndef _LDAPINT_H
#define _LDAPINT_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#ifdef hpux
#include <strings.h>
#endif /* hpux */

#ifdef _WINDOWS
#  define FD_SETSIZE		256	/* number of connections we support */
#  define WIN32_LEAN_AND_MEAN
# include <windows.h>
#elif defined(macintosh)
#include "ldap-macos.h"
#else /* _WINDOWS */
# include <sys/time.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
#if !defined(XP_OS2) && !defined(XP_BEOS)
# include <arpa/inet.h>
#endif
# include <netdb.h>
#if !defined(hpux) && !defined(SUNOS4) && !defined(XP_BEOS)
# include <sys/select.h>
#endif /* !defined(hpux) and others */
#endif /* _WINDOWS */

#if defined(IRIX)
#include <bstring.h>
#endif /* IRIX */

#ifdef XP_BEOS
#define NSLDAPI_AVOID_OS_SOCKETS
#endif

#define NSLBERI_LBER_INT_FRIEND
#ifdef macintosh
#include "lber-int.h"
#else /* macintosh */
#include "../liblber/lber-int.h"
#endif /* macintosh */

#include "ldap.h"
#include "ldaprot.h"
#include "ldaplog.h"
#include "portable.h"

#ifdef LDAP_ASYNC_IO
#ifdef NEED_FILIO
#include <sys/filio.h>		/* to get FIONBIO for ioctl() call */
#else /* NEED_FILIO */
#if !defined( _WINDOWS) && !defined (macintosh)
#include <sys/ioctl.h>		/* to get FIONBIO for ioctl() call */
#endif /* _WINDOWS && macintosh */
#endif /* NEED_FILIO */
#endif /* LDAP_ASYNC_IO */

#ifdef USE_SYSCONF
#  include <unistd.h>
#endif /* USE_SYSCONF */

#ifdef LDAP_SASLIO_HOOKS
#include <sasl.h>
#define SASL_MAX_BUFF_SIZE      65536
#define SASL_MIN_BUFF_SIZE      4096
#endif

#if !defined(_WINDOWS) && !defined(macintosh) && !defined(BSDI) && \
    !defined(XP_OS2) && !defined(XP_BEOS) && !defined(NTO) && \
    !defined(DARWIN)
#define NSLDAPI_HAVE_POLL	1
#endif

/* SSL version, or 0 if not built with SSL */
#if defined(NET_SSL)
#  define SSL_VERSION 3
#else
#  define SSL_VERSION 0
#endif


#define LDAP_URL_URLCOLON	"URL:"
#define LDAP_URL_URLCOLON_LEN	4

#define LDAP_LDAP_REF_STR	LDAP_URL_PREFIX
#define LDAP_LDAP_REF_STR_LEN	LDAP_URL_PREFIX_LEN
#define LDAP_LDAPS_REF_STR	LDAPS_URL_PREFIX
#define LDAP_LDAPS_REF_STR_LEN	LDAPS_URL_PREFIX_LEN

/* default limit on nesting of referrals */
#define LDAP_DEFAULT_REFHOPLIMIT	5
#ifdef LDAP_DNS
#define LDAP_DX_REF_STR		"dx://"
#define LDAP_DX_REF_STR_LEN	5
#endif /* LDAP_DNS */

typedef enum { 
    LDAP_CACHE_LOCK, 
    LDAP_MEMCACHE_LOCK, 
    LDAP_MSGID_LOCK,
    LDAP_REQ_LOCK, 
    LDAP_RESP_LOCK, 
    LDAP_ABANDON_LOCK, 
    LDAP_CTRL_LOCK,
    LDAP_OPTION_LOCK, 
    LDAP_ERR_LOCK, 
    LDAP_CONN_LOCK, 
    LDAP_IOSTATUS_LOCK,		/* serializes access to ld->ld_iostatus */
    LDAP_RESULT_LOCK, 
    LDAP_PEND_LOCK, 
    LDAP_THREADID_LOCK, 
#ifdef LDAP_SASLIO_HOOKS
    LDAP_SASL_LOCK,
#endif
    LDAP_MAX_LOCK 
} LDAPLock;

/*
 * This structure represents both ldap messages and ldap responses.
 * These are really the same, except in the case of search responses,
 * where a response has multiple messages.
 */

struct ldapmsg {
	int		lm_msgid;	/* the message id */
	ber_tag_t	lm_msgtype;	/* the message type */
	BerElement	*lm_ber;	/* the ber encoded message contents */
	struct ldapmsg	*lm_chain;	/* for search - next msg in the resp */
	struct ldapmsg	*lm_next;	/* next response */
	int		lm_fromcache;	/* memcache: origin of message */
};

/*
 * structure for tracking LDAP server host, ports, DNs, etc.
 */
typedef struct ldap_server {
	char			*lsrv_host;
	char			*lsrv_dn;	/* if NULL, use default */
	int			lsrv_port;
	unsigned long		lsrv_options;	/* boolean options */
#define LDAP_SRV_OPT_SECURE	0x01
	struct ldap_server	*lsrv_next;
} LDAPServer;

/*
 * structure for representing an LDAP server connection
 */
typedef struct ldap_conn {
	Sockbuf			*lconn_sb;
	BerElement		*lconn_ber;  /* non-NULL if in midst of msg. */
	int			lconn_version;	/* LDAP protocol version */
	int			lconn_refcnt;
	unsigned long		lconn_lastused;	/* time */
	int			lconn_status;
#define LDAP_CONNST_CONNECTING		2
#define LDAP_CONNST_CONNECTED		3
#define LDAP_CONNST_DEAD		4
	LDAPServer		*lconn_server;
	char			*lconn_binddn;	/* DN of last successful bind */
	int			lconn_bound;	/* has a bind been done? */
	int			lconn_pending_requests; /* count of unsent req*/
	char			*lconn_krbinstance;
#ifdef LDAP_SASLIO_HOOKS
    sasl_conn_t     *lconn_sasl_ctx; /* the sasl connection context */
#endif /* LDAP_SASLIO_HOOKS */
	struct ldap_conn	*lconn_next;
} LDAPConn;


/*
 * structure used to track outstanding requests
 */
typedef struct ldapreq {
	int		lr_msgid;	/* the message id */
	int		lr_status;	/* status of request */
#define LDAP_REQST_INPROGRESS	1
#define LDAP_REQST_CHASINGREFS	2
#define LDAP_REQST_WRITING	4
#define LDAP_REQST_CONNDEAD	5	/* associated conn. has failed */
	int		lr_outrefcnt;	/* count of outstanding referrals */
	int		lr_origid;	/* original request's message id */
	int		lr_parentcnt;	/* count of parent requests */
	ber_tag_t	lr_res_msgtype;	/* result message type */
	int		lr_expect_resp;	/* if non-zero, expect a response */
	int		lr_res_errno;	/* result LDAP errno */
	char		*lr_res_error;	/* result error string */
	char		*lr_res_matched;/* result matched DN string */
	BerElement	*lr_ber;	/* ber encoded request contents */
	LDAPConn	*lr_conn;	/* connection used to send request */
	char		*lr_binddn;	/* request is a bind for this DN */
	struct ldapreq	*lr_parent;	/* request that spawned this referral */
	struct ldapreq	*lr_child;	/* list of requests we spawned */
	struct ldapreq	*lr_sibling;	/* next referral spawned */
	struct ldapreq	*lr_prev;	/* ld->ld_requests previous request */
	struct ldapreq	*lr_next;	/* ld->ld_requests next request */
	LDAPControl	**lr_res_ctrls; /* result controls */
} LDAPRequest;

typedef struct ldappend {
	void		*lp_sema;	/* semaphore to post */
	int		lp_msgid;	/* message id */
	LDAPMessage	*lp_result;	/* result storage */
	struct ldappend	*lp_prev;	/* previous pending */
	struct ldappend	*lp_next;	/* next pending */
} LDAPPend;

/*
 * forward declaration for I/O status structure (defined in os-ip.c)
 */
typedef struct nsldapi_iostatus_info NSLDAPIIOStatus;

/*
 * old extended IO structure (before writev callback was added)
 */
struct ldap_x_ext_io_fns_rev0 {
        int                                     lextiof_size;
        LDAP_X_EXTIOF_CONNECT_CALLBACK          *lextiof_connect;
        LDAP_X_EXTIOF_CLOSE_CALLBACK            *lextiof_close;
        LDAP_X_EXTIOF_READ_CALLBACK             *lextiof_read;
        LDAP_X_EXTIOF_WRITE_CALLBACK            *lextiof_write;
        LDAP_X_EXTIOF_POLL_CALLBACK             *lextiof_poll;
        LDAP_X_EXTIOF_NEWHANDLE_CALLBACK        *lextiof_newhandle;
        LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK    *lextiof_disposehandle;
        void                                    *lextiof_session_arg;
};
#define LDAP_X_EXTIO_FNS_SIZE_REV0   sizeof(struct ldap_x_ext_io_fns_rev0)


/*
 * Structure representing an ldap connection.
 *
 * This is an opaque struct; the fields are not visible to
 * applications that use the LDAP API.
 */
struct ldap {
	struct sockbuf	*ld_sbp;	/* pointer to socket desc. & buffer */
	char		*ld_host;
	int		ld_version;	/* LDAP protocol version */
	char		ld_lberoptions;
	int		ld_deref;

	int		ld_timelimit;
	int		ld_sizelimit;

	struct ldap_filt_desc	*ld_filtd;	/* from getfilter for ufn searches */
	char		*ld_ufnprefix;	/* for incomplete ufn's */

	int		ld_errno;
	char		*ld_error;
	char		*ld_matched;
	int		ld_msgid;

	/* Note: the ld_requests list is ordered old to new */
	LDAPRequest	*ld_requests;	/* list of outstanding requests */
	LDAPMessage	*ld_responses;	/* list of outstanding responses */
	int		*ld_abandoned;	/* array of abandoned requests */
	char		*ld_cldapdn;	/* DN used in connectionless search */

	int		ld_cldaptries;	/* connectionless search retry count */
	int		ld_cldaptimeout;/* time between retries */
	int		ld_refhoplimit;	/* limit on referral nesting */
	unsigned long	ld_options;	/* boolean options */

#define LDAP_BITOPT_REFERRALS	0x80000000
#define LDAP_BITOPT_SSL		0x40000000
#define LDAP_BITOPT_DNS		0x20000000
#define LDAP_BITOPT_RESTART	0x10000000
#define LDAP_BITOPT_RECONNECT	0x08000000
#define LDAP_BITOPT_ASYNC       0x04000000
#define LDAP_BITOPT_NOREBIND    0x02000000

	char		*ld_defhost;	/* full name of default server */
	int		ld_defport;	/* port of default server */
	BERTranslateProc ld_lber_encode_translate_proc;
	BERTranslateProc ld_lber_decode_translate_proc;
	LDAPConn	*ld_defconn;	/* default connection */
	LDAPConn	*ld_conns;	/* list of all server connections */
	NSLDAPIIOStatus	*ld_iostatus;	/* status info. about network sockets */
	LDAP_REBINDPROC_CALLBACK *ld_rebind_fn;
	void		*ld_rebind_arg;

	/* function pointers, etc. for extended I/O */
	struct ldap_x_ext_io_fns ld_ext_io_fns;
#define ld_extio_size		ld_ext_io_fns.lextiof_size
#define ld_extclose_fn		ld_ext_io_fns.lextiof_close
#define ld_extconnect_fn	ld_ext_io_fns.lextiof_connect
#define ld_extread_fn		ld_ext_io_fns.lextiof_read
#define ld_extwrite_fn		ld_ext_io_fns.lextiof_write
#define ld_extwritev_fn         ld_ext_io_fns.lextiof_writev
#define ld_extpoll_fn		ld_ext_io_fns.lextiof_poll
#define ld_extnewhandle_fn	ld_ext_io_fns.lextiof_newhandle
#define ld_extdisposehandle_fn	ld_ext_io_fns.lextiof_disposehandle
#define ld_ext_session_arg	ld_ext_io_fns.lextiof_session_arg

	/* allocated pointer for older I/O functions */
	struct ldap_io_fns	*ld_io_fns_ptr;
#define NSLDAPI_USING_CLASSIC_IO_FUNCTIONS( ld ) ((ld)->ld_io_fns_ptr != NULL)

	/* function pointers, etc. for DNS */
	struct ldap_dns_fns	ld_dnsfn;
#define ld_dns_extradata	ld_dnsfn.lddnsfn_extradata
#define ld_dns_bufsize		ld_dnsfn.lddnsfn_bufsize
#define ld_dns_gethostbyname_fn	ld_dnsfn.lddnsfn_gethostbyname
#define ld_dns_gethostbyaddr_fn	ld_dnsfn.lddnsfn_gethostbyaddr
#define ld_dns_getpeername_fn   ld_dnsfn.lddnsfn_getpeername

	/* function pointers, etc. for threading */
	struct ldap_thread_fns	ld_thread;
#define ld_mutex_alloc_fn	ld_thread.ltf_mutex_alloc
#define ld_mutex_free_fn	ld_thread.ltf_mutex_free
#define ld_mutex_lock_fn	ld_thread.ltf_mutex_lock
#define ld_mutex_unlock_fn	ld_thread.ltf_mutex_unlock
#define ld_get_errno_fn		ld_thread.ltf_get_errno
#define ld_set_errno_fn		ld_thread.ltf_set_errno
#define ld_get_lderrno_fn	ld_thread.ltf_get_lderrno
#define ld_set_lderrno_fn	ld_thread.ltf_set_lderrno
#define ld_lderrno_arg		ld_thread.ltf_lderrno_arg
	void			**ld_mutex;

	/* function pointers, etc. for caching */
	int			ld_cache_on;
	int			ld_cache_strategy;
	struct ldap_cache_fns	ld_cache;
#define ld_cache_config		ld_cache.lcf_config
#define ld_cache_bind		ld_cache.lcf_bind
#define ld_cache_unbind		ld_cache.lcf_unbind
#define ld_cache_search		ld_cache.lcf_search
#define ld_cache_compare	ld_cache.lcf_compare
#define ld_cache_add		ld_cache.lcf_add
#define ld_cache_delete		ld_cache.lcf_delete
#if 0
#define ld_cache_rename		ld_cache.lcf_rename
#endif
#define ld_cache_modify		ld_cache.lcf_modify
#define ld_cache_modrdn		ld_cache.lcf_modrdn
#define ld_cache_abandon	ld_cache.lcf_abandon
#define ld_cache_result		ld_cache.lcf_result
#define ld_cache_flush		ld_cache.lcf_flush
#define ld_cache_arg		ld_cache.lcf_arg

	/* ldapv3 controls */
	LDAPControl		**ld_servercontrols;
	LDAPControl		**ld_clientcontrols;

	/* Preferred language */
	char            *ld_preferred_language;

	/* MemCache */
	LDAPMemCache	*ld_memcache;

	/* Pending results */
	LDAPPend	*ld_pend;	/* list of pending results */

	/* extra thread function pointers */
	struct ldap_extra_thread_fns	ld_thread2;

	/*
	 * With the 4.0 and later versions of the LDAP SDK, the extra thread
	 * functions except for the ld_threadid_fn have been disabled.
	 * Look at the release notes for the full explanation.
	 */
#define ld_mutex_trylock_fn		ld_thread2.ltf_mutex_trylock
#define ld_sema_alloc_fn		ld_thread2.ltf_sema_alloc
#define ld_sema_free_fn			ld_thread2.ltf_sema_free
#define ld_sema_wait_fn			ld_thread2.ltf_sema_wait
#define ld_sema_post_fn			ld_thread2.ltf_sema_post
#define ld_threadid_fn			ld_thread2.ltf_threadid_fn

	/* extra data for mutex handling in referrals */
	void 			*ld_mutex_threadid[LDAP_MAX_LOCK];
	unsigned long		ld_mutex_refcnt[LDAP_MAX_LOCK];

	/* connect timeout value (milliseconds) */
	int				ld_connect_timeout;

#ifdef LDAP_SASLIO_HOOKS
	/* SASL default option settings */
	char                    *ld_def_sasl_mech;
	char                    *ld_def_sasl_realm;
	char                    *ld_def_sasl_authcid;
	char                    *ld_def_sasl_authzid;
	/* SASL Security properties */
	struct sasl_security_properties ld_sasl_secprops;
#endif
};

/* allocate/free mutex */
#define LDAP_MUTEX_ALLOC( ld ) \
	(((ld)->ld_mutex_alloc_fn != NULL) ? (ld)->ld_mutex_alloc_fn() : NULL)

/* allocate/free mutex */
#define LDAP_MUTEX_FREE( ld, m ) \
	if ( (ld)->ld_mutex_free_fn != NULL && m != NULL ) { \
		(ld)->ld_mutex_free_fn( m ); \
	}

/* enter/exit critical sections */
/*
 * The locks assume that the locks are thread safe.  XXXmcs: which means???
 *
 * Note that we test for both ld_mutex_lock_fn != NULL AND ld_mutex != NULL.
 * This is necessary because there is a window in ldap_init() between the
 * time we set the ld_mutex_lock_fn pointer and the time we allocate the
 * mutexes in which external code COULD be called which COULD make a call to
 * something like ldap_get_option(), which uses LDAP_MUTEX_LOCK().  The
 * libprldap code does this in its newhandle callback (prldap_newhandle).
 */

#define LDAP_MUTEX_LOCK(ld, lock) \
    if ((ld)->ld_mutex_lock_fn != NULL && ld->ld_mutex != NULL) { \
        if ((ld)->ld_threadid_fn != NULL) { \
            if ((ld)->ld_mutex_threadid[lock] == (ld)->ld_threadid_fn()) { \
                (ld)->ld_mutex_refcnt[lock]++; \
            } else { \
                (ld)->ld_mutex_lock_fn(ld->ld_mutex[lock]); \
                (ld)->ld_mutex_threadid[lock] = ld->ld_threadid_fn(); \
                (ld)->ld_mutex_refcnt[lock] = 1; \
            } \
        } else { \
            (ld)->ld_mutex_lock_fn(ld->ld_mutex[lock]); \
        } \
    } 

#define LDAP_MUTEX_UNLOCK(ld, lock) \
    if ((ld)->ld_mutex_lock_fn != NULL && ld->ld_mutex != NULL) { \
        if ((ld)->ld_threadid_fn != NULL) { \
            if ((ld)->ld_mutex_threadid[lock] == (ld)->ld_threadid_fn()) { \
                (ld)->ld_mutex_refcnt[lock]--; \
                if ((ld)->ld_mutex_refcnt[lock] <= 0) { \
                    (ld)->ld_mutex_threadid[lock] = (void *) -1; \
                    (ld)->ld_mutex_refcnt[lock] = 0; \
                    (ld)->ld_mutex_unlock_fn(ld->ld_mutex[lock]); \
                } \
            } \
        } else { \
            ld->ld_mutex_unlock_fn(ld->ld_mutex[lock]); \
        } \
    }

/* Backward compatibility locks */
#define LDAP_MUTEX_BC_LOCK( ld, i ) \
	/* the ld_mutex_trylock_fn is always set to NULL */ \
	/* in setoption.c as the extra thread functions were */ \
	/* turned off in the 4.0 SDK.  This check will  */ \
	/* always be true */ \
	if( (ld)->ld_mutex_trylock_fn == NULL ) { \
		LDAP_MUTEX_LOCK( ld, i ) ; \
	}
#define LDAP_MUTEX_BC_UNLOCK( ld, i ) \
	/* the ld_mutex_trylock_fn is always set to NULL */ \
	/* in setoption.c as the extra thread functions were */ \
	/* turned off in the 4.0 SDK.  This check will  */ \
	/* always be true */ \
	if( (ld)->ld_mutex_trylock_fn == NULL ) { \
		LDAP_MUTEX_UNLOCK( ld, i ) ; \
	}

/* allocate/free semaphore */
#define LDAP_SEMA_ALLOC( ld ) \
	(((ld)->ld_sema_alloc_fn != NULL) ? (ld)->ld_sema_alloc_fn() : NULL)
#define LDAP_SEMA_FREE( ld, m ) \
	if ( (ld)->ld_sema_free_fn != NULL && m != NULL ) { \
		(ld)->ld_sema_free_fn( m ); \
	}

/* wait/post binary semaphore */
#define LDAP_SEMA_WAIT( ld, lp ) \
	if ( (ld)->ld_sema_wait_fn != NULL ) { \
		(ld)->ld_sema_wait_fn( lp->lp_sema ); \
	}
#define LDAP_SEMA_POST( ld, lp ) \
	if ( (ld)->ld_sema_post_fn != NULL ) { \
		(ld)->ld_sema_post_fn( lp->lp_sema ); \
	}
#define POST( ld, y, z ) \
	/* the ld_mutex_trylock_fn is always set to NULL */ \
	/* in setoption.c as the extra thread functions were */ \
	/* turned off in the 4.0 SDK.  This check will  */ \
	/* always be false */ \
	if( (ld)->ld_mutex_trylock_fn != NULL ) { \
		nsldapi_post_result( ld, y, z ); \
	}

/* get/set errno */
#ifndef macintosh
#define LDAP_SET_ERRNO( ld, e ) \
	if ( (ld)->ld_set_errno_fn != NULL ) { \
		(ld)->ld_set_errno_fn( e ); \
	} else { \
		errno = e; \
	}
#define LDAP_GET_ERRNO( ld ) \
	(((ld)->ld_get_errno_fn != NULL) ? \
		(ld)->ld_get_errno_fn() : errno)
#else /* macintosh */
#define LDAP_SET_ERRNO( ld, e ) \
	if ( (ld)->ld_set_errno_fn != NULL ) { \
		(ld)->ld_set_errno_fn( e ); \
	}
#define LDAP_GET_ERRNO( ld ) \
	(((ld)->ld_get_errno_fn != NULL) ? \
		(ld)->ld_get_errno_fn() : 0)
#endif


/* get/set ldap-specific errno */
#define LDAP_SET_LDERRNO( ld, e, m, s )	ldap_set_lderrno( ld, e, m, s )
#define LDAP_GET_LDERRNO( ld, m, s ) ldap_get_lderrno( ld, m, s )

/*
 * your standard "mimimum of two values" macro
 */
#define NSLDAPI_MIN(a, b)	(((a) < (b)) ? (a) : (b))

/*
 * handy macro to check whether LDAP struct is set up for CLDAP or not
 */
#define LDAP_IS_CLDAP( ld )	( ld->ld_sbp->sb_naddr > 0 )

/*
 * Some Unix error defs. Under CW 7, we can't define OTUNIXERRORS because
 * it generates many conflicts with errno.h. Define what we need here.
 * These need to be in sync with OpenTransport.h
 */
 
#if defined(macintosh)
#define EWOULDBLOCK     35
#define EHOSTUNREACH    65
#endif

/*
 * handy macro to check errno "e" for an "in progress" sort of error
 */
#if defined(macintosh) || defined(_WINDOWS)
#define NSLDAPI_ERRNO_IO_INPROGRESS( e )  ((e) == EWOULDBLOCK || (e) == EAGAIN)
#else
#ifdef EAGAIN
#define NSLDAPI_ERRNO_IO_INPROGRESS( e )  ((e) == EWOULDBLOCK || (e) == EINPROGRESS || (e) == EAGAIN)
#else /* EAGAIN */
#define NSLDAPI_ERRNO_IO_INPROGRESS( e )  ((e) == EWOULDBLOCK || (e) == EINPROGRESS) 
#endif /* EAGAIN */
#endif /* macintosh || _WINDOWS*/

/*
 * macro to return the LDAP protocol version we are using
 */
#define NSLDAPI_LDAP_VERSION( ld )	( (ld)->ld_defconn == NULL ? \
					(ld)->ld_version : \
					(ld)->ld_defconn->lconn_version )

/*
 * Structures used for handling client filter lists.
 */
#define LDAP_FILT_MAXSIZ	1024

struct ldap_filt_list {
    char			*lfl_tag;
    char			*lfl_pattern;
    char			*lfl_delims;
    struct ldap_filt_info	*lfl_ilist;
    struct ldap_filt_list	*lfl_next;
};

struct ldap_filt_desc {
	LDAPFiltList		*lfd_filtlist;
	LDAPFiltInfo		*lfd_curfip;
	LDAPFiltInfo		lfd_retfi;
	char			lfd_filter[ LDAP_FILT_MAXSIZ ];
	char			*lfd_curval;
	char			*lfd_curvalcopy;
	char			**lfd_curvalwords;
	char			*lfd_filtprefix;
	char			*lfd_filtsuffix;
};

/*
 * "internal" globals used to track defaults and memory allocation callbacks:
 *    (the actual definitions are in open.c)
 */
extern struct ldap			nsldapi_ld_defaults;
extern struct ldap_memalloc_fns		nsldapi_memalloc_fns;
extern int				nsldapi_initialized;


/*
 * Memory allocation done in liblber should all go through one of the
 * following macros. This is so we can plug-in alternative memory
 * allocators, etc. as the need arises.
 */
#define NSLDAPI_MALLOC( size )		ldap_x_malloc( size )
#define NSLDAPI_CALLOC( nelem, elsize )	ldap_x_calloc( nelem, elsize )
#define NSLDAPI_REALLOC( ptr, size )	ldap_x_realloc( ptr, size )
#define NSLDAPI_FREE( ptr )		ldap_x_free( ptr )


/*
 * macros used to check validity of data structures and parameters
 */
#define NSLDAPI_VALID_LDAP_POINTER( ld ) \
	( (ld) != NULL )

#define NSLDAPI_VALID_LDAPMESSAGE_POINTER( lm ) \
	( (lm) != NULL )

#define NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( lm ) \
	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_SEARCH_ENTRY )

#define NSLDAPI_VALID_LDAPMESSAGE_REFERENCE_POINTER( lm ) \
	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_SEARCH_REFERENCE )

#define NSLDAPI_VALID_LDAPMESSAGE_BINDRESULT_POINTER( lm ) \
	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_BIND )

#define NSLDAPI_VALID_LDAPMESSAGE_EXRESULT_POINTER( lm ) \
	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_EXTENDED )

#define NSLDAPI_VALID_LDAPMOD_ARRAY( mods ) \
	( (mods) != NULL )

#define NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( mods ) \
	( (mods) != NULL && (mods)[0] != NULL )

#define NSLDAPI_IS_SEARCH_ENTRY( code ) \
	((code) == LDAP_RES_SEARCH_ENTRY)

#define NSLDAPI_IS_SEARCH_RESULT( code ) \
	((code) == LDAP_RES_SEARCH_RESULT)

#define NSLDAPI_SEARCH_RELATED_RESULT( code ) \
	(NSLDAPI_IS_SEARCH_RESULT( code ) || NSLDAPI_IS_SEARCH_ENTRY( code ))

/*
 * in bind.c
 */
char *nsldapi_get_binddn( LDAP *ld );

/*
 * in cache.c
 */
void nsldapi_add_result_to_cache( LDAP *ld, LDAPMessage *result );

/*
 * in dsparse.c
 */
int nsldapi_next_line_tokens( char **bufp, long *blenp, char ***toksp );
void nsldapi_free_strarray( char **sap );

/*
 * in error.c
 */
int nsldapi_parse_result( LDAP *ld, int msgtype, BerElement *rber,
    int *errcodep, char **matchednp, char **errmsgp, char ***referralsp,
    LDAPControl ***serverctrlsp );

/*
 * in open.c
 */
void nsldapi_initialize_defaults( void );
void nsldapi_mutex_alloc_all( LDAP *ld );
void nsldapi_mutex_free_all( LDAP *ld );
int nsldapi_open_ldap_defconn( LDAP *ld );
char *nsldapi_strdup( const char *s );  /* if s is NULL, returns NULL */

/*
 * in os-ip.c
 */
int nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *host,
	int port, int secure, char **krbinstancep );
void nsldapi_close_connection( LDAP *ld, Sockbuf *sb );

int nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout );
void nsldapi_iostatus_free( LDAP *ld );
int nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb );
int nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb );
int nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb );
int nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb );
int nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb );
int nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb );
int nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns );

/*
 * if referral.c
 */
int nsldapi_parse_reference( LDAP *ld, BerElement *rber, char ***referralsp,
	LDAPControl ***serverctrlsp );


/*
 * in result.c
 */
int ldap_msgdelete( LDAP *ld, int msgid );
int nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
    struct timeval *timeout, LDAPMessage **result );
int nsldapi_wait_result( LDAP *ld, int msgid, int all, struct timeval *timeout,
    LDAPMessage **result );
int nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result );

/*
 * in request.c
 */
int nsldapi_send_initial_request( LDAP *ld, int msgid, unsigned long msgtype,
	char *dn, BerElement *ber );
int nsldapi_send_pending_requests_nolock( LDAP *ld, LDAPConn *lc );
int nsldapi_alloc_ber_with_options( LDAP *ld, BerElement **berp );
void nsldapi_set_ber_options( LDAP *ld, BerElement *ber );
int nsldapi_send_ber_message( LDAP *ld, Sockbuf *sb, BerElement *ber,
	int freeit, int epipe_handler );
int nsldapi_send_server_request( LDAP *ld, BerElement *ber, int msgid,
	LDAPRequest *parentreq, LDAPServer *srvlist, LDAPConn *lc,
	char *bindreqdn, int bind );
LDAPConn *nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
	int connect, int bind );
LDAPRequest *nsldapi_find_request_by_msgid( LDAP *ld, int msgid );
LDAPRequest *nsldapi_new_request( LDAPConn *lc, BerElement *ber, int msgid,
   int expect_resp );
void nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn );
void nsldapi_queue_request_nolock( LDAP *ld, LDAPRequest *lr );
void nsldapi_free_connection( LDAP *ld, LDAPConn *lc,
	LDAPControl **serverctrls, LDAPControl **clientctrls,
	int force, int unbind );
void nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all );
void nsldapi_dump_requests_and_responses( LDAP *ld );
int nsldapi_chase_v2_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp,
	int *totalcountp, int *chasingcountp );
int nsldapi_chase_v3_refs( LDAP *ld, LDAPRequest *lr, char **refs,
	int is_reference, int *totalcountp, int *chasingcountp );
int nsldapi_append_referral( LDAP *ld, char **referralsp, char *s );
void nsldapi_connection_lost_nolock( LDAP *ld, Sockbuf *sb );

#ifdef LDAP_SASLIO_HOOKS
/*
 * in saslbind.c
 */
int nsldapi_sasl_is_inited();
int nsldapi_sasl_cvterrno( LDAP *ld, int err, char *msg );
int nsldapi_sasl_secprops( const char *in,
                        sasl_security_properties_t *secprops );

/*
 * in saslio.c
 */
int nsldapi_sasl_install( LDAP *ld, LDAPConn *lconn );
int nsldapi_sasl_open( LDAP *ld, LDAPConn *lconn, sasl_conn_t **ctx, sasl_ssf_t ssf );

#endif /* LDAP_SASLIO_HOOKS */

/*
 * in search.c
 */
int nsldapi_build_search_req( LDAP *ld, const char *base, int scope,
	const char *filter, char **attrs, int attrsonly,
	LDAPControl **serverctrls, LDAPControl **clientctrls,
	int timelimit, int sizelimit, int msgid, BerElement **berp );

/*
 * in unbind.c
 */
int ldap_ld_free( LDAP *ld, LDAPControl **serverctrls,
	LDAPControl **clientctrls, int close );
int nsldapi_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **serverctrls,
	LDAPControl **clientctrls );

#ifdef LDAP_DNS
/*
 * in getdxbyname.c
 */
char **nsldapi_getdxbyname( char *domain );

#endif /* LDAP_DNS */

/*
 * in unescape.c
 */
void nsldapi_hex_unescape( char *s );

/*
 * in compat.c
 */
#ifdef hpux
char *nsldapi_compat_ctime_r( const time_t *clock, char *buf, int buflen );
struct hostent *nsldapi_compat_gethostbyname_r( const char *name,
	struct hostent *result, char *buffer, int buflen, int *h_errnop );
#endif /* hpux */

/*
 * in control.c
 */
int nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
	BerElement *ber );
int nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp );
int nsldapi_find_controls( BerElement *ber, LDAPControl ***controlsp );
int nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls,
	LDAPControl **newctrls );
int nsldapi_build_control( char *oid, BerElement *ber, int freeber,
    char iscritical, LDAPControl **ctrlp );


/*
 * in url.c
 */
int nsldapi_url_parse( const char *inurl, LDAPURLDesc **ludpp,
	int dn_required );


/*
 * in charset.c
 *
 * If we ever want to expose character set translation functionality to
 * users of libldap, all of these prototypes will need to be moved to ldap.h
 */
#ifdef STR_TRANSLATION
void ldap_set_string_translators( LDAP *ld,
        BERTranslateProc encode_proc, BERTranslateProc decode_proc );
int ldap_translate_from_t61( LDAP *ld, char **bufp,
        unsigned long *lenp, int free_input );
int ldap_translate_to_t61( LDAP *ld, char **bufp,
        unsigned long *lenp, int free_input );
void ldap_enable_translation( LDAP *ld, LDAPMessage *entry,
        int enable );
#ifdef LDAP_CHARSET_8859
int ldap_t61_to_8859( char **bufp, unsigned long *buflenp,
        int free_input );
int ldap_8859_to_t61( char **bufp, unsigned long *buflenp,
        int free_input );
#endif /* LDAP_CHARSET_8859 */
#endif /* STR_TRANSLATION */

/*
 * in memcache.h
 */
int ldap_memcache_createkey( LDAP *ld, const char *base, int scope,
	const char *filter, char **attrs, int attrsonly,
	LDAPControl **serverctrls, LDAPControl **clientctrls,
	unsigned long *keyp );
int ldap_memcache_result( LDAP *ld, int msgid, unsigned long key );
int ldap_memcache_new( LDAP *ld, int msgid, unsigned long key,
	const char *basedn );
int ldap_memcache_append( LDAP *ld, int msgid, int bLast, LDAPMessage *result );
int ldap_memcache_abandon( LDAP *ld, int msgid );

/*
 * in sbind.c
 */
void nsldapi_handle_reconnect( LDAP *ld );

#endif /* _LDAPINT_H */