summaryrefslogtreecommitdiff
path: root/usr/src/lib/libldap5/sources/ldap
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libldap5/sources/ldap
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libldap5/sources/ldap')
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ber/bprint.c94
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ber/decode.c770
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ber/encode.c679
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ber/io.c1363
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ber/lber-int.h296
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/abandon.c271
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/add.c212
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/bind.c157
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/cache.c164
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/charray.c232
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/charset.c1841
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/compare.c181
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/compat.c73
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/control.c492
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/countvalues.c54
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/cram_md5.c116
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/delete.c156
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/digest_md5.c841
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/disptmpl.c787
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/dsparse.c215
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/error.c681
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/extendop.c249
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/free.c140
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/freevalues.c60
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/friendly.c138
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/getattr.c142
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/getdn.c406
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/getdxbyname.c252
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/getentry.c128
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/getfilter.c541
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/getoption.c450
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/getvalues.c478
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/ldap-int.h878
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/ldaputf8.c269
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/llib-lldap530
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/memcache.c2203
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/message.c92
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/modify.c213
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/open.c809
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/os-ip.c1822
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/proxyauthctrl.c151
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/psearch.c172
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/referral.c193
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/rename.c252
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/request.c1349
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/reslist.c65
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/result.c1473
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/sasl.c974
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/saslbind.c286
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/sbind.c264
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/search.c1019
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/secutil.c32
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/setoption.c425
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/sort.c320
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/sortctrl.c421
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/spagectrl.c73
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/srchpref.c421
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/tmplout.c1140
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/ufn.c541
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/unbind.c233
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/unescape.c68
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/url.c853
-rw-r--r--usr/src/lib/libldap5/sources/ldap/common/vlistctrl.c254
-rw-r--r--usr/src/lib/libldap5/sources/ldap/prldap/ldappr-dns.c366
-rw-r--r--usr/src/lib/libldap5/sources/ldap/prldap/ldappr-error.c229
-rw-r--r--usr/src/lib/libldap5/sources/ldap/prldap/ldappr-int.h113
-rw-r--r--usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c721
-rw-r--r--usr/src/lib/libldap5/sources/ldap/prldap/ldappr-public.c382
-rw-r--r--usr/src/lib/libldap5/sources/ldap/prldap/ldappr-threads.c754
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ssldap/clientinit.c880
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ssldap/errormap.c295
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ssldap/ldapsinit.c1317
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ssldap/prerrstrs.h194
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ssldap/secerrstrs.h510
-rw-r--r--usr/src/lib/libldap5/sources/ldap/ssldap/sslerrstrs.h419
-rw-r--r--usr/src/lib/libldap5/sources/ldap/util/line64.c605
-rw-r--r--usr/src/lib/libldap5/sources/ldap/util/log.c168
77 files changed, 37407 insertions, 0 deletions
diff --git a/usr/src/lib/libldap5/sources/ldap/ber/bprint.c b/usr/src/lib/libldap5/sources/ldap/ber/bprint.c
new file mode 100644
index 0000000000..317a11e25f
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ber/bprint.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/* bprint.c - a printing utility for debuging output */
+#include <string.h>
+#include "lber-int.h"
+
+#ifdef LDAP_DEBUG
+/*
+ * Print arbitrary stuff, for debugging.
+ */
+
+#define BPLEN 48
+
+void
+lber_bprint( char *data, int len )
+{
+ static char hexdig[] = "0123456789abcdef";
+ char out[ BPLEN ];
+ int i = 0;
+
+ memset( out, 0, BPLEN );
+ for ( ;; ) {
+ if ( len < 1 ) {
+ char msg[BPLEN + 80];
+ sprintf( msg, "\t%s\n", ( i == 0 ) ? "(end)" : out );
+ ber_err_print( msg );
+ break;
+ }
+
+#ifndef HEX
+ if ( isgraph( (unsigned char)*data )) {
+ out[ i ] = ' ';
+ out[ i+1 ] = *data;
+ } else {
+#endif
+ out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
+ out[ i+1 ] = hexdig[ *data & 0x0f ];
+#ifndef HEX
+ }
+#endif
+ i += 2;
+ len--;
+ data++;
+
+ if ( i > BPLEN - 2 ) {
+ char msg[BPLEN + 80];
+ sprintf( msg, "\t%s\n", out );
+ ber_err_print( msg );
+ memset( out, 0, BPLEN );
+ i = 0;
+ continue;
+ }
+ out[ i++ ] = ' ';
+ }
+}
+
+#endif
+
+void ber_err_print( char *data )
+{
+#ifdef USE_DEBUG_WIN
+ OutputDebugString( data );
+#else
+ fputs( data, stderr );
+ fflush( stderr );
+#endif
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/ber/decode.c b/usr/src/lib/libldap5/sources/ldap/ber/decode.c
new file mode 100644
index 0000000000..27c308f4c7
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ber/decode.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* decode.c - ber input decoding routines */
+
+#include "lber-int.h"
+LDAP_API(void) LDAP_CALL ber_svecfree( char **vals );
+
+/*
+ * Note: ber_get_tag() only uses the ber_end and ber_ptr elements of ber.
+ * If that changes, the ber_peek_tag() and/or ber_skip_tag() implementations
+ * will need to be changed.
+ */
+/* return the tag - LBER_DEFAULT returned means trouble */
+ber_tag_t
+LDAP_CALL
+ber_get_tag( BerElement *ber )
+{
+ unsigned char xbyte;
+ ber_tag_t tag;
+ char *tagp;
+ int i;
+
+ if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
+ return( LBER_DEFAULT );
+
+ if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
+ return( (ber_uint_t) xbyte );
+
+ tagp = (char *) &tag;
+ tagp[0] = xbyte;
+ for ( i = 1; i < sizeof(ber_int_t); i++ ) {
+ if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
+ return( LBER_DEFAULT );
+
+ tagp[i] = xbyte;
+
+ if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+ break;
+ }
+
+ /* tag too big! */
+ if ( i == sizeof(ber_int_t) )
+ return( LBER_DEFAULT );
+
+ /* want leading, not trailing 0's */
+ return( tag >> (sizeof(ber_int_t) - i - 1) );
+}
+
+/*
+ * Note: ber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
+ * If that changes, the implementation of ber_peek_tag() will need to
+ * be changed.
+ */
+ber_tag_t
+LDAP_CALL
+ber_skip_tag( BerElement *ber, ber_len_t *len )
+{
+ ber_tag_t tag;
+ unsigned char lc;
+ int noctets, diff;
+ ber_len_t netlen;
+
+ /*
+ * Any ber element looks like this: tag length contents.
+ * Assuming everything's ok, we return the tag byte (we
+ * can assume a single byte), and return the length in len.
+ *
+ * Assumptions:
+ * 1) definite lengths
+ * 2) primitive encodings used whenever possible
+ */
+
+ /*
+ * First, we read the tag.
+ */
+
+ if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT )
+ return( LBER_DEFAULT );
+
+ /*
+ * Next, read the length. The first byte contains the length of
+ * the length. If bit 8 is set, the length is the long form,
+ * otherwise it's the short form. We don't allow a length that's
+ * greater than what we can hold in an unsigned long.
+ */
+
+ *len = netlen = 0;
+ if ( ber_read( ber, (char *) &lc, 1 ) != 1 )
+ return( LBER_DEFAULT );
+ if ( lc & 0x80 ) {
+ noctets = (lc & 0x7f);
+ if ( noctets > sizeof(ber_uint_t) )
+ return( LBER_DEFAULT );
+ diff = sizeof(ber_int_t) - noctets;
+ if ( ber_read( ber, (char *) &netlen + diff, noctets )
+ != noctets )
+ return( LBER_DEFAULT );
+ *len = LBER_NTOHL( netlen );
+ } else {
+ *len = lc;
+ }
+
+ return( tag );
+}
+
+
+/*
+ * Note: Previously, we passed the "ber" parameter directly to ber_skip_tag(),
+ * saving and restoring the ber_ptr element only. We now take advantage
+ * of the fact that the only ber structure elements touched by ber_skip_tag()
+ * are ber_end and ber_ptr. If that changes, this code must change too.
+ */
+ber_tag_t
+LDAP_CALL
+ber_peek_tag( BerElement *ber, ber_len_t *len )
+{
+ BerElement bercopy;
+
+ bercopy.ber_end = ber->ber_end;
+ bercopy.ber_ptr = ber->ber_ptr;
+ return( ber_skip_tag( &bercopy, len ));
+}
+
+static int
+ber_getnint( BerElement *ber, ber_int_t *num, ber_slen_t len )
+{
+ int i;
+ ber_int_t value;
+ unsigned char buffer[sizeof(ber_int_t)];
+ /*
+ * The tag and length have already been stripped off. We should
+ * be sitting right before len bytes of 2's complement integer,
+ * ready to be read straight into an int. We may have to sign
+ * extend after we read it in.
+ */
+
+ if ( len > sizeof(ber_slen_t) )
+ return( -1 );
+
+ /* read into the low-order bytes of netnum */
+ if ( ber_read( ber, (char *) buffer, len ) != len )
+ return( -1 );
+
+ /* This sets the required sign extension */
+ if ( len != 0) {
+ value = 0x80 & buffer[0] ? (LBER_FUNC_VALUE) : 0;
+ } else {
+ value = 0;
+ }
+
+ for ( i = 0; i < len; i++ )
+ value = (value << 8) | buffer[i];
+
+ *num = value;
+
+ return( len );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_int( BerElement *ber, ber_int_t *num )
+{
+ ber_tag_t tag;
+ ber_len_t len;
+
+ if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+ return( LBER_DEFAULT );
+
+ /*
+ * len is being demoted to a long here -- possible conversion error
+ */
+
+ if ( ber_getnint( ber, num, (int)len ) != (ber_slen_t)len )
+ return( LBER_DEFAULT );
+ else
+ return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_stringb( BerElement *ber, char *buf, ber_len_t *len )
+{
+ ber_len_t datalen;
+ ber_tag_t tag;
+#ifdef STR_TRANSLATION
+ char *transbuf;
+#endif /* STR_TRANSLATION */
+
+ if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+ return( LBER_DEFAULT );
+ if ( datalen > (*len - 1) )
+ return( LBER_DEFAULT );
+
+ /*
+ * datalen is being demoted to a long here -- possible conversion error
+ */
+
+ if ( ber_read( ber, buf, datalen ) != (ber_slen_t) datalen )
+ return( LBER_DEFAULT );
+
+ buf[datalen] = '\0';
+
+#ifdef STR_TRANSLATION
+ if ( datalen > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS )
+ != 0 && ber->ber_decode_translate_proc != NULL ) {
+ transbuf = buf;
+ ++datalen;
+ if ( (*(ber->ber_decode_translate_proc))( &transbuf, &datalen,
+ 0 ) != 0 ) {
+ return( LBER_DEFAULT );
+ }
+ if ( datalen > *len ) {
+ NSLBERI_FREE( transbuf );
+ return( LBER_DEFAULT );
+ }
+ SAFEMEMCPY( buf, transbuf, datalen );
+ NSLBERI_FREE( transbuf );
+ --datalen;
+ }
+#endif /* STR_TRANSLATION */
+
+ *len = datalen;
+ return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_stringa( BerElement *ber, char **buf )
+{
+ ber_len_t datalen;
+ ber_tag_t tag;
+
+ if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+ return( LBER_DEFAULT );
+
+ if ( (*buf = (char *)NSLBERI_MALLOC( (size_t)datalen + 1 )) == NULL )
+ return( LBER_DEFAULT );
+
+ /*
+ * datalen is being demoted to a long here -- possible conversion error
+ */
+ if ( ber_read( ber, *buf, datalen ) != (ber_slen_t) datalen )
+ return( LBER_DEFAULT );
+ (*buf)[datalen] = '\0';
+
+#ifdef STR_TRANSLATION
+ if ( datalen > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS )
+ != 0 && ber->ber_decode_translate_proc != NULL ) {
+ ++datalen;
+ if ( (*(ber->ber_decode_translate_proc))( buf, &datalen, 1 )
+ != 0 ) {
+ NSLBERI_FREE( *buf );
+ return( LBER_DEFAULT );
+ }
+ }
+#endif /* STR_TRANSLATION */
+
+ return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_stringal( BerElement *ber, struct berval **bv )
+{
+ ber_len_t len;
+ ber_tag_t tag;
+
+ if ( (*bv = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
+ == NULL ) {
+ return( LBER_DEFAULT );
+ }
+
+ if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
+ return( LBER_DEFAULT );
+ }
+
+ if ( ((*bv)->bv_val = (char *)NSLBERI_MALLOC( (size_t)len + 1 ))
+ == NULL ) {
+ return( LBER_DEFAULT );
+ }
+
+ /*
+ * len is being demoted to a long here -- possible conversion error
+ */
+ if ( ber_read( ber, (*bv)->bv_val, len ) != (ber_slen_t) len )
+ return( LBER_DEFAULT );
+ ((*bv)->bv_val)[len] = '\0';
+ (*bv)->bv_len = len;
+
+#ifdef STR_TRANSLATION
+ if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0
+ && ber->ber_decode_translate_proc != NULL ) {
+ ++len;
+ if ( (*(ber->ber_decode_translate_proc))( &((*bv)->bv_val),
+ &len, 1 ) != 0 ) {
+ NSLBERI_FREE( (*bv)->bv_val );
+ return( LBER_DEFAULT );
+ }
+ (*bv)->bv_len = len - 1;
+ }
+#endif /* STR_TRANSLATION */
+
+ return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_bitstringa( BerElement *ber, char **buf, ber_len_t *blen )
+{
+ ber_len_t datalen;
+ ber_tag_t tag;
+ unsigned char unusedbits;
+
+ if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+ return( LBER_DEFAULT );
+ --datalen;
+
+ if ( (*buf = (char *)NSLBERI_MALLOC( (size_t)datalen )) == NULL )
+ return( LBER_DEFAULT );
+
+ if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 )
+ return( LBER_DEFAULT );
+
+ /*
+ * datalen is being demoted to a long here -- possible conversion error
+ */
+ if ( ber_read( ber, *buf, datalen ) != (ber_slen_t) datalen )
+ return( LBER_DEFAULT );
+
+ *blen = datalen * 8 - unusedbits;
+ return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_null( BerElement *ber )
+{
+ ber_len_t len;
+ ber_tag_t tag;
+
+ if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+ return( LBER_DEFAULT );
+
+ if ( len != 0 )
+ return( LBER_DEFAULT );
+
+ return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_boolean( BerElement *ber, int *boolval )
+{
+ ber_int_t longbool;
+ int rc;
+
+ rc = ber_get_int( ber, &longbool );
+ *boolval = longbool;
+
+ return( rc );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_first_element( BerElement *ber, ber_len_t *len, char **last )
+{
+ /* skip the sequence header, use the len to mark where to stop */
+ if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
+ return( LBER_ERROR );
+ }
+
+ *last = ber->ber_ptr + *len;
+
+ if ( *last == ber->ber_ptr ) {
+ return( LBER_END_OF_SEQORSET );
+ }
+
+ return( ber_peek_tag( ber, len ) );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_next_element( BerElement *ber, ber_len_t *len, char *last )
+{
+ if ( ber->ber_ptr == last ) {
+ return( LBER_END_OF_SEQORSET );
+ }
+
+ return( ber_peek_tag( ber, len ) );
+}
+
+/* VARARGS */
+ber_tag_t
+LDAP_C
+ber_scanf( BerElement *ber, const char *fmt, ... )
+{
+ va_list ap;
+ char *last, *p;
+ char *s, **ss, ***sss;
+ struct berval ***bv, **bvp, *bval;
+ int *i, j;
+ ber_int_t *l, rc, tag;
+ ber_tag_t *t;
+ ber_len_t len;
+ size_t array_size;
+
+ va_start( ap, fmt );
+
+#ifdef LDAP_DEBUG
+ if ( lber_debug & 64 ) {
+ char msg[80];
+ sprintf( msg, "ber_scanf fmt (%s) ber:\n", fmt );
+ ber_err_print( msg );
+ ber_dump( ber, 1 );
+ }
+#endif
+
+ for ( rc = 0, p = (char *)fmt; *p && rc != LBER_DEFAULT; p++ ) {
+ switch ( *p ) {
+ case 'a': /* octet string - allocate storage as needed */
+ ss = va_arg( ap, char ** );
+ rc = ber_get_stringa( ber, ss );
+ break;
+
+ case 'b': /* boolean */
+ i = va_arg( ap, int * );
+ rc = ber_get_boolean( ber, i );
+ break;
+
+ case 'e': /* enumerated */
+ case 'i': /* int */
+ l = va_arg( ap, ber_slen_t * );
+ rc = ber_get_int( ber, l );
+ break;
+
+ case 'l': /* length of next item */
+ l = va_arg( ap, ber_slen_t * );
+ rc = ber_peek_tag( ber, (ber_len_t *)l );
+ break;
+
+ case 'n': /* null */
+ rc = ber_get_null( ber );
+ break;
+
+ case 's': /* octet string - in a buffer */
+ s = va_arg( ap, char * );
+ l = va_arg( ap, ber_slen_t * );
+ rc = ber_get_stringb( ber, s, (ber_len_t *)l );
+ break;
+
+ case 'o': /* octet string in a supplied berval */
+ bval = va_arg( ap, struct berval * );
+ ber_peek_tag( ber, &bval->bv_len );
+ rc = ber_get_stringa( ber, &bval->bv_val );
+ break;
+
+ case 'O': /* octet string - allocate & include length */
+ bvp = va_arg( ap, struct berval ** );
+ rc = ber_get_stringal( ber, bvp );
+ break;
+
+ case 'B': /* bit string - allocate storage as needed */
+ ss = va_arg( ap, char ** );
+ l = va_arg( ap, ber_slen_t * ); /* for length, in bits */
+ rc = ber_get_bitstringa( ber, ss, (ber_len_t *)l );
+ break;
+
+ case 't': /* tag of next item */
+ t = va_arg( ap, ber_tag_t * );
+ *t = rc = ber_peek_tag( ber, &len );
+ break;
+
+ case 'T': /* skip tag of next item */
+ t = va_arg( ap, ber_tag_t * );
+ *t = rc = ber_skip_tag( ber, &len );
+ break;
+
+ case 'v': /* sequence of strings */
+ sss = va_arg( ap, char *** );
+ *sss = NULL;
+ j = 0;
+ array_size = 0;
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_DEFAULT && tag != LBER_END_OF_SEQORSET
+ && rc != LBER_DEFAULT;
+ tag = ber_next_element( ber, &len, last ) ) {
+ if ( *sss == NULL ) {
+ /* Make room for at least 15 strings */
+ *sss = (char **)NSLBERI_MALLOC(16 * sizeof(char *) );
+ array_size = 16;
+ } else {
+ if ( (size_t)(j+2) > array_size) {
+ /* We'v overflowed our buffer */
+ *sss = (char **)NSLBERI_REALLOC( *sss, (array_size * 2) * sizeof(char *) );
+ array_size = array_size * 2;
+ }
+ }
+ rc = ber_get_stringa( ber, &((*sss)[j]) );
+ j++;
+ }
+ if ( rc != LBER_DEFAULT &&
+ tag != LBER_END_OF_SEQORSET ) {
+ rc = LBER_DEFAULT;
+ }
+ if ( j > 0 )
+ (*sss)[j] = NULL;
+ break;
+
+ case 'V': /* sequence of strings + lengths */
+ bv = va_arg( ap, struct berval *** );
+ *bv = NULL;
+ j = 0;
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_DEFAULT && tag != LBER_END_OF_SEQORSET
+ && rc != LBER_DEFAULT;
+ tag = ber_next_element( ber, &len, last ) ) {
+ if ( *bv == NULL ) {
+ *bv = (struct berval **)NSLBERI_MALLOC(
+ 2 * sizeof(struct berval *) );
+ } else {
+ *bv = (struct berval **)NSLBERI_REALLOC(
+ *bv,
+ (j + 2) * sizeof(struct berval *) );
+ }
+ rc = ber_get_stringal( ber, &((*bv)[j]) );
+ j++;
+ }
+ if ( rc != LBER_DEFAULT &&
+ tag != LBER_END_OF_SEQORSET ) {
+ rc = LBER_DEFAULT;
+ }
+ if ( j > 0 )
+ (*bv)[j] = NULL;
+ break;
+
+ case 'x': /* skip the next element - whatever it is */
+ if ( (rc = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+ break;
+ ber->ber_ptr += len;
+ break;
+
+ case '{': /* begin sequence */
+ case '[': /* begin set */
+ if ( *(p + 1) != 'v' && *(p + 1) != 'V' )
+ rc = ber_skip_tag( ber, &len );
+ break;
+
+ case '}': /* end sequence */
+ case ']': /* end set */
+ break;
+
+ default:
+ {
+ char msg[80];
+ sprintf( msg, "unknown fmt %c\n", *p );
+ ber_err_print( msg );
+ }
+ rc = LBER_DEFAULT;
+ break;
+ }
+ }
+
+
+ va_end( ap );
+ if (rc == LBER_DEFAULT) {
+ va_start( ap, fmt );
+ for ( p--; fmt < p && *fmt; fmt++ ) {
+ switch ( *fmt ) {
+ case 'a': /* octet string - allocate storage as needed */
+ ss = va_arg( ap, char ** );
+ NSLBERI_FREE(*ss);
+ *ss = NULL;
+ break;
+
+ case 'b': /* boolean */
+ i = va_arg( ap, int * );
+ break;
+
+ case 'e': /* enumerated */
+ case 'i': /* int */
+ l = va_arg( ap, ber_slen_t * );
+ break;
+
+ case 'l': /* length of next item */
+ l = va_arg( ap, ber_slen_t * );
+ break;
+
+ case 'n': /* null */
+ break;
+
+ case 's': /* octet string - in a buffer */
+ s = va_arg( ap, char * );
+ l = va_arg( ap, ber_slen_t * );
+ break;
+
+ case 'o': /* octet string in a supplied berval */
+ bval = va_arg( ap, struct berval * );
+ if (bval->bv_val) NSLBERI_FREE(bval->bv_val);
+ memset(bval, 0, sizeof(struct berval));
+ break;
+
+ case 'O': /* octet string - allocate & include length */
+ bvp = va_arg( ap, struct berval ** );
+ ber_bvfree(*bvp);
+ bvp = NULL;
+ break;
+
+ case 'B': /* bit string - allocate storage as needed */
+ ss = va_arg( ap, char ** );
+ l = va_arg( ap, ber_slen_t * ); /* for length, in bits */
+ if (*ss) NSLBERI_FREE(*ss);
+ *ss = NULL;
+ break;
+
+ case 't': /* tag of next item */
+ t = va_arg( ap, ber_tag_t * );
+ break;
+ case 'T': /* skip tag of next item */
+ t = va_arg( ap, ber_tag_t * );
+ break;
+
+ case 'v': /* sequence of strings */
+ sss = va_arg( ap, char *** );
+ ber_svecfree(*sss);
+ *sss = NULL;
+ break;
+
+ case 'V': /* sequence of strings + lengths */
+ bv = va_arg( ap, struct berval *** );
+ ber_bvecfree(*bv);
+ *bv = NULL;
+ break;
+
+ case 'x': /* skip the next element - whatever it is */
+ break;
+
+ case '{': /* begin sequence */
+ case '[': /* begin set */
+ break;
+
+ case '}': /* end sequence */
+ case ']': /* end set */
+ break;
+
+ default:
+ break;
+ }
+ } /* for */
+ va_end( ap );
+ } /* if */
+
+
+ return( rc );
+}
+
+void
+LDAP_CALL
+ber_bvfree( struct berval *bv )
+{
+ if ( bv != NULL ) {
+ if ( bv->bv_val != NULL ) {
+ NSLBERI_FREE( bv->bv_val );
+ }
+ NSLBERI_FREE( (char *) bv );
+ }
+}
+
+void
+LDAP_CALL
+ber_bvecfree( struct berval **bv )
+{
+ int i;
+
+ if ( bv != NULL ) {
+ for ( i = 0; bv[i] != NULL; i++ ) {
+ ber_bvfree( bv[i] );
+ }
+ NSLBERI_FREE( (char *) bv );
+ }
+}
+
+struct berval *
+LDAP_CALL
+ber_bvdup( const struct berval *bv )
+{
+ struct berval *new;
+
+ if ( (new = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
+ == NULL ) {
+ return( NULL );
+ }
+ if ( bv->bv_val == NULL ) {
+ new->bv_val = NULL;
+ new->bv_len = 0;
+ } else {
+ if ( (new->bv_val = (char *)NSLBERI_MALLOC( bv->bv_len + 1 ))
+ == NULL ) {
+ return( NULL );
+ }
+ SAFEMEMCPY( new->bv_val, bv->bv_val, (size_t) bv->bv_len );
+ new->bv_val[bv->bv_len] = '\0';
+ new->bv_len = bv->bv_len;
+ }
+
+ return( new );
+}
+
+void
+LDAP_CALL
+ber_svecfree( char **vals )
+{
+ int i;
+
+ if ( vals == NULL )
+ return;
+ for ( i = 0; vals[i] != NULL; i++ )
+ NSLBERI_FREE( vals[i] );
+ NSLBERI_FREE( (char *) vals );
+}
+
+#ifdef STR_TRANSLATION
+void
+LDAP_CALL
+ber_set_string_translators(
+ BerElement *ber,
+ BERTranslateProc encode_proc,
+ BERTranslateProc decode_proc
+)
+{
+ ber->ber_encode_translate_proc = encode_proc;
+ ber->ber_decode_translate_proc = decode_proc;
+}
+#endif /* STR_TRANSLATION */
diff --git a/usr/src/lib/libldap5/sources/ldap/ber/encode.c b/usr/src/lib/libldap5/sources/ldap/ber/encode.c
new file mode 100644
index 0000000000..49481aa70f
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ber/encode.c
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* encode.c - ber output encoding routines */
+
+#include "lber-int.h"
+
+/* the following constants are used in ber_calc_lenlen */
+
+#define LENMASK1 0xFF
+#define LENMASK2 0xFFFF
+#define LENMASK3 0xFFFFFF
+#define LENMASK4 0xFFFFFFFF
+#define _MASK 0x80
+
+static int
+ber_calc_taglen( ber_tag_t tag )
+{
+ int i;
+ ber_int_t mask;
+
+ /* find the first non-all-zero byte in the tag */
+ for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
+ mask = (LENMASK3 << (i * 8));
+ /* not all zero */
+ if ( tag & mask )
+ break;
+ }
+
+ return( i + 1 );
+}
+
+static int
+ber_put_tag( BerElement *ber, ber_tag_t tag, int nosos )
+{
+ int taglen;
+ ber_tag_t ntag;
+
+ taglen = ber_calc_taglen( tag );
+
+ ntag = LBER_HTONL( tag );
+
+ return( ber_write( ber, ((char *) &ntag) + sizeof(ber_int_t) - taglen,
+ taglen, nosos ) );
+}
+
+static int
+ber_calc_lenlen( ber_len_t len )
+{
+ /*
+ * short len if it's less than 128 - one byte giving the len,
+ * with bit 8 0.
+ */
+
+ if ( len <= 0x7F )
+ return( 1 );
+
+ /*
+ * long len otherwise - one byte with bit 8 set, giving the
+ * length of the length, followed by the length itself.
+ */
+
+ if ( len <= LENMASK1 )
+ return( 2 );
+ if ( len <= LENMASK2 )
+ return( 3 );
+ if ( len <= LENMASK3 )
+ return( 4 );
+
+ return( 5 );
+}
+
+static int
+ber_put_len( BerElement *ber, ber_len_t len, int nosos )
+{
+ int i;
+ char lenlen;
+ ber_int_t mask;
+ ber_len_t netlen;
+
+ /*
+ * short len if it's less than 128 - one byte giving the len,
+ * with bit 8 0.
+ */
+
+ if ( len <= 127 ) {
+ netlen = LBER_HTONL( len );
+ return( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) - 1,
+ 1, nosos ) );
+ }
+
+ /*
+ * long len otherwise - one byte with bit 8 set, giving the
+ * length of the length, followed by the length itself.
+ */
+
+ /* find the first non-all-zero byte */
+ for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
+ mask = (LENMASK1 << (i * 8));
+ /* not all zero */
+ if ( len & mask )
+ break;
+ }
+ lenlen = ++i;
+ if ( lenlen > 4 )
+ return( -1 );
+ lenlen |= 0x80;
+
+ /* write the length of the length */
+ if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
+ return( -1 );
+
+ /* write the length itself */
+ netlen = LBER_HTONL( len );
+ if ( ber_write( ber, (char *) &netlen + (sizeof(ber_int_t) - i), i, nosos )
+ != i )
+ return( -1 );
+
+ return( i + 1 );
+}
+
+static int
+ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
+{
+ int i, sign, taglen;
+ int len, lenlen;
+ ber_int_t netnum, mask;
+
+ sign = (num < 0);
+
+ /*
+ * high bit is set - look for first non-all-one byte
+ * high bit is clear - look for first non-all-zero byte
+ */
+ for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
+ mask = (LENMASK1 << (i * 8));
+
+ if ( sign ) {
+ /* not all ones */
+ if ( (num & mask) != mask )
+ break;
+ } else {
+ /* not all zero */
+ if ( num & mask )
+ break;
+ }
+ }
+
+ /*
+ * we now have the "leading byte". if the high bit on this
+ * byte matches the sign bit, we need to "back up" a byte.
+ */
+ mask = (num & (_MASK << (i * 8)));
+ if ( (mask && !sign) || (sign && !mask) )
+ i++;
+
+ len = i + 1;
+
+ if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+ return( -1 );
+
+ if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
+ return( -1 );
+ i++;
+ netnum = LBER_HTONL( num );
+ if ( ber_write( ber, (char *) &netnum + (sizeof(ber_int_t) - i), i, 0 )
+ == i)
+ /* length of tag + length + contents */
+ return( taglen + lenlen + i );
+
+ return( -1 );
+}
+
+int
+LDAP_CALL
+ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
+{
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_ENUMERATED;
+
+ return( ber_put_int_or_enum( ber, num, tag ) );
+}
+
+int
+LDAP_CALL
+ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag )
+{
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_INTEGER;
+
+ return( ber_put_int_or_enum( ber, num, tag ) );
+}
+
+int
+LDAP_CALL
+ber_put_ostring( BerElement *ber, char *str, ber_len_t len,
+ ber_tag_t tag )
+{
+ int taglen, lenlen, rc;
+#ifdef STR_TRANSLATION
+ int free_str;
+#endif /* STR_TRANSLATION */
+
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_OCTETSTRING;
+
+ if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+ return( -1 );
+
+#ifdef STR_TRANSLATION
+ if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0
+ && ber->ber_encode_translate_proc != NULL ) {
+ if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
+ != 0 ) {
+ return( -1 );
+ }
+ free_str = 1;
+ } else {
+ free_str = 0;
+ }
+#endif /* STR_TRANSLATION */
+
+ /*
+ * Note: below is a spot where we limit ber_write
+ * to signed long (instead of unsigned long)
+ */
+
+ if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
+ ber_write( ber, str, len, 0 ) != (ber_int_t) len ) {
+ rc = -1;
+ } else {
+ /* return length of tag + length + contents */
+ rc = taglen + lenlen + len;
+ }
+
+#ifdef STR_TRANSLATION
+ if ( free_str ) {
+ NSLBERI_FREE( str );
+ }
+#endif /* STR_TRANSLATION */
+
+ return( rc );
+}
+
+int
+LDAP_CALL
+ber_put_string( BerElement *ber, char *str, ber_tag_t tag )
+{
+ return( ber_put_ostring( ber, str, (ber_len_t) strlen( str ), tag ));
+}
+
+int
+LDAP_CALL
+ber_put_bitstring( BerElement *ber, char *str,
+ ber_len_t blen /* in bits */, ber_tag_t tag )
+{
+ int taglen, lenlen, len;
+ unsigned char unusedbits;
+
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_BITSTRING;
+
+ if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+ return( -1 );
+
+ len = ( blen + 7 ) / 8;
+ unusedbits = (unsigned char) (len * 8 - blen);
+ if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
+ return( -1 );
+
+ if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
+ return( -1 );
+
+ if ( ber_write( ber, str, len, 0 ) != len )
+ return( -1 );
+
+ /* return length of tag + length + unused bit count + contents */
+ return( taglen + 1 + lenlen + len );
+}
+
+int
+LDAP_CALL
+ber_put_null( BerElement *ber, ber_tag_t tag )
+{
+ int taglen;
+
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_NULL;
+
+ if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+ return( -1 );
+
+ if ( ber_put_len( ber, 0, 0 ) != 1 )
+ return( -1 );
+
+ return( taglen + 1 );
+}
+
+int
+LDAP_CALL
+ber_put_boolean( BerElement *ber, int boolval, ber_tag_t tag )
+{
+ int taglen;
+ unsigned char trueval = 0xff;
+ unsigned char falseval = 0x00;
+
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_BOOLEAN;
+
+ if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+ return( -1 );
+
+ if ( ber_put_len( ber, 1, 0 ) != 1 )
+ return( -1 );
+
+ if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
+ != 1 )
+ return( -1 );
+
+ return( taglen + 2 );
+}
+
+#define FOUR_BYTE_LEN 5
+
+
+/* the idea here is roughly this: we maintain a stack of these Seqorset
+ * structures. This is pushed when we see the beginning of a new set or
+ * sequence. It is popped when we see the end of a set or sequence.
+ * Since we don't want to malloc and free these structures all the time,
+ * we pre-allocate a small set of them within the ber element structure.
+ * thus we need to spot when we've overflowed this stack and fall back to
+ * malloc'ing instead.
+ */
+static int
+ber_start_seqorset( BerElement *ber, ber_tag_t tag )
+{
+ Seqorset *new_sos;
+
+ /* can we fit into the local stack ? */
+ if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
+ /* yes */
+ new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
+ } else {
+ /* no */
+ if ( (new_sos = (Seqorset *)NSLBERI_MALLOC( sizeof(Seqorset)))
+ == NULLSEQORSET ) {
+ return( -1 );
+ }
+ }
+ ber->ber_sos_stack_posn++;
+
+ if ( ber->ber_sos == NULLSEQORSET )
+ new_sos->sos_first = ber->ber_ptr;
+ else
+ new_sos->sos_first = ber->ber_sos->sos_ptr;
+
+ /* Set aside room for a 4 byte length field */
+ new_sos->sos_ptr = new_sos->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
+ new_sos->sos_tag = tag;
+
+ new_sos->sos_next = ber->ber_sos;
+ new_sos->sos_clen = 0;
+
+ ber->ber_sos = new_sos;
+ if (ber->ber_sos->sos_ptr > ber->ber_end) {
+ nslberi_ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
+ }
+ return( 0 );
+}
+
+int
+LDAP_CALL
+ber_start_seq( BerElement *ber, ber_tag_t tag )
+{
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_SEQUENCE;
+
+ return( ber_start_seqorset( ber, tag ) );
+}
+
+int
+LDAP_CALL
+ber_start_set( BerElement *ber, ber_tag_t tag )
+{
+ if ( tag == LBER_DEFAULT )
+ tag = LBER_SET;
+
+ return( ber_start_seqorset( ber, tag ) );
+}
+
+static int
+ber_put_seqorset( BerElement *ber )
+{
+ ber_len_t len, netlen;
+ int taglen, lenlen;
+ unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1;
+ Seqorset *next;
+ Seqorset **sos = &ber->ber_sos;
+
+ /*
+ * If this is the toplevel sequence or set, we need to actually
+ * write the stuff out. Otherwise, it's already been put in
+ * the appropriate buffer and will be written when the toplevel
+ * one is written. In this case all we need to do is update the
+ * length and tag.
+ */
+
+ len = (*sos)->sos_clen;
+ netlen = LBER_HTONL( len );
+ if ( sizeof(ber_int_t) > 4 && len > LENMASK4 )
+ return( -1 );
+
+ if ( ber->ber_options & LBER_OPT_USE_DER ) {
+ lenlen = ber_calc_lenlen( len );
+ } else {
+ lenlen = FOUR_BYTE_LEN;
+ }
+
+ if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
+ /* write the tag */
+ if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
+ return( -1 );
+
+ if ( ber->ber_options & LBER_OPT_USE_DER ) {
+ /* Write the length in the minimum # of octets */
+ if ( ber_put_len( ber, len, 1 ) == -1 )
+ return( -1 );
+
+ if (lenlen != FOUR_BYTE_LEN) {
+ /*
+ * We set aside FOUR_BYTE_LEN bytes for
+ * the length field. Move the data if
+ * we don't actually need that much
+ */
+ SAFEMEMCPY( (*sos)->sos_first + taglen +
+ lenlen, (*sos)->sos_first + taglen +
+ FOUR_BYTE_LEN, len );
+ }
+ } else {
+ /* Fill FOUR_BYTE_LEN bytes for length field */
+ /* one byte of length length */
+ if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 )
+ return( -1 );
+
+ /* the length itself */
+ if ( ber_write( ber, (char *) &netlen + sizeof(ber_int_t)
+ - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
+ != FOUR_BYTE_LEN - 1 )
+ return( -1 );
+ }
+ /* The ber_ptr is at the set/seq start - move it to the end */
+ ber->ber_ptr += len;
+ } else {
+ ber_tag_t ntag;
+
+ /* the tag */
+ taglen = ber_calc_taglen( (*sos)->sos_tag );
+ ntag = LBER_HTONL( (*sos)->sos_tag );
+ SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
+ sizeof(ber_int_t) - taglen, taglen );
+
+ if ( ber->ber_options & LBER_OPT_USE_DER ) {
+ ltag = (lenlen == 1) ? (unsigned char)len :
+ (unsigned char) (0x80 + (lenlen - 1));
+ }
+
+ /* one byte of length length */
+ SAFEMEMCPY( (*sos)->sos_first + 1, &ltag, 1 );
+
+ if ( ber->ber_options & LBER_OPT_USE_DER ) {
+ if (lenlen > 1) {
+ /* Write the length itself */
+ SAFEMEMCPY( (*sos)->sos_first + 2,
+ (char *)&netlen + sizeof(ber_uint_t) -
+ (lenlen - 1),
+ lenlen - 1 );
+ }
+ if (lenlen != FOUR_BYTE_LEN) {
+ /*
+ * We set aside FOUR_BYTE_LEN bytes for
+ * the length field. Move the data if
+ * we don't actually need that much
+ */
+ SAFEMEMCPY( (*sos)->sos_first + taglen +
+ lenlen, (*sos)->sos_first + taglen +
+ FOUR_BYTE_LEN, len );
+ }
+ } else {
+ /* the length itself */
+ SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
+ (char *) &netlen + sizeof(ber_int_t) -
+ (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
+ }
+
+ next->sos_clen += (taglen + lenlen + len);
+ next->sos_ptr += (taglen + lenlen + len);
+ }
+
+ /* we're done with this seqorset, so free it up */
+ /* was this one from the local stack ? */
+ if (ber->ber_sos_stack_posn <= SOS_STACK_SIZE) {
+ /* yes */
+ } else {
+ /* no */
+ NSLBERI_FREE( (char *) (*sos) );
+ }
+ ber->ber_sos_stack_posn--;
+ *sos = next;
+
+ return( taglen + lenlen + len );
+}
+
+int
+LDAP_CALL
+ber_put_seq( BerElement *ber )
+{
+ return( ber_put_seqorset( ber ) );
+}
+
+int
+LDAP_CALL
+ber_put_set( BerElement *ber )
+{
+ return( ber_put_seqorset( ber ) );
+}
+
+/* VARARGS */
+int
+LDAP_C
+ber_printf( BerElement *ber, const char *fmt, ... )
+{
+ va_list ap;
+ char *s, **ss;
+ struct berval **bv;
+ int rc, i;
+ ber_len_t len;
+
+ va_start( ap, fmt );
+
+#ifdef LDAP_DEBUG
+ if ( lber_debug & 64 ) {
+ char msg[80];
+ sprintf( msg, "ber_printf fmt (%s)\n", fmt );
+ ber_err_print( msg );
+ }
+#endif
+
+ for ( rc = 0; *fmt && rc != -1; fmt++ ) {
+ switch ( *fmt ) {
+ case 'b': /* boolean */
+ i = va_arg( ap, int );
+ rc = ber_put_boolean( ber, i, ber->ber_tag );
+ break;
+
+ case 'i': /* int */
+ i = va_arg( ap, int );
+ rc = ber_put_int( ber, (ber_int_t)i, ber->ber_tag );
+ break;
+
+ case 'e': /* enumeration */
+ i = va_arg( ap, int );
+ rc = ber_put_enum( ber, (ber_int_t)i, ber->ber_tag );
+ break;
+
+ case 'n': /* null */
+ rc = ber_put_null( ber, ber->ber_tag );
+ break;
+
+ case 'o': /* octet string (non-null terminated) */
+ s = va_arg( ap, char * );
+ len = va_arg( ap, int );
+ rc = ber_put_ostring( ber, s, len, ber->ber_tag );
+ break;
+
+ case 's': /* string */
+ s = va_arg( ap, char * );
+ rc = ber_put_string( ber, s, ber->ber_tag );
+ break;
+
+ case 'B': /* bit string */
+ s = va_arg( ap, char * );
+ len = va_arg( ap, int ); /* in bits */
+ rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
+ break;
+
+ case 't': /* tag for the next element */
+ ber->ber_tag = va_arg( ap, ber_tag_t );
+ ber->ber_usertag = 1;
+ break;
+
+ case 'v': /* vector of strings */
+ if ( (ss = va_arg( ap, char ** )) == NULL )
+ break;
+ for ( i = 0; ss[i] != NULL; i++ ) {
+ if ( (rc = ber_put_string( ber, ss[i],
+ ber->ber_tag )) == -1 )
+ break;
+ }
+ break;
+
+ case 'V': /* sequences of strings + lengths */
+ if ( (bv = va_arg( ap, struct berval ** )) == NULL )
+ break;
+ for ( i = 0; bv[i] != NULL; i++ ) {
+ if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
+ bv[i]->bv_len, ber->ber_tag )) == -1 )
+ break;
+ }
+ break;
+
+ case '{': /* begin sequence */
+ rc = ber_start_seq( ber, ber->ber_tag );
+ break;
+
+ case '}': /* end sequence */
+ rc = ber_put_seqorset( ber );
+ break;
+
+ case '[': /* begin set */
+ rc = ber_start_set( ber, ber->ber_tag );
+ break;
+
+ case ']': /* end set */
+ rc = ber_put_seqorset( ber );
+ break;
+
+ default: {
+ char msg[80];
+ sprintf( msg, "unknown fmt %c\n", *fmt );
+ ber_err_print( msg );
+ rc = -1;
+ break;
+ }
+ }
+
+ if ( ber->ber_usertag == 0 )
+ ber->ber_tag = LBER_DEFAULT;
+ else
+ ber->ber_usertag = 0;
+ }
+
+ va_end( ap );
+
+ return( rc );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/ber/io.c b/usr/src/lib/libldap5/sources/ldap/ber/io.c
new file mode 100644
index 0000000000..2110501f09
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ber/io.c
@@ -0,0 +1,1363 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* io.c - ber general i/o routines */
+
+#include "lber-int.h"
+
+#define bergetc( sb, len ) ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \
+ (unsigned char)*sb->sb_ber.ber_ptr++ : \
+ ber_filbuf( sb, len ))
+
+# ifdef macintosh
+/*
+ * MacTCP/OpenTransport
+ */
+# define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL )
+# define MAX_WRITE 65535
+# define BerWrite( sb, b, l ) tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE )
+# else /* macintosh */
+# if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2)
+/*
+ * 32-bit Windows Socket API (under Windows NT or Windows 95)
+ */
+# define read( s, b, l ) recv( s, b, l, 0 )
+# define BerWrite( s, b, l ) send( s->sb_sd, b, l, 0 )
+# else /* _WIN32 */
+/*
+ * everything else (Unix/BSD 4.3 socket API)
+ */
+# define BerWrite( sb, b, l ) write( sb->sb_sd, b, l )
+# define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \
+ (struct sockaddr *)sb->sb_fromaddr, \
+ (al = sizeof(struct sockaddr), &al))
+# define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \
+ (struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr))
+# endif /* _WIN32 */
+# endif /* macintosh */
+
+#ifndef udp_read
+#define udp_read( sb, b, l, al ) CLDAP NOT SUPPORTED
+#define udp_write( sb, b, l ) CLDAP NOT SUPPORTED
+#endif /* udp_read */
+
+#define EXBUFSIZ 1024
+
+#ifdef LDAP_DEBUG
+int lber_debug;
+#endif
+
+/*
+ * function prototypes
+ */
+static void nslberi_install_compat_io_fns( Sockbuf *sb );
+static int nslberi_extread_compat( int s, void *buf, int len,
+ struct lextiof_socket_private *arg );
+static int nslberi_extwrite_compat( int s, const void *buf, int len,
+ struct lextiof_socket_private *arg );
+
+
+/*
+ * internal global structure for memory allocation callback functions
+ */
+static struct lber_memalloc_fns nslberi_memalloc_fns;
+
+
+/*
+ * buffered read from "sb".
+ * returns value of first character read on success and -1 on error.
+ */
+static int
+ber_filbuf( Sockbuf *sb, ber_slen_t len )
+{
+ ssize_t rc;
+#ifdef CLDAP
+ int addrlen;
+#endif /* CLDAP */
+
+ if ( sb->sb_ber.ber_buf == NULL ) {
+ if ( (sb->sb_ber.ber_buf = (char *)NSLBERI_MALLOC(
+ READBUFSIZ )) == NULL ) {
+ return( -1 );
+ }
+ sb->sb_ber.ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+ sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf;
+ sb->sb_ber.ber_end = sb->sb_ber.ber_buf;
+ }
+
+ if ( sb->sb_naddr > 0 ) {
+#ifdef CLDAP
+ rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen );
+#ifdef LDAP_DEBUG
+ if ( lber_debug ) {
+ char msg[80];
+ sprintf( msg, "ber_filbuf udp_read %d bytes\n",
+ rc );
+ ber_err_print( msg );
+ if ( lber_debug > 1 && rc > 0 )
+ lber_bprint( sb->sb_ber.ber_buf, rc );
+ }
+#endif /* LDAP_DEBUG */
+#else /* CLDAP */
+ rc = -1;
+#endif /* CLDAP */
+ } else {
+ if ( sb->sb_ext_io_fns.lbextiofn_read != NULL ) {
+ rc = sb->sb_ext_io_fns.lbextiofn_read(
+ sb->sb_sd, sb->sb_ber.ber_buf,
+ ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
+ && (len < READBUFSIZ)) ? len : READBUFSIZ,
+ sb->sb_ext_io_fns.lbextiofn_socket_arg );
+ } else {
+ rc = read( sb->sb_sd, sb->sb_ber.ber_buf,
+ ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
+ && (len < READBUFSIZ)) ? len : READBUFSIZ );
+ }
+ }
+
+ if ( rc > 0 ) {
+ sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1;
+ sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc;
+ return( (unsigned char)*sb->sb_ber.ber_buf );
+ }
+
+ return( -1 );
+}
+
+
+static ber_int_t
+BerRead( Sockbuf *sb, char *buf, ber_slen_t len )
+{
+ int c;
+ ber_int_t nread = 0;
+
+ while ( len > 0 ) {
+ if ( (c = bergetc( sb, len )) < 0 ) {
+ if ( nread > 0 )
+ break;
+ return( c );
+ }
+ *buf++ = c;
+ nread++;
+ len--;
+ }
+
+ return( nread );
+}
+
+
+/*
+ * Note: ber_read() only uses the ber_end and ber_ptr elements of ber.
+ * Functions like ber_get_tag(), ber_skip_tag, and ber_peek_tag() rely on
+ * that fact, so if this code is changed to use any additional elements of
+ * the ber structure, those functions will need to be changed as well.
+ */
+ber_int_t
+LDAP_CALL
+ber_read( BerElement *ber, char *buf, ber_len_t len )
+{
+ ber_len_t actuallen;
+ ber_uint_t nleft;
+
+ nleft = ber->ber_end - ber->ber_ptr;
+ actuallen = nleft < len ? nleft : len;
+
+ SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
+
+ ber->ber_ptr += actuallen;
+
+ return( (ber_int_t)actuallen );
+}
+
+/*
+ * enlarge the ber buffer.
+ * return 0 on success, -1 on error.
+ */
+int
+nslberi_ber_realloc( BerElement *ber, ber_len_t len )
+{
+ ber_uint_t need, have, total;
+ size_t have_bytes;
+ Seqorset *s;
+ ber_int_t off;
+ char *oldbuf;
+
+ have_bytes = ber->ber_end - ber->ber_buf;
+ have = have_bytes / EXBUFSIZ;
+ need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
+ total = have * EXBUFSIZ + need * EXBUFSIZ;
+
+ oldbuf = ber->ber_buf;
+
+ if (ber->ber_buf == NULL) {
+ if ( (ber->ber_buf = (char *)NSLBERI_MALLOC( (size_t)total ))
+ == NULL ) {
+ return( -1 );
+ }
+ ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+ } else {
+ if ( ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER ) {
+ /* transition to malloc'd buffer */
+ if ( (ber->ber_buf = (char *)NSLBERI_MALLOC(
+ (size_t)total )) == NULL ) {
+ return( -1 );
+ }
+ ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+ /* copy existing data into new malloc'd buffer */
+ SAFEMEMCPY( ber->ber_buf, oldbuf, have_bytes );
+ } else {
+ if ( (ber->ber_buf = (char *)NSLBERI_REALLOC(
+ ber->ber_buf,(size_t)total )) == NULL ) {
+ return( -1 );
+ }
+ }
+ }
+
+ ber->ber_end = ber->ber_buf + total;
+
+ /*
+ * If the stinking thing was moved, we need to go through and
+ * reset all the sos and ber pointers. Offsets would've been
+ * a better idea... oh well.
+ */
+
+ if ( ber->ber_buf != oldbuf ) {
+ ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
+
+ for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
+ off = s->sos_first - oldbuf;
+ s->sos_first = ber->ber_buf + off;
+
+ off = s->sos_ptr - oldbuf;
+ s->sos_ptr = ber->ber_buf + off;
+ }
+ }
+
+ return( 0 );
+}
+
+/*
+ * returns "len" on success and -1 on failure.
+ */
+ber_int_t
+LDAP_CALL
+ber_write( BerElement *ber, char *buf, ber_len_t len, int nosos )
+{
+ if ( nosos || ber->ber_sos == NULL ) {
+ if ( ber->ber_ptr + len > ber->ber_end ) {
+ if ( nslberi_ber_realloc( ber, len ) != 0 )
+ return( -1 );
+ }
+ SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
+ ber->ber_ptr += len;
+ return( len );
+ } else {
+ if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
+ if ( nslberi_ber_realloc( ber, len ) != 0 )
+ return( -1 );
+ }
+ SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
+ ber->ber_sos->sos_ptr += len;
+ ber->ber_sos->sos_clen += len;
+ return( len );
+ }
+}
+
+void
+LDAP_CALL
+ber_free( BerElement *ber, int freebuf )
+{
+ if ( ber != NULL ) {
+ if ( freebuf &&
+ !(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
+ NSLBERI_FREE(ber->ber_buf);
+ }
+ NSLBERI_FREE( (char *) ber );
+ }
+}
+
+/*
+ * return >= 0 on success, -1 on failure.
+ */
+int
+LDAP_CALL
+ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
+{
+ ssize_t nwritten, towrite, rc;
+
+ if ( ber->ber_rwptr == NULL ) {
+ ber->ber_rwptr = ber->ber_buf;
+ } else if (ber->ber_rwptr >= ber->ber_end) {
+ /* we will use the ber_rwptr to continue an exited flush,
+ so if rwptr is not within the buffer we return an error. */
+ return( -1 );
+ }
+ towrite = ber->ber_ptr - ber->ber_rwptr;
+
+#ifdef LDAP_DEBUG
+ if ( lber_debug ) {
+ char msg[80];
+ sprintf( msg, "ber_flush: %ld bytes to sd %ld%s\n", towrite,
+ sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
+ : "" );
+ ber_err_print( msg );
+ if ( lber_debug > 1 )
+ lber_bprint( ber->ber_rwptr, towrite );
+ }
+#endif
+#if !defined(macintosh) && !defined(DOS)
+ if ( sb->sb_options & (LBER_SOCKBUF_OPT_TO_FILE | LBER_SOCKBUF_OPT_TO_FILE_ONLY) ) {
+ rc = write( sb->sb_copyfd, ber->ber_buf, towrite );
+ if ( sb->sb_options & LBER_SOCKBUF_OPT_TO_FILE_ONLY ) {
+ return( (int)rc );
+ }
+ }
+#endif
+
+ nwritten = 0;
+ do {
+ if (sb->sb_naddr > 0) {
+#ifdef CLDAP
+ rc = udp_write( sb, ber->ber_buf + nwritten,
+ (size_t)towrite );
+#else /* CLDAP */
+ rc = -1;
+#endif /* CLDAP */
+ if ( rc <= 0 )
+ return( -1 );
+ /* fake error if write was not atomic */
+ if (rc < towrite) {
+#if !defined( macintosh ) && !defined( DOS )
+ errno = EMSGSIZE; /* For Win32, see portable.h */
+#endif
+ return( -1 );
+ }
+ } else {
+ if ( sb->sb_ext_io_fns.lbextiofn_write != NULL ) {
+ if ( (rc = sb->sb_ext_io_fns.lbextiofn_write(
+ sb->sb_sd, ber->ber_rwptr, (size_t)towrite,
+ sb->sb_ext_io_fns.lbextiofn_socket_arg ))
+ <= 0 ) {
+ return( -1 );
+ }
+ } else {
+ if ( (rc = BerWrite( sb, ber->ber_rwptr,
+ (size_t) towrite )) <= 0 ) {
+ return( -1 );
+ }
+ }
+ }
+ towrite -= rc;
+ nwritten += rc;
+ ber->ber_rwptr += rc;
+ } while ( towrite > 0 );
+
+ if ( freeit )
+ ber_free( ber, 1 );
+
+ return( 0 );
+}
+
+
+/* we pre-allocate a buffer to save the extra malloc later */
+BerElement *
+LDAP_CALL
+ber_alloc_t( int options )
+{
+ BerElement *ber;
+
+ if ( (ber = (BerElement*)NSLBERI_CALLOC( 1,
+ sizeof(struct berelement) + EXBUFSIZ )) == NULL ) {
+ return( NULL );
+ }
+
+ /*
+ * for compatibility with the C LDAP API standard, we recognize
+ * LBER_USE_DER as LBER_OPT_USE_DER. See lber.h for a bit more info.
+ */
+ if ( options & LBER_USE_DER ) {
+ options &= ~LBER_USE_DER;
+ options |= LBER_OPT_USE_DER;
+ }
+
+ ber->ber_tag = LBER_DEFAULT;
+ ber->ber_options = options;
+ ber->ber_buf = (char*)ber + sizeof(struct berelement);
+ ber->ber_ptr = ber->ber_buf;
+ ber->ber_end = ber->ber_buf + EXBUFSIZ;
+ ber->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
+
+ return( ber );
+}
+
+
+BerElement *
+LDAP_CALL
+ber_alloc()
+{
+ return( ber_alloc_t( 0 ) );
+}
+
+BerElement *
+LDAP_CALL
+der_alloc()
+{
+ return( ber_alloc_t( LBER_OPT_USE_DER ) );
+}
+
+BerElement *
+LDAP_CALL
+ber_dup( BerElement *ber )
+{
+ BerElement *new;
+
+ if ( (new = ber_alloc()) == NULL )
+ return( NULL );
+
+ *new = *ber;
+
+ return( new );
+}
+
+
+void
+LDAP_CALL
+ber_init_w_nullchar( BerElement *ber, int options )
+{
+ (void) memset( (char *)ber, '\0', sizeof(struct berelement) );
+ ber->ber_tag = LBER_DEFAULT;
+
+ /*
+ * For compatibility with the C LDAP API standard, we recognize
+ * LBER_USE_DER as LBER_OPT_USE_DER. See lber.h for a bit more info.
+ */
+ if ( options & LBER_USE_DER ) {
+ options &= ~LBER_USE_DER;
+ options |= LBER_OPT_USE_DER;
+ }
+
+ ber->ber_options = options;
+}
+
+
+void
+LDAP_CALL
+ber_reset( BerElement *ber, int was_writing )
+{
+ if ( was_writing ) {
+ ber->ber_end = ber->ber_ptr;
+ ber->ber_ptr = ber->ber_buf;
+ } else {
+ ber->ber_ptr = ber->ber_end;
+ }
+
+ ber->ber_rwptr = NULL;
+}
+
+
+#ifdef LDAP_DEBUG
+
+void
+ber_dump( BerElement *ber, int inout )
+{
+ char msg[128];
+ sprintf( msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
+ ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end );
+ ber_err_print( msg );
+ if ( inout == 1 ) {
+ sprintf( msg, " current len %ld, contents:\n",
+ ber->ber_end - ber->ber_ptr );
+ ber_err_print( msg );
+ lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr );
+ } else {
+ sprintf( msg, " current len %ld, contents:\n",
+ ber->ber_ptr - ber->ber_buf );
+ ber_err_print( msg );
+ lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf );
+ }
+}
+
+void
+ber_sos_dump( Seqorset *sos )
+{
+ char msg[80];
+ ber_err_print ( "*** sos dump ***\n" );
+ while ( sos != NULLSEQORSET ) {
+ sprintf( msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
+ sos->sos_clen, sos->sos_first, sos->sos_ptr );
+ ber_err_print( msg );
+ sprintf( msg, " current len %ld contents:\n",
+ sos->sos_ptr - sos->sos_first );
+ ber_err_print( msg );
+ lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
+
+ sos = sos->sos_next;
+ }
+ ber_err_print( "*** end dump ***\n" );
+}
+
+#endif
+
+/* return the tag - LBER_DEFAULT returned means trouble */
+static ber_tag_t
+get_tag( Sockbuf *sb )
+{
+ unsigned char xbyte;
+ ber_tag_t tag;
+ char *tagp;
+ int i;
+
+ if ( (i = BerRead( sb, (char *) &xbyte, 1 )) != 1 ) {
+ return( LBER_DEFAULT );
+ }
+
+ if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
+ return( (ber_uint_t) xbyte );
+ }
+
+ tagp = (char *) &tag;
+ tagp[0] = xbyte;
+ for ( i = 1; i < sizeof(ber_int_t); i++ ) {
+ if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 )
+ return( LBER_DEFAULT );
+
+ tagp[i] = xbyte;
+
+ if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+ break;
+ }
+
+ /* tag too big! */
+ if ( i == sizeof(ber_int_t) )
+ return( LBER_DEFAULT );
+
+ /* want leading, not trailing 0's */
+ return( tag >> (sizeof(ber_int_t) - i - 1) );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_next( Sockbuf *sb, ber_len_t *len, BerElement *ber )
+{
+ ber_tag_t tag = 0;
+ ber_len_t netlen;
+ ber_uint_t toread;
+ unsigned char lc;
+ ber_int_t rc;
+ int noctets, diff;
+
+#ifdef LDAP_DEBUG
+ if ( lber_debug )
+ ber_err_print( "ber_get_next\n" );
+#endif
+
+ /*
+ * Any ber element looks like this: tag length contents.
+ * Assuming everything's ok, we return the tag byte (we
+ * can assume a single byte), return the length in len,
+ * and the rest of the undecoded element in buf.
+ *
+ * Assumptions:
+ * 1) small tags (less than 128)
+ * 2) definite lengths
+ * 3) primitive encodings used whenever possible
+ */
+
+ /*
+ * first time through - malloc the buffer, set up ptrs, and
+ * read the tag and the length and as much of the rest as we can
+ */
+
+ if ( ber->ber_rwptr == NULL ) {
+ /*
+ * First, we read the tag.
+ */
+
+ if ( (tag = get_tag( sb )) == LBER_DEFAULT ) {
+ return( LBER_DEFAULT );
+ }
+ ber->ber_tag = tag;
+
+ /*
+ * Next, read the length. The first byte contains the length
+ * of the length. If bit 8 is set, the length is the long
+ * form, otherwise it's the short form. We don't allow a
+ * length that's greater than what we can hold in an unsigned
+ * long.
+ */
+
+ *len = netlen = 0;
+ if ( BerRead( sb, (char *) &lc, 1 ) != 1 ) {
+ return( LBER_DEFAULT );
+ }
+ if ( lc & 0x80 ) {
+ noctets = (lc & 0x7f);
+ if ( noctets > sizeof(ber_uint_t) )
+ return( LBER_DEFAULT );
+ diff = sizeof(ber_uint_t) - noctets;
+ if ( BerRead( sb, (char *) &netlen + diff, noctets ) !=
+ noctets ) {
+ return( LBER_DEFAULT );
+ }
+ *len = LBER_NTOHL( netlen );
+ } else {
+ *len = lc;
+ }
+ ber->ber_len = *len;
+
+ /*
+ * Finally, malloc a buffer for the contents and read it in.
+ * It's this buffer that's passed to all the other ber decoding
+ * routines.
+ */
+
+#if defined( DOS ) && !( defined( _WIN32 ) || defined(XP_OS2) )
+ if ( *len > 65535 ) { /* DOS can't allocate > 64K */
+ return( LBER_DEFAULT );
+ }
+#endif /* DOS && !_WIN32 */
+
+ if ( ( sb->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
+ && *len > sb->sb_max_incoming ) {
+ return( LBER_DEFAULT );
+ }
+
+ if ( (ber->ber_buf = (char *)NSLBERI_CALLOC( 1,(size_t)*len ))
+ == NULL ) {
+ return( LBER_DEFAULT );
+ }
+ ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+ ber->ber_ptr = ber->ber_buf;
+ ber->ber_end = ber->ber_buf + *len;
+ ber->ber_rwptr = ber->ber_buf;
+ }
+
+ toread = (uintptr_t)ber->ber_end - (uintptr_t)ber->ber_rwptr;
+ do {
+ if ( (rc = BerRead( sb, ber->ber_rwptr, (ber_int_t)toread )) <= 0 ) {
+ return( LBER_DEFAULT );
+ }
+
+ toread -= rc;
+ ber->ber_rwptr += rc;
+ } while ( toread > 0 );
+
+#ifdef LDAP_DEBUG
+ if ( lber_debug ) {
+ char msg[80];
+ sprintf( msg, "ber_get_next: tag 0x%lx len %ld contents:\n",
+ tag, ber->ber_len );
+ ber_err_print( msg );
+ if ( lber_debug > 1 )
+ ber_dump( ber, 1 );
+ }
+#endif
+
+ *len = ber->ber_len;
+ ber->ber_rwptr = NULL;
+ return( ber->ber_tag );
+}
+
+Sockbuf *
+LDAP_CALL
+ber_sockbuf_alloc()
+{
+ return( (Sockbuf *)NSLBERI_CALLOC( 1, sizeof(struct sockbuf) ) );
+}
+
+void
+LDAP_CALL
+ber_sockbuf_free(Sockbuf *p)
+{
+ if ( p != NULL ) {
+ if ( p->sb_ber.ber_buf != NULL &&
+ !(p->sb_ber.ber_flags & LBER_FLAG_NO_FREE_BUFFER) ) {
+ NSLBERI_FREE( p->sb_ber.ber_buf );
+ }
+ NSLBERI_FREE(p);
+ }
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_set_option( struct berelement *ber, int option, void *value )
+{
+
+ /*
+ * memory allocation callbacks are global, so it is OK to pass
+ * NULL for ber. Handle this as a special case.
+ */
+ if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
+ /* struct copy */
+ nslberi_memalloc_fns = *((struct lber_memalloc_fns *)value);
+ return( 0 );
+ }
+
+ /*
+ * lber_debug is global, so it is OK to pass
+ * NULL for ber. Handle this as a special case.
+ */
+ if ( option == LBER_OPT_DEBUG_LEVEL ) {
+#ifdef LDAP_DEBUG
+ lber_debug = *(int *)value;
+#endif
+ return( 0 );
+ }
+
+ /*
+ * all the rest require a non-NULL ber
+ */
+ if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
+ return( -1 );
+ }
+
+ switch ( option ) {
+ case LBER_OPT_USE_DER:
+ case LBER_OPT_TRANSLATE_STRINGS:
+ if ( value != NULL ) {
+ ber->ber_options |= option;
+ } else {
+ ber->ber_options &= ~option;
+ }
+ break;
+ case LBER_OPT_REMAINING_BYTES:
+ ber->ber_end = ber->ber_ptr + *((ber_uint_t *)value);
+ break;
+ case LBER_OPT_TOTAL_BYTES:
+ ber->ber_end = ber->ber_buf + *((ber_uint_t *)value);
+ break;
+ case LBER_OPT_BYTES_TO_WRITE:
+ ber->ber_ptr = ber->ber_buf + *((ber_uint_t *)value);
+ break;
+ default:
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_get_option( struct berelement *ber, int option, void *value )
+{
+ /*
+ * memory callocation callbacks are global, so it is OK to pass
+ * NULL for ber. Handle this as a special case
+ */
+ if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
+ /* struct copy */
+ *((struct lber_memalloc_fns *)value) = nslberi_memalloc_fns;
+ return( 0 );
+ }
+
+ /*
+ * lber_debug is global, so it is OK to pass
+ * NULL for ber. Handle this as a special case.
+ */
+ if ( option == LBER_OPT_DEBUG_LEVEL ) {
+#ifdef LDAP_DEBUG
+ *(int *)value = lber_debug;
+#endif
+ return( 0 );
+ }
+ /*
+ * all the rest require a non-NULL ber
+ */
+ if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
+ return( -1 );
+ }
+
+ switch ( option ) {
+ case LBER_OPT_USE_DER:
+ case LBER_OPT_TRANSLATE_STRINGS:
+ *((int *) value) = (ber->ber_options & option);
+ break;
+ case LBER_OPT_REMAINING_BYTES:
+ *((ber_uint_t *) value) = ber->ber_end - ber->ber_ptr;
+ break;
+ case LBER_OPT_TOTAL_BYTES:
+ *((ber_uint_t *) value) = ber->ber_end - ber->ber_buf;
+ break;
+ case LBER_OPT_BYTES_TO_WRITE:
+ *((ber_uint_t *) value) = ber->ber_ptr - ber->ber_buf;
+ break;
+ default:
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_sockbuf_set_option( Sockbuf *sb, int option, void *value )
+{
+ struct lber_x_ext_io_fns *extiofns;
+
+ if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
+ return( -1 );
+ }
+
+ switch ( option ) {
+ case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
+ sb->sb_max_incoming = *((ber_uint_t *) value);
+ /* FALL */
+ case LBER_SOCKBUF_OPT_TO_FILE:
+ case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
+ case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
+ if ( value != NULL ) {
+ sb->sb_options |= option;
+ } else {
+ sb->sb_options &= ~option;
+ }
+ break;
+ case LBER_SOCKBUF_OPT_DESC:
+ sb->sb_sd = *((LBER_SOCKET *) value);
+ break;
+ case LBER_SOCKBUF_OPT_COPYDESC:
+ sb->sb_copyfd = *((LBER_SOCKET *) value);
+ break;
+ case LBER_SOCKBUF_OPT_READ_FN:
+ sb->sb_io_fns.lbiof_read = (LDAP_IOF_READ_CALLBACK *) value;
+ nslberi_install_compat_io_fns( sb );
+ break;
+ case LBER_SOCKBUF_OPT_WRITE_FN:
+ sb->sb_io_fns.lbiof_write = (LDAP_IOF_WRITE_CALLBACK *) value;
+ nslberi_install_compat_io_fns( sb );
+ break;
+ case LBER_SOCKBUF_OPT_EXT_IO_FNS:
+ extiofns = (struct lber_x_ext_io_fns *) value;
+ if ( extiofns == NULL ) { /* remove */
+ (void)memset( (char *)&sb->sb_ext_io_fns, '\0',
+ sizeof(sb->sb_ext_io_fns ));
+ } else if ( extiofns->lbextiofn_size
+ == LBER_X_EXTIO_FNS_SIZE ) {
+ /* struct copy */
+ sb->sb_ext_io_fns = *extiofns;
+ } else {
+ return( -1 );
+ }
+ break;
+ default:
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_sockbuf_get_option( Sockbuf *sb, int option, void *value )
+{
+ struct lber_x_ext_io_fns *extiofns;
+
+ if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
+ return( -1 );
+ }
+
+ switch ( option ) {
+ case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
+ *((ber_uint_t *) value) = sb->sb_max_incoming;
+ break;
+ case LBER_SOCKBUF_OPT_TO_FILE:
+ case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
+ case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
+ *((int *) value) = (sb->sb_options & option);
+ break;
+ case LBER_SOCKBUF_OPT_DESC:
+ *((LBER_SOCKET *) value) = sb->sb_sd;
+ break;
+ case LBER_SOCKBUF_OPT_COPYDESC:
+ *((LBER_SOCKET *) value) = sb->sb_copyfd;
+ break;
+ case LBER_SOCKBUF_OPT_READ_FN:
+ *((LDAP_IOF_READ_CALLBACK **) value)
+ = sb->sb_io_fns.lbiof_read;
+ break;
+ case LBER_SOCKBUF_OPT_WRITE_FN:
+ *((LDAP_IOF_WRITE_CALLBACK **) value)
+ = sb->sb_io_fns.lbiof_write;
+ break;
+ case LBER_SOCKBUF_OPT_EXT_IO_FNS:
+ extiofns = (struct lber_x_ext_io_fns *) value;
+ if ( extiofns == NULL || extiofns->lbextiofn_size
+ != LBER_X_EXTIO_FNS_SIZE ) {
+ return( -1 );
+ }
+ /* struct copy */
+ *extiofns = sb->sb_ext_io_fns;
+ break;
+ default:
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+/* new dboreham code below: */
+
+struct byte_buffer {
+ unsigned char *p;
+ int offset;
+ int length;
+};
+typedef struct byte_buffer byte_buffer;
+
+
+/* This call allocates us a BerElement structure plus some extra memory.
+ * It returns a pointer to the BerElement, plus a pointer to the extra memory.
+ * This routine also allocates a ber data buffer within the same block, thus
+ * saving a call to calloc later when we read data.
+ */
+void*
+LDAP_CALL
+ber_special_alloc(size_t size, BerElement **ppBer)
+{
+ char *mem = NULL;
+
+ /* Make sure mem size requested is aligned */
+ if (0 != ( size & 0x03 )) {
+ size += (sizeof(ber_int_t) - (size & 0x03));
+ }
+
+ mem = NSLBERI_MALLOC(sizeof(struct berelement) + EXBUFSIZ + size );
+ if (NULL == mem) {
+ return NULL;
+ }
+ *ppBer = (BerElement*) (mem + size);
+ memset(*ppBer,0,sizeof(struct berelement));
+ (*ppBer)->ber_tag = LBER_DEFAULT;
+ (*ppBer)->ber_buf = mem + size + sizeof(struct berelement);
+ (*ppBer)->ber_ptr = (*ppBer)->ber_buf;
+ (*ppBer)->ber_end = (*ppBer)->ber_buf + EXBUFSIZ;
+ (*ppBer)->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
+ return (void*)mem;
+}
+
+void
+LDAP_CALL
+ber_special_free(void* buf, BerElement *ber)
+{
+ if (!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
+ NSLBERI_FREE(ber->ber_buf);
+ }
+ NSLBERI_FREE( buf );
+}
+
+static int
+read_bytes(byte_buffer *b, unsigned char *return_buffer, int bytes_to_read)
+{
+ /* copy up to bytes_to_read bytes into the caller's buffer, return the number of bytes copied */
+ int bytes_to_copy = 0;
+
+ if (bytes_to_read <= (b->length - b->offset) ) {
+ bytes_to_copy = bytes_to_read;
+ } else {
+ bytes_to_copy = (b->length - b->offset);
+ }
+ if (1 == bytes_to_copy) {
+ *return_buffer = *(b->p+b->offset++);
+ } else
+ if (0 == bytes_to_copy) {
+ ;
+ } else
+ {
+ memcpy(return_buffer,b->p+b->offset,bytes_to_copy);
+ b->offset += bytes_to_copy;
+ }
+ return bytes_to_copy;
+}
+
+/* return the tag - LBER_DEFAULT returned means trouble */
+static ber_tag_t
+get_buffer_tag(byte_buffer *sb )
+{
+ unsigned char xbyte;
+ ber_tag_t tag;
+ char *tagp;
+ int i;
+
+ if ( (i = read_bytes( sb, &xbyte, 1 )) != 1 ) {
+ return( LBER_DEFAULT );
+ }
+
+ if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
+ return( (ber_uint_t) xbyte );
+ }
+
+ tagp = (char *) &tag;
+ tagp[0] = xbyte;
+ for ( i = 1; i < sizeof(ber_int_t); i++ ) {
+ if ( read_bytes( sb, &xbyte, 1 ) != 1 )
+ return( LBER_DEFAULT );
+
+ tagp[i] = xbyte;
+
+ if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+ break;
+ }
+
+ /* tag too big! */
+ if ( i == sizeof(ber_int_t) )
+ return( LBER_DEFAULT );
+
+ /* want leading, not trailing 0's */
+ return( tag >> (sizeof(ber_int_t) - i - 1) );
+}
+
+/* Like ber_get_next, but from a byte buffer the caller already has. */
+/* Bytes_Scanned returns the number of bytes we actually looked at in the buffer. */
+/* ber_get_next_buffer is now implemented in terms of ber_get_next_buffer_ext */
+/* and is here for backward compatibility. This new function allows us to pass */
+/* the Sockbuf structure along */
+
+ber_uint_t
+LDAP_CALL
+ber_get_next_buffer( void *buffer, size_t buffer_size, ber_len_t *len,
+ BerElement *ber, ber_uint_t *Bytes_Scanned )
+{
+ return (ber_get_next_buffer_ext( buffer, buffer_size, len, ber,
+ Bytes_Scanned, NULL));
+}
+
+ber_uint_t
+LDAP_CALL
+ber_get_next_buffer_ext( void *buffer, size_t buffer_size, ber_len_t *len,
+ BerElement *ber, ber_uint_t *Bytes_Scanned, Sockbuf *sock )
+{
+ ber_tag_t tag = 0;
+ ber_len_t netlen;
+ ber_uint_t toread;
+ unsigned char lc;
+ ssize_t rc;
+ int noctets, diff;
+ byte_buffer sb = {0};
+
+
+ /*
+ * Any ber element looks like this: tag length contents.
+ * Assuming everything's ok, we return the tag byte (we
+ * can assume a single byte), return the length in len,
+ * and the rest of the undecoded element in buf.
+ *
+ * Assumptions:
+ * 1) small tags (less than 128)
+ * 2) definite lengths
+ * 3) primitive encodings used whenever possible
+ */
+
+ /*
+ * first time through - malloc the buffer, set up ptrs, and
+ * read the tag and the length and as much of the rest as we can
+ */
+
+ sb.p = buffer;
+ sb.length = buffer_size;
+
+ if ( ber->ber_rwptr == NULL ) {
+ /*
+ * First, we read the tag.
+ */
+
+ if ( (tag = get_buffer_tag( &sb )) == LBER_DEFAULT ) {
+ goto premature_exit;
+ }
+ ber->ber_tag = tag;
+
+ /*
+ * Next, read the length. The first byte contains the length
+ * of the length. If bit 8 is set, the length is the long
+ * form, otherwise it's the short form. We don't allow a
+ * length that's greater than what we can hold in an unsigned
+ * long.
+ */
+
+ *len = netlen = 0;
+ if ( read_bytes( &sb, &lc, 1 ) != 1 ) {
+ goto premature_exit;
+ }
+ if ( lc & 0x80 ) {
+ noctets = (lc & 0x7f);
+ if ( noctets > sizeof(ber_uint_t) )
+ goto premature_exit;
+ diff = sizeof(ber_uint_t) - noctets;
+ if ( read_bytes( &sb, (unsigned char *)&netlen + diff,
+ noctets ) != noctets ) {
+ goto premature_exit;
+ }
+ *len = LBER_NTOHL( netlen );
+ } else {
+ *len = lc;
+ }
+ ber->ber_len = *len;
+
+ /*
+ * Finally, malloc a buffer for the contents and read it in.
+ * It's this buffer that's passed to all the other ber decoding
+ * routines.
+ */
+
+#if defined( DOS ) && !defined( _WIN32 )
+ if ( *len > 65535 ) { /* DOS can't allocate > 64K */
+ goto premature_exit;
+ }
+#endif /* DOS && !_WIN32 */
+
+ if ( (sock != NULL) &&
+ ( sock->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
+ && (*len > sock->sb_max_incoming) ) {
+ return( LBER_DEFAULT );
+ }
+
+ if ( ber->ber_buf + *len > ber->ber_end ) {
+ if ( nslberi_ber_realloc( ber, *len ) != 0 )
+ goto premature_exit;
+ }
+ ber->ber_ptr = ber->ber_buf;
+ ber->ber_end = ber->ber_buf + *len;
+ ber->ber_rwptr = ber->ber_buf;
+ }
+
+ toread = (uintptr_t)ber->ber_end - (uintptr_t)ber->ber_rwptr;
+ do {
+ if ( (rc = read_bytes( &sb, (unsigned char *)ber->ber_rwptr,
+ (ber_int_t)toread )) <= 0 ) {
+ goto premature_exit;
+ }
+
+ toread -= rc;
+ ber->ber_rwptr += rc;
+ } while ( toread > 0 );
+
+ *len = ber->ber_len;
+ *Bytes_Scanned = sb.offset;
+ return( ber->ber_tag );
+
+premature_exit:
+ /*
+ * we're here because we hit the end of the buffer before seeing
+ * all of the PDU
+ */
+ *Bytes_Scanned = sb.offset;
+ return(LBER_DEFAULT);
+}
+
+
+/* The ber_flatten routine allocates a struct berval whose contents
+ * are a BER encoding taken from the ber argument. The bvPtr pointer
+ * points to the returned berval, which must be freed using
+ * ber_bvfree(). This routine returns 0 on success and -1 on error.
+ * The use of ber_flatten on a BerElement in which all '{' and '}'
+ * format modifiers have not been properly matched can result in a
+ * berval whose contents are not a valid BER encoding.
+ * Note that the ber_ptr is not modified.
+ */
+int
+LDAP_CALL
+ber_flatten( BerElement *ber, struct berval **bvPtr )
+{
+ struct berval *new;
+ ber_len_t len;
+
+ /* allocate a struct berval */
+ if ( (new = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
+ == NULL ) {
+ return( -1 );
+ }
+
+ /*
+ * Copy everything from the BerElement's ber_buf to ber_ptr
+ * into the berval structure.
+ */
+ if ( ber == NULL ) {
+ new->bv_val = NULL;
+ new->bv_len = 0;
+ } else {
+ len = ber->ber_ptr - ber->ber_buf;
+ if ( ( new->bv_val = (char *)NSLBERI_MALLOC( len + 1 )) == NULL ) {
+ ber_bvfree( new );
+ return( -1 );
+ }
+ SAFEMEMCPY( new->bv_val, ber->ber_buf, (size_t)len );
+ new->bv_val[len] = '\0';
+ new->bv_len = len;
+ }
+
+ /* set bvPtr pointer to point to the returned berval */
+ *bvPtr = new;
+
+ return( 0 );
+}
+
+
+/*
+ * The ber_init function constructs and returns a new BerElement
+ * containing a copy of the data in the bv argument. ber_init
+ * returns the null pointer on error.
+ */
+BerElement *
+LDAP_CALL
+ber_init( const struct berval *bv )
+{
+ BerElement *ber;
+
+ /* construct BerElement */
+ if (( ber = ber_alloc_t( 0 )) != NULLBER ) {
+ /* copy data from the bv argument into BerElement */
+ /* XXXmcs: had to cast unsigned long bv_len to long */
+ if ( (ber_write ( ber, bv->bv_val, bv->bv_len, 0 ))
+ != (ber_slen_t)bv->bv_len ) {
+ ber_free( ber, 1 );
+ return( NULL );
+ }
+ }
+
+ /*
+ * reset ber_ptr back to the beginning of buffer so that this new
+ * and initialized ber element can be READ
+ */
+ ber_reset( ber, 1);
+
+ /*
+ * return a ptr to a new BerElement containing a copy of the data
+ * in the bv argument or a null pointer on error
+ */
+ return( ber );
+}
+
+
+/*
+ * memory allocation functions.
+ */
+void *
+nslberi_malloc( size_t size )
+{
+ return( nslberi_memalloc_fns.lbermem_malloc == NULL ?
+ malloc( size ) :
+ nslberi_memalloc_fns.lbermem_malloc( size ));
+}
+
+
+void *
+nslberi_calloc( size_t nelem, size_t elsize )
+{
+ return( nslberi_memalloc_fns.lbermem_calloc == NULL ?
+ calloc( nelem, elsize ) :
+ nslberi_memalloc_fns.lbermem_calloc( nelem, elsize ));
+}
+
+
+void *
+nslberi_realloc( void *ptr, size_t size )
+{
+ return( nslberi_memalloc_fns.lbermem_realloc == NULL ?
+ realloc( ptr, size ) :
+ nslberi_memalloc_fns.lbermem_realloc( ptr, size ));
+}
+
+
+void
+nslberi_free( void *ptr )
+{
+ if ( nslberi_memalloc_fns.lbermem_free == NULL ) {
+ free( ptr );
+ } else {
+ nslberi_memalloc_fns.lbermem_free( ptr );
+ }
+}
+
+
+/*
+ ******************************************************************************
+ * functions to bridge the gap between new extended I/O functions that are
+ * installed using ber_sockbuf_set_option( ..., LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ * ... ).
+ *
+ * the basic strategy is to use the new extended arg to hold a pointer to the
+ * Sockbuf itself so we can find the old functions and call them.
+ * note that the integer socket s passed in is not used. we use the sb_sd
+ * from the Sockbuf itself because it is the correct type.
+ */
+static int
+nslberi_extread_compat( int s, void *buf, int len,
+ struct lextiof_socket_private *arg )
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+
+ return( sb->sb_io_fns.lbiof_read( sb->sb_sd, buf, len ));
+}
+
+
+static int
+nslberi_extwrite_compat( int s, const void *buf, int len,
+ struct lextiof_socket_private *arg )
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+
+ return( sb->sb_io_fns.lbiof_write( sb->sb_sd, buf, len ));
+}
+
+
+/*
+ * Install I/O compatiblity functions. This can't fail.
+ */
+static void
+nslberi_install_compat_io_fns( Sockbuf *sb )
+{
+ sb->sb_ext_io_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ sb->sb_ext_io_fns.lbextiofn_read = nslberi_extread_compat;
+ sb->sb_ext_io_fns.lbextiofn_write = nslberi_extwrite_compat;
+ sb->sb_ext_io_fns.lbextiofn_socket_arg = (void *)sb;
+}
+/*
+ * end of compat I/O functions
+ ******************************************************************************
+ */
diff --git a/usr/src/lib/libldap5/sources/ldap/ber/lber-int.h b/usr/src/lib/libldap5/sources/ldap/ber/lber-int.h
new file mode 100644
index 0000000000..07e59b6a45
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ber/lber-int.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* lbet-int.h - internal header file for liblber */
+
+#ifndef _LBERINT_H
+#define _LBERINT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef LDAP_SASLIO_HOOKS
+#include <sasl/sasl.h>
+#endif
+
+#ifdef macintosh
+# include "ldap-macos.h"
+#else /* macintosh */
+#if !defined(BSDI)
+# include <malloc.h>
+#endif
+# include <errno.h>
+# include <sys/types.h>
+#if defined(SUNOS4) || defined(SCOOS)
+# include <sys/time.h>
+#endif
+#if defined( _WINDOWS )
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <time.h>
+/* No stderr in a 16-bit Windows DLL */
+# if defined(_WINDLL) && !defined(_WIN32)
+# define USE_DBG_WIN
+# endif
+# else
+#if !defined(XP_OS2)
+/* # include <sys/varargs.h> */
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <unistd.h>
+#endif
+# endif /* defined( _WINDOWS ) */
+#endif /* macintosh */
+
+#include <memory.h>
+#include <string.h>
+#include "portable.h"
+
+#ifdef _WINDOWS
+#include <winsock.h>
+#include <io.h>
+#endif /* _WINDOWS */
+
+#ifdef XP_OS2
+#include <os2sock.h>
+#include <io.h>
+#endif /* XP_OS2 */
+
+/* No stderr in a 16-bit Windows DLL */
+#if defined(_WINDLL) && !defined(_WIN32)
+#define stderr NULL
+#endif
+
+#include "lber.h"
+
+#ifdef _SOLARIS_SDK
+#include <libintl.h>
+#include "solaris-int.h"
+#endif
+
+#ifdef macintosh
+#define NSLDAPI_LBER_SOCKET_IS_PTR
+#endif
+
+#define OLD_LBER_SEQUENCE 0x10 /* w/o constructed bit - broken */
+#define OLD_LBER_SET 0x11 /* w/o constructed bit - broken */
+
+#ifndef _IFP
+#define _IFP
+typedef int (LDAP_C LDAP_CALLBACK *IFP)();
+#endif
+
+typedef struct seqorset {
+ ber_len_t sos_clen;
+ ber_tag_t sos_tag;
+ char *sos_first;
+ char *sos_ptr;
+ struct seqorset *sos_next;
+} Seqorset;
+#define NULLSEQORSET ((Seqorset *) 0)
+
+#define SOS_STACK_SIZE 8 /* depth of the pre-allocated sos structure stack */
+
+struct berelement {
+ char *ber_buf;
+ char *ber_ptr;
+ char *ber_end;
+ struct seqorset *ber_sos;
+ ber_tag_t ber_tag;
+ ber_len_t ber_len;
+ int ber_usertag;
+ char ber_options;
+ char *ber_rwptr;
+ BERTranslateProc ber_encode_translate_proc;
+ BERTranslateProc ber_decode_translate_proc;
+ int ber_flags;
+#define LBER_FLAG_NO_FREE_BUFFER 1 /* don't free ber_buf */
+ int ber_sos_stack_posn;
+ Seqorset ber_sos_stack[SOS_STACK_SIZE];
+};
+
+#ifndef _SOLARIS_SDK
+#define NULLBER ((BerElement *)NULL)
+#endif
+
+#ifdef LDAP_DEBUG
+void ber_dump( BerElement *ber, int inout );
+#endif
+
+
+
+/*
+ * structure for read/write I/O callback functions.
+ */
+struct nslberi_io_fns {
+ LDAP_IOF_READ_CALLBACK *lbiof_read;
+ LDAP_IOF_WRITE_CALLBACK *lbiof_write;
+};
+
+
+struct sockbuf {
+ LBER_SOCKET sb_sd;
+ BerElement sb_ber;
+ int sb_naddr; /* > 0 implies using CLDAP (UDP) */
+ void *sb_useaddr; /* pointer to sockaddr to use next */
+ void *sb_fromaddr; /* pointer to message source sockaddr */
+ void **sb_addrs; /* actually an array of pointers to
+ sockaddrs */
+
+ int sb_options; /* to support copying ber elements */
+ LBER_SOCKET sb_copyfd; /* for LBER_SOCKBUF_OPT_TO_FILE* opts */
+ ber_uint_t sb_max_incoming;
+
+ struct nslberi_io_fns
+ sb_io_fns; /* classic I/O callback functions */
+
+ struct lber_x_ext_io_fns
+ sb_ext_io_fns; /* extended I/O callback functions */
+#ifdef LDAP_SASLIO_HOOKS
+ sasl_conn_t *sb_sasl_ctx; /* pointer to sasl context */
+ char *sb_sasl_ibuf; /* sasl decrypted input buffer */
+ char *sb_sasl_iptr; /* current location in buffer */
+ int sb_sasl_bfsz; /* Alloc'd size of input buffer */
+ int sb_sasl_ilen; /* remaining length to process */
+ struct lber_x_ext_io_fns
+ sb_sasl_fns; /* sasl redirect copy ext I/O funcs */
+ void *sb_sasl_prld; /* reverse ld pointer for callbacks */
+#endif
+};
+#define NULLSOCKBUF ((Sockbuf *)NULL)
+
+
+#ifndef NSLBERI_LBER_INT_FRIEND
+/*
+ * Everything from this point on is excluded if NSLBERI_LBER_INT_FRIEND is
+ * defined. The code under ../libraries/libldap defines this.
+ */
+
+#define READBUFSIZ 8192
+
+/*
+ * macros used to check validity of data structures and parameters
+ */
+#define NSLBERI_VALID_BERELEMENT_POINTER( ber ) \
+ ( (ber) != NULLBER )
+
+#define NSLBERI_VALID_SOCKBUF_POINTER( sb ) \
+ ( (sb) != NULLSOCKBUF )
+
+
+#if defined(_WIN32) && defined(_ALPHA)
+#define LBER_HTONL( _l ) \
+ ((((_l)&0xff)<<24) + (((_l)&0xff00)<<8) + \
+ (((_l)&0xff0000)>>8) + (((_l)&0xff000000)>>24))
+#define LBER_NTOHL(_l) LBER_HTONL(_l)
+
+#elif !defined(__alpha) || defined(VMS)
+
+#define LBER_HTONL( l ) htonl( l )
+#define LBER_NTOHL( l ) ntohl( l )
+
+#else /* __alpha */
+/*
+ * htonl and ntohl on the DEC Alpha under OSF 1 seem to only swap the
+ * lower-order 32-bits of a (64-bit) long, so we define correct versions
+ * here.
+ */
+#define LBER_HTONL( l ) (((long)htonl( (l) & 0x00000000FFFFFFFF )) << 32 \
+ | htonl( ( (l) & 0xFFFFFFFF00000000 ) >> 32 ))
+
+#define LBER_NTOHL( l ) (((long)ntohl( (l) & 0x00000000FFFFFFFF )) << 32 \
+ | ntohl( ( (l) & 0xFFFFFFFF00000000 ) >> 32 ))
+#endif /* __alpha */
+
+
+/* function prototypes */
+#ifdef LDAP_DEBUG
+void lber_bprint( char *data, int len );
+#endif
+void ber_err_print( char *data );
+void *nslberi_malloc( size_t size );
+void *nslberi_calloc( size_t nelem, size_t elsize );
+void *nslberi_realloc( void *ptr, size_t size );
+void nslberi_free( void *ptr );
+int nslberi_ber_realloc( BerElement *ber, ber_len_t len );
+
+
+
+/* blame: dboreham
+ * slapd spends much of its time doing memcpy's for the ber code.
+ * Most of these are single-byte, so we special-case those and speed
+ * things up considerably.
+ */
+
+#ifdef sunos4
+#define THEMEMCPY( d, s, n ) bcopy( s, d, n )
+#else /* sunos4 */
+#define THEMEMCPY( d, s, n ) memmove( d, s, n )
+#endif /* sunos4 */
+
+#ifdef SAFEMEMCPY
+#undef SAFEMEMCPY
+#define SAFEMEMCPY(d,s,n) if (1 == n) *((char*)d) = *((char*)s); else THEMEMCPY(d,s,n);
+#endif
+
+/*
+ * 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 NSLBERI_MALLOC( size ) nslberi_malloc( size )
+#define NSLBERI_CALLOC( nelem, elsize ) nslberi_calloc( nelem, elsize )
+#define NSLBERI_REALLOC( ptr, size ) nslberi_realloc( ptr, size )
+#define NSLBERI_FREE( ptr ) nslberi_free( ptr )
+
+/* allow the library to access the debug variable */
+
+extern int lber_debug;
+
+#endif /* !NSLBERI_LBER_INT_FRIEND */
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LBERINT_H */
diff --git a/usr/src/lib/libldap5/sources/ldap/common/abandon.c b/usr/src/lib/libldap5/sources/ldap/common/abandon.c
new file mode 100644
index 0000000000..e695cbd495
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/abandon.c
@@ -0,0 +1,271 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * abandon.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static int do_abandon( LDAP *ld, int origid, int msgid,
+ LDAPControl **serverctrls, LDAPControl **clientctrls );
+
+/*
+ * ldap_abandon - perform an ldap abandon operation. Parameters:
+ *
+ * ld LDAP descriptor
+ * msgid The message id of the operation to abandon
+ *
+ * ldap_abandon returns 0 if everything went ok, -1 otherwise.
+ *
+ * Example:
+ * ldap_abandon( ld, msgid );
+ */
+int
+LDAP_CALL
+ldap_abandon( LDAP *ld, int msgid )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
+
+ if ( ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS ) {
+ return( 0 );
+ }
+
+ return( -1 );
+}
+
+
+/*
+ * LDAPv3 extended abandon.
+ * Returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_abandon_ext( LDAP *ld, int msgid, LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ rc = do_abandon( ld, msgid, msgid, serverctrls, clientctrls );
+
+ /*
+ * XXXmcs should use cache function pointers to hook in memcache
+ */
+ ldap_memcache_abandon( ld, msgid );
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+ return( rc );
+}
+
+
+/*
+ * Abandon all outstanding requests for msgid (included child requests
+ * spawned when chasing referrals). This function calls itself recursively.
+ * No locking is done is this function so it must be done by the caller.
+ * Returns an LDAP error code and sets it in LDAP *ld as well
+ */
+static int
+do_abandon( LDAP *ld, int origid, int msgid, LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
+{
+ BerElement *ber;
+ int i, bererr, lderr, sendabandon;
+ Sockbuf *sb;
+ LDAPRequest *lr = NULL;
+
+ /*
+ * An abandon request looks like this:
+ * AbandonRequest ::= MessageID
+ */
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
+ origid, msgid, 0 );
+
+ /* optimistic */
+ lderr = LDAP_SUCCESS;
+
+/*
+ * this is not the best implementation...
+ * the code special cases the when async io is enabled.
+ * The logic is clear this way, at the cost of code bloat.
+ * This logic should be cleaned up post nova 4.5 rtm
+ */
+ if (ld->ld_options & LDAP_BITOPT_ASYNC)
+ {
+ /* Don't send an abandon message unless there is something to abandon. */
+ sendabandon = 0;
+
+ /* Find the request that we are abandoning. */
+ if (ld->ld_requests != NULL) {
+ for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+ if ( lr->lr_msgid == msgid ) { /* this message */
+ if ( origid == msgid && lr->lr_parent != NULL ) {
+ /* don't let caller abandon child requests! */
+ lderr = LDAP_PARAM_ERROR;
+ goto set_errorcode_and_return;
+ }
+ if ( lr->lr_status == LDAP_REQST_INPROGRESS ) {
+ /* We only need to send an abandon message if the request
+ * is in progress.
+ */
+ sendabandon = 1;
+ }
+ break;
+ }
+ if ( lr->lr_origid == msgid ) { /* child: abandon it */
+ (void)do_abandon( ld, msgid, lr->lr_msgid,
+ serverctrls, clientctrls );
+ /* we ignore errors from child abandons... */
+ }
+ }
+ }
+ }
+ else
+ {
+ sendabandon = 1;
+ /* find the request that we are abandoning */
+ for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+ if ( lr->lr_msgid == msgid ) { /* this message */
+ break;
+ }
+ if ( lr->lr_origid == msgid ) { /* child: abandon it */
+ (void)do_abandon( ld, msgid, lr->lr_msgid,
+ serverctrls, clientctrls );
+ /* we ignore errors from child abandons... */
+ }
+ }
+
+ if ( lr != NULL ) {
+ if ( origid == msgid && lr->lr_parent != NULL ) {
+ /* don't let caller abandon child requests! */
+ lderr = LDAP_PARAM_ERROR;
+ goto set_errorcode_and_return;
+ }
+ if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
+ /* no need to send abandon message */
+ sendabandon = 0;
+ }
+ }
+ }
+ if ( ldap_msgdelete( ld, msgid ) == 0 ) {
+ /* we had all the results and deleted them */
+ goto set_errorcode_and_return;
+ }
+
+ if ( sendabandon ) {
+ /* create a message to send */
+ if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber )) ==
+ LDAP_SUCCESS ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+#ifdef CLDAP
+ if ( ld->ld_dbp->sb_naddr > 0 ) {
+ bererr = ber_printf( ber, "{isti",
+ ++ld->ld_msgid, ld->ld_cldapdn,
+ LDAP_REQ_ABANDON, msgid );
+ } else {
+#endif /* CLDAP */
+ bererr = ber_printf( ber, "{iti",
+ ++ld->ld_msgid, LDAP_REQ_ABANDON, msgid );
+#ifdef CLDAP
+ }
+#endif /* CLDAP */
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ if ( bererr == -1 ||
+ ( lderr = nsldapi_put_controls( ld, serverctrls,
+ 1, ber )) != LDAP_SUCCESS ) {
+ lderr = LDAP_ENCODING_ERROR;
+ ber_free( ber, 1 );
+ } else {
+ /* send the message */
+ if ( lr != NULL ) {
+ sb = lr->lr_conn->lconn_sb;
+ } else {
+ sb = ld->ld_sbp;
+ }
+ if ( nsldapi_ber_flush( ld, sb, ber, 1, 0 )
+ != 0 ) {
+ lderr = LDAP_SERVER_DOWN;
+ }
+ }
+ }
+ }
+
+ if ( lr != NULL ) {
+ if ( sendabandon ) {
+ nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL,
+ 0, 1 );
+ }
+ if ( origid == msgid ) {
+ nsldapi_free_request( ld, lr, 0 );
+ }
+ }
+
+
+ LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
+ if ( ld->ld_abandoned == NULL ) {
+ if ( (ld->ld_abandoned = (int *)NSLDAPI_MALLOC( 2
+ * sizeof(int) )) == NULL ) {
+ lderr = LDAP_NO_MEMORY;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ goto set_errorcode_and_return;
+ }
+ i = 0;
+ } else {
+ for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+ ; /* NULL */
+ if ( (ld->ld_abandoned = (int *)NSLDAPI_REALLOC( (char *)
+ ld->ld_abandoned, (i + 2) * sizeof(int) )) == NULL ) {
+ lderr = LDAP_NO_MEMORY;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ goto set_errorcode_and_return;
+ }
+ }
+ ld->ld_abandoned[i] = msgid;
+ ld->ld_abandoned[i + 1] = -1;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+
+set_errorcode_and_return:
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ return( lderr );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/add.c b/usr/src/lib/libldap5/sources/ldap/common/add.c
new file mode 100644
index 0000000000..ff678f888d
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/add.c
@@ -0,0 +1,212 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * add.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_add - initiate an ldap add operation. Parameters:
+ *
+ * ld LDAP descriptor
+ * dn DN of the entry to add
+ * mods List of attributes for the entry. This is a null-
+ * terminated array of pointers to LDAPMod structures.
+ * only the type and values in the structures need be
+ * filled in.
+ *
+ * Example:
+ * LDAPMod *attrs[] = {
+ * { 0, "cn", { "babs jensen", "babs", 0 } },
+ * { 0, "sn", { "jensen", 0 } },
+ * { 0, "objectClass", { "person", 0 } },
+ * 0
+ * }
+ * msgid = ldap_add( ld, dn, attrs );
+ */
+int
+LDAP_CALL
+ldap_add( LDAP *ld, const char *dn, LDAPMod **attrs )
+{
+ int msgid;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_add\n", 0, 0, 0 );
+
+ if ( ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid )
+ == LDAP_SUCCESS ) {
+ return( msgid );
+ } else {
+ return( -1 ); /* error is in ld handle */
+ }
+}
+
+
+/*
+ * LDAPv3 extended add.
+ * Returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_add_ext( LDAP *ld, const char *dn, LDAPMod **attrs,
+ LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp )
+{
+ BerElement *ber;
+ int i, rc, lderr;
+
+ /*
+ * An add request looks like this:
+ * AddRequest ::= SEQUENCE {
+ * entry DistinguishedName,
+ * attrs SEQUENCE OF SEQUENCE {
+ * type AttributeType,
+ * values SET OF AttributeValue
+ * }
+ * }
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_add_ext\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( msgidp ))
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+ if ( !NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( attrs )
+ || msgidp == NULL ) {
+ lderr = LDAP_PARAM_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ return( lderr );
+ }
+
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ *msgidp = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ /* see if we should add to the cache */
+ if ( ld->ld_cache_on && ld->ld_cache_add != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_add)( ld, *msgidp, LDAP_REQ_ADD, dn,
+ attrs )) != 0 ) {
+ *msgidp = rc;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+
+ /* create a message to send */
+ if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( lderr );
+ }
+
+ if ( ber_printf( ber, "{it{s{", *msgidp, LDAP_REQ_ADD, dn )
+ == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ /* for each attribute in the entry... */
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ if ( ( attrs[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
+ rc = ber_printf( ber, "{s[V]}", attrs[i]->mod_type,
+ attrs[i]->mod_bvalues );
+ } else {
+ rc = ber_printf( ber, "{s[v]}", attrs[i]->mod_type,
+ attrs[i]->mod_values );
+ }
+ if ( rc == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+ }
+
+ if ( ber_printf( ber, "}}" ) == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_ADD,
+ (char *) dn, ber );
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_add_s( LDAP *ld, const char *dn, LDAPMod **attrs )
+{
+ return( ldap_add_ext_s( ld, dn, attrs, NULL, NULL ));
+}
+
+int LDAP_CALL
+ldap_add_ext_s( LDAP *ld, const char *dn, LDAPMod **attrs,
+ LDAPControl **serverctrls, LDAPControl **clientctrls )
+{
+ int err, msgid;
+ LDAPMessage *res;
+
+ if (( err = ldap_add_ext( ld, dn, attrs, serverctrls, clientctrls,
+ &msgid )) != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res ) == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ return( ldap_result2error( ld, res, 1 ) );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/bind.c b/usr/src/lib/libldap5/sources/ldap/common/bind.c
new file mode 100644
index 0000000000..d28168a448
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/bind.c
@@ -0,0 +1,157 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * bind.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_bind - bind to the ldap server. The dn and password
+ * of the entry to which to bind are supplied, along with the authentication
+ * method to use. The msgid of the bind request is returned on success,
+ * -1 if there's trouble. Note, the kerberos support assumes the user already
+ * has a valid tgt for now. ldap_result() should be called to find out the
+ * outcome of the bind request.
+ *
+ * Example:
+ * ldap_bind( ld, "cn=manager, o=university of michigan, c=us", "secret",
+ * LDAP_AUTH_SIMPLE )
+ */
+
+int
+LDAP_CALL
+ldap_bind( LDAP *ld, const char *dn, const char *passwd, int authmethod )
+{
+ /*
+ * The bind request looks like this:
+ * BindRequest ::= SEQUENCE {
+ * version INTEGER,
+ * name DistinguishedName, -- who
+ * authentication CHOICE {
+ * simple [0] OCTET STRING -- passwd
+ * }
+ * }
+ * all wrapped up in an LDAPMessage sequence.
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_bind\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 );
+ }
+
+ switch ( authmethod ) {
+ case LDAP_AUTH_SIMPLE:
+ return( ldap_simple_bind( ld, dn, passwd ) );
+
+ default:
+ LDAP_SET_LDERRNO( ld, LDAP_AUTH_UNKNOWN, NULL, NULL );
+ return( -1 );
+ }
+}
+
+/*
+ * ldap_bind_s - bind to the ldap server. The dn and password
+ * of the entry to which to bind are supplied, along with the authentication
+ * method to use. This routine just calls whichever bind routine is
+ * appropriate and returns the result of the bind (e.g. LDAP_SUCCESS or
+ * some other error indication). Note, the kerberos support assumes the
+ * user already has a valid tgt for now.
+ *
+ * Examples:
+ * ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ * "secret", LDAP_AUTH_SIMPLE )
+ * ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ * NULL, LDAP_AUTH_KRBV4 )
+ */
+int
+LDAP_CALL
+ldap_bind_s( LDAP *ld, const char *dn, const char *passwd, int authmethod )
+{
+ int err;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_bind_s\n", 0, 0, 0 );
+
+ switch ( authmethod ) {
+ case LDAP_AUTH_SIMPLE:
+ return( ldap_simple_bind_s( ld, dn, passwd ) );
+
+ default:
+ err = LDAP_AUTH_UNKNOWN;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+}
+
+
+void
+LDAP_CALL
+ldap_set_rebind_proc( LDAP *ld, LDAP_REBINDPROC_CALLBACK *rebindproc,
+ void *arg )
+{
+ if ( ld == NULL ) {
+ if ( !nsldapi_initialized ) {
+ nsldapi_initialize_defaults();
+ }
+ ld = &nsldapi_ld_defaults;
+ }
+
+ if ( NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+ ld->ld_rebind_fn = rebindproc;
+ ld->ld_rebind_arg = arg;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+ }
+}
+
+
+/*
+ * return a pointer to the bind DN for the default connection (a copy is
+ * not made). If there is no bind DN available, NULL is returned.
+ */
+char *
+nsldapi_get_binddn( LDAP *ld )
+{
+ char *binddn;
+
+ binddn = NULL; /* default -- assume they are not bound */
+
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ if ( NULL != ld->ld_defconn && LDAP_CONNST_CONNECTED ==
+ ld->ld_defconn->lconn_status && ld->ld_defconn->lconn_bound ) {
+ if (( binddn = ld->ld_defconn->lconn_binddn ) == NULL ) {
+ binddn = "";
+ }
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+ return( binddn );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/cache.c b/usr/src/lib/libldap5/sources/ldap/common/cache.c
new file mode 100644
index 0000000000..51e749f7a2
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/cache.c
@@ -0,0 +1,164 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1993 The Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * cache.c - generic caching support for LDAP
+ */
+
+#include "ldap-int.h"
+
+/*
+ * ldap_cache_flush - flush part of the LDAP cache. returns an
+ * ldap error code (LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT, etc.).
+ */
+
+int
+LDAP_CALL
+ldap_cache_flush( LDAP *ld, const char *dn, const char *filter )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+ return( (ld->ld_cache_flush)( ld, dn, filter ) );
+}
+
+/*
+ * nsldapi_add_result_to_cache - add an ldap entry we just read off the network
+ * to the ldap cache. this routine parses the ber for the entry and
+ * constructs the appropriate add request. this routine calls the
+ * cache add routine to actually add the entry.
+ */
+
+void
+nsldapi_add_result_to_cache( LDAP *ld, LDAPMessage *m )
+{
+ char *dn;
+ LDAPMod **mods;
+ int i, max, rc;
+ char *a;
+ BerElement *ber;
+ char buf[50];
+ struct berval bv;
+ struct berval *bvp[2];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_add_result_to_cache id %d type %d\n",
+ m->lm_msgid, m->lm_msgtype, 0 );
+ if ( m->lm_msgtype != LDAP_RES_SEARCH_ENTRY ||
+ ld->ld_cache_add == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache not added\n", 0, 0, 0 );
+ return;
+ }
+
+#define GRABSIZE 5
+
+ dn = ldap_get_dn( ld, m );
+ mods = (LDAPMod **)NSLDAPI_MALLOC( GRABSIZE * sizeof(LDAPMod *) );
+ if (mods == NULL) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache malloc failed\n", 0, 0, 0 );
+ return;
+ }
+ max = GRABSIZE;
+ for ( i = 0, a = ldap_first_attribute( ld, m, &ber ); a != NULL;
+ a = ldap_next_attribute( ld, m, ber ), i++ ) {
+ if ( i == (max - 1) ) {
+ max += GRABSIZE;
+ mods = (LDAPMod **)NSLDAPI_REALLOC( mods,
+ sizeof(LDAPMod *) * max );
+ if (mods == NULL) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache realloc failed\n",
+ 0, 0, 0 );
+ return;
+ }
+ }
+
+ mods[i] = (LDAPMod *)NSLDAPI_CALLOC( 1, sizeof(LDAPMod) );
+ if (mods[i] == NULL) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache calloc failed\n",
+ 0, 0, 0 );
+ ldap_mods_free( mods, 1 );
+ return;
+ }
+ mods[i]->mod_op = LDAP_MOD_BVALUES;
+ mods[i]->mod_type = a;
+ mods[i]->mod_bvalues = ldap_get_values_len( ld, m, a );
+ }
+ if ( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ if (( rc = LDAP_GET_LDERRNO( ld, NULL, NULL )) != LDAP_SUCCESS ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache error: failed to construct mod list (%s)\n",
+ ldap_err2string( rc ), 0, 0 );
+ ldap_mods_free( mods, 1 );
+ return;
+ }
+
+ /* update special cachedtime attribute */
+ if ( i == (max - 1) ) {
+ max++;
+ mods = (LDAPMod **)NSLDAPI_REALLOC( mods,
+ sizeof(LDAPMod *) * max );
+ if (mods == NULL) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache calloc failed\n",
+ 0, 0, 0 );
+ ldap_mods_free( mods, 1 );
+ return;
+ }
+ }
+ mods[i] = (LDAPMod *)NSLDAPI_CALLOC( 1, sizeof(LDAPMod) );
+ if (mods[i] == NULL) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache calloc failed\n",
+ 0, 0, 0 );
+ ldap_mods_free( mods, 1 );
+ return;
+ }
+ mods[i]->mod_op = LDAP_MOD_BVALUES;
+ mods[i]->mod_type = "cachedtime";
+ sprintf( buf, "%d", time( NULL ) );
+ bv.bv_val = buf;
+ bv.bv_len = strlen( buf );
+ bvp[0] = &bv;
+ bvp[1] = NULL;
+ mods[i]->mod_bvalues = bvp;
+ mods[++i] = NULL;
+
+ /* msgid of -1 means don't send the result */
+ rc = (ld->ld_cache_add)( ld, -1, m->lm_msgtype, dn, mods );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_add_result_to_cache added (rc %d)\n", rc, 0, 0 );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/charray.c b/usr/src/lib/libldap5/sources/ldap/common/charray.c
new file mode 100644
index 0000000000..f1ecdceb58
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/charray.c
@@ -0,0 +1,232 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/* charray.c - routines for dealing with char * arrays */
+
+
+#include "ldap-int.h"
+
+/*
+ * Add s at the end of the array of strings *a.
+ * Return 0 for success, -1 for failure.
+ */
+int
+LDAP_CALL
+ldap_charray_add(
+ char ***a,
+ char *s
+)
+{
+ int n;
+
+ if ( *a == NULL ) {
+ *a = (char **)NSLDAPI_MALLOC( 2 * sizeof(char *) );
+ if ( *a == NULL ) {
+ return -1;
+ }
+ n = 0;
+ } else {
+ for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+ ; /* NULL */
+ }
+
+ *a = (char **)NSLDAPI_REALLOC( (char *) *a,
+ (n + 2) * sizeof(char *) );
+ if ( *a == NULL ) {
+ return -1;
+ }
+ }
+
+ (*a)[n++] = s;
+ (*a)[n] = NULL;
+ return 0;
+}
+
+/*
+ * Add array of strings s at the end of the array of strings *a.
+ * Return 0 for success, -1 for failure.
+ */
+int
+LDAP_CALL
+ldap_charray_merge(
+ char ***a,
+ char **s
+)
+{
+ int i, n, nn;
+
+ if ( (s == NULL) || (s[0] == NULL) )
+ return 0;
+
+ for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+ ; /* NULL */
+ }
+ for ( nn = 0; s[nn] != NULL; nn++ ) {
+ ; /* NULL */
+ }
+
+ *a = (char **)NSLDAPI_REALLOC( (char *) *a,
+ (n + nn + 1) * sizeof(char *) );
+ if ( *a == NULL ) {
+ return -1;
+ }
+
+ for ( i = 0; i < nn; i++ ) {
+ (*a)[n + i] = s[i];
+ }
+ (*a)[n + nn] = NULL;
+ return 0;
+}
+
+void
+LDAP_CALL
+ldap_charray_free( char **array )
+{
+ char **a;
+
+ if ( array == NULL ) {
+ return;
+ }
+
+ for ( a = array; *a != NULL; a++ ) {
+ if ( *a != NULL ) {
+ NSLDAPI_FREE( *a );
+ }
+ }
+ NSLDAPI_FREE( (char *) array );
+}
+
+int
+LDAP_CALL
+ldap_charray_inlist(
+ char **a,
+ char *s
+)
+{
+ int i;
+
+ if ( a == NULL )
+ return( 0 );
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ if ( strcasecmp( s, a[i] ) == 0 ) {
+ return( 1 );
+ }
+ }
+
+ return( 0 );
+}
+
+/*
+ * Duplicate the array of strings a, return NULL upon any memory failure.
+ */
+char **
+LDAP_CALL
+ldap_charray_dup( char **a )
+{
+ int i;
+ char **new;
+
+ for ( i = 0; a[i] != NULL; i++ )
+ ; /* NULL */
+
+ new = (char **)NSLDAPI_MALLOC( (i + 1) * sizeof(char *) );
+ if ( new == NULL ) {
+ return NULL;
+ }
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ new[i] = nsldapi_strdup( a[i] );
+ if ( new[i] == NULL ) {
+ int j;
+
+ for ( j = 0; j < i; j++ )
+ NSLDAPI_FREE( new[j] );
+ NSLDAPI_FREE( new );
+ return NULL;
+ }
+ }
+ new[i] = NULL;
+
+ return( new );
+}
+
+/*
+ * Tokenize the string str, return NULL upon any memory failure.
+ * XXX: on many platforms this function is not thread safe because it
+ * uses strtok().
+ */
+char **
+LDAP_CALL
+ldap_str2charray( char *str, char *brkstr )
+ /* This implementation fails if brkstr contains multibyte characters.
+ But it works OK if str is UTF-8 and brkstr is 7-bit ASCII.
+ */
+{
+ char **res;
+ char *s;
+ int i;
+
+ i = 1;
+ for ( s = str; *s; s++ ) {
+ if ( strchr( brkstr, *s ) != NULL ) {
+ i++;
+ }
+ }
+
+ res = (char **)NSLDAPI_MALLOC( (i + 1) * sizeof(char *) );
+ if ( res == NULL ) {
+ return NULL;
+ }
+ i = 0;
+ for ( s = strtok( str, brkstr ); s != NULL; s = strtok( NULL,
+ brkstr ) ) {
+ res[i++] = nsldapi_strdup( s );
+ if ( res[i - 1] == NULL ) {
+ int j;
+
+ for ( j = 0; j < (i - 1); j++ )
+ NSLDAPI_FREE( res[j] );
+ NSLDAPI_FREE( res );
+ return NULL;
+ }
+ }
+ res[i] = NULL;
+
+ return( res );
+}
+
+int
+LDAP_CALL
+ldap_charray_position( char **a, char *s )
+{
+ int i;
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ if ( strcasecmp( s, a[i] ) == 0 ) {
+ return( i );
+ }
+ }
+
+ return( -1 );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/charset.c b/usr/src/lib/libldap5/sources/ldap/common/charset.c
new file mode 100644
index 0000000000..06674cdb47
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/charset.c
@@ -0,0 +1,1841 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * charset.c
+ */
+
+#include "ldap-int.h"
+
+#ifdef STR_TRANSLATION
+
+void
+ldap_set_string_translators( LDAP *ld, BERTranslateProc encode_proc,
+ BERTranslateProc decode_proc )
+{
+ if ( ld == NULL ) {
+ if ( !nsldapi_initialized ) {
+ nsldapi_initialize_defaults();
+ }
+ ld = &nsldapi_ld_defaults;
+ }
+
+ if ( NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ ld->ld_lber_encode_translate_proc = encode_proc;
+ ld->ld_lber_decode_translate_proc = decode_proc;
+ }
+}
+
+
+void
+ldap_enable_translation( LDAP *ld, LDAPMessage *entry, int enable )
+{
+ char *optionsp;
+
+ if ( ld == NULL ) {
+ if ( !nsldapi_initialized ) {
+ nsldapi_initialize_defaults();
+ }
+ ld = &nsldapi_ld_defaults;
+ }
+
+ optionsp = ( entry == NULLMSG ) ? &ld->ld_lberoptions :
+ &entry->lm_ber->ber_options;
+
+ if ( enable ) {
+ *optionsp |= LBER_OPT_TRANSLATE_STRINGS;
+ } else {
+ *optionsp &= ~LBER_OPT_TRANSLATE_STRINGS;
+ }
+}
+
+
+int
+ldap_translate_from_t61( LDAP *ld, char **bufp, unsigned long *lenp,
+ int free_input )
+{
+ ber_len_t length = (ber_len_t)*lenp;
+
+ if ( ld->ld_lber_decode_translate_proc == NULL ) {
+ return( LDAP_SUCCESS );
+ }
+
+ return( (*ld->ld_lber_decode_translate_proc)( bufp, &length, free_input ));
+}
+
+
+int
+ldap_translate_to_t61( LDAP *ld, char **bufp, unsigned long *lenp,
+ int free_input )
+{
+ ber_len_t length = (ber_len_t)*lenp;
+
+ if ( ld->ld_lber_encode_translate_proc == NULL ) {
+ return( LDAP_SUCCESS );
+ }
+
+ return( (*ld->ld_lber_encode_translate_proc)( bufp, &length, free_input ));
+}
+
+
+/*
+ ** Character translation routine notes:
+ *
+ * On entry: bufp points to a "string" to be converted (not necessarily
+ * zero-terminated) and buflenp points to the length of the buffer.
+ *
+ * On exit: bufp should point to a malloc'd result. If free_input is
+ * non-zero then the original bufp will be freed. *buflenp should be
+ * set to the new length. Zero bytes in the input buffer must be left
+ * as zero bytes.
+ *
+ * Return values: any ldap error code (LDAP_SUCCESS if all goes well).
+ */
+
+
+#ifdef LDAP_CHARSET_8859
+
+#if LDAP_CHARSET_8859 == 88591
+#define ISO_8859 1
+#elif LDAP_CHARSET_8859 == 88592
+#define ISO_8859 2
+#elif LDAP_CHARSET_8859 == 88593
+#define ISO_8859 3
+#elif LDAP_CHARSET_8859 == 88594
+#define ISO_8859 4
+#elif LDAP_CHARSET_8859 == 88595
+#define ISO_8859 5
+#elif LDAP_CHARSET_8859 == 88596
+#define ISO_8859 6
+#elif LDAP_CHARSET_8859 == 88597
+#define ISO_8859 7
+#elif LDAP_CHARSET_8859 == 88598
+#define ISO_8859 8
+#elif LDAP_CHARSET_8859 == 88599
+#define ISO_8859 9
+#elif LDAP_CHARSET_8859 == 885910
+#define ISO_8859 10
+#else
+#define ISO_8859 0
+#endif
+
+/*
+ * the following ISO_8859 to/afrom T.61 character set translation code is
+ * based on the code found in Enrique Silvestre Mora's iso-t61.c, found
+ * as part of this package:
+ * ftp://pereiii.uji.es/pub/uji-ftp/unix/ldap/iso-t61.translation.tar.Z
+ * Enrique is now (10/95) at this address: enrique.silvestre@uv.es
+ *
+ * changes made by mcs@umich.edu 12 October 1995:
+ * Change calling conventions of iso8859_t61() and t61_iso8859() to
+ * match libldap conventions; rename to ldap_8859_to_t61() and
+ * ldap_t61_to_8859().
+ * Change conversion routines to deal with non-zero terminated strings.
+ * ANSI-ize functions and include prototypes.
+ */
+
+/* iso-t61.c - ISO-T61 translation routines (version: 0.2.1, July-1994) */
+/*
+ * Copyright (c) 1994 Enrique Silvestre Mora, Universitat Jaume I, Spain.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the Universitat Jaume I. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Character set used: ISO 8859-1, ISO 8859-2, ISO 8859-3, ... */
+/* #define ISO_8859 1 */
+
+#ifndef ISO_8859
+# define ISO_8859 0
+#endif
+
+typedef unsigned char Byte;
+typedef struct { Byte a, b; } Couple;
+
+#ifdef NEEDPROTOS
+static Byte *c_to_hh( Byte *o, Byte c );
+static Byte *c_to_cc( Byte *o, Couple *cc, Byte c );
+static int hh_to_c( Byte *h );
+static Byte *cc_to_t61( Byte *o, Byte *s );
+#else /* NEEDPROTOS */
+static Byte *c_to_hh();
+static Byte *c_to_cc();
+static int hh_to_c();
+static Byte *cc_to_t61();
+#endif /* NEEDPROTOS */
+
+/*
+ Character choosed as base in diacritics alone: NO-BREAK SPACE.
+ (The standard say it must be a blank space, 0x20.)
+*/
+#define ALONE 0xA0
+
+static Couple diacritic[16] = {
+#if (ISO_8859 == 1) || (ISO_8859 == 9)
+ {0,0}, {'`',0}, {0xb4,0}, {'^',0},
+ {'~',0}, {0xaf,0}, {'(',ALONE}, {'.',ALONE},
+ {0xa8,0}, {0,0}, {'0',ALONE}, {0xb8,0},
+ {0,0}, {'"',ALONE}, {';',ALONE}, {'<',ALONE},
+#elif (ISO_8859 == 2)
+ {0,0}, {'`',0}, {0xb4,0}, {'^',0},
+ {'~',0}, {'-',ALONE}, {0xa2,0}, {0xff,0},
+ {0xa8,0}, {0,0}, {'0',ALONE}, {0xb8,0},
+ {0,0}, {0xbd,0}, {0xb2,0}, {0xb7,0}
+#elif (ISO_8859 == 3)
+ {0,0}, {'`',0}, {0xb4,0}, {'^',0},
+ {'~',0}, {'-',ALONE}, {0xa2,0}, {0xff,0},
+ {0xa8,0}, {0,0}, {'0',ALONE}, {0xb8,0},
+ {0,0}, {'"',ALONE}, {';',ALONE}, {'<',ALONE}
+#elif (ISO_8859 == 4)
+ {0,0}, {'`',0}, {0xb4,0}, {'^',0},
+ {'~',0}, {0xaf,0}, {'(',ALONE}, {0xff,0},
+ {0xa8,0}, {0,0}, {'0',ALONE}, {0xb8,0},
+ {0,0}, {'"',ALONE}, {0xb2,0}, {0xb7,0}
+#else
+ {0,0}, {'`',0}, {'\'',ALONE}, {'^',0},
+ {'~',0}, {'-',ALONE}, {'(',ALONE}, {'.',ALONE},
+ {':',ALONE}, {0,0}, {'0',ALONE}, {',',ALONE},
+ {0,0}, {'"',ALONE}, {';',ALONE}, {'<',ALONE}
+#endif
+};
+
+/*
+ --- T.61 (T.51) letters with diacritics: conversion to ISO 8859-n -----
+ A, C, D, E, G, H, I, J, K,
+ L, N, O, R, S, T, U, W, Y, Z.
+ -----------------------------------------------------------------------
+*/
+static int letter_w_diacritic[16][38] = {
+#if (ISO_8859 == 1)
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xc0,0, 0, 0xc8,0, 0, 0xcc,0, 0,
+ 0, 0, 0xd2,0, 0, 0, 0xd9,0, 0, 0,
+ 0xe0,0, 0, 0xe8,0, 0, 0xec,0, 0,
+ 0, 0, 0xf2,0, 0, 0, 0xf9,0, 0, 0,
+ 0xc1,-1, 0, 0xc9,0, 0, 0xcd,0, 0,
+ -1, -1, 0xd3,-1, -1, 0, 0xda,0, 0xdd,-1,
+ 0xe1,-1, 0, 0xe9,0, 0, 0xed,0, 0,
+ -1, -1, 0xf3,-1, -1, 0, 0xfa,0, 0xfd,-1,
+ 0xc2,-1, 0, 0xca,-1, -1, 0xce,-1, 0,
+ 0, 0, 0xd4,0, -1, 0, 0xdb,-1, -1, 0,
+ 0xe2,-1, 0, 0xea,-1, -1, 0xee,-1, 0,
+ 0, 0, 0xf4,0, -1, 0, 0xfb,-1, -1, 0,
+ 0xc3,0, 0, 0, 0, 0, -1, 0, 0,
+ 0, 0xd1,0xd5,0, 0, 0, -1, 0, 0, 0,
+ 0xe3,0, 0, 0, 0, 0, -1, 0, 0,
+ 0, 0xf1,0xf5,0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, -1, -1, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0, -1, 0, -1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0xc4,0, 0, 0xcb,0, 0, 0xcf,0, 0,
+ 0, 0, 0xd6,0, 0, 0, 0xdc,0, -1, 0,
+ 0xe4,0, 0, 0xeb,0, 0, 0xef,0, 0,
+ 0, 0, 0xf6,0, 0, 0, 0xfc,0, 0xff,0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xc5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0xe5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0xc7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, 0,
+ 0, 0xe7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1
+#elif (ISO_8859 == 2)
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0xc1,0xc6,0, 0xc9,0, 0, 0xcd,0, 0,
+ 0xc5,0xd1,0xd3,0xc0,0xa6,0, 0xda,0, 0xdd,0xac,
+ 0xe1,0xe6,0, 0xe9,0, 0, 0xed,0, 0,
+ 0xe5,0xf1,0xf3,0xe0,0xb6,0, 0xfa,0, 0xfd,0xbc,
+ 0xc2,-1, 0, -1, -1, -1, 0xce,-1, 0,
+ 0, 0, 0xd4,0, -1, 0, -1, -1, -1, 0,
+ 0xe2,-1, 0, -1, -1, -1, 0xee,-1, 0,
+ 0, 0, 0xf4,0, -1, 0, -1, -1, -1, 0,
+ -1, 0, 0, 0, 0, 0, -1, 0, 0,
+ 0, -1, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, -1, 0, 0,
+ 0, -1, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0xc3,0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0xe3,0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, -1, -1, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xaf,
+ 0, -1, 0, -1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xbf,
+ 0xc4,0, 0, 0xcb,0, 0, -1, 0, 0,
+ 0, 0, 0xd6,0, 0, 0, 0xdc,0, -1, 0,
+ 0xe4,0, 0, 0xeb,0, 0, -1, 0, 0,
+ 0, 0, 0xf6,0, 0, 0, 0xfc,0, -1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xd9,0, 0, 0,
+ -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xf9,0, 0, 0,
+ 0, 0xc7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, 0xaa,0xde,0, 0, 0, 0,
+ 0, 0xe7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, 0xba,0xfe,0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xd5,0, 0, 0, 0xdb,0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xf5,0, 0, 0, 0xfb,0, 0, 0,
+ 0xa1,0, 0, 0xca,0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0xb1,0, 0, 0xea,0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0xc8,0xcf,0xcc,0, 0, 0, 0, 0,
+ 0xa5,0xd2,0, 0xd8,0xa9,0xab,0, 0, 0, 0xae,
+ 0, 0xe8,0xef,0xec,0, 0, 0, 0, 0,
+ 0xb5,0xf2,0, 0xf8,0xb9,0xbb,0, 0, 0, 0xbe
+#elif (ISO_8859 == 3)
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xc0,0, 0, 0xc8,0, 0, 0xcc,0, 0,
+ 0, 0, 0xd2,0, 0, 0, 0xd9,0, 0, 0,
+ 0xe0,0, 0, 0xe8,0, 0, 0xec,0, 0,
+ 0, 0, 0xf2,0, 0, 0, 0xf9,0, 0, 0,
+ 0xc1,-1, 0, 0xc9,0, 0, 0xcd,0, 0,
+ -1, -1, 0xd3,-1, -1, 0, 0xda,0, -1, -1,
+ 0xe1,-1, 0, 0xe9,0, 0, 0xed,0, 0,
+ -1, -1, 0xf3,-1, -1, 0, 0xfa,0, -1, -1,
+ 0xc2,0xc6,0, 0xca,0xd8,0xa6,0xce,0xac,0,
+ 0, 0, 0xd4,0, 0xde,0, 0xdb,-1, -1, 0,
+ 0xe2,0xe6,0, 0xea,0xf8,0xb6,0xee,0xbc,0,
+ 0, 0, 0xf4,0, 0xfe,0, 0xfb,-1, -1, 0,
+ -1, 0, 0, 0, 0, 0, -1, 0, 0,
+ 0, 0xd1,-1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, -1, 0, 0,
+ 0, 0xf1,-1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0xab,0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xdd,0, 0, 0,
+ -1, 0, 0, 0, 0xbb,0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xfd,0, 0, 0,
+ 0, 0xc5,0, -1, 0xd5,0, 0xa9,0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xaf,
+ 0, 0xe5,0, -1, 0xf5,0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xbf,
+ 0xc4,0, 0, 0xcb,0, 0, 0xcf,0, 0,
+ 0, 0, 0xd6,0, 0, 0, 0xdc,0, -1, 0,
+ 0xe4,0, 0, 0xeb,0, 0, 0xef,0, 0,
+ 0, 0, 0xf6,0, 0, 0, 0xfc,0, -1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0xc7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, 0xaa,-1, 0, 0, 0, 0,
+ 0, 0xe7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, 0xba,-1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1
+#elif (ISO_8859 == 4)
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0xc1,-1, 0, 0xc9,0, 0, 0xcd,0, 0,
+ -1, -1, -1, -1, -1, 0, 0xda,0, -1, -1,
+ 0xe1,-1, 0, 0xe9,0, 0, 0xed,0, 0,
+ -1, -1, -1, -1, -1, 0, 0xfa,0, -1, -1,
+ 0xc2,-1, 0, -1, -1, -1, 0xce,-1, 0,
+ 0, 0, 0xd4,0, -1, 0, 0xdb,-1, -1, 0,
+ 0xe2,-1, 0, -1, -1, -1, 0xee,-1, 0,
+ 0, 0, 0xf4,0, -1, 0, 0xfb,-1, -1, 0,
+ 0xc3,0, 0, 0, 0, 0, 0xa5,0, 0,
+ 0, -1, 0xd5,0, 0, 0, 0xdd,0, 0, 0,
+ 0xe3,0, 0, 0, 0, 0, 0xb5,0, 0,
+ 0, -1, 0xf5,0, 0, 0, 0xfd,0, 0, 0,
+ 0xc0,0, 0, 0xaa,0, 0, 0xcf,0, 0,
+ 0, 0, 0xd2,0, 0, 0, 0xde,0, 0, 0,
+ 0xe0,0, 0, 0xba,0, 0, 0xef,0, 0,
+ 0, 0, 0xf2,0, 0, 0, 0xfe,0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, 0xcc,-1, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0, -1, 0, 0xec,-1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0xc4,0, 0, 0xcb,0, 0, -1, 0, 0,
+ 0, 0, 0xd6,0, 0, 0, 0xdc,0, -1, 0,
+ 0xe4,0, 0, 0xeb,0, 0, -1, 0, 0,
+ 0, 0, 0xf6,0, 0, 0, 0xfc,0, -1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xc5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0xe5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, 0, 0xab,0, 0, 0, 0xd3,
+ 0xa6,0xd1,0, 0xa3,-1, -1, 0, 0, 0, 0,
+ 0, -1, 0, 0, 0xbb,0, 0, 0, 0xf3,
+ 0xb6,0xf1,0, 0xb3,-1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0xa1,0, 0, 0xca,0, 0, 0xc7,0, 0,
+ 0, 0, 0, 0, 0, 0, 0xd9,0, 0, 0,
+ 0xb1,0, 0, 0xea,0, 0, 0xe7,0, 0,
+ 0, 0, 0, 0, 0, 0, 0xf9,0, 0, 0,
+ 0, 0xc8,-1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, 0xa9,-1, 0, 0, 0, 0xae,
+ 0, 0xe8,-1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, 0xb9,-1, 0, 0, 0, 0xbe
+#elif (ISO_8859 == 9)
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xc0,0, 0, 0xc8,0, 0, 0xcc,0, 0,
+ 0, 0, 0xd2,0, 0, 0, 0xd9,0, 0, 0,
+ 0xe0,0, 0, 0xe8,0, 0, -1, 0, 0,
+ 0, 0, 0xf2,0, 0, 0, 0xf9,0, 0, 0,
+ 0xc1,-1, 0, 0xc9,0, 0, 0xcd,0, 0,
+ -1, -1, 0xd3,-1, -1, 0, 0xda,0, -1, -1,
+ 0xe1,-1, 0, 0xe9,0, 0, 0xed,0, 0,
+ -1, -1, 0xf3,-1, -1, 0, 0xfa,0, -1, -1,
+ 0xc2,-1, 0, 0xca,-1, -1, 0xce,-1, 0,
+ 0, 0, 0xd4,0, -1, 0, 0xdb,-1, -1, 0,
+ 0xe2,-1, 0, -1, -1, -1, 0xee,-1, 0,
+ 0, 0, 0xf4,0, -1, 0, 0xfb,-1, -1, 0,
+ 0xc3,0, 0, 0, 0, 0, -1, 0, 0,
+ 0, 0xd1,0xd5,0, 0, 0, -1, 0, 0, 0,
+ 0xe3,0, 0, 0, 0, 0, -1, 0, 0,
+ 0, 0xf1,0xf5,0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, 0xef,0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0xd0,0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0xf0,0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, -1, -1, 0, 0xdd,0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0, -1, 0, 0xec,-1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0xc4,0, 0, 0xcb,0, 0, 0xcf,0, 0,
+ 0, 0, 0xd6,0, 0, 0, 0xdc,0, -1, 0,
+ 0xe4,0, 0, 0xeb,0, 0, -1, 0, 0,
+ 0, 0, 0xf6,0, 0, 0, 0xfc,0, 0xff,0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xc5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0xe5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0xc7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, 0xde,-1, 0, 0, 0, 0,
+ 0, 0xe7,0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, 0xfe,-1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0xea,0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1
+#elif (ISO_8859 == 10)
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0xc1,-1, 0, 0xc9,0, 0, 0xcd,0, 0,
+ -1, -1, 0xd3,-1, -1, 0, 0xda,0, 0xdd,-1,
+ 0xe1,-1, 0, 0xe9,0, 0, 0xed,0, 0,
+ -1, -1, 0xf3,-1, -1, 0, 0xfa,0, 0xfd,-1,
+ 0xc2,-1, 0, -1, -1, -1, 0xce,-1, 0,
+ 0, 0, 0xd4,0, -1, 0, 0xdb,-1, -1, 0,
+ 0xe2,-1, 0, -1, -1, -1, 0xee,-1, 0,
+ 0, 0, 0xf4,0, -1, 0, 0xfb,-1, -1, 0,
+ 0xc3,0, 0, 0, 0, 0, 0xa5,0, 0,
+ 0, -1, 0xd5,0, 0, 0, 0xd7,0, 0, 0,
+ 0xe3,0, 0, 0, 0, 0, 0xb5,0, 0,
+ 0, -1, 0xf5,0, 0, 0, 0xf7,0, 0, 0,
+ 0xc0,0, 0, 0xa2,0, 0, 0xa4,0, 0,
+ 0, 0, 0xd2,0, 0, 0, 0xae,0, 0, 0,
+ 0xe0,0, 0, 0xb2,0, 0, 0xb4,0, 0,
+ 0, 0, 0xf2,0, 0, 0, 0xbe,0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, 0xcc,-1, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0, -1, 0, 0xec,-1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0xc4,0, 0, 0xcb,0, 0, 0xcf,0, 0,
+ 0, 0, 0xd6,0, 0, 0, 0xdc,0, -1, 0,
+ 0xe4,0, 0, 0xeb,0, 0, 0xef,0, 0,
+ 0, 0, 0xf6,0, 0, 0, 0xfc,0, -1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xc5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0xe5,0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, 0, 0xa3,0, 0, 0, 0xa6,
+ 0xa8,0xd1,0, -1, -1, -1, 0, 0, 0, 0,
+ 0, -1, 0, 0, 0xb3,0, 0, 0, 0xb6,
+ 0xb8,0xf1,0, -1, -1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0xa1,0, 0, 0xca,0, 0, 0xc7,0, 0,
+ 0, 0, 0, 0, 0, 0, 0xd9,0, 0, 0,
+ 0xb1,0, 0, 0xea,0, 0, 0xe7,0, 0,
+ 0, 0, 0, 0, 0, 0, 0xf9,0, 0, 0,
+ 0, 0xc8,-1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, 0xaa,-1, 0, 0, 0, 0xac,
+ 0, 0xe8,-1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, 0xba,-1, 0, 0, 0, 0xbc
+#else
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, -1, 0, -1, 0, 0, -1, 0, 0,
+ -1, -1, -1, -1, -1, 0, -1, 0, -1, -1,
+ -1, -1, 0, -1, 0, 0, -1, 0, 0,
+ -1, -1, -1, -1, -1, 0, -1, 0, -1, -1,
+ -1, -1, 0, -1, -1, -1, -1, -1, 0,
+ 0, 0, -1, 0, -1, 0, -1, -1, -1, 0,
+ -1, -1, 0, -1, -1, -1, -1, -1, 0,
+ 0, 0, -1, 0, -1, 0, -1, -1, -1, 0,
+ -1, 0, 0, 0, 0, 0, -1, 0, 0,
+ 0, -1, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, -1, 0, 0,
+ 0, -1, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, -1, -1, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ 0, -1, 0, -1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, -1, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, -1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, 0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, 0,
+ 0, -1, 0, 0, -1, 0, 0, 0, -1,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ -1, 0, 0, -1, 0, 0, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1,
+ 0, -1, -1, -1, 0, 0, 0, 0, 0,
+ -1, -1, 0, -1, -1, -1, 0, 0, 0, -1
+#endif
+};
+
+/*
+--- T.61 characters [0xA0 .. 0xBF] -----------------
+*/
+static Couple trans_t61a_iso8859[32] = {
+#if (ISO_8859 == 1) || (ISO_8859 == 9)
+ {'N','S'}, {0xa1,0}, {0xa2,0}, {0xa3,0},
+ {'D','O'}, {0xa5,0}, {'C','u'}, {0xa7,0},
+ {0xa4,0}, {'\'','6'},{'"','6'}, {0xab,0},
+ {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+ {0xb0,0}, {0xb1,0}, {0xb2,0}, {0xb3,0},
+ {0xd7,0}, {0xb5,0}, {0xb6,0}, {0xb7,0},
+ {0xf7,0}, {'\'','9'},{'"','9'}, {0xbb,0},
+ {0xbc,0}, {0xbd,0}, {0xbe,0}, {0xbf,0}
+#elif (ISO_8859 == 2) || (ISO_8859 == 4)
+ {'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+ {'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+ {0xa4,0}, {'\'','6'},{'"','6'}, {'<','<'},
+ {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+ {0xb0,0}, {'+','-'}, {'2','S'}, {'3','S'},
+ {0xd7,0}, {'M','y'}, {'P','I'}, {'.','M'},
+ {0xf7,0}, {'\'','9'},{'"','9'}, {'>','>'},
+ {'1','4'}, {'1','2'}, {'3','4'}, {'?','I'},
+#elif (ISO_8859 == 3)
+ {'N','S'}, {'!','I'}, {'C','t'}, {0xa3,0},
+ {'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+ {0xa4,0}, {'\'','6'},{'"','6'}, {'<','<'},
+ {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+ {0xb0,0}, {'+','-'}, {0xb2,0}, {0xb3,0},
+ {0xd7,0}, {0xb5,0}, {'P','I'}, {0xb7,0},
+ {0xf7,0}, {'\'','9'},{'"','9'}, {'>','>'},
+ {'1','4'}, {0xbd,0}, {'3','4'}, {'?','I'}
+#elif (ISO_8859 == 10)
+ {'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+ {'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+ {'C','u'}, {'\'','6'},{'"','6'}, {'<','<'},
+ {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+ {0xb0,0}, {'+','-'}, {'2','S'}, {'3','S'},
+ {'*','X'}, {'M','y'}, {'P','I'}, {0xb7,0},
+ {'-',':'}, {'\'','9'},{'"','9'}, {'>','>'},
+ {'1','4'}, {'1','2'}, {'3','4'}, {'?','I'}
+#else
+ {'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+ {'D','O'}, {'Y','e'}, {'C','u'}, {'S','E'},
+ {'X','O'}, {'\'','6'},{'"','6'}, {'<','<'},
+ {'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+ {'D','G'}, {'+','-'}, {'2','S'}, {'3','S'},
+ {'*','X'}, {'M','y'}, {'P','I'}, {'.','M'},
+ {'-',':'}, {'\'','9'},{'"','9'}, {'>','>'},
+ {'1','4'}, {'1','2'}, {'3','4'}, {'?','I'}
+#endif
+};
+
+/*
+--- T.61 characters [0xE0 .. 0xFF] -----------------
+*/
+static Couple trans_t61b_iso8859[48] = {
+#if (ISO_8859 == 1)
+ {'-','M'}, {0xb9,0}, {0xae,0}, {0xa9,0},
+ {'T','M'}, {'M','8'}, {0xac,0}, {0xa6,0},
+ {0,0}, {0,0}, {0,0}, {0,0},
+ {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+ {'O','m'}, {0xc6,0}, {0xd0,0}, {0xaa,0},
+ {'H','/'}, {0,0}, {'I','J'}, {'L','.'},
+ {'L','/'}, {0xd8,0}, {'O','E'}, {0xba,0},
+ {0xde,0}, {'T','/'}, {'N','G'}, {'\'','n'},
+ {'k','k'}, {0xe6,0}, {'d','/'}, {0xf0,0},
+ {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+ {'l','/'}, {0xf8,0}, {'o','e'}, {0xdf,0},
+ {0xfe,0}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 2)
+ {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+ {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+ {0,0}, {0,0}, {0,0}, {0,0},
+ {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+ {'O','m'}, {'A','E'}, {0xd0,0}, {'-','a'},
+ {'H','/'}, {0,0}, {'I','J'}, {'L','.'},
+ {0xa3,0}, {'O','/'}, {'O','E'}, {'-','o'},
+ {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+ {'k','k'}, {'a','e'}, {0xf0,0}, {'d','-'},
+ {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+ {0xb3,0}, {'o','/'}, {'o','e'}, {0xdf,0},
+ {'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 3)
+ {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+ {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+ {0,0}, {0,0}, {0,0}, {0,0},
+ {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+ {'O','m'}, {'A','E'}, {'D','/'}, {'-','a'},
+ {0xa1,0}, {0,0}, {'I','J'}, {'L','.'},
+ {'L','/'}, {'O','/'}, {'O','E'}, {'-','o'},
+ {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+ {'k','k'}, {'a','e'}, {'d','/'}, {'d','-'},
+ {0xb1,0}, {0xb9,0}, {'i','j'}, {'l','.'},
+ {'l','/'}, {'o','/'}, {'o','e'}, {0xdf,0},
+ {'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 4)
+ {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+ {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+ {0,0}, {0,0}, {0,0}, {0,0},
+ {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+ {'O','m'}, {0xc6,0}, {0xd0,0}, {'-','a'},
+ {'H','/'}, {0,0}, {'I','J'}, {'L','.'},
+ {'L','/'}, {0xd8,0}, {'O','E'}, {'-','o'},
+ {'T','H'}, {0xac,0}, {0xbd,0}, {'\'','n'},
+ {0xa2,0}, {0xe6,0}, {0xf0,0}, {'d','-'},
+ {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+ {'l','/'}, {0xf8,0}, {'o','e'}, {0xdf,0},
+ {'t','h'}, {0xbc,0}, {0xbf,0}, {'-','-'}
+#elif (ISO_8859 == 9)
+ {'-','M'}, {0xb9,0}, {0xae,0}, {0xa9,0},
+ {'T','M'}, {'M','8'}, {0xac,0}, {0xa6,0},
+ {0,0}, {0,0}, {0,0}, {0,0},
+ {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+ {'O','m'}, {0xc6,0}, {'D','/'}, {0xaa,0},
+ {'H','/'}, {0,0}, {'I','J'}, {'L','.'},
+ {'L','/'}, {0xd8,0}, {'O','E'}, {0xba,0},
+ {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+ {'k','k'}, {0xe6,0}, {'d','/'}, {'d','-'},
+ {'h','/'}, {0xfd,0}, {'i','j'}, {'l','.'},
+ {'l','/'}, {0xf8,0}, {'o','e'}, {0xdf,0},
+ {'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 10)
+ {0xbd,0}, {'1','S'}, {'R','g'}, {'C','o'},
+ {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+ {0,0}, {0,0}, {0,0}, {0,0},
+ {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+ {'O','m'}, {0xc6,0}, {0xa9,0}, {'-','a'},
+ {'H','/'}, {0,0}, {'I','J'}, {'L','.'},
+ {'L','/'}, {0xd8,0}, {'O','E'}, {'-','o'},
+ {0xde,0}, {0xab,0}, {0xaf,0}, {'\'','n'},
+ {0xff,0}, {0xe6,0}, {0xb9,0}, {0xf0,0},
+ {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+ {'l','/'}, {0xf8,0}, {'o','e'}, {0xdf,0},
+ {0xfe,0}, {0xbb,0}, {0xbf,0}, {'-','-'}
+#else
+ {'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+ {'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+ {0,0}, {0,0}, {0,0}, {0,0},
+ {'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+ {'O','m'}, {'A','E'}, {'D','/'}, {'-','a'},
+ {'H','/'}, {0,0}, {'I','J'}, {'L','.'},
+ {'L','/'}, {'O','/'}, {'O','E'}, {'-','o'},
+ {'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+ {'k','k'}, {'a','e'}, {'d','/'}, {'d','-'},
+ {'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+ {'l','/'}, {'o','/'}, {'o','e'}, {'s','s'},
+ {'t','h'}, {'t','-'}, {'n','g'}, {'-','-'}
+#endif
+};
+
+/*
+--- ISO 8859-n characters <0xA0 .. 0xFF> -------------------
+*/
+#if (ISO_8859 == 1)
+static Couple trans_iso8859_t61[96] = {
+ {0xa0,0}, {0xa1,0}, {0xa2,0}, {0xa3,0},
+ {0xa8,0}, {0xa5,0}, {0xd7,0}, {0xa7,0},
+ {0xc8,ALONE}, {0xd3,0}, {0xe3,0}, {0xab,0},
+ {0xd6,0}, {0xff,0}, {0xd2,0}, {0xc5,ALONE},
+ {0xb0,0}, {0xb1,0}, {0xb2,0}, {0xb3,0},
+ {0xc2,ALONE}, {0xb5,0}, {0xb6,0}, {0xb7,0},
+ {0xcb,ALONE}, {0xd1,0}, {0xeb,0}, {0xbb,0},
+ {0xbc,0}, {0xbd,0}, {0xbe,0}, {0xbf,0},
+ {0xc1,'A'}, {0xc2,'A'}, {0xc3,'A'}, {0xc4,'A'},
+ {0xc8,'A'}, {0xca,'A'}, {0xe1,0}, {0xcb,'C'},
+ {0xc1,'E'}, {0xc2,'E'}, {0xc3,'E'}, {0xc8,'E'},
+ {0xc1,'I'}, {0xc2,'I'}, {0xc3,'I'}, {0xc8,'I'},
+ {0xe2,0}, {0xc4,'N'}, {0xc1,'O'}, {0xc2,'O'},
+ {0xc3,'O'}, {0xc4,'O'}, {0xc8,'O'}, {0xb4,0},
+ {0xe9,0}, {0xc1,'U'}, {0xc2,'U'}, {0xc3,'U'},
+ {0xc8,'U'}, {0xc2,'Y'}, {0xec,0}, {0xfb,0},
+ {0xc1,'a'}, {0xc2,'a'}, {0xc3,'a'}, {0xc4,'a'},
+ {0xc8,'a'}, {0xca,'a'}, {0xf1,0}, {0xcb,'c'},
+ {0xc1,'e'}, {0xc2,'e'}, {0xc3,'e'}, {0xc8,'e'},
+ {0xc1,'i'}, {0xc2,'i'}, {0xc3,'i'}, {0xc8,'i'},
+ {0xf3,0}, {0xc4,'n'}, {0xc1,'o'}, {0xc2,'o'},
+ {0xc3,'o'}, {0xc4,'o'}, {0xc8,'o'}, {0xb8,0},
+ {0xf9,0}, {0xc1,'u'}, {0xc2,'u'}, {0xc3,'u'},
+ {0xc8,'u'}, {0xc2,'y'}, {0xfc,0}, {0xc8,'y'}
+};
+#elif (ISO_8859 == 2)
+static Couple trans_iso8859_t61[96] = {
+ {0xa0,0}, {0xce,'A'}, {0xc6,ALONE}, {0xe8,0},
+ {0xa8,0}, {0xcf,'L'}, {0xc2,'S'}, {0xa7,0},
+ {0xc8,ALONE}, {0xcf,'S'}, {0xcb,'S'}, {0xcf,'T'},
+ {0xc2,'Z'}, {0xff,0}, {0xcf,'Z'}, {0xc7,'Z'},
+ {0xb0,0}, {0xce,'a'}, {0xce,ALONE}, {0xf8,0},
+ {0xc2,ALONE}, {0xcf,'l'}, {0xc2,'s'}, {0xcf,ALONE},
+ {0xcb,ALONE}, {0xcf,'s'}, {0xcb,'s'}, {0xcf,'t'},
+ {0xc2,'z'}, {0xcd,ALONE}, {0xcf,'z'}, {0xc7,'z'},
+ {0xc2,'R'}, {0xc2,'A'}, {0xc3,'A'}, {0xc6,'A'},
+ {0xc8,'A'}, {0xc2,'L'}, {0xc2,'C'}, {0xcb,'C'},
+ {0xcf,'C'}, {0xc2,'E'}, {0xce,'E'}, {0xc8,'E'},
+ {0xcf,'E'}, {0xc2,'I'}, {0xc3,'I'}, {0xcf,'D'},
+ {0xe2,0}, {0xc2,'N'}, {0xcf,'N'}, {0xc2,'O'},
+ {0xc3,'O'}, {0xcd,'O'}, {0xc8,'O'}, {0xb4,0},
+ {0xcf,'R'}, {0xca,'U'}, {0xc2,'U'}, {0xcd,'U'},
+ {0xc8,'U'}, {0xc2,'Y'}, {0xcb,'T'}, {0xfb,0},
+ {0xc2,'r'}, {0xc2,'a'}, {0xc3,'a'}, {0xc6,'a'},
+ {0xc8,'a'}, {0xc2,'l'}, {0xc2,'c'}, {0xcb,'c'},
+ {0xcf,'c'}, {0xc2,'e'}, {0xce,'e'}, {0xc8,'e'},
+ {0xcf,'e'}, {0xc2,'i'}, {0xc3,'i'}, {0xcf,'d'},
+ {0xf2,0}, {0xc2,'n'}, {0xcf,'n'}, {0xc2,'o'},
+ {0xc3,'o'}, {0xcd,'o'}, {0xc8,'o'}, {0xb8,0},
+ {0xcf,'r'}, {0xca,'u'}, {0xc2,'u'}, {0xcd,'u'},
+ {0xc8,'u'}, {0xc2,'y'}, {0xcb,'t'}, {0xc7,ALONE}
+};
+#elif (ISO_8859 == 3)
+static Couple trans_iso8859_t61[96] = {
+ {0xa0,0}, {0xe4,0}, {0xc6,ALONE}, {0xa3,0},
+ {0xa8,0}, {0,0}, {0xc3,'H'}, {0xa7,0},
+ {0xc8,ALONE}, {0xc7,'I'}, {0xcb,'S'}, {0xc6,'G'},
+ {0xc3,'J'}, {0xff,0}, {0,0}, {0xc7,'Z'},
+ {0xb0,0}, {0xf4,0}, {0xb2,0}, {0xb3,0},
+ {0xc2,ALONE}, {0xb5,0}, {0xc3,'h'}, {0xb7,0},
+ {0xcb,ALONE}, {0xf5,0}, {0xcb,'s'}, {0xc6,'g'},
+ {0xc3,'j'}, {0xbd,0}, {0,0}, {0xc7,'z'},
+ {0xc1,'A'}, {0xc2,'A'}, {0xc3,'A'}, {0,0},
+ {0xc8,'A'}, {0xc7,'C'}, {0xc3,'C'}, {0xcb,'C'},
+ {0xc1,'E'}, {0xc2,'E'}, {0xc3,'E'}, {0xc8,'E'},
+ {0xc1,'I'}, {0xc2,'I'}, {0xc3,'I'}, {0xc8,'I'},
+ {0,0}, {0xc4,'N'}, {0xc1,'O'}, {0xc2,'O'},
+ {0xc3,'O'}, {0xc7,'G'}, {0xc8,'O'}, {0xb4,0},
+ {0xc3,'G'}, {0xc1,'U'}, {0xc2,'U'}, {0xc3,'U'},
+ {0xc8,'U'}, {0xc6,'U'}, {0xc3,'S'}, {0xfb,0},
+ {0xc1,'a'}, {0xc2,'a'}, {0xc3,'a'}, {0,0},
+ {0xc8,'a'}, {0xc7,'c'}, {0xc3,'c'}, {0xcb,'c'},
+ {0xc1,'e'}, {0xc2,'e'}, {0xc3,'e'}, {0xc8,'e'},
+ {0xc1,'i'}, {0xc2,'i'}, {0xc3,'i'}, {0xc8,'i'},
+ {0,0}, {0xc4,'n'}, {0xc1,'o'}, {0xc2,'o'},
+ {0xc3,'o'}, {0xc7,'g'}, {0xc8,'o'}, {0xb8,0},
+ {0xc3,'g'}, {0xc1,'u'}, {0xc2,'u'}, {0xc3,'u'},
+ {0xc8,'u'}, {0xc6,'u'}, {0xc3,'s'}, {0xc7,ALONE}
+};
+#elif (ISO_8859 == 4)
+static Couple trans_iso8859_t61[96] = {
+ {0xa0,0}, {0xce,'A'}, {0xf0,0}, {0xcb,'R'},
+ {0xa8,0}, {0xc4,'I'}, {0xcb,'L'}, {0xa7,0},
+ {0xc8,ALONE}, {0xcf,'S'}, {0xc5,'E'}, {0xcb,'G'},
+ {0xed,0}, {0xff,0}, {0xcf,'Z'}, {0xc5,ALONE},
+ {0xb0,0}, {0xce,'a'}, {0xce,ALONE}, {0xcb,'r'},
+ {0xc2,ALONE}, {0xc4,'i'}, {0xcb,'l'}, {0xcf,ALONE},
+ {0xcb,ALONE}, {0xcf,'s'}, {0xc5,'e'}, {0xcb,'g'},
+ {0xfd,0}, {0xee,0}, {0xcf,'z'}, {0xfe,0},
+ {0xc5,'A'}, {0xc2,'A'}, {0xc3,'A'}, {0xc4,'A'},
+ {0xc8,'A'}, {0xca,'A'}, {0xe1,0}, {0xce,'I'},
+ {0xcf,'C'}, {0xc2,'E'}, {0xce,'E'}, {0xc8,'E'},
+ {0xc7,'E'}, {0xc2,'I'}, {0xc3,'I'}, {0xc5,'I'},
+ {0xe2,0}, {0xcb,'N'}, {0xc5,'O'}, {0xcb,'K'},
+ {0xc3,'O'}, {0xc4,'O'}, {0xc8,'O'}, {0xb4,0},
+ {0xe9,0}, {0xce,'U'}, {0xc2,'U'}, {0xc3,'U'},
+ {0xc8,'U'}, {0xc4,'U'}, {0xc5,'U'}, {0xfb,0},
+ {0xc5,'a'}, {0xc2,'a'}, {0xc3,'a'}, {0xc4,'a'},
+ {0xc8,'a'}, {0xca,'a'}, {0xf1,0}, {0xce,'i'},
+ {0xcf,'c'}, {0xc2,'e'}, {0xce,'e'}, {0xc8,'e'},
+ {0xc7,'e'}, {0xc2,'i'}, {0xc3,'i'}, {0xc5,'i'},
+ {0xf2,0}, {0xcb,'n'}, {0xc5,'o'}, {0xcb,'k'},
+ {0xc3,'o'}, {0xc4,'o'}, {0xc8,'o'}, {0xb8,0},
+ {0xf9,0}, {0xce,'u'}, {0xc2,'u'}, {0xc3,'u'},
+ {0xc8,'u'}, {0xc4,'u'}, {0xc5,'u'}, {0xc7,ALONE}
+};
+#elif (ISO_8859 == 9)
+static Couple trans_iso8859_t61[96] = {
+ {0xa0,0}, {0xa1,0}, {0xa2,0}, {0xa3,0},
+ {0xa8,0}, {0xa5,0}, {0xd7,0}, {0xa7,0},
+ {0xc8,ALONE}, {0xd3,0}, {0xe3,0}, {0xab,0},
+ {0xd6,0}, {0xff,0}, {0xd2,0}, {0xc5,ALONE},
+ {0xb0,0}, {0xb1,0}, {0xb2,0}, {0xb3,0},
+ {0xc2,ALONE}, {0xb5,0}, {0xb6,0}, {0xb7,0},
+ {0xcb,ALONE}, {0xd1,0}, {0xeb,0}, {0xbb,0},
+ {0xbc,0}, {0xbd,0}, {0xbe,0}, {0xbf,0},
+ {0xc1,'A'}, {0xc2,'A'}, {0xc3,'A'}, {0xc4,'A'},
+ {0xc8,'A'}, {0xca,'A'}, {0xe1,0}, {0xcb,'C'},
+ {0xc1,'E'}, {0xc2,'E'}, {0xc3,'E'}, {0xc8,'E'},
+ {0xc1,'I'}, {0xc2,'I'}, {0xc3,'I'}, {0xc8,'I'},
+ {0xc6,'G'}, {0xc4,'N'}, {0xc1,'O'}, {0xc2,'O'},
+ {0xc3,'O'}, {0xc4,'O'}, {0xc8,'O'}, {0xb4,0},
+ {0xe9,0}, {0xc1,'U'}, {0xc2,'U'}, {0xc3,'U'},
+ {0xc8,'U'}, {0xc7,'I'}, {0xcb,'S'}, {0xfb,0},
+ {0xc1,'a'}, {0xc2,'a'}, {0xc3,'a'}, {0xc4,'a'},
+ {0xc8,'a'}, {0xca,'a'}, {0xf1,0}, {0xcb,'c'},
+ {0xc1,'e'}, {0xc2,'e'}, {0xce,'e'}, {0xc8,'e'},
+ {0xc7,'e'}, {0xc2,'i'}, {0xc3,'i'}, {0xc5,'i'},
+ {0xc6,'g'}, {0xc4,'n'}, {0xc1,'o'}, {0xc2,'o'},
+ {0xc3,'o'}, {0xc4,'o'}, {0xc8,'o'}, {0xb8,0},
+ {0xf9,0}, {0xc1,'u'}, {0xc2,'u'}, {0xc3,'u'},
+ {0xc8,'u'}, {0xf5,0}, {0xcb,'s'}, {0xc8,'y'}
+};
+#elif (ISO_8859 == 10)
+static Couple trans_iso8859_t61[96] = {
+ {0xa0,0}, {0xce,'A'}, {0xc5,'E'}, {0xcb,'G'},
+ {0xc5,'I'}, {0xc4,'I'}, {0xcb,'K'}, {0xa7,0},
+ {0xcb,'L'}, {0xe2,0}, {0xcf,'S'}, {0xed,0},
+ {0xcf,'Z'}, {0xff,0}, {0xc5,'U'}, {0xee,0},
+ {0xb0,0}, {0xce,'a'}, {0xc5,'e'}, {0xcb,'g'},
+ {0xc5,'i'}, {0xc4,'i'}, {0xcb,'k'}, {0xb7,0},
+ {0xcb,'l'}, {0xf2,0}, {0xcf,'s'}, {0xfd,0},
+ {0xcf,'z'}, {0xd0,0}, {0xc5,'u'}, {0xfe,0},
+ {0xc5,'A'}, {0xc2,'A'}, {0xc3,'A'}, {0xc4,'A'},
+ {0xc8,'A'}, {0xca,'A'}, {0xe1,0}, {0xce,'I'},
+ {0xcf,'C'}, {0xc2,'E'}, {0xce,'E'}, {0xc8,'E'},
+ {0xc7,'E'}, {0xc2,'I'}, {0xc3,'I'}, {0xc8,'I'},
+ {0,0}, {0xcb,'N'}, {0xc5,'O'}, {0xc2,'O'},
+ {0xc3,'O'}, {0xc4,'O'}, {0xc8,'O'}, {0xc4,'U'},
+ {0xe9,0}, {0xce,'U'}, {0xc2,'U'}, {0xc3,'U'},
+ {0xc8,'U'}, {0xc2,'Y'}, {0xec,0}, {0xfb,0},
+ {0xc5,'a'}, {0xc2,'a'}, {0xc3,'a'}, {0xc4,'a'},
+ {0xc8,'a'}, {0xca,'a'}, {0xf1,0}, {0xce,'i'},
+ {0xcf,'c'}, {0xc2,'e'}, {0xce,'e'}, {0xc8,'e'},
+ {0xc7,'e'}, {0xc2,'i'}, {0xc3,'i'}, {0xc8,'i'},
+ {0xf3,0}, {0xcb,'n'}, {0xc5,'o'}, {0xc2,'o'},
+ {0xc3,'o'}, {0xc4,'o'}, {0xc8,'o'}, {0xc4,'u'},
+ {0xf9,0}, {0xce,'u'}, {0xc2,'u'}, {0xc3,'u'},
+ {0xc8,'u'}, {0xc2,'y'}, {0xfc,0}, {0xf0,0}
+};
+#endif
+
+
+static Byte *
+c_to_hh( Byte *o, Byte c )
+{
+ Byte n;
+
+ *o++ = '{'; *o++ = 'x';
+ n = c >> 4;
+ *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+ n = c & 0x0F;
+ *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+ *o++ = '}';
+ return o;
+}
+
+
+static Byte *
+c_to_cc( Byte *o, Couple *cc, Byte c )
+{
+ if ( (*cc).a != 0 ) {
+ if ( (*cc).b == 0 )
+ *o++ = (*cc).a;
+ else {
+ *o++ = '{';
+ *o++ = (*cc).a;
+ *o++ = (*cc).b;
+ *o++ = '}';
+ }
+ return o;
+ }
+ else
+ return c_to_hh( o, c );
+}
+
+/* --- routine to convert from T.61 to ISO 8859-n --- */
+
+int
+ldap_t61_to_8859( char **bufp, unsigned long *buflenp, int free_input )
+{
+ Byte *s, *oo, *o;
+ unsigned int n;
+ int c;
+ unsigned long len;
+ Couple *cc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_t61_to_8859 input length: %ld\n",
+ *buflenp, 0, 0 );
+
+ len = *buflenp;
+ s = (Byte *) *bufp;
+
+ if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * len + 64 )) == NULL ) {
+ return( 1 );
+ }
+
+ while ( (char *)s - *(char **)bufp < len ) {
+ switch ( *s >> 4 ) {
+
+ case 0xA: case 0xB:
+ o = c_to_cc( o, &trans_t61a_iso8859[ *s - 0xA0 ], *s );
+ s++;
+ break;
+
+ case 0xD: case 0xE: case 0xF:
+ o = c_to_cc( o, &trans_t61b_iso8859[ *s - 0xD0 ], *s );
+ s++;
+ break;
+
+ case 0xC:
+ if ( (*s == 0xC0) || (*s == 0xC9) || (*s == 0xCC) ) {
+ o = c_to_hh( o, *s++ );
+ break;
+ }
+
+ n = (*s++) - 0xC0;
+ switch ( *s ) {
+
+ case 'A': c = letter_w_diacritic[n][0]; break;
+ case 'C': c = letter_w_diacritic[n][1]; break;
+ case 'D': c = letter_w_diacritic[n][2]; break;
+ case 'E': c = letter_w_diacritic[n][3]; break;
+ case 'G': c = letter_w_diacritic[n][4]; break;
+ case 'H': c = letter_w_diacritic[n][5]; break;
+ case 'I': c = letter_w_diacritic[n][6]; break;
+ case 'J': c = letter_w_diacritic[n][7]; break;
+ case 'K': c = letter_w_diacritic[n][8]; break;
+ case 'L': c = letter_w_diacritic[n][9]; break;
+ case 'N': c = letter_w_diacritic[n][10]; break;
+ case 'O': c = letter_w_diacritic[n][11]; break;
+ case 'R': c = letter_w_diacritic[n][12]; break;
+ case 'S': c = letter_w_diacritic[n][13]; break;
+ case 'T': c = letter_w_diacritic[n][14]; break;
+ case 'U': c = letter_w_diacritic[n][15]; break;
+ case 'W': c = letter_w_diacritic[n][16]; break;
+ case 'Y': c = letter_w_diacritic[n][17]; break;
+ case 'Z': c = letter_w_diacritic[n][18]; break;
+
+ case 'a': c = letter_w_diacritic[n][19]; break;
+ case 'c': c = letter_w_diacritic[n][20]; break;
+ case 'd': c = letter_w_diacritic[n][21]; break;
+ case 'e': c = letter_w_diacritic[n][22]; break;
+ case 'g': c = letter_w_diacritic[n][23]; break;
+ case 'h': c = letter_w_diacritic[n][24]; break;
+ case 'i': c = letter_w_diacritic[n][25]; break;
+ case 'j': c = letter_w_diacritic[n][26]; break;
+ case 'k': c = letter_w_diacritic[n][27]; break;
+ case 'l': c = letter_w_diacritic[n][28]; break;
+ case 'n': c = letter_w_diacritic[n][29]; break;
+ case 'o': c = letter_w_diacritic[n][30]; break;
+ case 'r': c = letter_w_diacritic[n][31]; break;
+ case 's': c = letter_w_diacritic[n][32]; break;
+ case 't': c = letter_w_diacritic[n][33]; break;
+ case 'u': c = letter_w_diacritic[n][34]; break;
+ case 'w': c = letter_w_diacritic[n][35]; break;
+ case 'y': c = letter_w_diacritic[n][36]; break;
+ case 'z': c = letter_w_diacritic[n][37]; break;
+
+ case ALONE: c = (( !diacritic[n].b ) ? diacritic[n].a : -1);
+ break;
+
+ default: c = 0;
+ }
+
+ if ( c > 0 ) {
+ *o++ = c; s++;
+ } else {
+ *o++ = '{';
+ if ( c == -1 ) {
+ *o++ = ( ( *s == ALONE ) ? ' ' : *s );
+ s++;
+ } else {
+ *o++ = '"';
+ }
+ *o++ = diacritic[n].a;
+ *o++ = '}';
+ }
+ break;
+
+#if (ISO_8859 == 0)
+ case 0x8: case 0x9:
+ *o++ = 0x1B; /* <ESC> */
+ *o++ = *s++ - 0x40;
+ break;
+#endif
+
+ default:
+ *o++ = *s++;
+ }
+ }
+
+ len = o - oo;
+ o = oo;
+
+ if ( (oo = (Byte *)NSLDAPI_REALLOC( o, len )) == NULL ) {
+ NSLDAPI_FREE( o );
+ return( 1 );
+ }
+
+ if ( free_input ) {
+ NSLDAPI_FREE( *bufp );
+ }
+ *bufp = (char *) oo;
+ *buflenp = len;
+ return( 0 );
+}
+
+
+static int
+hh_to_c( Byte *h )
+{
+ Byte c;
+
+ if ( (*h >= '0') && (*h <= '9') ) c = *h++ - '0';
+ else if ( (*h >= 'A') && (*h <= 'F') ) c = *h++ - 'A' + 10;
+ else if ( (*h >= 'a') && (*h <= 'f') ) c = *h++ - 'a' + 10;
+ else return -1;
+
+ c <<= 4;
+
+ if ( (*h >= '0') && (*h <= '9') ) c |= *h - '0';
+ else if ( (*h >= 'A') && (*h <= 'F') ) c |= *h - 'A' + 10;
+ else if ( (*h >= 'a') && (*h <= 'f') ) c |= *h - 'a' + 10;
+ else return -1;
+
+ return c;
+}
+
+
+static Byte *
+cc_to_t61( Byte *o, Byte *s )
+{
+ int n, c = 0;
+
+ switch ( *(s + 1) ) {
+
+ case '`': c = -1; break; /* <grave-accent> */
+
+ case '!':
+ switch ( *s ) {
+ case '!': c = 0x7C; break; /* <vertical-line> */
+ case '(': c = 0x7B; break; /* <left-curly-bracket> */
+ case '-': c = 0xAD; break; /* <upwards-arrow> */
+ default: c = -1; /* <grave-accent> */
+ }
+ break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+ (ISO_8859 == 4) || (ISO_8859 == 9)
+ case 0xB4:
+#endif
+ case '\'': c = -2; break; /* <acute-accent> */
+
+ case '^': c = -3; break; /* <circumflex-acent> */
+
+ case '>':
+ switch ( *s ) {
+ case ')': c = 0x5D; break; /* <right-square-bracket> */
+ case '>': c = 0xBB; break; /* <right-angle-quotation> */
+ case '-': c = 0xAE; break; /* <rightwards-arrow> */
+ default: c = -3; /* <circumflex-acent> */
+ }
+ break;
+
+ case '~':
+ case '?': c = -4; break; /* <tilde> */
+
+#if (ISO_8859 == 1) || (ISO_8859 == 4) || (ISO_8859 == 9)
+ case 0xAF: c = -5; break; /* <macron> */
+#endif
+
+ case '-':
+ switch ( *s ) {
+ case '-': c = 0xFF; break; /* <soft-hyphen> */
+ case '<': c = 0xAC; break; /* <leftwards arrow> */
+ case '+': c = 0xB1; break; /* <plus-minus> */
+ case 'd': c = 0xF3; break; /* <eth> */
+ default: c = -5; /* <macron> */
+ }
+ break;
+
+#if (ISO_8859 == 2) || (ISO_8859 == 3)
+ case 0xA2: c = -6; break; /* <breve> */
+#endif
+
+ case '(':
+ if ( *s == '<' ) c = 0x5B; /* <left-square-bracket> */
+ else c = -6; /* <breve> */
+ break;
+
+#if (ISO_8859 == 2) || (ISO_8859 == 3) || (ISO_8859 == 4)
+ case 0xFF: c = -7; break; /* <dot-accent> */
+#endif
+
+ case '.':
+ switch ( *s ) {
+ case 'i': c = 0xF5; break; /* <dotless-i> */
+ case 'L': c = 0xE7; break; /* <L-middle-dot> */
+ case 'l': c = 0xF7; break; /* <l-middle-dot> */
+ default: c = -7; /* <dot-accent> */
+ }
+ break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+ (ISO_8859 == 4) || (ISO_8859 == 9)
+ case 0xA8: c = -8; break; /* <diaeresis> */
+#endif
+
+ case ':':
+ if ( *s == '-') c = 0xB8; /* <division-sign> */
+ else c = -8; /* <diaeresis> */
+ break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+ (ISO_8859 == 4) || (ISO_8859 == 9) || (ISO_8859 == 10)
+ case 0xB0:
+#endif
+ case '0': c = -10; break; /* <ring-above> */
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+ (ISO_8859 == 4) || (ISO_8859 == 9)
+ case 0xB8:
+#endif
+ case ',': c = -11; break; /* <cedilla> */
+
+#if (ISO_8859 == 2)
+ case 0xBD:
+#endif
+ case '"': c = -13; break; /* <double-acute-accent> */
+
+#if (ISO_8859 == 2) || (ISO_8859 == 4)
+ case 0xB2:
+#endif
+ case ';': c = -14; break; /* <ogonek> */
+
+#if (ISO_8859 == 2) || (ISO_8859 == 4)
+ case 0xB7: c = -15; break; /* <caron> */
+#endif
+
+ case ')':
+ if ( *s == '!' ) c = 0x7D; /* <left-curly-bracket> */
+ break;
+
+ case '<':
+ if ( *s == '<' ) c = 0xAB; /* <left-angle-quotation> */
+ else c = -15; /* <caron> */
+ break;
+
+ case '/':
+ switch ( *s ) {
+ case '/': c = 0x5C; break; /* <reverse-solidus> */
+ case 'D': c = 0xE2; break; /* <D-stroke> */
+ case 'd': c = 0xF2; break; /* <d-stroke> */
+ case 'H': c = 0xE4; break; /* <H-stroke> */
+ case 'h': c = 0xF4; break; /* <h-stroke> */
+ case 'L': c = 0xE8; break; /* <L-stroke> */
+ case 'l': c = 0xF8; break; /* <l-stroke> */
+ case 'O': c = 0xE9; break; /* <O-stroke> */
+ case 'o': c = 0xF9; break; /* <o-stroke> */
+ case 'T': c = 0xED; break; /* <T-stroke> */
+ case 't': c = 0xFD; break; /* <t-stroke> */
+ }
+ break;
+
+ case '2':
+ if ( *s == '1' ) c = 0xBD; /* <one-half> */
+ break;
+
+ case '4':
+ switch ( *s ) {
+ case '1': c = 0xBC; break; /* <one-quarter> */
+ case '3': c = 0xBE; break; /* <three-quarters> */
+ }
+ break;
+
+ case '6':
+ switch ( *s ) {
+ case '\'': c = 0xA9; break; /* <left-single-quotation> */
+ case '"': c = 0xAA; break; /* <left-double-quotation> */
+ }
+ break;
+
+ case '8':
+ switch ( *s ) {
+ case '1': c = 0xDC; break; /* <one-eighth> */
+ case '3': c = 0xDD; break; /* <three-eighths> */
+ case '5': c = 0xDE; break; /* <five-eighths> */
+ case '7': c = 0xDF; break; /* <seven-eighths> */
+ case 'M': c = 0xD5; break; /* <eighth-note> */
+ }
+ break;
+
+ case '9':
+ switch ( *s ) {
+ case '\'': c = 0xB9; break; /* <right-single-quotation> */
+ case '"': c = 0xBA; break; /* <right-double-quotation> */
+ }
+ break;
+
+ case 'A':
+ if ( *s == 'A' ) c = -10; /* <ring-above> + <A> */
+ break;
+
+ case 'a':
+ switch ( *s ) {
+ case '-': c = 0xE3; break; /* <femenine-ordinal-a> */
+ case 'a': c = -10; break; /* <ring-above> + <a> */
+ }
+ break;
+
+ case 'B':
+ if ( *s == 'B' ) c = 0xD7; /* <broken-bar> */
+ break;
+
+ case 'b':
+ if ( *s == 'N' ) c = 0xA6; /* <number-sign> */
+ break;
+
+ case 'd':
+ if ( *s == 'P' ) c = 0xA3; /* <pound-sign> */
+ break;
+
+ case 'E':
+ switch ( *s ) {
+ case 'S': c = 0xA7; break; /* <section-sign> */
+ case 'A': c = 0xE1; break; /* <AE> */
+ case 'O': c = 0xEA; break; /* <OE> */
+ }
+ break;
+
+ case 'e':
+ switch ( *s ) {
+ case 'a': c = 0xF1; break; /* <ae> */
+ case 'o': c = 0xFA; break; /* <oe> */
+ case 'Y': c = 0xA5; break; /* <yen-sign> */
+ }
+ break;
+
+ case 'G':
+ switch ( *s ) {
+ case 'D': c = 0xB0; break; /* <degree-sign> */
+ case 'N': c = 0xEE; break; /* <Eng> */
+ }
+ break;
+
+ case 'g':
+ switch ( *s ) {
+ case 'R': c = 0xD2; break; /* <registered-sign> */
+ case 'n': c = 0xFE; break; /* <eng> */
+ }
+ break;
+
+ case 'H':
+ if ( *s == 'T' ) c = 0xEC; /* <Thorn> */
+ break;
+
+ case 'h':
+ if ( *s == 't' ) c = 0xFC; /* <thorn> */
+ break;
+
+ case 'I':
+ switch ( *s ) {
+ case 'P': c = 0xB6; break; /* <pilcrow-sign> */
+ case '!': c = 0xA1; break; /* <inverted-exclamation> */
+ case '?': c = 0xBF; break; /* <inverted-question> */
+ }
+ break;
+
+ case 'J':
+ if ( *s == 'I' ) c = 0xE6; /* <IJ> */
+ break;
+
+ case 'j':
+ if ( *s == 'i' ) c = 0xF6; /* <ij> */
+ break;
+
+ case 'k':
+ if ( *s == 'k' ) c = 0xF0; /* <kra> */
+ break;
+
+ case 'M':
+ switch ( *s ) {
+ case '.': c = 0xB7; break; /* <middle-dot> */
+ case '-': c = 0xD0; break; /* <em-dash> */
+ case 'T': c = 0xD4; break; /* <trade-mark-sign> */
+ }
+ break;
+
+ case 'm':
+ switch ( *s ) {
+ case '\'': /* <macron> RFC 1345 */
+ case ' ': c = -5; break; /* <macron> */
+ case 'O': c = 0xE0; break; /* <Ohm sign> */
+ }
+ break;
+
+ case 'n':
+ if ( *s == '\'' ) c = 0xEF; /* <n-preceded-by-apostrophe> */
+ break;
+
+ case 'O':
+ switch ( *s ) {
+ case 'D': c = 0xA4; break; /* <dollar-sign> */
+ case 'N': c = 0xD6; break; /* <not-sign> */
+ }
+ break;
+
+ case 'o':
+ switch ( *s ) {
+ case 'C': c = 0xD3; break; /* <copyright-sign> */
+ case '-': c = 0xEB; break; /* <masculine-ordinal-o> */
+ }
+ break;
+
+ case 'S':
+ switch ( *s ) {
+ case '1': c = 0xD1; break; /* <superscript-1> */
+ case '2': c = 0xB2; break; /* <superscript-2> */
+ case '3': c = 0xB3; break; /* <superscript-3> */
+ case 'N': c = 0xA0; break; /* <no-break-space> */
+ }
+ break;
+
+ case 's':
+ if ( *s == 's' ) c = 0xFB; /* <sharp-s> */
+ break;
+
+ case 't':
+ if ( *s == 'C' ) c = 0xA2; /* <cent-sign> */
+ break;
+
+ case 'u':
+ if ( *s == 'C' ) c = 0xA8; /* <currency-sign> */
+ break;
+
+ case 'v':
+ if ( *s == '-' ) c = 0xAF; /* <downwards-arrow> */
+ break;
+
+ case 'X':
+ if ( *s == '*' ) c = 0xB4; /* <multiplication-sign> */
+ break;
+
+ case 'y':
+ if ( *s == 'M' ) c = 0xB5; /* <micro-sign> */
+ break;
+ }
+
+ if ( c > 0 ) {
+ *o++ = c;
+ return o;
+ } else if ( !c )
+ return NULL;
+
+ /* else: c < 0 */
+ n = -c;
+ switch ( *s ) {
+
+ case 'A': c = letter_w_diacritic[n][0]; break;
+ case 'C': c = letter_w_diacritic[n][1]; break;
+ case 'D': c = letter_w_diacritic[n][2]; break;
+ case 'E': c = letter_w_diacritic[n][3]; break;
+ case 'G': c = letter_w_diacritic[n][4]; break;
+ case 'H': c = letter_w_diacritic[n][5]; break;
+ case 'I': c = letter_w_diacritic[n][6]; break;
+ case 'J': c = letter_w_diacritic[n][7]; break;
+ case 'K': c = letter_w_diacritic[n][8]; break;
+ case 'L': c = letter_w_diacritic[n][9]; break;
+ case 'N': c = letter_w_diacritic[n][10]; break;
+ case 'O': c = letter_w_diacritic[n][11]; break;
+ case 'R': c = letter_w_diacritic[n][12]; break;
+ case 'S': c = letter_w_diacritic[n][13]; break;
+ case 'T': c = letter_w_diacritic[n][14]; break;
+ case 'U': c = letter_w_diacritic[n][15]; break;
+ case 'W': c = letter_w_diacritic[n][16]; break;
+ case 'Y': c = letter_w_diacritic[n][17]; break;
+ case 'Z': c = letter_w_diacritic[n][18]; break;
+
+ case 'a': c = letter_w_diacritic[n][19]; break;
+ case 'c': c = letter_w_diacritic[n][20]; break;
+ case 'd': c = letter_w_diacritic[n][21]; break;
+ case 'e': c = letter_w_diacritic[n][22]; break;
+ case 'g': c = letter_w_diacritic[n][23]; break;
+ case 'h': c = letter_w_diacritic[n][24]; break;
+ case 'i': c = letter_w_diacritic[n][25]; break;
+ case 'j': c = letter_w_diacritic[n][26]; break;
+ case 'k': c = letter_w_diacritic[n][27]; break;
+ case 'l': c = letter_w_diacritic[n][28]; break;
+ case 'n': c = letter_w_diacritic[n][29]; break;
+ case 'o': c = letter_w_diacritic[n][30]; break;
+ case 'r': c = letter_w_diacritic[n][31]; break;
+ case 's': c = letter_w_diacritic[n][32]; break;
+ case 't': c = letter_w_diacritic[n][33]; break;
+ case 'u': c = letter_w_diacritic[n][34]; break;
+ case 'w': c = letter_w_diacritic[n][35]; break;
+ case 'y': c = letter_w_diacritic[n][36]; break;
+ case 'z': c = letter_w_diacritic[n][37]; break;
+
+ case '\'':
+ case ' ': c = -1; break;
+
+ default: c = 0;
+ }
+
+ if ( !c )
+ return NULL;
+
+ *o++ = n + 0xC0;
+ *o++ = ( ( (*s == ' ') || (*s == '\'') ) ? ALONE : *s );
+ return o;
+}
+
+
+/* --- routine to convert from ISO 8859-n to T.61 --- */
+
+int
+ldap_8859_to_t61( char **bufp, unsigned long *buflenp, int free_input )
+{
+ Byte *s, *oo, *o, *aux;
+ int c;
+ unsigned long len;
+ Couple *cc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_8859_to_t61 input length: %ld\n",
+ *buflenp, 0, 0 );
+
+ len = *buflenp;
+ s = (Byte *) *bufp;
+
+ if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * len + 64 )) == NULL ) {
+ return( 1 );
+ }
+
+ while ( (char *)s - *(char **)bufp < len ) {
+ switch( *s >> 5 ) {
+
+ case 2:
+ switch ( *s ) {
+
+ case '^': *o++ = 0xC3; *o++ = ALONE; s++; break;
+
+ case '\\':
+ s++;
+ if ( (c = hh_to_c( s )) != -1 ) {
+ *o++ = c;
+ s += 2;
+ } else
+ *o++ = '\\';
+ break;
+
+ default: *o++ = *s++;
+ }
+ break;
+
+ case 3:
+ switch ( *s ) {
+
+ case '`': *o++ = 0xC1; *o++ = ALONE; s++; break;
+ case '~': *o++ = 0xC4; *o++ = ALONE; s++; break;
+
+ case '{':
+ s++;
+ if ( *(s + 2) == '}' ) {
+ if ( (aux = cc_to_t61( o, s )) != NULL ) {
+ o = aux;
+ s += 3;
+ } else {
+ *o++ = '{';
+ }
+ } else if ( (*(s + 3) == '}') && ( (*s == 'x') || (*s == 'X') ) &&
+ ( (c = hh_to_c( s + 1 )) != -1 ) ) {
+ *o++ = c;
+ s += 4;
+ } else {
+ *o++ = '{';
+ }
+ break;
+
+ default:
+ *o++ = *s++;
+ }
+ break;
+
+#if (ISO_8859 == 0)
+ case 4: case 5: case 6: case 7:
+ s++;
+ break;
+#else
+ case 5: case 6: case 7:
+# if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+ (ISO_8859 == 4) || (ISO_8859 == 9) || (ISO_8859 == 10)
+ if ( (*(cc = &trans_iso8859_t61[ *s - 0xA0 ])).a ) {
+ *o++ = (*cc).a;
+ if ( (*cc).b ) *o++ = (*cc).b;
+ }
+# endif
+ s++;
+ break;
+#endif
+
+ default:
+ *o++ = *s++;
+ }
+ }
+
+ len = o - oo;
+ o = oo;
+
+ if ( (oo = (Byte *)NSLDAPI_REALLOC( o, len )) == NULL ) {
+ NSLDAPI_FREE( o );
+ return( 1 );
+ }
+
+ if ( free_input ) {
+ NSLDAPI_FREE( *bufp );
+ }
+ *bufp = (char *) oo;
+ *buflenp = len;
+ return( 0 );
+}
+
+
+#ifdef NOT_NEEDED_IN_LIBLDAP /* mcs@umich.edu 12 Oct 1995 */
+/* --- routine to convert "escaped" (\hh) characters to 8bits --- */
+
+void convert_escaped_to_8bit( s )
+char *s;
+{
+ char *o = s;
+ int c;
+
+ while ( *s ) {
+ if ( *s == '\\' ) {
+ if ( (c = hh_to_c( ++s )) != -1 ) {
+ *o++ = c;
+ s += 2;
+ } else
+ *o++ = '\\';
+ } else
+ *o++ = *s++;
+ }
+ *o = '\0';
+}
+
+/* --- routine to convert 8bits characters to the "escaped" (\hh) form --- */
+
+char *convert_8bit_to_escaped( s )
+Byte *s;
+{
+ Byte *o, *oo;
+ Byte n;
+
+ if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * strlen( s ) + 64 )) == NULL ) {
+ return( NULL );
+ }
+
+ while ( *s ) {
+ if ( *s < 0x80 )
+ *o++ = *s++;
+ else {
+ *o++ = '\\';
+ n = *s >> 4;
+ *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+ n = *s++ & 0x0F;
+ *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+ }
+ }
+ *o = '\0';
+
+ o = oo;
+
+ if ( (oo = (Byte *)NSLDAPI_REALLOC( o, strlen( o ) + 1 )) == NULL ) {
+ NSLDAPI_FREE( o );
+ return( NULL );
+ }
+
+ return( (char *)oo );
+}
+
+/* --- routine to convert from T.61 to printable characters --- */
+
+/*
+ printable characters [RFC 1488]: 'A'..'Z', 'a'..'z', '0'..'9',
+ '\'', '(', ')', '+', ',', '-', '.', '/', ':', '?, ' '.
+
+ that conversion is language dependent.
+*/
+
+static Couple last_t61_printabled[32] = {
+ {0,0}, {'A','E'}, {'D',0}, {0,0},
+ {'H',0}, {0,0}, {'I','J'}, {'L',0},
+ {'L',0}, {'O',0}, {'O','E'}, {0,0},
+ {'T','H'}, {'T',0}, {'N','G'}, {'n',0},
+ {'k',0}, {'a','e'}, {'d',0}, {'d',0},
+ {'h',0}, {'i',0}, {'i','j'}, {'l',0},
+ {'l',0}, {'o',0}, {'o','e'}, {'s','s'},
+ {'t','h'}, {'t',0}, {'n','g'}, {0,0}
+};
+
+char *t61_printable( s )
+Byte *s;
+{
+ Byte *o, *oo;
+ Byte n;
+ Couple *cc;
+
+ if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * strlen( s ) + 64 )) == NULL ) {
+ return( NULL );
+ }
+
+ while ( *s ) {
+ if ( ( (*s >= 'A') && (*s <= 'Z') ) ||
+ ( (*s >= 'a') && (*s <= 'z') ) ||
+ ( (*s >= '0') && (*s <= '9') ) ||
+ ( (*s >= '\'') && (*s <= ')') ) ||
+ ( (*s >= '+') && (*s <= '/') ) ||
+ ( *s == '?' ) || ( *s == ' ' ) )
+ *o++ = *s++;
+ else {
+ if ( *s >= 0xE0 ) {
+ if ( (*(cc = &last_t61_printabled[ *s - 0xE0 ])).a ) {
+ *o++ = (*cc).a;
+ if ( (*cc).b ) *o++ = (*cc).b;
+ }
+ }
+ else if ( (*s >> 4) == 0xC ) {
+ switch ( *s ) {
+ case 0xCA: /* ring */
+ switch ( *(s + 1) ) {
+ case 'A': *o++ = 'A'; *o++ = 'A'; s++; break; /* Swedish */
+ case 'a': *o++ = 'a'; *o++ = 'a'; s++; break; /* Swedish */
+ }
+ break;
+
+ case 0xC8: /* diaeresis */
+ switch ( *(s + 1) ) {
+ case 'Y': *o++ = 'I'; *o++ = 'J'; s++; break; /* Dutch */
+ case 'y': *o++ = 'i'; *o++ = 'j'; s++; break; /* Dutch */
+ }
+ break;
+ }
+ }
+ s++;
+ }
+ }
+ *o = '\0';
+
+ o = oo;
+
+ if ( (oo = (Byte *)NSLDAPI_REALLOC( o, strlen( o ) + 1 )) == NULL ) {
+ NSLDAPI_FREE( o );
+ return( NULL );
+ }
+
+ return( (char *)oo );
+}
+#endif /* NOT_NEEDED_IN_LIBLDAP */ /* mcs@umich.edu 12 Oct 1995 */
+
+#endif /* LDAP_CHARSET_8859 */
+#endif /* STR_TRANSLATION */
diff --git a/usr/src/lib/libldap5/sources/ldap/common/compare.c b/usr/src/lib/libldap5/sources/ldap/common/compare.c
new file mode 100644
index 0000000000..15422e1131
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/compare.c
@@ -0,0 +1,181 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * compare.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_compare - perform an ldap compare operation. The dn
+ * of the entry to compare to and the attribute and value to compare (in
+ * attr and value) are supplied. The msgid of the response is returned.
+ *
+ * Example:
+ * ldap_compare( ld, "c=us@cn=bob", "userPassword", "secret" )
+ */
+int
+LDAP_CALL
+ldap_compare( LDAP *ld, const char *dn, const char *attr, const char *value )
+{
+ int msgid;
+ struct berval bv;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_compare\n", 0, 0, 0 );
+
+ bv.bv_val = (char *)value;
+ bv.bv_len = ( value == NULL ) ? 0 : strlen( value );
+
+ if ( ldap_compare_ext( ld, dn, attr, &bv, NULL, NULL, &msgid )
+ == LDAP_SUCCESS ) {
+ return( msgid );
+ } else {
+ return( -1 ); /* error is in ld handle */
+ }
+}
+
+int
+LDAP_CALL
+ldap_compare_ext( LDAP *ld, const char *dn, const char *attr,
+ const struct berval *bvalue, LDAPControl **serverctrls,
+ LDAPControl **clientctrls, int *msgidp )
+{
+ BerElement *ber;
+ int rc, lderr;
+
+ /* The compare request looks like this:
+ * CompareRequest ::= SEQUENCE {
+ * entry DistinguishedName,
+ * ava SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue
+ * }
+ * }
+ * and must be wrapped in an LDAPMessage.
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_compare_ext\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+ if ( attr == NULL || bvalue == NULL || bvalue->bv_len == 0
+ || msgidp == NULL ) {
+ lderr = LDAP_PARAM_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ return( lderr );
+ }
+
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ *msgidp = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ /* check the cache */
+ if ( ld->ld_cache_on && ld->ld_cache_compare != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_compare)( ld, *msgidp,
+ LDAP_REQ_COMPARE, dn, attr, bvalue )) != 0 ) {
+ *msgidp = rc;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+
+ /* create a message to send */
+ if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( lderr );
+ }
+
+ if ( ber_printf( ber, "{it{s{so}}", *msgidp, LDAP_REQ_COMPARE, dn,
+ attr, bvalue->bv_val, (int)bvalue->bv_len /* XXX lossy cast */ )
+ == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_COMPARE,
+ (char *)dn, ber );
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_compare_s( LDAP *ld, const char *dn, const char *attr,
+ const char *value )
+{
+ struct berval bv;
+
+ bv.bv_val = (char *)value;
+ bv.bv_len = ( value == NULL ) ? 0 : strlen( value );
+
+ return( ldap_compare_ext_s( ld, dn, attr, &bv, NULL, NULL ));
+}
+
+int
+LDAP_CALL
+ldap_compare_ext_s( LDAP *ld, const char *dn, const char *attr,
+ const struct berval *bvalue, LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
+{
+ int err, msgid;
+ LDAPMessage *res;
+
+ if (( err = ldap_compare_ext( ld, dn, attr, bvalue, serverctrls,
+ clientctrls, &msgid )) != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res )
+ == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ return( ldap_result2error( ld, res, 1 ) );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/compat.c b/usr/src/lib/libldap5/sources/ldap/common/compat.c
new file mode 100644
index 0000000000..28ddf26778
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/compat.c
@@ -0,0 +1,73 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1994 The Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * compat.c - compatibility routines.
+ *
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1994 The Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+#ifdef notdef
+#if defined( HPUX10 ) && defined( _REENTRANT )
+extern int h_errno;
+
+struct hostent *
+nsldapi_compat_gethostbyname_r( const char *name, struct hostent *result,
+ char *buffer, int buflen, int *h_errnop )
+{
+ struct hostent_data *hep;
+
+ if ( buflen < sizeof(struct hostent_data)) { /* sanity check */
+ *h_errnop = NO_RECOVERY; /* XXX best error code to use? */
+ return( NULL );
+ }
+
+ hep = (struct hostent_data *)buffer;
+ hep->current = NULL;
+
+ if ( gethostbyname_r( name, result, hep ) == -1) {
+ *h_errnop = h_errno; /* XXX don't see anywhere else to get this */
+ return NULL;
+ }
+ return result;
+}
+
+char *
+nsldapi_compat_ctime_r( const time_t *clock, char *buf, int buflen )
+{
+ NSLDAPI_CTIME1( clock, buf, buflen );
+ return buf;
+}
+#endif /* HPUX10 && _REENTRANT */
+#endif
diff --git a/usr/src/lib/libldap5/sources/ldap/common/control.c b/usr/src/lib/libldap5/sources/ldap/common/control.c
new file mode 100644
index 0000000000..01dd0df52e
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/control.c
@@ -0,0 +1,492 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+/* control.c - routines to handle ldapv3 controls */
+
+#include "ldap-int.h"
+
+static LDAPControl *ldap_control_dup( LDAPControl *ctrl );
+static int ldap_control_copy_contents( LDAPControl *ctrl_dst,
+ LDAPControl *ctrl_src );
+
+/*
+ * Append a list of LDAPv3 controls to ber. If ctrls is NULL, use default
+ * set of controls from ld.
+ * Return an LDAP error code (LDAP_SUCCESS if all goes well).
+ * If closeseq is non-zero, we do an extra ber_put_seq() as well.
+ */
+int
+nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
+ BerElement *ber )
+{
+ LDAPControl *c;
+ int rc, i;
+
+ rc = LDAP_ENCODING_ERROR; /* the most popular error */
+
+ /* if no controls were passed in, use global list from LDAP * */
+ LDAP_MUTEX_LOCK( ld, LDAP_CTRL_LOCK );
+ if ( ctrls == NULL ) {
+ ctrls = ld->ld_servercontrols;
+ }
+
+ /* if there are no controls then we are done */
+ if ( ctrls == NULL || ctrls[ 0 ] == NULL ) {
+ goto clean_exit;
+ }
+
+ /*
+ * If we're using LDAPv2 or earlier we can't send any controls, so
+ * we just ignore them unless one is marked critical, in which case
+ * we return an error.
+ */
+ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+ for ( i = 0; ctrls != NULL && ctrls[i] != NULL; i++ ) {
+ if ( ctrls[i]->ldctl_iscritical ) {
+ rc = LDAP_NOT_SUPPORTED;
+ goto error_exit;
+ }
+ }
+ goto clean_exit;
+ }
+
+ /*
+ * encode the controls as a Sequence of Sequence
+ */
+ if ( ber_printf( ber, "t{", LDAP_TAG_CONTROLS ) == -1 ) {
+ goto error_exit;
+ }
+
+ for ( i = 0; ctrls[i] != NULL; i++ ) {
+ c = ctrls[i];
+
+ if ( ber_printf( ber, "{s", c->ldctl_oid ) == -1 ) {
+ goto error_exit;
+ }
+
+ /* criticality is "BOOLEAN DEFAULT FALSE" */
+ /* therefore, it should only be encoded if it exists AND is TRUE */
+ if ( c->ldctl_iscritical ) {
+ if ( ber_printf( ber, "b", (int)c->ldctl_iscritical )
+ == -1 ) {
+ goto error_exit;
+ }
+ }
+
+ if ( c->ldctl_value.bv_val != NULL ) {
+ if ( ber_printf( ber, "o", c->ldctl_value.bv_val,
+ (int)c->ldctl_value.bv_len /* XXX lossy cast */ )
+ == -1 ) {
+ goto error_exit;
+ }
+ }
+
+ if ( ber_put_seq( ber ) == -1 ) {
+ goto error_exit;
+ }
+ }
+
+ if ( ber_put_seq( ber ) == -1 ) {
+ goto error_exit;
+ }
+
+clean_exit:
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
+ if ( closeseq && ber_put_seq( ber ) == -1 ) {
+ goto error_exit;
+ }
+ return( LDAP_SUCCESS );
+
+error_exit:
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+}
+
+
+/*
+ * Pull controls out of "ber" (if any present) and return them in "controlsp."
+ * Returns an LDAP error code.
+ */
+int
+nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp )
+{
+ LDAPControl *newctrl;
+ ber_tag_t tag;
+ ber_len_t len;
+ int rc, maxcontrols, curcontrols;
+ char *last;
+
+ /*
+ * Each LDAPMessage can have a set of controls appended
+ * to it. Controls are used to extend the functionality
+ * of an LDAP operation (e.g., add an attribute size limit
+ * to the search operation). These controls look like this:
+ *
+ * Controls ::= SEQUENCE OF Control
+ *
+ * Control ::= SEQUENCE {
+ * controlType LDAPOID,
+ * criticality BOOLEAN DEFAULT FALSE,
+ * controlValue OCTET STRING
+ * }
+ */
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_get_controls\n", 0, 0, 0 );
+
+ *controlsp = NULL;
+
+ /*
+ * check to see if controls were included
+ */
+ if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
+ return( LDAP_DECODING_ERROR ); /* unexpected error */
+ }
+ if ( len == 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_get_controls no controls\n", 0, 0, 0 );
+ return( LDAP_SUCCESS ); /* no controls */
+ }
+ if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
+ if ( tag == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n",
+ 0, 0, 0 );
+ return( LDAP_DECODING_ERROR ); /* decoding error */
+ }
+ /*
+ * We found something other than controls. This should never
+ * happen in LDAPv3, but we don't treat this is a hard error --
+ * we just ignore the extra stuff.
+ */
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n",
+ tag, 0, 0 );
+ return( LDAP_SUCCESS );
+ }
+
+ maxcontrols = curcontrols = 0;
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( ber, &len, last ) ) {
+ if ( curcontrols >= maxcontrols - 1 ) {
+#define CONTROL_GRABSIZE 5
+ maxcontrols += CONTROL_GRABSIZE;
+ *controlsp = (struct ldapcontrol **)NSLDAPI_REALLOC(
+ (char *)*controlsp, maxcontrols *
+ sizeof(struct ldapcontrol *) );
+ if ( *controlsp == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto free_and_return;
+ }
+ }
+ if (( newctrl = (struct ldapcontrol *)NSLDAPI_CALLOC( 1,
+ sizeof(LDAPControl))) == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto free_and_return;
+ }
+
+ (*controlsp)[curcontrols++] = newctrl;
+ (*controlsp)[curcontrols] = NULL;
+
+ if ( ber_scanf( ber, "{a", &newctrl->ldctl_oid )
+ == LBER_ERROR ) {
+ rc = LDAP_DECODING_ERROR;
+ goto free_and_return;
+ }
+
+ /* the criticality is optional */
+ if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) {
+ int aint;
+
+ if ( ber_scanf( ber, "b", &aint ) == LBER_ERROR ) {
+ rc = LDAP_DECODING_ERROR;
+ goto free_and_return;
+ }
+ newctrl->ldctl_iscritical = (char)aint; /* XXX lossy cast */
+ } else {
+ /* absent is synonomous with FALSE */
+ newctrl->ldctl_iscritical = 0;
+ }
+
+ /* the control value is optional */
+ if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) {
+ if ( ber_scanf( ber, "o", &newctrl->ldctl_value )
+ == LBER_ERROR ) {
+ rc = LDAP_DECODING_ERROR;
+ goto free_and_return;
+ }
+ } else {
+ (newctrl->ldctl_value).bv_val = NULL;
+ (newctrl->ldctl_value).bv_len = 0;
+ }
+
+ }
+
+ if ( tag == LBER_ERROR ) {
+ rc = LDAP_DECODING_ERROR;
+ goto free_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_get_controls found %d controls\n", curcontrols, 0, 0 );
+ return( LDAP_SUCCESS );
+
+free_and_return:;
+ ldap_controls_free( *controlsp );
+ *controlsp = NULL;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= nsldapi_get_controls error 0x%x\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+void
+LDAP_CALL
+ldap_control_free( LDAPControl *ctrl )
+{
+ if ( ctrl != NULL ) {
+ if ( ctrl->ldctl_oid != NULL ) {
+ NSLDAPI_FREE( ctrl->ldctl_oid );
+ }
+ if ( ctrl->ldctl_value.bv_val != NULL ) {
+ NSLDAPI_FREE( ctrl->ldctl_value.bv_val );
+ }
+ NSLDAPI_FREE( (char *)ctrl );
+ }
+}
+
+
+void
+LDAP_CALL
+ldap_controls_free( LDAPControl **ctrls )
+{
+ int i;
+
+ if ( ctrls != NULL ) {
+ for ( i = 0; ctrls[i] != NULL; i++ ) {
+ ldap_control_free( ctrls[i] );
+ }
+ NSLDAPI_FREE( (char *)ctrls );
+ }
+}
+
+
+
+#if 0
+LDAPControl **
+LDAP_CALL
+ldap_control_append( LDAPControl **ctrl_src, LDAPControl *ctrl )
+{
+ int nctrls = 0;
+ LDAPControl **ctrlp;
+ int i;
+
+ if ( NULL == ctrl )
+ return ( NULL );
+
+ /* Count the existing controls */
+ if ( NULL != ctrl_src ) {
+ while( NULL != ctrl_src[nctrls] ) {
+ nctrls++;
+ }
+ }
+
+ /* allocate the new control structure */
+ if ( ( ctrlp = (LDAPControl **)NSLDAPI_MALLOC( sizeof(LDAPControl *)
+ * (nctrls + 2) ) ) == NULL ) {
+ return( NULL );
+ }
+ memset( ctrlp, 0, sizeof(*ctrlp) * (nctrls + 2) );
+
+ for( i = 0; i < (nctrls + 1); i++ ) {
+ if ( i < nctrls ) {
+ ctrlp[i] = ldap_control_dup( ctrl_src[i] );
+ } else {
+ ctrlp[i] = ldap_control_dup( ctrl );
+ }
+ if ( NULL == ctrlp[i] ) {
+ ldap_controls_free( ctrlp );
+ return( NULL );
+ }
+ }
+ return ctrlp;
+}
+#endif /* 0 */
+
+
+/*
+ * Replace *ldctrls with a copy of newctrls.
+ * returns 0 if successful.
+ * return -1 if not and set error code inside LDAP *ld.
+ */
+int
+nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, LDAPControl **newctrls )
+{
+ int count;
+
+ if ( *ldctrls != NULL ) {
+ ldap_controls_free( *ldctrls );
+ }
+
+ if ( newctrls == NULL || newctrls[0] == NULL ) {
+ *ldctrls = NULL;
+ return( 0 );
+ }
+
+ for ( count = 0; newctrls[ count ] != NULL; ++count ) {
+ ;
+ }
+
+ if (( *ldctrls = (LDAPControl **)NSLDAPI_MALLOC(( count + 1 ) *
+ sizeof( LDAPControl *))) == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ (*ldctrls)[ count ] = NULL;
+
+ for ( count = 0; newctrls[ count ] != NULL; ++count ) {
+ if (( (*ldctrls)[ count ] =
+ ldap_control_dup( newctrls[ count ] )) == NULL ) {
+ ldap_controls_free( *ldctrls );
+ *ldctrls = NULL;
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * return a malloc'd copy of "ctrl" (NULL if memory allocation fails)
+ */
+static LDAPControl *
+/* LDAP_CALL */ /* keep this routine internal for now */
+ldap_control_dup( LDAPControl *ctrl )
+{
+ LDAPControl *rctrl;
+
+ if (( rctrl = (LDAPControl *)NSLDAPI_MALLOC( sizeof( LDAPControl )))
+ == NULL ) {
+ return( NULL );
+ }
+
+ if ( ldap_control_copy_contents( rctrl, ctrl ) != LDAP_SUCCESS ) {
+ NSLDAPI_FREE( rctrl );
+ return( NULL );
+ }
+
+ return( rctrl );
+}
+
+
+/*
+ * duplicate the contents of "ctrl_src" and place in "ctrl_dst"
+ */
+static int
+/* LDAP_CALL */ /* keep this routine internal for now */
+ldap_control_copy_contents( LDAPControl *ctrl_dst, LDAPControl *ctrl_src )
+{
+ size_t len;
+
+ if ( NULL == ctrl_dst || NULL == ctrl_src ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical;
+
+ /* fill in the fields of this new control */
+ if (( ctrl_dst->ldctl_oid = nsldapi_strdup( ctrl_src->ldctl_oid ))
+ == NULL ) {
+ return( LDAP_NO_MEMORY );
+ }
+
+ len = (size_t)(ctrl_src->ldctl_value).bv_len;
+ if ( ctrl_src->ldctl_value.bv_val == NULL || len <= 0 ) {
+ ctrl_dst->ldctl_value.bv_len = 0;
+ ctrl_dst->ldctl_value.bv_val = NULL;
+ } else {
+ ctrl_dst->ldctl_value.bv_len = len;
+ if (( ctrl_dst->ldctl_value.bv_val = NSLDAPI_MALLOC( len ))
+ == NULL ) {
+ NSLDAPI_FREE( ctrl_dst->ldctl_oid );
+ return( LDAP_NO_MEMORY );
+ }
+ SAFEMEMCPY( ctrl_dst->ldctl_value.bv_val,
+ ctrl_src->ldctl_value.bv_val, len );
+ }
+
+ return ( LDAP_SUCCESS );
+}
+
+
+
+/*
+ * build an allocated LDAPv3 control. Returns an LDAP error code.
+ */
+int
+nsldapi_build_control( char *oid, BerElement *ber, int freeber, char iscritical,
+ LDAPControl **ctrlp )
+{
+ int rc;
+ struct berval *bvp;
+
+ if ( ber == NULL ) {
+ bvp = NULL;
+ } else {
+ /* allocate struct berval with contents of the BER encoding */
+ rc = ber_flatten( ber, &bvp );
+ if ( freeber ) {
+ ber_free( ber, 1 );
+ }
+ if ( rc == -1 ) {
+ return( LDAP_NO_MEMORY );
+ }
+ }
+
+ /* allocate the new control structure */
+ if (( *ctrlp = (LDAPControl *)NSLDAPI_MALLOC( sizeof(LDAPControl)))
+ == NULL ) {
+ if ( bvp != NULL ) {
+ ber_bvfree( bvp );
+ }
+ return( LDAP_NO_MEMORY );
+ }
+
+ /* fill in the fields of this new control */
+ (*ctrlp)->ldctl_iscritical = iscritical;
+ if (( (*ctrlp)->ldctl_oid = nsldapi_strdup( oid )) == NULL ) {
+ NSLDAPI_FREE( *ctrlp );
+ if ( bvp != NULL ) {
+ ber_bvfree( bvp );
+ }
+ return( LDAP_NO_MEMORY );
+ }
+
+ if ( bvp == NULL ) {
+ (*ctrlp)->ldctl_value.bv_len = 0;
+ (*ctrlp)->ldctl_value.bv_val = NULL;
+ } else {
+ (*ctrlp)->ldctl_value = *bvp; /* struct copy */
+ NSLDAPI_FREE( bvp ); /* free container, not contents! */
+ }
+
+ return( LDAP_SUCCESS );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/countvalues.c b/usr/src/lib/libldap5/sources/ldap/common/countvalues.c
new file mode 100644
index 0000000000..11492075f2
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/countvalues.c
@@ -0,0 +1,54 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * countvalues.c
+ */
+
+#include "ldap-int.h"
+
+int
+LDAP_CALL
+ldap_count_values( char **vals )
+{
+ int i;
+
+ if ( vals == NULL )
+ return( 0 );
+
+ for ( i = 0; vals[i] != NULL; i++ )
+ ; /* NULL */
+
+ return( i );
+}
+
+int
+LDAP_CALL
+ldap_count_values_len( struct berval **vals )
+{
+ return( ldap_count_values( (char **) vals ) );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/cram_md5.c b/usr/src/lib/libldap5/sources/ldap/common/cram_md5.c
new file mode 100644
index 0000000000..7b662829c7
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/cram_md5.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+#include <sys/types.h>
+#include <strings.h>
+#include "sec.h"
+
+/* text is the challenge, key is the password, digest is an allocated
+ buffer (min 16 chars) which will contain the resulting digest */
+void hmac_md5(unsigned char *text, int text_len, unsigned char *key,
+ int key_len, unsigned char *digest)
+{
+ MD5_CTX context;
+ unsigned char k_ipad[65];
+ unsigned char k_opad[65];
+ unsigned char tk[16];
+ int i;
+
+ if (key_len > 64){
+ MD5_CTX tctx;
+
+ (void) MD5Init(&tctx);
+ (void) MD5Update(&tctx, key, key_len);
+ (void) MD5Final(tk, &tctx);
+ key = tk;
+ key_len = 16;
+ }
+
+ bzero(k_ipad, sizeof (k_ipad));
+ bzero(k_opad, sizeof (k_opad));
+ bcopy(key, k_ipad, key_len);
+ bcopy(key, k_opad, key_len);
+
+ for (i=0; i<64; i++){
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* Perform inner MD5 */
+ (void) MD5Init(&context);
+ (void) MD5Update(&context, k_ipad, 64);
+ (void) MD5Update(&context, text, text_len);
+ (void) MD5Final(digest, &context);
+
+ /* Perform outer MD5 */
+ (void) MD5Init(&context);
+ (void) MD5Update(&context, k_opad, 64);
+ (void) MD5Update(&context, digest, 16);
+
+ (void) MD5Final(digest, &context);
+
+ return;
+}
+
+int ldap_sasl_cram_md5_bind_s(
+ LDAP *ld,
+ char *dn,
+ struct berval *cred,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
+{
+ int res;
+ struct berval *challenge = NULL;
+ struct berval resp;
+ unsigned char digest[16];
+ char *theHDigest;
+
+ if (dn == NULL){
+ return (LDAP_PARAM_ERROR);
+ }
+
+ bzero(digest, sizeof (digest));
+
+ if ((res = ldap_sasl_bind_s(ld, NULL, LDAP_SASL_CRAM_MD5, NULL, serverctrls, clientctrls, &challenge))
+ != LDAP_SASL_BIND_IN_PROGRESS){
+ return (res);
+ }
+ if (challenge == NULL){
+ return (LDAP_PARAM_ERROR);
+ }
+
+ LDAPDebug (LDAP_DEBUG_TRACE, "SASL challenge: %s\n", challenge->bv_val, 0, 0);
+
+ hmac_md5((unsigned char *)challenge->bv_val, challenge->bv_len,
+ (unsigned char *)cred->bv_val, cred->bv_len, digest);
+ ber_bvfree(challenge);
+ challenge = NULL;
+
+ theHDigest = hexa_print(digest, 16);
+ if (theHDigest == NULL){
+ return (LDAP_NO_MEMORY);
+ }
+
+ resp.bv_len = (strlen(dn) + 32 + 1);
+ if ((resp.bv_val = (char *)malloc(resp.bv_len+1)) == NULL) {
+ return(LDAP_NO_MEMORY);
+ }
+
+ sprintf(resp.bv_val, "%s %s", dn, theHDigest);
+ free(theHDigest);
+
+ LDAPDebug (LDAP_DEBUG_TRACE, "SASL response: %s\n", resp.bv_val, 0, 0);
+ res = ldap_sasl_bind_s(ld, NULL, LDAP_SASL_CRAM_MD5, &resp, serverctrls, clientctrls, &challenge);
+
+ free(resp.bv_val);
+ return (res);
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/delete.c b/usr/src/lib/libldap5/sources/ldap/common/delete.c
new file mode 100644
index 0000000000..e8c975bfc5
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/delete.c
@@ -0,0 +1,156 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * delete.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_delete - initiate an ldap delete operation. Parameters:
+ *
+ * ld LDAP descriptor
+ * dn DN of the object to delete
+ *
+ * Example:
+ * msgid = ldap_delete( ld, dn );
+ */
+int
+LDAP_CALL
+ldap_delete( LDAP *ld, const char *dn )
+{
+ int msgid;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_delete\n", 0, 0, 0 );
+
+ if ( ldap_delete_ext( ld, dn, NULL, NULL, &msgid ) == LDAP_SUCCESS ) {
+ return( msgid );
+ } else {
+ return( -1 ); /* error is in ld handle */
+ }
+}
+
+int
+LDAP_CALL
+ldap_delete_ext( LDAP *ld, const char *dn, LDAPControl **serverctrls,
+ LDAPControl **clientctrls, int *msgidp )
+{
+ BerElement *ber;
+ int rc, lderr;
+
+ /*
+ * A delete request looks like this:
+ * DelRequet ::= DistinguishedName,
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_delete_ext\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( msgidp ))
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ *msgidp = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ /* see if we should add to the cache */
+ if ( ld->ld_cache_on && ld->ld_cache_delete != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_delete)( ld, *msgidp, LDAP_REQ_DELETE,
+ dn )) != 0 ) {
+ *msgidp = rc;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+
+ /* create a message to send */
+ if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( lderr );
+ }
+
+ if ( ber_printf( ber, "{its", *msgidp, LDAP_REQ_DELETE, dn )
+ == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_DELETE,
+ (char *)dn, ber );
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_delete_s( LDAP *ld, const char *dn )
+{
+ return( ldap_delete_ext_s( ld, dn, NULL, NULL ));
+}
+
+int
+LDAP_CALL
+ldap_delete_ext_s( LDAP *ld, const char *dn, LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
+{
+ int err, msgid;
+ LDAPMessage *res;
+
+ if (( err = ldap_delete_ext( ld, dn, serverctrls, clientctrls,
+ &msgid )) != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res ) == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ return( ldap_result2error( ld, res, 1 ) );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/digest_md5.c b/usr/src/lib/libldap5/sources/ldap/common/digest_md5.c
new file mode 100644
index 0000000000..fe9434bef3
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/digest_md5.c
@@ -0,0 +1,841 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright (c) 1998-1999 Innosoft International, Inc. All Rights Reserved.
+ *
+ * Copyright (c) 1996-1997 Critical Angle Inc. All Rights Reserved.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <md5.h>
+#include <sys/time.h>
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+/*
+ * DIGEST-MD5 SASL Mechanism
+ */
+
+/* use this instead of "const unsigned char" to eliminate compiler warnings */
+typedef /* const */ unsigned char CONST_UCHAR;
+
+/* size of a digest result */
+#define DIGEST_SIZE 16
+
+/* size of a digest hex string */
+#define DIGEST_HEX_SIZE (DIGEST_SIZE * 2 + 1)
+
+/*
+ * extra bytes which a client response needs in addition to size of
+ * server challenge */
+#define DIGEST_CLIENT_EXTRA (DIGEST_HEX_SIZE + 128)
+
+/* erase a digest_attrs_t structure */
+#define digest_clear(attrs) memset((attrs), 0, sizeof (digest_attrs_t))
+
+/*
+ * broken-out digest attributes (with quotes removed)
+ * probably not NUL terminated.
+ */
+typedef struct {
+ const char *realm, *nonce, *cnonce, *qop, *user, *resp, *dom;
+ const char *max, *stale, *ncount, *uri, *charset;
+ int rlen, nlen, clen, qlen, ulen, resplen, dlen;
+ int mlen, slen, nclen, urilen, charsetlen;
+ char ncbuf[9];
+} digest_attrs_t;
+
+static const char hextab[] = "0123456789abcdef";
+static CONST_UCHAR colon[] = ":";
+
+/*
+ * Make a nonce (NUL terminated)
+ * buf -- buffer for result
+ * maxlen -- max length of result
+ * returns final length or -1 on error
+ */
+static int
+digest_nonce(char *buf, int maxlen)
+{
+ /*
+ * it shouldn't matter too much if two threads step on this counter
+ * at the same time, but mutexing it wouldn't hurt
+ */
+ static int counter;
+ char *dst;
+ int len;
+ struct chal_info {
+ time_t mytime;
+ unsigned char digest[16];
+ } cinfo;
+ MD5_CTX ctx;
+ long r;
+ static int set_rand = 0;
+ unsigned char *p;
+ int j;
+ int fd;
+ int got_random;
+
+ /* initialize challenge */
+ if (maxlen < 2 * sizeof (cinfo))
+ return (-1);
+ dst = buf;
+
+ /* get a timestamp */
+ time(&cinfo.mytime);
+
+ /* get some randomness */
+
+ got_random = 0;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd != -1) {
+ got_random =
+ (read(fd, &r, sizeof (r)) == sizeof (r));
+ close(fd);
+ }
+
+ if (!got_random) {
+ if (set_rand == 0) {
+ struct timeval tv;
+
+ r = cinfo.mytime - (getpid() *65536) + (random() & 0xffff);
+
+ gettimeofday(&tv, NULL);
+ r ^= tv.tv_usec;
+ r ^= gethostid();
+
+ srandom(r);
+ set_rand = 1;
+ }
+
+ r = random();
+ }
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char *) &r, sizeof (r));
+ MD5Update(&ctx, (unsigned char *) &counter, sizeof (counter));
+ ++counter;
+ MD5Final(cinfo.digest, &ctx);
+
+ /* compute hex for result */
+ for (j = 0, p = (unsigned char *)&cinfo; j < sizeof (cinfo); ++j) {
+ dst[j * 2] = hextab[p[j] >> 4];
+ dst[j * 2 + 1] = hextab[p[j] & 0xf];
+ }
+
+ /* take the entire time_t, plus at least 6 bytes of MD5 output */
+ len = ((sizeof (time_t) + 6) * 2);
+ dst += len;
+ maxlen -= len;
+
+ *dst = '\0';
+
+ return (dst - buf);
+}
+
+/*
+ * if the string is entirely in the 8859-1 subset of UTF-8, then translate
+ * to 8859-1 prior to MD5
+ */
+static void
+MD5_UTF8_8859_1(MD5_CTX *ctx, CONST_UCHAR *base, int len)
+{
+ CONST_UCHAR *scan, *end;
+ unsigned char cbuf;
+
+ end = base + len;
+ for (scan = base; scan < end; ++scan) {
+ if (*scan > 0xC3) break; /* abort if outside 8859-1 */
+ if (*scan >= 0xC0 && *scan <= 0xC3) {
+ if (++scan == end || *scan < 0x80 || *scan > 0xBF) break;
+ }
+ }
+ /* if we found a character outside 8859-1, don't alter string */
+ if (scan < end) {
+ MD5Update(ctx, base, len);
+ return;
+ }
+
+ /* convert to 8859-1 prior to applying hash */
+ do {
+ for (scan = base; scan < end && *scan < 0xC0; ++scan)
+ ;
+ if (scan != base) MD5Update(ctx, base, scan - base);
+ if (scan + 1 >= end) break;
+ cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
+ MD5Update(ctx, &cbuf, 1);
+ base = scan + 2;
+ } while (base < end);
+}
+
+/*
+ * Compute MD5( "<user>:<realm>:<pass>" )
+ * if use8859_1 is non-zero, then user/realm is 8859-1 charset
+ * if supplied lengths are 0, strlen() is used
+ * places result in hash_pass (of size DIGEST_SIZE) and returns it.
+ */
+static unsigned char *
+digest_hash_pass(const char *user, int ulen, const char *realm, int rlen,
+ const char *pass, int passlen, int use8859_1,
+ unsigned char *hash_pass)
+{
+ MD5_CTX ctx;
+
+ MD5Init(&ctx);
+ if (ulen == 0) ulen = strlen(user);
+ if (use8859_1) {
+ MD5Update(&ctx, (CONST_UCHAR *) user, ulen);
+ } else {
+ MD5_UTF8_8859_1(&ctx, (CONST_UCHAR *) user, ulen);
+ }
+ MD5Update(&ctx, colon, 1);
+ if (rlen == 0) rlen = strlen(realm);
+ if (use8859_1) {
+ MD5Update(&ctx, (CONST_UCHAR *) realm, rlen);
+ } else {
+ MD5_UTF8_8859_1(&ctx, (CONST_UCHAR *) realm, rlen);
+ }
+ MD5Update(&ctx, colon, 1);
+ if (passlen == 0) passlen = strlen(pass);
+ MD5Update(&ctx, (CONST_UCHAR *) pass, passlen);
+ MD5Final(hash_pass, &ctx);
+
+ return (hash_pass);
+}
+
+/*
+ * Compute MD5("<hash_pass>:<nonce>:<cnonce>")
+ * places result in hash_a1 and returns hash_a1
+ * note that hash_pass and hash_a1 may be the same
+ */
+static unsigned char *
+digest_hash_a1(const digest_attrs_t *attr, CONST_UCHAR *hash_pass,
+ unsigned char *hash_a1)
+{
+ MD5_CTX ctx;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, hash_pass, DIGEST_SIZE);
+ MD5Update(&ctx, colon, 1);
+ MD5Update(&ctx, (CONST_UCHAR *) attr->nonce, attr->nlen);
+ MD5Update(&ctx, colon, 1);
+ MD5Update(&ctx, (CONST_UCHAR *) attr->cnonce, attr->clen);
+ MD5Final(hash_a1, &ctx);
+
+ return (hash_a1);
+}
+
+/*
+ * calculate hash response for digest auth.
+ * outresp must be buffer of at least DIGEST_HEX_SIZE
+ * outresp and hex_int may be the same
+ * method may be NULL if mlen is 0
+ */
+static void
+digest_calc_resp(const digest_attrs_t *attr,
+ CONST_UCHAR *hash_a1, const char *method, int mlen,
+ CONST_UCHAR *hex_int, char *outresp)
+{
+ static CONST_UCHAR defncount[] = ":00000001:";
+ static CONST_UCHAR empty_hex_int[] =
+ "00000000000000000000000000000000";
+ MD5_CTX ctx;
+ unsigned char resp[DIGEST_SIZE];
+ unsigned char *hex_a1 = (unsigned char *) outresp;
+ unsigned char *hex_a2 = (unsigned char *) outresp;
+ unsigned j;
+
+ /* compute hash of A2 and put in resp */
+ MD5Init(&ctx);
+ if (mlen == 0 && method != NULL) mlen = strlen(method);
+ if (mlen) MD5Update(&ctx, (CONST_UCHAR *) method, mlen);
+ MD5Update(&ctx, colon, 1);
+ if (attr->urilen != 0) {
+ MD5Update(&ctx, (CONST_UCHAR *) attr->uri, attr->urilen);
+ }
+ if (attr->qlen != 4 || strncasecmp(attr->qop, "auth", 4) != 0) {
+ MD5Update(&ctx, colon, 1);
+ if (hex_int == NULL) hex_int = empty_hex_int;
+ MD5Update(&ctx, hex_int, DIGEST_SIZE * 2);
+ }
+ MD5Final(resp, &ctx);
+
+ /* compute hex_a1 from hash_a1 */
+ for (j = 0; j < DIGEST_SIZE; ++j) {
+ hex_a1[j * 2] = hextab[hash_a1[j] >> 4];
+ hex_a1[j * 2 + 1] = hextab[hash_a1[j] & 0xf];
+ }
+
+ /* compute response */
+ MD5Init(&ctx);
+ MD5Update(&ctx, hex_a1, DIGEST_SIZE * 2);
+ MD5Update(&ctx, colon, 1);
+ MD5Update(&ctx, (CONST_UCHAR *) attr->nonce, attr->nlen);
+ if (attr->ncount != NULL) {
+ MD5Update(&ctx, colon, 1);
+ MD5Update(&ctx, (CONST_UCHAR *) attr->ncount, attr->nclen);
+ MD5Update(&ctx, colon, 1);
+ } else {
+ MD5Update(&ctx, defncount, sizeof (defncount) - 1);
+ }
+ MD5Update(&ctx, (CONST_UCHAR *) attr->cnonce, attr->clen);
+ MD5Update(&ctx, colon, 1);
+ MD5Update(&ctx, (CONST_UCHAR *) attr->qop, attr->qlen);
+ MD5Update(&ctx, colon, 1);
+
+ /* compute hex_a2 from hash_a2 */
+ for (j = 0; j < DIGEST_SIZE; ++j) {
+ hex_a2[j * 2] = hextab[resp[j] >> 4];
+ hex_a2[j * 2 + 1] = hextab[resp[j] & 0xf];
+ }
+ MD5Update(&ctx, hex_a2, DIGEST_SIZE * 2);
+ MD5Final(resp, &ctx);
+
+ /* generate hex output */
+ for (j = 0; j < DIGEST_SIZE; ++j) {
+ outresp[j * 2] = hextab[resp[j] >> 4];
+ outresp[j * 2 + 1] = hextab[resp[j] & 0xf];
+ }
+ outresp[DIGEST_SIZE * 2] = '\0';
+ memset(resp, 0, sizeof (resp));
+}
+
+/*
+ * generate the client response from attributes
+ * either one of hash_pass and hash_a1 may be NULL
+ * hash_a1 is used on re-authentication and takes precedence over hash_pass
+ */
+static int
+digest_client_resp(const char *method, int mlen,
+ CONST_UCHAR *hash_pass, CONST_UCHAR *hash_a1,
+ digest_attrs_t *attr, /* in/out attributes */
+ char *outbuf, int maxout, int *plen)
+{
+#define prefixsize (sizeof (prefix) - 4 * 4 - 1)
+#define suffixsize (sizeof (rstr) + sizeof (qstr) - 1 + DIGEST_SIZE * 2)
+ static const char prefix[] =
+ "username=\"%.*s\",realm=\"%.*s\",nonce=\"%.*s\",nc=%.*s,cnonce=\"";
+ static const char rstr[] = "\",response=";
+ static const char qstr[] = ",qop=auth";
+ static const char chstr[] = "charset=";
+ char *scan;
+ int len;
+ char hexbuf[DIGEST_HEX_SIZE];
+ unsigned char hashbuf[DIGEST_SIZE];
+
+ /* make sure we have mandatory attributes */
+ if (attr->nonce == NULL || attr->nlen == 0 ||
+ attr->realm == NULL || attr->rlen == 0 ||
+ attr->qop == NULL || attr->qlen == 0 ||
+ (attr->nclen != 0 && attr->nclen != 8)) {
+ return (-5);
+ }
+ if (mlen != 0 && method == NULL)
+ return (-7);
+
+ /* initialize ncount */
+ if (attr->ncount == NULL) {
+ strcpy(attr->ncbuf, "00000001");
+ attr->ncount = attr->ncbuf;
+ attr->nclen = 8;
+ } else if (attr->ncount == attr->ncbuf) {
+ /* increment ncount */
+ scan = attr->ncbuf + 7;
+ while (scan >= attr->ncbuf) {
+ if (*scan == '9') {
+ *scan = 'a';
+ break;
+ } else if (*scan != 'f') {
+ ++*scan;
+ break;
+ }
+ *scan = '0';
+ --scan;
+ }
+ }
+
+ /* sanity check length */
+ len = prefixsize + attr->ulen + attr->rlen + attr->nlen + attr->nclen;
+ if (attr->charsetlen > 0) {
+ /* includes 1 for a comma */
+ len += sizeof (chstr) + attr->charsetlen;
+ }
+ if (len + suffixsize >= maxout)
+ return (-3);
+
+ scan = outbuf;
+
+ /* charset */
+ if (attr->charsetlen > 0 && attr->charset != NULL) {
+ memcpy(scan, chstr, sizeof (chstr) - 1);
+ scan += sizeof (chstr) - 1;
+ memcpy(scan, attr->charset, attr->charsetlen);
+ scan += attr->charsetlen;
+ *scan++ = ',';
+ }
+
+ /* generate string up to the client nonce */
+ sprintf(scan, prefix, attr->ulen, attr->user,
+ attr->rlen, attr->realm, attr->nlen, attr->nonce,
+ attr->nclen, attr->ncount);
+ scan = outbuf + len;
+
+ /* generate client nonce */
+ len = digest_nonce(scan, maxout - (scan - outbuf));
+ if (len < 0)
+ return (len);
+ attr->cnonce = scan;
+ attr->clen = len;
+ scan += len;
+ if (scan - outbuf + suffixsize > maxout)
+ return (-3);
+
+ /* compute response */
+ if (hash_a1 == NULL) {
+ if (hash_pass == NULL)
+ return (-7);
+ hash_a1 = digest_hash_a1(attr, hash_pass, hashbuf);
+ }
+ digest_calc_resp(attr, hash_a1, method, mlen, NULL, hexbuf);
+
+ /* finish it */
+ memcpy(scan, rstr, sizeof (rstr) - 1);
+ scan += sizeof (rstr) - 1;
+ memcpy(scan, hexbuf, DIGEST_SIZE * 2);
+ attr->resp = scan;
+ attr->resplen = DIGEST_SIZE * 2;
+ scan += DIGEST_SIZE * 2;
+ memcpy(scan, qstr, sizeof (qstr));
+
+ /* set final length */
+ if (plen != NULL) *plen = scan - outbuf + sizeof (qstr) - 1;
+
+ return (0);
+}
+
+#define lstreqcase(conststr, val, len) ((len) == sizeof (conststr) - 1 && \
+ strncasecmp((conststr), (val), sizeof (conststr) - 1) == 0)
+
+/* parse a digest auth string */
+static int
+digest_parse(const char *str, int len, digest_attrs_t *attr_out)
+{
+ static const char rstr[] = "realm";
+ static const char nstr[] = "nonce";
+ static const char cstr[] = "cnonce";
+ static const char qstr[] = "qop";
+ static const char ustr[] = "username";
+ static const char respstr[] = "response";
+ static const char dstr[] = "domain";
+ static const char mstr[] = "maxbuf";
+ static const char sstr[] = "stale";
+ static const char ncstr[] = "nc";
+ static const char uristr[] = "digest-uri";
+ static const char charsetstr[] = "charset";
+ const char *scan, *attr, *val, *end;
+ int alen, vlen;
+
+ if (len == 0) len = strlen(str);
+ scan = str;
+ end = str + len;
+ for (;;) {
+ /* skip over commas */
+ while (scan < end && (*scan == ',' || isspace(*scan))) ++scan;
+ /* parse attribute */
+ attr = scan;
+ while (scan < end && *scan != '=') ++scan;
+ alen = scan - attr;
+ if (!alen || scan == end || scan + 1 == end) {
+ return (-5);
+ }
+
+ /* parse value */
+ if (scan[1] == '"') {
+ scan += 2;
+ val = scan;
+ while (scan < end && *scan != '"') {
+ /* skip over "\" quoting, but don't remove it */
+ if (*scan == '\\') {
+ if (scan + 1 == end)
+ return (-5);
+ scan += 2;
+ } else {
+ ++scan;
+ }
+ }
+ vlen = scan - val;
+ if (*scan != '"')
+ return (-5);
+ ++scan;
+ } else {
+ ++scan;
+ val = scan;
+ while (scan < end && *scan != ',') ++scan;
+ vlen = scan - val;
+ }
+ if (!vlen)
+ return (-5);
+
+ /* lookup the attribute */
+ switch (*attr) {
+ case 'c':
+ case 'C':
+ if (lstreqcase(cstr, attr, alen)) {
+ attr_out->cnonce = val;
+ attr_out->clen = vlen;
+ }
+ if (lstreqcase(charsetstr, attr, alen)) {
+ attr_out->charset = val;
+ attr_out->charsetlen = vlen;
+ }
+ break;
+ case 'd':
+ case 'D':
+ if (lstreqcase(dstr, attr, alen)) {
+ attr_out->dom = val;
+ attr_out->dlen = vlen;
+ }
+ if (lstreqcase(uristr, attr, alen)) {
+ attr_out->uri = val;
+ attr_out->urilen = vlen;
+ }
+ break;
+ case 'm':
+ case 'M':
+ if (lstreqcase(mstr, attr, alen)) {
+ attr_out->max = val;
+ attr_out->mlen = vlen;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (lstreqcase(nstr, attr, alen)) {
+ attr_out->nonce = val;
+ attr_out->nlen = vlen;
+ }
+ if (lstreqcase(ncstr, attr, alen)) {
+ attr_out->ncount = val;
+ attr_out->nclen = vlen;
+ }
+ break;
+ case 'q':
+ case 'Q':
+ if (lstreqcase(qstr, attr, alen)) {
+ attr_out->qop = val;
+ attr_out->qlen = vlen;
+ }
+ break;
+ case 'r':
+ case 'R':
+ if (lstreqcase(rstr, attr, alen)) {
+ attr_out->realm = val;
+ attr_out->rlen = vlen;
+ }
+ if (lstreqcase(respstr, attr, alen)) {
+ attr_out->resp = val;
+ attr_out->resplen = vlen;
+ }
+ break;
+ case 's':
+ case 'S':
+ if (lstreqcase(sstr, attr, alen)) {
+ attr_out->stale = val;
+ attr_out->slen = vlen;
+ }
+ break;
+ case 'u':
+ case 'U':
+ if (lstreqcase(ustr, attr, alen)) {
+ attr_out->user = val;
+ attr_out->ulen = vlen;
+ }
+ break;
+ }
+
+ /* we should be at the end of the string or a comma */
+ if (scan == end) break;
+ if (*scan != ',')
+ return (-5);
+ }
+
+ return (0);
+}
+
+static int ldap_digest_md5_encode(
+ const char *challenge,
+ const char *username,
+ const char *passwd,
+ char **digest
+)
+{
+ unsigned char hash_pass[DIGEST_SIZE];
+ digest_attrs_t attrs;
+ char *outbuf;
+ int outlen;
+ int ret;
+
+ /* validate args */
+ if (challenge == NULL || username == NULL || passwd == NULL) {
+ return (LDAP_PARAM_ERROR);
+ }
+
+ /* parse the challenge */
+ digest_clear(&attrs);
+ ret = digest_parse(challenge, 0, &attrs);
+ if (ret != 0)
+ return (LDAP_DECODING_ERROR);
+
+ /* server MUST specify support for charset=utf-8 */
+ if (attrs.charsetlen != 5 ||
+ strncasecmp(attrs.charset, "utf-8", 5) != 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "server did not specify charset=utf-8\n",
+ 0, 0, 0);
+ return (LDAP_NOT_SUPPORTED);
+ }
+
+ /* set up digest attributes */
+ attrs.user = username;
+ attrs.ulen = strlen(attrs.user);
+
+ /* allocate the output buffer */
+ outlen = strlen(challenge) + DIGEST_CLIENT_EXTRA + 1;
+ outbuf = (char *)malloc(outlen);
+ if (outbuf == NULL)
+ return (LDAP_NO_MEMORY);
+
+ /* hash the password */
+ digest_hash_pass(username, 0, attrs.realm, attrs.rlen,
+ passwd, 0, 0, hash_pass),
+
+ /* create the response */
+ ret = digest_client_resp("AUTHENTICATE", 12, hash_pass, NULL,
+ &attrs, outbuf, outlen, &outlen);
+ memset(hash_pass, 0, DIGEST_SIZE);
+ if (ret != 0) {
+ free(outbuf);
+ return (LDAP_DECODING_ERROR);
+ }
+
+ /* null terminate the response */
+ *(outbuf+outlen) = '\0';
+
+ *digest = outbuf;
+ return (LDAP_SUCCESS);
+}
+
+int ldap_x_sasl_digest_md5_bind_s(
+ LDAP *ld,
+ char *user_name,
+ struct berval *cred,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls)
+{
+ struct berval *challenge = NULL;
+ int errnum;
+ char *digest = NULL;
+ struct berval resp;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "ldap_x_sasl_digest_md5_bind_s\n", 0, 0, 0);
+
+ /* Add debug */
+ if (ld == NULL || user_name == NULL || cred == NULL ||
+ cred->bv_val == NULL)
+ return (LDAP_PARAM_ERROR);
+
+ if (ld->ld_version < LDAP_VERSION3)
+ return (LDAP_PARAM_ERROR);
+
+ errnum = ldap_sasl_bind_s(ld, NULL, LDAP_SASL_DIGEST_MD5,
+ NULL, serverctrls, clientctrls, &challenge);
+
+ if (errnum == LDAP_SASL_BIND_IN_PROGRESS) {
+ if (challenge != NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "SASL challenge: %s\n",
+ challenge->bv_val, 0, 0);
+ errnum = ldap_digest_md5_encode(challenge->bv_val,
+ user_name, cred->bv_val, &digest);
+ ber_bvfree(challenge);
+ challenge = NULL;
+ if (errnum == LDAP_SUCCESS) {
+ resp.bv_val = digest;
+ resp.bv_len = strlen(digest);
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "SASL reply: %s\n",
+ digest, 0, 0);
+ errnum = ldap_sasl_bind_s(ld, NULL,
+ LDAP_SASL_DIGEST_MD5, &resp,
+ serverctrls, clientctrls, &challenge);
+ free(digest);
+ }
+ if (challenge != NULL)
+ ber_bvfree(challenge);
+ } else {
+ errnum = LDAP_NO_MEMORY; /* TO DO: What val? */
+ }
+ }
+
+ LDAP_MUTEX_LOCK(ld, LDAP_ERR_LOCK);
+ ld->ld_errno = errnum;
+ LDAP_MUTEX_UNLOCK(ld, LDAP_ERR_LOCK);
+ return (errnum);
+}
+
+static int
+sasl_digest_md5_bind_1(
+ LDAP *ld,
+ char *user_name,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ int *msgidp)
+{
+ if (ld == NULL || user_name == NULL || msgidp == NULL)
+ return (LDAP_PARAM_ERROR);
+
+ if (ld->ld_version < LDAP_VERSION3)
+ return (LDAP_PARAM_ERROR);
+
+ return (ldap_sasl_bind(ld, NULL, LDAP_SASL_DIGEST_MD5,
+ NULL, serverctrls, clientctrls, msgidp));
+}
+
+static int
+sasl_digest_md5_bind_2(
+ LDAP *ld,
+ char *user_name,
+ struct berval *cred,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ LDAPMessage *result,
+ int *msgidp)
+{
+ struct berval *challenge = NULL;
+ struct berval resp;
+ int errnum;
+ char *digest = NULL;
+ int err;
+
+ if (ld == NULL || user_name == NULL || cred == NULL ||
+ cred->bv_val == NULL || result == NULL || msgidp == NULL)
+ return (LDAP_PARAM_ERROR);
+
+ if (ld->ld_version < LDAP_VERSION3)
+ return (LDAP_PARAM_ERROR);
+
+ err = ldap_result2error(ld, result, 0);
+ if (err != LDAP_SASL_BIND_IN_PROGRESS)
+ return (err);
+
+ if ((err = ldap_parse_sasl_bind_result(ld, result, &challenge, 0))
+ != LDAP_SUCCESS)
+ return (err);
+ if (challenge == NULL)
+ return (LDAP_NO_MEMORY);
+
+ err = ldap_digest_md5_encode(challenge->bv_val,
+ user_name, cred->bv_val, &digest);
+ ber_bvfree(challenge);
+
+ if (err == LDAP_SUCCESS) {
+ resp.bv_val = digest;
+ resp.bv_len = strlen(digest);
+ LDAPDebug(LDAP_DEBUG_TRACE, "SASL reply: %s\n",
+ digest, 0, 0);
+ err = ldap_sasl_bind(ld, NULL, LDAP_SASL_DIGEST_MD5,
+ &resp, serverctrls, clientctrls, msgidp);
+ free(digest);
+ }
+ return (err);
+}
+
+int ldap_x_sasl_digest_md5_bind(
+ LDAP *ld,
+ char *user_name,
+ struct berval *cred,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ struct timeval *timeout,
+ LDAPMessage **result)
+{
+ LDAPMessage *res = NULL;
+ int msgid;
+ int rc;
+
+ if (ld == NULL || user_name == NULL || cred == NULL ||
+ result == NULL)
+ return (LDAP_PARAM_ERROR);
+
+ if (ld->ld_version < LDAP_VERSION3)
+ return (LDAP_PARAM_ERROR);
+
+ *result = NULL;
+
+ rc = sasl_digest_md5_bind_1(ld, user_name,
+ serverctrls, clientctrls, &msgid);
+ if (rc != LDAP_SUCCESS)
+ return (rc);
+
+ rc = ldap_result(ld, msgid, 1, timeout, &res);
+ if (rc == -1) {
+ if (res != NULL)
+ ldap_msgfree(res);
+ return (ldap_get_lderrno(ld, NULL, NULL));
+ }
+ rc = ldap_result2error(ld, res, 0);
+ if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
+ *result = res;
+ return (rc);
+ }
+
+ rc = sasl_digest_md5_bind_2(ld, user_name, cred,
+ serverctrls, clientctrls, res, &msgid);
+ ldap_msgfree(res);
+ res = NULL;
+
+ if (rc != LDAP_SUCCESS)
+ return (rc);
+
+ rc = ldap_result(ld, msgid, 1, timeout, &res);
+ if (rc == -1) {
+ if (res != NULL)
+ ldap_msgfree(res);
+ return (ldap_get_lderrno(ld, NULL, NULL));
+ }
+ *result = res;
+ rc = ldap_result2error(ld, res, 0);
+ return (rc);
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/disptmpl.c b/usr/src/lib/libldap5/sources/ldap/common/disptmpl.c
new file mode 100644
index 0000000000..216f93af03
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/disptmpl.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * disptmpl.c: display template library routines for LDAP clients
+ */
+
+#include "ldap-int.h"
+#include "disptmpl.h"
+
+static void free_disptmpl( struct ldap_disptmpl *tmpl );
+static int read_next_tmpl( char **bufp, long *blenp,
+ struct ldap_disptmpl **tmplp, int dtversion );
+
+static char *tmploptions[] = {
+ "addable", "modrdn",
+ "altview",
+ NULL
+};
+
+
+static unsigned long tmploptvals[] = {
+ LDAP_DTMPL_OPT_ADDABLE, LDAP_DTMPL_OPT_ALLOWMODRDN,
+ LDAP_DTMPL_OPT_ALTVIEW,
+};
+
+
+static char *itemtypes[] = {
+ "cis", "mls", "dn",
+ "bool", "jpeg", "jpegbtn",
+ "fax", "faxbtn", "audiobtn",
+ "time", "date", "url",
+ "searchact", "linkact", "adddnact",
+ "addact", "verifyact", "mail",
+ NULL
+};
+
+static unsigned long itemsynids[] = {
+ LDAP_SYN_CASEIGNORESTR, LDAP_SYN_MULTILINESTR, LDAP_SYN_DN,
+ LDAP_SYN_BOOLEAN, LDAP_SYN_JPEGIMAGE, LDAP_SYN_JPEGBUTTON,
+ LDAP_SYN_FAXIMAGE, LDAP_SYN_FAXBUTTON, LDAP_SYN_AUDIOBUTTON,
+ LDAP_SYN_TIME, LDAP_SYN_DATE, LDAP_SYN_LABELEDURL,
+ LDAP_SYN_SEARCHACTION, LDAP_SYN_LINKACTION, LDAP_SYN_ADDDNACTION,
+ LDAP_SYN_ADDDNACTION, LDAP_SYN_VERIFYDNACTION,LDAP_SYN_RFC822ADDR,
+};
+
+
+static char *itemoptions[] = {
+ "ro", "sort",
+ "1val", "hide",
+ "required", "hideiffalse",
+ NULL
+};
+
+
+static unsigned long itemoptvals[] = {
+ LDAP_DITEM_OPT_READONLY, LDAP_DITEM_OPT_SORTVALUES,
+ LDAP_DITEM_OPT_SINGLEVALUED, LDAP_DITEM_OPT_HIDEIFEMPTY,
+ LDAP_DITEM_OPT_VALUEREQUIRED, LDAP_DITEM_OPT_HIDEIFFALSE,
+};
+
+
+#define ADDEF_CONSTANT "constant"
+#define ADDEF_ADDERSDN "addersdn"
+
+
+int
+LDAP_CALL
+ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp )
+{
+ FILE *fp;
+ char *buf;
+ long rlen, len;
+ int rc, eof;
+
+ *tmpllistp = NULLDISPTMPL;
+
+ if (( fp = fopen( file, "r" )) == NULL ) {
+ return( LDAP_TMPL_ERR_FILE );
+ }
+
+ if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */
+ fclose( fp );
+ return( LDAP_TMPL_ERR_FILE );
+ }
+
+ len = ftell( fp );
+
+ if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */
+ fclose( fp );
+ return( LDAP_TMPL_ERR_FILE );
+ }
+
+ if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
+ fclose( fp );
+ return( LDAP_TMPL_ERR_MEM );
+ }
+
+ rlen = fread( buf, 1, (size_t)len, fp );
+ eof = feof( fp );
+ fclose( fp );
+
+ if ( rlen != len && !eof ) { /* error: didn't get the whole file */
+ NSLDAPI_FREE( buf );
+ return( LDAP_TMPL_ERR_FILE );
+ }
+
+ rc = ldap_init_templates_buf( buf, rlen, tmpllistp );
+ NSLDAPI_FREE( buf );
+
+ return( rc );
+}
+
+
+int
+LDAP_CALL
+ldap_init_templates_buf( char *buf, long buflen,
+ struct ldap_disptmpl **tmpllistp )
+{
+ int rc = 0, version;
+ char **toks;
+ struct ldap_disptmpl *prevtmpl, *tmpl;
+
+ *tmpllistp = prevtmpl = NULLDISPTMPL;
+
+ if ( ldap_next_line_tokens( &buf, &buflen, &toks ) != 2 ||
+ strcasecmp( toks[ 0 ], "version" ) != 0 ) {
+ ldap_free_strarray( toks );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ version = atoi( toks[ 1 ] );
+ ldap_free_strarray( toks );
+ if ( version != LDAP_TEMPLATE_VERSION ) {
+ return( LDAP_TMPL_ERR_VERSION );
+ }
+
+ while ( buflen > 0 && ( rc = read_next_tmpl( &buf, &buflen, &tmpl,
+ version )) == 0 && tmpl != NULLDISPTMPL ) {
+ if ( prevtmpl == NULLDISPTMPL ) {
+ *tmpllistp = tmpl;
+ } else {
+ prevtmpl->dt_next = tmpl;
+ }
+ prevtmpl = tmpl;
+ }
+
+ if ( rc != 0 ) {
+ ldap_free_templates( *tmpllistp );
+ }
+
+ return( rc );
+}
+
+
+
+void
+LDAP_CALL
+ldap_free_templates( struct ldap_disptmpl *tmpllist )
+{
+ struct ldap_disptmpl *tp, *nexttp;
+
+ if ( tmpllist != NULL ) {
+ for ( tp = tmpllist; tp != NULL; tp = nexttp ) {
+ nexttp = tp->dt_next;
+ free_disptmpl( tp );
+ }
+ }
+}
+
+
+static void
+free_disptmpl( struct ldap_disptmpl *tmpl )
+{
+ if ( tmpl != NULL ) {
+ if ( tmpl->dt_name != NULL ) {
+ NSLDAPI_FREE( tmpl->dt_name );
+ }
+
+ if ( tmpl->dt_pluralname != NULL ) {
+ NSLDAPI_FREE( tmpl->dt_pluralname );
+ }
+
+ if ( tmpl->dt_iconname != NULL ) {
+ NSLDAPI_FREE( tmpl->dt_iconname );
+ }
+
+ if ( tmpl->dt_authattrname != NULL ) {
+ NSLDAPI_FREE( tmpl->dt_authattrname );
+ }
+
+ if ( tmpl->dt_defrdnattrname != NULL ) {
+ NSLDAPI_FREE( tmpl->dt_defrdnattrname );
+ }
+
+ if ( tmpl->dt_defaddlocation != NULL ) {
+ NSLDAPI_FREE( tmpl->dt_defaddlocation );
+ }
+
+ if ( tmpl->dt_oclist != NULL ) {
+ struct ldap_oclist *ocp, *nextocp;
+
+ for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = nextocp ) {
+ nextocp = ocp->oc_next;
+ ldap_free_strarray( ocp->oc_objclasses );
+ NSLDAPI_FREE( ocp );
+ }
+ }
+
+ if ( tmpl->dt_adddeflist != NULL ) {
+ struct ldap_adddeflist *adp, *nextadp;
+
+ for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = nextadp ) {
+ nextadp = adp->ad_next;
+ if( adp->ad_attrname != NULL ) {
+ NSLDAPI_FREE( adp->ad_attrname );
+ }
+ if( adp->ad_value != NULL ) {
+ NSLDAPI_FREE( adp->ad_value );
+ }
+ NSLDAPI_FREE( adp );
+ }
+ }
+
+ if ( tmpl->dt_items != NULL ) {
+ struct ldap_tmplitem *rowp, *nextrowp, *colp, *nextcolp;
+
+ for ( rowp = tmpl->dt_items; rowp != NULL; rowp = nextrowp ) {
+ nextrowp = rowp->ti_next_in_col;
+ for ( colp = rowp; colp != NULL; colp = nextcolp ) {
+ nextcolp = colp->ti_next_in_row;
+ if ( colp->ti_attrname != NULL ) {
+ NSLDAPI_FREE( colp->ti_attrname );
+ }
+ if ( colp->ti_label != NULL ) {
+ NSLDAPI_FREE( colp->ti_label );
+ }
+ if ( colp->ti_args != NULL ) {
+ ldap_free_strarray( colp->ti_args );
+ }
+ NSLDAPI_FREE( colp );
+ }
+ }
+ }
+
+ NSLDAPI_FREE( tmpl );
+ }
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_first_disptmpl( struct ldap_disptmpl *tmpllist )
+{
+ return( tmpllist );
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
+ struct ldap_disptmpl *tmpl )
+{
+ return( tmpl == NULLDISPTMPL ? tmpl : tmpl->dt_next );
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_name2template( char *name, struct ldap_disptmpl *tmpllist )
+{
+ struct ldap_disptmpl *dtp;
+
+ for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
+ dtp = ldap_next_disptmpl( tmpllist, dtp )) {
+ if ( strcasecmp( name, dtp->dt_name ) == 0 ) {
+ return( dtp );
+ }
+ }
+
+ return( NULLDISPTMPL );
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist )
+{
+ struct ldap_disptmpl *dtp;
+ struct ldap_oclist *oclp;
+ int i, j, needcnt, matchcnt;
+
+ if ( tmpllist == NULL || oclist == NULL || oclist[ 0 ] == NULL ) {
+ return( NULLDISPTMPL );
+ }
+
+ for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
+ dtp = ldap_next_disptmpl( tmpllist, dtp )) {
+ for ( oclp = dtp->dt_oclist; oclp != NULLOCLIST;
+ oclp = oclp->oc_next ) {
+ needcnt = matchcnt = 0;
+ for ( i = 0; oclp->oc_objclasses[ i ] != NULL; ++i ) {
+ for ( j = 0; oclist[ j ] != NULL; ++j ) {
+ if ( strcasecmp( oclist[ j ], oclp->oc_objclasses[ i ] )
+ == 0 ) {
+ ++matchcnt;
+ }
+ }
+ ++needcnt;
+ }
+
+ if ( matchcnt == needcnt ) {
+ return( dtp );
+ }
+ }
+ }
+
+ return( NULLDISPTMPL );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_first_tmplrow( struct ldap_disptmpl *tmpl )
+{
+ return( tmpl->dt_items );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
+{
+ return( row == NULLTMPLITEM ? row : row->ti_next_in_col );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
+{
+ return( row );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
+ struct ldap_tmplitem *col )
+{
+ return( col == NULLTMPLITEM ? col : col->ti_next_in_row );
+}
+
+
+char **
+LDAP_CALL
+ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs,
+ int exclude, unsigned long syntaxmask )
+{
+/*
+ * this routine should filter out duplicate attributes...
+ */
+ struct ldap_tmplitem *tirowp, *ticolp;
+ int i, attrcnt, memerr;
+ char **attrs;
+
+ attrcnt = 0;
+ memerr = 0;
+
+ if (( attrs = (char **)NSLDAPI_MALLOC( sizeof( char * ))) == NULL ) {
+ return( NULL );
+ }
+
+ if ( includeattrs != NULL ) {
+ for ( i = 0; !memerr && includeattrs[ i ] != NULL; ++i ) {
+ if (( attrs = (char **)NSLDAPI_REALLOC( attrs, ( attrcnt + 2 ) *
+ sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
+ nsldapi_strdup( includeattrs[ i ] )) == NULL ) {
+ memerr = 1;
+ } else {
+ attrs[ attrcnt ] = NULL;
+ }
+ }
+ }
+
+ for ( tirowp = ldap_first_tmplrow( tmpl );
+ !memerr && tirowp != NULLTMPLITEM;
+ tirowp = ldap_next_tmplrow( tmpl, tirowp )) {
+ for ( ticolp = ldap_first_tmplcol( tmpl, tirowp );
+ ticolp != NULLTMPLITEM;
+ ticolp = ldap_next_tmplcol( tmpl, tirowp, ticolp )) {
+
+ if ( syntaxmask != 0 ) {
+ if (( exclude &&
+ ( syntaxmask & ticolp->ti_syntaxid ) != 0 ) ||
+ ( !exclude &&
+ ( syntaxmask & ticolp->ti_syntaxid ) == 0 )) {
+ continue;
+ }
+ }
+
+ if ( ticolp->ti_attrname != NULL ) {
+ if (( attrs = (char **)NSLDAPI_REALLOC( attrs, ( attrcnt + 2 )
+ * sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
+ nsldapi_strdup( ticolp->ti_attrname )) == NULL ) {
+ memerr = 1;
+ } else {
+ attrs[ attrcnt ] = NULL;
+ }
+ }
+ }
+ }
+
+ if ( memerr || attrcnt == 0 ) {
+ for ( i = 0; i < attrcnt; ++i ) {
+ if ( attrs[ i ] != NULL ) {
+ NSLDAPI_FREE( attrs[ i ] );
+ }
+ }
+
+ NSLDAPI_FREE( (char *)attrs );
+ return( NULL );
+ }
+
+ return( attrs );
+}
+
+
+static int
+read_next_tmpl( char **bufp, long *blenp, struct ldap_disptmpl **tmplp,
+ int dtversion )
+{
+ int i, j, tokcnt, samerow, adsource;
+ char **toks, *itemopts;
+ struct ldap_disptmpl *tmpl = NULL;
+ struct ldap_oclist *ocp = NULL, *prevocp = NULL;
+ struct ldap_adddeflist *adp = NULL, *prevadp = NULL;
+ struct ldap_tmplitem *rowp = NULL, *ip = NULL, *previp = NULL;
+
+ /*
+ * template name comes first
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ return( tokcnt == 0 ? 0 : LDAP_TMPL_ERR_SYNTAX );
+ }
+
+ if (( tmpl = (struct ldap_disptmpl *)NSLDAPI_CALLOC( 1,
+ sizeof( struct ldap_disptmpl ))) == NULL ) {
+ ldap_free_strarray( toks );
+ return( LDAP_TMPL_ERR_MEM );
+ }
+ tmpl->dt_name = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * template plural name comes next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ tmpl->dt_pluralname = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * template icon name is next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ tmpl->dt_iconname = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * template options come next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) < 1 ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ for ( i = 0; toks[ i ] != NULL; ++i ) {
+ for ( j = 0; tmploptions[ j ] != NULL; ++j ) {
+ if ( strcasecmp( toks[ i ], tmploptions[ j ] ) == 0 ) {
+ tmpl->dt_options |= tmploptvals[ j ];
+ }
+ }
+ }
+ ldap_free_strarray( toks );
+
+ /*
+ * object class list is next
+ */
+ while (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+ if (( ocp = (struct ldap_oclist *)NSLDAPI_CALLOC( 1,
+ sizeof( struct ldap_oclist ))) == NULL ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_MEM );
+ }
+ ocp->oc_objclasses = toks;
+ if ( tmpl->dt_oclist == NULL ) {
+ tmpl->dt_oclist = ocp;
+ } else {
+ prevocp->oc_next = ocp;
+ }
+ prevocp = ocp;
+ }
+ if ( tokcnt < 0 ) {
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+
+ /*
+ * read name of attribute to authenticate as
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ if ( toks[ 0 ][ 0 ] != '\0' ) {
+ tmpl->dt_authattrname = toks[ 0 ];
+ } else {
+ NSLDAPI_FREE( toks[ 0 ] );
+ }
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * read default attribute to use for RDN
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ tmpl->dt_defrdnattrname = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * read default location for new entries
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ if ( toks[ 0 ][ 0 ] != '\0' ) {
+ tmpl->dt_defaddlocation = toks[ 0 ];
+ } else {
+ NSLDAPI_FREE( toks[ 0 ] );
+ }
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * read list of rules used to define default values for new entries
+ */
+ while (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+ if ( strcasecmp( ADDEF_CONSTANT, toks[ 0 ] ) == 0 ) {
+ adsource = LDAP_ADSRC_CONSTANTVALUE;
+ } else if ( strcasecmp( ADDEF_ADDERSDN, toks[ 0 ] ) == 0 ) {
+ adsource = LDAP_ADSRC_ADDERSDN;
+ } else {
+ adsource = 0;
+ }
+ if ( adsource == 0 || tokcnt < 2 ||
+ ( adsource == LDAP_ADSRC_CONSTANTVALUE && tokcnt != 3 ) ||
+ ( adsource == LDAP_ADSRC_ADDERSDN && tokcnt != 2 )) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+
+ if (( adp = (struct ldap_adddeflist *)NSLDAPI_CALLOC( 1,
+ sizeof( struct ldap_adddeflist ))) == NULL ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_MEM );
+ }
+ adp->ad_source = adsource;
+ adp->ad_attrname = toks[ 1 ];
+ if ( adsource == LDAP_ADSRC_CONSTANTVALUE ) {
+ adp->ad_value = toks[ 2 ];
+ }
+ NSLDAPI_FREE( toks[ 0 ] );
+ NSLDAPI_FREE( (char *)toks );
+
+ if ( tmpl->dt_adddeflist == NULL ) {
+ tmpl->dt_adddeflist = adp;
+ } else {
+ prevadp->ad_next = adp;
+ }
+ prevadp = adp;
+ }
+
+ /*
+ * item list is next
+ */
+ samerow = 0;
+ while (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+ if ( strcasecmp( toks[ 0 ], "item" ) == 0 ) {
+ if ( tokcnt < 4 ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+
+ if (( ip = (struct ldap_tmplitem *)NSLDAPI_CALLOC( 1,
+ sizeof( struct ldap_tmplitem ))) == NULL ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_MEM );
+ }
+
+ /*
+ * find syntaxid from config file string
+ */
+ while (( itemopts = strrchr( toks[ 1 ], ',' )) != NULL ) {
+ *itemopts++ = '\0';
+ for ( i = 0; itemoptions[ i ] != NULL; ++i ) {
+ if ( strcasecmp( itemopts, itemoptions[ i ] ) == 0 ) {
+ break;
+ }
+ }
+ if ( itemoptions[ i ] == NULL ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ ip->ti_options |= itemoptvals[ i ];
+ }
+
+ for ( i = 0; itemtypes[ i ] != NULL; ++i ) {
+ if ( strcasecmp( toks[ 1 ], itemtypes[ i ] ) == 0 ) {
+ break;
+ }
+ }
+ if ( itemtypes[ i ] == NULL ) {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+
+ NSLDAPI_FREE( toks[ 0 ] );
+ NSLDAPI_FREE( toks[ 1 ] );
+ ip->ti_syntaxid = itemsynids[ i ];
+ ip->ti_label = toks[ 2 ];
+ if ( toks[ 3 ][ 0 ] == '\0' ) {
+ ip->ti_attrname = NULL;
+ NSLDAPI_FREE( toks[ 3 ] );
+ } else {
+ ip->ti_attrname = toks[ 3 ];
+ }
+ if ( toks[ 4 ] != NULL ) { /* extra args. */
+ for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
+ ;
+ }
+ if (( ip->ti_args = (char **)NSLDAPI_CALLOC( i + 1,
+ sizeof( char * ))) == NULL ) {
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_MEM );
+ }
+ for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
+ ip->ti_args[ i ] = toks[ i + 4 ];
+ }
+ }
+ NSLDAPI_FREE( (char *)toks );
+
+ if ( tmpl->dt_items == NULL ) {
+ tmpl->dt_items = rowp = ip;
+ } else if ( samerow ) {
+ previp->ti_next_in_row = ip;
+ } else {
+ rowp->ti_next_in_col = ip;
+ rowp = ip;
+ }
+ previp = ip;
+ samerow = 0;
+ } else if ( strcasecmp( toks[ 0 ], "samerow" ) == 0 ) {
+ ldap_free_strarray( toks );
+ samerow = 1;
+ } else {
+ ldap_free_strarray( toks );
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+ }
+ if ( tokcnt < 0 ) {
+ free_disptmpl( tmpl );
+ return( LDAP_TMPL_ERR_SYNTAX );
+ }
+
+ *tmplp = tmpl;
+ return( 0 );
+}
+
+
+struct tmplerror {
+ int e_code;
+ char *e_reason;
+};
+
+#ifdef SUN
+static struct tmplerror ldap_tmplerrlist[] = {
+ { LDAP_TMPL_ERR_VERSION, 0},
+ { LDAP_TMPL_ERR_MEM, 0},
+ { LDAP_TMPL_ERR_SYNTAX, 0},
+ { LDAP_TMPL_ERR_FILE, 0},
+ { -1, 0 }
+};
+#else
+static struct tmplerror ldap_tmplerrlist[] = {
+ { LDAP_TMPL_ERR_VERSION, "Bad template version" },
+ { LDAP_TMPL_ERR_MEM, "Out of memory" },
+ { LDAP_TMPL_ERR_SYNTAX, "Bad template syntax" },
+ { LDAP_TMPL_ERR_FILE, "File error reading template" },
+ { -1, 0 }
+};
+#endif
+
+char *
+LDAP_CALL
+ldap_tmplerr2string( int err )
+{
+ static int init_flag = 0;
+ int i;
+
+ /* Multiple threads should be ok since they assign same strings */
+ if (init_flag == 0) {
+ ldap_tmplerrlist[0].e_reason =
+ dgettext(TEXT_DOMAIN, "Bad template version");
+ ldap_tmplerrlist[1].e_reason =
+ dgettext(TEXT_DOMAIN, "Out of memory");
+ ldap_tmplerrlist[2].e_reason =
+ dgettext(TEXT_DOMAIN, "Bad template syntax");
+ ldap_tmplerrlist[3].e_reason =
+ dgettext(TEXT_DOMAIN, "File error reading template");
+ init_flag = 1;
+ }
+
+ for ( i = 0; ldap_tmplerrlist[i].e_code != -1; i++ ) {
+ if ( err == ldap_tmplerrlist[i].e_code )
+ return( ldap_tmplerrlist[i].e_reason );
+ }
+
+ return(dgettext(TEXT_DOMAIN, "Unknown error") );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/dsparse.c b/usr/src/lib/libldap5/sources/ldap/common/dsparse.c
new file mode 100644
index 0000000000..69aed4ae65
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/dsparse.c
@@ -0,0 +1,215 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * dsparse.c: parsing routines used by display template and search
+ * preference file library routines for LDAP clients.
+ *
+ */
+
+#include "ldap-int.h"
+
+static int next_line( char **bufp, long *blenp, char **linep );
+static char *next_token( char ** sp );
+
+int
+ldap_next_line_tokens( char **bufp, long *blenp, char ***toksp )
+{
+ char *p, *line, *token, **toks;
+ int rc, tokcnt;
+
+ *toksp = NULL;
+
+ if (( rc = next_line( bufp, blenp, &line )) <= 0 ) {
+ return( rc );
+ }
+
+ if (( toks = (char **)NSLDAPI_CALLOC( 1, sizeof( char * ))) == NULL ) {
+ NSLDAPI_FREE( line );
+ return( -1 );
+ }
+ tokcnt = 0;
+
+ p = line;
+ while (( token = next_token( &p )) != NULL ) {
+ if (( toks = (char **)NSLDAPI_REALLOC( toks, ( tokcnt + 2 ) *
+ sizeof( char * ))) == NULL ) {
+ NSLDAPI_FREE( (char *)toks );
+ NSLDAPI_FREE( line );
+ return( -1 );
+ }
+ toks[ tokcnt ] = token;
+ toks[ ++tokcnt ] = NULL;
+ }
+
+ if ( tokcnt == 1 && strcasecmp( toks[ 0 ], "END" ) == 0 ) {
+ tokcnt = 0;
+ ldap_free_strarray( toks );
+ toks = NULL;
+ }
+
+ NSLDAPI_FREE( line );
+
+ if ( tokcnt == 0 ) {
+ if ( toks != NULL ) {
+ NSLDAPI_FREE( (char *)toks );
+ }
+ } else {
+ *toksp = toks;
+ }
+
+ return( tokcnt );
+}
+
+
+static int
+next_line( char **bufp, long *blenp, char **linep )
+{
+ char *linestart, *line, *p;
+ long plen;
+
+ linestart = *bufp;
+ p = *bufp;
+ plen = *blenp;
+
+ do {
+ for ( linestart = p; plen > 0; ++p, --plen ) {
+ if ( *p == '\r' ) {
+ if ( plen > 1 && *(p+1) == '\n' ) {
+ ++p;
+ --plen;
+ }
+ break;
+ }
+
+ if ( *p == '\n' ) {
+ if ( plen > 1 && *(p+1) == '\r' ) {
+ ++p;
+ --plen;
+ }
+ break;
+ }
+ }
+ ++p;
+ --plen;
+ } while ( plen > 0 && ( *linestart == '#' || linestart + 1 == p ));
+
+
+ *bufp = p;
+ *blenp = plen;
+
+
+ if ( plen <= 0 ) {
+ *linep = NULL;
+ return( 0 ); /* end of file */
+ }
+
+ if (( line = NSLDAPI_MALLOC( p - linestart )) == NULL ) {
+ *linep = NULL;
+ return( -1 ); /* fatal error */
+ }
+
+ SAFEMEMCPY( line, linestart, p - linestart );
+ line[ p - linestart - 1 ] = '\0';
+ *linep = line;
+ return( strlen( line ));
+}
+
+
+static char *
+next_token( char **sp )
+{
+ int in_quote = 0;
+ char *p, *tokstart, *t;
+
+ if ( **sp == '\0' ) {
+ return( NULL );
+ }
+
+ p = *sp;
+
+ while ( ldap_utf8isspace( p )) { /* skip leading white space */
+ ++p;
+ }
+
+ if ( *p == '\0' ) {
+ return( NULL );
+ }
+
+ if ( *p == '\"' ) {
+ in_quote = 1;
+ ++p;
+ }
+ t = tokstart = p;
+
+ for ( ;; ) {
+ if ( *p == '\0' || ( ldap_utf8isspace( p ) && !in_quote )) {
+ if ( *p != '\0' ) {
+ ++p;
+ }
+ *t++ = '\0'; /* end of token */
+ break;
+ }
+
+ if ( *p == '\"' ) {
+ in_quote = !in_quote;
+ ++p;
+ } else {
+ *t++ = *p++;
+ }
+ }
+
+ *sp = p;
+
+ if ( t == tokstart ) {
+ return( NULL );
+ }
+
+ return( nsldapi_strdup( tokstart ));
+}
+
+
+void
+ldap_free_strarray( char **sap )
+{
+ int i;
+
+ if ( sap != NULL ) {
+ for ( i = 0; sap[ i ] != NULL; ++i ) {
+ NSLDAPI_FREE( sap[ i ] );
+ }
+ NSLDAPI_FREE( (char *)sap );
+ }
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/error.c b/usr/src/lib/libldap5/sources/ldap/common/error.c
new file mode 100644
index 0000000000..fc1d89d7c9
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/error.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+#include "ldap-int.h"
+
+struct ldaperror {
+ int e_code;
+ char *e_reason;
+};
+
+#ifdef _SOLARIS_SDK
+#include <synch.h>
+static struct ldaperror ldap_errlist[] = {
+ { LDAP_SUCCESS, 0 },
+ { LDAP_OPERATIONS_ERROR, 0 },
+ { LDAP_PROTOCOL_ERROR, 0 },
+ { LDAP_TIMELIMIT_EXCEEDED, 0 },
+ { LDAP_SIZELIMIT_EXCEEDED, 0 },
+ { LDAP_COMPARE_FALSE, 0 },
+ { LDAP_COMPARE_TRUE, 0 },
+ { LDAP_STRONG_AUTH_NOT_SUPPORTED, 0 },
+ { LDAP_STRONG_AUTH_REQUIRED, 0 },
+ { LDAP_PARTIAL_RESULTS, 0 },
+ { LDAP_REFERRAL, 0 },
+ { LDAP_ADMINLIMIT_EXCEEDED, 0 },
+ { LDAP_UNAVAILABLE_CRITICAL_EXTENSION, 0 },
+ { LDAP_CONFIDENTIALITY_REQUIRED, 0 },
+ { LDAP_SASL_BIND_IN_PROGRESS, 0 },
+
+ { LDAP_NO_SUCH_ATTRIBUTE, 0 },
+ { LDAP_UNDEFINED_TYPE, 0 },
+ { LDAP_INAPPROPRIATE_MATCHING, 0 },
+ { LDAP_CONSTRAINT_VIOLATION, 0 },
+ { LDAP_TYPE_OR_VALUE_EXISTS, 0 },
+ { LDAP_INVALID_SYNTAX, 0 },
+
+ { LDAP_NO_SUCH_OBJECT, 0 },
+ { LDAP_ALIAS_PROBLEM, 0 },
+ { LDAP_INVALID_DN_SYNTAX, 0 },
+ { LDAP_IS_LEAF, 0 },
+ { LDAP_ALIAS_DEREF_PROBLEM, 0 },
+
+ { LDAP_INAPPROPRIATE_AUTH, 0 },
+ { LDAP_INVALID_CREDENTIALS, 0 },
+ { LDAP_INSUFFICIENT_ACCESS, 0 },
+ { LDAP_BUSY, 0 },
+ { LDAP_UNAVAILABLE, 0 },
+ { LDAP_UNWILLING_TO_PERFORM, 0 },
+ { LDAP_LOOP_DETECT, 0 },
+ { LDAP_SORT_CONTROL_MISSING, 0 },
+ { LDAP_INDEX_RANGE_ERROR, 0 },
+
+ { LDAP_NAMING_VIOLATION, 0 },
+ { LDAP_OBJECT_CLASS_VIOLATION, 0 },
+ { LDAP_NOT_ALLOWED_ON_NONLEAF, 0 },
+ { LDAP_NOT_ALLOWED_ON_RDN, 0 },
+ { LDAP_ALREADY_EXISTS, 0 },
+ { LDAP_NO_OBJECT_CLASS_MODS, 0 },
+ { LDAP_RESULTS_TOO_LARGE, 0 },
+ { LDAP_AFFECTS_MULTIPLE_DSAS, 0 },
+
+ { LDAP_OTHER, 0 },
+ { LDAP_SERVER_DOWN, 0 },
+ { LDAP_LOCAL_ERROR, 0 },
+ { LDAP_ENCODING_ERROR, 0 },
+ { LDAP_DECODING_ERROR, 0 },
+ { LDAP_TIMEOUT, 0 },
+ { LDAP_AUTH_UNKNOWN, 0 },
+ { LDAP_FILTER_ERROR, 0 },
+ { LDAP_USER_CANCELLED, 0 },
+ { LDAP_PARAM_ERROR, 0 },
+ { LDAP_NO_MEMORY, 0 },
+ { LDAP_CONNECT_ERROR, 0 },
+ { LDAP_NOT_SUPPORTED, 0 },
+ { LDAP_CONTROL_NOT_FOUND, 0 },
+ { LDAP_NO_RESULTS_RETURNED, 0 },
+ { LDAP_MORE_RESULTS_TO_RETURN, 0 },
+ { LDAP_CLIENT_LOOP, 0 },
+ { LDAP_REFERRAL_LIMIT_EXCEEDED, 0 },
+ { -1, 0 }
+};
+const int last_index = sizeof(ldap_errlist)/sizeof(ldap_errlist[0]) - 2;
+#else
+static struct ldaperror ldap_errlist[] = {
+ { LDAP_SUCCESS, "Success" },
+ { LDAP_OPERATIONS_ERROR, "Operations error" },
+ { LDAP_PROTOCOL_ERROR, "Protocol error" },
+ { LDAP_TIMELIMIT_EXCEEDED, "Timelimit exceeded" },
+ { LDAP_SIZELIMIT_EXCEEDED, "Sizelimit exceeded" },
+ { LDAP_COMPARE_FALSE, "Compare false" },
+ { LDAP_COMPARE_TRUE, "Compare true" },
+ { LDAP_STRONG_AUTH_NOT_SUPPORTED, "Authentication method not supported" },
+ { LDAP_STRONG_AUTH_REQUIRED, "Strong authentication required" },
+ { LDAP_PARTIAL_RESULTS, "Partial results and referral received" },
+ { LDAP_REFERRAL, "Referral received" },
+ { LDAP_ADMINLIMIT_EXCEEDED, "Administrative limit exceeded" },
+ { LDAP_UNAVAILABLE_CRITICAL_EXTENSION, "Unavailable critical extension" },
+ { LDAP_CONFIDENTIALITY_REQUIRED, "Confidentiality required" },
+ { LDAP_SASL_BIND_IN_PROGRESS, "SASL bind in progress" },
+
+ { LDAP_NO_SUCH_ATTRIBUTE, "No such attribute" },
+ { LDAP_UNDEFINED_TYPE, "Undefined attribute type" },
+ { LDAP_INAPPROPRIATE_MATCHING, "Inappropriate matching" },
+ { LDAP_CONSTRAINT_VIOLATION, "Constraint violation" },
+ { LDAP_TYPE_OR_VALUE_EXISTS, "Type or value exists" },
+ { LDAP_INVALID_SYNTAX, "Invalid syntax" },
+
+ { LDAP_NO_SUCH_OBJECT, "No such object" },
+ { LDAP_ALIAS_PROBLEM, "Alias problem" },
+ { LDAP_INVALID_DN_SYNTAX, "Invalid DN syntax" },
+ { LDAP_IS_LEAF, "Object is a leaf" },
+ { LDAP_ALIAS_DEREF_PROBLEM, "Alias dereferencing problem" },
+
+ { LDAP_INAPPROPRIATE_AUTH, "Inappropriate authentication" },
+ { LDAP_INVALID_CREDENTIALS, "Invalid credentials" },
+ { LDAP_INSUFFICIENT_ACCESS, "Insufficient access" },
+ { LDAP_BUSY, "DSA is busy" },
+ { LDAP_UNAVAILABLE, "DSA is unavailable" },
+ { LDAP_UNWILLING_TO_PERFORM, "DSA is unwilling to perform" },
+ { LDAP_LOOP_DETECT, "Loop detected" },
+ { LDAP_SORT_CONTROL_MISSING, "Sort Control is missing" },
+ { LDAP_INDEX_RANGE_ERROR, "Search results exceed the range specified by the offsets" },
+
+ { LDAP_NAMING_VIOLATION, "Naming violation" },
+ { LDAP_OBJECT_CLASS_VIOLATION, "Object class violation" },
+ { LDAP_NOT_ALLOWED_ON_NONLEAF, "Operation not allowed on nonleaf" },
+ { LDAP_NOT_ALLOWED_ON_RDN, "Operation not allowed on RDN" },
+ { LDAP_ALREADY_EXISTS, "Already exists" },
+ { LDAP_NO_OBJECT_CLASS_MODS, "Cannot modify object class" },
+ { LDAP_RESULTS_TOO_LARGE, "Results too large" },
+ { LDAP_AFFECTS_MULTIPLE_DSAS, "Affects multiple servers" },
+
+ { LDAP_OTHER, "Unknown error" },
+ { LDAP_SERVER_DOWN, "Can't contact LDAP server" },
+ { LDAP_LOCAL_ERROR, "Local error" },
+ { LDAP_ENCODING_ERROR, "Encoding error" },
+ { LDAP_DECODING_ERROR, "Decoding error" },
+ { LDAP_TIMEOUT, "Timed out" },
+ { LDAP_AUTH_UNKNOWN, "Unknown authentication method" },
+ { LDAP_FILTER_ERROR, "Bad search filter" },
+ { LDAP_USER_CANCELLED, "User cancelled operation" },
+ { LDAP_PARAM_ERROR, "Bad parameter to an ldap routine" },
+ { LDAP_NO_MEMORY, "Out of memory" },
+ { LDAP_CONNECT_ERROR, "Can't connect to the LDAP server" },
+ { LDAP_NOT_SUPPORTED, "Not supported by this version of the LDAP protocol" },
+ { LDAP_CONTROL_NOT_FOUND, "Requested LDAP control not found" },
+ { LDAP_NO_RESULTS_RETURNED, "No results returned" },
+ { LDAP_MORE_RESULTS_TO_RETURN, "More results to return" },
+ { LDAP_CLIENT_LOOP, "Client detected loop" },
+ { LDAP_REFERRAL_LIMIT_EXCEEDED, "Referral hop limit exceeded" },
+ { -1, 0 }
+};
+#endif
+
+#ifdef _SOLARIS_SDK
+static mutex_t err_mutex = DEFAULTMUTEX;
+
+static void fill_ldap_errlist()
+{
+ int i=0;
+ mutex_lock(&err_mutex);
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "fill_ldap_errlist\n", 0, 0, 0 );
+
+ if (ldap_errlist[last_index].e_reason != NULL) {
+ mutex_unlock(&err_mutex);
+ return;
+ }
+
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Success");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Operations error");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Protocol error");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Timelimit exceeded");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Sizelimit exceeded");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Compare false");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Compare true");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Authentication method not supported");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Strong authentication required");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Partial results and referral received");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Referral received");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Administrative limit exceeded");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Unavailable critical extension");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Confidentiality required");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "SASL bind in progress");
+
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "No such attribute");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Undefined attribute type");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Inappropriate matching");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Constraint violation");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Type or value exists");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Invalid syntax");
+
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "No such object");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Alias problem");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Invalid DN syntax");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Object is a leaf");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Alias dereferencing problem");
+
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Inappropriate authentication");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Invalid credentials");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Insufficient access");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "DSA is busy");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "DSA is unavailable");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "DSA is unwilling to perform");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Loop detected");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Sort Control is missing");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Search results exceed the range specified by the offsets");
+
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Naming violation");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Object class violation");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Operation not allowed on nonleaf");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Operation not allowed on RDN");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Already exists");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Cannot modify object class");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Results too large");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Affects multiple servers");
+
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Unknown error");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Can't contact LDAP server");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Local error");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Encoding error");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Decoding error");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Timed out");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Unknown authentication method");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Bad search filter");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "User cancelled operation");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Bad parameter to an ldap routine");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN, "Out of memory");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Can't connect to the LDAP server");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Not supported by this version of the LDAP protocol");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Requested LDAP control not found");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "No results returned");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "More results to return");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Client detected loop");
+ ldap_errlist[i++].e_reason = dgettext(TEXT_DOMAIN,
+ "Referral hop limit exceeded");
+ mutex_unlock(&err_mutex);
+}
+#endif
+
+char *
+LDAP_CALL
+ldap_err2string( int err )
+{
+ int i;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 );
+
+#ifdef _SOLARIS_SDK
+ /* Make sure errlist is initialized before referencing err string */
+ if (ldap_errlist[last_index].e_reason == NULL)
+ fill_ldap_errlist();
+#endif
+
+ for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) {
+ if ( err == ldap_errlist[i].e_code )
+ return( ldap_errlist[i].e_reason );
+ }
+
+ return( dgettext(TEXT_DOMAIN, "Unknown error") );
+}
+
+
+static char *
+nsldapi_safe_strerror( int e )
+{
+ char *s;
+
+ if (( s = strerror( e )) == NULL ) {
+ s = dgettext(TEXT_DOMAIN, "unknown error");
+ }
+
+ return( s );
+}
+
+
+void
+LDAP_CALL
+ldap_perror( LDAP *ld, const char *s )
+{
+ int i, err;
+ char *matched, *errmsg, *separator;
+ char msg[1024];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_perror\n", 0, 0, 0 );
+
+#ifdef _SOLARIS_SDK
+ /* Make sure errlist is initialized before referencing err string */
+ if (ldap_errlist[last_index].e_reason == NULL)
+ fill_ldap_errlist();
+#endif
+
+ if ( s == NULL ) {
+ s = separator = "";
+ } else {
+ separator = ": ";
+ }
+
+ if ( ld == NULL ) {
+ sprintf( msg, "%s%s%s", s, separator,
+ nsldapi_safe_strerror( errno ) );
+ ber_err_print( msg );
+ return;
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_ERR_LOCK );
+ err = LDAP_GET_LDERRNO( ld, &matched, &errmsg );
+ for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) {
+ if ( err == ldap_errlist[i].e_code ) {
+ sprintf( msg, "%s%s%s", s, separator,
+ ldap_errlist[i].e_reason );
+ ber_err_print( msg );
+ if ( err == LDAP_CONNECT_ERROR ) {
+ ber_err_print( " - " );
+ ber_err_print( nsldapi_safe_strerror(
+ LDAP_GET_ERRNO( ld )));
+ }
+ ber_err_print( "\n" );
+ if ( matched != NULL && *matched != '\0' ) {
+ sprintf( msg, dgettext(TEXT_DOMAIN,
+ "%s%smatched: %s\n"),
+ s, separator, matched );
+ ber_err_print( msg );
+ }
+ if ( errmsg != NULL && *errmsg != '\0' ) {
+ sprintf( msg, dgettext(TEXT_DOMAIN,
+ "%s%sadditional info: %s\n"),
+ s, separator, errmsg );
+ ber_err_print( msg );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK );
+ return;
+ }
+ }
+ sprintf( msg, dgettext(TEXT_DOMAIN, "%s%sNot an LDAP errno %d\n"),
+ s, separator, err );
+ ber_err_print( msg );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK );
+}
+
+int
+LDAP_CALL
+ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit )
+{
+ int lderr_parse, lderr;
+
+ lderr_parse = ldap_parse_result( ld, r, &lderr, NULL, NULL, NULL,
+ NULL, freeit );
+
+ if ( lderr_parse != LDAP_SUCCESS ) {
+ return( lderr_parse );
+ }
+
+ return( lderr );
+}
+
+int
+LDAP_CALL
+ldap_get_lderrno( LDAP *ld, char **m, char **s )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR ); /* punt */
+ }
+
+ if ( ld->ld_get_lderrno_fn == NULL ) {
+ if ( m != NULL ) {
+ *m = ld->ld_matched;
+ }
+ if ( s != NULL ) {
+ *s = ld->ld_error;
+ }
+ return( ld->ld_errno );
+ } else {
+ return( ld->ld_get_lderrno_fn( m, s, ld->ld_lderrno_arg ) );
+ }
+}
+
+
+/*
+ * Note: there is no need for callers of ldap_set_lderrno() to lock the
+ * ld mutex. If applications intend to share an LDAP session handle
+ * between threads they *must* perform their own locking around the
+ * session handle or they must install a "set lderrno" thread callback
+ * function.
+ *
+ */
+int
+LDAP_CALL
+ldap_set_lderrno( LDAP *ld, int e, char *m, char *s )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ld->ld_set_lderrno_fn != NULL ) {
+ ld->ld_set_lderrno_fn( e, m, s, ld->ld_lderrno_arg );
+ } else {
+ LDAP_MUTEX_LOCK( ld, LDAP_ERR_LOCK );
+ ld->ld_errno = e;
+ if ( ld->ld_matched ) {
+ NSLDAPI_FREE( ld->ld_matched );
+ }
+ ld->ld_matched = m;
+ if ( ld->ld_error ) {
+ NSLDAPI_FREE( ld->ld_error );
+ }
+ ld->ld_error = s;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK );
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Returns an LDAP error that says whether parse succeeded. The error code
+ * from the LDAP result itself is returned in the errcodep result parameter.
+ * If any of the result params. (errcodep, matchednp, errmsgp, referralsp,
+ * or serverctrlsp) are NULL we don't return that info.
+ */
+int
+LDAP_CALL
+ldap_parse_result( LDAP *ld, LDAPMessage *res, int *errcodep, char **matchednp,
+ char **errmsgp, char ***referralsp, LDAPControl ***serverctrlsp,
+ int freeit )
+{
+ LDAPMessage *lm;
+ int err, errcode;
+ char *m, *e;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
+ !NSLDAPI_VALID_LDAPMESSAGE_POINTER( res )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /* skip over entries and references to find next result in this chain */
+ for ( lm = res; lm != NULL; lm = lm->lm_chain ) {
+ if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY &&
+ lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
+ break;
+ }
+ }
+
+ if ( lm == NULL ) {
+ err = LDAP_NO_RESULTS_RETURNED;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ err = nsldapi_parse_result( ld, lm->lm_msgtype, lm->lm_ber, &errcode,
+ &m, &e, referralsp, serverctrlsp );
+
+ if ( err == LDAP_SUCCESS ) {
+ if ( errcodep != NULL ) {
+ *errcodep = errcode;
+ }
+ if ( matchednp != NULL ) {
+ *matchednp = nsldapi_strdup( m );
+ }
+ if ( errmsgp != NULL ) {
+ *errmsgp = nsldapi_strdup( e );
+ }
+
+ /*
+ * if there are more result messages in the chain, arrange to
+ * return the special LDAP_MORE_RESULTS_TO_RETURN "error" code.
+ */
+ for ( lm = lm->lm_chain; lm != NULL; lm = lm->lm_chain ) {
+ if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY &&
+ lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
+ err = LDAP_MORE_RESULTS_TO_RETURN;
+ break;
+ }
+ }
+ } else {
+ m = e = NULL;
+ }
+
+ if ( freeit ) {
+ ldap_msgfree( res );
+ }
+
+ LDAP_SET_LDERRNO( ld, ( err == LDAP_SUCCESS ) ? errcode : err, m, e );
+
+ return( err );
+}
+
+
+/*
+ * returns an LDAP error code indicating success or failure of parsing
+ * does NOT set any error information inside "ld"
+ */
+int
+nsldapi_parse_result( LDAP *ld, int msgtype, BerElement *rber, int *errcodep,
+ char **matchednp, char **errmsgp, char ***referralsp,
+ LDAPControl ***serverctrlsp )
+{
+ BerElement ber;
+ ber_len_t len;
+ int berrc, err, errcode;
+ ber_int_t along;
+ char *m, *e;
+
+ /*
+ * Parse the result message. LDAPv3 result messages look like this:
+ *
+ * LDAPResult ::= SEQUENCE {
+ * resultCode ENUMERATED { ... },
+ * matchedDN LDAPDN,
+ * errorMessage LDAPString,
+ * referral [3] Referral OPTIONAL
+ * opSpecificStuff OPTIONAL
+ * }
+ *
+ * all wrapped up in an LDAPMessage sequence which looks like this:
+ * LDAPMessage ::= SEQUENCE {
+ * messageID MessageID,
+ * LDAPResult CHOICE { ... }, // message type
+ * controls [0] Controls OPTIONAL
+ * }
+ *
+ * LDAPv2 messages don't include referrals or controls.
+ * LDAPv1 messages don't include matchedDN, referrals, or controls.
+ *
+ * ldap_result() pulls out the message id, so by the time a result
+ * message gets here we are sitting at the start of the LDAPResult.
+ */
+
+ err = LDAP_SUCCESS; /* optimistic */
+ m = e = NULL;
+ if ( matchednp != NULL ) {
+ *matchednp = NULL;
+ }
+ if ( errmsgp != NULL ) {
+ *errmsgp = NULL;
+ }
+ if ( referralsp != NULL ) {
+ *referralsp = NULL;
+ }
+ if ( serverctrlsp != NULL ) {
+ *serverctrlsp = NULL;
+ }
+ ber = *rber; /* struct copy */
+
+ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION2 ) {
+ berrc = ber_scanf( &ber, "{ia}", &along, &e );
+ errcode = (int)along; /* XXX lossy cast */
+ } else {
+ if (( berrc = ber_scanf( &ber, "{iaa", &along, &m, &e ))
+ != LBER_ERROR ) {
+ errcode = (int)along; /* XXX lossy cast */
+ /* check for optional referrals */
+ if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_REFERRAL ) {
+ if ( referralsp == NULL ) {
+ /* skip referrals */
+ berrc = ber_scanf( &ber, "x" );
+ } else {
+ /* suck out referrals */
+ berrc = ber_scanf( &ber, "v",
+ referralsp );
+ }
+ } else if ( referralsp != NULL ) {
+ *referralsp = NULL;
+ }
+ }
+
+ if ( berrc != LBER_ERROR ) {
+ /*
+ * skip past optional operation-specific elements:
+ * bind results - serverSASLcreds
+ * extendedop results - OID plus value
+ */
+ if ( msgtype == LDAP_RES_BIND ) {
+ if ( ber_peek_tag( &ber, &len ) ==
+ LDAP_TAG_SASL_RES_CREDS ) {
+ berrc = ber_scanf( &ber, "x" );
+ }
+ } else if ( msgtype == LDAP_RES_EXTENDED ) {
+ if ( ber_peek_tag( &ber, &len ) ==
+ LDAP_TAG_EXOP_RES_OID ) {
+ berrc = ber_scanf( &ber, "x" );
+ }
+ if ( berrc != LBER_ERROR &&
+ ber_peek_tag( &ber, &len ) ==
+ LDAP_TAG_EXOP_RES_VALUE ) {
+ berrc = ber_scanf( &ber, "x" );
+ }
+ }
+ }
+
+ /* pull out controls (if requested and any are present) */
+ if ( berrc != LBER_ERROR && serverctrlsp != NULL &&
+ ( berrc = ber_scanf( &ber, "}" )) != LBER_ERROR ) {
+ err = nsldapi_get_controls( &ber, serverctrlsp );
+ }
+ }
+
+ if ( berrc == LBER_ERROR && err == LDAP_SUCCESS ) {
+ err = LDAP_DECODING_ERROR;
+ }
+
+ if ( errcodep != NULL ) {
+ *errcodep = errcode;
+ }
+ if ( matchednp != NULL ) {
+ *matchednp = m;
+ } else if ( m != NULL ) {
+ NSLDAPI_FREE( m );
+ }
+ if ( errmsgp != NULL ) {
+ *errmsgp = e;
+ } else if ( e != NULL ) {
+ NSLDAPI_FREE( e );
+ }
+
+ return( err );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/extendop.c b/usr/src/lib/libldap5/sources/ldap/common/extendop.c
new file mode 100644
index 0000000000..61a41a8017
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/extendop.c
@@ -0,0 +1,249 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+#include "ldap-int.h"
+
+/*
+ * ldap_extended_operation - initiate an arbitrary ldapv3 extended operation.
+ * the oid and data of the extended operation are supplied. Returns an
+ * LDAP error code.
+ *
+ * Example:
+ * struct berval exdata;
+ * char *exoid;
+ * int err, msgid;
+ * ... fill in oid and data ...
+ * err = ldap_extended_operation( ld, exoid, &exdata, NULL, NULL, &msgid );
+ */
+
+int
+LDAP_CALL
+ldap_extended_operation(
+ LDAP *ld,
+ const char *exoid,
+ const struct berval *exdata,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ int *msgidp
+)
+{
+ BerElement *ber;
+ int rc, msgid;
+
+ /*
+ * the ldapv3 extended operation request looks like this:
+ *
+ * ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+ * requestName LDAPOID,
+ * requestValue OCTET STRING
+ * }
+ *
+ * all wrapped up in an LDAPMessage sequence.
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+
+ /* only ldapv3 or higher can do extended operations */
+ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+ rc = LDAP_NOT_SUPPORTED;
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+ }
+
+ if ( msgidp == NULL || exoid == NULL || *exoid == '\0' ||
+ exdata == NULL || exdata->bv_val == NULL ) {
+ rc = LDAP_PARAM_ERROR;
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ msgid = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+#if 0
+ if ( ld->ld_cache_on && ld->ld_cache_extendedop != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_extendedop)( ld, msgid,
+ LDAP_REQ_EXTENDED, exoid, cred )) != 0 ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( rc );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+#endif
+
+ /* create a message to send */
+ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( rc );
+ }
+
+ /* fill it in */
+ if ( ber_printf( ber, "{it{tsto}", msgid, LDAP_REQ_EXTENDED,
+ LDAP_TAG_EXOP_REQ_OID, exoid, LDAP_TAG_EXOP_REQ_VALUE,
+ exdata->bv_val, (int)exdata->bv_len /* XXX lossy cast */ ) == -1 ) {
+ rc = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ ber_free( ber, 1 );
+ return( rc );
+ }
+
+ if (( rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( rc );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_EXTENDED, NULL,
+ ber );
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+
+/*
+ * ldap_extended_operation_s - perform an arbitrary ldapv3 extended operation.
+ * the oid and data of the extended operation are supplied. LDAP_SUCCESS
+ * is returned upon success, the ldap error code otherwise.
+ *
+ * Example:
+ * struct berval exdata, exretval;
+ * char *exoid;
+ * int rc;
+ * ... fill in oid and data ...
+ * rc = ldap_extended_operation_s( ld, exoid, &exdata, &exretval );
+ */
+int
+LDAP_CALL
+ldap_extended_operation_s(
+ LDAP *ld,
+ const char *requestoid,
+ const struct berval *requestdata,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ char **retoidp,
+ struct berval **retdatap
+)
+{
+ int err, msgid;
+ LDAPMessage *result;
+
+ if (( err = ldap_extended_operation( ld, requestoid, requestdata,
+ serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result )
+ == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ if (( err = ldap_parse_extended_result( ld, result, retoidp, retdatap,
+ 0 )) != LDAP_SUCCESS ) {
+ ldap_msgfree( result );
+ return( err );
+ }
+
+ return( ldap_result2error( ld, result, 1 ) );
+}
+
+
+/*
+ * Pull the oid returned by the server and the data out of an extended
+ * operation result. Return an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_parse_extended_result(
+ LDAP *ld,
+ LDAPMessage *res,
+ char **retoidp, /* may be NULL */
+ struct berval **retdatap, /* may be NULL */
+ int freeit
+)
+{
+ struct berelement ber;
+ ber_len_t len;
+ ber_int_t err;
+ char *m, *e, *roid;
+ struct berval *rdata;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_EXRESULT_POINTER( res )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ m = e = NULL;
+ ber = *(res->lm_ber);
+ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+ return( LDAP_NOT_SUPPORTED );
+ }
+
+ if ( ber_scanf( &ber, "{iaa", &err, &m, &e ) == LBER_ERROR ) {
+ goto decoding_error;
+ }
+ roid = NULL;
+ if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_EXOP_RES_OID ) {
+ if ( ber_scanf( &ber, "a", &roid ) == LBER_ERROR ) {
+ goto decoding_error;
+ }
+ }
+ if ( retoidp != NULL ) {
+ *retoidp = roid;
+ } else if ( roid != NULL ) {
+ NSLDAPI_FREE( roid );
+ }
+
+ rdata = NULL;
+ if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_EXOP_RES_VALUE ) {
+ if ( ber_scanf( &ber, "O", &rdata ) == LBER_ERROR ) {
+ goto decoding_error;
+ }
+ }
+ if ( retdatap != NULL ) {
+ *retdatap = rdata;
+ } else if ( rdata != NULL ) {
+ ber_bvfree( rdata );
+ }
+
+ LDAP_SET_LDERRNO( ld, err, m, e );
+
+ if ( freeit ) {
+ ldap_msgfree( res );
+ }
+
+ return( LDAP_SUCCESS );
+
+decoding_error:;
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ return( LDAP_DECODING_ERROR );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/free.c b/usr/src/lib/libldap5/sources/ldap/common/free.c
new file mode 100644
index 0000000000..16a9fc574a
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/free.c
@@ -0,0 +1,140 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1994 The Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * free.c - some free routines are included here to avoid having to
+ * link in lots of extra code when not using certain features
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1994 The Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+void
+LDAP_CALL
+ldap_getfilter_free( LDAPFiltDesc *lfdp )
+{
+ LDAPFiltList *flp, *nextflp;
+ LDAPFiltInfo *fip, *nextfip;
+
+ if ( lfdp == NULL ) {
+ return;
+ }
+
+ for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = nextflp ) {
+ for ( fip = flp->lfl_ilist; fip != NULL; fip = nextfip ) {
+ nextfip = fip->lfi_next;
+ NSLDAPI_FREE( fip->lfi_filter );
+ NSLDAPI_FREE( fip->lfi_desc );
+ NSLDAPI_FREE( fip );
+ }
+ nextflp = flp->lfl_next;
+ NSLDAPI_FREE( flp->lfl_pattern );
+ NSLDAPI_FREE( flp->lfl_delims );
+ NSLDAPI_FREE( flp->lfl_tag );
+ NSLDAPI_FREE( flp );
+ }
+
+ if ( lfdp->lfd_curvalcopy != NULL ) {
+ NSLDAPI_FREE( lfdp->lfd_curvalcopy );
+ }
+ if ( lfdp->lfd_curvalwords != NULL ) {
+ NSLDAPI_FREE( lfdp->lfd_curvalwords );
+ }
+ if ( lfdp->lfd_filtprefix != NULL ) {
+ NSLDAPI_FREE( lfdp->lfd_filtprefix );
+ }
+ if ( lfdp->lfd_filtsuffix != NULL ) {
+ NSLDAPI_FREE( lfdp->lfd_filtsuffix );
+ }
+
+ NSLDAPI_FREE( lfdp );
+}
+
+
+/*
+ * free a null-terminated array of pointers to mod structures. the
+ * structures are freed, not the array itself, unless the freemods
+ * flag is set.
+ */
+void
+LDAP_CALL
+ldap_mods_free( LDAPMod **mods, int freemods )
+{
+ int i;
+
+ if ( !NSLDAPI_VALID_LDAPMOD_ARRAY( mods )) {
+ return;
+ }
+
+ for ( i = 0; mods[i] != NULL; i++ ) {
+ if ( mods[i]->mod_op & LDAP_MOD_BVALUES ) {
+ if ( mods[i]->mod_bvalues != NULL ) {
+ ber_bvecfree( mods[i]->mod_bvalues );
+ }
+ } else if ( mods[i]->mod_values != NULL ) {
+ ldap_value_free( mods[i]->mod_values );
+ }
+ if ( mods[i]->mod_type != NULL ) {
+ NSLDAPI_FREE( mods[i]->mod_type );
+ }
+ NSLDAPI_FREE( (char *) mods[i] );
+ }
+
+ if ( freemods )
+ NSLDAPI_FREE( (char *) mods );
+}
+
+
+/*
+ * ldap_memfree() is needed to ensure that memory allocated by the C runtime
+ * assocated with libldap is freed by the same runtime code.
+ */
+void
+LDAP_CALL
+ldap_memfree( void *s )
+{
+ if ( s != NULL ) {
+ NSLDAPI_FREE( s );
+ }
+}
+
+
+/*
+ * ldap_ber_free() is just a cover for ber_free()
+ * ber_free() checks for ber == NULL, so we don't bother.
+ */
+void
+LDAP_CALL
+ldap_ber_free( BerElement *ber, int freebuf )
+{
+ ber_free( ber, freebuf );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/freevalues.c b/usr/src/lib/libldap5/sources/ldap/common/freevalues.c
new file mode 100644
index 0000000000..179e011a80
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/freevalues.c
@@ -0,0 +1,60 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * freevalues.c
+ */
+
+#include "ldap-int.h"
+
+void
+LDAP_CALL
+ldap_value_free( char **vals )
+{
+ int i;
+
+ if ( vals == NULL )
+ return;
+ for ( i = 0; vals[i] != NULL; i++ )
+ NSLDAPI_FREE( vals[i] );
+ NSLDAPI_FREE( (char *) vals );
+}
+
+void
+LDAP_CALL
+ldap_value_free_len( struct berval **vals )
+{
+ int i;
+
+ if ( vals == NULL )
+ return;
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ NSLDAPI_FREE( vals[i]->bv_val );
+ NSLDAPI_FREE( vals[i] );
+ }
+ NSLDAPI_FREE( (char *) vals );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/friendly.c b/usr/src/lib/libldap5/sources/ldap/common/friendly.c
new file mode 100644
index 0000000000..91bb491469
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/friendly.c
@@ -0,0 +1,138 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * friendly.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+char *
+LDAP_CALL
+ldap_friendly_name( char *filename, char *name, FriendlyMap *map )
+{
+ int i, entries;
+ FILE *fp;
+ char *s;
+ char buf[BUFSIZ];
+
+ if ( map == NULL ) {
+ return( name );
+ }
+ if ( NULL == name)
+ {
+ return (name);
+ }
+
+ if ( *map == NULL ) {
+ if ( (fp = fopen( filename, "r" )) == NULL )
+ return( name );
+
+ entries = 0;
+ while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+ if ( buf[0] != '#' )
+ entries++;
+ }
+ rewind( fp );
+
+ if ( (*map = (FriendlyMap)NSLDAPI_MALLOC( (entries + 1) *
+ sizeof(struct friendly) )) == NULL ) {
+ fclose( fp );
+ return( name );
+ }
+
+ i = 0;
+ while ( fgets( buf, sizeof(buf), fp ) != NULL && i < entries ) {
+ if ( buf[0] == '#' )
+ continue;
+
+ if ( (s = strchr( buf, '\n' )) != NULL )
+ *s = '\0';
+
+ if ( (s = strchr( buf, '\t' )) == NULL )
+ continue;
+ *s++ = '\0';
+
+ if ( *s == '"' ) {
+ int esc = 0, found = 0;
+
+ for ( ++s; *s && !found; s++ ) {
+ switch ( *s ) {
+ case '\\':
+ esc = 1;
+ break;
+ case '"':
+ if ( !esc )
+ found = 1;
+ /* FALL */
+ default:
+ esc = 0;
+ break;
+ }
+ }
+ }
+
+ (*map)[i].f_unfriendly = nsldapi_strdup( buf );
+ (*map)[i].f_friendly = nsldapi_strdup( s );
+ i++;
+ }
+
+ fclose( fp );
+ (*map)[i].f_unfriendly = NULL;
+ }
+
+ for ( i = 0; (*map)[i].f_unfriendly != NULL; i++ ) {
+ if ( strcasecmp( name, (*map)[i].f_unfriendly ) == 0 )
+ return( (*map)[i].f_friendly );
+ }
+ return( name );
+}
+
+
+void
+LDAP_CALL
+ldap_free_friendlymap( FriendlyMap *map )
+{
+ struct friendly* pF;
+
+ if ( map == NULL || *map == NULL ) {
+ return;
+ }
+
+ for ( pF = *map; pF->f_unfriendly; pF++ ) {
+ NSLDAPI_FREE( pF->f_unfriendly );
+ NSLDAPI_FREE( pF->f_friendly );
+ }
+ NSLDAPI_FREE( *map );
+ *map = NULL;
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/getattr.c b/usr/src/lib/libldap5/sources/ldap/common/getattr.c
new file mode 100644
index 0000000000..76ed024dff
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/getattr.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * getattr.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+
+static ber_len_t
+bytes_remaining( BerElement *ber )
+{
+ ber_len_t len;
+
+ if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
+ return( 0 ); /* not sure what else to do.... */
+ }
+ return( len );
+}
+
+
+char *
+LDAP_CALL
+ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **ber )
+{
+ char *attr;
+ int err;
+ ber_int_t seqlength;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_first_attribute\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( NULL ); /* punt */
+ }
+
+ if ( ber == NULL || !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( NULL );
+ }
+
+ if ( nsldapi_alloc_ber_with_options( ld, ber ) != LDAP_SUCCESS ) {
+ return( NULL );
+ }
+
+ **ber = *entry->lm_ber;
+
+ attr = NULL; /* pessimistic */
+ err = LDAP_DECODING_ERROR; /* ditto */
+
+ /*
+ * Skip past the sequence, dn, and sequence of sequence.
+ * Reset number of bytes remaining so we confine the rest of our
+ * decoding to the current sequence.
+ */
+ if ( ber_scanf( *ber, "{xl{", &seqlength ) != LBER_ERROR &&
+ ber_set_option( *ber, LBER_OPT_REMAINING_BYTES, &seqlength )
+ == 0 ) {
+ /* snarf the attribute type, and skip the set of values,
+ * leaving us positioned right before the next attribute
+ * type/value sequence.
+ */
+ if ( ber_scanf( *ber, "{ax}", &attr ) != LBER_ERROR ||
+ bytes_remaining( *ber ) == 0 ) {
+ err = LDAP_SUCCESS;
+ }
+ }
+
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ if ( attr == NULL || err != LDAP_SUCCESS ) {
+ ber_free( *ber, 0 );
+ *ber = NULL;
+ }
+ return( attr );
+}
+
+/* ARGSUSED */
+char *
+LDAP_CALL
+ldap_next_attribute( LDAP *ld, LDAPMessage *entry, BerElement *ber )
+{
+ char *attr;
+ int err;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_next_attribute\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( NULL ); /* punt */
+ }
+
+ if ( ber == NULL || !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( NULL );
+ }
+
+ attr = NULL; /* pessimistic */
+ err = LDAP_DECODING_ERROR; /* ditto */
+
+ /* skip sequence, snarf attribute type, skip values */
+ if ( ber_scanf( ber, "{ax}", &attr ) != LBER_ERROR ||
+ bytes_remaining( ber ) == 0 ) {
+ err = LDAP_SUCCESS;
+ }
+
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( attr );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/getdn.c b/usr/src/lib/libldap5/sources/ldap/common/getdn.c
new file mode 100644
index 0000000000..4ab49eef28
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/getdn.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * getdn.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+char *
+LDAP_CALL
+ldap_get_dn( LDAP *ld, LDAPMessage *entry )
+{
+ char *dn;
+ struct berelement tmp;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( NULL ); /* punt */
+ }
+
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( NULL );
+ }
+
+ tmp = *entry->lm_ber; /* struct copy */
+ if ( ber_scanf( &tmp, "{a", &dn ) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ return( NULL );
+ }
+
+ return( dn );
+}
+
+char *
+LDAP_CALL
+ldap_dn2ufn( const char *dn )
+{
+ char *p, *ufn, *r;
+ size_t plen;
+ int state;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
+
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+ if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL )
+ return( nsldapi_strdup( (char *)dn ));
+
+ ufn = nsldapi_strdup( ++p );
+
+#define INQUOTE 1
+#define OUTQUOTE 2
+ state = OUTQUOTE;
+ for ( p = ufn, r = ufn; *p; p += plen ) {
+ plen = 1;
+ switch ( *p ) {
+ case '\\':
+ if ( *++p == '\0' )
+ plen=0;
+ else {
+ *r++ = '\\';
+ r += (plen = LDAP_UTF8COPY(r,p));
+ }
+ break;
+ case '"':
+ if ( state == INQUOTE )
+ state = OUTQUOTE;
+ else
+ state = INQUOTE;
+ *r++ = *p;
+ break;
+ case ';':
+ case ',':
+ if ( state == OUTQUOTE )
+ *r++ = ',';
+ else
+ *r++ = *p;
+ break;
+ case '=':
+ if ( state == INQUOTE )
+ *r++ = *p;
+ else {
+ char *rsave = r;
+ LDAP_UTF8DEC(r);
+ *rsave = '\0';
+ while ( !ldap_utf8isspace( r ) && *r != ';'
+ && *r != ',' && r > ufn )
+ LDAP_UTF8DEC(r);
+ LDAP_UTF8INC(r);
+
+ if ( strcasecmp( r, "c" )
+ && strcasecmp( r, "o" )
+ && strcasecmp( r, "ou" )
+ && strcasecmp( r, "st" )
+ && strcasecmp( r, "l" )
+ && strcasecmp( r, "dc" )
+ && strcasecmp( r, "uid" )
+ && strcasecmp( r, "cn" ) ) {
+ r = rsave;
+ *r++ = '=';
+ }
+ }
+ break;
+ default:
+ r += (plen = LDAP_UTF8COPY(r,p));
+ break;
+ }
+ }
+ *r = '\0';
+
+ return( ufn );
+}
+
+char **
+LDAP_CALL
+ldap_explode_dns( const char *dn )
+{
+ int ncomps, maxcomps;
+ char *s, *cpydn;
+ char **rdns;
+#ifdef HAVE_STRTOK_R /* defined in portable.h */
+ char *lasts;
+#endif
+
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+ if ( (rdns = (char **)NSLDAPI_MALLOC( 8 * sizeof(char *) )) == NULL ) {
+ return( NULL );
+ }
+
+ maxcomps = 8;
+ ncomps = 0;
+ cpydn = nsldapi_strdup( (char *)dn );
+ for ( s = STRTOK( cpydn, "@.", &lasts ); s != NULL;
+ s = STRTOK( NULL, "@.", &lasts ) ) {
+ if ( ncomps == maxcomps ) {
+ maxcomps *= 2;
+ if ( (rdns = (char **)NSLDAPI_REALLOC( rdns, maxcomps *
+ sizeof(char *) )) == NULL ) {
+ NSLDAPI_FREE( cpydn );
+ return( NULL );
+ }
+ }
+ rdns[ncomps++] = nsldapi_strdup( s );
+ }
+ rdns[ncomps] = NULL;
+ NSLDAPI_FREE( cpydn );
+
+ return( rdns );
+}
+
+#define LDAP_DN 1
+#define LDAP_RDN 2
+
+static char **
+ldap_explode( const char *dn, const int notypes, const int nametype )
+{
+ char *p, *q, *rdnstart, **rdns = NULL;
+ size_t plen = 0;
+ int state, count = 0, endquote, len, goteq;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_explode\n", 0, 0, 0 );
+
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+#if 0
+ if ( ldap_is_dns_dn( dn ) ) {
+ return( ldap_explode_dns( dn ) );
+ }
+#endif
+
+ while ( ldap_utf8isspace( (char *)dn )) { /* ignore leading spaces */
+ ++dn;
+ }
+
+ p = rdnstart = (char *) dn;
+ state = OUTQUOTE;
+ goteq = 0;
+
+ do {
+ p += plen;
+ plen = 1;
+ switch ( *p ) {
+ case '\\':
+ if ( *++p == '\0' )
+ p--;
+ else
+ plen = LDAP_UTF8LEN(p);
+ break;
+ case '"':
+ if ( state == INQUOTE )
+ state = OUTQUOTE;
+ else
+ state = INQUOTE;
+ break;
+ case '+': if ( nametype != LDAP_RDN ) break;
+ case ';':
+ case ',':
+ case '\0':
+ if ( state == OUTQUOTE ) {
+ /*
+ * semicolon and comma are not valid RDN
+ * separators.
+ */
+ if ( nametype == LDAP_RDN &&
+ ( *p == ';' || *p == ',' || !goteq)) {
+ ldap_charray_free( rdns );
+ return NULL;
+ }
+ if ( (*p == ',' || *p == ';') && !goteq ) {
+ /* If we get here, we have a case similar
+ * to <attr>=<value>,<string>,<attr>=<value>
+ * This is not a valid dn */
+ ldap_charray_free( rdns );
+ return NULL;
+ }
+ goteq = 0;
+ ++count;
+ if ( rdns == NULL ) {
+ if (( rdns = (char **)NSLDAPI_MALLOC( 8
+ * sizeof( char *))) == NULL )
+ return( NULL );
+ } else if ( count >= 8 ) {
+ if (( rdns = (char **)NSLDAPI_REALLOC(
+ rdns, (count+1) *
+ sizeof( char *))) == NULL )
+ return( NULL );
+ }
+ rdns[ count ] = NULL;
+ endquote = 0;
+ if ( notypes ) {
+ for ( q = rdnstart;
+ q < p && *q != '='; ++q ) {
+ ;
+ }
+ if ( q < p ) { /* *q == '=' */
+ rdnstart = ++q;
+ }
+ if ( *rdnstart == '"' ) {
+ ++rdnstart;
+ }
+
+ if ( *(p-1) == '"' ) {
+ endquote = 1;
+ --p;
+ }
+ }
+
+ len = p - rdnstart;
+ if (( rdns[ count-1 ] = (char *)NSLDAPI_CALLOC(
+ 1, len + 1 )) != NULL ) {
+ SAFEMEMCPY( rdns[ count-1 ], rdnstart,
+ len );
+ if ( !endquote ) {
+ /* trim trailing spaces */
+ while ( len > 0 &&
+ ldap_utf8isspace(
+ &rdns[count-1][len-1] )) {
+ --len;
+ }
+ }
+ rdns[ count-1 ][ len ] = '\0';
+ }
+
+ /*
+ * Don't forget to increment 'p' back to where
+ * it should be. If we don't, then we will
+ * never get past an "end quote."
+ */
+ if ( endquote == 1 )
+ p++;
+
+ rdnstart = *p ? p + 1 : p;
+ while ( ldap_utf8isspace( rdnstart ))
+ ++rdnstart;
+ }
+ break;
+ case '=':
+ if ( state == OUTQUOTE ) {
+ goteq = 1;
+ }
+ /* FALL */
+ default:
+ plen = LDAP_UTF8LEN(p);
+ break;
+ }
+ } while ( *p );
+
+ return( rdns );
+}
+
+char **
+LDAP_CALL
+ldap_explode_dn( const char *dn, const int notypes )
+{
+ return( ldap_explode( dn, notypes, LDAP_DN ) );
+}
+
+char **
+LDAP_CALL
+ldap_explode_rdn( const char *rdn, const int notypes )
+{
+ return( ldap_explode( rdn, notypes, LDAP_RDN ) );
+}
+
+int
+LDAP_CALL
+ldap_is_dns_dn( const char *dn )
+{
+ return( dn != NULL && dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL &&
+ strchr( dn, ',' ) == NULL );
+}
+
+#ifdef _SOLARIS_SDK
+
+/*
+ * Convert a DNS domain name into an X.500 distinguished name.
+ * For example, "sales.wiz.com" -> "dc=sales,dc=wiz,dc=com"
+ *
+ * If an error is encountered zero is returned, otherwise a string
+ * distinguished name and the number of nameparts is returned.
+ * The caller should free the returned string if it is non-zero.
+ */
+
+char *
+ldap_dns_to_dn(
+ char *dns_name,
+ int *nameparts
+)
+{
+ size_t dns_len;
+ char *dn = 0;
+ char *cp;
+
+ /* check for NULL string, empty name and name ending in '.' */
+ if (dns_name && (dns_len = strlen(dns_name)) &&
+ (dns_name[dns_len - 1] != '.')) {
+ if (dn = (char *)malloc(dns_len * 3 + 1)) {
+ *nameparts = 0;
+ cp = dn;
+ while (*dns_name) {
+ *cp++ = 'd';
+ *cp++ = 'c';
+ *cp++ = '=';
+
+ while (*dns_name && (*dns_name != '.')) {
+ *cp++ = *dns_name++;
+ }
+ if (*dns_name == '.') {
+ dns_name++;
+ *cp++ = ',';
+ }
+ (*nameparts)++;
+ }
+ *cp = '\0';
+ }
+ }
+ return (dn);
+}
+
+#endif
+
diff --git a/usr/src/lib/libldap5/sources/ldap/common/getdxbyname.c b/usr/src/lib/libldap5/sources/ldap/common/getdxbyname.c
new file mode 100644
index 0000000000..617ff5a9c5
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/getdxbyname.c
@@ -0,0 +1,252 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * nsldapi_getdxbyname - retrieve DX records from the DNS (from
+ * TXT records for now)
+ */
+
+#include <stdio.h>
+
+#ifdef LDAP_DNS
+
+XXX not MT-safe XXX
+
+#include <string.h>
+#include <ctype.h>
+
+#ifdef macintosh
+#include <stdlib.h>
+#include "macos.h"
+#endif /* macintosh */
+
+#ifdef _WINDOWS
+#include <windows.h>
+#endif
+
+#if !defined(macintosh) && !defined(DOS) && !defined( _WINDOWS )
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <resolv.h>
+#endif
+#include "ldap-int.h"
+
+#if defined( DOS )
+#include "msdos.h"
+#endif /* DOS */
+
+
+#ifdef NEEDPROTOS
+static char ** decode_answer( unsigned char *answer, int len );
+#else /* NEEDPROTOS */
+static char **decode_answer();
+#endif /* NEEDPROTOS */
+
+extern int h_errno;
+extern char *h_errlist[];
+
+
+#define MAX_TO_SORT 32
+
+
+/*
+ * nsldapi_getdxbyname - lookup DNS DX records for domain and return an ordered
+ * array.
+ */
+char **
+nsldapi_getdxbyname( char *domain )
+{
+ unsigned char buf[ PACKETSZ ];
+ char **dxs;
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_getdxbyname( %s )\n", domain, 0, 0 );
+
+ memset( buf, 0, sizeof( buf ));
+
+ /* XXX not MT safe XXX */
+ if (( rc = res_search( domain, C_IN, T_TXT, buf, sizeof( buf ))) < 0
+ || ( dxs = decode_answer( buf, rc )) == NULL ) {
+ /*
+ * punt: return list conisting of the original domain name only
+ */
+ if (( dxs = (char **)NSLDAPI_MALLOC( 2 * sizeof( char * ))) == NULL ||
+ ( dxs[ 0 ] = nsldapi_strdup( domain )) == NULL ) {
+ if ( dxs != NULL ) {
+ NSLDAPI_FREE( dxs );
+ }
+ dxs = NULL;
+ } else {
+ dxs[ 1 ] = NULL;
+ }
+ }
+
+ return( dxs );
+}
+
+
+static char **
+decode_answer( unsigned char *answer, int len )
+{
+ HEADER *hp;
+ char buf[ 256 ], **dxs;
+ unsigned char *eom, *p;
+ int ancount, err, rc, type, class, dx_count, rr_len;
+ int dx_pref[ MAX_TO_SORT ];
+
+#ifdef LDAP_DEBUG
+ if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+/* __p_query( answer ); */
+ }
+#endif /* LDAP_DEBUG */
+
+ dxs = NULL;
+ hp = (HEADER *)answer;
+ eom = answer + len;
+
+ if ( ntohs( hp->qdcount ) != 1 ) {
+ h_errno = NO_RECOVERY;
+ return( NULL );
+ }
+
+ ancount = ntohs( hp->ancount );
+ if ( ancount < 1 ) {
+ h_errno = NO_DATA;
+ return( NULL );
+ }
+
+ /*
+ * skip over the query
+ */
+ p = answer + HFIXEDSZ;
+ if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
+ h_errno = NO_RECOVERY;
+ return( NULL );
+ }
+ p += ( rc + QFIXEDSZ );
+
+ /*
+ * pull out the answers we are interested in
+ */
+ err = dx_count = 0;
+ while ( ancount > 0 && err == 0 && p < eom ) {
+ if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
+ err = NO_RECOVERY;
+ continue;
+ }
+ p += rc; /* skip over name */
+ type = _getshort( p );
+ p += INT16SZ;
+ class = _getshort( p );
+ p += INT16SZ;
+ p += INT32SZ; /* skip over TTL */
+ rr_len = _getshort( p );
+ p += INT16SZ;
+ if ( class == C_IN && type == T_TXT ) {
+ int i, n, pref, txt_len;
+ char *q, *r;
+
+ q = (char *)p;
+ while ( q < (char *)p + rr_len && err == 0 ) {
+ if ( *q >= 3 && strncasecmp( q + 1, "dx:", 3 ) == 0 ) {
+ txt_len = *q - 3;
+ r = q + 4;
+ while ( isspace( *r )) {
+ ++r;
+ --txt_len;
+ }
+ pref = 0;
+ while ( isdigit( *r )) {
+ pref *= 10;
+ pref += ( *r - '0' );
+ ++r;
+ --txt_len;
+ }
+ if ( dx_count < MAX_TO_SORT - 1 ) {
+ dx_pref[ dx_count ] = pref;
+ }
+ while ( isspace( *r )) {
+ ++r;
+ --txt_len;
+ }
+ if ( dx_count == 0 ) {
+ dxs = (char **)NSLDAPI_MALLOC( 2 * sizeof( char * ));
+ } else {
+ dxs = (char **)NSLDAPI_REALLOC( dxs,
+ ( dx_count + 2 ) * sizeof( char * ));
+ }
+ if ( dxs == NULL || ( dxs[ dx_count ] =
+ (char *)NSLDAPI_CALLOC( 1, txt_len + 1 ))
+ == NULL ) {
+ err = NO_RECOVERY;
+ continue;
+ }
+ SAFEMEMCPY( dxs[ dx_count ], r, txt_len );
+ dxs[ ++dx_count ] = NULL;
+ }
+ q += ( *q + 1 ); /* move past last TXT record */
+ }
+ }
+ p += rr_len;
+ }
+
+ if ( err == 0 ) {
+ if ( dx_count == 0 ) {
+ err = NO_DATA;
+ } else {
+ /*
+ * sort records based on associated preference value
+ */
+ int i, j, sort_count, tmp_pref;
+ char *tmp_dx;
+
+ sort_count = ( dx_count < MAX_TO_SORT ) ? dx_count : MAX_TO_SORT;
+ for ( i = 0; i < sort_count; ++i ) {
+ for ( j = i + 1; j < sort_count; ++j ) {
+ if ( dx_pref[ i ] > dx_pref[ j ] ) {
+ tmp_pref = dx_pref[ i ];
+ dx_pref[ i ] = dx_pref[ j ];
+ dx_pref[ j ] = tmp_pref;
+ tmp_dx = dxs[ i ];
+ dxs[ i ] = dxs[ j ];
+ dxs[ j ] = tmp_dx;
+ }
+ }
+ }
+ }
+ }
+
+ h_errno = err;
+ return( dxs );
+}
+
+#endif /* LDAP_DNS */
diff --git a/usr/src/lib/libldap5/sources/ldap/common/getentry.c b/usr/src/lib/libldap5/sources/ldap/common/getentry.c
new file mode 100644
index 0000000000..1d3b588eac
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/getentry.c
@@ -0,0 +1,128 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * getentry.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+LDAPMessage *
+LDAP_CALL
+ldap_first_entry( LDAP *ld, LDAPMessage *chain )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || chain == NULLMSG ) {
+ return( NULLMSG );
+ }
+
+ if ( chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) {
+ return( chain );
+ }
+
+ return( ldap_next_entry( ld, chain ));
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_next_entry( LDAP *ld, LDAPMessage *entry )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || entry == NULLMSG ) {
+ return( NULLMSG );
+ }
+
+ for ( entry = entry->lm_chain; entry != NULLMSG;
+ entry = entry->lm_chain ) {
+ if ( entry->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) {
+ return( entry );
+ }
+ }
+
+ return( NULLMSG );
+}
+
+int
+LDAP_CALL
+ldap_count_entries( LDAP *ld, LDAPMessage *chain )
+{
+ int i;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 );
+ }
+
+ for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
+ if ( chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) {
+ ++i;
+ }
+ }
+
+ return( i );
+}
+
+
+int
+LDAP_CALL
+ldap_get_entry_controls( LDAP *ld, LDAPMessage *entry,
+ LDAPControl ***serverctrlsp )
+{
+ int rc;
+ BerElement tmpber;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_entry_controls\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )
+ || serverctrlsp == NULL ) {
+ rc = LDAP_PARAM_ERROR;
+ goto report_error_and_return;
+ }
+
+ *serverctrlsp = NULL;
+ tmpber = *entry->lm_ber; /* struct copy */
+
+ /* skip past dn and entire attribute/value list */
+ if ( ber_scanf( &tmpber, "{xx" ) == LBER_ERROR ) {
+ rc = LDAP_DECODING_ERROR;
+ goto report_error_and_return;
+ }
+
+ rc = nsldapi_get_controls( &tmpber, serverctrlsp );
+
+report_error_and_return:
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/getfilter.c b/usr/src/lib/libldap5/sources/ldap/common/getfilter.c
new file mode 100644
index 0000000000..3ecdfbb8ab
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/getfilter.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * getfilter.c -- optional add-on to libldap
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+#include "regex.h"
+#include <stdio.h> /* sprintf */
+
+static int break_into_words( char *str, char *delims, char ***wordsp );
+
+#if !defined( macintosh ) && !defined( DOS )
+extern char * LDAP_CALL re_comp();
+extern int LDAP_CALL re_exec( char *lp );
+#endif
+
+#define FILT_MAX_LINE_LEN 1024
+
+LDAPFiltDesc *
+LDAP_CALL
+ldap_init_getfilter( char *fname )
+{
+ FILE *fp;
+ char *buf;
+ ssize_t rlen, len;
+ int eof;
+ LDAPFiltDesc *lfdp;
+
+ if (( fp = fopen( fname, "r" )) == NULL ) {
+ return( NULL );
+ }
+
+ if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */
+ fclose( fp );
+ return( NULL );
+ }
+
+ len = ftell( fp );
+
+ if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */
+ fclose( fp );
+ return( NULL );
+ }
+
+ if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
+ fclose( fp );
+ return( NULL );
+ }
+
+ rlen = fread( buf, 1, (size_t)len, fp );
+ eof = feof( fp );
+ fclose( fp );
+
+ if ( rlen != len && !eof ) { /* error: didn't get the whole file */
+ NSLDAPI_FREE( buf );
+ return( NULL );
+ }
+
+
+ lfdp = ldap_init_getfilter_buf( buf, rlen );
+ NSLDAPI_FREE( buf );
+
+ return( lfdp );
+}
+
+
+LDAPFiltDesc *
+LDAP_CALL
+ldap_init_getfilter_buf( char *buf, ssize_t buflen )
+{
+ LDAPFiltDesc *lfdp;
+ LDAPFiltList *flp, *nextflp;
+ LDAPFiltInfo *fip, *nextfip;
+ char *tag, **tok;
+ int tokcnt, i;
+ long buffer_len = (long)buflen;
+
+ if ( (buf == NULL) || (buflen < 0) ||
+ ( lfdp = (LDAPFiltDesc *)NSLDAPI_CALLOC(1, sizeof( LDAPFiltDesc)))
+ == NULL ) {
+ return( NULL );
+ }
+
+ flp = nextflp = NULL;
+ fip = NULL;
+ tag = NULL;
+
+ while ( buflen > 0 && ( tokcnt = ldap_next_line_tokens( &buf,
+ &buffer_len, &tok )) > 0 ) {
+ switch( tokcnt ) {
+ case 1: /* tag line */
+ if ( tag != NULL ) {
+ NSLDAPI_FREE( tag );
+ }
+ tag = tok[ 0 ];
+ NSLDAPI_FREE( tok );
+ break;
+ case 4:
+ case 5: /* start of filter info. list */
+ if (( nextflp = (LDAPFiltList *)NSLDAPI_CALLOC( 1,
+ sizeof( LDAPFiltList ))) == NULL ) {
+ ldap_getfilter_free( lfdp );
+ return( NULL );
+ }
+ nextflp->lfl_tag = nsldapi_strdup( tag );
+ nextflp->lfl_pattern = tok[ 0 ];
+ if ( re_comp( nextflp->lfl_pattern ) != NULL ) {
+ char msg[256];
+ ldap_getfilter_free( lfdp );
+ sprintf( msg, dgettext(TEXT_DOMAIN,
+ "bad regular expresssion %s\n"),
+ nextflp->lfl_pattern );
+ ber_err_print( msg );
+ ldap_free_strarray( tok );
+ return( NULL );
+ }
+
+ nextflp->lfl_delims = tok[ 1 ];
+ nextflp->lfl_ilist = NULL;
+ nextflp->lfl_next = NULL;
+ if ( flp == NULL ) { /* first one */
+ lfdp->lfd_filtlist = nextflp;
+ } else {
+ flp->lfl_next = nextflp;
+ }
+ flp = nextflp;
+ fip = NULL;
+ for ( i = 2; i < 5; ++i ) {
+ tok[ i - 2 ] = tok[ i ];
+ }
+ /* fall through */
+
+ case 2:
+ case 3: /* filter, desc, and optional search scope */
+ if ( nextflp != NULL ) { /* add to info list */
+ if (( nextfip = (LDAPFiltInfo *)NSLDAPI_CALLOC( 1,
+ sizeof( LDAPFiltInfo ))) == NULL ) {
+ ldap_getfilter_free( lfdp );
+ ldap_free_strarray( tok );
+ return( NULL );
+ }
+ if ( fip == NULL ) { /* first one */
+ nextflp->lfl_ilist = nextfip;
+ } else {
+ fip->lfi_next = nextfip;
+ }
+ fip = nextfip;
+ nextfip->lfi_next = NULL;
+ nextfip->lfi_filter = tok[ 0 ];
+ nextfip->lfi_desc = tok[ 1 ];
+ if ( tok[ 2 ] != NULL ) {
+ if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) {
+ nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
+ } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) {
+ nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL;
+ } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) {
+ nextfip->lfi_scope = LDAP_SCOPE_BASE;
+ } else {
+ ldap_free_strarray( tok );
+ ldap_getfilter_free( lfdp );
+ return( NULL );
+ }
+ NSLDAPI_FREE( tok[ 2 ] );
+ tok[ 2 ] = NULL;
+ } else {
+ nextfip->lfi_scope = LDAP_SCOPE_SUBTREE; /* default */
+ }
+ nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
+ strchr( tok[ 0 ], '~' ) == NULL );
+ NSLDAPI_FREE( tok );
+ }
+ break;
+
+ default:
+ ldap_free_strarray( tok );
+ ldap_getfilter_free( lfdp );
+ return( NULL );
+ }
+ }
+
+ if ( tag != NULL ) {
+ NSLDAPI_FREE( tag );
+ }
+
+ return( lfdp );
+}
+
+
+int
+LDAP_CALL
+ldap_set_filter_additions( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
+{
+ if ( lfdp == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( lfdp->lfd_filtprefix != NULL ) {
+ NSLDAPI_FREE( lfdp->lfd_filtprefix );
+ }
+ lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : nsldapi_strdup( prefix );
+
+ if ( lfdp->lfd_filtsuffix != NULL ) {
+ NSLDAPI_FREE( lfdp->lfd_filtsuffix );
+ }
+ lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : nsldapi_strdup( suffix );
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * ldap_setfilteraffixes() is deprecated -- use ldap_set_filter_additions()
+ */
+void
+LDAP_CALL
+ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
+{
+ (void)ldap_set_filter_additions( lfdp, prefix, suffix );
+}
+
+
+LDAPFiltInfo *
+LDAP_CALL
+ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value )
+{
+ LDAPFiltList *flp;
+
+ if ( lfdp == NULL || tagpat == NULL || value == NULL ) {
+ return( NULL ); /* punt */
+ }
+
+ if ( lfdp->lfd_curvalcopy != NULL ) {
+ NSLDAPI_FREE( lfdp->lfd_curvalcopy );
+ NSLDAPI_FREE( lfdp->lfd_curvalwords );
+ }
+
+ lfdp->lfd_curval = value;
+ lfdp->lfd_curfip = NULL;
+
+ for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
+ if ( re_comp( tagpat ) == NULL && re_exec( flp->lfl_tag ) == 1
+ && re_comp( flp->lfl_pattern ) == NULL
+ && re_exec( lfdp->lfd_curval ) == 1 ) {
+ lfdp->lfd_curfip = flp->lfl_ilist;
+ break;
+ }
+ }
+
+ if ( lfdp->lfd_curfip == NULL ) {
+ return( NULL );
+ }
+
+ if (( lfdp->lfd_curvalcopy = nsldapi_strdup( value )) == NULL ) {
+ return( NULL );
+ }
+
+ if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
+ &lfdp->lfd_curvalwords ) < 0 ) {
+ NSLDAPI_FREE( lfdp->lfd_curvalwords );
+ lfdp->lfd_curvalwords = NULL;
+ return( NULL );
+ }
+
+ return( ldap_getnextfilter( lfdp ));
+}
+
+
+LDAPFiltInfo *
+LDAP_CALL
+ldap_getnextfilter( LDAPFiltDesc *lfdp )
+{
+ LDAPFiltInfo *fip;
+
+ if ( lfdp == NULL || ( fip = lfdp->lfd_curfip ) == NULL ) {
+ return( NULL );
+ }
+
+ lfdp->lfd_curfip = fip->lfi_next;
+
+ ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
+ lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
+ lfdp->lfd_curval, lfdp->lfd_curvalwords );
+ lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
+ lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
+ lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
+ lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
+
+ return( &lfdp->lfd_retfi );
+}
+
+
+static char*
+filter_add_strn( char *f, char *flimit, char *v, size_t vlen )
+ /* Copy v into f. If flimit is too small, return NULL;
+ * otherwise return (f + vlen).
+ */
+{
+ auto size_t flen = flimit - f;
+ if ( vlen > flen ) { /* flimit is too small */
+ if ( flen > 0 ) SAFEMEMCPY( f, v, flen );
+ return NULL;
+ }
+ if ( vlen > 0 ) SAFEMEMCPY( f, v, vlen );
+ return f + vlen;
+}
+
+static char*
+filter_add_value( char *f, char *flimit, char *v, int escape_all )
+ /* Copy v into f, but with parentheses escaped. But only escape * and \
+ * if escape_all is non-zero so that either "*" or "\2a" can be used in
+ * v, with different meanings.
+ * If flimit is too small, return NULL; otherwise
+ * return (f + the number of bytes copied).
+ */
+{
+ auto char x[4];
+ auto size_t slen;
+ while ( f && *v ) {
+ switch ( *v ) {
+ case '*':
+ if ( escape_all ) {
+ f = filter_add_strn( f, flimit, "\\2a", 3 );
+ v++;
+ } else {
+ if ( f < flimit ) {
+ *f++ = *v++;
+ } else {
+ f = NULL; /* overflow */
+ }
+ }
+ break;
+
+ case '(':
+ case ')':
+ sprintf( x, "\\%02x", (unsigned)*v );
+ f = filter_add_strn( f, flimit, x, 3 );
+ v++;
+ break;
+
+ case '\\':
+ if ( escape_all ) {
+ f = filter_add_strn( f, flimit, "\\5c", 3 );
+ v++;
+ } else {
+ slen = (ldap_utf8isxdigit( v+1 ) &&
+ ldap_utf8isxdigit( v+2 )) ? 3 : (v[1] ? 2 : 1);
+ f = filter_add_strn( f, flimit, v, slen );
+ v += slen;
+ }
+ break;
+
+ default:
+ if ( f < flimit ) {
+ *f++ = *v++;
+ } else {
+ f = NULL; /* overflow */
+ }
+ break;
+ }
+ }
+ return f;
+}
+
+int
+LDAP_CALL
+ldap_create_filter( char *filtbuf, unsigned long buflen, char *pattern,
+ char *prefix, char *suffix, char *attr, char *value, char **valwords )
+{
+ char *p, *f, *flimit;
+ int i, wordcount, wordnum, endwordnum, escape_all;
+
+ /*
+ * there is some confusion on what to create for a filter if
+ * attr or value are null pointers. For now we just leave them
+ * as TO BE DEALT with
+ */
+
+ if ( filtbuf == NULL || buflen == 0 || pattern == NULL ){
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( valwords == NULL ) {
+ wordcount = 0;
+ } else {
+ for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
+ ;
+ }
+ }
+
+ f = filtbuf;
+ flimit = filtbuf + buflen - 1;
+
+ if ( prefix != NULL ) {
+ f = filter_add_strn( f, flimit, prefix, strlen( prefix ));
+ }
+
+ for ( p = pattern; f != NULL && *p != '\0'; ++p ) {
+ if ( *p == '%' ) {
+ ++p;
+ if ( *p == 'v' || *p == 'e' ) {
+ escape_all = ( *p == 'e' );
+ if ( ldap_utf8isdigit( p+1 )) {
+ ++p;
+ wordnum = *p - '1';
+ if ( *(p+1) == '-' ) {
+ ++p;
+ if ( ldap_utf8isdigit( p+1 )) {
+ ++p;
+ endwordnum = *p - '1'; /* e.g., "%v2-4" */
+ if ( endwordnum > wordcount - 1 ) {
+ endwordnum = wordcount - 1;
+ }
+ } else {
+ endwordnum = wordcount - 1; /* e.g., "%v2-" */
+ }
+ } else {
+ endwordnum = wordnum; /* e.g., "%v2" */
+ }
+
+ if ( wordcount > 0 ) {
+ for ( i = wordnum; i <= endwordnum; ++i ) {
+ if ( i > wordnum ) { /* add blank btw words */
+ f = filter_add_strn( f, flimit, " ", 1 );
+ if ( f == NULL ) break;
+ }
+ f = filter_add_value( f, flimit, valwords[ i ],
+ escape_all );
+ if ( f == NULL ) break;
+ }
+ }
+ } else if ( *(p+1) == '$' ) {
+ ++p;
+ if ( wordcount > 0 ) {
+ wordnum = wordcount - 1;
+ f = filter_add_value( f, flimit,
+ valwords[ wordnum ], escape_all );
+ }
+ } else if ( value != NULL ) {
+ f = filter_add_value( f, flimit, value, escape_all );
+ }
+ } else if ( *p == 'a' && attr != NULL ) {
+ f = filter_add_strn( f, flimit, attr, strlen( attr ));
+ } else {
+ *f++ = *p;
+ }
+ } else {
+ *f++ = *p;
+ }
+ if ( f > flimit ) { /* overflow */
+ f = NULL;
+ }
+ }
+
+ if ( suffix != NULL && f != NULL) {
+ f = filter_add_strn( f, flimit, suffix, strlen( suffix ));
+ }
+
+ if ( f == NULL ) {
+ *flimit = '\0';
+ return( LDAP_SIZELIMIT_EXCEEDED );
+ }
+ *f = '\0';
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * ldap_build_filter() is deprecated -- use ldap_create_filter() instead
+ */
+void
+LDAP_CALL
+ldap_build_filter( char *filtbuf, size_t buflen, char *pattern,
+ char *prefix, char *suffix, char *attr, char *value, char **valwords )
+{
+ (void)ldap_create_filter( filtbuf, buflen, pattern, prefix, suffix, attr,
+ value, valwords );
+}
+
+
+static int
+break_into_words( char *str, char *delims, char ***wordsp )
+{
+ char *word, **words;
+ int count;
+ char *lasts;
+
+ if (( words = (char **)NSLDAPI_CALLOC( 1, sizeof( char * ))) == NULL ) {
+ return( -1 );
+ }
+ count = 0;
+ words[ count ] = NULL;
+
+ word = ldap_utf8strtok_r( str, delims, &lasts );
+ while ( word != NULL ) {
+ if (( words = (char **)NSLDAPI_REALLOC( words,
+ ( count + 2 ) * sizeof( char * ))) == NULL ) {
+ return( -1 );
+ }
+
+ words[ count ] = word;
+ words[ ++count ] = NULL;
+ word = ldap_utf8strtok_r( NULL, delims, &lasts );
+ }
+
+ *wordsp = words;
+ return( count );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/getoption.c b/usr/src/lib/libldap5/sources/ldap/common/getoption.c
new file mode 100644
index 0000000000..da799fbc55
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/getoption.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+#include "ldap-int.h"
+
+#define LDAP_GET_BITOPT( ld, bit ) \
+ ((ld)->ld_options & bit ) != 0 ? 1 : 0
+
+static int nsldapi_get_api_info( LDAPAPIInfo *aip );
+static int nsldapi_get_feature_info( LDAPAPIFeatureInfo *fip );
+
+
+int
+LDAP_CALL
+ldap_get_option( LDAP *ld, int option, void *optdata )
+{
+ int rc = 0;
+
+ if ( !nsldapi_initialized ) {
+ nsldapi_initialize_defaults();
+ }
+
+ /*
+ * optdata MUST be a valid pointer...
+ */
+ if (NULL == optdata)
+ {
+ return(LDAP_PARAM_ERROR);
+ }
+ /*
+ * process global options (not associated with an LDAP session handle)
+ */
+ if ( option == LDAP_OPT_MEMALLOC_FN_PTRS ) {
+ /* struct copy */
+ *((struct ldap_memalloc_fns *)optdata) = nsldapi_memalloc_fns;
+ return( 0 );
+ }
+
+ if ( option == LDAP_OPT_API_INFO ) {
+ rc = nsldapi_get_api_info( (LDAPAPIInfo *)optdata );
+ if ( rc != LDAP_SUCCESS ) {
+ if ( ld != NULL ) {
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ }
+ return( -1 );
+ }
+ return( 0 );
+ }
+ /*
+ * LDAP_OPT_DEBUG_LEVEL is global
+ */
+ if (LDAP_OPT_DEBUG_LEVEL == option)
+ {
+#ifdef LDAP_DEBUG
+ *((int *) optdata) = ldap_debug;
+#endif /* LDAP_DEBUG */
+ return ( 0 );
+ }
+
+ /*
+ * if ld is NULL, arrange to return options from our default settings
+ */
+ if ( ld == NULL ) {
+ ld = &nsldapi_ld_defaults;
+ }
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 ); /* punt */
+ }
+
+
+ if (ld != &nsldapi_ld_defaults)
+ LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+ switch( option ) {
+#ifdef LDAP_DNS
+ case LDAP_OPT_DNS:
+ *((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_DNS );
+ break;
+#endif
+
+ case LDAP_OPT_REFERRALS:
+ *((int *) optdata) =
+ LDAP_GET_BITOPT( ld, LDAP_BITOPT_REFERRALS );
+ break;
+
+#ifdef LDAP_SSLIO_HOOKS
+ case LDAP_OPT_SSL:
+ *((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_SSL );
+ break;
+#endif
+ case LDAP_OPT_RESTART:
+ *((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_RESTART );
+ break;
+
+ case LDAP_OPT_RECONNECT:
+ *((int *) optdata) =
+ LDAP_GET_BITOPT( ld, LDAP_BITOPT_RECONNECT );
+ break;
+
+#ifdef LDAP_ASYNC_IO
+ case LDAP_OPT_ASYNC_CONNECT:
+ *((int *) optdata) =
+ LDAP_GET_BITOPT( ld, LDAP_BITOPT_ASYNC );
+ break;
+#endif /* LDAP_ASYNC_IO */
+
+ /* stuff in the sockbuf */
+ case LDAP_X_OPT_SOCKBUF:
+ *((Sockbuf **) optdata) = ld->ld_sbp;
+ break;
+ case LDAP_OPT_DESC:
+ if ( ber_sockbuf_get_option( ld->ld_sbp,
+ LBER_SOCKBUF_OPT_DESC, optdata ) != 0 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ rc = -1;
+ }
+ break;
+
+ /* fields in the LDAP structure */
+ case LDAP_OPT_DEREF:
+ *((int *) optdata) = ld->ld_deref;
+ break;
+ case LDAP_OPT_SIZELIMIT:
+ *((int *) optdata) = ld->ld_sizelimit;
+ break;
+ case LDAP_OPT_TIMELIMIT:
+ *((int *) optdata) = ld->ld_timelimit;
+ break;
+ case LDAP_OPT_REFERRAL_HOP_LIMIT:
+ *((int *) optdata) = ld->ld_refhoplimit;
+ break;
+ case LDAP_OPT_PROTOCOL_VERSION:
+ *((int *) optdata) = ld->ld_version;
+ break;
+ case LDAP_OPT_SERVER_CONTROLS:
+ /* fall through */
+ case LDAP_OPT_CLIENT_CONTROLS:
+ *((LDAPControl ***)optdata) = NULL;
+ /* nsldapi_dup_controls returns -1 and sets lderrno on error */
+ rc = nsldapi_dup_controls( ld, (LDAPControl ***)optdata,
+ ( option == LDAP_OPT_SERVER_CONTROLS ) ?
+ ld->ld_servercontrols : ld->ld_clientcontrols );
+ break;
+
+ /* rebind proc */
+ case LDAP_OPT_REBIND_FN:
+ *((LDAP_REBINDPROC_CALLBACK **) optdata) = ld->ld_rebind_fn;
+ break;
+ case LDAP_OPT_REBIND_ARG:
+ *((void **) optdata) = ld->ld_rebind_arg;
+ break;
+
+#ifdef LDAP_SSLIO_HOOKS
+ /* i/o function pointers */
+ case LDAP_OPT_IO_FN_PTRS:
+ if ( ld->ld_io_fns_ptr == NULL ) {
+ memset( optdata, 0, sizeof( struct ldap_io_fns ));
+ } else {
+ /* struct copy */
+ *((struct ldap_io_fns *)optdata) = *(ld->ld_io_fns_ptr);
+ }
+ break;
+
+ /* extended i/o function pointers */
+ case LDAP_X_OPT_EXTIO_FN_PTRS:
+ if ( ((struct ldap_x_ext_io_fns *) optdata)->lextiof_size == LDAP_X_EXTIO_FNS_SIZE_REV0) {
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_close = ld->ld_extclose_fn;
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_connect = ld->ld_extconnect_fn;
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_read = ld->ld_extread_fn;
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_write = ld->ld_extwrite_fn;
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_poll = ld->ld_extpoll_fn;
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_newhandle = ld->ld_extnewhandle_fn;
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_disposehandle = ld->ld_extdisposehandle_fn;
+ ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_session_arg = ld->ld_ext_session_arg;
+ } else if ( ((struct ldap_x_ext_io_fns *) optdata)->lextiof_size ==
+ LDAP_X_EXTIO_FNS_SIZE ) {
+ /* struct copy */
+ *((struct ldap_x_ext_io_fns *) optdata) = ld->ld_ext_io_fns;
+ } else {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ rc = -1;
+ }
+ break;
+#endif /* LDAP_SSLIO_HOOKS */
+
+ /* thread function pointers */
+ case LDAP_OPT_THREAD_FN_PTRS:
+ /* struct copy */
+ *((struct ldap_thread_fns *) optdata) = ld->ld_thread;
+ break;
+
+ /* DNS function pointers */
+ case LDAP_OPT_DNS_FN_PTRS:
+ /* struct copy */
+ *((struct ldap_dns_fns *) optdata) = ld->ld_dnsfn;
+ break;
+
+ /* cache function pointers */
+ case LDAP_OPT_CACHE_FN_PTRS:
+ /* struct copy */
+ *((struct ldap_cache_fns *) optdata) = ld->ld_cache;
+ break;
+ case LDAP_OPT_CACHE_STRATEGY:
+ *((int *) optdata) = ld->ld_cache_strategy;
+ break;
+ case LDAP_OPT_CACHE_ENABLE:
+ *((int *) optdata) = ld->ld_cache_on;
+ break;
+
+ case LDAP_OPT_ERROR_NUMBER:
+ *((int *) optdata) = LDAP_GET_LDERRNO( ld, NULL, NULL );
+ break;
+
+ case LDAP_OPT_ERROR_STRING:
+ (void)LDAP_GET_LDERRNO( ld, NULL, (char **)optdata );
+ *((char **) optdata) = nsldapi_strdup( *((char **) optdata ));
+ break;
+
+ case LDAP_OPT_MATCHED_DN:
+ (void)LDAP_GET_LDERRNO( ld, (char **)optdata, NULL );
+ *((char **) optdata) = nsldapi_strdup( *((char **) optdata ));
+ break;
+
+ case LDAP_OPT_PREFERRED_LANGUAGE:
+ if ( NULL != ld->ld_preferred_language ) {
+ *((char **) optdata) =
+ nsldapi_strdup(ld->ld_preferred_language);
+ } else {
+ *((char **) optdata) = NULL;
+ }
+ break;
+
+ case LDAP_OPT_API_FEATURE_INFO:
+ rc = nsldapi_get_feature_info( (LDAPAPIFeatureInfo *)optdata );
+ if ( rc != LDAP_SUCCESS ) {
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ rc = -1;
+ }
+ break;
+
+ case LDAP_OPT_HOST_NAME:
+ *((char **) optdata) = nsldapi_strdup( ld->ld_defhost );
+ break;
+
+ case LDAP_X_OPT_CONNECT_TIMEOUT:
+ *((int *) optdata) = ld->ld_connect_timeout;
+ break;
+
+#ifdef LDAP_SASLIO_HOOKS
+ /* SASL options */
+ case LDAP_OPT_X_SASL_MECH:
+ *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_mech);
+ break;
+ case LDAP_OPT_X_SASL_REALM:
+ *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_realm);
+ break;
+ case LDAP_OPT_X_SASL_AUTHCID:
+ *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_authcid);
+ break;
+ case LDAP_OPT_X_SASL_AUTHZID:
+ *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_authzid);
+ break;
+ case LDAP_OPT_X_SASL_SSF:
+ {
+ int sc;
+ sasl_ssf_t *ssf;
+ sasl_conn_t *ctx;
+ if( ld->ld_defconn == NULL ||
+ ld->ld_defconn->lconn_sb == NULL ) {
+ return -1;
+ }
+ ctx = (sasl_conn_t *)(ld->ld_defconn->lconn_sb->sb_sasl_ctx);
+ if ( ctx == NULL ) {
+ return -1;
+ }
+ sc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
+ if ( sc != SASL_OK ) {
+ return -1;
+ }
+ *((sasl_ssf_t *) optdata) = *ssf;
+ }
+ break;
+ case LDAP_OPT_X_SASL_SSF_MIN:
+ *((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.min_ssf;
+ break;
+ case LDAP_OPT_X_SASL_SSF_MAX:
+ *((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.max_ssf;
+ break;
+ case LDAP_OPT_X_SASL_MAXBUFSIZE:
+ *((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.maxbufsize;
+ break;
+ case LDAP_OPT_X_SASL_SSF_EXTERNAL:
+ case LDAP_OPT_X_SASL_SECPROPS:
+ /*
+ * These options are write only. Making these options
+ * read/write would expose semi-private interfaces of libsasl
+ * for which there are no cross platform/standardized
+ * definitions.
+ */
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ rc = -1;
+ break;
+#endif
+
+ default:
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ rc = -1;
+ }
+ if (ld != &nsldapi_ld_defaults)
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+ return( rc );
+}
+
+
+/*
+ * Table of extended API features we support.
+ * The first field is the version of the info. strcuture itself; we do not
+ * use the ones from this table so it is okay to leave as zero.
+ */
+static LDAPAPIFeatureInfo nsldapi_extensions[] = {
+ { 0, "SERVER_SIDE_SORT", LDAP_API_FEATURE_SERVER_SIDE_SORT },
+ { 0, "VIRTUAL_LIST_VIEW", LDAP_API_FEATURE_VIRTUAL_LIST_VIEW },
+ { 0, "PERSISTENT_SEARCH", LDAP_API_FEATURE_PERSISTENT_SEARCH },
+ { 0, "PROXY_AUTHORIZATION", LDAP_API_FEATURE_PROXY_AUTHORIZATION },
+ { 0, "X_LDERRNO", LDAP_API_FEATURE_X_LDERRNO },
+ { 0, "X_MEMCACHE", LDAP_API_FEATURE_X_MEMCACHE },
+ { 0, "X_IO_FUNCTIONS", LDAP_API_FEATURE_X_IO_FUNCTIONS },
+ { 0, "X_EXTIO_FUNCTIONS", LDAP_API_FEATURE_X_EXTIO_FUNCTIONS },
+ { 0, "X_DNS_FUNCTIONS", LDAP_API_FEATURE_X_DNS_FUNCTIONS },
+ { 0, "X_MEMALLOC_FUNCTIONS", LDAP_API_FEATURE_X_MEMALLOC_FUNCTIONS },
+ { 0, "X_THREAD_FUNCTIONS", LDAP_API_FEATURE_X_THREAD_FUNCTIONS },
+ { 0, "X_EXTHREAD_FUNCTIONS", LDAP_API_FEATURE_X_EXTHREAD_FUNCTIONS },
+ { 0, "X_GETLANGVALUES", LDAP_API_FEATURE_X_GETLANGVALUES },
+ { 0, "X_CLIENT_SIDE_SORT", LDAP_API_FEATURE_X_CLIENT_SIDE_SORT },
+ { 0, "X_URL_FUNCTIONS", LDAP_API_FEATURE_X_URL_FUNCTIONS },
+ { 0, "X_FILTER_FUNCTIONS", LDAP_API_FEATURE_X_FILTER_FUNCTIONS },
+};
+
+#define NSLDAPI_EXTENSIONS_COUNT \
+ (sizeof(nsldapi_extensions)/sizeof(LDAPAPIFeatureInfo))
+
+/*
+ * Retrieve information about this implementation of the LDAP API.
+ * Returns an LDAP error code.
+ */
+static int
+nsldapi_get_api_info( LDAPAPIInfo *aip )
+{
+ int i;
+
+ if ( aip == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ aip->ldapai_api_version = LDAP_API_VERSION;
+
+ if ( aip->ldapai_info_version != LDAP_API_INFO_VERSION ) {
+ aip->ldapai_info_version = LDAP_API_INFO_VERSION;
+ return( LDAP_PARAM_ERROR );
+ }
+
+ aip->ldapai_protocol_version = LDAP_VERSION_MAX;
+ aip->ldapai_vendor_version = LDAP_VENDOR_VERSION;
+
+ if (( aip->ldapai_vendor_name = nsldapi_strdup( LDAP_VENDOR_NAME ))
+ == NULL ) {
+ return( LDAP_NO_MEMORY );
+ }
+
+ if ( NSLDAPI_EXTENSIONS_COUNT < 1 ) {
+ aip->ldapai_extensions = NULL;
+ } else {
+ if (( aip->ldapai_extensions = NSLDAPI_CALLOC(
+ NSLDAPI_EXTENSIONS_COUNT + 1, sizeof(char *))) == NULL ) {
+ NSLDAPI_FREE( aip->ldapai_vendor_name );
+ aip->ldapai_vendor_name = NULL;
+ return( LDAP_NO_MEMORY );
+ }
+
+ for ( i = 0; i < NSLDAPI_EXTENSIONS_COUNT; ++i ) {
+ if (( aip->ldapai_extensions[i] = nsldapi_strdup(
+ nsldapi_extensions[i].ldapaif_name )) == NULL ) {
+ ldap_value_free( aip->ldapai_extensions );
+ NSLDAPI_FREE( aip->ldapai_vendor_name );
+ aip->ldapai_extensions = NULL;
+ aip->ldapai_vendor_name = NULL;
+ return( LDAP_NO_MEMORY );
+ }
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Retrieves information about a specific extended feature of the LDAP API/
+ * Returns an LDAP error code.
+ */
+static int
+nsldapi_get_feature_info( LDAPAPIFeatureInfo *fip )
+{
+ int i;
+
+ if ( fip == NULL || fip->ldapaif_name == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( fip->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION ) {
+ fip->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
+ return( LDAP_PARAM_ERROR );
+ }
+
+ for ( i = 0; i < NSLDAPI_EXTENSIONS_COUNT; ++i ) {
+ if ( strcmp( fip->ldapaif_name,
+ nsldapi_extensions[i].ldapaif_name ) == 0 ) {
+ fip->ldapaif_version =
+ nsldapi_extensions[i].ldapaif_version;
+ break;
+ }
+ }
+
+ return(( i < NSLDAPI_EXTENSIONS_COUNT ) ? LDAP_SUCCESS
+ : LDAP_PARAM_ERROR );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/getvalues.c b/usr/src/lib/libldap5/sources/ldap/common/getvalues.c
new file mode 100644
index 0000000000..51cddff2d6
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/getvalues.c
@@ -0,0 +1,478 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * getvalues.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+
+static void **
+internal_ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target,
+ int lencall )
+{
+ struct berelement ber;
+ char *attr;
+ int rc;
+ void **vals;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( NULL ); /* punt */
+ }
+ if ( target == NULL ||
+ !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( NULL );
+ }
+
+ ber = *entry->lm_ber;
+
+ /* skip sequence, dn, sequence of, and snag the first attr */
+ if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ return( NULL );
+ }
+
+ rc = strcasecmp( (char *)target, attr );
+ NSLDAPI_FREE( attr );
+ if ( rc != 0 ) {
+ while ( 1 ) {
+ if ( ber_scanf( &ber, "x}{a", &attr ) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR,
+ NULL, NULL );
+ return( NULL );
+ }
+
+ rc = strcasecmp( (char *)target, attr );
+ if ( rc == 0 ) {
+ NSLDAPI_FREE( attr );
+ break;
+ }
+ NSLDAPI_FREE( attr );
+ }
+ }
+
+ /*
+ * if we get this far, we've found the attribute and are sitting
+ * just before the set of values.
+ */
+
+ if ( lencall ) {
+ rc = ber_scanf( &ber, "[V]", &vals );
+ } else {
+ rc = ber_scanf( &ber, "[v]", &vals );
+ }
+
+ if ( rc == LBER_ERROR ) {
+ rc = LDAP_DECODING_ERROR;
+ } else {
+ rc = LDAP_SUCCESS;
+ }
+
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+
+ return(( rc == LDAP_SUCCESS ) ? vals : NULL );
+}
+
+
+/* For language-sensitive attribute matching, we are looking for a
+ language tag that looks like one of the following:
+
+ cn
+ cn;lang-en
+ cn;lang-en-us
+ cn;lang-ja
+ cn;lang-ja-JP-kanji
+
+ The base language specification consists of two letters following
+ "lang-". After that, there may be additional language-specific
+ narrowings preceded by a "-". In our processing we go from the
+ specific to the general, preferring a complete subtype match, but
+ accepting a partial one. For example:
+
+ For a request for "cn;lang-en-us", we would return cn;lang-en-us
+ if present, otherwise cn;lang-en if present, otherwise cn.
+
+ Besides the language subtype, there may be other subtypes:
+
+ cn;lang-ja;binary (Unlikely!)
+ cn;lang-ja;phonetic
+
+ If not in the target, they are ignored. If they are in the target,
+ they must be in the attribute to match.
+*/
+#define LANG_SUBTYPE_INDEX_NONE -1
+#define LANG_SUBTYPE_INDEX_DUPLICATE -2
+
+typedef struct {
+ int start;
+ int length;
+} _SubStringIndex;
+
+static int
+parse_subtypes( const char *target, int *baseLenp, char **langp,
+ _SubStringIndex **subs, int *nsubtypes )
+{
+ int nSubtypes = 0;
+ int ind = 0;
+ char *nextToken;
+ _SubStringIndex *result = NULL;
+ int langIndex;
+ int targetLen;
+ int subtypeStart;
+
+ langIndex = LANG_SUBTYPE_INDEX_NONE;
+ *subs = NULL;
+ *langp = NULL;
+ *baseLenp = 0;
+ *nsubtypes = 0;
+ targetLen = strlen( target );
+
+ /* Parse past base attribute */
+ nextToken = strchr( target, ';' );
+ if ( NULL != nextToken ) {
+ subtypeStart = nextToken - target + 1;
+ *baseLenp = subtypeStart - 1;
+ }
+ else {
+ subtypeStart = targetLen;
+ *baseLenp = subtypeStart;
+ }
+ ind = subtypeStart;
+
+ /* How many subtypes? */
+ nextToken = (char *)target + subtypeStart;
+ while ( nextToken && *nextToken ) {
+ char *thisToken = nextToken;
+ nextToken = strchr( thisToken, ';' );
+ if ( NULL != nextToken )
+ nextToken++;
+ if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
+ /* If there was a previous lang tag, this is illegal! */
+ if ( langIndex != LANG_SUBTYPE_INDEX_NONE ) {
+ langIndex = LANG_SUBTYPE_INDEX_DUPLICATE;
+ return langIndex;
+ }
+ else {
+ langIndex = nSubtypes;
+ }
+ } else {
+ nSubtypes++;
+ }
+ }
+ /* No language subtype? */
+ if ( langIndex < 0 )
+ return langIndex;
+
+ /* Allocate array of non-language subtypes */
+ if ( nSubtypes > 0 ) {
+ result = (_SubStringIndex *)NSLDAPI_MALLOC( sizeof(*result)
+ * nSubtypes );
+ if (result == NULL) {
+ return LANG_SUBTYPE_INDEX_NONE; /* Error */
+ }
+ memset( result, 0, sizeof(*result) * nSubtypes );
+ }
+ ind = 0;
+ nSubtypes = 0;
+ ind = subtypeStart;
+ nextToken = (char *)target + subtypeStart;
+ while ( nextToken && *nextToken ) {
+ char *thisToken = nextToken;
+ int len;
+ nextToken = strchr( thisToken, ';' );
+ if ( NULL != nextToken ) {
+ len = nextToken - thisToken;
+ nextToken++;
+ }
+ else {
+ nextToken = (char *)target + targetLen;
+ len = nextToken - thisToken;
+ }
+ if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
+ int i;
+ *langp = (char *)NSLDAPI_MALLOC( len + 1 );
+ if (*langp == NULL) {
+ if (result != NULL)
+ NSLDAPI_FREE(result);
+ return LANG_SUBTYPE_INDEX_NONE; /* Error */
+ }
+ for( i = 0; i < len; i++ )
+ (*langp)[i] = toupper( target[ind+i] );
+ (*langp)[len] = 0;
+ }
+ else {
+ result[nSubtypes].start = thisToken - target;
+ result[nSubtypes].length = len;
+ nSubtypes++;
+ }
+ }
+ *subs = result;
+ *nsubtypes = nSubtypes;
+ return langIndex;
+}
+
+
+static int
+check_lang_match( const char *target, const char *baseTarget,
+ _SubStringIndex *targetTypes,
+ int ntargetTypes, char *targetLang, char *attr )
+{
+ int langIndex;
+ _SubStringIndex *subtypes;
+ int baseLen;
+ char *lang;
+ int nsubtypes;
+ int mismatch = 0;
+ int match = -1;
+ int i;
+
+ /* Get all subtypes in the attribute name */
+ langIndex = parse_subtypes( attr, &baseLen, &lang, &subtypes, &nsubtypes );
+
+ /* Check if there any required non-language subtypes which are
+ not in this attribute */
+ for( i = 0; i < ntargetTypes; i++ ) {
+ char *t = (char *)target+targetTypes[i].start;
+ int tlen = targetTypes[i].length;
+ int j;
+ for( j = 0; j < nsubtypes; j++ ) {
+ char *a = attr + subtypes[j].start;
+ int alen = subtypes[j].length;
+ if ( (tlen == alen) && !strncasecmp( t, a, tlen ) )
+ break;
+ }
+ if ( j >= nsubtypes ) {
+ mismatch = 1;
+ break;
+ }
+ }
+ if ( mismatch ) {
+ if ( NULL != subtypes )
+ NSLDAPI_FREE( subtypes );
+ if ( NULL != lang )
+ NSLDAPI_FREE( lang );
+ return -1;
+ }
+
+ /* If there was no language subtype... */
+ if ( langIndex < 0 ) {
+ if ( NULL != subtypes )
+ NSLDAPI_FREE( subtypes );
+ if ( NULL != lang )
+ NSLDAPI_FREE( lang );
+ if ( LANG_SUBTYPE_INDEX_NONE == langIndex )
+ return 0;
+ else
+ return -1;
+ }
+
+ /* Okay, now check the language subtag */
+ i = 0;
+ while( targetLang[i] && lang[i] &&
+ (toupper(targetLang[i]) == toupper(lang[i])) )
+ i++;
+
+ /* The total length can't be longer than the requested subtype */
+ if ( !lang[i] || (lang[i] == ';') ) {
+ /* If the found subtype is shorter than the requested one, the next
+ character in the requested one should be "-" */
+ if ( !targetLang[i] || (targetLang[i] == '-') )
+ match = i;
+ }
+ return match;
+}
+
+static int check_base_match( const char *target, char *attr )
+{
+ int i = 0;
+ int rc;
+ while( target[i] && attr[i] && (toupper(target[i]) == toupper(attr[i])) )
+ i++;
+ rc = ( !target[i] && (!attr[i] || (';' == attr[i])) );
+ return rc;
+}
+
+static void **
+internal_ldap_get_lang_values( LDAP *ld, LDAPMessage *entry,
+ const char *target, char **type, int lencall )
+{
+ struct berelement ber;
+ char *attr = NULL;
+ int rc;
+ void **vals = NULL;
+ int langIndex;
+ _SubStringIndex *subtypes;
+ int nsubtypes;
+ char *baseTarget = NULL;
+ int bestMatch = 0;
+ char *lang = NULL;
+ int len;
+ int firstAttr = 1;
+ char *bestType = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( NULL );
+ }
+ if ( (target == NULL) ||
+ !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( NULL );
+ }
+
+ /* A language check was requested, so see if there really is a
+ language subtype in the attribute spec */
+ langIndex = parse_subtypes( target, &len, &lang,
+ &subtypes, &nsubtypes );
+ if ( langIndex < 0 ) {
+ if ( NULL != subtypes ) {
+ NSLDAPI_FREE( subtypes );
+ subtypes = NULL;
+ }
+ vals = internal_ldap_get_values( ld, entry, target, lencall );
+ if ( NULL != type )
+ *type = nsldapi_strdup( target );
+ return vals;
+ } else {
+ /* Get just the base attribute name */
+ baseTarget = (char *)NSLDAPI_MALLOC( len + 1 );
+ if (baseTarget == NULL) {
+ return( NULL );
+ }
+ memcpy( baseTarget, target, len );
+ baseTarget[len] = 0;
+ }
+
+ ber = *entry->lm_ber;
+
+ /* Process all attributes in the entry */
+ while ( 1 ) {
+ int foundMatch = 0;
+ if ( NULL != attr )
+ NSLDAPI_FREE( attr );
+ if ( firstAttr ) {
+ firstAttr = 0;
+ /* skip sequence, dn, sequence of, and snag the first attr */
+ if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
+ break;
+ }
+ } else {
+ if ( ber_scanf( &ber, "{a", &attr ) == LBER_ERROR ) {
+ break;
+ }
+ }
+
+ if ( check_base_match( (const char *)baseTarget, attr ) ) {
+ int thisMatch = check_lang_match( target, baseTarget,
+ subtypes, nsubtypes, lang, attr );
+ if ( thisMatch > bestMatch ) {
+ if ( vals )
+ NSLDAPI_FREE( vals );
+ foundMatch = 1;
+ bestMatch = thisMatch;
+ if ( NULL != bestType )
+ NSLDAPI_FREE( bestType );
+ bestType = attr;
+ attr = NULL;
+ }
+ }
+ if ( foundMatch ) {
+ if ( lencall ) {
+ rc = ber_scanf( &ber, "[V]}", &vals );
+ } else {
+ rc = ber_scanf( &ber, "[v]}", &vals );
+ }
+ } else {
+ ber_scanf( &ber, "x}" );
+ }
+ }
+
+ NSLDAPI_FREE( lang );
+ NSLDAPI_FREE( baseTarget );
+ NSLDAPI_FREE( subtypes );
+
+ if ( NULL != type )
+ *type = bestType;
+ else if ( NULL != bestType )
+ NSLDAPI_FREE( bestType );
+
+ if ( NULL == vals ) {
+ rc = LDAP_DECODING_ERROR;
+ } else {
+ rc = LDAP_SUCCESS;
+ }
+
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+
+ return( vals );
+}
+
+
+char **
+LDAP_CALL
+ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target )
+{
+ return( (char **) internal_ldap_get_values( ld, entry, target, 0 ) );
+}
+
+struct berval **
+LDAP_CALL
+ldap_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target )
+{
+ return( (struct berval **) internal_ldap_get_values( ld, entry, target,
+ 1 ) );
+}
+
+char **
+LDAP_CALL
+ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, const char *target,
+ char **type )
+{
+ return( (char **) internal_ldap_get_lang_values( ld, entry,
+ target, type, 0 ) );
+}
+
+struct berval **
+LDAP_CALL
+ldap_get_lang_values_len( LDAP *ld, LDAPMessage *entry, const char *target,
+ char **type )
+{
+ return( (struct berval **) internal_ldap_get_lang_values( ld, entry,
+ target, type, 1 ) );
+}
+
diff --git a/usr/src/lib/libldap5/sources/ldap/common/ldap-int.h b/usr/src/lib/libldap5/sources/ldap/common/ldap-int.h
new file mode 100644
index 0000000000..e21deba22a
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/ldap-int.h
@@ -0,0 +1,878 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+#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"
+#elif defined(XP_OS2)
+#include <os2sock.h>
+#else /* _WINDOWS */
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#if !defined(hpux) && !defined(SUNOS4) && !defined(LINUX)
+# include <sys/select.h>
+#endif /* !defined(hpux) and others */
+#endif /* _WINDOWS */
+
+#if defined(IRIX)
+#include <bstring.h>
+#endif /* IRIX */
+
+#define NSLBERI_LBER_INT_FRIEND
+#ifdef macintosh
+#include "lber-int.h"
+#elif defined(_SOLARIS_SDK)
+#include "../ber/lber-int.h"
+#else /* _SOLARIS_SDK */
+#include "../liblber/lber-int.h"
+#endif /* macintosh */
+
+#include "ldap.h"
+#include "ldaprot.h"
+#include "ldaplog.h"
+#include "portable.h"
+#include "regex.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 _SOLARIS_SDK
+#include <libintl.h>
+#endif
+#ifdef LDAP_SASLIO_HOOKS
+#include <sasl/sasl.h>
+#define SASL_MAX_BUFF_SIZE 65536
+#define SASL_MIN_BUFF_SIZE 4096
+#endif
+
+#if !defined(_WINDOWS) && !defined(macintosh) && !defined(LINUX) && !defined(BSDI)
+#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 */
+ int 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_NEEDSOCKET 1
+#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? */
+ char *lconn_krbinstance;
+ 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_NOTCONNECTED 3
+#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 */
+ int lr_res_msgtype; /* result message type */
+ 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 */
+} 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
+ */
+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;
+
+ /* do not mess with these */
+ 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 */
+
+ /* it is OK to change these next four values directly */
+ 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
+
+ /* do not mess with the rest though */
+ 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 version of the LDAP SDK */
+ /* the extra thread functions except for */
+ /* the ld_threadid_fn has 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;
+ /* prldap shadow io functions */
+ struct ldap_x_ext_io_fns ld_sasl_io_fns;
+#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 )
+
+/*
+ * 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 ldap_next_line_tokens( char **bufp, long *blenp, char ***toksp );
+void ldap_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_alloc_ber_with_options( LDAP *ld, BerElement **berp );
+void nsldapi_set_ber_options( LDAP *ld, BerElement *ber );
+int nsldapi_ber_flush( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit,
+ int async );
+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 );
+void nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn );
+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 );
+
+/*
+ * 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 );
+
+int ldap_put_filter( BerElement *ber, char *str );
+/*
+ * 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 reslist.c
+ */
+LDAPMessage *ldap_delete_result_entry( LDAPMessage **list, LDAPMessage *e );
+void ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e );
+
+/*
+ * 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_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 ../ber/bprint.c
+ */
+void ber_err_print( char *data );
+
+#ifdef _SOLARIS_SDK
+/*
+ * in ../prldap/ldappr-dns.c
+ */
+int prldap_x_install_dns_skipdb(LDAP *ld, const char *skip);
+/*
+ * in ../prldap/ldappr-threads.c
+ */
+void prldap_nspr_init(void);
+#endif
+
+/*
+ * in ../prldap/ldappr-public.c
+ */
+int
+prldap_install_io_functions( LDAP *ld, int shared );
+int
+prldap_install_dns_functions( LDAP *ld );
+int
+prldap_install_thread_functions( LDAP *ld, int shared );
+
+
+
+#ifndef _SOLARIS_SDK
+
+/*
+ * 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
+ *
+ * These are moved to ldap.h in the Solaris version of the library
+ *
+ */
+#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 */
+
+#endif /* _SOLARIS_SDK */
+
+/*
+ * 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 );
+
+#endif /* _LDAPINT_H */
diff --git a/usr/src/lib/libldap5/sources/ldap/common/ldaputf8.c b/usr/src/lib/libldap5/sources/ldap/common/ldaputf8.c
new file mode 100644
index 0000000000..65bc85a378
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/ldaputf8.c
@@ -0,0 +1,269 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/* uft8.c - misc. utf8 "string" functions. */
+#include "ldap-int.h"
+
+static char UTF8len[64]
+= {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6};
+
+int
+LDAP_CALL
+ldap_utf8len (const char* s)
+ /* Return the number of char's in the character at *s. */
+{
+ return ldap_utf8next((char*)s) - s;
+}
+
+char*
+LDAP_CALL
+ldap_utf8next (char* s)
+ /* Return a pointer to the character immediately following *s.
+ Handle any valid UTF-8 character, including '\0' and ASCII.
+ Try to handle a misaligned pointer or a malformed character.
+ */
+{
+ register unsigned char* next = (unsigned char*)s;
+ switch (UTF8len [(*next >> 2) & 0x3F]) {
+ case 0: /* erroneous: s points to the middle of a character. */
+ case 6: if ((*++next & 0xC0) != 0x80) break;
+ case 5: if ((*++next & 0xC0) != 0x80) break;
+ case 4: if ((*++next & 0xC0) != 0x80) break;
+ case 3: if ((*++next & 0xC0) != 0x80) break;
+ case 2: if ((*++next & 0xC0) != 0x80) break;
+ case 1: ++next;
+ }
+ return (char*) next;
+}
+
+char*
+LDAP_CALL
+ldap_utf8prev (char* s)
+ /* Return a pointer to the character immediately preceding *s.
+ Handle any valid UTF-8 character, including '\0' and ASCII.
+ Try to handle a misaligned pointer or a malformed character.
+ */
+{
+ register unsigned char* prev = (unsigned char*)s;
+ unsigned char* limit = prev - 6;
+ while (((*--prev & 0xC0) == 0x80) && (prev != limit)) {
+ ;
+ }
+ return (char*) prev;
+}
+
+int
+LDAP_CALL
+ldap_utf8copy (char* dst, const char* src)
+ /* Copy a character from src to dst; return the number of char's copied.
+ Handle any valid UTF-8 character, including '\0' and ASCII.
+ Try to handle a misaligned pointer or a malformed character.
+ */
+{
+ register const unsigned char* s = (const unsigned char*)src;
+ switch (UTF8len [(*s >> 2) & 0x3F]) {
+ case 0: /* erroneous: s points to the middle of a character. */
+ case 6: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+ case 5: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+ case 4: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+ case 3: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+ case 2: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+ case 1: *dst = *s++;
+ }
+ return s - (const unsigned char*)src;
+}
+
+size_t
+LDAP_CALL
+ldap_utf8characters (const char* src)
+ /* Return the number of UTF-8 characters in the 0-terminated array s. */
+{
+ register char* s = (char*)src;
+ size_t n;
+ for (n = 0; *s; LDAP_UTF8INC(s)) ++n;
+ return n;
+}
+
+unsigned long LDAP_CALL
+ldap_utf8getcc( const char** src )
+{
+ register unsigned long c;
+ register const unsigned char* s = (const unsigned char*)*src;
+ switch (UTF8len [(*s >> 2) & 0x3F]) {
+ case 0: /* erroneous: s points to the middle of a character. */
+ c = (*s++) & 0x3F; goto more5;
+ case 1: c = (*s++); break;
+ case 2: c = (*s++) & 0x1F; goto more1;
+ case 3: c = (*s++) & 0x0F; goto more2;
+ case 4: c = (*s++) & 0x07; goto more3;
+ case 5: c = (*s++) & 0x03; goto more4;
+ case 6: c = (*s++) & 0x01; goto more5;
+ more5: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+ more4: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+ more3: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+ more2: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+ more1: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+ break;
+ }
+ *src = (const char*)s;
+ return c;
+}
+
+char*
+LDAP_CALL
+ldap_utf8strtok_r( char* sp, const char* brk, char** next)
+{
+ const char *bp;
+ unsigned long sc, bc;
+ char *tok;
+
+ if (sp == NULL && (sp = *next) == NULL)
+ return NULL;
+
+ /* Skip leading delimiters; roughly, sp += strspn(sp, brk) */
+ cont:
+ sc = LDAP_UTF8GETC(sp);
+ for (bp = brk; (bc = LDAP_UTF8GETCC(bp)) != 0;) {
+ if (sc == bc)
+ goto cont;
+ }
+
+ if (sc == 0) { /* no non-delimiter characters */
+ *next = NULL;
+ return NULL;
+ }
+ tok = LDAP_UTF8PREV(sp);
+
+ /* Scan token; roughly, sp += strcspn(sp, brk)
+ * Note that brk must be 0-terminated; we stop if we see that, too.
+ */
+ while (1) {
+ sc = LDAP_UTF8GETC(sp);
+ bp = brk;
+ do {
+ if ((bc = LDAP_UTF8GETCC(bp)) == sc) {
+ if (sc == 0) {
+ *next = NULL;
+ } else {
+ *next = sp;
+ *(LDAP_UTF8PREV(sp)) = 0;
+ }
+ return tok;
+ }
+ } while (bc != 0);
+ }
+ /* NOTREACHED */
+}
+
+int
+LDAP_CALL
+ldap_utf8isalnum( char* s )
+{
+ register unsigned char c = *(unsigned char*)s;
+ if (0x80 & c) return 0;
+ if (c >= 'A' && c <= 'Z') return 1;
+ if (c >= 'a' && c <= 'z') return 1;
+ if (c >= '0' && c <= '9') return 1;
+ return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isalpha( char* s )
+{
+ register unsigned char c = *(unsigned char*)s;
+ if (0x80 & c) return 0;
+ if (c >= 'A' && c <= 'Z') return 1;
+ if (c >= 'a' && c <= 'z') return 1;
+ return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isdigit( char* s )
+{
+ register unsigned char c = *(unsigned char*)s;
+ if (0x80 & c) return 0;
+ if (c >= '0' && c <= '9') return 1;
+ return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isxdigit( char* s )
+{
+ register unsigned char c = *(unsigned char*)s;
+ if (0x80 & c) return 0;
+ if (c >= '0' && c <= '9') return 1;
+ if (c >= 'A' && c <= 'F') return 1;
+ if (c >= 'a' && c <= 'f') return 1;
+ return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isspace( char* s )
+{
+ register unsigned char *c = (unsigned char*)s;
+ int len = ldap_utf8len(s);
+
+ if (len == 0) {
+ return 0;
+ } else if (len == 1) {
+ switch (*c) {
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x20:
+ return 1;
+ default:
+ return 0;
+ }
+ } else if (len == 2) {
+ if (*c == 0xc2) {
+ return *(c+1) == 0x80;
+ }
+ } else if (len == 3) {
+ if (*c == 0xE2) {
+ c++;
+ if (*c == 0x80) {
+ c++;
+ return (*c>=0x80 && *c<=0x8a);
+ }
+ } else if (*c == 0xE3) {
+ return (*(c+1)==0x80) && (*(c+2)==0x80);
+ } else if (*c==0xEF) {
+ return (*(c+1)==0xBB) && (*(c+2)==0xBF);
+ }
+ return 0;
+ }
+
+ /* should never reach here */
+ return 0;
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/llib-lldap b/usr/src/lib/libldap5/sources/ldap/common/llib-lldap
new file mode 100644
index 0000000000..9ce0512704
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/llib-lldap
@@ -0,0 +1,530 @@
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2001, 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <lber.h>
+#include <ldap.h>
+
+
+/*
+ * in abandon.c:
+ */
+int ldap_abandon_ext(LDAP *ld, int msgid, LDAPControl **serverctrls, LDAPControl ** clientctrls);
+
+int ldap_abandon( LDAP *ld, int msgid );
+
+/*
+ * in add.c:
+ */
+int ldap_add_ext( LDAP *ld, const char *dn, LDAPMod **attrs, LDAPControl ** serverctrls, LDAPControl **clientctrls, int *msgidp);
+
+int ldap_add_ext_s( LDAP *ld, const char *dn, LDAPMod **attrs, LDAPControl ** serverctrls, LDAPControl **clientctrls);
+
+int ldap_add( LDAP *ld, const char *dn, LDAPMod **attrs );
+int ldap_add_s( LDAP *ld, const char *dn, LDAPMod **attrs );
+
+/*
+ * in bind.c:
+ */
+int ldap_bind(LDAP *ld, const char *dn, const char *passwd, int authmethod);
+int ldap_bind_s(LDAP *ld, const char *dn, const char *passwd, int authmethod);
+void ldap_set_rebind_proc(LDAP *ld, LDAP_REBINDPROC_CALLBACK *rebindproc, void *arg);
+
+/*
+ * in sbind.c:
+ */
+int ldap_simple_bind( LDAP *ld, const char *dn, const char *passwd );
+int ldap_simple_bind_s( LDAP *ld, const char *dn, const char *passwd );
+
+/*
+ * in saslbind.c:
+ */
+int ldap_sasl_bind(LDAP *ld, const char *dn, const char *mechanism, const struct berval *cred, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp);
+
+int ldap_sasl_bind_s(LDAP *ld, const char *dn, const char *mechanism, const struct berval *cred, LDAPControl **serverctrls, LDAPControl **clientctrls, struct berval **servercredp);
+
+/*
+ * in kbind.c:
+ */
+
+/*
+ * in cache.c
+ */
+
+/*
+ * in compare.c:
+ */
+int ldap_compare_ext(LDAP *ld, const char *dn, const char *attr, const struct berval *bvalue, LDAPControl ** serverctrls, LDAPControl **clientctrls, int *msgidp);
+
+int ldap_compare_ext_s(LDAP *ld, const char *dn, const char *attr, const struct berval *bvalue, LDAPControl ** serverctrls, LDAPControl **clientctrls) ;
+
+int ldap_compare( LDAP *ld, const char *dn, const char *attr, const char *value );
+
+int ldap_compare_s( LDAP *ld, const char *dn, const char *attr, const char *value );
+
+/*
+ * in delete.c:
+ */
+int ldap_delete_ext(LDAP *ld, const char *dn, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp);
+
+int ldap_delete_ext_s(LDAP *ld, const char *dn, LDAPControl **serverctrls, LDAPControl **clientctrls);
+
+int ldap_delete( LDAP *ld, const char *dn );
+int ldap_delete_s( LDAP *ld, const char *dn );
+
+/*
+ * in error.c:
+ */
+char *ldap_err2string( int err );
+void ldap_perror(LDAP *ld, const char *s);
+int ldap_result2error(LDAP *ld, LDAPMessage *r, int freeit);
+int ldap_get_lderrno(LDAP *ld, char **m, char **s);
+int ldap_set_lderrno(LDAP *ld, int e, char *m, char *s);
+
+/*
+ * in modify.c:
+ */
+int ldap_modify_ext(LDAP *ld, const char *dn, LDAPMod **mods, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp);
+
+int ldap_modify_ext_s(LDAP *ld, const char *dn, LDAPMod **mods, LDAPControl **serverctrls, LDAPControl **clientctrls) ;
+
+int ldap_modify( LDAP *ld, const char *dn, LDAPMod **mods );
+int ldtap_modify_s( LDAP *ld, const char *dn, LDAPMod **mods );
+
+/*
+ * in modrdn.c:
+ */
+
+/*
+ * in rename.c:
+ */
+int ldap_rename(LDAP *ld, const char *dn, const char *newrdn, const char *newparent, int deleteoldrdn, LDAPControl ** serverctrls, LDAPControl **clientctrls, int *msgidp);
+
+int ldap_rename_s(LDAP *ld, const char *dn, const char *newrdn, const char *newparent, int deleteoldrdn, LDAPControl ** serverctrls, LDAPControl **clientctrls);
+
+int ldap_modrdn(LDAP *ld, const char *dn, const char *newrdn);
+int ldap_modrdn_s(LDAP *ld, const char *dn, const char *newrdn);
+int ldap_modrdn2(LDAP *ld, const char *dn, const char *newrdn, int deleteoldrdn);
+
+int ldap_modrdn2_s(LDAP *ld, const char *dn, const char *newrdn, int deleteoldrdn);
+
+/*
+ * in open.c:
+ */
+LDAP *ldap_init( const char *defhost, int defport );
+LDAP *ldap_open(const char *host, int port);
+int ldap_version(LDAPVersion *ver);
+
+/*
+ * in getentry.c:
+ */
+LDAPMessage *ldap_first_entry( LDAP *ld, LDAPMessage *res );
+LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );
+int ldap_count_entries( LDAP *ld, LDAPMessage *res );
+int ldap_get_entry_controls(LDAP *ld, LDAPMessage *entry, LDAPControl ***serverctrlsp);
+
+/*
+ * in getmsg.c:
+ */
+LDAPMessage *ldap_first_message( LDAP *ld, LDAPMessage *res );
+LDAPMessage *ldap_next_message( LDAP *ld, LDAPMessage *msg );
+int ldap_count_messages( LDAP *ld, LDAPMessage *res );
+
+/*
+ * in getref.c:
+ */
+LDAPMessage *ldap_first_reference( LDAP *ld, LDAPMessage *res );
+LDAPMessage *ldap_next_reference( LDAP *ld, LDAPMessage *entry );
+int ldap_count_references( LDAP *ld, LDAPMessage *res );
+
+/*
+ * in getdn.c
+ */
+char *ldap_get_dn( LDAP *ld, LDAPMessage *entry );
+char **ldap_explode_dn( const char *dn, const int notypes );
+char ** ldap_explode_rdn( const char *rdn, const int notypes );
+char *ldap_dn2ufn( const char *dn );
+char **ldap_explode_dns( const char *dn );
+int ldap_is_dns_dn( const char *dn );
+char *ldap_dns_to_dn(char *dns_name, int *nameparts);
+
+/*
+ * in getattr.c
+ */
+char *ldap_first_attribute( LDAP *ld, LDAPMessage *entry,
+ BerElement **ber );
+
+char *ldap_next_attribute( LDAP *ld, LDAPMessage *entry,
+ BerElement *ber );
+
+void ldap_memfree(void *p);
+
+/*
+ * in getvalues.c
+ */
+char **ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target );
+int ldap_count_values( char **vals );
+int ldap_count_values_len( struct berval **vals );
+void ldap_value_free( char **vals );
+void ldap_value_free_len( struct berval **vals );
+
+struct berval **ldap_get_values_len(LDAP *ld, LDAPMessage *entry, const char *target);
+
+char **ldap_get_lang_values(LDAP *ld, LDAPMessage *entry, const char *target, char **type);
+
+struct berval **ldap_get_lang_values_len(LDAP *ld, LDAPMessage *entry, const char *target, char **type);
+
+/*
+ * in referral.c:
+ */
+int ldap_parse_reference(LDAP *ld, LDAPMessage *ref,
+ char ***referralsp, LDAPControl ***serverctrlsp, int freeit);
+char ** ldap_get_reference_urls(LDAP *ld, LDAPMessage *res);
+
+/*
+ * in result.c:
+ */
+int ldap_result( LDAP *ld, int msgid, int all,
+ struct timeval *timeout, LDAPMessage **result );
+
+int ldap_msgfree( LDAPMessage *lm );
+int ldap_msgtype( LDAPMessage *res );
+int ldap_msgid( LDAPMessage *res );
+int ldap_parse_result(LDAP *ld, LDAPMessage *res, int *errcodep, char **matcheddnp, char **errmsgp, char ***referralsp, LDAPControl ***serverctrlsp, int freeit) ;
+
+int ldap_parse_sasl_bind_result(LDAP *ld, LDAPMessage *res, struct berval **servercredp, int freeit);
+
+int ldap_parse_extended_result(LDAP *ld, LDAPMessage *res, char **resultoidp, struct berval **resultdata, int freeit);
+
+/*
+ * in search.c:
+ */
+int ldap_search_ext(LDAP *ld, const char *base, int scope, const char *filter, char **attrs, int attrsonly, LDAPControl **serverctrls, LDAPControl **clientctrls, struct timeval *timeoutp, int sizelimit, int *msgidp);
+
+int ldap_search_ext_s(LDAP *ld, const char *base, int scope, const char *filter, char **attrs, int attrsonly, LDAPControl **serverctrls, LDAPControl **clientctrls, struct timeval *timeoutp, int sizelimit, LDAPMessage **res);
+
+int ldap_search( LDAP *ld, const char *base, int scope, const char *filter,
+ char **attrs, int attrsonly );
+
+int ldap_search_s( LDAP *ld, const char *base, int scope, const char *filter,
+ char **attrs, int attrsonly, LDAPMessage **res );
+
+int ldap_search_st( LDAP *ld, const char *base, int scope, const char *filter,
+ char **attrs, int attrsonly, struct timeval *timeout, LDAPMessage **res );
+
+/*
+ * in ufn.c
+ */
+int ldap_ufn_search_c( LDAP *ld, char *ufn, char **attrs,
+ int attrsonly, LDAPMessage **res, LDAP_CANCELPROC_CALLBACK cancelproc,
+ void *cancelparm );
+
+int ldap_ufn_search_ct( LDAP *ld, char *ufn, char **attrs,
+ int attrsonly, LDAPMessage **res, LDAP_CANCELPROC_CALLBACK cancelproc,
+ void *cancelparm, char *tag1, char *tag2, char *tag3 );
+
+int ldap_ufn_search_s( LDAP *ld, char *ufn, char **attrs,
+ int attrsonly, LDAPMessage **res );
+
+LDAPFiltDesc *ldap_ufn_setfilter( LDAP *ld, char *fname );
+void ldap_ufn_setprefix( LDAP *ld, char *prefix );
+int ldap_ufn_timeout( void *tvparam );
+
+
+/*
+ * in unbind.c
+ */
+int ldap_unbind( LDAP *ld );
+int ldap_unbind_s( LDAP *ld );
+int ldap_unbind_ext(LDAP *ld, LDAPControl **serverctrls, LDAPControl **clientctrls);
+
+
+/*
+ * in getfilter.c
+ */
+LDAPFiltDesc *ldap_init_getfilter( char *fname );
+LDAPFiltDesc *ldap_init_getfilter_buf( char *buf, ssize_t buflen );
+LDAPFiltInfo *ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat,
+ char *value );
+
+LDAPFiltInfo *ldap_getnextfilter( LDAPFiltDesc *lfdp );
+void ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix );
+void ldap_build_filter( char *filtbuf, size_t buflen,
+ char *pattern, char *prefix, char *suffix, char *attr,
+ char *value, char **valwords );
+
+int ldap_create_filter(char *buf, unsigned long buflen, char *pattern, char *prefix, char *suffix, char *attr, char *value, char **valwords);
+
+/*
+ * in free.c
+ */
+void ldap_getfilter_free( LDAPFiltDesc *lfdp );
+void ldap_mods_free( LDAPMod **mods, int freemods );
+void ldap_ber_free(BerElement *ber, int freebuf);
+
+/*
+ * in friendly.c
+ */
+char *ldap_friendly_name( char *filename, char *uname,
+ FriendlyMap *map );
+
+void ldap_free_friendlymap( FriendlyMap *map );
+
+
+/*
+ * in cldap.c
+ */
+
+
+/*
+ * in sort.c
+ */
+int ldap_sort_entries( LDAP *ld, LDAPMessage **chain, char *attr,
+ int (*cmp)() );
+
+int ldap_sort_values( LDAP *ld, char **vals, int (*cmp)() );
+int ldap_sort_strcasecmp( const char **a, const char **b );
+int ldap_multisort_entries(LDAP *ld, LDAPMessage **chain, char **attr, LDAP_CMP_CALLBACK *cmp);
+
+
+/*
+ * in url.c
+ */
+int ldap_is_ldap_url( const char *url );
+int ldap_url_parse( const char *url, LDAPURLDesc **ludpp );
+int ldap_url_parse_nodn(const char *url, LDAPURLDesc **ludpp);
+void ldap_free_urldesc( LDAPURLDesc *ludp );
+int ldap_url_search( LDAP *ld, const char *url, int attrsonly );
+int ldap_url_search_s( LDAP *ld, const char *url, int attrsonly,
+ LDAPMessage **res );
+
+int ldap_url_search_st( LDAP *ld, const char *url, int attrsonly,
+ struct timeval *timeout, LDAPMessage **res );
+
+char *ldap_dns_to_url(LDAP *ld, char *dns_name, char *attrs,
+char *scope, char *filter);
+char *ldap_dn_to_url(LDAP *ld, char *dn, int nameparts);
+
+
+/*
+ * in charset.c
+ */
+void ldap_set_string_translators( LDAP *ld,
+ BERTranslateProc encode_proc, BERTranslateProc decode_proc );
+
+int ldap_translate_from_t61( LDAP *ld, char **bufp,
+ unsigned int *lenp, int free_input );
+
+int ldap_translate_to_t61( LDAP *ld, char **bufp,
+ unsigned int *lenp, int free_input );
+
+void ldap_enable_translation( LDAP *ld, LDAPMessage *entry,
+ int enable );
+
+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);
+
+
+/*
+ * in io.c
+ */
+BerElement *ber_alloc_t(int options);
+int ber_flatten(BerElement *ber, struct berval **bvPtr);
+void ber_free(BerElement *ber, int freebuf);
+BerElement *ber_alloc(void);
+BerElement *ber_init(const struct berval *bv);
+
+/*
+ * in decode.c
+ */
+struct berval *ber_bvdup(const struct berval *bv);
+void ber_bvecfree(struct berval **bv);
+void ber_bvfree(struct berval *bv);
+ber_tag_t ber_first_element(BerElement *ber, unsigned int *len, char **last);
+ber_tag_t ber_next_element(BerElement *ber, ber_tag_t *len, char *last);
+ber_tag_t ber_peek_tag(BerElement *ber, ber_tag_t *len);
+ber_tag_t ber_scanf(BerElement *ber, const char *fmt, ...);
+ber_tag_t ber_skip_tag(BerElement *ber, ber_tag_t *len);
+ber_tag_t ber_get_int(BerElement *ber, ber_int_t *num);
+
+/*
+ * in encode.c
+ */
+int ber_printf(BerElement *ber, const char *fmt, ...);
+
+/*
+ * in control.c
+ */
+void ldap_control_free (LDAPControl *ctrl);
+void ldap_controls_free (LDAPControl **ctrls);
+
+/*
+ * in spagectrl.c
+ */
+int ldap_create_page_control(LDAP *ld, unsigned int pagesize, struct berval *cookie, char isCritical, LDAPControl **output);
+
+int ldap_parse_page_control(LDAP *ld, LDAPControl **controls, unsigned int *totalcount, struct berval **cookie);
+
+/*
+ * in tmplout.c
+ */
+int ldap_entry2html(LDAP *ld, char *buf, LDAPMessage *entry, struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals, writeptype writeproc, void *writeparm, char *eol, int rdncount, unsigned long opts, char *urlprefix, char *base);
+
+int ldap_entry2html_search(LDAP *ld, char *dn, char *base, LDAPMessage *entry, struct ldap_disptmpl*tmpllist, char **defattrs, char ***defvals, writeptype writeproc, void *writeparm, char *eol,int rdncount, unsigned long opts, char *urlprefix);
+
+int ldap_entry2text(LDAP *ld, char *buf, LDAPMessage *entry, struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals, writeptype writeproc, void *writeparm, char *eol, int rdncount, unsigned long opts);
+
+int ldap_entry2text_search(LDAP *ld,char *dn, char *base, LDAPMessage *entry, struct ldap_disptmpl*tmpllist, char **defattrs, char ***defvals, writeptype writeproc, void *writeparm, char *eol,int rdncount, unsigned long opts);
+
+int ldap_vals2html(LDAP *ld, char *buf, char **vals, char *label, int labelwidth, unsigned long syntaxid, writeptype writeproc, void *writeparm, char *eol, int rdncount, char *urlprefix);
+
+int ldap_vals2text(LDAP *ld, char *buf, char **vals, char *label, int labelwidth, unsigned long syntaxid, writeptype writeproc, void *writeparm, char *eol, int rdncount);
+
+/*
+ * in extendop.c
+ */
+int ldap_extended_operation(LDAP *ld, const char *requestoid, const struct berval *requestdata, LDAPControl **serverctrls, LDAPControl**clientctrls, int *msgidp);
+
+int ldap_extended_operation_s(LDAP *ld, const char *requestoid, const struct berval *requestdata, LDAPControl **serverctrls, LDAPControl **clientctrls, char **retoidp, struct berval **retdatap);
+
+/*
+ * in disptmpl.c
+ */
+struct ldap_disptmpl *ldap_first_disptmpl(struct ldap_disptmpl *tmpllist);
+struct ldap_tmplitem *ldap_first_tmplcol(struct ldap_disptmpl *tmpl,struct ldap_tmplitem *row);
+
+struct ldap_tmplitem *ldap_first_tmplrow(struct ldap_disptmpl *tmpl);
+void ldap_free_templates(struct ldap_disptmpl *tmpllist);
+int ldap_init_templates(char *file, struct ldap_disptmpl **tmpllistp);
+
+int ldap_init_templates_buf(char *buf, long buflen, struct ldap_disptmpl **tmpllistp);
+
+struct ldap_disptmpl *ldap_next_disptmpl(struct ldap_disptmpl *tmpllist, struct ldap_disptmpl *tmpl);
+
+struct ldap_tmplitem *ldap_next_tmplcol(struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row, struct ldap_tmplitem *col);
+
+struct ldap_tmplitem *ldap_next_tmplrow(struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row);
+
+struct ldap_disptmpl *ldap_oc2template(char **oclist, struct ldap_disptmpl *tmpllist);
+
+char **ldap_tmplattrs(struct ldap_disptmpl *tmpl, char **includeattrs, int exclude, unsigned long syntaxmask);
+
+struct ldap_disptmpl *ldap_name2template(char *name, struct ldap_disptmpl *tmpllist);
+
+/*
+ * in cram_md5.c
+ */
+int ldap_sasl_cram_md5_bind_s(LDAP *ld, char *dn, struct berval *cred, LDAPControl **serverctrls, LDAPControl **clientctrls);
+
+/*
+ * in setoption.c
+ */
+int ldap_set_option (LDAP *ld, int option, const void *optdata);
+
+/*
+ * in log.c
+ */
+void ldaplogconfigf(FILE *fd);
+
+/*
+ * in line64.c
+ */
+char *ldif_type_and_value(char *type, char *val, int vlen);
+char *str_getline(char **next);
+int str_parse_line(char *line, char **type, char **value, int *vlen);
+
+/*
+ * in sortctrl.c
+ */
+int ldap_create_sort_control (LDAP *ld, LDAPsortkey **sortKeyList, const char ctl_iscritical, LDAPControl **ctrlp);
+
+int ldap_parse_sort_control(LDAP *ld, LDAPControl **ctrlp, unsigned long *result, char **attribute);
+
+int ldap_create_sort_keylist(LDAPsortkey ***sortKeyList, const char *string_rep);
+
+void ldap_free_sort_keylist(LDAPsortkey **sortKeyList);
+
+/*
+ * in vlistctrl.c
+ */
+int ldap_create_virtuallist_control(LDAP *ld, LDAPVirtualList *ldvlistp, LDAPControl **ctrlp);
+
+int ldap_parse_virtuallist_control(LDAP *ld, LDAPControl **ctrls, unsigned long *target_posp, unsigned long *list_sizep, int *errcodep);
+
+/*
+ * in ldapsinit.c
+ */
+LDAP * ldapssl_init( const char *defhost, int defport, int defsecure );
+int ldapssl_install_routines( LDAP *ld );
+int ldapssl_enable_clientauth( LDAP *ld, char *keynickname, char *keypasswd, char *certnickname );
+
+/*
+ * in clientinit.c
+ */
+int ldapssl_client_init( const char *certdbpath, void *certdbhandle);
+int ldapssl_clientauth_init(const char *certdbpath, void *certdbhandle, const int needkeydb, const char *keydbpath, void *keydbhandle);
+
+int ldapssl_advclientauth_init( const char *certdbpath, void *certdbhandle, const int needkeydb, const char *keydbpath, void *keydbhandle, const int needsecmoddb, const char *secmoddbpath, const int sslstrength );
+
+int ldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns);
+
+/*
+ * in errormap.c
+ */
+const char * ldapssl_err2string( const int prerrno );
+
+/*
+ * in psearch.c
+ */
+int ldap_create_persistentsearch_control(LDAP *ld, int changetypes, int changesonly, int return_echg_ctls, char ctl_iscritical, LDAPControl **ctrlp);
+
+int ldap_parse_entrychange_control(LDAP *ld, LDAPControl **ctrls, int *chgtypep, char **prevdnp, int *chgnumpresentp, ber_int_t *chgnump);
+
+/*
+ * in proxyauthctrl.c
+ */
+int ldap_create_proxyauth_control(LDAP *ld, const char *dn, const char ctl_iscritical, LDAPControl **ctrlp);
+
+int ldap_create_proxiedauth_control(LDAP *ld, const char *authzid, LDAPControl **ctrlp);
+
+/*
+ * in srchpref.c
+ */
+struct ldap_searchobj *ldap_first_searchobj(struct ldap_searchobj *solist);
+void ldap_free_searchprefs(struct ldap_searchobj *solist);
+int ldap_init_searchprefs(char *file, struct ldap_searchobj **solistp);
+int ldap_init_searchprefs_buf(char *buf, long buflen, struct ldap_searchobj **solistp);
+
+struct ldap_searchobj *ldap_next_searchobj(struct ldap_searchobj *solist, struct ldap_searchobj *so);
+
+/*
+ * in getoption.c
+ */
+int ldap_get_option (LDAP *ld, int option, void *outvalue);
+
+/*
+ * in memcache.c
+ */
+int ldap_memcache_init(unsigned long ttl, unsigned long size, char **baseDNs, struct ldap_thread_fns *thread_fns, LDAPMemCache **cachep);
+
+int ldap_memcache_set(LDAP *ld, LDAPMemCache *cache);
+int ldap_memcache_get(LDAP *ld, LDAPMemCache **cachep);
+void ldap_memcache_flush(LDAPMemCache *cache, char *dn, int scope);
+void ldap_memcache_destroy(LDAPMemCache *cache);
+void ldap_memcache_update(LDAPMemCache *cache);
+
+/*
+ * in digest_md5.c
+ */
+int ldap_x_sasl_digest_md5_bind_s(LDAP *ld, char *dn, struct berval *cred, LDAPControl **serverctrls, LDAPControl **clientctrls);
diff --git a/usr/src/lib/libldap5/sources/ldap/common/memcache.c b/usr/src/lib/libldap5/sources/ldap/common/memcache.c
new file mode 100644
index 0000000000..a9d4597bb5
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/memcache.c
@@ -0,0 +1,2203 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ *
+ * memcache.c - routines that implement an in-memory cache.
+ *
+ * To Do: 1) ber_dup_ext().
+ * 2) referrals and reference?
+ */
+
+#include <assert.h>
+#include "ldap-int.h"
+
+/*
+ * Extra size allocated to BerElement.
+ * XXXmcs: must match EXBUFSIZ in liblber/io.c?
+ */
+#define EXTRA_SIZE 1024
+
+/* Mode constants for function memcache_access() */
+#define MEMCACHE_ACCESS_ADD 0
+#define MEMCACHE_ACCESS_APPEND 1
+#define MEMCACHE_ACCESS_APPEND_LAST 2
+#define MEMCACHE_ACCESS_FIND 3
+#define MEMCACHE_ACCESS_DELETE 4
+#define MEMCACHE_ACCESS_DELETE_ALL 5
+#define MEMCACHE_ACCESS_UPDATE 6
+#define MEMCACHE_ACCESS_FLUSH 7
+#define MEMCACHE_ACCESS_FLUSH_ALL 8
+#define MEMCACHE_ACCESS_FLUSH_LRU 9
+
+/* Mode constants for function memcache_adj_size */
+#define MEMCACHE_SIZE_DEDUCT 0
+#define MEMCACHE_SIZE_ADD 1
+
+#define MEMCACHE_SIZE_ENTRIES 1
+#define MEMCACHE_SIZE_NON_ENTRIES 2
+
+/* Size used for calculation if given size of cache is 0 */
+#define MEMCACHE_DEF_SIZE 131072 /* 128K bytes */
+
+/* Index into different list structure */
+#define LIST_TTL 0
+#define LIST_LRU 1
+#define LIST_TMP 2
+#define LIST_TOTAL 3
+
+
+static char *emptyStr = "";
+
+/* Macros to make code more readable */
+#define NSLDAPI_VALID_MEMCACHE_POINTER( cp ) ( (cp) != NULL )
+#define NSLDAPI_STR_NONNULL( s ) ( (s) ? (s) : emptyStr )
+#define NSLDAPI_SAFE_STRLEN( s ) ( (s) ? strlen((s)) + 1 : 1 )
+
+/* Macros dealing with mutex */
+#define LDAP_MEMCACHE_MUTEX_LOCK( c ) \
+ if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_lock ) { \
+ ((c)->ldmemc_lock_fns).ltf_mutex_lock( (c)->ldmemc_lock ); \
+ }
+
+#define LDAP_MEMCACHE_MUTEX_UNLOCK( c ) \
+ if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_unlock ) { \
+ ((c)->ldmemc_lock_fns).ltf_mutex_unlock( (c)->ldmemc_lock ); \
+ }
+
+#define LDAP_MEMCACHE_MUTEX_ALLOC( c ) \
+ ((c) && ((c)->ldmemc_lock_fns).ltf_mutex_alloc ? \
+ ((c)->ldmemc_lock_fns).ltf_mutex_alloc() : NULL)
+
+#define LDAP_MEMCACHE_MUTEX_FREE( c ) \
+ if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_free ) { \
+ ((c)->ldmemc_lock_fns).ltf_mutex_free( (c)->ldmemc_lock ); \
+ }
+
+/* Macros used for triming unnecessary spaces in a basedn */
+#define NSLDAPI_IS_SPACE( c ) \
+ (((c) == ' ') || ((c) == '\t') || ((c) == '\n'))
+
+#define NSLDAPI_IS_SEPARATER( c ) \
+ ((c) == ',')
+
+/* Hash table callback function pointer definition */
+typedef int (*HashFuncPtr)(int table_size, void *key);
+typedef int (*PutDataPtr)(void **ppTableData, void *key, void *pData);
+typedef int (*GetDataPtr)(void *pTableData, void *key, void **ppData);
+typedef int (*RemoveDataPtr)(void **ppTableData, void *key, void **ppData);
+typedef int (*MiscFuncPtr)(void **ppTableData, void *key, void *pData);
+typedef void (*ClrTableNodePtr)(void **ppTableData, void *pData);
+
+/* Structure of a node in a hash table */
+typedef struct HashTableNode_struct {
+ void *pData;
+} HashTableNode;
+
+/* Structure of a hash table */
+typedef struct HashTable_struct {
+ HashTableNode *table;
+ int size;
+ HashFuncPtr hashfunc;
+ PutDataPtr putdata;
+ GetDataPtr getdata;
+ MiscFuncPtr miscfunc;
+ RemoveDataPtr removedata;
+ ClrTableNodePtr clrtablenode;
+} HashTable;
+
+/* Structure uniquely identifies a search request */
+typedef struct ldapmemcacheReqId_struct {
+ LDAP *ldmemcrid_ld;
+ int ldmemcrid_msgid;
+} ldapmemcacheReqId;
+
+/* Structure representing a ldap handle associated to memcache */
+typedef struct ldapmemcacheld_struct {
+ LDAP *ldmemcl_ld;
+ struct ldapmemcacheld_struct *ldmemcl_next;
+} ldapmemcacheld;
+
+/* Structure representing header of a search result */
+typedef struct ldapmemcacheRes_struct {
+ char *ldmemcr_basedn;
+ unsigned long ldmemcr_crc_key;
+ unsigned long ldmemcr_resSize;
+ unsigned long ldmemcr_timestamp;
+ LDAPMessage *ldmemcr_resHead;
+ LDAPMessage *ldmemcr_resTail;
+ ldapmemcacheReqId ldmemcr_req_id;
+ struct ldapmemcacheRes_struct *ldmemcr_next[LIST_TOTAL];
+ struct ldapmemcacheRes_struct *ldmemcr_prev[LIST_TOTAL];
+ struct ldapmemcacheRes_struct *ldmemcr_htable_next;
+} ldapmemcacheRes;
+
+/* Structure for memcache statistics */
+typedef struct ldapmemcacheStats_struct {
+ unsigned long ldmemcstat_tries;
+ unsigned long ldmemcstat_hits;
+} ldapmemcacheStats;
+
+/* Structure of a memcache object */
+struct ldapmemcache {
+ unsigned long ldmemc_ttl;
+ unsigned long ldmemc_size;
+ unsigned long ldmemc_size_used;
+ unsigned long ldmemc_size_entries;
+ char **ldmemc_basedns;
+ void *ldmemc_lock;
+ ldapmemcacheld *ldmemc_lds;
+ HashTable *ldmemc_resTmp;
+ HashTable *ldmemc_resLookup;
+ ldapmemcacheRes *ldmemc_resHead[LIST_TOTAL];
+ ldapmemcacheRes *ldmemc_resTail[LIST_TOTAL];
+ struct ldap_thread_fns ldmemc_lock_fns;
+ ldapmemcacheStats ldmemc_stats;
+};
+
+/* Function prototypes */
+static int memcache_exist(LDAP *ld);
+static int memcache_add_to_ld(LDAP *ld, int msgid, LDAPMessage *pMsg);
+static int memcache_compare_dn(const char *main_dn, const char *dn, int scope);
+static int memcache_dup_message(LDAPMessage *res, int msgid, int fromcache,
+ LDAPMessage **ppResCopy, unsigned long *pSize);
+static BerElement* memcache_ber_dup(BerElement* pBer, unsigned long *pSize);
+
+static void memcache_trim_basedn_spaces(char *basedn);
+static int memcache_validate_basedn(LDAPMemCache *cache, const char *basedn);
+static int memcache_get_ctrls_len(LDAPControl **ctrls);
+static void memcache_append_ctrls(char *buf, LDAPControl **serverCtrls,
+ LDAPControl **clientCtrls);
+static int memcache_adj_size(LDAPMemCache *cache, unsigned long size,
+ int usageFlags, int bAdd);
+static int memcache_free_entry(LDAPMemCache *cache, ldapmemcacheRes *pRes);
+static int memcache_expired(LDAPMemCache *cache, ldapmemcacheRes *pRes,
+ unsigned long curTime);
+static int memcache_add_to_list(LDAPMemCache *cache, ldapmemcacheRes *pRes,
+ int index);
+static int memcache_add_res_to_list(ldapmemcacheRes *pRes, LDAPMessage *pMsg,
+ unsigned long size);
+static int memcache_free_from_list(LDAPMemCache *cache, ldapmemcacheRes *pRes,
+ int index);
+static int memcache_search(LDAP *ld, unsigned long key, LDAPMessage **ppRes);
+static int memcache_add(LDAP *ld, unsigned long key, int msgid,
+ const char *basedn);
+static int memcache_append(LDAP *ld, int msgid, LDAPMessage *pRes);
+static int memcache_append_last(LDAP *ld, int msgid, LDAPMessage *pRes);
+static int memcache_remove(LDAP *ld, int msgid);
+#if 0 /* function not used */
+static int memcache_remove_all(LDAP *ld);
+#endif /* 0 */
+static int memcache_access(LDAPMemCache *cache, int mode,
+ void *pData1, void *pData2, void *pData3);
+#ifdef LDAP_DEBUG
+static void memcache_print_list( LDAPMemCache *cache, int index );
+static void memcache_report_statistics( LDAPMemCache *cache );
+#endif /* LDAP_DEBUG */
+
+static int htable_calculate_size(int sizelimit);
+static int htable_sizeinbytes(HashTable *pTable);
+static int htable_put(HashTable *pTable, void *key, void *pData);
+static int htable_get(HashTable *pTable, void *key, void **ppData);
+static int htable_misc(HashTable *pTable, void *key, void *pData);
+static int htable_remove(HashTable *pTable, void *key, void **ppData);
+static int htable_removeall(HashTable *pTable, void *pData);
+static int htable_create(int size_limit, HashFuncPtr hashf,
+ PutDataPtr putDataf, GetDataPtr getDataf,
+ RemoveDataPtr removeDataf, ClrTableNodePtr clrNodef,
+ MiscFuncPtr miscOpf, HashTable **ppTable);
+static int htable_free(HashTable *pTable);
+
+static int msgid_hashf(int table_size, void *key);
+static int msgid_putdata(void **ppTableData, void *key, void *pData);
+static int msgid_getdata(void *pTableData, void *key, void **ppData);
+static int msgid_removedata(void **ppTableData, void *key, void **ppData);
+static int msgid_clear_ld_items(void **ppTableData, void *key, void *pData);
+static void msgid_clearnode(void **ppTableData, void *pData);
+
+static int attrkey_hashf(int table_size, void *key);
+static int attrkey_putdata(void **ppTableData, void *key, void *pData);
+static int attrkey_getdata(void *pTableData, void *key, void **ppData);
+static int attrkey_removedata(void **ppTableData, void *key, void **ppData);
+static void attrkey_clearnode(void **ppTableData, void *pData);
+
+static unsigned long crc32_convert(char *buf, int len);
+
+/* Create a memcache object. */
+int
+LDAP_CALL
+ldap_memcache_init( unsigned long ttl, unsigned long size,
+ char **baseDNs, struct ldap_thread_fns *thread_fns,
+ LDAPMemCache **cachep )
+{
+ unsigned long total_size = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_init\n", 0, 0, 0 );
+
+ if ( cachep == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ((*cachep = (LDAPMemCache*)NSLDAPI_CALLOC(1,
+ sizeof(LDAPMemCache))) == NULL) {
+ return ( LDAP_NO_MEMORY );
+ }
+
+ total_size += sizeof(LDAPMemCache);
+
+ (*cachep)->ldmemc_ttl = ttl;
+ (*cachep)->ldmemc_size = size;
+ (*cachep)->ldmemc_lds = NULL;
+
+ /* Non-zero default size needed for calculating size of hash tables */
+ size = (size ? size : MEMCACHE_DEF_SIZE);
+
+ if (thread_fns) {
+ memcpy(&((*cachep)->ldmemc_lock_fns), thread_fns,
+ sizeof(struct ldap_thread_fns));
+ } else {
+ memset(&((*cachep)->ldmemc_lock_fns), 0,
+ sizeof(struct ldap_thread_fns));
+ }
+
+ (*cachep)->ldmemc_lock = LDAP_MEMCACHE_MUTEX_ALLOC( *cachep );
+
+ /* Cache basedns */
+ if (baseDNs != NULL) {
+
+ int i;
+
+ for (i = 0; baseDNs[i]; i++) {
+ ;
+ }
+
+ (*cachep)->ldmemc_basedns = (char**)NSLDAPI_CALLOC(i + 1,
+ sizeof(char*));
+
+ if ((*cachep)->ldmemc_basedns == NULL) {
+ ldap_memcache_destroy(*cachep);
+ *cachep = NULL;
+ return ( LDAP_NO_MEMORY );
+ }
+
+ total_size += (i + 1) * sizeof(char*);
+
+ for (i = 0; baseDNs[i]; i++) {
+ (*cachep)->ldmemc_basedns[i] = nsldapi_strdup(baseDNs[i]);
+ if ((*cachep)->ldmemc_basedns[i] == NULL)
+ return ( LDAP_NO_MEMORY );
+ total_size += strlen(baseDNs[i]) + 1;
+ }
+
+ (*cachep)->ldmemc_basedns[i] = NULL;
+ }
+
+ /* Create hash table for temporary cache */
+ if (htable_create(size, msgid_hashf, msgid_putdata, msgid_getdata,
+ msgid_removedata, msgid_clearnode, msgid_clear_ld_items,
+ &((*cachep)->ldmemc_resTmp)) != LDAP_SUCCESS) {
+ ldap_memcache_destroy(*cachep);
+ *cachep = NULL;
+ return( LDAP_NO_MEMORY );
+ }
+
+ total_size += htable_sizeinbytes((*cachep)->ldmemc_resTmp);
+
+ /* Create hash table for primary cache */
+ if (htable_create(size, attrkey_hashf, attrkey_putdata,
+ attrkey_getdata, attrkey_removedata, attrkey_clearnode,
+ NULL, &((*cachep)->ldmemc_resLookup)) != LDAP_SUCCESS) {
+ ldap_memcache_destroy(*cachep);
+ *cachep = NULL;
+ return( LDAP_NO_MEMORY );
+ }
+
+ total_size += htable_sizeinbytes((*cachep)->ldmemc_resLookup);
+
+ /* See if there is enough room so far */
+ if (memcache_adj_size(*cachep, total_size, MEMCACHE_SIZE_NON_ENTRIES,
+ MEMCACHE_SIZE_ADD) != LDAP_SUCCESS) {
+ ldap_memcache_destroy(*cachep);
+ *cachep = NULL;
+ return( LDAP_SIZELIMIT_EXCEEDED );
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_init new cache 0x%x\n",
+ *cachep, 0, 0 );
+
+ return( LDAP_SUCCESS );
+}
+
+/* Associates a ldap handle to a memcache object. */
+int
+LDAP_CALL
+ldap_memcache_set( LDAP *ld, LDAPMemCache *cache )
+{
+ int nRes = LDAP_SUCCESS;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_set\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) )
+ return( LDAP_PARAM_ERROR );
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ if (ld->ld_memcache != cache) {
+
+ LDAPMemCache *c = ld->ld_memcache;
+ ldapmemcacheld *pCur = NULL;
+ ldapmemcacheld *pPrev = NULL;
+
+ /* First dissociate handle from old cache */
+
+ LDAP_MEMCACHE_MUTEX_LOCK( c );
+
+ pCur = (c ? c->ldmemc_lds : NULL);
+ for (; pCur; pCur = pCur->ldmemcl_next) {
+ if (pCur->ldmemcl_ld == ld)
+ break;
+ pPrev = pCur;
+ }
+
+ if (pCur) {
+
+ ldapmemcacheReqId reqid;
+
+ reqid.ldmemcrid_ld = ld;
+ reqid.ldmemcrid_msgid = -1;
+ htable_misc(c->ldmemc_resTmp, (void*)&reqid, (void*)c);
+
+ if (pPrev)
+ pPrev->ldmemcl_next = pCur->ldmemcl_next;
+ else
+ c->ldmemc_lds = pCur->ldmemcl_next;
+ NSLDAPI_FREE(pCur);
+ pCur = NULL;
+
+ memcache_adj_size(c, sizeof(ldapmemcacheld),
+ MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_DEDUCT);
+ }
+
+ LDAP_MEMCACHE_MUTEX_UNLOCK( c );
+
+ ld->ld_memcache = NULL;
+
+ /* Exit if no new cache is specified */
+ if (cache == NULL) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+
+ /* Then associate handle with new cache */
+
+ LDAP_MEMCACHE_MUTEX_LOCK( cache );
+
+ if ((nRes = memcache_adj_size(cache, sizeof(ldapmemcacheld),
+ MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_ADD)) != LDAP_SUCCESS) {
+ LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+ return nRes;
+ }
+
+ pCur = (ldapmemcacheld*)NSLDAPI_CALLOC(1, sizeof(ldapmemcacheld));
+ if (pCur == NULL) {
+ memcache_adj_size(cache, sizeof(ldapmemcacheld),
+ MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_DEDUCT);
+ nRes = LDAP_NO_MEMORY;
+ } else {
+ pCur->ldmemcl_ld = ld;
+ pCur->ldmemcl_next = cache->ldmemc_lds;
+ cache->ldmemc_lds = pCur;
+ ld->ld_memcache = cache;
+ }
+
+ LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ return nRes;
+}
+
+/* Retrieves memcache with which the ldap handle has been associated. */
+int
+LDAP_CALL
+ldap_memcache_get( LDAP *ld, LDAPMemCache **cachep )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_get ld: 0x%x\n", ld, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || cachep == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+ *cachep = ld->ld_memcache;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ return( LDAP_SUCCESS );
+}
+
+/*
+ * Function that stays inside libldap and proactively expires items from
+ * the given cache. This should be called from a newly created thread since
+ * it will not return until after ldap_memcache_destroy() is called.
+ */
+void
+LDAP_CALL
+ldap_memcache_update( LDAPMemCache *cache )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_update: cache 0x%x\n",
+ cache, 0, 0 );
+
+ if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
+ return;
+ }
+
+ LDAP_MEMCACHE_MUTEX_LOCK( cache );
+ memcache_access(cache, MEMCACHE_ACCESS_UPDATE, NULL, NULL, NULL);
+ LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+}
+
+/* Removes specified entries from given memcache. */
+void
+LDAP_CALL
+ldap_memcache_flush( LDAPMemCache *cache, char *dn, int scope )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldap_memcache_flush( cache: 0x%x, dn: %s, scope: %d)\n",
+ cache, ( dn == NULL ) ? "(null)" : dn, scope );
+
+ if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
+ return;
+ }
+
+ LDAP_MEMCACHE_MUTEX_LOCK( cache );
+
+ if (!dn) {
+ memcache_access(cache, MEMCACHE_ACCESS_FLUSH_ALL, NULL, NULL, NULL);
+ } else {
+ memcache_access(cache, MEMCACHE_ACCESS_FLUSH,
+ (void*)dn, (void*)(uintptr_t)scope, NULL);
+ }
+
+ LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+}
+
+/* Destroys the given memcache. */
+void
+LDAP_CALL
+ldap_memcache_destroy( LDAPMemCache *cache )
+{
+ int i = 0;
+ unsigned long size = sizeof(LDAPMemCache);
+ ldapmemcacheld *pNode = NULL, *pNextNode = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_destroy( 0x%x )\n",
+ cache, 0, 0 );
+
+ if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
+ return;
+ }
+
+ /* Dissociate all ldap handes from this cache. */
+ LDAP_MEMCACHE_MUTEX_LOCK( cache );
+
+ for (pNode = cache->ldmemc_lds; pNode; pNode = pNextNode, i++) {
+ LDAP_MUTEX_LOCK( pNode->ldmemcl_ld, LDAP_MEMCACHE_LOCK );
+ cache->ldmemc_lds = pNode->ldmemcl_next;
+ pNode->ldmemcl_ld->ld_memcache = NULL;
+ LDAP_MUTEX_UNLOCK( pNode->ldmemcl_ld, LDAP_MEMCACHE_LOCK );
+ pNextNode = pNode->ldmemcl_next;
+ NSLDAPI_FREE(pNode);
+ }
+
+ size += i * sizeof(ldapmemcacheld);
+
+ LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+
+ /* Free array of basedns */
+ if (cache->ldmemc_basedns) {
+ for (i = 0; cache->ldmemc_basedns[i]; i++) {
+ size += strlen(cache->ldmemc_basedns[i]) + 1;
+ NSLDAPI_FREE(cache->ldmemc_basedns[i]);
+ }
+ size += (i + 1) * sizeof(char*);
+ NSLDAPI_FREE(cache->ldmemc_basedns);
+ }
+
+ /* Free hash table used for temporary cache */
+ if (cache->ldmemc_resTmp) {
+ size += htable_sizeinbytes(cache->ldmemc_resTmp);
+ memcache_access(cache, MEMCACHE_ACCESS_DELETE_ALL, NULL, NULL, NULL);
+ htable_free(cache->ldmemc_resTmp);
+ }
+
+ /* Free hash table used for primary cache */
+ if (cache->ldmemc_resLookup) {
+ size += htable_sizeinbytes(cache->ldmemc_resLookup);
+ memcache_access(cache, MEMCACHE_ACCESS_FLUSH_ALL, NULL, NULL, NULL);
+ htable_free(cache->ldmemc_resLookup);
+ }
+
+ memcache_adj_size(cache, size, MEMCACHE_SIZE_NON_ENTRIES,
+ MEMCACHE_SIZE_DEDUCT);
+
+ LDAP_MEMCACHE_MUTEX_FREE( cache );
+
+ NSLDAPI_FREE(cache);
+}
+
+/************************* Internal API Functions ****************************/
+
+/* Creates an integer key by applying the Cyclic Reduntency Check algorithm on
+ a long string formed by concatenating all the search parameters plus the
+ current bind DN. The key is used in the cache for looking up cached
+ entries. It is assumed that the CRC algorithm will generate
+ different integers from different byte strings. */
+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 nRes, i, j, i_smallest;
+ int len;
+ int defport;
+ char buf[50];
+ char *tmp, *defhost, *binddn, *keystr, *tmpbase;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (keyp == NULL) )
+ return( LDAP_PARAM_ERROR );
+
+ *keyp = 0;
+
+ if (!memcache_exist(ld))
+ return( LDAP_LOCAL_ERROR );
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+ LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+ nRes = memcache_validate_basedn(ld->ld_memcache, base);
+ LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ if (nRes != LDAP_SUCCESS)
+ return nRes;
+
+ defhost = NSLDAPI_STR_NONNULL(ld->ld_defhost);
+ defport = ld->ld_defport;
+ tmpbase = nsldapi_strdup(NSLDAPI_STR_NONNULL(base));
+ if (tmpbase == NULL)
+ return( LDAP_LOCAL_ERROR );
+ memcache_trim_basedn_spaces(tmpbase);
+
+ if ((binddn = nsldapi_get_binddn(ld)) == NULL)
+ binddn = "";
+
+ sprintf(buf, "%i\n%i\n%i\n", defport, scope, (attrsonly ? 1 : 0));
+ len = NSLDAPI_SAFE_STRLEN(buf) + NSLDAPI_SAFE_STRLEN(tmpbase) +
+ NSLDAPI_SAFE_STRLEN(filter) + NSLDAPI_SAFE_STRLEN(defhost) +
+ NSLDAPI_SAFE_STRLEN(binddn);
+
+ if (attrs) {
+ for (i = 0; attrs[i]; i++) {
+
+ for (i_smallest = j = i; attrs[j]; j++) {
+ if (strcasecmp(attrs[i_smallest], attrs[j]) > 0)
+ i_smallest = j;
+ }
+
+ if (i != i_smallest) {
+ tmp = attrs[i];
+ attrs[i] = attrs[i_smallest];
+ attrs[i_smallest] = tmp;
+ }
+
+ len += NSLDAPI_SAFE_STRLEN(attrs[i]);
+ }
+ } else {
+ len += 1;
+ }
+
+ len += memcache_get_ctrls_len(serverctrls) +
+ memcache_get_ctrls_len(clientctrls) + 1;
+
+ if ((keystr = (char*)NSLDAPI_CALLOC(len, sizeof(char))) == NULL) {
+ if (defhost != emptyStr)
+ NSLDAPI_FREE(defhost);
+ NSLDAPI_FREE(tmpbase);
+ return( LDAP_NO_MEMORY );
+ }
+
+ sprintf(keystr, "%s\n%s\n%s\n%s\n%s\n", binddn, tmpbase,
+ NSLDAPI_STR_NONNULL(defhost), NSLDAPI_STR_NONNULL(filter),
+ NSLDAPI_STR_NONNULL(buf));
+
+ if (attrs) {
+ for (i = 0; attrs[i]; i++) {
+ strcat(keystr, NSLDAPI_STR_NONNULL(attrs[i]));
+ strcat(keystr, "\n");
+ }
+ } else {
+ strcat(keystr, "\n");
+ }
+
+ for (tmp = keystr; *tmp;
+ *tmp += (*tmp >= 'a' && *tmp <= 'z' ? 'A'-'a' : 0), tmp++) {
+ ;
+ }
+
+ memcache_append_ctrls(keystr, serverctrls, clientctrls);
+
+ /* CRC algorithm */
+ *keyp = crc32_convert(keystr, len);
+
+ NSLDAPI_FREE(keystr);
+ NSLDAPI_FREE(tmpbase);
+
+ return LDAP_SUCCESS;
+}
+
+/* Searches the cache for the right cached entries, and if found, attaches
+ them to the given ldap handle. This function relies on locking by the
+ caller. */
+int
+ldap_memcache_result(LDAP *ld, int msgid, unsigned long key)
+{
+ int nRes;
+ LDAPMessage *pMsg = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldap_memcache_result( ld: 0x%x, msgid: %d, key: 0x%8.8lx)\n",
+ ld, msgid, key );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (msgid < 0) ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if (!memcache_exist(ld)) {
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+ LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+
+ /* Search the cache and append the results to ld if found */
+ ++ld->ld_memcache->ldmemc_stats.ldmemcstat_tries;
+ if ((nRes = memcache_search(ld, key, &pMsg)) == LDAP_SUCCESS) {
+ nRes = memcache_add_to_ld(ld, msgid, pMsg);
+ ++ld->ld_memcache->ldmemc_stats.ldmemcstat_hits;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldap_memcache_result: key 0x%8.8lx found in cache\n",
+ key, 0, 0 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldap_memcache_result: key 0x%8.8lx not found in cache\n",
+ key, 0, 0 );
+ }
+
+#ifdef LDAP_DEBUG
+ memcache_print_list( ld->ld_memcache, LIST_LRU );
+ memcache_report_statistics( ld->ld_memcache );
+#endif /* LDAP_DEBUG */
+
+ LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ return nRes;
+}
+
+/* Creates a new header in the cache so that entries arriving from the
+ directory server can later be cached under the header. */
+int
+ldap_memcache_new(LDAP *ld, int msgid, unsigned long key, const char *basedn)
+{
+ int nRes;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ if (!memcache_exist(ld)) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+ nRes = memcache_add(ld, key, msgid, basedn);
+ LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ return nRes;
+}
+
+/* Appends a chain of entries to an existing cache header. Parameter "bLast"
+ indicates whether there will be more entries arriving for the search in
+ question. */
+int
+ldap_memcache_append(LDAP *ld, int msgid, int bLast, LDAPMessage *result)
+{
+ int nRes = LDAP_SUCCESS;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_append( ld: 0x%x, ", ld, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_TRACE, "msgid %d, bLast: %d, result: 0x%x)\n",
+ msgid, bLast, result );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || !result ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ if (!memcache_exist(ld)) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+
+ if (!bLast)
+ nRes = memcache_append(ld, msgid, result);
+ else
+ nRes = memcache_append_last(ld, msgid, result);
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldap_memcache_append: %s result for msgid %d\n",
+ ( nRes == LDAP_SUCCESS ) ? "added" : "failed to add", msgid , 0 );
+
+ LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ return nRes;
+}
+
+/* Removes partially cached results for a search as a result of calling
+ ldap_abandon() by the client. */
+int
+ldap_memcache_abandon(LDAP *ld, int msgid)
+{
+ int nRes;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (msgid < 0) ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ if (!memcache_exist(ld)) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+ nRes = memcache_remove(ld, msgid);
+ LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+ return nRes;
+}
+
+/*************************** helper functions *******************************/
+
+/* Removes extraneous spaces in a basedn so that basedns differ by only those
+ spaces will be treated as equal. Extraneous spaces are those that
+ precedes the basedn and those that follow a comma. */
+/*
+ * XXXmcs: this is a bit too agressive... we need to deal with the fact that
+ * commas and spaces may be quoted, in which case it is wrong to remove them.
+ */
+static void
+memcache_trim_basedn_spaces(char *basedn)
+{
+ char *pRead, *pWrite;
+
+ if (!basedn)
+ return;
+
+ for (pWrite = pRead = basedn; *pRead; ) {
+ for (; *pRead && NSLDAPI_IS_SPACE(*pRead); pRead++) {
+ ;
+ }
+ for (; *pRead && !NSLDAPI_IS_SEPARATER(*pRead);
+ *(pWrite++) = *(pRead++)) {
+ ;
+ }
+ *(pWrite++) = (*pRead ? *(pRead++) : *pRead);
+ }
+}
+
+/* Verifies whether the results of a search should be cached or not by
+ checking if the search's basedn falls under any of the basedns for which
+ the memcache is responsible. */
+static int
+memcache_validate_basedn(LDAPMemCache *cache, const char *basedn)
+{
+ int i;
+
+ if ( cache->ldmemc_basedns == NULL ) {
+ return( LDAP_SUCCESS );
+ }
+
+#if 1
+ if (basedn == NULL) {
+ basedn = "";
+ }
+#else
+ /* XXXmcs: I do not understand this code... */
+ if (basedn == NULL)
+ return (cache->ldmemc_basedns && cache->ldmemc_basedns[0] ?
+ LDAP_OPERATIONS_ERROR : LDAP_SUCCESS);
+ }
+#endif
+
+ for (i = 0; cache->ldmemc_basedns[i]; i++) {
+ if (memcache_compare_dn(basedn, cache->ldmemc_basedns[i],
+ LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE) {
+ return( LDAP_SUCCESS );
+ }
+ }
+
+ return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Calculates the length of the buffer needed to concatenate the contents of
+ a ldap control. */
+static int
+memcache_get_ctrls_len(LDAPControl **ctrls)
+{
+ int len = 0, i;
+
+ if (ctrls) {
+ for (i = 0; ctrls[i]; i++) {
+ len += strlen(NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid)) +
+ (ctrls[i]->ldctl_value).bv_len + 4;
+ }
+ }
+
+ return len;
+}
+
+/* Contenates the contents of client and server controls to a buffer. */
+static void
+memcache_append_ctrls(char *buf, LDAPControl **serverCtrls,
+ LDAPControl **clientCtrls)
+{
+ int i, j;
+ char *pCh = buf + strlen(buf);
+ LDAPControl **ctrls;
+
+ for (j = 0; j < 2; j++) {
+
+ if ((ctrls = (j ? clientCtrls : serverCtrls)) == NULL)
+ continue;
+
+ for (i = 0; ctrls[i]; i++) {
+ sprintf(pCh, "%s\n", NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid));
+ pCh += strlen(NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid)) + 1;
+ if ((ctrls[i]->ldctl_value).bv_len > 0) {
+ memcpy(pCh, (ctrls[i]->ldctl_value).bv_val,
+ (ctrls[i]->ldctl_value).bv_len);
+ pCh += (ctrls[i]->ldctl_value).bv_len;
+ }
+ sprintf(pCh, "\n%i\n", (ctrls[i]->ldctl_iscritical ? 1 : 0));
+ pCh += 3;
+ }
+ }
+}
+
+/* Increases or decreases the size (in bytes) the given memcache currently
+ uses. If the size goes over the limit, the function returns an error. */
+static int
+memcache_adj_size(LDAPMemCache *cache, unsigned long size,
+ int usageFlags, int bAdd)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "memcache_adj_size: attempting to %s %ld %s bytes...\n",
+ bAdd ? "add" : "remove", size,
+ ( usageFlags & MEMCACHE_SIZE_ENTRIES ) ? "entry" : "non-entry" );
+
+ if (bAdd) {
+ cache->ldmemc_size_used += size;
+ if ((cache->ldmemc_size > 0) &&
+ (cache->ldmemc_size_used > cache->ldmemc_size)) {
+
+ if (size > cache->ldmemc_size_entries) {
+ cache->ldmemc_size_used -= size;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "memcache_adj_size: failed (size > size_entries %ld).\n",
+ cache->ldmemc_size_entries, 0, 0 );
+ return( LDAP_SIZELIMIT_EXCEEDED );
+ }
+
+ while (cache->ldmemc_size_used > cache->ldmemc_size) {
+ if (memcache_access(cache, MEMCACHE_ACCESS_FLUSH_LRU,
+ NULL, NULL, NULL) != LDAP_SUCCESS) {
+ cache->ldmemc_size_used -= size;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "memcache_adj_size: failed (LRU flush failed).\n",
+ 0, 0, 0 );
+ return( LDAP_SIZELIMIT_EXCEEDED );
+ }
+ }
+ }
+ if (usageFlags & MEMCACHE_SIZE_ENTRIES)
+ cache->ldmemc_size_entries += size;
+ } else {
+ cache->ldmemc_size_used -= size;
+ assert(cache->ldmemc_size_used >= 0);
+ if (usageFlags & MEMCACHE_SIZE_ENTRIES)
+ cache->ldmemc_size_entries -= size;
+ }
+
+#ifdef LDAP_DEBUG
+ if ( cache->ldmemc_size == 0 ) { /* no size limit */
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "memcache_adj_size: succeeded (new size: %ld bytes).\n",
+ cache->ldmemc_size_used, 0, 0 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "memcache_adj_size: succeeded (new size: %ld bytes, "
+ "free space: %ld bytes).\n", cache->ldmemc_size_used,
+ cache->ldmemc_size - cache->ldmemc_size_used, 0 );
+ }
+#endif /* LDAP_DEBUG */
+
+ return( LDAP_SUCCESS );
+}
+
+/* Searches the cache for results for a particular search identified by
+ parameter "key", which was generated ldap_memcache_createkey(). */
+static int
+memcache_search(LDAP *ld, unsigned long key, LDAPMessage **ppRes)
+{
+ int nRes;
+ ldapmemcacheRes *pRes;
+
+ *ppRes = NULL;
+
+ if (!memcache_exist(ld))
+ return LDAP_LOCAL_ERROR;
+
+ nRes = memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_FIND,
+ (void*)&key, (void*)(&pRes), NULL);
+
+ if (nRes != LDAP_SUCCESS)
+ return nRes;
+
+ *ppRes = pRes->ldmemcr_resHead;
+ assert((pRes->ldmemcr_req_id).ldmemcrid_msgid == -1);
+
+ return( LDAP_SUCCESS );
+}
+
+/* Adds a new header into the cache as a place holder for entries
+ arriving later. */
+static int
+memcache_add(LDAP *ld, unsigned long key, int msgid,
+ const char *basedn)
+{
+ ldapmemcacheReqId reqid;
+
+ if (!memcache_exist(ld))
+ return LDAP_LOCAL_ERROR;
+
+ reqid.ldmemcrid_msgid = msgid;
+ reqid.ldmemcrid_ld = ld;
+
+ return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_ADD,
+ (void*)&key, (void*)&reqid, (void*)basedn);
+}
+
+/* Appends search entries arriving from the dir server to the cache. */
+static int
+memcache_append(LDAP *ld, int msgid, LDAPMessage *pRes)
+{
+ ldapmemcacheReqId reqid;
+
+ if (!memcache_exist(ld))
+ return LDAP_LOCAL_ERROR;
+
+ reqid.ldmemcrid_msgid = msgid;
+ reqid.ldmemcrid_ld = ld;
+
+ return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_APPEND,
+ (void*)&reqid, (void*)pRes, NULL);
+}
+
+/* Same as memcache_append(), but the entries being appended are the
+ last from the dir server. Once all entries for a search have arrived,
+ the entries are moved from secondary to primary cache, and a time
+ stamp is given to the entries. */
+static int
+memcache_append_last(LDAP *ld, int msgid, LDAPMessage *pRes)
+{
+ ldapmemcacheReqId reqid;
+
+ if (!memcache_exist(ld))
+ return LDAP_LOCAL_ERROR;
+
+ reqid.ldmemcrid_msgid = msgid;
+ reqid.ldmemcrid_ld = ld;
+
+ return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_APPEND_LAST,
+ (void*)&reqid, (void*)pRes, NULL);
+}
+
+/* Removes entries from the temporary cache. */
+static int
+memcache_remove(LDAP *ld, int msgid)
+{
+ ldapmemcacheReqId reqid;
+
+ if (!memcache_exist(ld))
+ return LDAP_LOCAL_ERROR;
+
+ reqid.ldmemcrid_msgid = msgid;
+ reqid.ldmemcrid_ld = ld;
+
+ return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_DELETE,
+ (void*)&reqid, NULL, NULL);
+}
+
+#if 0 /* this function is not used */
+/* Wipes out everything in the temporary cache directory. */
+static int
+memcache_remove_all(LDAP *ld)
+{
+ if (!memcache_exist(ld))
+ return LDAP_LOCAL_ERROR;
+
+ return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_DELETE_ALL,
+ NULL, NULL, NULL);
+}
+#endif /* 0 */
+
+/* Returns TRUE or FALSE */
+static int
+memcache_exist(LDAP *ld)
+{
+ return (ld->ld_memcache != NULL);
+}
+
+/* Attaches cached entries to an ldap handle. */
+static int
+memcache_add_to_ld(LDAP *ld, int msgid, LDAPMessage *pMsg)
+{
+ int nRes = LDAP_SUCCESS;
+ LDAPMessage **r;
+ LDAPMessage *pCopy;
+
+ nRes = memcache_dup_message(pMsg, msgid, 1, &pCopy, NULL);
+ if (nRes != LDAP_SUCCESS)
+ return nRes;
+
+ for (r = &(ld->ld_responses); *r; r = &((*r)->lm_next))
+ if ((*r)->lm_msgid == msgid)
+ break;
+
+ if (*r)
+ for (r = &((*r)->lm_chain); *r; r = &((*r)->lm_chain)) {
+ ;
+ }
+
+ *r = pCopy;
+
+ return nRes;
+}
+
+/* Check if main_dn is included in {dn, scope} */
+static int
+memcache_compare_dn(const char *main_dn, const char *dn, int scope)
+{
+ int nRes;
+ char **components = NULL;
+ char **main_components = NULL;
+
+ components = ldap_explode_dn(dn, 0);
+ main_components = ldap_explode_dn(main_dn, 0);
+
+ if (!components || !main_components) {
+ nRes = LDAP_COMPARE_TRUE;
+ }
+ else {
+
+ int i, main_i;
+
+ main_i = ldap_count_values(main_components) - 1;
+ i = ldap_count_values(components) - 1;
+
+ for (; i >= 0 && main_i >= 0; i--, main_i--) {
+ if (strcasecmp(main_components[main_i], components[i]))
+ break;
+ }
+
+ if (i >= 0 && main_i >= 0) {
+ nRes = LDAP_COMPARE_FALSE;
+ }
+ else if (i < 0 && main_i < 0) {
+ if (scope != LDAP_SCOPE_ONELEVEL)
+ nRes = LDAP_COMPARE_TRUE;
+ else
+ nRes = LDAP_COMPARE_FALSE;
+ }
+ else if (main_i < 0) {
+ nRes = LDAP_COMPARE_FALSE;
+ }
+ else {
+ if (scope == LDAP_SCOPE_BASE)
+ nRes = LDAP_COMPARE_FALSE;
+ else if (scope == LDAP_SCOPE_SUBTREE)
+ nRes = LDAP_COMPARE_TRUE;
+ else if (main_i == 0)
+ nRes = LDAP_COMPARE_TRUE;
+ else
+ nRes = LDAP_COMPARE_FALSE;
+ }
+ }
+
+ if (components)
+ ldap_value_free(components);
+
+ if (main_components)
+ ldap_value_free(main_components);
+
+ return nRes;
+}
+
+/* Dup a complete separate copy of a berelement, including the buffers
+ the berelement points to. */
+static BerElement*
+memcache_ber_dup(BerElement* pBer, unsigned long *pSize)
+{
+ BerElement *p = ber_dup(pBer);
+
+ *pSize = 0;
+
+ if (p) {
+
+ *pSize += sizeof(BerElement) + EXTRA_SIZE;
+
+ if (p->ber_len <= EXTRA_SIZE) {
+ p->ber_flags |= LBER_FLAG_NO_FREE_BUFFER;
+ p->ber_buf = (char*)p + sizeof(BerElement);
+ } else {
+ p->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+ p->ber_buf = (char*)NSLDAPI_CALLOC(1, p->ber_len);
+ *pSize += (p->ber_buf ? p->ber_len : 0);
+ }
+
+ if (p->ber_buf) {
+ p->ber_ptr = p->ber_buf + (pBer->ber_ptr - pBer->ber_buf);
+ p->ber_end = p->ber_buf + p->ber_len;
+ memcpy(p->ber_buf, pBer->ber_buf, p->ber_len);
+ } else {
+ ber_free(p, 0);
+ p = NULL;
+ *pSize = 0;
+ }
+ }
+
+ return p;
+}
+
+/* Dup a entry or a chain of entries. */
+static int
+memcache_dup_message(LDAPMessage *res, int msgid, int fromcache,
+ LDAPMessage **ppResCopy, unsigned long *pSize)
+{
+ int nRes = LDAP_SUCCESS;
+ unsigned long ber_size;
+ LDAPMessage *pCur;
+ LDAPMessage **ppCurNew;
+
+ *ppResCopy = NULL;
+
+ if (pSize)
+ *pSize = 0;
+
+ /* Make a copy of res */
+ for (pCur = res, ppCurNew = ppResCopy; pCur;
+ pCur = pCur->lm_chain, ppCurNew = &((*ppCurNew)->lm_chain)) {
+
+ if ((*ppCurNew = (LDAPMessage*)NSLDAPI_CALLOC(1,
+ sizeof(LDAPMessage))) == NULL) {
+ nRes = LDAP_NO_MEMORY;
+ break;
+ }
+
+ memcpy(*ppCurNew, pCur, sizeof(LDAPMessage));
+ (*ppCurNew)->lm_next = NULL;
+ (*ppCurNew)->lm_ber = memcache_ber_dup(pCur->lm_ber, &ber_size);
+ (*ppCurNew)->lm_msgid = msgid;
+ (*ppCurNew)->lm_fromcache = (fromcache != 0);
+
+ if (pSize)
+ *pSize += sizeof(LDAPMessage) + ber_size;
+ }
+
+ if ((nRes != LDAP_SUCCESS) && (*ppResCopy != NULL)) {
+ ldap_msgfree(*ppResCopy);
+ *ppResCopy = NULL;
+ if (pSize)
+ *pSize = 0;
+ }
+
+ return nRes;
+}
+
+/************************* Cache Functions ***********************/
+
+/* Frees a cache header. */
+static int
+memcache_free_entry(LDAPMemCache *cache, ldapmemcacheRes *pRes)
+{
+ if (pRes) {
+
+ unsigned long size = sizeof(ldapmemcacheRes);
+
+ if (pRes->ldmemcr_basedn) {
+ size += strlen(pRes->ldmemcr_basedn) + 1;
+ NSLDAPI_FREE(pRes->ldmemcr_basedn);
+ }
+
+ if (pRes->ldmemcr_resHead) {
+ size += pRes->ldmemcr_resSize;
+ ldap_msgfree(pRes->ldmemcr_resHead);
+ }
+
+ NSLDAPI_FREE(pRes);
+
+ memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
+ MEMCACHE_SIZE_DEDUCT);
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+/* Detaches a cache header from the list of headers. */
+static int
+memcache_free_from_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, int index)
+{
+ if (pRes->ldmemcr_prev[index])
+ pRes->ldmemcr_prev[index]->ldmemcr_next[index] =
+ pRes->ldmemcr_next[index];
+
+ if (pRes->ldmemcr_next[index])
+ pRes->ldmemcr_next[index]->ldmemcr_prev[index] =
+ pRes->ldmemcr_prev[index];
+
+ if (cache->ldmemc_resHead[index] == pRes)
+ cache->ldmemc_resHead[index] = pRes->ldmemcr_next[index];
+
+ if (cache->ldmemc_resTail[index] == pRes)
+ cache->ldmemc_resTail[index] = pRes->ldmemcr_prev[index];
+
+ pRes->ldmemcr_prev[index] = NULL;
+ pRes->ldmemcr_next[index] = NULL;
+
+ return( LDAP_SUCCESS );
+}
+
+/* Inserts a new cache header to a list of headers. */
+static int
+memcache_add_to_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, int index)
+{
+ if (cache->ldmemc_resHead[index])
+ cache->ldmemc_resHead[index]->ldmemcr_prev[index] = pRes;
+ else
+ cache->ldmemc_resTail[index] = pRes;
+
+ pRes->ldmemcr_prev[index] = NULL;
+ pRes->ldmemcr_next[index] = cache->ldmemc_resHead[index];
+ cache->ldmemc_resHead[index] = pRes;
+
+ return( LDAP_SUCCESS );
+}
+
+/* Appends a chain of entries to the given cache header. */
+static int
+memcache_add_res_to_list(ldapmemcacheRes *pRes, LDAPMessage *pMsg,
+ unsigned long size)
+{
+ if (pRes->ldmemcr_resTail)
+ pRes->ldmemcr_resTail->lm_chain = pMsg;
+ else
+ pRes->ldmemcr_resHead = pMsg;
+
+ for (pRes->ldmemcr_resTail = pMsg;
+ pRes->ldmemcr_resTail->lm_chain;
+ pRes->ldmemcr_resTail = pRes->ldmemcr_resTail->lm_chain) {
+ ;
+ }
+
+ pRes->ldmemcr_resSize += size;
+
+ return( LDAP_SUCCESS );
+}
+
+
+#ifdef LDAP_DEBUG
+static void
+memcache_print_list( LDAPMemCache *cache, int index )
+{
+ char *name;
+ ldapmemcacheRes *restmp;
+
+ switch( index ) {
+ case LIST_TTL:
+ name = "TTL";
+ break;
+ case LIST_LRU:
+ name = "LRU";
+ break;
+ case LIST_TMP:
+ name = "TMP";
+ break;
+ case LIST_TOTAL:
+ name = "TOTAL";
+ break;
+ default:
+ name = "unknown";
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "memcache 0x%x %s list:\n",
+ cache, name, 0 );
+ for ( restmp = cache->ldmemc_resHead[index]; restmp != NULL;
+ restmp = restmp->ldmemcr_next[index] ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ " key: 0x%8.8lx, ld: 0x%x, msgid: %d\n",
+ restmp->ldmemcr_crc_key,
+ restmp->ldmemcr_req_id.ldmemcrid_ld,
+ restmp->ldmemcr_req_id.ldmemcrid_msgid );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "memcache 0x%x end of %s list.\n",
+ cache, name, 0 );
+}
+#endif /* LDAP_DEBUG */
+
+/* Tells whether a cached result has expired. */
+static int
+memcache_expired(LDAPMemCache *cache, ldapmemcacheRes *pRes,
+ unsigned long curTime)
+{
+ if (!cache->ldmemc_ttl)
+ return 0;
+
+ return ((unsigned long)difftime(
+ (time_t)curTime,
+ (time_t)(pRes->ldmemcr_timestamp)) >=
+ cache->ldmemc_ttl);
+}
+
+/* Operates the cache in a central place. */
+static int
+memcache_access(LDAPMemCache *cache, int mode,
+ void *pData1, void *pData2, void *pData3)
+{
+ int nRes = LDAP_SUCCESS;
+ unsigned long size = 0;
+
+ /* Add a new cache header to the cache. */
+ if (mode == MEMCACHE_ACCESS_ADD) {
+ unsigned long key = *((unsigned long*)pData1);
+ char *basedn = (char*)pData3;
+ ldapmemcacheRes *pRes = NULL;
+
+ nRes = htable_get(cache->ldmemc_resTmp, pData2, (void**)&pRes);
+ if (nRes == LDAP_SUCCESS)
+ return( LDAP_ALREADY_EXISTS );
+
+ pRes = (ldapmemcacheRes*)NSLDAPI_CALLOC(1, sizeof(ldapmemcacheRes));
+ if (pRes == NULL)
+ return( LDAP_NO_MEMORY );
+
+ pRes->ldmemcr_crc_key = key;
+ pRes->ldmemcr_req_id = *((ldapmemcacheReqId*)pData2);
+ pRes->ldmemcr_basedn = (basedn ? nsldapi_strdup(basedn) : NULL);
+
+ size += sizeof(ldapmemcacheRes) + strlen(basedn) + 1;
+ nRes = memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
+ MEMCACHE_SIZE_ADD);
+ if (nRes == LDAP_SUCCESS)
+ nRes = htable_put(cache->ldmemc_resTmp, pData2, (void*)pRes);
+ if (nRes == LDAP_SUCCESS)
+ memcache_add_to_list(cache, pRes, LIST_TMP);
+ else
+ memcache_free_entry(cache, pRes);
+ }
+ /* Append entries to an existing cache header. */
+ else if ((mode == MEMCACHE_ACCESS_APPEND) ||
+ (mode == MEMCACHE_ACCESS_APPEND_LAST)) {
+
+ LDAPMessage *pMsg = (LDAPMessage*)pData2;
+ LDAPMessage *pCopy = NULL;
+ ldapmemcacheRes *pRes = NULL;
+
+ nRes = htable_get(cache->ldmemc_resTmp, pData1, (void**)&pRes);
+ if (nRes != LDAP_SUCCESS)
+ return nRes;
+
+ nRes = memcache_dup_message(pMsg, pMsg->lm_msgid, 0, &pCopy, &size);
+ if (nRes != LDAP_SUCCESS) {
+ nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, pRes, LIST_TMP);
+ memcache_free_entry(cache, pRes);
+ return nRes;
+ }
+
+ nRes = memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
+ MEMCACHE_SIZE_ADD);
+ if (nRes != LDAP_SUCCESS) {
+ ldap_msgfree(pCopy);
+ nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, pRes, LIST_TMP);
+ memcache_free_entry(cache, pRes);
+ return nRes;
+ }
+
+ memcache_add_res_to_list(pRes, pCopy, size);
+
+ if (mode == MEMCACHE_ACCESS_APPEND)
+ return( LDAP_SUCCESS );
+
+ nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, pRes, LIST_TMP);
+ (pRes->ldmemcr_req_id).ldmemcrid_ld = NULL;
+ (pRes->ldmemcr_req_id).ldmemcrid_msgid = -1;
+ pRes->ldmemcr_timestamp = (unsigned long)time(NULL);
+
+ if ((nRes = htable_put(cache->ldmemc_resLookup,
+ (void*)&(pRes->ldmemcr_crc_key),
+ (void*)pRes)) == LDAP_SUCCESS) {
+ memcache_add_to_list(cache, pRes, LIST_TTL);
+ memcache_add_to_list(cache, pRes, LIST_LRU);
+ } else {
+ memcache_free_entry(cache, pRes);
+ }
+ }
+ /* Search for cached entries for a particular search. */
+ else if (mode == MEMCACHE_ACCESS_FIND) {
+
+ ldapmemcacheRes **ppRes = (ldapmemcacheRes**)pData2;
+
+ nRes = htable_get(cache->ldmemc_resLookup, pData1, (void**)ppRes);
+ if (nRes != LDAP_SUCCESS)
+ return nRes;
+
+ if (!memcache_expired(cache, *ppRes, (unsigned long)time(0))) {
+ memcache_free_from_list(cache, *ppRes, LIST_LRU);
+ memcache_add_to_list(cache, *ppRes, LIST_LRU);
+ return( LDAP_SUCCESS );
+ }
+
+ nRes = htable_remove(cache->ldmemc_resLookup, pData1, NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, *ppRes, LIST_TTL);
+ memcache_free_from_list(cache, *ppRes, LIST_LRU);
+ memcache_free_entry(cache, *ppRes);
+ nRes = LDAP_NO_SUCH_OBJECT;
+ *ppRes = NULL;
+ }
+ /* Remove cached entries in the temporary cache. */
+ else if (mode == MEMCACHE_ACCESS_DELETE) {
+
+ ldapmemcacheRes *pCurRes = NULL;
+
+ if ((nRes = htable_remove(cache->ldmemc_resTmp, pData1,
+ (void**)&pCurRes)) == LDAP_SUCCESS) {
+ memcache_free_from_list(cache, pCurRes, LIST_TMP);
+ memcache_free_entry(cache, pCurRes);
+ }
+ }
+ /* Wipe out the temporary cache. */
+ else if (mode == MEMCACHE_ACCESS_DELETE_ALL) {
+
+ nRes = htable_removeall(cache->ldmemc_resTmp, (void*)cache);
+ }
+ /* Remove expired entries from primary cache. */
+ else if (mode == MEMCACHE_ACCESS_UPDATE) {
+
+ ldapmemcacheRes *pCurRes = cache->ldmemc_resTail[LIST_TTL];
+ unsigned long curTime = (unsigned long)time(NULL);
+
+ for (; pCurRes; pCurRes = cache->ldmemc_resTail[LIST_TTL]) {
+
+ if (!memcache_expired(cache, pCurRes, curTime))
+ break;
+
+ nRes = htable_remove(cache->ldmemc_resLookup,
+ (void*)&(pCurRes->ldmemcr_crc_key), NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, pCurRes, LIST_TTL);
+ memcache_free_from_list(cache, pCurRes, LIST_LRU);
+ memcache_free_entry(cache, pCurRes);
+ }
+ }
+ /* Wipe out the primary cache. */
+ else if (mode == MEMCACHE_ACCESS_FLUSH_ALL) {
+
+ ldapmemcacheRes *pCurRes = cache->ldmemc_resHead[LIST_TTL];
+
+ nRes = htable_removeall(cache->ldmemc_resLookup, (void*)cache);
+
+ for (; pCurRes; pCurRes = cache->ldmemc_resHead[LIST_TTL]) {
+ memcache_free_from_list(cache, pCurRes, LIST_LRU);
+ cache->ldmemc_resHead[LIST_TTL] =
+ cache->ldmemc_resHead[LIST_TTL]->ldmemcr_next[LIST_TTL];
+ memcache_free_entry(cache, pCurRes);
+ }
+ cache->ldmemc_resTail[LIST_TTL] = NULL;
+ }
+ /* Remove cached entries in both primary and temporary cache. */
+ else if (mode == MEMCACHE_ACCESS_FLUSH) {
+
+ int i, list_id, bDone;
+ int scope = (int)(uintptr_t)pData2;
+ char *dn = (char*)pData1;
+ char *dnTmp;
+ BerElement ber;
+ LDAPMessage *pMsg;
+ ldapmemcacheRes *pRes;
+
+ if (cache->ldmemc_basedns) {
+ for (i = 0; cache->ldmemc_basedns[i]; i++) {
+ if ((memcache_compare_dn(cache->ldmemc_basedns[i], dn,
+ LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE) ||
+ (memcache_compare_dn(dn, cache->ldmemc_basedns[i],
+ LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE))
+ break;
+ }
+ if (cache->ldmemc_basedns[i] == NULL)
+ return( LDAP_SUCCESS );
+ }
+
+ for (i = 0; i < 2; i++) {
+
+ list_id = (i == 0 ? LIST_TTL : LIST_TMP);
+
+ for (pRes = cache->ldmemc_resHead[list_id]; pRes != NULL;
+ pRes = pRes->ldmemcr_next[list_id]) {
+
+ if ((memcache_compare_dn(pRes->ldmemcr_basedn, dn,
+ LDAP_SCOPE_SUBTREE) != LDAP_COMPARE_TRUE) &&
+ (memcache_compare_dn(dn, pRes->ldmemcr_basedn,
+ LDAP_SCOPE_SUBTREE) != LDAP_COMPARE_TRUE))
+ continue;
+
+ for (pMsg = pRes->ldmemcr_resHead, bDone = 0;
+ !bDone && pMsg; pMsg = pMsg->lm_chain) {
+
+ if (!NSLDAPI_IS_SEARCH_ENTRY( pMsg->lm_msgtype ))
+ continue;
+
+ ber = *(pMsg->lm_ber);
+ if (ber_scanf(&ber, "{a", &dnTmp) != LBER_ERROR) {
+ bDone = (memcache_compare_dn(dnTmp, dn, scope) ==
+ LDAP_COMPARE_TRUE);
+ ldap_memfree(dnTmp);
+ }
+ }
+
+ if (!bDone)
+ continue;
+
+ if (list_id == LIST_TTL) {
+ nRes = htable_remove(cache->ldmemc_resLookup,
+ (void*)&(pRes->ldmemcr_crc_key), NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, pRes, LIST_TTL);
+ memcache_free_from_list(cache, pRes, LIST_LRU);
+ } else {
+ nRes = htable_remove(cache->ldmemc_resTmp,
+ (void*)&(pRes->ldmemcr_req_id), NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, pRes, LIST_TMP);
+ }
+ memcache_free_entry(cache, pRes);
+ }
+ }
+ }
+ /* Flush least recently used entries from cache */
+ else if (mode == MEMCACHE_ACCESS_FLUSH_LRU) {
+
+ ldapmemcacheRes *pRes = cache->ldmemc_resTail[LIST_LRU];
+
+ if (pRes == NULL)
+ return LDAP_NO_SUCH_OBJECT;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "memcache_access FLUSH_LRU: removing key 0x%8.8lx\n",
+ pRes->ldmemcr_crc_key, 0, 0 );
+ nRes = htable_remove(cache->ldmemc_resLookup,
+ (void*)&(pRes->ldmemcr_crc_key), NULL);
+ assert(nRes == LDAP_SUCCESS);
+ memcache_free_from_list(cache, pRes, LIST_TTL);
+ memcache_free_from_list(cache, pRes, LIST_LRU);
+ memcache_free_entry(cache, pRes);
+ }
+ /* Unknown command */
+ else {
+ nRes = LDAP_PARAM_ERROR;
+ }
+
+ return nRes;
+}
+
+
+#ifdef LDAP_DEBUG
+static void
+memcache_report_statistics( LDAPMemCache *cache )
+{
+ unsigned long hitrate;
+
+ if ( cache->ldmemc_stats.ldmemcstat_tries == 0 ) {
+ hitrate = 0;
+ } else {
+ hitrate = ( 100L * cache->ldmemc_stats.ldmemcstat_hits ) /
+ cache->ldmemc_stats.ldmemcstat_tries;
+ }
+ LDAPDebug( LDAP_DEBUG_STATS, "memcache 0x%x:\n", cache, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_STATS, " tries: %ld hits: %ld hitrate: %ld%%\n",
+ cache->ldmemc_stats.ldmemcstat_tries,
+ cache->ldmemc_stats.ldmemcstat_hits, hitrate );
+ if ( cache->ldmemc_size <= 0 ) { /* no size limit */
+ LDAPDebug( LDAP_DEBUG_STATS, " memory bytes used: %ld\n",
+ cache->ldmemc_size_used, 0, 0 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_STATS, " memory bytes used: %ld free: %ld\n",
+ cache->ldmemc_size_used,
+ cache->ldmemc_size - cache->ldmemc_size_used, 0 );
+ }
+}
+#endif /* LDAP_DEBUG */
+
+/************************ Hash Table Functions *****************************/
+
+/* Calculates size (# of entries) of hash table given the size limit for
+ the cache. */
+static int
+htable_calculate_size(int sizelimit)
+{
+ int i, j;
+ int size = (int)(((double)sizelimit /
+ (double)(sizeof(BerElement) + EXTRA_SIZE)) / 1.5);
+
+ /* Get a prime # */
+ size = (size & 0x1 ? size : size + 1);
+ for (i = 3, j = size / 2; i < j; i++) {
+ if ((size % i) == 0) {
+ size += 2;
+ i = 3;
+ j = size / 2;
+ }
+ }
+
+ return size;
+}
+
+/* Returns the size in bytes of the given hash table. */
+static int
+htable_sizeinbytes(HashTable *pTable)
+{
+ if (!pTable)
+ return 0;
+
+ return (pTable->size * sizeof(HashTableNode));
+}
+
+/* Inserts an item into the hash table. */
+static int
+htable_put(HashTable *pTable, void *key, void *pData)
+{
+ int index = pTable->hashfunc(pTable->size, key);
+
+ if (index >= 0 && index < pTable->size)
+ return pTable->putdata(&(pTable->table[index].pData), key, pData);
+
+ return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Retrieves an item from the hash table. */
+static int
+htable_get(HashTable *pTable, void *key, void **ppData)
+{
+ int index = pTable->hashfunc(pTable->size, key);
+
+ *ppData = NULL;
+
+ if (index >= 0 && index < pTable->size)
+ return pTable->getdata(pTable->table[index].pData, key, ppData);
+
+ return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Performs a miscellaneous operation on a hash table entry. */
+static int
+htable_misc(HashTable *pTable, void *key, void *pData)
+{
+ if (pTable->miscfunc) {
+ int index = pTable->hashfunc(pTable->size, key);
+ if (index >= 0 && index < pTable->size)
+ return pTable->miscfunc(&(pTable->table[index].pData), key, pData);
+ }
+
+ return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Removes an item from the hash table. */
+static int
+htable_remove(HashTable *pTable, void *key, void **ppData)
+{
+ int index = pTable->hashfunc(pTable->size, key);
+
+ if (ppData)
+ *ppData = NULL;
+
+ if (index >= 0 && index < pTable->size)
+ return pTable->removedata(&(pTable->table[index].pData), key, ppData);
+
+ return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Removes everything in the hash table. */
+static int
+htable_removeall(HashTable *pTable, void *pData)
+{
+ int i;
+
+ for (i = 0; i < pTable->size; i++)
+ pTable->clrtablenode(&(pTable->table[i].pData), pData);
+
+ return( LDAP_SUCCESS );
+}
+
+/* Creates a new hash table. */
+static int
+htable_create(int size_limit, HashFuncPtr hashf,
+ PutDataPtr putDataf, GetDataPtr getDataf,
+ RemoveDataPtr removeDataf, ClrTableNodePtr clrNodef,
+ MiscFuncPtr miscOpf, HashTable **ppTable)
+{
+ size_limit = htable_calculate_size(size_limit);
+
+ if ((*ppTable = (HashTable*)NSLDAPI_CALLOC(1, sizeof(HashTable))) == NULL)
+ return( LDAP_NO_MEMORY );
+
+ (*ppTable)->table = (HashTableNode*)NSLDAPI_CALLOC(size_limit,
+ sizeof(HashTableNode));
+ if ((*ppTable)->table == NULL) {
+ NSLDAPI_FREE(*ppTable);
+ *ppTable = NULL;
+ return( LDAP_NO_MEMORY );
+ }
+
+ (*ppTable)->size = size_limit;
+ (*ppTable)->hashfunc = hashf;
+ (*ppTable)->putdata = putDataf;
+ (*ppTable)->getdata = getDataf;
+ (*ppTable)->miscfunc = miscOpf;
+ (*ppTable)->removedata = removeDataf;
+ (*ppTable)->clrtablenode = clrNodef;
+
+ return( LDAP_SUCCESS );
+}
+
+/* Destroys a hash table. */
+static int
+htable_free(HashTable *pTable)
+{
+ NSLDAPI_FREE(pTable->table);
+ NSLDAPI_FREE(pTable);
+ return( LDAP_SUCCESS );
+}
+
+/**************** Hash table callbacks for temporary cache ****************/
+
+/* Hash function */
+static int
+msgid_hashf(int table_size, void *key)
+{
+ uint_t code = (uint_t)(uintptr_t)((ldapmemcacheReqId*)key)->ldmemcrid_ld;
+ return (((code << 20) + (code >> 12)) % table_size);
+}
+
+/* Called by hash table to insert an item. */
+static int
+msgid_putdata(void **ppTableData, void *key, void *pData)
+{
+ ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+ ldapmemcacheRes *pRes = (ldapmemcacheRes*)pData;
+ ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+ ldapmemcacheRes *pCurRes = *ppHead;
+ ldapmemcacheRes *pPrev = NULL;
+
+ for (; pCurRes; pCurRes = pCurRes->ldmemcr_htable_next) {
+ if ((pCurRes->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+ break;
+ pPrev = pCurRes;
+ }
+
+ if (pCurRes) {
+ for (; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) {
+ if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid ==
+ pReqId->ldmemcrid_msgid)
+ return( LDAP_ALREADY_EXISTS );
+ pPrev = pCurRes;
+ }
+ pPrev->ldmemcr_next[LIST_TTL] = pRes;
+ pRes->ldmemcr_prev[LIST_TTL] = pPrev;
+ pRes->ldmemcr_next[LIST_TTL] = NULL;
+ } else {
+ if (pPrev)
+ pPrev->ldmemcr_htable_next = pRes;
+ else
+ *ppHead = pRes;
+ pRes->ldmemcr_htable_next = NULL;
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+/* Called by hash table to retrieve an item. */
+static int
+msgid_getdata(void *pTableData, void *key, void **ppData)
+{
+ ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+ ldapmemcacheRes *pCurRes = (ldapmemcacheRes*)pTableData;
+
+ *ppData = NULL;
+
+ for (; pCurRes; pCurRes = pCurRes->ldmemcr_htable_next) {
+ if ((pCurRes->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+ break;
+ }
+
+ if (!pCurRes)
+ return( LDAP_NO_SUCH_OBJECT );
+
+ for (; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) {
+ if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid ==
+ pReqId->ldmemcrid_msgid) {
+ *ppData = (void*)pCurRes;
+ return( LDAP_SUCCESS );
+ }
+ }
+
+ return( LDAP_NO_SUCH_OBJECT );
+}
+
+/* Called by hash table to remove an item. */
+static int
+msgid_removedata(void **ppTableData, void *key, void **ppData)
+{
+ ldapmemcacheRes *pHead = *((ldapmemcacheRes**)ppTableData);
+ ldapmemcacheRes *pCurRes = NULL;
+ ldapmemcacheRes *pPrev = NULL;
+ ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+
+ if (ppData)
+ *ppData = NULL;
+
+ for (; pHead; pHead = pHead->ldmemcr_htable_next) {
+ if ((pHead->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+ break;
+ pPrev = pHead;
+ }
+
+ if (!pHead)
+ return( LDAP_NO_SUCH_OBJECT );
+
+ for (pCurRes = pHead; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) {
+ if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid ==
+ pReqId->ldmemcrid_msgid)
+ break;
+ }
+
+ if (!pCurRes)
+ return( LDAP_NO_SUCH_OBJECT );
+
+ if (ppData) {
+ pCurRes->ldmemcr_next[LIST_TTL] = NULL;
+ pCurRes->ldmemcr_prev[LIST_TTL] = NULL;
+ pCurRes->ldmemcr_htable_next = NULL;
+ *ppData = (void*)pCurRes;
+ }
+
+ if (pCurRes != pHead) {
+ if (pCurRes->ldmemcr_prev[LIST_TTL])
+ pCurRes->ldmemcr_prev[LIST_TTL]->ldmemcr_next[LIST_TTL] =
+ pCurRes->ldmemcr_next[LIST_TTL];
+ if (pCurRes->ldmemcr_next[LIST_TTL])
+ pCurRes->ldmemcr_next[LIST_TTL]->ldmemcr_prev[LIST_TTL] =
+ pCurRes->ldmemcr_prev[LIST_TTL];
+ return( LDAP_SUCCESS );
+ }
+
+ if (pPrev) {
+ if (pHead->ldmemcr_next[LIST_TTL]) {
+ pPrev->ldmemcr_htable_next = pHead->ldmemcr_next[LIST_TTL];
+ pHead->ldmemcr_next[LIST_TTL]->ldmemcr_htable_next =
+ pHead->ldmemcr_htable_next;
+ } else {
+ pPrev->ldmemcr_htable_next = pHead->ldmemcr_htable_next;
+ }
+ } else {
+ if (pHead->ldmemcr_next[LIST_TTL]) {
+ *((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_next[LIST_TTL];
+ pHead->ldmemcr_next[LIST_TTL]->ldmemcr_htable_next =
+ pHead->ldmemcr_htable_next;
+ } else {
+ *((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_htable_next;
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+/* Called by hash table to remove all cached entries associated to searches
+ being performed using the given ldap handle. */
+static int
+msgid_clear_ld_items(void **ppTableData, void *key, void *pData)
+{
+ LDAPMemCache *cache = (LDAPMemCache*)pData;
+ ldapmemcacheRes *pHead = *((ldapmemcacheRes**)ppTableData);
+ ldapmemcacheRes *pPrev = NULL;
+ ldapmemcacheRes *pCurRes = NULL;
+ ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+
+ for (; pHead; pHead = pHead->ldmemcr_htable_next) {
+ if ((pHead->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+ break;
+ pPrev = pHead;
+ }
+
+ if (!pHead)
+ return( LDAP_NO_SUCH_OBJECT );
+
+ if (pPrev)
+ pPrev->ldmemcr_htable_next = pHead->ldmemcr_htable_next;
+ else
+ *((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_htable_next;
+
+ for (pCurRes = pHead; pHead; pCurRes = pHead) {
+ pHead = pHead->ldmemcr_next[LIST_TTL];
+ memcache_free_from_list(cache, pCurRes, LIST_TMP);
+ memcache_free_entry(cache, pCurRes);
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+/* Called by hash table for removing all items in the table. */
+static void
+msgid_clearnode(void **ppTableData, void *pData)
+{
+ LDAPMemCache *cache = (LDAPMemCache*)pData;
+ ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+ ldapmemcacheRes *pSubHead = *ppHead;
+ ldapmemcacheRes *pCurRes = NULL;
+
+ for (; *ppHead; pSubHead = *ppHead) {
+ ppHead = &((*ppHead)->ldmemcr_htable_next);
+ for (pCurRes = pSubHead; pSubHead; pCurRes = pSubHead) {
+ pSubHead = pSubHead->ldmemcr_next[LIST_TTL];
+ memcache_free_from_list(cache, pCurRes, LIST_TMP);
+ memcache_free_entry(cache, pCurRes);
+ }
+ }
+}
+
+/********************* Hash table for primary cache ************************/
+
+/* Hash function */
+static int
+attrkey_hashf(int table_size, void *key)
+{
+ return ((*((unsigned long*)key)) % table_size);
+}
+
+/* Called by hash table to insert an item. */
+static int
+attrkey_putdata(void **ppTableData, void *key, void *pData)
+{
+ unsigned long attrkey = *((unsigned long*)key);
+ ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+ ldapmemcacheRes *pRes = *ppHead;
+
+ for (; pRes; pRes = pRes->ldmemcr_htable_next) {
+ if (pRes->ldmemcr_crc_key == attrkey)
+ return( LDAP_ALREADY_EXISTS );
+ }
+
+ pRes = (ldapmemcacheRes*)pData;
+ pRes->ldmemcr_htable_next = *ppHead;
+ *ppHead = pRes;
+
+ return( LDAP_SUCCESS );
+}
+
+/* Called by hash table to retrieve an item. */
+static int
+attrkey_getdata(void *pTableData, void *key, void **ppData)
+{
+ unsigned long attrkey = *((unsigned long*)key);
+ ldapmemcacheRes *pRes = (ldapmemcacheRes*)pTableData;
+
+ for (; pRes; pRes = pRes->ldmemcr_htable_next) {
+ if (pRes->ldmemcr_crc_key == attrkey) {
+ *ppData = (void*)pRes;
+ return( LDAP_SUCCESS );
+ }
+ }
+
+ *ppData = NULL;
+
+ return( LDAP_NO_SUCH_OBJECT );
+}
+
+/* Called by hash table to remove an item. */
+static int
+attrkey_removedata(void **ppTableData, void *key, void **ppData)
+{
+ unsigned long attrkey = *((unsigned long*)key);
+ ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+ ldapmemcacheRes *pRes = *ppHead;
+ ldapmemcacheRes *pPrev = NULL;
+
+ for (; pRes; pRes = pRes->ldmemcr_htable_next) {
+ if (pRes->ldmemcr_crc_key == attrkey) {
+ if (ppData)
+ *ppData = (void*)pRes;
+ if (pPrev)
+ pPrev->ldmemcr_htable_next = pRes->ldmemcr_htable_next;
+ else
+ *ppHead = pRes->ldmemcr_htable_next;
+ pRes->ldmemcr_htable_next = NULL;
+ return( LDAP_SUCCESS );
+ }
+ pPrev = pRes;
+ }
+
+ if (ppData)
+ *ppData = NULL;
+
+ return( LDAP_NO_SUCH_OBJECT );
+}
+
+/* Called by hash table for removing all items in the table. */
+static void
+attrkey_clearnode(void **ppTableData, void *pData)
+{
+ ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+ ldapmemcacheRes *pRes = *ppHead;
+
+ (void)pData;
+
+ for (; *ppHead; pRes = *ppHead) {
+ ppHead = &((*ppHead)->ldmemcr_htable_next);
+ pRes->ldmemcr_htable_next = NULL;
+ }
+}
+
+/***************************** CRC algorithm ********************************/
+
+/* From http://www.faqs.org/faqs/compression-faq/part1/section-25.html */
+
+/*
+ * Build auxiliary table for parallel byte-at-a-time CRC-32.
+ */
+#define NSLDAPI_CRC32_POLY 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */
+
+static unsigned long crc32_table[256] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 };
+
+/* Initialized first time "crc32()" is called. If you prefer, you can
+ * statically initialize it at compile time. [Another exercise.]
+ */
+
+static unsigned long
+crc32_convert(char *buf, int len)
+{
+ char *p;
+#ifdef OSF1V4D
+ unsigned int crc;
+#else
+ unsigned long crc; /* FIXME: this is not 32-bits on all platforms! */
+#endif /* OSF1V4D */
+
+ crc = 0xffffffff; /* preload shift register, per CRC-32 spec */
+ for (p = buf; len > 0; ++p, --len)
+ crc = ((crc << 8) ^ crc32_table[(crc >> 24) ^ *p]) & 0xffffffff;
+
+ return (unsigned long) ~crc; /* transmit complement, per CRC-32 spec */
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/message.c b/usr/src/lib/libldap5/sources/ldap/common/message.c
new file mode 100644
index 0000000000..7ca4a38c03
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/message.c
@@ -0,0 +1,92 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+#include "ldap-int.h"
+
+int
+LDAP_CALL
+ldap_msgid( LDAPMessage *lm )
+{
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( lm )) {
+ return( -1 );
+ }
+
+ return( lm->lm_msgid );
+}
+
+int
+LDAP_CALL
+ldap_msgtype( LDAPMessage *lm )
+{
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( lm )) {
+ return( -1 );
+ }
+
+ return( lm->lm_msgtype );
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_first_message( LDAP *ld, LDAPMessage *chain )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( NULLMSG ); /* punt */
+ }
+
+ return( chain );
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_next_message( LDAP *ld, LDAPMessage *msg )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( NULLMSG ); /* punt */
+ }
+
+ if ( msg == NULLMSG || msg->lm_chain == NULLMSG ) {
+ return( NULLMSG );
+ }
+
+ return( msg->lm_chain );
+}
+
+
+int
+LDAP_CALL
+ldap_count_messages( LDAP *ld, LDAPMessage *chain )
+{
+ int i;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 );
+ }
+
+ for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
+ i++;
+ }
+
+ return( i );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/modify.c b/usr/src/lib/libldap5/sources/ldap/common/modify.c
new file mode 100644
index 0000000000..55bbc3a666
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/modify.c
@@ -0,0 +1,213 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * modify.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_modify - initiate an ldap modify operation. Parameters:
+ *
+ * ld LDAP descriptor
+ * dn DN of the object to modify
+ * mods List of modifications to make. This is null-terminated
+ * array of struct ldapmod's, specifying the modifications
+ * to perform.
+ *
+ * Example:
+ * LDAPMod *mods[] = {
+ * { LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } },
+ * { LDAP_MOD_REPLACE, "sn", { "jensen", 0 } },
+ * 0
+ * }
+ * msgid = ldap_modify( ld, dn, mods );
+ */
+int
+LDAP_CALL
+ldap_modify( LDAP *ld, const char *dn, LDAPMod **mods )
+{
+ int msgid;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_modify\n", 0, 0, 0 );
+
+ if ( ldap_modify_ext( ld, dn, mods, NULL, NULL, &msgid )
+ == LDAP_SUCCESS ) {
+ return( msgid );
+ } else {
+ return( -1 ); /* error is in ld handle */
+ }
+}
+
+int
+LDAP_CALL
+ldap_modify_ext( LDAP *ld, const char *dn, LDAPMod **mods,
+ LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp )
+{
+ BerElement *ber;
+ int i, rc, lderr;
+
+ /*
+ * A modify request looks like this:
+ * ModifyRequet ::= SEQUENCE {
+ * object DistinguishedName,
+ * modifications SEQUENCE OF SEQUENCE {
+ * operation ENUMERATED {
+ * add (0),
+ * delete (1),
+ * replace (2)
+ * },
+ * modification SEQUENCE {
+ * type AttributeType,
+ * values SET OF AttributeValue
+ * }
+ * }
+ * }
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_modify_ext\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+ if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( msgidp ))
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( !NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( mods )) {
+ lderr = LDAP_PARAM_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ return( lderr );
+ }
+ if ( dn == NULL ) {
+ dn = "";
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ *msgidp = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ /* see if we should add to the cache */
+ if ( ld->ld_cache_on && ld->ld_cache_modify != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_modify)( ld, *msgidp, LDAP_REQ_MODIFY,
+ dn, mods )) != 0 ) {
+ *msgidp = rc;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+
+ /* create a message to send */
+ if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( lderr );
+ }
+
+ if ( ber_printf( ber, "{it{s{", *msgidp, LDAP_REQ_MODIFY, dn )
+ == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ /* for each modification to be performed... */
+ for ( i = 0; mods[i] != NULL; i++ ) {
+ if (( mods[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
+ rc = ber_printf( ber, "{e{s[V]}}",
+ mods[i]->mod_op & ~LDAP_MOD_BVALUES,
+ mods[i]->mod_type, mods[i]->mod_bvalues );
+ } else {
+ rc = ber_printf( ber, "{e{s[v]}}", mods[i]->mod_op,
+ mods[i]->mod_type, mods[i]->mod_values );
+ }
+
+ if ( rc == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+ }
+
+ if ( ber_printf( ber, "}}" ) == -1 ) {
+ lderr = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( lderr );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_MODIFY,
+ (char *)dn, ber );
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_modify_s( LDAP *ld, const char *dn, LDAPMod **mods )
+{
+ return( ldap_modify_ext_s( ld, dn, mods, NULL, NULL ));
+}
+
+int
+LDAP_CALL
+ldap_modify_ext_s( LDAP *ld, const char *dn, LDAPMod **mods,
+ LDAPControl **serverctrls, LDAPControl **clientctrls )
+{
+ int msgid, err;
+ LDAPMessage *res;
+
+ if (( err = ldap_modify_ext( ld, dn, mods, serverctrls, clientctrls,
+ &msgid )) != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res ) == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ return( ldap_result2error( ld, res, 1 ) );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/open.c b/usr/src/lib/libldap5/sources/ldap/common/open.c
new file mode 100644
index 0000000000..ee59bf4c0a
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/open.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * open.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+#ifdef LDAP_SASLIO_HOOKS
+/* Valid for any ANSI C compiler */
+#include <limits.h>
+#endif
+
+#define VI_PRODUCTVERSION 3
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK ((unsigned long) 0x7f000001)
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#ifdef LDAP_DEBUG
+int ldap_debug;
+#endif
+
+
+/*
+ * global defaults for callbacks are stored here. callers of the API set
+ * these by passing a NULL "ld" to ldap_set_option(). Everything in
+ * nsldapi_ld_defaults can be overridden on a per-ld basis as well (the
+ * memory allocation functions are global to all ld's).
+ */
+struct ldap nsldapi_ld_defaults;
+struct ldap_memalloc_fns nsldapi_memalloc_fns = { 0, 0, 0, 0 };
+int nsldapi_initialized = 0;
+
+#ifndef _WINDOWS
+#include <pthread.h>
+static pthread_key_t nsldapi_key;
+
+struct nsldapi_ldap_error {
+ int le_errno;
+ char *le_matched;
+ char *le_errmsg;
+};
+#else
+__declspec ( thread ) int nsldapi_gldaperrno;
+__declspec ( thread ) char *nsldapi_gmatched = NULL;
+__declspec ( thread ) char *nsldapi_gldaperror = NULL;
+#endif /* _WINDOWS */
+
+#ifdef _WINDOWS
+#define LDAP_MUTEX_T HANDLE
+
+int
+pthread_mutex_init( LDAP_MUTEX_T *mp, void *attr)
+{
+ if ( (*mp = CreateMutex(NULL, FALSE, NULL)) == NULL )
+ return( 1 );
+ else
+ return( 0 );
+}
+
+static void *
+pthread_mutex_alloc( void )
+{
+ LDAP_MUTEX_T *mutexp;
+
+ if ( (mutexp = malloc( sizeof(LDAP_MUTEX_T) )) != NULL ) {
+ pthread_mutex_init( mutexp, NULL );
+ }
+ return( mutexp );
+}
+
+int
+pthread_mutex_destroy( LDAP_MUTEX_T *mp )
+{
+ if ( !(CloseHandle(*mp)) )
+ return( 1 );
+ else
+ return( 0 );
+}
+
+static void
+pthread_mutex_free( void *mutexp )
+{
+ pthread_mutex_destroy( (LDAP_MUTEX_T *) mutexp );
+ free( mutexp );
+}
+
+int
+pthread_mutex_lock( LDAP_MUTEX_T *mp )
+{
+ if ( (WaitForSingleObject(*mp, INFINITE) != WAIT_OBJECT_0) )
+ return( 1 );
+ else
+ return( 0 );
+}
+
+int
+pthread_mutex_unlock( LDAP_MUTEX_T *mp )
+{
+ if ( !(ReleaseMutex(*mp)) )
+ return( 1 );
+ else
+ return( 0 );
+}
+
+static int
+get_errno( void )
+{
+ return errno;
+}
+
+static void
+set_errno( int Errno )
+{
+ errno = Errno;
+}
+
+static int
+get_ld_error( char **LDMatched, char **LDError, void * Args )
+{
+ if ( LDMatched != NULL )
+ {
+ *LDMatched = nsldapi_gmatched;
+ }
+ if ( LDError != NULL )
+ {
+ *LDError = nsldapi_gldaperror;
+ }
+ return nsldapi_gldaperrno;
+}
+
+static void
+set_ld_error( int LDErrno, char * LDMatched, char * LDError,
+ void * Args )
+{
+ /* Clean up any previous string storage. */
+ if ( nsldapi_gmatched != NULL )
+ {
+ ldap_memfree( nsldapi_gmatched );
+ }
+ if ( nsldapi_gldaperror != NULL )
+ {
+ ldap_memfree( nsldapi_gldaperror );
+ }
+
+ nsldapi_gldaperrno = LDErrno;
+ nsldapi_gmatched = LDMatched;
+ nsldapi_gldaperror = LDError;
+}
+#else
+static void *
+pthread_mutex_alloc( void )
+{
+ pthread_mutex_t *mutexp;
+
+ if ( (mutexp = malloc( sizeof(pthread_mutex_t) )) != NULL ) {
+ pthread_mutex_init( mutexp, NULL );
+ }
+ return( mutexp );
+}
+
+static void
+pthread_mutex_free( void *mutexp )
+{
+ pthread_mutex_destroy( (pthread_mutex_t *) mutexp );
+ free( mutexp );
+}
+
+static void
+set_ld_error( int err, char *matched, char *errmsg, void *dummy )
+{
+ struct nsldapi_ldap_error *le;
+ void *tsd;
+
+ le = pthread_getspecific( nsldapi_key );
+
+ if (le == NULL) {
+ tsd = (void *)calloc(1, sizeof(struct nsldapi_ldap_error));
+ pthread_setspecific( nsldapi_key, tsd );
+ }
+
+ le = pthread_getspecific( nsldapi_key );
+
+ if (le == NULL) {
+ free(tsd);
+ return;
+ }
+
+ le->le_errno = err;
+
+ if ( le->le_matched != NULL ) {
+ ldap_memfree( le->le_matched );
+ }
+ le->le_matched = matched;
+
+ if ( le->le_errmsg != NULL ) {
+ ldap_memfree( le->le_errmsg );
+ }
+ le->le_errmsg = errmsg;
+}
+
+static int
+get_ld_error( char **matched, char **errmsg, void *dummy )
+{
+ struct nsldapi_ldap_error *le;
+
+ le = pthread_getspecific( nsldapi_key );
+ if (le != NULL) {
+ if ( matched != NULL ) {
+ *matched = le->le_matched;
+ }
+ if ( errmsg != NULL ) {
+ *errmsg = le->le_errmsg;
+ }
+ return( le->le_errno );
+ } else {
+ if ( matched != NULL )
+ *matched = NULL;
+ if ( errmsg != NULL )
+ *errmsg = NULL;
+ }
+ return (LDAP_SUCCESS);
+}
+
+static void
+set_errno( int err )
+{
+ errno = err;
+}
+
+static int
+get_errno( void )
+{
+ return( errno );
+}
+#endif /* _WINDOWS */
+
+static struct ldap_thread_fns
+ nsldapi_default_thread_fns = {
+ (void *(*)(void))pthread_mutex_alloc,
+ (void (*)(void *))pthread_mutex_free,
+ (int (*)(void *))pthread_mutex_lock,
+ (int (*)(void *))pthread_mutex_unlock,
+ (int (*)(void))get_errno,
+ (void (*)(int))set_errno,
+ (int (*)(char **, char **, void *))get_ld_error,
+ (void (*)(int, char *, char *, void *))set_ld_error,
+ 0 };
+
+static struct ldap_extra_thread_fns
+ nsldapi_default_extra_thread_fns = {
+ 0, 0, 0, 0, 0,
+#ifdef _WINDOWS
+ 0
+#else
+ (void *(*)(void))pthread_self
+#endif /* _WINDOWS */
+ };
+
+void
+nsldapi_initialize_defaults( void )
+{
+
+ if ( nsldapi_initialized ) {
+ return;
+ }
+#ifdef _SOLARIS_SDK
+ /*
+ * This has to be called before nsldapi_initialized is set to 1
+ * because nsldapi_initialized does not have mutex protection
+ */
+ prldap_nspr_init();
+#endif
+
+#ifndef _WINDOWS
+ if ( pthread_key_create(&nsldapi_key, free ) != 0) {
+ perror("pthread_key_create");
+ }
+#endif /* _WINDOWS */
+
+ nsldapi_initialized = 1;
+ memset( &nsldapi_memalloc_fns, 0, sizeof( nsldapi_memalloc_fns ));
+ memset( &nsldapi_ld_defaults, 0, sizeof( nsldapi_ld_defaults ));
+ nsldapi_ld_defaults.ld_options = LDAP_BITOPT_REFERRALS;
+ nsldapi_ld_defaults.ld_version = LDAP_VERSION2;
+ nsldapi_ld_defaults.ld_lberoptions = LBER_OPT_USE_DER;
+ nsldapi_ld_defaults.ld_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
+
+#ifdef LDAP_SASLIO_HOOKS
+ /* SASL default option settings */
+ nsldapi_ld_defaults.ld_def_sasl_mech = NULL;
+ nsldapi_ld_defaults.ld_def_sasl_realm = NULL;
+ nsldapi_ld_defaults.ld_def_sasl_authcid = NULL;
+ nsldapi_ld_defaults.ld_def_sasl_authzid = NULL;
+ /* SASL Security properties */
+ nsldapi_ld_defaults.ld_sasl_secprops.max_ssf = UINT_MAX;
+ nsldapi_ld_defaults.ld_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE;
+ nsldapi_ld_defaults.ld_sasl_secprops.security_flags =
+ SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS;
+#endif
+
+#if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
+ nsldapi_ld_defaults.ld_lberoptions |= LBER_OPT_TRANSLATE_STRINGS;
+#if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
+ ldap_set_string_translators( &nsldapi_ld_defaults, ldap_8859_to_t61,
+ ldap_t61_to_8859 );
+#endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
+#endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
+
+ /* set default connect timeout (in milliseconds) */
+ /* this was picked as it is the standard tcp timeout as well */
+ nsldapi_ld_defaults.ld_connect_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+
+ /* load up default platform specific locking routines */
+ if (ldap_set_option( NULL, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&nsldapi_default_thread_fns) != LDAP_SUCCESS) {
+ return;
+ }
+
+#ifndef _WINDOWS
+ /* load up default threadid function */
+ if (ldap_set_option( NULL, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
+ (void *)&nsldapi_default_extra_thread_fns) != LDAP_SUCCESS) {
+ return;
+ }
+#endif /* _WINDOWS */
+}
+
+
+/*
+ * ldap_version - report version levels for important properties
+ * This function is deprecated. Use ldap_get_option( ..., LDAP_OPT_API_INFO,
+ * ... ) instead.
+ *
+ * Example:
+ * LDAPVersion ver;
+ * ldap_version( &ver );
+ * if ( (ver.sdk_version < 100) || (ver.SSL_version < 300) )
+ * fprintf( stderr, "LDAP SDK level insufficient\n" );
+ *
+ * or:
+ * if ( ldap_version(NULL) < 100 )
+ * fprintf( stderr, "LDAP SDK level insufficient\n" );
+ *
+ */
+
+int
+LDAP_CALL
+ldap_version( LDAPVersion *ver )
+{
+ if ( NULL != ver )
+ {
+ memset( ver, 0, sizeof(*ver) );
+ ver->sdk_version = (int)(VI_PRODUCTVERSION * 100);
+ ver->protocol_version = LDAP_VERSION_MAX * 100;
+ ver->SSL_version = SSL_VERSION * 100;
+ /*
+ * set security to none by default
+ */
+
+ ver->security_level = LDAP_SECURITY_NONE;
+#if defined(LINK_SSL)
+#if defined(NS_DOMESTIC)
+ ver->security_level = 128;
+#elif defined(NSS_EXPORT)
+ ver->security_level = 40;
+#endif
+#endif
+
+ }
+ return (int)(VI_PRODUCTVERSION * 100);
+}
+
+/*
+ * ldap_open - initialize and connect to an ldap server. A magic cookie to
+ * be used for future communication is returned on success, NULL on failure.
+ * "host" may be a space-separated list of hosts or IP addresses
+ *
+ * Example:
+ * LDAP *ld;
+ * ld = ldap_open( hostname, port );
+ */
+
+LDAP *
+LDAP_CALL
+ldap_open( const char *host, int port )
+{
+ LDAP *ld;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+
+ if (( ld = ldap_init( host, port )) == NULL ) {
+ return( NULL );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ ldap_ld_free( ld, NULL, NULL, 0 );
+ return( NULL );
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open successful, ld_host is %s\n",
+ ( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
+
+ return( ld );
+}
+
+
+/*
+ * ldap_init - initialize the LDAP library. A magic cookie to be used for
+ * future communication is returned on success, NULL on failure.
+ * "defhost" may be a space-separated list of hosts or IP addresses
+ *
+ * Example:
+ * LDAP *ld;
+ * ld = ldap_init( default_hostname, default_port );
+ */
+LDAP *
+LDAP_CALL
+ldap_init( const char *defhost, int defport )
+{
+ LDAP *ld;
+
+ if ( !nsldapi_initialized ) {
+ nsldapi_initialize_defaults();
+ }
+
+ if ( defport < 0 || defport > LDAP_PORT_MAX ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldap_init: port %d is invalid (port numbers must range from 1 to %d)\n",
+ defport, LDAP_PORT_MAX, 0 );
+#if !defined( macintosh ) && !defined( DOS )
+ errno = EINVAL;
+#endif
+ return( NULL );
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_init\n", 0, 0, 0 );
+
+ if ( (ld = (LDAP*)NSLDAPI_MALLOC( sizeof(struct ldap) )) == NULL ) {
+ return( NULL );
+ }
+
+ /* copy defaults */
+ SAFEMEMCPY( ld, &nsldapi_ld_defaults, sizeof( struct ldap ));
+ if ( nsldapi_ld_defaults.ld_io_fns_ptr != NULL ) {
+ if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_MALLOC(
+ sizeof( struct ldap_io_fns ))) == NULL ) {
+ NSLDAPI_FREE( (char *)ld );
+ return( NULL );
+ }
+ /* struct copy */
+ *(ld->ld_io_fns_ptr) = *(nsldapi_ld_defaults.ld_io_fns_ptr);
+ }
+
+ /* call the new handle I/O callback if one is defined */
+ if ( ld->ld_extnewhandle_fn != NULL ) {
+ /*
+ * We always pass the session extended I/O argument to
+ * the new handle callback.
+ */
+ if ( ld->ld_extnewhandle_fn( ld, ld->ld_ext_session_arg )
+ != LDAP_SUCCESS ) {
+ NSLDAPI_FREE( (char*)ld );
+ return( NULL );
+ }
+ }
+
+ /* allocate session-specific resources */
+ if (( ld->ld_sbp = ber_sockbuf_alloc()) == NULL ||
+ ( defhost != NULL &&
+ ( ld->ld_defhost = nsldapi_strdup( defhost )) == NULL ) ||
+ ((ld->ld_mutex = (void **) NSLDAPI_CALLOC( LDAP_MAX_LOCK, sizeof(void *))) == NULL )) {
+ if ( ld->ld_sbp != NULL ) {
+ ber_sockbuf_free( ld->ld_sbp );
+ }
+ if( ld->ld_mutex != NULL ) {
+ NSLDAPI_FREE( ld->ld_mutex );
+ }
+ NSLDAPI_FREE( (char*)ld );
+ return( NULL );
+ }
+
+ /* install Sockbuf I/O functions if set in LDAP * */
+ if ( ld->ld_extread_fn != NULL || ld->ld_extwrite_fn != NULL ) {
+ struct lber_x_ext_io_fns lberiofns;
+
+ memset( &lberiofns, 0, sizeof( lberiofns ));
+
+ lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ lberiofns.lbextiofn_read = ld->ld_extread_fn;
+ lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
+ lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
+ lberiofns.lbextiofn_socket_arg = NULL;
+ ber_sockbuf_set_option( ld->ld_sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ (void *)&lberiofns );
+ }
+
+#ifdef _SOLARIS_SDK
+ /* Install the functions for IPv6 support */
+ /* code sequencing is critical from here to nsldapi_mutex_alloc_all */
+ if ( prldap_install_thread_functions( ld, 1 ) != 0 ||
+ prldap_install_io_functions( ld, 1 ) != 0 ||
+ prldap_install_dns_functions( ld ) != 0 ) {
+ /* go through ld and free resources */
+ ldap_unbind( ld );
+ ld = NULL;
+ return( NULL );
+ }
+#else
+
+ /* allocate mutexes */
+ nsldapi_mutex_alloc_all( ld );
+#endif
+
+ /* set default port */
+ ld->ld_defport = ( defport == 0 ) ? LDAP_PORT : defport;
+
+ return( ld );
+}
+
+void
+nsldapi_mutex_alloc_all( LDAP *ld )
+{
+ int i;
+
+ if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
+ for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
+ ld->ld_mutex[i] = LDAP_MUTEX_ALLOC( ld );
+ ld->ld_mutex_threadid[i] = (void *) -1;
+ ld->ld_mutex_refcnt[i] = 0;
+ }
+ }
+}
+
+
+void
+nsldapi_mutex_free_all( LDAP *ld )
+{
+ int i;
+
+ if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
+ for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
+ LDAP_MUTEX_FREE( ld, ld->ld_mutex[i] );
+ }
+ }
+}
+
+/* returns 0 if connection opened and -1 if an error occurs */
+int
+nsldapi_open_ldap_defconn( LDAP *ld )
+{
+ LDAPServer *srv;
+
+ if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer ))) ==
+ NULL || ( ld->ld_defhost != NULL && ( srv->lsrv_host =
+ nsldapi_strdup( ld->ld_defhost )) == NULL )) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ srv->lsrv_port = ld->ld_defport;
+
+#ifdef LDAP_SSLIO_HOOKS
+ if (( ld->ld_options & LDAP_BITOPT_SSL ) != 0 ) {
+ srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
+ }
+#endif
+
+ if (( ld->ld_defconn = nsldapi_new_connection( ld, &srv, 1, 1, 0 ))
+ == NULL ) {
+ if ( ld->ld_defhost != NULL ) {
+ NSLDAPI_FREE( srv->lsrv_host );
+ }
+ NSLDAPI_FREE( (char *)srv );
+ return( -1 );
+ }
+ ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
+
+ return( 0 );
+}
+
+
+struct ldap_x_hostlist_status {
+ char *lhs_hostlist;
+ char *lhs_nexthost;
+ int lhs_defport;
+};
+
+/*
+ * Return the first host and port in hostlist (setting *hostp and *portp).
+ * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
+ * Note that a NULL or zero-length hostlist causes the host "127.0.0.1" to
+ * be returned.
+ */
+int LDAP_CALL
+ldap_x_hostlist_first( const char *hostlist, int defport, char **hostp,
+ int *portp, struct ldap_x_hostlist_status **statusp )
+{
+
+ if ( NULL == hostp || NULL == portp || NULL == statusp ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL == hostlist || *hostlist == '\0' ) {
+ *hostp = nsldapi_strdup( "127.0.0.1" );
+ if ( NULL == *hostp ) {
+ return( LDAP_NO_MEMORY );
+ }
+ *portp = defport;
+ *statusp = NULL;
+ return( LDAP_SUCCESS );
+ }
+
+ *statusp = NSLDAPI_CALLOC( 1, sizeof( struct ldap_x_hostlist_status ));
+ if ( NULL == *statusp ) {
+ return( LDAP_NO_MEMORY );
+ }
+ (*statusp)->lhs_hostlist = nsldapi_strdup( hostlist );
+ if ( NULL == (*statusp)->lhs_hostlist ) {
+ return( LDAP_NO_MEMORY );
+ }
+ (*statusp)->lhs_nexthost = (*statusp)->lhs_hostlist;
+ (*statusp)->lhs_defport = defport;
+ return( ldap_x_hostlist_next( hostp, portp, *statusp ));
+}
+
+/*
+ * Return the next host and port in hostlist (setting *hostp and *portp).
+ * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
+ * If no more hosts are available, LDAP_SUCCESS is returned but *hostp is set
+ * to NULL.
+ */
+int LDAP_CALL
+ldap_x_hostlist_next( char **hostp, int *portp,
+ struct ldap_x_hostlist_status *status )
+{
+ char *q;
+ int squarebrackets = 0;
+
+ if ( NULL == hostp || NULL == portp ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL == status || NULL == status->lhs_nexthost ) {
+ *hostp = NULL;
+ return( LDAP_SUCCESS );
+ }
+
+ /*
+ * skip past leading '[' if present (IPv6 addresses may be surrounded
+ * with square brackets, e.g., [fe80::a00:20ff:fee5:c0b4]:389
+ */
+ if ( status->lhs_nexthost[0] == '[' ) {
+ ++status->lhs_nexthost;
+ squarebrackets = 1;
+ }
+
+ /* copy host into *hostp */
+ if ( NULL != ( q = strchr( status->lhs_nexthost, ' ' ))) {
+ size_t len = q - status->lhs_nexthost;
+ *hostp = NSLDAPI_MALLOC( len + 1 );
+ if ( NULL == *hostp ) {
+ return( LDAP_NO_MEMORY );
+ }
+ strncpy( *hostp, status->lhs_nexthost, len );
+ (*hostp)[len] = '\0';
+ status->lhs_nexthost += ( len + 1 );
+ } else { /* last host */
+ *hostp = nsldapi_strdup( status->lhs_nexthost );
+ if ( NULL == *hostp ) {
+ return( LDAP_NO_MEMORY );
+ }
+ status->lhs_nexthost = NULL;
+ }
+
+ /*
+ * Look for closing ']' and skip past it before looking for port.
+ */
+ if ( squarebrackets && NULL != ( q = strchr( *hostp, ']' ))) {
+ *q++ = '\0';
+ } else {
+ q = *hostp;
+ }
+
+ /* determine and set port */
+ if ( NULL != ( q = strchr( q, ':' ))) {
+ *q++ = '\0';
+ *portp = atoi( q );
+ } else {
+ *portp = status->lhs_defport;
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+void LDAP_CALL
+ldap_x_hostlist_statusfree( struct ldap_x_hostlist_status *status )
+{
+ if ( NULL != status ) {
+ if ( NULL != status->lhs_hostlist ) {
+ NSLDAPI_FREE( status->lhs_hostlist );
+ }
+ NSLDAPI_FREE( status );
+ }
+}
+
+
+
+/*
+ * memory allocation functions. we include these in open.c since every
+ * LDAP application is likely to pull the rest of the code in this file
+ * in anyways.
+ */
+void *
+ldap_x_malloc( size_t size )
+{
+ return( nsldapi_memalloc_fns.ldapmem_malloc == NULL ?
+ malloc( size ) :
+ nsldapi_memalloc_fns.ldapmem_malloc( size ));
+}
+
+
+void *
+ldap_x_calloc( size_t nelem, size_t elsize )
+{
+ return( nsldapi_memalloc_fns.ldapmem_calloc == NULL ?
+ calloc( nelem, elsize ) :
+ nsldapi_memalloc_fns.ldapmem_calloc( nelem, elsize ));
+}
+
+
+void *
+ldap_x_realloc( void *ptr, size_t size )
+{
+ return( nsldapi_memalloc_fns.ldapmem_realloc == NULL ?
+ realloc( ptr, size ) :
+ nsldapi_memalloc_fns.ldapmem_realloc( ptr, size ));
+}
+
+
+void
+ldap_x_free( void *ptr )
+{
+ if ( nsldapi_memalloc_fns.ldapmem_free == NULL ) {
+ free( ptr );
+ } else {
+ nsldapi_memalloc_fns.ldapmem_free( ptr );
+ }
+}
+
+
+/* if s is NULL, returns NULL */
+char *
+nsldapi_strdup( const char *s )
+{
+ char *p;
+
+ if ( s == NULL ||
+ (p = (char *)NSLDAPI_MALLOC( strlen( s ) + 1 )) == NULL )
+ return( NULL );
+
+ strcpy( p, s );
+
+ return( p );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/os-ip.c b/usr/src/lib/libldap5/sources/ldap/common/os-ip.c
new file mode 100644
index 0000000000..00e9769cfa
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/os-ip.c
@@ -0,0 +1,1822 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * os-ip.c -- platform-specific TCP & UDP related code
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+#ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
+#include <signal.h>
+#endif
+
+#ifdef NSLDAPI_HAVE_POLL
+#include <poll.h>
+#endif
+
+
+#ifdef _WINDOWS
+#define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) == INVALID_SOCKET)
+#else
+#define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) < 0 )
+#endif
+
+
+#define NSLDAPI_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
+
+
+/*
+ * Structures and union for tracking status of network sockets
+ */
+#ifdef NSLDAPI_HAVE_POLL
+struct nsldapi_os_statusinfo { /* used with native OS poll() */
+ struct pollfd *ossi_pollfds;
+ int ossi_pollfds_size;
+};
+#else /* NSLDAPI_HAVE_POLL */
+struct nsldapi_os_statusinfo { /* used with native OS select() */
+ fd_set ossi_readfds;
+ fd_set ossi_writefds;
+ fd_set ossi_use_readfds;
+ fd_set ossi_use_writefds;
+};
+#endif /* else NSLDAPI_HAVE_POLL */
+
+struct nsldapi_cb_statusinfo { /* used with ext. I/O poll() callback */
+ LDAP_X_PollFD *cbsi_pollfds;
+ int cbsi_pollfds_size;
+};
+
+/*
+ * NSLDAPI_CB_POLL_MATCH() evaluates to non-zero (true) if the Sockbuf *sdp
+ * matches the LDAP_X_PollFD pollfd.
+ */
+#ifdef _WINDOWS
+#define NSLDAPI_CB_POLL_SD_CAST (unsigned int)
+#else
+#define NSLDAPI_CB_POLL_SD_CAST
+#endif
+#if defined(LDAP_SASLIO_HOOKS)
+#define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
+ ( ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd)) && \
+ (((sbp)->sb_sasl_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg) || \
+ ((sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg) ) )
+#else
+#define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
+ ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd) && \
+ (sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg)
+#endif
+
+
+struct nsldapi_iostatus_info {
+ int ios_type;
+#define NSLDAPI_IOSTATUS_TYPE_OSNATIVE 1 /* poll() or select() */
+#define NSLDAPI_IOSTATUS_TYPE_CALLBACK 2 /* poll()-like */
+ int ios_read_count;
+ int ios_write_count;
+ union {
+ struct nsldapi_os_statusinfo ios_osinfo;
+ struct nsldapi_cb_statusinfo ios_cbinfo;
+ } ios_status;
+};
+
+
+#ifdef NSLDAPI_HAVE_POLL
+static int nsldapi_add_to_os_pollfds( int fd,
+ struct nsldapi_os_statusinfo *pip, short events );
+static int nsldapi_clear_from_os_pollfds( int fd,
+ struct nsldapi_os_statusinfo *pip, short events );
+static int nsldapi_find_in_os_pollfds( int fd,
+ struct nsldapi_os_statusinfo *pip, short revents );
+#endif /* NSLDAPI_HAVE_POLL */
+
+static int nsldapi_iostatus_init_nolock( LDAP *ld );
+static int nsldapi_add_to_cb_pollfds( Sockbuf *sb,
+ struct nsldapi_cb_statusinfo *pip, short events );
+static int nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
+ struct nsldapi_cb_statusinfo *pip, short events );
+static int nsldapi_find_in_cb_pollfds( Sockbuf *sb,
+ struct nsldapi_cb_statusinfo *pip, short revents );
+
+
+#ifdef irix
+#ifndef _PR_THREADS
+/*
+ * XXXmcs: on IRIX NSPR's poll() and select() wrappers will crash if NSPR
+ * has not been initialized. We work around the problem by bypassing
+ * the NSPR wrapper functions and going directly to the OS' functions.
+ */
+#define NSLDAPI_POLL _poll
+#define NSLDAPI_SELECT _select
+extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
+extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout);
+#else /* _PR_THREADS */
+#define NSLDAPI_POLL poll
+#define NSLDAPI_SELECT select
+#endif /* else _PR_THREADS */
+#else /* irix */
+#define NSLDAPI_POLL poll
+#define NSLDAPI_SELECT select
+#endif /* else irix */
+
+
+static LBER_SOCKET nsldapi_os_socket( LDAP *ld, int secure, int domain,
+ int type, int protocol );
+static int nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp );
+static int nsldapi_os_connect_with_to( LBER_SOCKET s, struct sockaddr *name,
+ int namelen, LDAP *ld);
+
+/*
+ * Function typedefs used by nsldapi_try_each_host()
+ */
+typedef LBER_SOCKET (NSLDAPI_SOCKET_FN)( LDAP *ld, int secure, int domain,
+ int type, int protocol );
+typedef int (NSLDAPI_IOCTL_FN)( LBER_SOCKET s, int option, int *statusp );
+typedef int (NSLDAPI_CONNECT_WITH_TO_FN )( LBER_SOCKET s, struct sockaddr *name,
+ int namelen, LDAP *ld);
+typedef int (NSLDAPI_CONNECT_FN )( LBER_SOCKET s, struct sockaddr *name,
+ int namelen );
+typedef int (NSLDAPI_CLOSE_FN )( LBER_SOCKET s );
+
+static int nsldapi_try_each_host( LDAP *ld, const char *hostlist, int defport,
+ int secure, NSLDAPI_SOCKET_FN *socketfn, NSLDAPI_IOCTL_FN *ioctlfn,
+ NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
+ NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn );
+
+
+static int
+nsldapi_os_closesocket( LBER_SOCKET s )
+{
+ int rc;
+
+#ifdef _WINDOWS
+ rc = closesocket( s );
+#else
+ rc = close( s );
+#endif
+ return( rc );
+}
+
+
+static LBER_SOCKET
+nsldapi_os_socket( LDAP *ld, int secure, int domain, int type, int protocol )
+{
+ int s, invalid_socket;
+ char *errmsg = NULL;
+
+ if ( secure ) {
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
+ nsldapi_strdup( dgettext(TEXT_DOMAIN,
+ "secure mode not supported") ));
+ return( -1 );
+ }
+
+ s = socket( domain, type, protocol );
+
+ /*
+ * if the socket() call failed or it returned a socket larger
+ * than we can deal with, return a "local error."
+ */
+ if ( NSLDAPI_INVALID_OS_SOCKET( s )) {
+ errmsg = dgettext(TEXT_DOMAIN, "unable to create a socket");
+ invalid_socket = 1;
+ } else { /* valid socket -- check for overflow */
+ invalid_socket = 0;
+#if !defined(NSLDAPI_HAVE_POLL) && !defined(_WINDOWS)
+ /* not on Windows and do not have poll() */
+ if ( s >= FD_SETSIZE ) {
+ errmsg = "can't use socket >= FD_SETSIZE";
+ }
+#endif
+ }
+
+ if ( errmsg != NULL ) { /* local socket error */
+ if ( !invalid_socket ) {
+ nsldapi_os_closesocket( s );
+ }
+ errmsg = nsldapi_strdup( errmsg );
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, errmsg );
+ return( -1 );
+ }
+
+ return( s );
+}
+
+
+
+/*
+ * Non-blocking connect call function
+ */
+static int
+nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
+ int salen, LDAP *ld)
+{
+#ifndef _WINDOWS
+ int flags;
+#endif /* _WINDOWS */
+ int n, error;
+ int len;
+ fd_set rset, wset;
+ struct timeval tval;
+#ifdef _WINDOWS
+ int nonblock = 1;
+ int block = 0;
+ fd_set eset;
+#endif /* _WINDOWS */
+ int msec = ld->ld_connect_timeout; /* milliseconds */
+ int continue_on_intr = 0;
+#ifdef _SOLARIS_SDK
+ hrtime_t start_time = 0, tmp_time, tv_time; /* nanoseconds */
+#else
+ long start_time = 0, tmp_time; /* seconds */
+#endif
+
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_nonblock timeout: %d (msec)\n",
+ msec, 0, 0);
+
+#ifdef _WINDOWS
+ ioctlsocket(sockfd, FIONBIO, &nonblock);
+#else
+ flags = fcntl(sockfd, F_GETFL, 0);
+ fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+#endif /* _WINDOWS */
+
+ error = 0;
+ if ((n = connect(sockfd, saptr, salen)) < 0)
+#ifdef _WINDOWS
+ if ((n != SOCKET_ERROR) && (WSAGetLastError() != WSAEWOULDBLOCK)) {
+#else
+ if (errno != EINPROGRESS) {
+#endif /* _WINDOWS */
+#ifdef LDAP_DEBUG
+ if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+ perror("connect");
+ }
+#endif
+ return (-1);
+ }
+
+ /* success */
+ if (n == 0)
+ goto done;
+
+ FD_ZERO(&rset);
+ FD_SET(sockfd, &rset);
+ wset = rset;
+
+#ifdef _WINDOWS
+ eset = rset;
+#endif /* _WINDOWS */
+
+ if (msec < 0 && msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "Invalid timeout value detected.."
+ "resetting connect timeout to default value "
+ "(LDAP_X_IO_TIMEOUT_NO_TIMEOUT\n", 0, 0, 0);
+ msec = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+ } else {
+ if (msec != 0) {
+ tval.tv_sec = msec / MILLISEC;
+ tval.tv_usec = (MICROSEC / MILLISEC) *
+ (msec % MILLISEC);
+#ifdef _SOLARIS_SDK
+ start_time = gethrtime();
+ tv_time = (hrtime_t)msec * (NANOSEC / MILLISEC);
+#else
+ start_time = (long)time(NULL);
+#endif
+ } else {
+ tval.tv_sec = 0;
+ tval.tv_usec = 0;
+ }
+ }
+
+ /* if timeval structure == NULL, select will block indefinitely */
+ /* != NULL, and value == 0, select will */
+ /* not block */
+ /* Windows is a bit quirky on how it behaves w.r.t nonblocking */
+ /* connects. If the connect fails, the exception fd, eset, is */
+ /* set to show the failure. The first argument in select is */
+ /* ignored */
+
+#ifdef _WINDOWS
+ if ((n = select(sockfd +1, &rset, &wset, &eset,
+ (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
+ errno = WSAETIMEDOUT;
+ return (-1);
+ }
+ /* if wset is set, the connect worked */
+ if (FD_ISSET(sockfd, &wset) || FD_ISSET(sockfd, &rset)) {
+ len = sizeof(error);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
+ < 0)
+ return (-1);
+ goto done;
+ }
+
+ /* if eset is set, the connect failed */
+ if (FD_ISSET(sockfd, &eset)) {
+ return (-1);
+ }
+
+ /* failure on select call */
+ if (n == SOCKET_ERROR) {
+ perror("select error: SOCKET_ERROR returned");
+ return (-1);
+ }
+#else
+ /*
+ * if LDAP_BITOPT_RESTART and select() is interrupted
+ * try again.
+ */
+ do {
+ continue_on_intr = 0;
+ if ((n = select(sockfd +1, &rset, &wset, NULL,
+ (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? \
+ &tval : NULL)) == 0) {
+ errno = ETIMEDOUT;
+ return (-1);
+ }
+ if (n < 0) {
+ if ((ld->ld_options & LDAP_BITOPT_RESTART) &&
+ (errno == EINTR)) {
+ continue_on_intr = 1;
+ errno = 0;
+ FD_ZERO(&rset);
+ FD_SET(sockfd, &rset);
+ wset = rset;
+ /* honour the timeout */
+ if ((msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) &&
+ (msec != 0)) {
+#ifdef _SOLARIS_SDK
+ tmp_time = gethrtime();
+ if ((tv_time -=
+ (tmp_time - start_time)) <= 0) {
+#else
+ tmp_time = (long)time(NULL);
+ if ((tval.tv_sec -=
+ (tmp_time - start_time)) <= 0) {
+#endif
+ /* timeout */
+ errno = ETIMEDOUT;
+ return (-1);
+ }
+#ifdef _SOLARIS_SDK
+ tval.tv_sec = tv_time / NANOSEC;
+ tval.tv_usec = (tv_time % NANOSEC) /
+ (NANOSEC / MICROSEC);
+#endif
+ start_time = tmp_time;
+ }
+ } else {
+#ifdef LDAP_DEBUG
+ perror("select error: ");
+#endif
+ return (-1);
+ }
+ }
+ } while (continue_on_intr == 1);
+
+ if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
+ len = sizeof(error);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
+ < 0)
+ return (-1);
+#ifdef LDAP_DEBUG
+ } else if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+ perror("select error: sockfd not set");
+#endif
+ }
+#endif /* _WINDOWS */
+
+done:
+#ifdef _WINDOWS
+ ioctlsocket(sockfd, FIONBIO, &block);
+#else
+ fcntl(sockfd, F_SETFL, flags);
+#endif /* _WINDOWS */
+
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+static int
+nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp )
+{
+ int err;
+#ifdef _WINDOWS
+ u_long iostatus;
+#endif
+
+ if ( FIONBIO != option ) {
+ return( -1 );
+ }
+
+#ifdef _WINDOWS
+ iostatus = *(u_long *)statusp;
+ err = ioctlsocket( s, FIONBIO, &iostatus );
+#else
+ err = ioctl( s, FIONBIO, (caddr_t)statusp );
+#endif
+
+ return( err );
+}
+
+
+int
+nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *hostlist,
+ int defport, int secure, char **krbinstancep )
+/*
+ * "defport" must be in host byte order
+ * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
+ * if -1 is returned, ld_errno is set
+ */
+{
+ int s;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_to_host: %s, port: %d\n",
+ NULL == hostlist ? "NULL" : hostlist, defport, 0 );
+
+ /*
+ * If an extended I/O connect callback has been defined, just use it.
+ */
+ if ( NULL != ld->ld_extconnect_fn ) {
+ unsigned long connect_opts = 0;
+
+ if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
+ connect_opts |= LDAP_X_EXTIOF_OPT_NONBLOCKING;
+ }
+ if ( secure ) {
+ connect_opts |= LDAP_X_EXTIOF_OPT_SECURE;
+ }
+ s = ld->ld_extconnect_fn( hostlist, defport,
+ ld->ld_connect_timeout, connect_opts,
+ ld->ld_ext_session_arg,
+ &sb->sb_ext_io_fns.lbextiofn_socket_arg
+#ifdef _SOLARIS_SDK
+ , NULL );
+#else
+ );
+#endif /* _SOLARIS_SDK */
+
+ } else {
+ s = nsldapi_try_each_host( ld, hostlist,
+ defport, secure, nsldapi_os_socket,
+ nsldapi_os_ioctl, nsldapi_os_connect_with_to,
+ NULL, nsldapi_os_closesocket );
+ }
+
+ if ( s < 0 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
+ return( -1 );
+ }
+
+ sb->sb_sd = s;
+
+ /*
+ * Set krbinstancep (canonical name of host for use by Kerberos).
+ */
+#ifdef KERBEROS
+ char *p;
+
+ if (( *krbinstancep = nsldapi_host_connected_to( sb )) != NULL
+ && ( p = strchr( *krbinstancep, '.' )) != NULL ) {
+ *p = '\0';
+ }
+#else /* KERBEROS */
+ *krbinstancep = NULL;
+#endif /* KERBEROS */
+
+ return( 0 );
+}
+
+
+/*
+ * Returns a socket number if successful and -1 if an error occurs.
+ */
+static int
+nsldapi_try_each_host( LDAP *ld, const char *hostlist,
+ int defport, int secure, NSLDAPI_SOCKET_FN *socketfn,
+ NSLDAPI_IOCTL_FN *ioctlfn, NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
+ NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn )
+{
+ int rc, i, s, err, connected, use_hp;
+ int parse_err, port;
+ struct sockaddr_in sin;
+ nsldapi_in_addr_t address;
+ char **addrlist, *ldhpbuf, *ldhpbuf_allocd;
+ char *host;
+ LDAPHostEnt ldhent, *ldhp;
+ struct hostent *hp;
+ struct ldap_x_hostlist_status *status;
+#ifdef GETHOSTBYNAME_BUF_T
+ GETHOSTBYNAME_BUF_T hbuf;
+ struct hostent hent;
+#endif /* GETHOSTBYNAME_BUF_T */
+
+ connected = 0;
+ parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
+ &status );
+ while ( !connected && LDAP_SUCCESS == parse_err && host != NULL ) {
+ ldhpbuf_allocd = NULL;
+ ldhp = NULL;
+ hp = NULL;
+ s = 0;
+ use_hp = 0;
+ addrlist = NULL;
+
+
+ if (( address = inet_addr( host )) == -1 ) {
+ if ( ld->ld_dns_gethostbyname_fn == NULL ) {
+ if (( hp = GETHOSTBYNAME( host, &hent, hbuf,
+ sizeof(hbuf), &err )) != NULL ) {
+ addrlist = hp->h_addr_list;
+ }
+ } else {
+ /*
+ * DNS callback installed... use it.
+ */
+#ifdef GETHOSTBYNAME_buf_t
+ /* avoid allocation by using hbuf if large enough */
+ if ( sizeof( hbuf ) < ld->ld_dns_bufsize ) {
+ ldhpbuf = ldhpbuf_allocd
+ = NSLDAPI_MALLOC( ld->ld_dns_bufsize );
+ } else {
+ ldhpbuf = (char *)hbuf;
+ }
+#else /* GETHOSTBYNAME_buf_t */
+ ldhpbuf = ldhpbuf_allocd = NSLDAPI_MALLOC(
+ ld->ld_dns_bufsize );
+#endif /* else GETHOSTBYNAME_buf_t */
+
+ if ( ldhpbuf == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY,
+ NULL, NULL );
+ ldap_memfree( host );
+ ldap_x_hostlist_statusfree( status );
+ return( -1 );
+ }
+
+ if (( ldhp = ld->ld_dns_gethostbyname_fn( host,
+ &ldhent, ldhpbuf, ld->ld_dns_bufsize, &err,
+ ld->ld_dns_extradata )) != NULL ) {
+ addrlist = ldhp->ldaphe_addr_list;
+ }
+ }
+
+ if ( addrlist == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
+ LDAP_SET_ERRNO( ld, EHOSTUNREACH ); /* close enough */
+ if ( ldhpbuf_allocd != NULL ) {
+ NSLDAPI_FREE( ldhpbuf_allocd );
+ }
+ ldap_memfree( host );
+ ldap_x_hostlist_statusfree( status );
+ return( -1 );
+ }
+ use_hp = 1;
+ }
+
+ rc = -1;
+ for ( i = 0; !use_hp || ( addrlist[ i ] != 0 ); i++ ) {
+ if ( -1 == ( s = (*socketfn)( ld, secure, AF_INET,
+ SOCK_STREAM, 0 ))) {
+ if ( ldhpbuf_allocd != NULL ) {
+ NSLDAPI_FREE( ldhpbuf_allocd );
+ }
+ ldap_memfree( host );
+ ldap_x_hostlist_statusfree( status );
+ return( -1 );
+ }
+
+ if ( ld->ld_options & LDAP_BITOPT_ASYNC ) {
+ int iostatus = 1;
+
+ err = (*ioctlfn)( s, FIONBIO, &iostatus );
+ if ( err == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "FIONBIO ioctl failed on %d\n",
+ s, 0, 0 );
+ }
+ }
+
+ (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons( (unsigned short)port );
+
+ SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
+ ( use_hp ? (char *) addrlist[ i ] :
+ (char *) &address ), sizeof( sin.sin_addr.s_addr) );
+
+ {
+#ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
+/*
+ * Block all of the signals that might interrupt connect() since there
+ * is an OS bug that causes connect() to fail if it is restarted. Look in
+ * ns/netsite/ldap/include/portable.h for the definition of
+ * LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
+ */
+ sigset_t ints_off, oldset;
+
+ sigemptyset( &ints_off );
+ sigaddset( &ints_off, SIGALRM );
+ sigaddset( &ints_off, SIGIO );
+ sigaddset( &ints_off, SIGCLD );
+
+ sigprocmask( SIG_BLOCK, &ints_off, &oldset );
+#endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
+
+ if ( NULL != connectwithtofn ) {
+ err = (*connectwithtofn)(s,
+ (struct sockaddr *)&sin,
+ sizeof(struct sockaddr_in),
+ ld);
+ } else {
+ err = (*connectfn)(s,
+ (struct sockaddr *)&sin,
+ sizeof(struct sockaddr_in));
+ }
+#ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
+/*
+ * restore original signal mask
+ */
+ sigprocmask( SIG_SETMASK, &oldset, 0 );
+#endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
+
+ }
+ if ( err >= 0 ) {
+ connected = 1;
+ rc = 0;
+ break;
+ } else {
+ if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
+#ifdef _WINDOWS
+ if (err == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
+ LDAP_SET_ERRNO( ld, EWOULDBLOCK );
+#endif /* _WINDOWS */
+ err = LDAP_GET_ERRNO( ld );
+ if ( NSLDAPI_ERRNO_IO_INPROGRESS( err )) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "connect would block...\n",
+ 0, 0, 0 );
+ rc = -2;
+ break;
+ }
+ }
+
+#ifdef LDAP_DEBUG
+ if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+ perror( (char *)inet_ntoa( sin.sin_addr ));
+ }
+#endif
+ (*closefn)( s );
+ if ( !use_hp ) {
+ break;
+ }
+ }
+ }
+
+ ldap_memfree( host );
+ parse_err = ldap_x_hostlist_next( &host, &port, status );
+ }
+
+ if ( ldhpbuf_allocd != NULL ) {
+ NSLDAPI_FREE( ldhpbuf_allocd );
+ }
+ ldap_memfree( host );
+ ldap_x_hostlist_statusfree( status );
+
+ if ( connected ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
+ s, inet_ntoa( sin.sin_addr ), 0 );
+ }
+
+ return( rc == 0 ? s : -1 );
+}
+
+
+void
+nsldapi_close_connection( LDAP *ld, Sockbuf *sb )
+{
+ if ( ld->ld_extclose_fn == NULL ) {
+ nsldapi_os_closesocket( sb->sb_sd );
+ } else {
+ ld->ld_extclose_fn( sb->sb_sd,
+ sb->sb_ext_io_fns.lbextiofn_socket_arg );
+ }
+}
+
+
+#ifdef KERBEROS
+char *
+nsldapi_host_connected_to( Sockbuf *sb )
+{
+ struct hostent *hp;
+ char *p;
+ int len;
+ struct sockaddr_in sin;
+
+ (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+ len = sizeof( sin );
+ if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
+ return( NULL );
+ }
+
+ /*
+ * do a reverse lookup on the addr to get the official hostname.
+ * this is necessary for kerberos to work right, since the official
+ * hostname is used as the kerberos instance.
+ */
+#error XXXmcs: need to use DNS callbacks here
+ if (( hp = gethostbyaddr((char *) &sin.sin_addr,
+ sizeof( sin.sin_addr ), AF_INET)) != NULL ) {
+ if ( hp->h_name != NULL ) {
+ return( nsldapi_strdup( hp->h_name ));
+ }
+ }
+
+ return( NULL );
+}
+#endif /* KERBEROS */
+
+
+/*
+ * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
+ * Also allocates initializes ld->ld_iostatus if needed..
+ */
+int
+nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
+{
+ NSLDAPIIOStatus *iosp;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+
+ if ( ld->ld_iostatus == NULL
+ && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+ return( -1 );
+ }
+
+ iosp = ld->ld_iostatus;
+
+ if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+ if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo, POLLOUT )) {
+ ++iosp->ios_write_count;
+ }
+#else /* NSLDAPI_HAVE_POLL */
+ if ( !FD_ISSET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_writefds )) {
+ FD_SET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_writefds );
+ ++iosp->ios_write_count;
+ }
+#endif /* else NSLDAPI_HAVE_POLL */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+ if ( nsldapi_add_to_cb_pollfds( sb,
+ &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
+ ++iosp->ios_write_count;
+ }
+
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_interest_write: unknown I/O type %d\n",
+ iosp->ios_type, 0, 0 );
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+
+ return( 0 );
+}
+
+
+/*
+ * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
+ * Also allocates initializes ld->ld_iostatus if needed..
+ */
+int
+nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
+{
+ NSLDAPIIOStatus *iosp;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+
+ if ( ld->ld_iostatus == NULL
+ && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+ return( -1 );
+ }
+
+ iosp = ld->ld_iostatus;
+
+ if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+ if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo, POLLIN )) {
+ ++iosp->ios_read_count;
+ }
+#else /* NSLDAPI_HAVE_POLL */
+ if ( !FD_ISSET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_readfds )) {
+ FD_SET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_readfds );
+ ++iosp->ios_read_count;
+ }
+#endif /* else NSLDAPI_HAVE_POLL */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+ if ( nsldapi_add_to_cb_pollfds( sb,
+ &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
+ ++iosp->ios_read_count;
+ }
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_interest_read: unknown I/O type %d\n",
+ iosp->ios_type, 0, 0 );
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+
+ return( 0 );
+}
+
+
+/*
+ * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
+ * Also allocates initializes ld->ld_iostatus if needed..
+ */
+int
+nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
+{
+ NSLDAPIIOStatus *iosp;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+
+ if ( ld->ld_iostatus == NULL
+ && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+ return( -1 );
+ }
+
+ iosp = ld->ld_iostatus;
+
+ if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+ if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo, POLLOUT )) {
+ --iosp->ios_write_count;
+ }
+ if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo, POLLIN )) {
+ --iosp->ios_read_count;
+ }
+#else /* NSLDAPI_HAVE_POLL */
+ if ( FD_ISSET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_writefds )) {
+ FD_CLR( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_writefds );
+ --iosp->ios_write_count;
+ }
+ if ( FD_ISSET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_readfds )) {
+ FD_CLR( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_readfds );
+ --iosp->ios_read_count;
+ }
+#endif /* else NSLDAPI_HAVE_POLL */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+ if ( nsldapi_clear_from_cb_pollfds( sb,
+ &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
+ --iosp->ios_write_count;
+ }
+ if ( nsldapi_clear_from_cb_pollfds( sb,
+ &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
+ --iosp->ios_read_count;
+ }
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_interest_clear: unknown I/O type %d\n",
+ iosp->ios_type, 0, 0 );
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+
+ return( 0 );
+}
+
+
+/*
+ * Return a non-zero value if sb is ready for write.
+ */
+int
+nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
+{
+ int rc;
+ NSLDAPIIOStatus *iosp;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+ iosp = ld->ld_iostatus;
+
+ if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+ /*
+ * if we are using poll() we do something a little tricky: if
+ * any bits in the socket's returned events field other than
+ * POLLIN (ready for read) are set, we return true. This
+ * is done so we notice when a server closes a connection
+ * or when another error occurs. The actual error will be
+ * noticed later when we call write() or send().
+ */
+ rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo, ~POLLIN );
+
+#else /* NSLDAPI_HAVE_POLL */
+ rc = FD_ISSET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_use_writefds );
+#endif /* else NSLDAPI_HAVE_POLL */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+ rc = nsldapi_find_in_cb_pollfds( sb,
+ &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLIN );
+
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_is_write_ready: unknown I/O type %d\n",
+ iosp->ios_type, 0, 0 );
+ rc = 0;
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+ return( rc );
+}
+
+
+/*
+ * Return a non-zero value if sb is ready for read.
+ */
+int
+nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
+{
+ int rc;
+ NSLDAPIIOStatus *iosp;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+ iosp = ld->ld_iostatus;
+
+ if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+ /*
+ * if we are using poll() we do something a little tricky: if
+ * any bits in the socket's returned events field other than
+ * POLLOUT (ready for write) are set, we return true. This
+ * is done so we notice when a server closes a connection
+ * or when another error occurs. The actual error will be
+ * noticed later when we call read() or recv().
+ */
+ rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo, ~POLLOUT );
+
+#else /* NSLDAPI_HAVE_POLL */
+ rc = FD_ISSET( sb->sb_sd,
+ &iosp->ios_status.ios_osinfo.ossi_use_readfds );
+#endif /* else NSLDAPI_HAVE_POLL */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+ rc = nsldapi_find_in_cb_pollfds( sb,
+ &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLOUT );
+
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_is_read_ready: unknown I/O type %d\n",
+ iosp->ios_type, 0, 0 );
+ rc = 0;
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+ return( rc );
+}
+
+
+/*
+ * Allocated and initialize ld->ld_iostatus if not already done.
+ * Should be called with LDAP_IOSTATUS_LOCK locked.
+ * Returns 0 if all goes well and -1 if not (sets error in ld)
+ */
+static int
+nsldapi_iostatus_init_nolock( LDAP *ld )
+{
+ NSLDAPIIOStatus *iosp;
+
+ if ( ld->ld_iostatus != NULL ) {
+ return( 0 );
+ }
+
+ if (( iosp = (NSLDAPIIOStatus *)NSLDAPI_CALLOC( 1,
+ sizeof( NSLDAPIIOStatus ))) == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+
+ if ( ld->ld_extpoll_fn == NULL ) {
+ iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_OSNATIVE;
+#ifndef NSLDAPI_HAVE_POLL
+ FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_readfds );
+ FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_writefds );
+#endif /* !NSLDAPI_HAVE_POLL */
+
+ } else {
+ iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_CALLBACK;
+ }
+
+ ld->ld_iostatus = iosp;
+ return( 0 );
+}
+
+
+void
+nsldapi_iostatus_free( LDAP *ld )
+{
+ if ( ld == NULL ) {
+ return;
+ }
+
+
+ /* clean up classic I/O compatibility glue */
+ if ( ld->ld_io_fns_ptr != NULL ) {
+ if ( ld->ld_ext_session_arg != NULL ) {
+ NSLDAPI_FREE( ld->ld_ext_session_arg );
+ }
+ NSLDAPI_FREE( ld->ld_io_fns_ptr );
+ }
+
+ /* clean up I/O status tracking info. */
+ if ( ld->ld_iostatus != NULL ) {
+ NSLDAPIIOStatus *iosp = ld->ld_iostatus;
+
+ if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+ if ( iosp->ios_status.ios_osinfo.ossi_pollfds
+ != NULL ) {
+ NSLDAPI_FREE(
+ iosp->ios_status.ios_osinfo.ossi_pollfds );
+ }
+#endif /* NSLDAPI_HAVE_POLL */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+ if ( iosp->ios_status.ios_cbinfo.cbsi_pollfds
+ != NULL ) {
+ NSLDAPI_FREE(
+ iosp->ios_status.ios_cbinfo.cbsi_pollfds );
+ }
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_free: unknown I/O type %d\n",
+ iosp->ios_type, 0, 0 );
+ }
+
+ NSLDAPI_FREE( iosp );
+ }
+}
+
+
+static int
+nsldapi_get_select_table_size( void )
+{
+ static int tblsize = 0; /* static */
+
+ if ( tblsize == 0 ) {
+#if defined(_WINDOWS) || defined(XP_OS2)
+ tblsize = FOPEN_MAX; /* ANSI spec. */
+#else
+#ifdef USE_SYSCONF
+ tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+ tblsize = getdtablesize();
+#endif /* else USE_SYSCONF */
+#endif /* else _WINDOWS */
+
+ if ( tblsize >= FD_SETSIZE ) {
+ /*
+ * clamp value so we don't overrun the fd_set structure
+ */
+ tblsize = FD_SETSIZE - 1;
+ }
+ }
+
+ return( tblsize );
+}
+
+static int
+nsldapi_tv2ms( struct timeval *tv )
+{
+ if ( tv == NULL ) {
+ return( -1 ); /* infinite timout for poll() */
+ }
+
+ return( tv->tv_sec * 1000 + tv->tv_usec / 1000 );
+}
+
+
+int
+nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout )
+{
+ int rc;
+ NSLDAPIIOStatus *iosp;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_iostatus_poll\n", 0, 0, 0 );
+
+ LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+ iosp = ld->ld_iostatus;
+
+ if ( iosp == NULL ||
+ ( iosp->ios_read_count <= 0 && iosp->ios_read_count <= 0 )) {
+ rc = 0; /* simulate a timeout */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+
+ rc = NSLDAPI_POLL( iosp->ios_status.ios_osinfo.ossi_pollfds,
+ iosp->ios_status.ios_osinfo.ossi_pollfds_size,
+ nsldapi_tv2ms( timeout ));
+
+#else /* NSLDAPI_HAVE_POLL */
+
+ /* two (potentially large) struct copies */
+ iosp->ios_status.ios_osinfo.ossi_use_readfds
+ = iosp->ios_status.ios_osinfo.ossi_readfds;
+ iosp->ios_status.ios_osinfo.ossi_use_writefds
+ = iosp->ios_status.ios_osinfo.ossi_writefds;
+
+#ifdef HPUX9
+ rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
+ (int *)&iosp->ios_status.ios_osinfo.ossi_use_readfds
+ (int *)&iosp->ios_status.ios_osinfo.ossi_use_writefds,
+ NULL, timeout );
+#else
+ rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
+ &iosp->ios_status.ios_osinfo.ossi_use_readfds,
+ &iosp->ios_status.ios_osinfo.ossi_use_writefds,
+ NULL, timeout );
+#endif /* else HPUX9 */
+#endif /* else NSLDAPI_HAVE_POLL */
+
+ } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+ /*
+ * We always pass the session extended I/O argument to
+ * the extended poll() callback.
+ */
+ rc = ld->ld_extpoll_fn(
+ iosp->ios_status.ios_cbinfo.cbsi_pollfds,
+ iosp->ios_status.ios_cbinfo.cbsi_pollfds_size,
+ nsldapi_tv2ms( timeout ), ld->ld_ext_session_arg );
+
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_poll: unknown I/O type %d\n",
+ iosp->ios_type, 0, 0 );
+ rc = 0; /* simulate a timeout (what else to do?) */
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+ return( rc );
+}
+
+
+#ifdef NSLDAPI_HAVE_POLL
+/*
+ * returns 1 if "fd" was added to pollfds.
+ * returns 1 if some of the bits in "events" were added to pollfds.
+ * returns 0 if no changes were made.
+ */
+static int
+nsldapi_add_to_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
+ short events )
+{
+ int i, openslot;
+
+ /* first we check to see if "fd" is already in our pollfds */
+ openslot = -1;
+ for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
+ if ( pip->ossi_pollfds[ i ].fd == fd ) {
+ if (( pip->ossi_pollfds[ i ].events & events )
+ != events ) {
+ pip->ossi_pollfds[ i ].events |= events;
+ return( 1 );
+ } else {
+ return( 0 );
+ }
+ }
+ if ( pip->ossi_pollfds[ i ].fd == -1 && openslot == -1 ) {
+ openslot = i; /* remember for later */
+ }
+ }
+
+ /*
+ * "fd" is not currently being poll'd on -- add to array.
+ * if we need to expand the pollfds array, we do it in increments of
+ * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
+ */
+ if ( openslot == -1 ) {
+ struct pollfd *newpollfds;
+
+ if ( pip->ossi_pollfds_size == 0 ) {
+ newpollfds = (struct pollfd *)NSLDAPI_MALLOC(
+ NSLDAPI_POLL_ARRAY_GROWTH
+ * sizeof( struct pollfd ));
+ } else {
+ newpollfds = (struct pollfd *)NSLDAPI_REALLOC(
+ pip->ossi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
+ + pip->ossi_pollfds_size)
+ * sizeof( struct pollfd ));
+ }
+ if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
+ return( 0 );
+ }
+ pip->ossi_pollfds = newpollfds;
+ openslot = pip->ossi_pollfds_size;
+ pip->ossi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
+ for ( i = openslot + 1; i < pip->ossi_pollfds_size; ++i ) {
+ pip->ossi_pollfds[ i ].fd = -1;
+ pip->ossi_pollfds[ i ].events =
+ pip->ossi_pollfds[ i ].revents = 0;
+ }
+ }
+ pip->ossi_pollfds[ openslot ].fd = fd;
+ pip->ossi_pollfds[ openslot ].events = events;
+ pip->ossi_pollfds[ openslot ].revents = 0;
+ return( 1 );
+}
+
+
+/*
+ * returns 1 if any "events" from "fd" were removed from pollfds
+ * returns 0 of "fd" wasn't in pollfds or if events did not overlap.
+ */
+static int
+nsldapi_clear_from_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
+ short events )
+{
+ int i;
+
+ for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
+ if ( pip->ossi_pollfds[i].fd == fd ) {
+ if (( pip->ossi_pollfds[ i ].events & events ) != 0 ) {
+ pip->ossi_pollfds[ i ].events &= ~events;
+ if ( pip->ossi_pollfds[ i ].events == 0 ) {
+ pip->ossi_pollfds[i].fd = -1;
+ }
+ return( 1 ); /* events overlap */
+ } else {
+ return( 0 ); /* events do not overlap */
+ }
+ }
+ }
+
+ return( 0 ); /* "fd" was not found */
+}
+
+
+/*
+ * returns 1 if any "revents" from "fd" were set in pollfds revents field.
+ * returns 0 if not.
+ */
+static int
+nsldapi_find_in_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
+ short revents )
+{
+ int i;
+
+ for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
+ if ( pip->ossi_pollfds[i].fd == fd ) {
+ if (( pip->ossi_pollfds[ i ].revents & revents ) != 0 ) {
+ return( 1 ); /* revents overlap */
+ } else {
+ return( 0 ); /* revents do not overlap */
+ }
+ }
+ }
+
+ return( 0 ); /* "fd" was not found */
+}
+#endif /* NSLDAPI_HAVE_POLL */
+
+
+/*
+ * returns 1 if "sb" was added to pollfds.
+ * returns 1 if some of the bits in "events" were added to pollfds.
+ * returns 0 if no changes were made.
+ */
+static int
+nsldapi_add_to_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
+ short events )
+{
+ int i, openslot;
+
+ /* first we check to see if "sb" is already in our pollfds */
+ openslot = -1;
+ for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
+ if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
+ if (( pip->cbsi_pollfds[ i ].lpoll_events & events )
+ != events ) {
+ pip->cbsi_pollfds[ i ].lpoll_events |= events;
+ return( 1 );
+ } else {
+ return( 0 );
+ }
+ }
+ if ( pip->cbsi_pollfds[ i ].lpoll_fd == -1 && openslot == -1 ) {
+ openslot = i; /* remember for later */
+ }
+ }
+
+ /*
+ * "sb" is not currently being poll'd on -- add to array.
+ * if we need to expand the pollfds array, we do it in increments of
+ * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
+ */
+ if ( openslot == -1 ) {
+ LDAP_X_PollFD *newpollfds;
+
+ if ( pip->cbsi_pollfds_size == 0 ) {
+ newpollfds = (LDAP_X_PollFD *)NSLDAPI_MALLOC(
+ NSLDAPI_POLL_ARRAY_GROWTH
+ * sizeof( LDAP_X_PollFD ));
+ } else {
+ newpollfds = (LDAP_X_PollFD *)NSLDAPI_REALLOC(
+ pip->cbsi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
+ + pip->cbsi_pollfds_size)
+ * sizeof( LDAP_X_PollFD ));
+ }
+ if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
+ return( 0 );
+ }
+ pip->cbsi_pollfds = newpollfds;
+ openslot = pip->cbsi_pollfds_size;
+ pip->cbsi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
+ for ( i = openslot + 1; i < pip->cbsi_pollfds_size; ++i ) {
+ pip->cbsi_pollfds[ i ].lpoll_fd = -1;
+ pip->cbsi_pollfds[ i ].lpoll_socketarg = NULL;
+ pip->cbsi_pollfds[ i ].lpoll_events =
+ pip->cbsi_pollfds[ i ].lpoll_revents = 0;
+ }
+ }
+ pip->cbsi_pollfds[ openslot ].lpoll_fd = sb->sb_sd;
+ pip->cbsi_pollfds[ openslot ].lpoll_socketarg =
+ sb->sb_ext_io_fns.lbextiofn_socket_arg;
+ pip->cbsi_pollfds[ openslot ].lpoll_events = events;
+ pip->cbsi_pollfds[ openslot ].lpoll_revents = 0;
+ return( 1 );
+}
+
+
+/*
+ * returns 1 if any "events" from "sb" were removed from pollfds
+ * returns 0 of "sb" wasn't in pollfds or if events did not overlap.
+ */
+static int
+nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
+ struct nsldapi_cb_statusinfo *pip, short events )
+{
+ int i;
+
+ for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
+ if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
+ if (( pip->cbsi_pollfds[ i ].lpoll_events
+ & events ) != 0 ) {
+ pip->cbsi_pollfds[ i ].lpoll_events &= ~events;
+ if ( pip->cbsi_pollfds[ i ].lpoll_events
+ == 0 ) {
+ pip->cbsi_pollfds[i].lpoll_fd = -1;
+ }
+ return( 1 ); /* events overlap */
+ } else {
+ return( 0 ); /* events do not overlap */
+ }
+ }
+ }
+
+ return( 0 ); /* "sb" was not found */
+}
+
+
+/*
+ * returns 1 if any "revents" from "sb" were set in pollfds revents field.
+ * returns 0 if not.
+ */
+static int
+nsldapi_find_in_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
+ short revents )
+{
+ int i;
+
+ for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
+ if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
+ if (( pip->cbsi_pollfds[ i ].lpoll_revents
+ & revents ) != 0 ) {
+ return( 1 ); /* revents overlap */
+ } else {
+ return( 0 ); /* revents do not overlap */
+ }
+ }
+ }
+
+ return( 0 ); /* "sb" was not found */
+}
+
+
+/*
+ * Install read and write functions into lber layer / sb
+ */
+int
+nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb )
+{
+ struct lber_x_ext_io_fns lberiofns;
+
+ memset( &lberiofns, 0, sizeof(struct lber_x_ext_io_fns) );
+ if ( NULL != sb ) {
+ lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ lberiofns.lbextiofn_read = ld->ld_extread_fn;
+ lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
+ lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
+ lberiofns.lbextiofn_socket_arg = ld->ld_ext_session_arg;
+
+ if ( ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ &lberiofns ) != 0 ) {
+ return( LDAP_LOCAL_ERROR );
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ ******************************************************************************
+ * One struct and several functions to bridge the gap between new extended
+ * I/O functions that are installed using ldap_set_option( ...,
+ * LDAP_OPT_EXTIO_FN_PTRS, ... ) and the original "classic" I/O functions
+ * (installed using LDAP_OPT_IO_FN_PTRS) follow.
+ *
+ * Our basic strategy is to use the new extended arg to hold a pointer to a
+ * structure that contains a pointer to the LDAP * (which contains pointers
+ * to the old functions so we can call them) as well as a pointer to an
+ * LBER_SOCKET to hold the socket used by the classic functions (the new
+ * functions use a simple int for the socket).
+ */
+typedef struct nsldapi_compat_socket_info {
+ LBER_SOCKET csi_socket;
+ LDAP *csi_ld;
+} NSLDAPICompatSocketInfo;
+
+static int LDAP_CALLBACK
+nsldapi_ext_compat_read( int s, void *buf, int len,
+ struct lextiof_socket_private *arg )
+{
+ NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
+ struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
+
+ return( iofns->liof_read( csip->csi_socket, buf, len ));
+}
+
+
+static int LDAP_CALLBACK
+nsldapi_ext_compat_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *arg )
+{
+ NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
+ struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
+
+ return( iofns->liof_write( csip->csi_socket, buf, len ));
+}
+
+
+static int LDAP_CALLBACK
+nsldapi_ext_compat_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
+ struct lextiof_session_private *arg )
+{
+ NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
+ struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
+ fd_set readfds, writefds;
+ int i, rc, maxfd = 0;
+ struct timeval tv, *tvp;
+
+ /*
+ * Prepare fd_sets for select()
+ */
+ FD_ZERO( &readfds );
+ FD_ZERO( &writefds );
+ for ( i = 0; i < nfds; ++i ) {
+ if ( fds[ i ].lpoll_fd < 0 ) {
+ continue;
+ }
+
+ if ( fds[ i ].lpoll_fd >= FD_SETSIZE ) {
+ LDAP_SET_ERRNO( csip->csi_ld, EINVAL );
+ return( -1 );
+ }
+
+ if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )) {
+ FD_SET( fds[i].lpoll_fd, &readfds );
+ }
+
+ if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )) {
+ FD_SET( fds[i].lpoll_fd, &writefds );
+ }
+
+ fds[i].lpoll_revents = 0; /* clear revents */
+
+ if ( fds[i].lpoll_fd >= maxfd ) {
+ maxfd = fds[i].lpoll_fd;
+ }
+ }
+
+ /*
+ * select() using callback.
+ */
+ ++maxfd;
+ if ( timeout == -1 ) {
+ tvp = NULL;
+ } else {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = 1000 * ( timeout - tv.tv_sec * 1000 );
+ tvp = &tv;
+ }
+ rc = iofns->liof_select( maxfd, &readfds, &writefds, NULL, tvp );
+ if ( rc <= 0 ) { /* timeout or fatal error */
+ return( rc );
+ }
+
+ /*
+ * Use info. in fd_sets to populate poll() revents.
+ */
+ for ( i = 0; i < nfds; ++i ) {
+ if ( fds[ i ].lpoll_fd < 0 ) {
+ continue;
+ }
+
+ if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )
+ && FD_ISSET( fds[i].lpoll_fd, &readfds )) {
+ fds[i].lpoll_revents |= LDAP_X_POLLIN;
+ }
+
+ if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )
+ && FD_ISSET( fds[i].lpoll_fd, &writefds )) {
+ fds[i].lpoll_revents |= LDAP_X_POLLOUT;
+ }
+
+ /* XXXmcs: any other cases to deal with? LDAP_X_POLLERR? */
+ }
+
+ return( rc );
+}
+
+
+static LBER_SOCKET
+nsldapi_compat_socket( LDAP *ld, int secure, int domain, int type,
+ int protocol )
+{
+ int s;
+
+ s = ld->ld_io_fns_ptr->liof_socket( domain, type, protocol );
+
+ if ( s >= 0 ) {
+ char *errmsg = NULL;
+
+#ifdef NSLDAPI_HAVE_POLL
+ if ( ld->ld_io_fns_ptr->liof_select != NULL
+ && s >= FD_SETSIZE ) {
+ errmsg = dgettext(TEXT_DOMAIN,
+ "can't use socket >= FD_SETSIZE");
+ }
+#elif !defined(_WINDOWS) /* not on Windows and do not have poll() */
+ if ( s >= FD_SETSIZE ) {
+ errmsg = "can't use socket >= FD_SETSIZE";
+ }
+#endif
+
+ if ( NULL == errmsg && secure &&
+ ld->ld_io_fns_ptr->liof_ssl_enable( s ) < 0 ) {
+ errmsg = dgettext(TEXT_DOMAIN,
+ "failed to enable secure mode");
+ }
+
+ if ( NULL != errmsg ) {
+ if ( NULL == ld->ld_io_fns_ptr->liof_close ) {
+ nsldapi_os_closesocket( s );
+ } else {
+ ld->ld_io_fns_ptr->liof_close( s );
+ }
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
+ nsldapi_strdup( errmsg ));
+ return( -1 );
+ }
+ }
+
+ return( s );
+}
+
+
+/*
+ * Note: timeout is ignored because we have no way to pass it via
+ * the old I/O callback interface.
+ */
+static int LDAP_CALLBACK
+nsldapi_ext_compat_connect( const char *hostlist, int defport, int timeout,
+ unsigned long options, struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp
+#ifdef _SOLARIS_SDK
+ , void **not_used )
+#else
+ )
+#endif /* _SOLARIS_SDK */
+{
+ NSLDAPICompatSocketInfo *defcsip;
+ struct ldap_io_fns *iofns;
+ int s, secure;
+ NSLDAPI_SOCKET_FN *socketfn;
+ NSLDAPI_IOCTL_FN *ioctlfn;
+ NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn;
+ NSLDAPI_CONNECT_FN *connectfn;
+ NSLDAPI_CLOSE_FN *closefn;
+
+ defcsip = (NSLDAPICompatSocketInfo *)sessionarg;
+ iofns = defcsip->csi_ld->ld_io_fns_ptr;
+
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
+ if ( NULL == iofns->liof_ssl_enable ) {
+ LDAP_SET_ERRNO( defcsip->csi_ld, EINVAL );
+ return( -1 );
+ }
+ secure = 1;
+ } else {
+ secure = 0;
+ }
+
+ socketfn = ( iofns->liof_socket == NULL ) ?
+ nsldapi_os_socket : nsldapi_compat_socket;
+ ioctlfn = ( iofns->liof_ioctl == NULL ) ?
+ nsldapi_os_ioctl : (NSLDAPI_IOCTL_FN *)(iofns->liof_ioctl);
+ if ( NULL == iofns->liof_connect ) {
+ connectwithtofn = nsldapi_os_connect_with_to;
+ connectfn = NULL;
+ } else {
+ connectwithtofn = NULL;
+ connectfn = iofns->liof_connect;
+ }
+ closefn = ( iofns->liof_close == NULL ) ?
+ nsldapi_os_closesocket : iofns->liof_close;
+
+ s = nsldapi_try_each_host( defcsip->csi_ld, hostlist, defport,
+ secure, socketfn, ioctlfn, connectwithtofn,
+ connectfn, closefn );
+
+ if ( s >= 0 ) {
+ NSLDAPICompatSocketInfo *csip;
+
+ if (( csip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
+ sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
+ (*closefn)( s );
+ LDAP_SET_LDERRNO( defcsip->csi_ld, LDAP_NO_MEMORY,
+ NULL, NULL );
+ return( -1 );
+ }
+
+ csip->csi_socket = s;
+ csip->csi_ld = defcsip->csi_ld;
+ *socketargp = (void *)csip;
+
+ /*
+ * We always return 1, which is a valid but not unique socket
+ * (file descriptor) number. The extended I/O functions only
+ * require that the combination of the void *arg and the int
+ * socket be unique. Since we allocate the
+ * NSLDAPICompatSocketInfo that we assign to arg, we meet
+ * that requirement.
+ */
+ s = 1;
+ }
+
+ return( s );
+}
+
+
+static int LDAP_CALLBACK
+nsldapi_ext_compat_close( int s, struct lextiof_socket_private *arg )
+{
+ NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
+ struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
+ int rc;
+
+ rc = iofns->liof_close( csip->csi_socket );
+
+ NSLDAPI_FREE( csip );
+
+ return( rc );
+}
+
+/*
+ * Install the I/O functions.
+ * Return an LDAP error code (LDAP_SUCCESS if all goes well).
+ */
+int
+nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns )
+{
+ NSLDAPICompatSocketInfo *defcsip;
+
+ if (( defcsip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
+ sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
+ return( LDAP_NO_MEMORY );
+ }
+
+ defcsip->csi_socket = -1;
+ defcsip->csi_ld = ld;
+
+ if ( ld->ld_io_fns_ptr != NULL ) {
+ (void)memset( (char *)ld->ld_io_fns_ptr, 0,
+ sizeof( struct ldap_io_fns ));
+ } else if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_CALLOC(
+ 1, sizeof( struct ldap_io_fns ))) == NULL ) {
+ NSLDAPI_FREE( defcsip );
+ return( LDAP_NO_MEMORY );
+ }
+
+ /* struct copy */
+ *(ld->ld_io_fns_ptr) = *iofns;
+
+ ld->ld_extio_size = LBER_X_EXTIO_FNS_SIZE;
+ ld->ld_ext_session_arg = defcsip;
+ ld->ld_extread_fn = nsldapi_ext_compat_read;
+ ld->ld_extwrite_fn = nsldapi_ext_compat_write;
+ ld->ld_extpoll_fn = nsldapi_ext_compat_poll;
+ ld->ld_extconnect_fn = nsldapi_ext_compat_connect;
+ ld->ld_extclose_fn = nsldapi_ext_compat_close;
+
+ return( nsldapi_install_lber_extiofns( ld, ld->ld_sbp ));
+}
+/*
+ * end of compat I/O functions
+ ******************************************************************************
+ */
+#ifdef _SOLARIS_SDK
+/*
+ * _ns_gethostbyaddr is a helper function for the ssl layer so that
+ * it can use the ldap layer's gethostbyaddr resolver.
+ */
+
+LDAPHostEnt *
+_ns_gethostbyaddr(LDAP *ld, const char *addr, int length, int type,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata)
+{
+ if (ld == NULL || ld->ld_dns_gethostbyaddr_fn == NULL)
+ return (NULL);
+ return (ld->ld_dns_gethostbyaddr_fn(addr, length, type,
+ result, buffer, buflen, statusp, extradata));
+}
+
+#endif /* _SOLARIS_SDK */
+
+
diff --git a/usr/src/lib/libldap5/sources/ldap/common/proxyauthctrl.c b/usr/src/lib/libldap5/sources/ldap/common/proxyauthctrl.c
new file mode 100644
index 0000000000..478111d0cd
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/proxyauthctrl.c
@@ -0,0 +1,151 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+#include "ldap-int.h"
+
+/* ldap_create_proxyauth_control
+
+ Create a "version 1" proxied authorization control.
+
+ Parameters are
+
+ ld LDAP pointer to the desired connection
+
+ dn The dn used in the proxy auth
+
+ ctl_iscritical Indicates whether the control is critical of not. If
+ this field is non-zero, the operation will only be car-
+ ried out if the control is recognized by the server
+ and/or client
+
+ ctrlp the address of a place to put the constructed control
+*/
+
+int
+LDAP_CALL
+ldap_create_proxyauth_control (
+ LDAP *ld,
+ const char *dn,
+ const char ctl_iscritical,
+ LDAPControl **ctrlp
+)
+{
+ BerElement *ber;
+ int rc;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ctrlp == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return ( LDAP_PARAM_ERROR );
+ }
+ if (NULL == dn)
+ {
+ dn = "";
+ }
+
+ /* create a ber package to hold the controlValue */
+ if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+
+
+
+ if ( LBER_ERROR == ber_printf( ber,
+ "{s}",
+ dn ) )
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ rc = nsldapi_build_control( LDAP_CONTROL_PROXYAUTH, ber, 1,
+ ctl_iscritical, ctrlp );
+
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+
+}
+
+
+/* ldap_create_proxiedauth_control
+
+ Create a "version 2" proxied authorization control.
+
+ Parameters are
+
+ ld LDAP pointer to the desired connection
+
+ authzid The authorization identity used in the proxy auth,
+ e.g., dn:uid=bjensen,dc=example,dc=com
+
+ ctrlp the address of a place to put the constructed control
+*/
+
+int
+LDAP_CALL
+ldap_create_proxiedauth_control (
+ LDAP *ld,
+ const char *authzid,
+ LDAPControl **ctrlp
+)
+{
+ BerElement *ber;
+ int rc;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ctrlp == NULL || authzid == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return ( LDAP_PARAM_ERROR );
+ }
+
+ /* create a ber package to hold the controlValue */
+ if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+
+
+
+ if ( LBER_ERROR == ber_printf( ber,
+ "s",
+ authzid ) )
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ rc = nsldapi_build_control( LDAP_CONTROL_PROXIEDAUTH, ber, 1, 1, ctrlp );
+
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/psearch.c b/usr/src/lib/libldap5/sources/ldap/common/psearch.c
new file mode 100644
index 0000000000..7d5b0d1067
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/psearch.c
@@ -0,0 +1,172 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+/*
+ * psearch.c - Persistent search and "Entry Change Notification" support.
+ */
+#include "ldap-int.h"
+
+
+int
+LDAP_CALL
+ldap_create_persistentsearch_control( LDAP *ld, int changetypes,
+ int changesonly, int return_echg_ctls, char ctl_iscritical,
+ LDAPControl **ctrlp )
+{
+ BerElement *ber;
+ int rc;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ctrlp == NULL || ( changetypes & ~LDAP_CHANGETYPE_ANY ) != 0 ) {
+ rc = LDAP_PARAM_ERROR;
+ goto report_error_and_return;
+ }
+
+ /*
+ * create a Persistent Search control. The control value looks like this:
+ *
+ * PersistentSearch ::= SEQUENCE {
+ * changeTypes INTEGER,
+ * -- the changeTypes field is the logical OR of
+ * -- one or more of these values: add (1), delete (2),
+ * -- modify (4), modDN (8). It specifies which types of
+ * -- changes will cause an entry to be returned.
+ * changesOnly BOOLEAN, -- skip initial search?
+ * returnECs BOOLEAN, -- return "Entry Change" controls?
+ * }
+ */
+ if (( nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) {
+ rc = LDAP_NO_MEMORY;
+ goto report_error_and_return;
+ }
+
+ if ( ber_printf( ber, "{ibb}", changetypes, changesonly,
+ return_echg_ctls ) == -1 ) {
+ ber_free( ber, 1 );
+ rc = LDAP_ENCODING_ERROR;
+ goto report_error_and_return;
+ }
+
+ rc = nsldapi_build_control( LDAP_CONTROL_PERSISTENTSEARCH, ber, 1,
+ ctl_iscritical, ctrlp );
+
+report_error_and_return:
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+}
+
+
+int
+LDAP_CALL
+ldap_parse_entrychange_control( LDAP *ld, LDAPControl **ctrls, int *chgtypep,
+ char **prevdnp, int *chgnumpresentp, ber_int_t *chgnump )
+{
+ BerElement *ber;
+ int rc, i, changetype;
+ ber_len_t len;
+ ber_int_t along;
+ char *previousdn;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /*
+ * find the entry change notification in the list of controls
+ */
+ for ( i = 0; ctrls != NULL && ctrls[i] != NULL; ++i ) {
+ if ( strcmp( ctrls[i]->ldctl_oid, LDAP_CONTROL_ENTRYCHANGE ) == 0 ) {
+ break;
+ }
+ }
+
+ if ( ctrls == NULL || ctrls[i] == NULL ) {
+ rc = LDAP_CONTROL_NOT_FOUND;
+ goto report_error_and_return;
+ }
+
+ /*
+ * allocate a BER element from the control value and parse it. The control
+ * value should look like this:
+ *
+ * EntryChangeNotification ::= SEQUENCE {
+ * changeType ENUMERATED {
+ * add (1), -- these values match the
+ * delete (2), -- values used for changeTypes
+ * modify (4), -- in the PersistentSearch control.
+ * modDN (8),
+ * },
+ * previousDN LDAPDN OPTIONAL, -- modDN ops. only
+ * changeNumber INTEGER OPTIONAL, -- if supported
+ * }
+ */
+ if (( ber = ber_init( &(ctrls[i]->ldctl_value))) == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto report_error_and_return;
+ }
+
+ if ( ber_scanf( ber, "{e", &along ) == LBER_ERROR ) {
+ ber_free( ber, 1 );
+ rc = LDAP_DECODING_ERROR;
+ goto report_error_and_return;
+ }
+ changetype = (int)along; /* XXX lossy cast */
+
+ if ( changetype == LDAP_CHANGETYPE_MODDN ) {
+ if ( ber_scanf( ber, "a", &previousdn ) == LBER_ERROR ) {
+ ber_free( ber, 1 );
+ rc = LDAP_DECODING_ERROR;
+ goto report_error_and_return;
+ }
+ } else {
+ previousdn = NULL;
+ }
+
+ if ( chgtypep != NULL ) {
+ *chgtypep = changetype;
+ }
+ if ( prevdnp != NULL ) {
+ *prevdnp = previousdn;
+ } else if ( previousdn != NULL ) {
+ NSLDAPI_FREE( previousdn );
+ }
+
+ if ( chgnump != NULL ) { /* check for optional changenumber */
+ if ( ber_peek_tag( ber, &len ) == LBER_INTEGER
+ && ber_get_int( ber, chgnump ) != LBER_ERROR ) {
+ if ( chgnumpresentp != NULL ) {
+ *chgnumpresentp = 1;
+ }
+ } else {
+ if ( chgnumpresentp != NULL ) {
+ *chgnumpresentp = 0;
+ }
+ }
+ }
+
+ ber_free( ber, 1 );
+ rc = LDAP_SUCCESS;
+
+report_error_and_return:
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/referral.c b/usr/src/lib/libldap5/sources/ldap/common/referral.c
new file mode 100644
index 0000000000..6d6973bb5f
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/referral.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * referral.c - routines for handling LDAPv3 referrals and references.
+ */
+
+#include "ldap-int.h"
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_first_reference( LDAP *ld, LDAPMessage *res )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || res == NULLMSG ) {
+ return( NULLMSG );
+ }
+
+ if ( res->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+ return( res );
+ }
+
+ return( ldap_next_reference( ld, res ));
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_next_reference( LDAP *ld, LDAPMessage *ref )
+{
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || ref == NULLMSG ) {
+ return( NULLMSG ); /* punt */
+ }
+
+ for ( ref = ref->lm_chain; ref != NULLMSG; ref = ref->lm_chain ) {
+ if ( ref->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+ return( ref );
+ }
+ }
+
+ return( NULLMSG );
+}
+
+
+int
+LDAP_CALL
+ldap_count_references( LDAP *ld, LDAPMessage *res )
+{
+ int i;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 );
+ }
+
+ for ( i = 0; res != NULL; res = res->lm_chain ) {
+ if ( res->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+ ++i;
+ }
+ }
+
+ return( i );
+}
+
+
+/*
+ * returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_parse_reference( LDAP *ld, LDAPMessage *ref, char ***referralsp,
+ LDAPControl ***serverctrlsp, int freeit )
+{
+ int err;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
+ !NSLDAPI_VALID_LDAPMESSAGE_REFERENCE_POINTER( ref )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ err = nsldapi_parse_reference( ld, ref->lm_ber, referralsp,
+ serverctrlsp );
+
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+
+ if ( freeit ) {
+ ldap_msgfree( ref );
+ }
+
+ return( err );
+}
+
+
+/*
+ * returns an LDAP error code indicating success or failure of parsing
+ * does NOT set any error information inside "ld"
+ */
+int
+nsldapi_parse_reference( LDAP *ld, BerElement *rber, char ***referralsp,
+ LDAPControl ***serverctrlsp )
+{
+ int err;
+ BerElement ber;
+ char **refs;
+
+ /*
+ * Parse a searchResultReference message. These are used in LDAPv3
+ * and beyond and look like this:
+ *
+ * SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+ *
+ * all wrapped up in an LDAPMessage sequence which looks like this:
+ *
+ * LDAPMessage ::= SEQUENCE {
+ * messageID MessageID,
+ * SearchResultReference
+ * controls [0] Controls OPTIONAL
+ * }
+ *
+ * ldap_result() pulls out the message id, so by the time a result
+ * message gets here we are conveniently sitting at the start of the
+ * SearchResultReference itself.
+ */
+ err = LDAP_SUCCESS; /* optimistic */
+ ber = *rber; /* struct copy */
+
+ if ( ber_scanf( &ber, "{v", &refs ) == LBER_ERROR ) {
+ err = LDAP_DECODING_ERROR;
+ } else if ( serverctrlsp != NULL ) {
+ /* pull out controls (if requested and any are present) */
+ if ( ber_scanf( &ber, "}" ) == LBER_ERROR ) {
+ err = LDAP_DECODING_ERROR;
+ } else {
+ err = nsldapi_get_controls( &ber, serverctrlsp );
+ }
+ }
+
+ if ( referralsp == NULL ) {
+ ldap_value_free( refs );
+ } else {
+ *referralsp = refs;
+ }
+
+ return( err );
+}
+
+#ifdef _SOLARIS_SDK
+
+char ** ldap_get_reference_urls(LDAP *ld, LDAPMessage *res)
+{
+ BerElement tmp;
+ char **urls = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_reference_urls\n", 0, 0, 0 );
+
+ if (res == NULL){
+ ld->ld_errno = LDAP_PARAM_ERROR;
+ return (NULL);
+ }
+ tmp = *res->lm_ber; /* struct copy */
+ if ( ber_scanf( &tmp, "{v}", &urls) == LBER_ERROR){
+ ld->ld_errno = LDAP_DECODING_ERROR;
+ return (NULL);
+ }
+ return (urls);
+}
+
+#endif /* _SOLARIS_SDK */
+
diff --git a/usr/src/lib/libldap5/sources/ldap/common/rename.c b/usr/src/lib/libldap5/sources/ldap/common/rename.c
new file mode 100644
index 0000000000..1328e7d3bc
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/rename.c
@@ -0,0 +1,252 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * rename.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_rename - initiate an ldap modifyDN operation. Parameters:
+ *
+ * ld LDAP descriptor
+ * dn DN of the object to modify
+ * newrdn RDN that will form leftmost component of entry's new name
+ * newparent if present, this is the Distinguished Name of the entry
+ * which becomes the immediate parent of the existing entry
+ * deleteoldrdn nonzero means to delete old rdn values from the entry
+ * while zero means to retain them as attributes of the entry
+ * serverctrls list of LDAP server controls
+ * clientctrls list of client controls
+ * msgidp this result parameter will be set to the message id of the
+ * request if the ldap_rename() call succeeds
+ *
+ * Example:
+ * int rc;
+ * rc = ldap_rename( ld, dn, newrdn, newparent, deleteoldrdn, serverctrls, clientctrls, &msgid );
+ */
+int
+LDAP_CALL
+ldap_rename(
+ LDAP *ld,
+ const char *dn,
+ const char *newrdn,
+ const char *newparent,
+ int deleteoldrdn,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls, /* not used for anything yet */
+ int *msgidp
+)
+{
+ BerElement *ber;
+ int rc, err;
+
+ /*
+ * A modify dn request looks like this:
+ * ModifyDNRequest ::= SEQUENCE {
+ * entry LDAPDN,
+ * newrdn RelativeLDAPDN,
+ * newparent [0] LDAPDN OPTIONAL,
+ * deleteoldrdn BOOLEAN
+ * }
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_rename\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+ if ( NULL == newrdn) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /* only ldapv3 or higher can do a proper rename
+ * (i.e. with non-NULL newparent and/or controls)
+ */
+
+ if (( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 )
+ && ((newparent != NULL) || (serverctrls != NULL)
+ || (clientctrls != NULL))) {
+ LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+ return( LDAP_NOT_SUPPORTED );
+ }
+
+ if ( msgidp == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ *msgidp = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ /* see if modRDN or modDN is handled by the cache */
+ if ( ld->ld_cache_on ) {
+ if ( newparent == NULL && ld->ld_cache_modrdn != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_modrdn)( ld, *msgidp,
+ LDAP_REQ_MODRDN, dn, newrdn, deleteoldrdn ))
+ != 0 ) {
+ *msgidp = rc;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+#if 0
+ } else if ( ld->ld_cache_rename != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_rename)( ld, *msgidp,
+ LDAP_REQ_MODDN, dn, newrdn, newparent,
+ deleteoldrdn )) != 0 ) {
+ *msgidp = rc;
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+#endif
+ }
+ }
+
+ /* create a message to send */
+ if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ /* fill it in */
+ if ( ber_printf( ber, "{it{ssb", *msgidp, LDAP_REQ_MODDN, dn,
+ newrdn, deleteoldrdn ) == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ if ( newparent == NULL ) {
+ if ( ber_printf( ber, "}" ) == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+ } else {
+ if ( ber_printf( ber, "ts}", LDAP_TAG_NEWSUPERIOR, newparent )
+ == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+ }
+
+ if (( rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( rc );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_MODDN,
+ (char *) dn, ber );
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_modrdn2( LDAP *ld, const char *dn, const char *newrdn, int deleteoldrdn )
+{
+ int msgid;
+
+ if ( ldap_rename( ld, dn, newrdn, NULL, deleteoldrdn, NULL, NULL, &msgid ) == LDAP_SUCCESS ) {
+ return( msgid );
+ } else {
+ return( -1 ); /* error is in ld handle */
+ }
+}
+
+int
+LDAP_CALL
+ldap_modrdn( LDAP *ld, const char *dn, const char *newrdn )
+{
+ return( ldap_modrdn2( ld, dn, newrdn, 1 ) );
+}
+
+int
+LDAP_CALL
+ldap_rename_s(
+ LDAP *ld,
+ const char *dn,
+ const char *newrdn,
+ const char *newparent,
+ int deleteoldrdn,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls /* not used for anything yet */
+)
+{
+ int msgid;
+ LDAPMessage *res;
+
+ if ( ldap_rename( ld, dn, newrdn, newparent, deleteoldrdn, serverctrls, clientctrls, &msgid ) != LDAP_SUCCESS ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ if ( msgid == -1 )
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+ return( ldap_result2error( ld, res, 1 ) );
+}
+
+int
+LDAP_CALL
+ldap_modrdn2_s( LDAP *ld, const char *dn, const char *newrdn, int deleteoldrdn )
+{
+ int msgid;
+ LDAPMessage *res;
+
+ if ( (msgid = ldap_modrdn2( ld, dn, newrdn, deleteoldrdn )) == -1 )
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+ return( ldap_result2error( ld, res, 1 ) );
+}
+
+int
+LDAP_CALL
+ldap_modrdn_s( LDAP *ld, const char *dn, const char *newrdn )
+{
+ return( ldap_modrdn2_s( ld, dn, newrdn, 1 ) );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/request.c b/usr/src/lib/libldap5/sources/ldap/common/request.c
new file mode 100644
index 0000000000..c931497ada
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/request.c
@@ -0,0 +1,1349 @@
+/*
+ * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * request.c - sending of ldap requests; handling of referrals
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static LDAPConn *find_connection( LDAP *ld, LDAPServer *srv, int any );
+static void use_connection( LDAP *ld, LDAPConn *lc );
+static void free_servers( LDAPServer *srvlist );
+static int chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq,
+ char *refurl, char *desc, int *unknownp );
+static int re_encode_request( LDAP *ld, BerElement *origber,
+ int msgid, LDAPURLDesc *ludp, BerElement **berp );
+
+#ifdef LDAP_DNS
+static LDAPServer *dn2servers( LDAP *ld, char *dn );
+#endif /* LDAP_DNS */
+
+
+/* returns an LDAP error code and also sets error inside LDAP * */
+int
+nsldapi_alloc_ber_with_options( LDAP *ld, BerElement **berp )
+{
+ int err;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+ if (( *berp = ber_alloc_t( ld->ld_lberoptions )) == NULLBER ) {
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ } else {
+ err = LDAP_SUCCESS;
+#ifdef STR_TRANSLATION
+ nsldapi_set_ber_options( ld, *berp );
+#endif /* STR_TRANSLATION */
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+
+ return( err );
+}
+
+
+void
+nsldapi_set_ber_options( LDAP *ld, BerElement *ber )
+{
+ ber->ber_options = ld->ld_lberoptions;
+#ifdef STR_TRANSLATION
+ if (( ld->ld_lberoptions & LBER_OPT_TRANSLATE_STRINGS ) != 0 ) {
+ ber_set_string_translators( ber,
+ ld->ld_lber_encode_translate_proc,
+ ld->ld_lber_decode_translate_proc );
+ }
+#endif /* STR_TRANSLATION */
+}
+
+
+/* returns the message id of the request or -1 if an error occurs */
+int
+nsldapi_send_initial_request( LDAP *ld, int msgid, unsigned long msgtype,
+ char *dn, BerElement *ber )
+{
+ LDAPServer *servers;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_initial_request\n", 0,0,0 );
+
+#ifdef LDAP_DNS
+ LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+ if (( ld->ld_options & LDAP_BITOPT_DNS ) != 0 && ldap_is_dns_dn( dn )) {
+ if (( servers = dn2servers( ld, dn )) == NULL ) {
+ ber_free( ber, 1 );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+ return( -1 );
+ }
+
+#ifdef LDAP_DEBUG
+ if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+ LDAPServer *srv;
+ char msg[256];
+
+ for ( srv = servers; srv != NULL;
+ srv = srv->lsrv_next ) {
+ sprintf( msg,
+ "LDAP server %s: dn %s, port %d\n",
+ srv->lsrv_host, ( srv->lsrv_dn == NULL ) ?
+ "(default)" : srv->lsrv_dn,
+ srv->lsrv_port );
+ ber_err_print( msg );
+ }
+ }
+#endif /* LDAP_DEBUG */
+ } else {
+#endif /* LDAP_DNS */
+ /*
+ * use of DNS is turned off or this is an LDAP DN...
+ * use our default connection
+ */
+ servers = NULL;
+#ifdef LDAP_DNS
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+#endif /* LDAP_DNS */
+
+ return( nsldapi_send_server_request( ld, ber, msgid, NULL,
+ servers, NULL, ( msgtype == LDAP_REQ_BIND ) ? dn : NULL, 0 ));
+}
+
+
+/* returns the message id of the request or -1 if an error occurs */
+int
+nsldapi_send_server_request(
+ LDAP *ld, /* session handle */
+ BerElement *ber, /* message to send */
+ int msgid, /* ID of message to send */
+ LDAPRequest *parentreq, /* non-NULL for referred requests */
+ LDAPServer *srvlist, /* servers to connect to (NULL for default) */
+ LDAPConn *lc, /* connection to use (NULL for default) */
+ char *bindreqdn, /* non-NULL for bind requests */
+ int bind /* perform a bind after opening new conn.? */
+)
+{
+ LDAPRequest *lr;
+ int err;
+ int incparent; /* did we bump parent's ref count? */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_server_request\n", 0, 0, 0 );
+
+ incparent = 0;
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ if ( lc == NULL ) {
+ if ( srvlist == NULL ) {
+ if ( ld->ld_defconn == NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+ if ( bindreqdn == NULL && ( ld->ld_options
+ & LDAP_BITOPT_RECONNECT ) != 0 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
+ NULL, NULL );
+ ber_free( ber, 1 );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ return( -1 );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+
+ if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
+ ber_free( ber, 1 );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ return( -1 );
+ }
+ }
+ lc = ld->ld_defconn;
+ } else {
+ if (( lc = find_connection( ld, srvlist, 1 )) ==
+ NULL ) {
+ if ( bind && (parentreq != NULL) ) {
+ /* Remember the bind in the parent */
+ incparent = 1;
+ ++parentreq->lr_outrefcnt;
+ }
+
+ lc = nsldapi_new_connection( ld, &srvlist, 0,
+ 1, bind );
+ }
+ free_servers( srvlist );
+ }
+ }
+
+
+ /*
+ * the logic here is:
+ * if
+ * 1. no connections exists,
+ * or
+ * 2. if the connection is either not in the connected
+ * or connecting state in an async io model
+ * or
+ * 3. the connection is notin a connected state with normal (non async io)
+ */
+ if ( lc == NULL
+ || ( (ld->ld_options & LDAP_BITOPT_ASYNC
+ && lc->lconn_status != LDAP_CONNST_CONNECTING
+ && lc->lconn_status != LDAP_CONNST_CONNECTED)
+ || (!(ld->ld_options & LDAP_BITOPT_ASYNC )
+ && lc->lconn_status != LDAP_CONNST_CONNECTED) ) ) {
+
+ ber_free( ber, 1 );
+ if ( lc != NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+ }
+ if ( incparent ) {
+ /* Forget about the bind */
+ --parentreq->lr_outrefcnt;
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ return( -1 );
+ }
+
+ use_connection( ld, lc );
+ if (( lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ))) ==
+ NULL || ( bindreqdn != NULL && ( bindreqdn =
+ nsldapi_strdup( bindreqdn )) == NULL )) {
+ if ( lr != NULL ) {
+ NSLDAPI_FREE( lr );
+ }
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
+ ber_free( ber, 1 );
+ if ( incparent ) {
+ /* Forget about the bind */
+ --parentreq->lr_outrefcnt;
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ return( -1 );
+ }
+ lr->lr_binddn = bindreqdn;
+ lr->lr_msgid = msgid;
+ lr->lr_status = LDAP_REQST_INPROGRESS;
+ lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */
+ lr->lr_ber = ber;
+ lr->lr_conn = lc;
+
+ if ( parentreq != NULL ) { /* sub-request */
+ if ( !incparent ) {
+ /* Increment if we didn't do it before the bind */
+ ++parentreq->lr_outrefcnt;
+ }
+ lr->lr_origid = parentreq->lr_origid;
+ lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
+ lr->lr_parent = parentreq;
+ if ( parentreq->lr_child != NULL ) {
+ lr->lr_sibling = parentreq->lr_child;
+ }
+ parentreq->lr_child = lr;
+ } else { /* original request */
+ lr->lr_origid = lr->lr_msgid;
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ if (( lr->lr_next = ld->ld_requests ) != NULL ) {
+ lr->lr_next->lr_prev = lr;
+ }
+ ld->ld_requests = lr;
+ lr->lr_prev = NULL;
+
+ if (( err = nsldapi_ber_flush( ld, lc->lconn_sb, ber, 0, 1 )) != 0 ) {
+
+ /* need to continue write later */
+ if (ld->ld_options & LDAP_BITOPT_ASYNC && err == -2 ) {
+ lr->lr_status = LDAP_REQST_WRITING;
+ nsldapi_iostatus_interest_write( ld, lc->lconn_sb );
+ } else {
+
+ LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+ nsldapi_free_request( ld, lr, 0 );
+ nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ return( -1 );
+ }
+
+ } else {
+ if ( parentreq == NULL ) {
+ ber->ber_end = ber->ber_ptr;
+ ber->ber_ptr = ber->ber_buf;
+ }
+
+ /* sent -- waiting for a response */
+ if (ld->ld_options & LDAP_BITOPT_ASYNC) {
+ lc->lconn_status = LDAP_CONNST_CONNECTED;
+ }
+
+ nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+ LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+ return( msgid );
+}
+
+
+/*
+ * returns -1 if a fatal error occurs. If async is non-zero and the flush
+ * would block, -2 is returned.
+ */
+int
+nsldapi_ber_flush( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit,
+ int async )
+{
+ int terrno;
+
+ for ( ;; ) {
+ /*
+ * ber_flush() doesn't set errno on EOF, so we pre-set it to
+ * zero to avoid getting tricked by leftover "EAGAIN" errors
+ */
+ LDAP_SET_ERRNO( ld, 0 );
+
+ if ( ber_flush( sb, ber, freeit ) == 0 ) {
+ return( 0 ); /* success */
+ }
+
+ terrno = LDAP_GET_ERRNO( ld );
+
+ if (ld->ld_options & LDAP_BITOPT_ASYNC) {
+ if ( terrno != 0 && !NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
+ nsldapi_connection_lost_nolock( ld, sb );
+ return( -1 ); /* fatal error */
+ }
+ }
+ else if ( !NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
+
+ nsldapi_connection_lost_nolock( ld, sb );
+ return( -1 ); /* fatal error */
+ }
+
+ if ( async ) {
+ return( -2 ); /* would block */
+ }
+ }
+}
+
+LDAPConn *
+nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
+ int connect, int bind )
+{
+ int rc;
+
+ LDAPConn *lc;
+ LDAPServer *prevsrv, *srv;
+ Sockbuf *sb = NULL;
+
+ /*
+ * make a new LDAP server connection
+ */
+ if (( lc = (LDAPConn *)NSLDAPI_CALLOC( 1, sizeof( LDAPConn ))) == NULL
+ || ( !use_ldsb && ( sb = ber_sockbuf_alloc()) == NULL )) {
+ if ( lc != NULL ) {
+ NSLDAPI_FREE( (char *)lc );
+ }
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( NULL );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+ if ( !use_ldsb ) {
+ /*
+ * we have allocated a new sockbuf
+ * set I/O routines to match those in default LDAP sockbuf
+ */
+ IFP sb_fn;
+ struct lber_x_ext_io_fns extiofns;
+
+ extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+
+ if ( ber_sockbuf_get_option( ld->ld_sbp,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns ) == 0 ) {
+ ber_sockbuf_set_option( sb,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns );
+ }
+ if ( ber_sockbuf_get_option( ld->ld_sbp,
+ LBER_SOCKBUF_OPT_READ_FN, (void *)&sb_fn ) == 0
+ && sb_fn != NULL ) {
+ ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_READ_FN,
+ (void *)sb_fn );
+ }
+ if ( ber_sockbuf_get_option( ld->ld_sbp,
+ LBER_SOCKBUF_OPT_WRITE_FN, (void *)&sb_fn ) == 0
+ && sb_fn != NULL ) {
+ ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_WRITE_FN,
+ (void *)sb_fn );
+ }
+ }
+
+ lc->lconn_sb = ( use_ldsb ) ? ld->ld_sbp : sb;
+ lc->lconn_version = ld->ld_version; /* inherited */
+ LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+
+ if ( connect ) {
+ prevsrv = NULL;
+ /*
+ * save the return code for later
+ */
+ for ( srv = *srvlistp; srv != NULL; srv = srv->lsrv_next ) {
+ rc = nsldapi_connect_to_host( ld, lc->lconn_sb,
+ srv->lsrv_host, srv->lsrv_port,
+ ( srv->lsrv_options & LDAP_SRV_OPT_SECURE ) != 0,
+ &lc->lconn_krbinstance );
+ if (rc != -1) {
+ break;
+ }
+ prevsrv = srv;
+ }
+
+ if ( srv == NULL ) {
+ if ( !use_ldsb ) {
+ NSLDAPI_FREE( (char *)lc->lconn_sb );
+ }
+ NSLDAPI_FREE( (char *)lc );
+ /* nsldapi_open_ldap_connection has already set ld_errno */
+ return( NULL );
+ }
+
+ if ( prevsrv == NULL ) {
+ *srvlistp = srv->lsrv_next;
+ } else {
+ prevsrv->lsrv_next = srv->lsrv_next;
+ }
+ lc->lconn_server = srv;
+ }
+
+ if (ld->ld_options & LDAP_BITOPT_ASYNC && rc == -2)
+ {
+ lc->lconn_status = LDAP_CONNST_CONNECTING;
+ }
+ else {
+ lc->lconn_status = LDAP_CONNST_CONNECTED;
+ }
+
+ lc->lconn_next = ld->ld_conns;
+ ld->ld_conns = lc;
+
+ /*
+ * XXX for now, we always do a synchronous bind. This will have
+ * to change in the long run...
+ */
+ if ( bind ) {
+ int err, lderr, freepasswd, authmethod;
+ char *binddn, *passwd;
+ LDAPConn *savedefconn;
+
+ freepasswd = err = 0;
+
+ if ( ld->ld_rebind_fn == NULL ) {
+ binddn = passwd = "";
+ authmethod = LDAP_AUTH_SIMPLE;
+ } else {
+ if (( lderr = (*ld->ld_rebind_fn)( ld, &binddn, &passwd,
+ &authmethod, 0, ld->ld_rebind_arg ))
+ == LDAP_SUCCESS ) {
+ freepasswd = 1;
+ } else {
+ LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+ err = -1;
+ }
+ }
+
+
+ if ( err == 0 ) {
+ savedefconn = ld->ld_defconn;
+ ld->ld_defconn = lc;
+ ++lc->lconn_refcnt; /* avoid premature free */
+
+ /*
+ * when binding, we will back down as low as LDAPv2
+ * if we get back "protocol error" from bind attempts
+ */
+ for ( ;; ) {
+ /* LDAP_MUTEX_UNLOCK(ld, LDAP_CONN_LOCK); */
+ if (( lderr = ldap_bind_s( ld, binddn, passwd,
+ authmethod )) == LDAP_SUCCESS ) {
+ /* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
+ break;
+ }
+ /* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
+ if ( lc->lconn_version <= LDAP_VERSION2
+ || lderr != LDAP_PROTOCOL_ERROR ) {
+ err = -1;
+ break;
+ }
+ --lc->lconn_version; /* try lower version */
+ }
+ --lc->lconn_refcnt;
+ ld->ld_defconn = savedefconn;
+ }
+
+ if ( freepasswd ) {
+ (*ld->ld_rebind_fn)( ld, &binddn, &passwd,
+ &authmethod, 1, ld->ld_rebind_arg );
+ }
+
+ if ( err != 0 ) {
+ nsldapi_free_connection( ld, lc, NULL, NULL, 1, 0 );
+ lc = NULL;
+ }
+ }
+
+ return( lc );
+}
+
+
+#define LDAP_CONN_SAMEHOST( h1, h2 ) \
+ (( (h1) == NULL && (h2) == NULL ) || \
+ ( (h1) != NULL && (h2) != NULL && strcasecmp( (h1), (h2) ) == 0 ))
+
+static LDAPConn *
+find_connection( LDAP *ld, LDAPServer *srv, int any )
+/*
+ * return an existing connection (if any) to the server srv
+ * if "any" is non-zero, check for any server in the "srv" chain
+ */
+{
+ LDAPConn *lc;
+ LDAPServer *ls;
+
+ for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
+ for ( ls = srv; ls != NULL; ls = ls->lsrv_next ) {
+ if ( LDAP_CONN_SAMEHOST( ls->lsrv_host,
+ lc->lconn_server->lsrv_host )
+ && ls->lsrv_port == lc->lconn_server->lsrv_port
+ && ls->lsrv_options ==
+ lc->lconn_server->lsrv_options ) {
+ return( lc );
+ }
+ if ( !any ) {
+ break;
+ }
+ }
+ }
+
+ return( NULL );
+}
+
+
+
+static void
+use_connection( LDAP *ld, LDAPConn *lc )
+{
+ ++lc->lconn_refcnt;
+ lc->lconn_lastused = time( 0 );
+}
+
+
+void
+nsldapi_free_connection( LDAP *ld, LDAPConn *lc, LDAPControl **serverctrls,
+ LDAPControl **clientctrls, int force, int unbind )
+{
+ LDAPConn *tmplc, *prevlc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection\n", 0, 0, 0 );
+
+ if ( force || --lc->lconn_refcnt <= 0 ) {
+ if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
+ nsldapi_iostatus_interest_clear( ld, lc->lconn_sb );
+ if ( unbind ) {
+ nsldapi_send_unbind( ld, lc->lconn_sb,
+ serverctrls, clientctrls );
+ }
+ }
+ nsldapi_close_connection( ld, lc->lconn_sb );
+ prevlc = NULL;
+ for ( tmplc = ld->ld_conns; tmplc != NULL;
+ tmplc = tmplc->lconn_next ) {
+ if ( tmplc == lc ) {
+ if ( prevlc == NULL ) {
+ ld->ld_conns = tmplc->lconn_next;
+ } else {
+ prevlc->lconn_next = tmplc->lconn_next;
+ }
+ break;
+ }
+ prevlc = tmplc;
+ }
+ free_servers( lc->lconn_server );
+ if ( lc->lconn_krbinstance != NULL ) {
+ NSLDAPI_FREE( lc->lconn_krbinstance );
+ }
+ /*
+ * if this is the default connection (lc->lconn_sb==ld->ld_sbp)
+ * we do not free the Sockbuf here since it will be freed
+ * later inside ldap_unbind().
+ */
+ if ( lc->lconn_sb != ld->ld_sbp ) {
+ ber_sockbuf_free( lc->lconn_sb );
+ lc->lconn_sb = NULL;
+ }
+ if ( lc->lconn_ber != NULLBER ) {
+ ber_free( lc->lconn_ber, 1 );
+ }
+ if ( lc->lconn_binddn != NULL ) {
+ NSLDAPI_FREE( lc->lconn_binddn );
+ }
+ NSLDAPI_FREE( lc );
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection: actually freed\n",
+ 0, 0, 0 );
+ } else {
+ lc->lconn_lastused = time( 0 );
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection: refcnt %d\n",
+ lc->lconn_refcnt, 0, 0 );
+ }
+}
+
+
+#ifdef LDAP_DEBUG
+void
+nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
+{
+ LDAPConn *lc;
+ char msg[256];
+/* CTIME for this platform doesn't use this. */
+#if !defined(SUNOS4) && !defined(_WIN32) && !defined(LINUX)
+ char buf[26];
+#endif
+
+ sprintf( msg, "** Connection%s:\n", all ? "s" : "" );
+ ber_err_print( msg );
+ for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
+ if ( lc->lconn_server != NULL ) {
+ sprintf( msg, "* host: %s port: %d secure: %s%s\n",
+ ( lc->lconn_server->lsrv_host == NULL ) ? "(null)"
+ : lc->lconn_server->lsrv_host,
+ lc->lconn_server->lsrv_port,
+ ( lc->lconn_server->lsrv_options &
+ LDAP_SRV_OPT_SECURE ) ? "Yes" :
+ "No", ( lc->lconn_sb == ld->ld_sbp ) ?
+ " (default)" : "" );
+ ber_err_print( msg );
+ }
+ sprintf( msg, " refcnt: %d status: %s\n", lc->lconn_refcnt,
+ ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ?
+ "NeedSocket" : ( lc->lconn_status ==
+ LDAP_CONNST_CONNECTING ) ? "Connecting" :
+ ( lc->lconn_status == LDAP_CONNST_DEAD ) ? "Dead" :
+ "Connected" );
+ ber_err_print( msg );
+ sprintf( msg, " last used: %s",
+ NSLDAPI_CTIME( (time_t *) &lc->lconn_lastused, buf,
+ sizeof(buf) ));
+ ber_err_print( msg );
+ if ( lc->lconn_ber != NULLBER ) {
+ ber_err_print( " partial response has been received:\n" );
+ ber_dump( lc->lconn_ber, 1 );
+ }
+ ber_err_print( "\n" );
+
+ if ( !all ) {
+ break;
+ }
+ }
+}
+
+
+void
+nsldapi_dump_requests_and_responses( LDAP *ld )
+{
+ LDAPRequest *lr;
+ LDAPMessage *lm, *l;
+ char msg[256];
+
+ ber_err_print( "** Outstanding Requests:\n" );
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ if (( lr = ld->ld_requests ) == NULL ) {
+ ber_err_print( " Empty\n" );
+ }
+ for ( ; lr != NULL; lr = lr->lr_next ) {
+ sprintf( msg, " * msgid %d, origid %d, status %s\n",
+ lr->lr_msgid, lr->lr_origid, ( lr->lr_status ==
+ LDAP_REQST_INPROGRESS ) ? "InProgress" :
+ ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
+ ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
+ ( lr->lr_status == LDAP_REQST_CONNDEAD ) ? "Dead" :
+ "Writing" );
+ ber_err_print( msg );
+ sprintf( msg, " outstanding referrals %d, parent count %d\n",
+ lr->lr_outrefcnt, lr->lr_parentcnt );
+ ber_err_print( msg );
+ if ( lr->lr_binddn != NULL ) {
+ sprintf( msg, " pending bind DN: <%s>\n", lr->lr_binddn );
+ ber_err_print( msg );
+ }
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+
+ ber_err_print( "** Response Queue:\n" );
+ LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+ if (( lm = ld->ld_responses ) == NULLMSG ) {
+ ber_err_print( " Empty\n" );
+ }
+ for ( ; lm != NULLMSG; lm = lm->lm_next ) {
+ sprintf( msg, " * msgid %d, type %d\n",
+ lm->lm_msgid, lm->lm_msgtype );
+ ber_err_print( msg );
+ if (( l = lm->lm_chain ) != NULL ) {
+ ber_err_print( " chained responses:\n" );
+ for ( ; l != NULLMSG; l = l->lm_chain ) {
+ sprintf( msg,
+ " * msgid %d, type %d\n",
+ l->lm_msgid, l->lm_msgtype );
+ ber_err_print( msg );
+ }
+ }
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+}
+#endif /* LDAP_DEBUG */
+
+
+void
+nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn )
+{
+ LDAPRequest *tmplr, *nextlr;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "nsldapi_free_request 0x%x (origid %d, msgid %d)\n",
+ lr, lr->lr_origid, lr->lr_msgid );
+
+ if ( lr->lr_parent != NULL ) {
+ --lr->lr_parent->lr_outrefcnt;
+ }
+
+ /* free all of our spawned referrals (child requests) */
+ for ( tmplr = lr->lr_child; tmplr != NULL; tmplr = nextlr ) {
+ nextlr = tmplr->lr_sibling;
+ nsldapi_free_request( ld, tmplr, free_conn );
+ }
+
+ if ( free_conn ) {
+ nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL, 0, 1 );
+ }
+
+ if ( lr->lr_prev == NULL ) {
+ ld->ld_requests = lr->lr_next;
+ } else {
+ lr->lr_prev->lr_next = lr->lr_next;
+ }
+
+ if ( lr->lr_next != NULL ) {
+ lr->lr_next->lr_prev = lr->lr_prev;
+ }
+
+ if ( lr->lr_ber != NULL ) {
+ ber_free( lr->lr_ber, 1 );
+ }
+
+ if ( lr->lr_res_error != NULL ) {
+ NSLDAPI_FREE( lr->lr_res_error );
+ }
+
+ if ( lr->lr_res_matched != NULL ) {
+ NSLDAPI_FREE( lr->lr_res_matched );
+ }
+
+ if ( lr->lr_binddn != NULL ) {
+ NSLDAPI_FREE( lr->lr_binddn );
+ }
+ NSLDAPI_FREE( lr );
+}
+
+
+static void
+free_servers( LDAPServer *srvlist )
+{
+ LDAPServer *nextsrv;
+
+ while ( srvlist != NULL ) {
+ nextsrv = srvlist->lsrv_next;
+ if ( srvlist->lsrv_dn != NULL ) {
+ NSLDAPI_FREE( srvlist->lsrv_dn );
+ }
+ if ( srvlist->lsrv_host != NULL ) {
+ NSLDAPI_FREE( srvlist->lsrv_host );
+ }
+ NSLDAPI_FREE( srvlist );
+ srvlist = nextsrv;
+ }
+}
+
+
+/*
+ * Initiate chasing of LDAPv2+ (Umich extension) referrals.
+ *
+ * Returns an LDAP error code.
+ *
+ * Note that *hadrefp will be set to 1 if one or more referrals were found in
+ * "*errstrp" (even if we can't chase them) and zero if none were found.
+ *
+ * XXX merging of errors in this routine needs to be improved.
+ */
+int
+nsldapi_chase_v2_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp,
+ int *totalcountp, int *chasingcountp )
+{
+ char *p, *ref, *unfollowed;
+ LDAPRequest *origreq;
+ int rc, tmprc, len, unknown;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_chase_v2_referrals\n", 0, 0, 0 );
+
+ *totalcountp = *chasingcountp = 0;
+
+ if ( *errstrp == NULL ) {
+ return( LDAP_SUCCESS );
+ }
+
+ len = strlen( *errstrp );
+ for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) {
+ if (( *p == 'R' || *p == 'r' ) && strncasecmp( p,
+ LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
+ *p = '\0';
+ p += LDAP_REF_STR_LEN;
+ break;
+ }
+ }
+
+ if ( len < LDAP_REF_STR_LEN ) {
+ return( LDAP_SUCCESS );
+ }
+
+ if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "more than %d referral hops (dropping)\n",
+ ld->ld_refhoplimit, 0, 0 );
+ return( LDAP_REFERRAL_LIMIT_EXCEEDED );
+ }
+
+ /* find original request */
+ for ( origreq = lr; origreq->lr_parent != NULL;
+ origreq = origreq->lr_parent ) {
+ ;
+ }
+
+ unfollowed = NULL;
+ rc = LDAP_SUCCESS;
+
+ /* parse out & follow referrals */
+ for ( ref = p; rc == LDAP_SUCCESS && ref != NULL; ref = p ) {
+ if (( p = strchr( ref, '\n' )) != NULL ) {
+ *p++ = '\0';
+ } else {
+ p = NULL;
+ }
+
+ ++*totalcountp;
+
+ rc = chase_one_referral( ld, lr, origreq, ref, "v2 referral",
+ &unknown );
+
+ if ( rc != LDAP_SUCCESS || unknown ) {
+ if (( tmprc = nsldapi_append_referral( ld, &unfollowed,
+ ref )) != LDAP_SUCCESS ) {
+ rc = tmprc;
+ }
+ } else {
+ ++*chasingcountp;
+ }
+ }
+
+ NSLDAPI_FREE( *errstrp );
+ *errstrp = unfollowed;
+
+ return( rc );
+}
+
+
+/* returns an LDAP error code */
+int
+nsldapi_chase_v3_refs( LDAP *ld, LDAPRequest *lr, char **v3refs,
+ int is_reference, int *totalcountp, int *chasingcountp )
+{
+ int i, rc, unknown;
+ LDAPRequest *origreq;
+
+ *totalcountp = *chasingcountp = 0;
+
+ if ( v3refs == NULL || v3refs[0] == NULL ) {
+ return( LDAP_SUCCESS );
+ }
+
+ *totalcountp = 1;
+
+ if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "more than %d referral hops (dropping)\n",
+ ld->ld_refhoplimit, 0, 0 );
+ return( LDAP_REFERRAL_LIMIT_EXCEEDED );
+ }
+
+ /* find original request */
+ for ( origreq = lr; origreq->lr_parent != NULL;
+ origreq = origreq->lr_parent ) {
+ ;
+ }
+
+ /*
+ * in LDAPv3, we just need to follow one referral in the set.
+ * we dp this by stopping as soon as we succeed in initiating a
+ * chase on any referral (basically this means we were able to connect
+ * to the server and bind).
+ */
+ for ( i = 0; v3refs[i] != NULL; ++i ) {
+ rc = chase_one_referral( ld, lr, origreq, v3refs[i],
+ is_reference ? "v3 reference" : "v3 referral", &unknown );
+ if ( rc == LDAP_SUCCESS && !unknown ) {
+ *chasingcountp = 1;
+ break;
+ }
+ }
+
+ /* XXXmcs: should we save unfollowed referrals somewhere? */
+
+ return( rc ); /* last error is as good as any other I guess... */
+}
+
+/*
+ * returns an LDAP error code
+ *
+ * XXXmcs: this function used to have #ifdef LDAP_DNS code in it but I
+ * removed it when I improved the parsing (we don't define LDAP_DNS
+ * here at Netscape).
+ */
+static int
+chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq,
+ char *refurl, char *desc, int *unknownp )
+{
+ int rc, tmprc, secure, msgid;
+ LDAPServer *srv;
+ BerElement *ber;
+ LDAPURLDesc *ludp;
+
+ *unknownp = 0;
+ ludp = NULLLDAPURLDESC;
+
+ if ( nsldapi_url_parse( refurl, &ludp, 0 ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ignoring unknown %s <%s>\n", desc, refurl, 0 );
+ *unknownp = 1;
+ rc = LDAP_SUCCESS;
+ goto cleanup_and_return;
+ }
+
+ secure = (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 );
+
+/* XXXmcs: can't tell if secure is supported by connect callback */
+ if ( secure && ld->ld_extconnect_fn == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ignoring LDAPS %s <%s>\n", desc, refurl, 0 );
+ *unknownp = 1;
+ rc = LDAP_SUCCESS;
+ goto cleanup_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "chasing LDAP%s %s: <%s>\n",
+ secure ? "S" : "", desc, refurl );
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ msgid = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ if (( tmprc = re_encode_request( ld, origreq->lr_ber, msgid,
+ ludp, &ber )) != LDAP_SUCCESS ) {
+ rc = tmprc;
+ goto cleanup_and_return;
+ }
+
+ if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer )))
+ == NULL ) {
+ ber_free( ber, 1 );
+ rc = LDAP_NO_MEMORY;
+ goto cleanup_and_return;
+ }
+
+ if (ludp->lud_host == NULL && ld->ld_defhost == NULL) {
+ srv->lsrv_host = NULL;
+ } else {
+ if (ludp->lud_host == NULL) {
+ srv->lsrv_host =
+ nsldapi_strdup( origreq->lr_conn->lconn_server->lsrv_host );
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "chase_one_referral: using hostname '%s' from original "
+ "request on new request\n",
+ srv->lsrv_host, 0, 0);
+ } else {
+ srv->lsrv_host = nsldapi_strdup(ludp->lud_host);
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "chase_one_referral: using hostname '%s' as specified "
+ "on new request\n",
+ srv->lsrv_host, 0, 0);
+ }
+
+ if (srv->lsrv_host == NULL) {
+ NSLDAPI_FREE((char *)srv);
+ ber_free(ber, 1);
+ rc = LDAP_NO_MEMORY;
+ goto cleanup_and_return;
+ }
+ }
+
+ /*
+ * According to our reading of RFCs 2255 and 1738, the
+ * following algorithm applies:
+ * - no hostport (no host, no port) provided in LDAP URL, use those
+ * of previous request
+ * - no port but a host, use default LDAP port
+ * - else use given hostport
+ */
+ if (ludp->lud_port == 0 && ludp->lud_host == NULL) {
+ srv->lsrv_port = origreq->lr_conn->lconn_server->lsrv_port;
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "chase_one_referral: using port (%d) from original "
+ "request on new request\n",
+ srv->lsrv_port, 0, 0);
+ } else if (ludp->lud_port == 0 && ludp->lud_host != NULL) {
+ srv->lsrv_port = (secure) ? LDAPS_PORT : LDAP_PORT;
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "chase_one_referral: using default port (%d) \n",
+ srv->lsrv_port, 0, 0);
+ } else {
+ srv->lsrv_port = ludp->lud_port;
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "chase_one_referral: using port (%d) as specified on "
+ "new request\n",
+ srv->lsrv_port, 0, 0);
+ }
+
+ if ( secure ) {
+ srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
+ }
+
+ if ( nsldapi_send_server_request( ld, ber, msgid,
+ lr, srv, NULL, NULL, 1 ) < 0 ) {
+ rc = LDAP_GET_LDERRNO( ld, NULL, NULL );
+ LDAPDebug( LDAP_DEBUG_ANY, "Unable to chase %s %s (%s)\n",
+ desc, refurl, ldap_err2string( rc ));
+ } else {
+ rc = LDAP_SUCCESS;
+ }
+
+cleanup_and_return:
+ if ( ludp != NULLLDAPURLDESC ) {
+ ldap_free_urldesc( ludp );
+ }
+
+ return( rc );
+}
+
+
+/* returns an LDAP error code */
+int
+nsldapi_append_referral( LDAP *ld, char **referralsp, char *s )
+{
+ int first;
+
+ if ( *referralsp == NULL ) {
+ first = 1;
+ *referralsp = (char *)NSLDAPI_MALLOC( strlen( s ) +
+ LDAP_REF_STR_LEN + 1 );
+ } else {
+ first = 0;
+ *referralsp = (char *)NSLDAPI_REALLOC( *referralsp,
+ strlen( *referralsp ) + strlen( s ) + 2 );
+ }
+
+ if ( *referralsp == NULL ) {
+ return( LDAP_NO_MEMORY );
+ }
+
+ if ( first ) {
+ strcpy( *referralsp, LDAP_REF_STR );
+ } else {
+ strcat( *referralsp, "\n" );
+ }
+ strcat( *referralsp, s );
+
+ return( LDAP_SUCCESS );
+}
+
+
+
+/* returns an LDAP error code */
+static int
+re_encode_request( LDAP *ld, BerElement *origber, int msgid, LDAPURLDesc *ludp,
+ BerElement **berp )
+{
+/*
+ * XXX this routine knows way too much about how the lber library works!
+ */
+ ber_uint_t along;
+ ber_tag_t tag;
+ ber_int_t ver;
+ int rc;
+ BerElement *ber;
+ struct berelement tmpber;
+ char *dn, *orig_dn;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "re_encode_request: new msgid %d, new dn <%s>\n",
+ msgid, ( ludp->lud_dn == NULL ) ? "NONE" : ludp->lud_dn, 0 );
+
+ tmpber = *origber;
+
+ /*
+ * All LDAP requests are sequences that start with a message id. For
+ * everything except delete requests, this is followed by a sequence
+ * that is tagged with the operation code. For deletes, there is just
+ * a DN that is tagged with the operation code.
+ */
+
+ /* skip past msgid and get operation tag */
+ if ( ber_scanf( &tmpber, "{it", &along, &tag ) == LBER_ERROR ) {
+ return( LDAP_DECODING_ERROR );
+ }
+
+ /*
+ * XXXmcs: we don't support scope or filters in search referrals yet,
+ * so if either were present we return an error which is probably
+ * better than just ignoring the extra info.
+ */
+ if ( tag == LDAP_REQ_SEARCH &&
+ ( ludp->lud_scope != -1 || ludp->lud_filter != NULL )) {
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ if ( tag == LDAP_REQ_BIND ) {
+ /* bind requests have a version number before the DN */
+ rc = ber_scanf( &tmpber, "{ia", &ver, &orig_dn );
+ } else if ( tag == LDAP_REQ_DELETE ) {
+ /* delete requests DNs are not within a sequence */
+ rc = ber_scanf( &tmpber, "a", &orig_dn );
+ } else {
+ rc = ber_scanf( &tmpber, "{a", &orig_dn );
+ }
+
+ if ( rc == LBER_ERROR ) {
+ return( LDAP_DECODING_ERROR );
+ }
+
+ if ( ludp->lud_dn == NULL ) {
+ dn = orig_dn;
+ } else {
+ dn = ludp->lud_dn;
+ NSLDAPI_FREE( orig_dn );
+ orig_dn = NULL;
+ }
+
+ /* allocate and build the new request */
+ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ if ( orig_dn != NULL ) {
+ NSLDAPI_FREE( orig_dn );
+ }
+ return( rc );
+ }
+
+ if ( tag == LDAP_REQ_BIND ) {
+ rc = ber_printf( ber, "{it{is", msgid, tag,
+ (int)ver /* XXX lossy cast */, dn );
+ } else if ( tag == LDAP_REQ_DELETE ) {
+ rc = ber_printf( ber, "{its}", msgid, tag, dn );
+ } else {
+ rc = ber_printf( ber, "{it{s", msgid, tag, dn );
+ }
+
+ if ( orig_dn != NULL ) {
+ NSLDAPI_FREE( orig_dn );
+ }
+/*
+ * can't use "dn" or "orig_dn" from this point on (they've been freed)
+ */
+
+ if ( rc == -1 ) {
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ if ( tag != LDAP_REQ_DELETE &&
+ ( ber_write( ber, tmpber.ber_ptr, ( tmpber.ber_end -
+ tmpber.ber_ptr ), 0 ) != ( tmpber.ber_end - tmpber.ber_ptr )
+ || ber_printf( ber, "}}" ) == -1 )) {
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+#ifdef LDAP_DEBUG
+ if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n",
+ 0, 0, 0 );
+ ber_dump( ber, 0 );
+ }
+#endif /* LDAP_DEBUG */
+
+ *berp = ber;
+ return( LDAP_SUCCESS );
+}
+
+
+LDAPRequest *
+nsldapi_find_request_by_msgid( LDAP *ld, int msgid )
+{
+ LDAPRequest *lr;
+
+ for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+ if ( msgid == lr->lr_msgid ) {
+ break;
+ }
+ }
+
+ return( lr );
+}
+
+
+/*
+ * nsldapi_connection_lost_nolock() resets "ld" to a non-connected, known
+ * state. It should be called whenever a fatal error occurs on the
+ * Sockbuf "sb." sb == NULL means we don't know specifically where
+ * the problem was so we assume all connections are bad.
+ */
+void
+nsldapi_connection_lost_nolock( LDAP *ld, Sockbuf *sb )
+{
+ LDAPRequest *lr;
+
+ /*
+ * change status of all pending requests that are associated with "sb
+ * to "connection dead."
+ * also change the connection status to "dead" and remove it from
+ * the list of sockets we are interested in.
+ */
+ for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+ if ( sb == NULL ||
+ ( lr->lr_conn != NULL && lr->lr_conn->lconn_sb == sb )) {
+ lr->lr_status = LDAP_REQST_CONNDEAD;
+ if ( lr->lr_conn != NULL ) {
+ lr->lr_conn->lconn_status = LDAP_CONNST_DEAD;
+ nsldapi_iostatus_interest_clear( ld,
+ lr->lr_conn->lconn_sb );
+ }
+ }
+ }
+}
+
+
+#ifdef LDAP_DNS
+static LDAPServer *
+dn2servers( LDAP *ld, char *dn ) /* dn can also be a domain.... */
+{
+ char *p, *domain, *host, *server_dn, **dxs;
+ int i, port;
+ LDAPServer *srvlist, *prevsrv, *srv;
+
+ if (( domain = strrchr( dn, '@' )) != NULL ) {
+ ++domain;
+ } else {
+ domain = dn;
+ }
+
+ if (( dxs = nsldapi_getdxbyname( domain )) == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( NULL );
+ }
+
+ srvlist = NULL;
+
+ for ( i = 0; dxs[ i ] != NULL; ++i ) {
+ port = LDAP_PORT;
+ server_dn = NULL;
+ if ( strchr( dxs[ i ], ':' ) == NULL ) {
+ host = dxs[ i ];
+ } else if ( strlen( dxs[ i ] ) >= 7 &&
+ strncmp( dxs[ i ], "ldap://", 7 ) == 0 ) {
+ host = dxs[ i ] + 7;
+ if (( p = strchr( host, ':' )) == NULL ) {
+ p = host;
+ } else {
+ *p++ = '\0';
+ port = atoi( p );
+ }
+ if (( p = strchr( p, '/' )) != NULL ) {
+ server_dn = ++p;
+ if ( *server_dn == '\0' ) {
+ server_dn = NULL;
+ }
+ }
+ } else {
+ host = NULL;
+ }
+
+ if ( host != NULL ) { /* found a server we can use */
+ if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1,
+ sizeof( LDAPServer ))) == NULL ) {
+ free_servers( srvlist );
+ srvlist = NULL;
+ break; /* exit loop & return */
+ }
+
+ /* add to end of list of servers */
+ if ( srvlist == NULL ) {
+ srvlist = srv;
+ } else {
+ prevsrv->lsrv_next = srv;
+ }
+ prevsrv = srv;
+
+ /* copy in info. */
+ if (( srv->lsrv_host = nsldapi_strdup( host )) == NULL
+ || ( server_dn != NULL && ( srv->lsrv_dn =
+ nsldapi_strdup( server_dn )) == NULL )) {
+ free_servers( srvlist );
+ srvlist = NULL;
+ break; /* exit loop & return */
+ }
+ srv->lsrv_port = port;
+ }
+ }
+
+ ldap_value_free( dxs );
+
+ if ( srvlist == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+ }
+
+ return( srvlist );
+}
+#endif /* LDAP_DNS */
diff --git a/usr/src/lib/libldap5/sources/ldap/common/reslist.c b/usr/src/lib/libldap5/sources/ldap/common/reslist.c
new file mode 100644
index 0000000000..1cbc533340
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/reslist.c
@@ -0,0 +1,65 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * reslist.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+LDAPMessage *
+ldap_delete_result_entry( LDAPMessage **list, LDAPMessage *e )
+{
+ LDAPMessage *tmp, *prev = NULL;
+
+ for ( tmp = *list; tmp != NULL && tmp != e; tmp = tmp->lm_chain )
+ prev = tmp;
+
+ if ( tmp == NULL )
+ return( NULL );
+
+ if ( prev == NULL )
+ *list = tmp->lm_chain;
+ else
+ prev->lm_chain = tmp->lm_chain;
+ tmp->lm_chain = NULL;
+
+ return( tmp );
+}
+
+void
+ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e )
+{
+ e->lm_chain = *list;
+ *list = e;
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/result.c b/usr/src/lib/libldap5/sources/ldap/common/result.c
new file mode 100644
index 0000000000..ecf807653a
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/result.c
@@ -0,0 +1,1473 @@
+/*
+ * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * result.c - wait for an ldap result
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+#ifdef _SOLARIS_SDK
+/* high resolution timer usage */
+#include <sys/time.h>
+#endif
+
+static int check_response_queue( LDAP *ld, int msgid, int all,
+ int do_abandon_check, LDAPMessage **result );
+static int ldap_abandoned( LDAP *ld, int msgid );
+static int ldap_mark_abandoned( LDAP *ld, int msgid );
+static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
+ struct timeval *timeout, LDAPMessage **result );
+static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
+ LDAPMessage **result );
+static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
+ int ldapversion, int *totalcountp, int *chasingcountp );
+static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr );
+static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
+#if defined( CLDAP )
+static int cldap_select1( LDAP *ld, struct timeval *timeout );
+#endif
+static void link_pend( LDAP *ld, LDAPPend *lp );
+#if 0 /* these functions are no longer used */
+static void unlink_pend( LDAP *ld, LDAPPend *lp );
+static int unlink_msg( LDAP *ld, int msgid, int all );
+#endif /* 0 */
+
+/*
+ * ldap_result - wait for an ldap result response to a message from the
+ * ldap server. If msgid is -1, any message will be accepted, otherwise
+ * ldap_result will wait for a response with msgid. If all is 0 the
+ * first message with id msgid will be accepted, otherwise, ldap_result
+ * will wait for all responses with id msgid and then return a pointer to
+ * the entire list of messages. This is only useful for search responses,
+ * which can be of two message types (zero or more entries, followed by an
+ * ldap result). The type of the first message received is returned.
+ * When waiting, any messages that have been abandoned are discarded.
+ *
+ * Example:
+ * ldap_result( s, msgid, all, timeout, result )
+ */
+int
+LDAP_CALL
+ldap_result(
+ LDAP *ld,
+ int msgid,
+ int all,
+ struct timeval *timeout,
+ LDAPMessage **result
+)
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 ); /* punt */
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
+
+ rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result);
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
+
+ return( rc );
+}
+
+
+int
+nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
+ struct timeval *timeout, LDAPMessage **result )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 );
+
+ /*
+ * First, look through the list of responses we have received on
+ * this association and see if the response we're interested in
+ * is there. If it is, return it. If not, call wait4msg() to
+ * wait until it arrives or timeout occurs.
+ */
+
+ if ( result == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( -1 );
+ }
+
+ if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+ rc = (*result)->lm_msgtype;
+ } else {
+ rc = wait4msg( ld, msgid, all, unlock_permitted, timeout,
+ result );
+ }
+
+ /*
+ * XXXmcs should use cache function pointers to hook in memcache
+ */
+ if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) &&
+ !((*result)->lm_fromcache )) {
+ ldap_memcache_append( ld, (*result)->lm_msgid,
+ (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result );
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Look through the list of queued responses for a message that matches the
+ * criteria in the msgid and all parameters. msgid == LDAP_RES_ANY matches
+ * all ids.
+ *
+ * If an appropriate message is found, a non-zero value is returned and the
+ * message is dequeued and assigned to *result.
+ *
+ * If not, *result is set to NULL and this function returns 0.
+ */
+static int
+check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
+ LDAPMessage **result )
+{
+ LDAPMessage *lm, *lastlm, *nextlm;
+ LDAPRequest *lr;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 );
+
+ *result = NULL;
+ lastlm = NULL;
+ LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+ for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
+ nextlm = lm->lm_next;
+
+ if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) {
+ ldap_mark_abandoned( ld, lm->lm_msgid );
+
+ if ( lastlm == NULL ) {
+ ld->ld_responses = lm->lm_next;
+ } else {
+ lastlm->lm_next = nextlm;
+ }
+
+ ldap_msgfree( lm );
+
+ continue;
+ }
+
+ if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
+ LDAPMessage *tmp;
+
+ if ( all == 0
+ || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
+ && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
+ && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
+ break;
+
+ for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
+ if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
+ break;
+ }
+
+ if ( tmp == NULL ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= check_response_queue NOT FOUND\n",
+ 0, 0, 0 );
+ return( 0 ); /* no message to return */
+ }
+
+ break;
+ }
+ lastlm = lm;
+ }
+
+ /*
+ * if we did not find a message OR if the one we found is a result for
+ * a request that is still pending, return failure.
+ */
+ if ( lm == NULL
+ || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid ))
+ != NULL && lr->lr_outrefcnt > 0 )) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= check_response_queue NOT FOUND\n",
+ 0, 0, 0 );
+ return( 0 ); /* no message to return */
+ }
+
+ if ( all == 0 ) {
+ if ( lm->lm_chain == NULL ) {
+ if ( lastlm == NULL ) {
+ ld->ld_responses = lm->lm_next;
+ } else {
+ lastlm->lm_next = lm->lm_next;
+ }
+ } else {
+ if ( lastlm == NULL ) {
+ ld->ld_responses = lm->lm_chain;
+ ld->ld_responses->lm_next = lm->lm_next;
+ } else {
+ lastlm->lm_next = lm->lm_chain;
+ lastlm->lm_next->lm_next = lm->lm_next;
+ }
+ }
+ } else {
+ if ( lastlm == NULL ) {
+ ld->ld_responses = lm->lm_next;
+ } else {
+ lastlm->lm_next = lm->lm_next;
+ }
+ }
+
+ if ( all == 0 ) {
+ lm->lm_chain = NULL;
+ }
+ lm->lm_next = NULL;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+
+ *result = lm;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= check_response_queue returning msgid %d type %d\n",
+ lm->lm_msgid, lm->lm_msgtype, 0 );
+ return( 1 ); /* a message was found and returned in *result */
+}
+
+
+static int
+wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
+ struct timeval *timeout, LDAPMessage **result )
+{
+ int rc;
+ struct timeval tv, *tvp;
+#ifdef _SOLARIS_SDK
+ hrtime_t start_time = 0, tmp_time, tv_time;
+#else
+ long start_time = 0, tmp_time;
+#endif
+ LDAPConn *lc, *nextlc;
+ LDAPRequest *lr;
+
+#ifdef LDAP_DEBUG
+ if ( timeout == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
+ 0, 0, 0 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
+ timeout->tv_sec, timeout->tv_usec, 0 );
+ }
+#endif /* LDAP_DEBUG */
+
+ /* check the cache */
+ if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) {
+ /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
+ if ( rc != 0 ) {
+ return( rc );
+ }
+ if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
+ LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
+ return( 0 ); /* timeout */
+ }
+ }
+
+ /*
+ * if we are looking for a specific msgid, check to see if it is
+ * associated with a dead connection and return an error if so.
+ */
+ if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ if (( lr = nsldapi_find_request_by_msgid( ld, msgid ))
+ == NULL ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
+ nsldapi_strdup( dgettext(TEXT_DOMAIN,
+ "unknown message id") ));
+ return( -1 ); /* could not find request for msgid */
+ }
+ if ( lr->lr_conn != NULL &&
+ lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
+ nsldapi_free_request( ld, lr, 1 );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+ return( -1 ); /* connection dead */
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ }
+
+ if ( timeout == NULL ) {
+ tvp = NULL;
+ } else {
+ tv = *timeout;
+ tvp = &tv;
+#ifdef _SOLARIS_SDK
+ start_time = gethrtime();
+ tv_time = ((hrtime_t)tv.tv_sec * NANOSEC +
+ (hrtime_t)tv.tv_usec * (NANOSEC / MICROSEC));
+#else
+ start_time = (long)time( NULL );
+#endif
+ }
+
+ rc = -2;
+ while ( rc == -2 ) {
+#ifdef LDAP_DEBUG
+ if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+ nsldapi_dump_connection( ld, ld->ld_conns, 1 );
+ nsldapi_dump_requests_and_responses( ld );
+ }
+#endif /* LDAP_DEBUG */
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
+ if ( lc->lconn_sb->sb_ber.ber_ptr <
+ lc->lconn_sb->sb_ber.ber_end ) {
+ rc = read1msg( ld, msgid, all, lc->lconn_sb,
+ lc, result );
+ break;
+ }
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+ if ( lc == NULL ) {
+ rc = nsldapi_iostatus_poll( ld, tvp );
+
+#if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
+ if ( rc == -1 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "nsldapi_iostatus_poll returned -1: errno %d\n",
+ LDAP_GET_ERRNO( ld ), 0, 0 );
+ }
+#endif
+
+#if !defined( macintosh ) && !defined( DOS )
+ if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
+ LDAP_BITOPT_RESTART ) == 0 ||
+ LDAP_GET_ERRNO( ld ) != EINTR ))) {
+#else
+ if ( rc == -1 || rc == 0 ) {
+#endif
+ LDAP_SET_LDERRNO( ld, (rc == -1 ?
+ LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
+ NULL );
+ if ( rc == -1 ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ nsldapi_connection_lost_nolock( ld,
+ NULL );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ }
+ return( rc );
+ }
+
+ if ( rc == -1 ) {
+ rc = -2; /* select interrupted: loop */
+ } else {
+ rc = -2;
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
+ lc = nextlc ) {
+ nextlc = lc->lconn_next;
+ if ( lc->lconn_status ==
+ LDAP_CONNST_CONNECTED &&
+ nsldapi_iostatus_is_read_ready( ld,
+ lc->lconn_sb )) {
+ rc = read1msg( ld, msgid, all,
+ lc->lconn_sb, lc, result );
+ }
+ else if (ld->ld_options & LDAP_BITOPT_ASYNC) {
+ if ( lr
+ && lc->lconn_status == LDAP_CONNST_CONNECTING
+ && nsldapi_iostatus_is_write_ready( ld,
+ lc->lconn_sb ) ) {
+ rc = nsldapi_ber_flush( ld, lc->lconn_sb, lr->lr_ber, 0, 1 );
+ if ( rc == 0 ) {
+ rc = LDAP_RES_BIND;
+ lc->lconn_status = LDAP_CONNST_CONNECTED;
+
+ lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
+ lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
+ nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
+ }
+ else if ( rc == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+ nsldapi_free_request( ld, lr, 0 );
+ nsldapi_free_connection( ld, lc, NULL, NULL,
+ 0, 0 );
+ }
+ }
+
+ }
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+ }
+ }
+
+ /*
+ * It is possible that recursion occurred while chasing
+ * referrals and as a result the message we are looking
+ * for may have been placed on the response queue. Look
+ * for it there before continuing so we don't end up
+ * waiting on the network for a message that we already
+ * received!
+ */
+ if ( rc == -2 &&
+ check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+ rc = (*result)->lm_msgtype;
+ }
+
+ /*
+ * honor the timeout if specified
+ */
+ if ( rc == -2 && tvp != NULL ) {
+#ifdef _SOLARIS_SDK
+ tmp_time = gethrtime();
+ if ((tv_time -= (tmp_time - start_time)) <= 0) {
+#else
+ tmp_time = (long)time( NULL );
+ if (( tv.tv_sec -= ( tmp_time - start_time )) <= 0 ) {
+#endif
+ rc = 0; /* timed out */
+ LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
+ NULL );
+ break;
+ }
+
+#ifdef _SOLARIS_SDK
+ tv.tv_sec = tv_time / NANOSEC;
+ tv.tv_usec = (tv_time % NANOSEC) / (NANOSEC / MICROSEC);
+#endif
+ LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg: %ld secs to go\n",
+ tv.tv_sec, 0, 0 );
+ start_time = tmp_time;
+ }
+ }
+
+ return( rc );
+}
+
+
+/*
+ * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
+ */
+static int
+read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
+ LDAPMessage **result )
+{
+ BerElement *ber;
+ LDAPMessage *new, *l, *prev, *chainprev, *tmp;
+ ber_int_t id;
+ ber_tag_t tag;
+ ber_len_t len;
+ int terrno, lderr, foundit = 0;
+ LDAPRequest *lr;
+ int rc, has_parent, message_can_be_returned;
+ int manufactured_result = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
+
+ message_can_be_returned = 1; /* the usual case... */
+
+ /*
+ * if we are not already in the midst of reading a message, allocate
+ * a ber that is associated with this connection
+ */
+ if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
+ &lc->lconn_ber ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+
+ /*
+ * ber_get_next() doesn't set errno on EOF, so we pre-set it to
+ * zero to avoid getting tricked by leftover "EAGAIN" errors
+ */
+ LDAP_SET_ERRNO( ld, 0 );
+
+ /* get the next message */
+ if ( (tag = ber_get_next( sb, &len, lc->lconn_ber ))
+ != LDAP_TAG_MESSAGE ) {
+ terrno = LDAP_GET_ERRNO( ld );
+ if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
+ return( -2 ); /* try again */
+ }
+ LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
+ LDAP_LOCAL_ERROR), NULL, NULL );
+ if ( tag == LBER_DEFAULT ) {
+ nsldapi_connection_lost_nolock( ld, sb );
+ }
+ return( -1 );
+ }
+
+ /*
+ * Since we have received a complete message now, we pull this ber
+ * out of the connection structure and never read into it again.
+ */
+ ber = lc->lconn_ber;
+ lc->lconn_ber = NULLBER;
+
+ /* message id */
+ if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ return( -1 );
+ }
+
+ /* if it's been abandoned, toss it */
+ if ( ldap_abandoned( ld, (int)id ) ) {
+ ber_free( ber, 1 );
+ return( -2 ); /* continue looking */
+ }
+
+ if ( id == LDAP_RES_UNSOLICITED ) {
+ lr = NULL;
+ } else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "no request for response with msgid %ld (tossing)\n",
+ id, 0, 0 );
+ ber_free( ber, 1 );
+ return( -2 ); /* continue looking */
+ }
+
+ /* the message type */
+ if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ return( -1 );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
+ ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
+ ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id,
+ ( lr == NULL ) ? id : lr->lr_origid );
+
+ if ( lr != NULL ) {
+ id = lr->lr_origid;
+ lr->lr_res_msgtype = tag;
+ }
+ rc = -2; /* default is to keep looking (no response found) */
+
+ if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
+ tag != LDAP_RES_SEARCH_ENTRY )) {
+ int refchasing, reftotal, simple_request = 0;
+
+ check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal,
+ &refchasing );
+
+ if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) {
+ /*
+ * we're chasing one or more new refs...
+ */
+ ber_free( ber, 1 );
+ ber = NULLBER;
+ lr->lr_status = LDAP_REQST_CHASINGREFS;
+ message_can_be_returned = 0;
+
+ } else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
+ /*
+ * this request is complete...
+ */
+ has_parent = ( lr->lr_parent != NULL );
+
+ if ( lr->lr_outrefcnt <= 0 && !has_parent ) {
+ /* request without any refs */
+ simple_request = ( reftotal == 0 );
+ }
+
+ /*
+ * If this is not a child request and it is a bind
+ * request, reset the connection's bind DN and
+ * status based on the result of the operation.
+ */
+ if ( !has_parent &&
+ LDAP_RES_BIND == lr->lr_res_msgtype &&
+ lr->lr_conn != NULL ) {
+ if ( lr->lr_conn->lconn_binddn != NULL ) {
+ NSLDAPI_FREE(
+ lr->lr_conn->lconn_binddn );
+ }
+ if ( LDAP_SUCCESS == nsldapi_parse_result( ld,
+ lr->lr_res_msgtype, ber, &lderr, NULL,
+ NULL, NULL, NULL )
+ && LDAP_SUCCESS == lderr ) {
+ lr->lr_conn->lconn_bound = 1;
+ lr->lr_conn->lconn_binddn =
+ lr->lr_binddn;
+ lr->lr_binddn = NULL;
+ } else {
+ lr->lr_conn->lconn_bound = 0;
+ lr->lr_conn->lconn_binddn = NULL;
+ }
+ }
+
+ /*
+ * if this response is to a child request, we toss
+ * the message contents and just merge error info.
+ * into the parent.
+ */
+ if ( has_parent ) {
+ ber_free( ber, 1 );
+ ber = NULLBER;
+ }
+ while ( lr->lr_parent != NULL ) {
+ merge_error_info( ld, lr->lr_parent, lr );
+
+ lr = lr->lr_parent;
+ if ( --lr->lr_outrefcnt > 0 ) {
+ break; /* not completely done yet */
+ }
+ }
+
+ /*
+ * we recognize a request as complete when:
+ * 1) it has no outstanding referrals
+ * 2) it is not a child request
+ * 3) we have received a result for the request (i.e.,
+ * something other than an entry or a reference).
+ */
+ if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL &&
+ lr->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY &&
+ lr->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
+ id = lr->lr_msgid;
+ tag = lr->lr_res_msgtype;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "request %ld done\n", id, 0, 0 );
+LDAPDebug( LDAP_DEBUG_TRACE,
+"res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
+lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
+lr->lr_res_matched ? lr->lr_res_matched : "" );
+ if ( !simple_request ) {
+ if ( ber != NULLBER ) {
+ ber_free( ber, 1 );
+ ber = NULLBER;
+ }
+ if ( build_result_ber( ld, &ber, lr )
+ != LDAP_SUCCESS ) {
+ rc = -1; /* fatal error */
+ } else {
+ manufactured_result = 1;
+ }
+ }
+
+ nsldapi_free_request( ld, lr, 1 );
+ } else {
+ message_can_be_returned = 0;
+ }
+ }
+ }
+
+ if ( ber == NULLBER ) {
+ return( rc );
+ }
+
+ /* make a new ldap message */
+ if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
+ == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ new->lm_msgid = (int)id;
+ new->lm_msgtype = tag;
+ new->lm_ber = ber;
+
+ /*
+ * if this is a search entry or if this request is complete (i.e.,
+ * there are no outstanding referrals) then add to cache and check
+ * to see if we should return this to the caller right away or not.
+ */
+ if ( message_can_be_returned ) {
+ if ( ld->ld_cache_on ) {
+ nsldapi_add_result_to_cache( ld, new );
+ }
+
+ if ( msgid == LDAP_RES_ANY || id == msgid ) {
+ if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+ /*
+ * return the first response we have for this
+ * search request later (possibly an entire
+ * chain of messages).
+ */
+ foundit = 1;
+ } else if ( all == 0
+ || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
+ && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
+ *result = new;
+ LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL,
+ NULL );
+ return( tag );
+ }
+ }
+ }
+
+ /*
+ * if not, we must add it to the list of responses. if
+ * the msgid is already there, it must be part of an existing
+ * search response.
+ */
+
+ prev = NULL;
+ LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+ for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
+ if ( l->lm_msgid == new->lm_msgid )
+ break;
+ prev = l;
+ }
+
+ /* not part of an existing search response */
+ if ( l == NULL ) {
+ if ( foundit ) {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ *result = new;
+ LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+ return( tag );
+ }
+
+ new->lm_next = ld->ld_responses;
+ ld->ld_responses = new;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "adding new response id %d type %d (looking for id %d)\n",
+ new->lm_msgid, new->lm_msgtype, msgid );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ if( message_can_be_returned )
+ POST( ld, new->lm_msgid, new );
+ return( -2 ); /* continue looking */
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "adding response id %d type %d (looking for id %d)\n",
+ new->lm_msgid, new->lm_msgtype, msgid );
+
+ /*
+ * part of a search response - add to end of list of entries
+ *
+ * the first step is to find the end of the list of entries and
+ * references. after the following loop is executed, tmp points to
+ * the last entry or reference in the chain. If there are none,
+ * tmp points to the search result.
+ */
+ chainprev = NULL;
+ for ( tmp = l; tmp->lm_chain != NULL &&
+ ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
+ || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE );
+ tmp = tmp->lm_chain ) {
+ chainprev = tmp;
+ }
+
+ /*
+ * If this is a manufactured result message and a result is already
+ * queued we throw away the one that is queued and replace it with
+ * our new result. This is necessary so we don't end up returning
+ * more than one result.
+ */
+ if ( manufactured_result &&
+ tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+ /*
+ * the result is the only thing in the chain... replace it.
+ */
+ new->lm_chain = tmp->lm_chain;
+ new->lm_next = tmp->lm_next;
+ if ( chainprev == NULL ) {
+ if ( prev == NULL ) {
+ ld->ld_responses = new;
+ } else {
+ prev->lm_next = new;
+ }
+ } else {
+ chainprev->lm_chain = new;
+ }
+ if ( l == tmp ) {
+ l = new;
+ }
+ ldap_msgfree( tmp );
+
+ } else if ( manufactured_result && tmp->lm_chain != NULL
+ && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+ /*
+ * entries or references are also present, so the result
+ * is the next entry after tmp. replace it.
+ */
+ new->lm_chain = tmp->lm_chain->lm_chain;
+ new->lm_next = tmp->lm_chain->lm_next;
+ ldap_msgfree( tmp->lm_chain );
+ tmp->lm_chain = new;
+
+ } else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+ /*
+ * the result is the only thing in the chain... add before it.
+ */
+ new->lm_chain = tmp;
+ if ( chainprev == NULL ) {
+ if ( prev == NULL ) {
+ ld->ld_responses = new;
+ } else {
+ prev->lm_next = new;
+ }
+ } else {
+ chainprev->lm_chain = new;
+ }
+ if ( l == tmp ) {
+ l = new;
+ }
+
+ } else {
+ /*
+ * entries and/or references are present... add to the end
+ * of the entry/reference part of the chain.
+ */
+ new->lm_chain = tmp->lm_chain;
+ tmp->lm_chain = new;
+ }
+
+ /*
+ * return the first response or the whole chain if that's what
+ * we were looking for....
+ */
+ if ( foundit ) {
+ if ( all == 0 && l->lm_chain != NULL ) {
+ /*
+ * only return the first response in the chain
+ */
+ if ( prev == NULL ) {
+ ld->ld_responses = l->lm_chain;
+ } else {
+ prev->lm_next = l->lm_chain;
+ }
+ l->lm_chain = NULL;
+ tag = l->lm_msgtype;
+ } else {
+ /*
+ * return all of the responses (may be a chain)
+ */
+ if ( prev == NULL ) {
+ ld->ld_responses = l->lm_next;
+ } else {
+ prev->lm_next = l->lm_next;
+ }
+ }
+ *result = l;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+ return( tag );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ return( -2 ); /* continue looking */
+}
+
+
+/*
+ * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
+ * errors are merged in "lr".
+ */
+static void
+check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
+ int ldapversion, int *totalcountp, int *chasingcountp )
+{
+ int err, origerr;
+ char *errstr, *matcheddn, **v3refs;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 );
+
+ *chasingcountp = *totalcountp = 0;
+
+ if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL
+ && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) {
+ /* referrals are not supported or are disabled */
+ return;
+ }
+
+ if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+ err = nsldapi_parse_reference( ld, ber, &v3refs, NULL );
+ origerr = LDAP_REFERRAL; /* a small lie... */
+ matcheddn = errstr = NULL;
+ } else {
+ err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber,
+ &origerr, &matcheddn, &errstr, &v3refs, NULL );
+ }
+
+ if ( err != LDAP_SUCCESS ) {
+ /* parse failed */
+ return;
+ }
+
+ if ( origerr == LDAP_REFERRAL ) { /* ldapv3 */
+ if ( v3refs != NULL ) {
+ err = nsldapi_chase_v3_refs( ld, lr, v3refs,
+ ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ),
+ totalcountp, chasingcountp );
+ ldap_value_free( v3refs );
+ }
+ } else if ( ldapversion == LDAP_VERSION2
+ && origerr != LDAP_SUCCESS ) {
+ /* referrals may be present in the error string */
+ err = nsldapi_chase_v2_referrals( ld, lr, &errstr,
+ totalcountp, chasingcountp );
+ }
+
+ /* set LDAP errno, message, and matched string appropriately */
+ if ( lr->lr_res_error != NULL ) {
+ NSLDAPI_FREE( lr->lr_res_error );
+ }
+ lr->lr_res_error = errstr;
+
+ if ( lr->lr_res_matched != NULL ) {
+ NSLDAPI_FREE( lr->lr_res_matched );
+ }
+ lr->lr_res_matched = matcheddn;
+
+ if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) {
+ if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS
+ || origerr == LDAP_REFERRAL )) {
+ /* substitute success for referral error codes */
+ lr->lr_res_errno = LDAP_SUCCESS;
+ } else {
+ /* preserve existing non-referral error code */
+ lr->lr_res_errno = origerr;
+ }
+ } else if ( err != LDAP_SUCCESS ) {
+ /* error occurred while trying to chase referrals */
+ lr->lr_res_errno = err;
+ } else {
+ /* some referrals were not recognized */
+ lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 )
+ ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "check_for_refs: new result: msgid %d, res_errno %d, ",
+ lr->lr_msgid, lr->lr_res_errno, 0 );
+ LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n",
+ lr->lr_res_error ? lr->lr_res_error : "",
+ lr->lr_res_matched ? lr->lr_res_matched : "", 0 );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "check_for_refs: %d new refs(s); chasing %d of them\n",
+ *totalcountp, *chasingcountp, 0 );
+}
+
+
+/* returns an LDAP error code and also sets it in LDAP * */
+static int
+build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr )
+{
+ ber_len_t len;
+ ber_int_t along;
+ BerElement *ber;
+ int err;
+
+ if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( err );
+ }
+ *berp = ber;
+ if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
+ (long)lr->lr_res_msgtype, lr->lr_res_errno,
+ lr->lr_res_matched ? lr->lr_res_matched : "",
+ lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ ber_reset( ber, 1 );
+ if ( ber_skip_tag( ber, &len ) == LBER_ERROR ||
+ ber_get_int( ber, &along ) == LBER_ERROR ||
+ ber_peek_tag( ber, &len ) == LBER_ERROR ) {
+ return( LDAP_DECODING_ERROR );
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+static void
+merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
+{
+/*
+ * Merge error information in "lr" with "parentr" error code and string.
+ */
+ if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
+ parentr->lr_res_errno = lr->lr_res_errno;
+ if ( lr->lr_res_error != NULL ) {
+ (void)nsldapi_append_referral( ld, &parentr->lr_res_error,
+ lr->lr_res_error );
+ }
+ } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
+ parentr->lr_res_errno == LDAP_SUCCESS ) {
+ parentr->lr_res_errno = lr->lr_res_errno;
+ if ( parentr->lr_res_error != NULL ) {
+ NSLDAPI_FREE( parentr->lr_res_error );
+ }
+ parentr->lr_res_error = lr->lr_res_error;
+ lr->lr_res_error = NULL;
+ if ( NAME_ERROR( lr->lr_res_errno )) {
+ if ( parentr->lr_res_matched != NULL ) {
+ NSLDAPI_FREE( parentr->lr_res_matched );
+ }
+ parentr->lr_res_matched = lr->lr_res_matched;
+ lr->lr_res_matched = NULL;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info: ",
+ parentr->lr_msgid, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n",
+ parentr->lr_res_errno, parentr->lr_res_error ?
+ parentr->lr_res_error : "", parentr->lr_res_matched ?
+ parentr->lr_res_matched : "" );
+}
+
+#if defined( CLDAP )
+#if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2)
+/* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
+static int
+cldap_select1( LDAP *ld, struct timeval *timeout )
+{
+ int rc;
+ static int tblsize = 0;
+ NSLDAPIIOStatus *iosp = ld->ld_iostatus;
+
+ if ( tblsize == 0 ) {
+#ifdef USE_SYSCONF
+ tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+ tblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+ }
+
+ if ( tblsize >= FD_SETSIZE ) {
+ /*
+ * clamp value so we don't overrun the fd_set structure
+ */
+ tblsize = FD_SETSIZE - 1;
+ }
+
+ if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) {
+ fd_set readfds;
+
+ FD_ZERO( &readfds );
+ FD_SET( ld->ld_sbp->sb_sd, &readfds );
+
+ /* XXXmcs: UNIX platforms should use poll() */
+ rc = select( tblsize, &readfds, 0, 0, timeout ) );
+
+ } else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) {
+ LDAP_X_PollFD pollfds[ 1 ];
+
+ pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd;
+ pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg;
+ pollfds[0].lpoll_events = LDAP_X_POLLIN;
+ pollfds[0].lpoll_revents = 0;
+ rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ),
+ ld->ld_ext_session_arg );
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nsldapi_iostatus_poll: unknown I/O type %d\n",
+ rc = 0; /* simulate a timeout (what else to do?) */
+ }
+
+ return( rc );
+}
+#endif /* !macintosh */
+
+
+#ifdef macintosh
+static int
+cldap_select1( LDAP *ld, struct timeval *timeout )
+{
+ /* XXXmcs: needs to be revised to support I/O callbacks */
+ return( tcpselect( ld->ld_sbp->sb_sd, timeout ));
+}
+#endif /* macintosh */
+
+
+#if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2)
+/* XXXmcs: needs to be revised to support extended I/O callbacks */
+static int
+cldap_select1( LDAP *ld, struct timeval *timeout )
+{
+ fd_set readfds;
+ int rc;
+
+ FD_ZERO( &readfds );
+ FD_SET( ld->ld_sbp->sb_sd, &readfds );
+
+ if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type &&
+ NULL != ld->ld_select_fn ) {
+ rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout );
+ } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type &&
+ NULL != ld->ld_extselect_fn ) {
+ rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0,
+ 0, timeout ) );
+ } else {
+ /* XXXmcs: UNIX platforms should use poll() */
+ rc = select( 1, &readfds, 0, 0, timeout ) );
+ }
+
+ return( rc == SOCKET_ERROR ? -1 : rc );
+}
+#endif /* WINSOCK || _WINDOWS */
+#endif /* CLDAP */
+
+int
+LDAP_CALL
+ldap_msgfree( LDAPMessage *lm )
+{
+ LDAPMessage *next;
+ int type = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
+
+ for ( ; lm != NULL; lm = next ) {
+ next = lm->lm_chain;
+ type = lm->lm_msgtype;
+ ber_free( lm->lm_ber, 1 );
+ NSLDAPI_FREE( (char *) lm );
+ }
+
+ return( type );
+}
+
+/*
+ * ldap_msgdelete - delete a message. It returns:
+ * 0 if the entire message was deleted
+ * -1 if the message was not found, or only part of it was found
+ */
+int
+ldap_msgdelete( LDAP *ld, int msgid )
+{
+ LDAPMessage *lm, *prev;
+ int msgtype;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 ); /* punt */
+ }
+
+ prev = NULL;
+ LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+ for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
+ if ( lm->lm_msgid == msgid )
+ break;
+ prev = lm;
+ }
+
+ if ( lm == NULL )
+ {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ return( -1 );
+ }
+
+ if ( prev == NULL )
+ ld->ld_responses = lm->lm_next;
+ else
+ prev->lm_next = lm->lm_next;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+
+ msgtype = ldap_msgfree( lm );
+ if ( msgtype == LDAP_RES_SEARCH_ENTRY
+ || msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * return 1 if message msgid is waiting to be abandoned, 0 otherwise
+ */
+static int
+ldap_abandoned( LDAP *ld, int msgid )
+{
+ int i;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
+ if ( ld->ld_abandoned == NULL )
+ {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ return( 0 );
+ }
+
+ for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+ if ( ld->ld_abandoned[i] == msgid )
+ {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ return( 1 );
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ return( 0 );
+}
+
+
+static int
+ldap_mark_abandoned( LDAP *ld, int msgid )
+{
+ int i;
+
+ LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
+ if ( ld->ld_abandoned == NULL )
+ {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ return( -1 );
+ }
+
+ for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+ if ( ld->ld_abandoned[i] == msgid )
+ break;
+
+ if ( ld->ld_abandoned[i] == -1 )
+ {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ return( -1 );
+ }
+
+ for ( ; ld->ld_abandoned[i] != -1; i++ ) {
+ ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+ return( 0 );
+}
+
+
+#ifdef CLDAP
+int
+cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber )
+{
+ int rc;
+ ber_tag_t tag;
+ ber_len_t len;
+
+ if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) {
+ rc = cldap_select1( ld, timeout );
+ if ( rc == -1 || rc == 0 ) {
+ LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN :
+ LDAP_TIMEOUT), NULL, NULL );
+ return( rc );
+ }
+ }
+
+ /* get the next message */
+ if ( (tag = ber_get_next( ld->ld_sbp, &len, ber ))
+ != LDAP_TAG_MESSAGE ) {
+ LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
+ LDAP_LOCAL_ERROR), NULL, NULL );
+ return( -1 );
+ }
+
+ return( tag );
+}
+#endif /* CLDAP */
+
+int
+nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result )
+{
+ LDAPPend *lp;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "nsldapi_post_result(ld=0x%x, msgid=%d, result=0x%x)\n",
+ ld, msgid, result );
+ LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK );
+ if( msgid == LDAP_RES_ANY ) {
+ /*
+ * Look for any pending request for which someone is waiting.
+ */
+ for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
+ {
+ if ( lp->lp_sema != NULL ) {
+ break;
+ }
+ }
+ /*
+ * If we did't find a pending request, lp is NULL at this
+ * point, and we will leave this function without doing
+ * anything more -- which is exactly what we want to do.
+ */
+ }
+ else
+ {
+ /*
+ * Look for a pending request specific to this message id
+ */
+ for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
+ {
+ if( lp->lp_msgid == msgid )
+ break;
+ }
+
+ if( lp == NULL )
+ {
+ /*
+ * No pending requests for this response... append to
+ * our pending result list.
+ */
+ LDAPPend *newlp;
+ newlp = (LDAPPend *)NSLDAPI_CALLOC( 1,
+ sizeof( LDAPPend ));
+ if( newlp == NULL )
+ {
+ LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
+ NULL );
+ return (-1);
+ }
+ newlp->lp_msgid = msgid;
+ newlp->lp_result = result;
+ link_pend( ld, newlp );
+ }
+ }
+
+
+ if( lp != NULL )
+ {
+ /*
+ * Wake up a thread that is waiting for this result.
+ */
+ lp->lp_msgid = msgid;
+ lp->lp_result = result;
+ LDAP_SEMA_POST( ld, lp );
+ }
+
+ LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
+ return (0);
+}
+
+static void
+link_pend( LDAP *ld, LDAPPend *lp )
+{
+ if (( lp->lp_next = ld->ld_pend ) != NULL )
+ {
+ lp->lp_next->lp_prev = lp;
+ }
+ ld->ld_pend = lp;
+ lp->lp_prev = NULL;
+}
+
+#if 0 /* these functions are no longer used */
+static void
+unlink_pend( LDAP *ld, LDAPPend *lp )
+{
+ if ( lp->lp_prev == NULL ) {
+ ld->ld_pend = lp->lp_next;
+ } else {
+ lp->lp_prev->lp_next = lp->lp_next;
+ }
+
+ if ( lp->lp_next != NULL ) {
+ lp->lp_next->lp_prev = lp->lp_prev;
+ }
+}
+
+static int
+unlink_msg( LDAP *ld, int msgid, int all )
+{
+ int rc;
+ LDAPMessage *lm, *lastlm, *nextlm;
+
+ lastlm = NULL;
+ LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+ for ( lm = ld->ld_responses; lm != NULL; lm = nextlm )
+ {
+ nextlm = lm->lm_next;
+
+ if ( lm->lm_msgid == msgid )
+ {
+ LDAPMessage *tmp;
+
+ if ( all == 0
+ || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
+ && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
+ && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
+ break;
+
+ for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
+ if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
+ break;
+ }
+ if( tmp != NULL )
+ break;
+ }
+ lastlm = lm;
+ }
+
+ if( lm != NULL )
+ {
+
+ if ( all == 0 )
+ {
+ if ( lm->lm_chain == NULL )
+ {
+ if ( lastlm == NULL )
+ ld->ld_responses = lm->lm_next;
+ else
+ lastlm->lm_next = lm->lm_next;
+ }
+ else
+ {
+ if ( lastlm == NULL )
+ {
+ ld->ld_responses = lm->lm_chain;
+ ld->ld_responses->lm_next = lm->lm_next;
+ }
+ else
+ {
+ lastlm->lm_next = lm->lm_chain;
+ lastlm->lm_next->lm_next = lm->lm_next;
+ }
+ }
+ }
+ else
+ {
+ if ( lastlm == NULL )
+ ld->ld_responses = lm->lm_next;
+ else
+ lastlm->lm_next = lm->lm_next;
+ }
+
+ if ( all == 0 )
+ lm->lm_chain = NULL;
+ lm->lm_next = NULL;
+ rc = lm->lm_msgtype;
+ }
+ else
+ {
+ rc = -2;
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+ return ( rc );
+}
+#endif /* 0 */
diff --git a/usr/src/lib/libldap5/sources/ldap/common/sasl.c b/usr/src/lib/libldap5/sources/ldap/common/sasl.c
new file mode 100644
index 0000000000..8dba6d6562
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/sasl.c
@@ -0,0 +1,974 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef LDAP_SASLIO_HOOKS
+#include <assert.h>
+#include "ldap-int.h"
+#include "../ber/lber-int.h"
+#include <sasl/sasl.h>
+#include <thread.h>
+#include <synch.h>
+
+#define SEARCH_TIMEOUT_SECS 120
+#define NSLDAPI_SM_BUF 128
+
+extern void *sasl_create_context(void);
+extern void sasl_free_context(void *ctx);
+extern int _sasl_client_init(void *ctx, const sasl_callback_t *callbacks);
+extern int _sasl_client_new(void *ctx, const char *service,
+ const char *serverFQDN, const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *prompt_supp,
+ unsigned flags, sasl_conn_t **pconn);
+extern int _sasl_server_init(void *ctx,
+ const sasl_callback_t *callbacks, const char *appname);
+extern int _sasl_server_new(void *ctx, const char *service,
+ const char *serverFQDN, const char *user_realm,
+ const char *iplocalport, const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ unsigned flags, sasl_conn_t **pconn);
+
+static int nsldapi_sasl_close( LDAP *ld, Sockbuf *sb );
+
+/*
+ * SASL Dependent routines
+ *
+ * SASL security and integrity options are supported through the
+ * use of the extended I/O functionality. Because the extended
+ * I/O functions may already be in use prior to enabling encryption,
+ * when SASL encryption is enabled, these routine interpose themselves
+ * over the existng extended I/O routines and add an additional level
+ * of indirection.
+ * IE: Before SASL: client->libldap->lber->extio
+ * After SASL: client->libldap->lber->saslio->extio
+ * Any extio functions are still used for the raw i/O [IE prldap]
+ * but SASL will decrypt before passing to lber.
+ * SASL cannot decrypt a stream so full packets must be read
+ * before proceeding.
+ */
+
+static int nsldapi_sasl_fail()
+{
+ return( SASL_FAIL );
+}
+
+/*
+ * Global SASL Init data
+ */
+
+static sasl_callback_t client_callbacks[] = {
+ { SASL_CB_GETOPT, nsldapi_sasl_fail, NULL },
+ { SASL_CB_GETREALM, NULL, NULL },
+ { SASL_CB_USER, NULL, NULL },
+ { SASL_CB_AUTHNAME, NULL, NULL },
+ { SASL_CB_PASS, NULL, NULL },
+ { SASL_CB_ECHOPROMPT, NULL, NULL },
+ { SASL_CB_NOECHOPROMPT, NULL, NULL },
+ { SASL_CB_LIST_END, NULL, NULL }
+};
+static mutex_t sasl_mutex = DEFAULTMUTEX;
+static int nsldapi_sasl_inited = 0;
+static void *gctx; /* intentially not freed - avoid libsasl re-inits */
+
+int nsldapi_sasl_init( void )
+{
+ int saslrc;
+
+ mutex_lock(&sasl_mutex);
+ if ( nsldapi_sasl_inited ) {
+ mutex_unlock(&sasl_mutex);
+ return( 0 );
+ }
+ if ((gctx = (void *)sasl_create_context()) != NULL) {
+ saslrc = _sasl_client_init(gctx, client_callbacks);
+ if (saslrc == SASL_OK ) {
+ nsldapi_sasl_inited = 1;
+ mutex_unlock(&sasl_mutex);
+ return( 0 );
+ }
+ }
+ mutex_unlock(&sasl_mutex);
+ return( -1 );
+}
+
+/*
+ * SASL encryption routines
+ */
+
+/*
+ * Get the 4 octet header [size] for a sasl encrypted buffer.
+ * See RFC222 [section 3].
+ */
+
+static int
+nsldapi_sasl_pktlen( char *buf, int maxbufsize )
+{
+ int size;
+
+ size = ntohl(*(long *)buf);
+
+ if ( size < 0 || size > maxbufsize ) {
+ return (-1 );
+ }
+
+ return( size + 4 ); /* include the first 4 bytes */
+}
+
+static int
+nsldapi_sasl_read( int s, void *buf, int len,
+ struct lextiof_socket_private *arg)
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+ LDAP *ld;
+ const char *dbuf;
+ char *cp;
+ int ret;
+ unsigned dlen, blen;
+
+ if (sb == NULL) {
+ return( -1 );
+ }
+
+ ld = (LDAP *)sb->sb_sasl_prld;
+ if (ld == NULL) {
+ return( -1 );
+ }
+
+ /* Is there anything left in the existing buffer? */
+ if ((ret = sb->sb_sasl_ilen) > 0) {
+ ret = (ret > len ? len : ret);
+ SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret );
+ if (ret == sb->sb_sasl_ilen) {
+ sb->sb_sasl_ilen = 0;
+ sb->sb_sasl_iptr = NULL;
+ } else {
+ sb->sb_sasl_ilen -= ret;
+ sb->sb_sasl_iptr += ret;
+ }
+ return( ret );
+ }
+
+ /* buffer is empty - fill it */
+ cp = sb->sb_sasl_ibuf;
+ dlen = 0;
+
+ /* Read the length of the packet */
+ while ( dlen < 4 ) {
+ if (sb->sb_sasl_fns.lbextiofn_read != NULL) {
+ ret = sb->sb_sasl_fns.lbextiofn_read(
+ s, cp, 4 - dlen,
+ sb->sb_sasl_fns.lbextiofn_socket_arg);
+ } else {
+ ret = read( sb->sb_sd, cp, 4 - dlen );
+ }
+#ifdef EINTR
+ if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
+ continue;
+#endif
+ if ( ret <= 0 )
+ return( ret );
+
+ cp += ret;
+ dlen += ret;
+ }
+
+ blen = 4;
+
+ ret = nsldapi_sasl_pktlen( sb->sb_sasl_ibuf, sb->sb_sasl_bfsz );
+ if (ret < 0) {
+ LDAP_SET_ERRNO(ld, EIO);
+ return( -1 );
+ }
+ dlen = ret - dlen;
+
+ /* read the rest of the encrypted packet */
+ while ( dlen > 0 ) {
+ if (sb->sb_sasl_fns.lbextiofn_read != NULL) {
+ ret = sb->sb_sasl_fns.lbextiofn_read(
+ s, cp, dlen,
+ sb->sb_sasl_fns.lbextiofn_socket_arg);
+ } else {
+ ret = read( sb->sb_sd, cp, dlen );
+ }
+
+#ifdef EINTR
+ if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
+ continue;
+#endif
+ if ( ret <= 0 )
+ return( ret );
+
+ cp += ret;
+ blen += ret;
+ dlen -= ret;
+ }
+
+ /* Decode the packet */
+ ret = sasl_decode( sb->sb_sasl_ctx,
+ sb->sb_sasl_ibuf, blen,
+ &dbuf, &dlen);
+ if ( ret != SASL_OK ) {
+ /* sb_sasl_read: failed to decode packet, drop it, error */
+ sb->sb_sasl_iptr = NULL;
+ sb->sb_sasl_ilen = 0;
+ LDAP_SET_ERRNO(ld, EIO);
+ return( -1 );
+ }
+
+ /* copy decrypted packet to the input buffer */
+ SAFEMEMCPY( sb->sb_sasl_ibuf, dbuf, dlen );
+ sb->sb_sasl_iptr = sb->sb_sasl_ibuf;
+ sb->sb_sasl_ilen = dlen;
+
+ ret = (dlen > (unsigned) len ? len : dlen);
+ SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret );
+ if (ret == sb->sb_sasl_ilen) {
+ sb->sb_sasl_ilen = 0;
+ sb->sb_sasl_iptr = NULL;
+ } else {
+ sb->sb_sasl_ilen -= ret;
+ sb->sb_sasl_iptr += ret;
+ }
+ return( ret );
+}
+
+static int
+nsldapi_sasl_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *arg)
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+ int ret;
+ const char *obuf, *optr;
+ unsigned olen;
+
+ if (sb == NULL) {
+ return( -1 );
+ }
+
+ /* encode the next packet. */
+ ret = sasl_encode( sb->sb_sasl_ctx, buf, (unsigned)len, &obuf, &olen);
+ if ( ret != SASL_OK ) {
+ /* XXX Log error? "sb_sasl_write: failed to encode packet..." */
+ return( -1 );
+ }
+
+ /* Write everything now, buffer is only good until next sasl_encode */
+ optr = obuf;
+ while (olen > 0) {
+ if (sb->sb_sasl_fns.lbextiofn_write != NULL) {
+ ret = sb->sb_sasl_fns.lbextiofn_write(
+ s, optr, olen,
+ sb->sb_sasl_fns.lbextiofn_socket_arg);
+ } else {
+ ret = write( sb->sb_sd, optr, olen);
+ }
+ if ( ret < 0 )
+ return( ret );
+ optr += ret;
+ olen -= ret;
+ }
+ return( len );
+}
+
+static int
+nsldapi_sasl_poll(
+ LDAP_X_PollFD fds[], int nfds, int timeout,
+ struct lextiof_session_private *arg )
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+ LDAP *ld;
+ int i;
+
+ if (sb == NULL) {
+ return( -1 );
+ }
+ ld = (LDAP *)sb->sb_sasl_prld;
+ if (ld == NULL) {
+ return( -1 );
+ }
+
+ if (fds && nfds > 0) {
+ for(i = 0; i < nfds; i++) {
+ if (fds[i].lpoll_socketarg ==
+ (struct lextiof_socket_private *)sb) {
+ fds[i].lpoll_socketarg =
+ (struct lextiof_socket_private *)
+ sb->sb_sasl_fns.lbextiofn_socket_arg;
+ }
+
+ }
+ }
+ return ( ld->ld_sasl_io_fns.lextiof_poll( fds, nfds, timeout,
+ (void *)ld->ld_sasl_io_fns.lextiof_session_arg) );
+}
+
+/* no encryption indirect routines */
+
+static int
+nsldapi_sasl_ne_read( int s, void *buf, int len,
+ struct lextiof_socket_private *arg)
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+
+ if (sb == NULL) {
+ return( -1 );
+ }
+
+ return( sb->sb_sasl_fns.lbextiofn_read( s, buf, len,
+ sb->sb_sasl_fns.lbextiofn_socket_arg) );
+}
+
+static int
+nsldapi_sasl_ne_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *arg)
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+
+ if (sb == NULL) {
+ return( -1 );
+ }
+
+ return( sb->sb_sasl_fns.lbextiofn_write( s, buf, len,
+ sb->sb_sasl_fns.lbextiofn_socket_arg) );
+}
+
+static int
+nsldapi_sasl_close_socket(int s, struct lextiof_socket_private *arg )
+{
+ Sockbuf *sb = (Sockbuf *)arg;
+ LDAP *ld;
+
+ if (sb == NULL) {
+ return( -1 );
+ }
+ ld = (LDAP *)sb->sb_sasl_prld;
+ if (ld == NULL) {
+ return( -1 );
+ }
+ /* undo function pointer interposing */
+ ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &ld->ld_sasl_io_fns );
+ ber_sockbuf_set_option( sb,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ (void *)&sb->sb_sasl_fns);
+
+ /* undo SASL */
+ nsldapi_sasl_close( ld, sb );
+
+ return ( ld->ld_sasl_io_fns.lextiof_close( s,
+ (struct lextiof_socket_private *)
+ sb->sb_sasl_fns.lbextiofn_socket_arg ) );
+}
+
+/*
+ * install encryption routines if security has been negotiated
+ */
+static int
+nsldapi_sasl_install( LDAP *ld, Sockbuf *sb, void *ctx_arg, sasl_ssf_t *ssf)
+{
+ struct lber_x_ext_io_fns fns;
+ struct ldap_x_ext_io_fns iofns;
+ sasl_security_properties_t *secprops;
+ int rc, value;
+ int bufsiz;
+ int encrypt = 0;
+
+ if (ssf && *ssf) {
+ encrypt = 1;
+ }
+ rc = ber_sockbuf_get_option( sb,
+ LBER_SOCKBUF_OPT_TO_FILE_ONLY,
+ (void *) &value);
+ if (rc != 0 || value != 0)
+ return( LDAP_LOCAL_ERROR );
+
+ if (encrypt) {
+ /* initialize input buffer - use MAX SIZE to avoid reallocs */
+ sb->sb_sasl_ctx = (sasl_conn_t *)ctx_arg;
+ rc = sasl_getprop( sb->sb_sasl_ctx, SASL_SEC_PROPS,
+ (const void **)&secprops );
+ if (rc != SASL_OK)
+ return( LDAP_LOCAL_ERROR );
+ bufsiz = secprops->maxbufsize;
+ if (bufsiz <= 0) {
+ return( LDAP_LOCAL_ERROR );
+ }
+ if ((sb->sb_sasl_ibuf = NSLDAPI_MALLOC(bufsiz)) == NULL) {
+ return( LDAP_LOCAL_ERROR );
+ }
+ sb->sb_sasl_iptr = NULL;
+ sb->sb_sasl_bfsz = bufsiz;
+ sb->sb_sasl_ilen = 0;
+ }
+
+ /* Reset Session then Socket Args */
+ /* Get old values */
+ (void) memset( &sb->sb_sasl_fns, 0, LBER_X_EXTIO_FNS_SIZE);
+ sb->sb_sasl_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ rc = ber_sockbuf_get_option( sb,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ (void *)&sb->sb_sasl_fns);
+ memset( &ld->ld_sasl_io_fns, 0, sizeof(iofns));
+ ld->ld_sasl_io_fns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ rc = ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ &ld->ld_sasl_io_fns );
+ if (rc != 0 )
+ return( LDAP_LOCAL_ERROR );
+
+ /* Set new values */
+ if ( ld->ld_sasl_io_fns.lextiof_read != NULL ||
+ ld->ld_sasl_io_fns.lextiof_write != NULL ||
+ ld->ld_sasl_io_fns.lextiof_poll != NULL ||
+ ld->ld_sasl_io_fns.lextiof_connect != NULL ||
+ ld->ld_sasl_io_fns.lextiof_close != NULL ) {
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if (encrypt) {
+ iofns.lextiof_read = nsldapi_sasl_read;
+ iofns.lextiof_write = nsldapi_sasl_write;
+ iofns.lextiof_poll = nsldapi_sasl_poll;
+ } else {
+ iofns.lextiof_read = nsldapi_sasl_ne_read;
+ iofns.lextiof_write = nsldapi_sasl_ne_write;
+ iofns.lextiof_poll = nsldapi_sasl_poll;
+ }
+ iofns.lextiof_connect = ld->ld_sasl_io_fns.lextiof_connect;
+ iofns.lextiof_close = nsldapi_sasl_close_socket;
+ iofns.lextiof_newhandle = ld->ld_sasl_io_fns.lextiof_newhandle;
+ iofns.lextiof_disposehandle =
+ ld->ld_sasl_io_fns.lextiof_disposehandle;
+ iofns.lextiof_session_arg =
+ (void *) sb;
+ /* ld->ld_sasl_io_fns.lextiof_session_arg; */
+ rc = ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ &iofns );
+ if (rc != 0 )
+ return( LDAP_LOCAL_ERROR );
+ sb->sb_sasl_prld = (void *)ld;
+ }
+
+ if (encrypt) {
+ (void) memset( &fns, 0, LBER_X_EXTIO_FNS_SIZE);
+ fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ fns.lbextiofn_read = nsldapi_sasl_read;
+ fns.lbextiofn_write = nsldapi_sasl_write;
+ fns.lbextiofn_socket_arg =
+ (void *) sb;
+ /* (void *)sb->sb_sasl_fns.lbextiofn_socket_arg; */
+ rc = ber_sockbuf_set_option( sb,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ (void *)&fns);
+ if (rc != 0)
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+static int
+nsldapi_sasl_cvterrno( LDAP *ld, int err )
+{
+ int rc = LDAP_LOCAL_ERROR;
+
+ switch (err) {
+ case SASL_OK:
+ rc = LDAP_SUCCESS;
+ break;
+ case SASL_NOMECH:
+ rc = LDAP_AUTH_UNKNOWN;
+ break;
+ case SASL_BADSERV:
+ rc = LDAP_CONNECT_ERROR;
+ break;
+ case SASL_DISABLED:
+ case SASL_ENCRYPT:
+ case SASL_EXPIRED:
+ case SASL_NOUSERPASS:
+ case SASL_NOVERIFY:
+ case SASL_PWLOCK:
+ case SASL_TOOWEAK:
+ case SASL_UNAVAIL:
+ case SASL_WEAKPASS:
+ rc = LDAP_INAPPROPRIATE_AUTH;
+ break;
+ case SASL_BADAUTH:
+ case SASL_NOAUTHZ:
+ rc = LDAP_INVALID_CREDENTIALS;
+ break;
+ case SASL_NOMEM:
+ rc = LDAP_NO_MEMORY;
+ break;
+ case SASL_NOUSER:
+ rc = LDAP_NO_SUCH_OBJECT;
+ break;
+ case SASL_CONTINUE:
+ case SASL_FAIL:
+ case SASL_INTERACT:
+ default:
+ rc = LDAP_LOCAL_ERROR;
+ break;
+ }
+
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+}
+
+int
+nsldapi_sasl_open(LDAP *ld)
+{
+ Sockbuf *sb;
+ char * host;
+ int saslrc;
+ sasl_conn_t *ctx;
+
+ if (ld == NULL) {
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ if (ld->ld_defconn == NULL) {
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+ sb = ld->ld_defconn->lconn_sb;
+ host = ld->ld_defhost;
+
+ if ( sb == NULL || host == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ /* SASL is not properly initialized */
+ mutex_lock(&sasl_mutex);
+ if (gctx == NULL) {
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ mutex_unlock(&sasl_mutex);
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ saslrc = _sasl_client_new(gctx, "ldap", host,
+ NULL, NULL, /* iplocal ipremote strings currently unused */
+ NULL, 0, &ctx );
+
+ if ( saslrc != SASL_OK ) {
+ mutex_unlock(&sasl_mutex);
+ return( nsldapi_sasl_cvterrno( ld, saslrc ) );
+ }
+
+ sb->sb_sasl_ctx = (void *)ctx;
+ mutex_unlock(&sasl_mutex);
+
+ return( LDAP_SUCCESS );
+}
+
+static int
+nsldapi_sasl_close( LDAP *ld, Sockbuf *sb )
+{
+ sasl_conn_t *ctx = (sasl_conn_t *)sb->sb_sasl_ctx;
+
+ if( ctx != NULL ) {
+ sasl_dispose( &ctx );
+ sb->sb_sasl_ctx = NULL;
+ }
+ return( LDAP_SUCCESS );
+}
+
+static int
+nsldapi_sasl_do_bind( LDAP *ld, const char *dn,
+ const char *mechs, unsigned flags,
+ LDAP_SASL_INTERACT_PROC *callback, void *defaults,
+ LDAPControl **sctrl, LDAPControl **cctrl )
+{
+ sasl_interact_t *prompts = NULL;
+ sasl_conn_t *ctx;
+ sasl_ssf_t *ssf = NULL;
+ const char *mech = NULL;
+ int saslrc, rc;
+ struct berval ccred;
+ unsigned credlen;
+
+ if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) {
+ LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+ return( LDAP_NOT_SUPPORTED );
+ }
+
+ /* shouldn't happen */
+ if (callback == NULL) {
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ if ( ld->ld_defconn == NULL ||
+ ld->ld_defconn->lconn_status != LDAP_CONNST_CONNECTED) {
+ rc = nsldapi_open_ldap_defconn( ld );
+ if( rc < 0 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+ }
+
+ /* should have a valid ld connection - now create sasl connection */
+ if ((rc = nsldapi_sasl_open(ld)) != LDAP_SUCCESS) {
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+ }
+
+ /* expect context to be initialized when connection is open */
+ ctx = (sasl_conn_t *)ld->ld_defconn->lconn_sb->sb_sasl_ctx;
+
+ if( ctx == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ /* (re)set security properties */
+ sasl_setprop( ctx, SASL_SEC_PROPS, &ld->ld_sasl_secprops );
+
+ ccred.bv_val = NULL;
+ ccred.bv_len = 0;
+
+ do {
+ saslrc = sasl_client_start( ctx,
+ mechs,
+ &prompts,
+ (const char **)&ccred.bv_val,
+ &credlen,
+ &mech );
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n",
+ (mech ? mech : ""), 0, 0 );
+
+ if( saslrc == SASL_INTERACT &&
+ (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) {
+ break;
+ }
+ } while ( saslrc == SASL_INTERACT );
+
+ ccred.bv_len = credlen;
+
+ if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
+ return( nsldapi_sasl_cvterrno( ld, saslrc ) );
+ }
+
+ do {
+ struct berval *scred;
+
+ scred = NULL;
+
+ /* notify server of a sasl bind step */
+ rc = ldap_sasl_bind_s(ld, dn, mech, &ccred,
+ sctrl, cctrl, &scred);
+
+ if ( ccred.bv_val != NULL ) {
+ ccred.bv_val = NULL;
+ }
+
+ if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
+ if( scred && scred->bv_len ) {
+ /* and server provided us with data? */
+ ber_bvfree( scred );
+ }
+ return( rc );
+ }
+
+ if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
+ /* we're done, no need to step */
+ if( scred && scred->bv_len ) {
+ /* but server provided us with data! */
+ ber_bvfree( scred );
+ LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR,
+ NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+ break;
+ }
+
+ /* perform the next step of the sasl bind */
+ do {
+ saslrc = sasl_client_step( ctx,
+ (scred == NULL) ? NULL : scred->bv_val,
+ (scred == NULL) ? 0 : scred->bv_len,
+ &prompts,
+ (const char **)&ccred.bv_val,
+ &credlen );
+
+ if( saslrc == SASL_INTERACT &&
+ (callback)(ld, flags, defaults, prompts)
+ != LDAP_SUCCESS ) {
+ break;
+ }
+ } while ( saslrc == SASL_INTERACT );
+
+ ccred.bv_len = credlen;
+ ber_bvfree( scred );
+
+ if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
+ return( nsldapi_sasl_cvterrno( ld, saslrc ) );
+ }
+ } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+
+ if ( saslrc != SASL_OK ) {
+ return( nsldapi_sasl_cvterrno( ld, saslrc ) );
+ }
+
+ saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
+ if( saslrc == SASL_OK ) {
+ rc = nsldapi_sasl_install(ld, ld->ld_conns->lconn_sb, ctx, ssf);
+ }
+
+ return( rc );
+}
+
+#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
+/*
+ * Get available SASL Mechanisms supported by the server
+ */
+
+static int
+nsldapi_get_sasl_mechs ( LDAP *ld, char **pmech )
+{
+ char *attr[] = { "supportedSASLMechanisms", NULL };
+ char **values, **v, *mech, *m;
+ LDAPMessage *res, *e;
+ struct timeval timeout;
+ int slen, rc;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+ timeout.tv_usec = 0;
+
+ rc = ldap_search_st( ld, "", LDAP_SCOPE_BASE,
+ "objectclass=*", attr, 0, &timeout, &res );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ e = ldap_first_entry( ld, res );
+ if ( e == NULL ) {
+ ldap_msgfree( res );
+ if ( ld->ld_errno == LDAP_SUCCESS ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_OBJECT, NULL, NULL );
+ }
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
+ if ( values == NULL ) {
+ ldap_msgfree( res );
+ LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL );
+ return( LDAP_NO_SUCH_ATTRIBUTE );
+ }
+
+ slen = 0;
+ for(v = values; *v != NULL; v++ ) {
+ slen += strlen(*v) + 1;
+ }
+ if ( (mech = NSLDAPI_CALLOC(1, slen)) == NULL) {
+ ldap_value_free( values );
+ ldap_msgfree( res );
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+ m = mech;
+ for(v = values; *v; v++) {
+ if (v != values) {
+ *m++ = ' ';
+ }
+ slen = strlen(*v);
+ strncpy(m, *v, slen);
+ m += slen;
+ }
+ *m = '\0';
+
+ ldap_value_free( values );
+ ldap_msgfree( res );
+
+ *pmech = mech;
+
+ return( LDAP_SUCCESS );
+}
+#endif
+
+int nsldapi_sasl_secprops(
+ const char *in,
+ sasl_security_properties_t *secprops )
+{
+ int i;
+ char **props = NULL;
+ char *inp;
+ unsigned sflags = 0;
+ sasl_ssf_t max_ssf = 0;
+ sasl_ssf_t min_ssf = 0;
+ unsigned maxbufsize = 0;
+ int got_sflags = 0;
+ int got_max_ssf = 0;
+ int got_min_ssf = 0;
+ int got_maxbufsize = 0;
+
+ if (in == NULL) {
+ return LDAP_PARAM_ERROR;
+ }
+ inp = nsldapi_strdup(in);
+ if (inp == NULL) {
+ return LDAP_PARAM_ERROR;
+ }
+ props = ldap_str2charray( inp, "," );
+ NSLDAPI_FREE( inp );
+
+ if( props == NULL || secprops == NULL ) {
+ return LDAP_PARAM_ERROR;
+ }
+
+ for( i=0; props[i]; i++ ) {
+ if( strcasecmp(props[i], "none") == 0 ) {
+ got_sflags++;
+
+ } else if( strcasecmp(props[i], "noactive") == 0 ) {
+ got_sflags++;
+ sflags |= SASL_SEC_NOACTIVE;
+
+ } else if( strcasecmp(props[i], "noanonymous") == 0 ) {
+ got_sflags++;
+ sflags |= SASL_SEC_NOANONYMOUS;
+
+ } else if( strcasecmp(props[i], "nodict") == 0 ) {
+ got_sflags++;
+ sflags |= SASL_SEC_NODICTIONARY;
+
+ } else if( strcasecmp(props[i], "noplain") == 0 ) {
+ got_sflags++;
+ sflags |= SASL_SEC_NOPLAINTEXT;
+
+ } else if( strcasecmp(props[i], "forwardsec") == 0 ) {
+ got_sflags++;
+ sflags |= SASL_SEC_FORWARD_SECRECY;
+
+ } else if( strcasecmp(props[i], "passcred") == 0 ) {
+ got_sflags++;
+ sflags |= SASL_SEC_PASS_CREDENTIALS;
+
+ } else if( strncasecmp(props[i],
+ "minssf=", sizeof("minssf")) == 0 ) {
+ if( isdigit( props[i][sizeof("minssf")] ) ) {
+ got_min_ssf++;
+ min_ssf = atoi( &props[i][sizeof("minssf")] );
+ } else {
+ return LDAP_NOT_SUPPORTED;
+ }
+
+ } else if( strncasecmp(props[i],
+ "maxssf=", sizeof("maxssf")) == 0 ) {
+ if( isdigit( props[i][sizeof("maxssf")] ) ) {
+ got_max_ssf++;
+ max_ssf = atoi( &props[i][sizeof("maxssf")] );
+ } else {
+ return LDAP_NOT_SUPPORTED;
+ }
+
+ } else if( strncasecmp(props[i],
+ "maxbufsize=", sizeof("maxbufsize")) == 0 ) {
+ if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
+ got_maxbufsize++;
+ maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
+ if( maxbufsize &&
+ (( maxbufsize < SASL_MIN_BUFF_SIZE )
+ || (maxbufsize > SASL_MAX_BUFF_SIZE ))) {
+ return( LDAP_PARAM_ERROR );
+ }
+ } else {
+ return( LDAP_NOT_SUPPORTED );
+ }
+ } else {
+ return( LDAP_NOT_SUPPORTED );
+ }
+ }
+
+ if(got_sflags) {
+ secprops->security_flags = sflags;
+ }
+ if(got_min_ssf) {
+ secprops->min_ssf = min_ssf;
+ }
+ if(got_max_ssf) {
+ secprops->max_ssf = max_ssf;
+ }
+ if(got_maxbufsize) {
+ secprops->maxbufsize = maxbufsize;
+ }
+
+ ldap_charray_free( props );
+ return( LDAP_SUCCESS );
+}
+
+/*
+ * SASL Authentication Interface: ldap_sasl_interactive_bind_s
+ *
+ * This routine takes a DN, SASL mech list, and a SASL callback
+ * and performs the necessary sequencing to complete a SASL bind
+ * to the LDAP connection ld. The user provided callback can
+ * use an optionally provided set of default values to complete
+ * any necessary interactions.
+ *
+ * Currently inpose the following restrictions:
+ * A mech list must be provided, only LDAP_SASL_INTERACTIVE
+ * mode is supported
+ */
+int
+LDAP_CALL
+ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn,
+ const char *saslMechanism,
+ LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
+ LDAP_SASL_INTERACT_PROC *callback, void *defaults )
+{
+#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
+ char *smechs;
+#endif
+ int rc;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind_s\n", 0, 0, 0);
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if (flags != LDAP_SASL_INTERACTIVE || callback == NULL) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ LDAP_MUTEX_LOCK(ld, LDAP_SASL_LOCK );
+
+ if( saslMechanism == NULL || *saslMechanism == '\0' ) {
+#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
+ rc = nsldapi_get_sasl_mechs( ld, &smechs );
+ if( rc != LDAP_SUCCESS ) {
+ LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
+ return( rc );
+ }
+ saslMechanism = smechs;
+#else
+ LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
+ return( LDAP_PARAM_ERROR );
+#endif
+ }
+
+ /* initialize SASL library */
+ if ( nsldapi_sasl_init() < 0 ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ rc = nsldapi_sasl_do_bind( ld, dn, saslMechanism,
+ flags, callback, defaults, sctrl, cctrl);
+
+ LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
+ return( rc );
+}
+
+#endif
diff --git a/usr/src/lib/libldap5/sources/ldap/common/saslbind.c b/usr/src/lib/libldap5/sources/ldap/common/saslbind.c
new file mode 100644
index 0000000000..044602d6b3
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/saslbind.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+#include "ldap-int.h"
+
+/*
+ * ldap_sasl_bind - authenticate to the ldap server. The dn, mechanism,
+ * and credentials of the entry to which to bind are supplied. An LDAP
+ * error code is returned and if LDAP_SUCCESS is returned *msgidp is set
+ * to the id of the request initiated.
+ *
+ * Example:
+ * struct berval creds;
+ * LDAPControl **ctrls;
+ * int err, msgid;
+ * ... fill in creds with credentials ...
+ * ... fill in ctrls with server controls ...
+ * err = ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us",
+ * "mechanismname", &creds, ctrls, NULL, &msgid );
+ */
+int
+LDAP_CALL
+ldap_sasl_bind(
+ LDAP *ld,
+ const char *dn,
+ const char *mechanism,
+ const struct berval *cred,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ int *msgidp
+)
+{
+ BerElement *ber;
+ int rc, simple, msgid, ldapversion;
+
+ /*
+ * The ldapv3 bind request looks like this:
+ * BindRequest ::= SEQUENCE {
+ * version INTEGER,
+ * name DistinguishedName, -- who
+ * authentication CHOICE {
+ * simple [0] OCTET STRING, -- passwd
+ * sasl [3] SaslCredentials -- v3 only
+ * }
+ * }
+ * SaslCredentials ::= SEQUENCE {
+ * mechanism LDAPString,
+ * credentials OCTET STRING
+ * }
+ * all wrapped up in an LDAPMessage sequence.
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
+
+ if ( msgidp == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ simple = ( mechanism == LDAP_SASL_SIMPLE );
+ ldapversion = NSLDAPI_LDAP_VERSION( ld );
+
+ /* only ldapv3 or higher can do sasl binds */
+ if ( !simple && ldapversion < LDAP_VERSION3 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+ return( LDAP_NOT_SUPPORTED );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ msgid = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ if ( dn == NULL )
+ dn = "";
+
+ if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn,
+ cred, LDAP_AUTH_SASL )) != 0 ) {
+ *msgidp = rc;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+
+ /* create a message to send */
+ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( rc );
+ }
+
+ /* fill it in */
+ if ( simple ) { /* simple bind; works in LDAPv2 or v3 */
+ struct berval tmpcred;
+
+ if ( cred == NULL ) {
+ tmpcred.bv_val = "";
+ tmpcred.bv_len = 0;
+ cred = &tmpcred;
+ }
+ rc = ber_printf( ber, "{it{isto}", msgid, LDAP_REQ_BIND,
+ ldapversion, dn, LDAP_AUTH_SIMPLE, cred->bv_val,
+ (int)cred->bv_len /* XXX lossy cast */ );
+
+ } else { /* SASL bind; requires LDAPv3 or better */
+ if ( cred == NULL ) {
+ rc = ber_printf( ber, "{it{ist{s}}", msgid,
+ LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL,
+ mechanism );
+ } else {
+ rc = ber_printf( ber, "{it{ist{so}}", msgid,
+ LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL,
+ mechanism, cred->bv_val,
+ (int)cred->bv_len /* XXX lossy cast */ );
+ }
+ }
+
+ if ( rc == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ if ( (rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( rc );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND,
+ (char *)dn, ber );
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+/*
+ * ldap_sasl_bind_s - bind to the ldap server using sasl authentication
+ * The dn, mechanism, and credentials of the entry to which to bind are
+ * supplied. LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ *
+ * Example:
+ * struct berval creds;
+ * ... fill in creds with credentials ...
+ * ldap_sasl_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ * "mechanismname", &creds )
+ */
+int
+LDAP_CALL
+ldap_sasl_bind_s(
+ LDAP *ld,
+ const char *dn,
+ const char *mechanism,
+ const struct berval *cred,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ struct berval **servercredp
+)
+{
+ int err, msgid;
+ LDAPMessage *result;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 );
+
+ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+ return( LDAP_NOT_SUPPORTED );
+ }
+
+ if ( ( err = ldap_sasl_bind( ld, dn, mechanism, cred, serverctrls,
+ clientctrls, &msgid )) != LDAP_SUCCESS )
+ return( err );
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 )
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+ err = ldap_parse_sasl_bind_result( ld, result, servercredp, 0 );
+ if (err != LDAP_SUCCESS && err != LDAP_SASL_BIND_IN_PROGRESS) {
+ ldap_msgfree( result );
+ return( err );
+ }
+
+ return( ldap_result2error( ld, result, 1 ) );
+}
+
+
+/* returns an LDAP error code that indicates if parse succeeded or not */
+int
+LDAP_CALL
+ldap_parse_sasl_bind_result(
+ LDAP *ld,
+ LDAPMessage *res,
+ struct berval **servercredp,
+ int freeit
+)
+{
+ BerElement ber;
+ int rc, err;
+ ber_int_t along;
+ ber_len_t len;
+ char *m, *e;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
+
+ /*
+ * the ldapv3 SASL bind response looks like this:
+ *
+ * BindResponse ::= [APPLICATION 1] SEQUENCE {
+ * COMPONENTS OF LDAPResult,
+ * serverSaslCreds [7] OCTET STRING OPTIONAL
+ * }
+ *
+ * all wrapped up in an LDAPMessage sequence.
+ */
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
+ !NSLDAPI_VALID_LDAPMESSAGE_BINDRESULT_POINTER( res )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /* only ldapv3 or higher can do sasl binds */
+ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+ return( LDAP_NOT_SUPPORTED );
+ }
+
+ if ( servercredp != NULL ) {
+ *servercredp = NULL;
+ }
+
+ ber = *(res->lm_ber); /* struct copy */
+
+ /* skip past message id, matched dn, error message ... */
+ rc = ber_scanf( &ber, "{iaa}", &along, &m, &e );
+
+ if ( rc != LBER_ERROR &&
+ ber_peek_tag( &ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) {
+ rc = ber_get_stringal( &ber, servercredp );
+ }
+
+ if ( freeit ) {
+ ldap_msgfree( res );
+ }
+
+ if ( rc == LBER_ERROR ) {
+ err = LDAP_DECODING_ERROR;
+ } else {
+ err = (int) along;
+ }
+
+ LDAP_SET_LDERRNO( ld, err, m, e );
+ /* this is a little kludge for the 3.0 Barracuda/hammerhead relese */
+ /* the docs state that the return is either LDAP_DECODING_ERROR */
+ /* or LDAP_SUCCESS. Here we match the docs... it's cleaner in 3.1 */
+
+ if ( LDAP_DECODING_ERROR == err ) {
+ return (LDAP_DECODING_ERROR);
+ } else {
+ return( LDAP_SUCCESS );
+ }
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/sbind.c b/usr/src/lib/libldap5/sources/ldap/common/sbind.c
new file mode 100644
index 0000000000..5a467c53b9
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/sbind.c
@@ -0,0 +1,264 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * sbind.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static int simple_bind_nolock( LDAP *ld, const char *dn, const char *passwd,
+ int unlock_permitted );
+static int simple_bindifnot_s( LDAP *ld, const char *dn, const char *passwd );
+
+/*
+ * ldap_simple_bind - bind to the ldap server. The dn and
+ * password of the entry to which to bind are supplied. The message id
+ * of the request initiated is returned.
+ *
+ * Example:
+ * ldap_simple_bind( ld, "cn=manager, o=university of michigan, c=us",
+ * "secret" )
+ */
+
+int
+LDAP_CALL
+ldap_simple_bind( LDAP *ld, const char *dn, const char *passwd )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 );
+ }
+
+ rc = simple_bind_nolock( ld, dn, passwd, 1 );
+
+ return( rc );
+}
+
+
+static int
+simple_bind_nolock( LDAP *ld, const char *dn, const char *passwd,
+ int unlock_permitted )
+{
+ BerElement *ber;
+ int rc, msgid;
+
+ /*
+ * The bind request looks like this:
+ * BindRequest ::= SEQUENCE {
+ * version INTEGER,
+ * name DistinguishedName, -- who
+ * authentication CHOICE {
+ * simple [0] OCTET STRING -- passwd
+ * }
+ * }
+ * all wrapped up in an LDAPMessage sequence.
+ */
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ msgid = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ if ( dn == NULL )
+ dn = "";
+ if ( passwd == NULL )
+ passwd = "";
+
+ if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) {
+ struct berval bv;
+
+ bv.bv_val = (char *)passwd;
+ bv.bv_len = strlen( passwd );
+ /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn, &bv,
+ LDAP_AUTH_SIMPLE );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
+ if ( rc != 0 ) {
+ return( rc );
+ }
+ }
+
+ /* create a message to send */
+ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+
+ /* fill it in */
+ if ( ber_printf( ber, "{it{ists}", msgid, LDAP_REQ_BIND,
+ NSLDAPI_LDAP_VERSION( ld ), dn, LDAP_AUTH_SIMPLE, passwd ) == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( -1 );
+ }
+
+ if ( nsldapi_put_controls( ld, NULL, 1, ber ) != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( -1 );
+ }
+
+ /* send the message */
+ return( nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND,
+ (char *)dn, ber ));
+}
+
+
+/*
+ * ldap_simple_bind - bind to the ldap server using simple
+ * authentication. The dn and password of the entry to which to bind are
+ * supplied. LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ *
+ * Example:
+ * ldap_simple_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ * "secret" )
+ */
+int
+LDAP_CALL
+ldap_simple_bind_s( LDAP *ld, const char *dn, const char *passwd )
+{
+ int msgid;
+ LDAPMessage *result;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n", 0, 0, 0 );
+
+ if ( NSLDAPI_VALID_LDAP_POINTER( ld ) &&
+ ( ld->ld_options & LDAP_BITOPT_RECONNECT ) != 0 ) {
+ return( simple_bindifnot_s( ld, dn, passwd ));
+ }
+
+ if ( (msgid = ldap_simple_bind( ld, dn, passwd )) == -1 )
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 )
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+ return( ldap_result2error( ld, result, 1 ) );
+}
+
+
+/*
+ * simple_bindifnot_s() is like ldap_simple_bind_s() except that it only does
+ * a bind if the default connection is not currently bound.
+ * If a successful bind using the same DN has already taken place we just
+ * return LDAP_SUCCESS without conversing with the server at all.
+ */
+static int
+simple_bindifnot_s( LDAP *ld, const char *dn, const char *passwd )
+{
+ int msgid, rc;
+ LDAPMessage *result;
+ char *binddn;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "simple_bindifnot_s\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( dn == NULL ) {
+ dn = ""; /* to make comparisons simpler */
+ }
+
+ /*
+ * if we are already bound using the same DN, just return LDAP_SUCCESS.
+ */
+ if ( NULL != ( binddn = nsldapi_get_binddn( ld ))
+ && 0 == strcmp( dn, binddn )) {
+ rc = LDAP_SUCCESS;
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return rc;
+ }
+
+ /*
+ * if the default connection has been lost and is now marked dead,
+ * dispose of the default connection so it will get re-established.
+ *
+ * if not, clear the bind DN and status to ensure that we don't
+ * report the wrong bind DN to a different thread while waiting
+ * for our bind result to return from the server.
+ */
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ if ( NULL != ld->ld_defconn ) {
+ if ( LDAP_CONNST_DEAD == ld->ld_defconn->lconn_status ) {
+ nsldapi_free_connection( ld, ld->ld_defconn, NULL, NULL, 1, 0 );
+ ld->ld_defconn = NULL;
+ } else if ( ld->ld_defconn->lconn_binddn != NULL ) {
+ NSLDAPI_FREE( ld->ld_defconn->lconn_binddn );
+ ld->ld_defconn->lconn_binddn = NULL;
+ ld->ld_defconn->lconn_bound = 0;
+ }
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+ /*
+ * finally, bind (this will open a new connection if necessary)
+ *
+ * do everything under the protection of the result lock to
+ * ensure that only one thread will be in this code at a time.
+ * XXXmcs: we should use a condition variable instead?
+ */
+ LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
+ if ( (msgid = simple_bind_nolock( ld, dn, passwd, 0 )) == -1 ) {
+ rc = LDAP_GET_LDERRNO( ld, NULL, NULL );
+ goto unlock_and_return;
+ }
+
+ /*
+ * Note that at this point the bind request is on its way to the
+ * server and at any time now we will either be bound as the new
+ * DN (if the bind succeeded) or we will be bound as anonymous (if
+ * the bind failed).
+ */
+
+ /*
+ * Wait for the bind result. Code inside result.c:read1msg()
+ * takes care of setting the connection's bind DN and status.
+ */
+ if ( nsldapi_result_nolock( ld, msgid, 1, 0, (struct timeval *) 0,
+ &result ) == -1 ) {
+ rc = LDAP_GET_LDERRNO( ld, NULL, NULL );
+ goto unlock_and_return;
+ }
+
+ rc = ldap_result2error( ld, result, 1 );
+
+unlock_and_return:
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
+ return( rc );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/search.c b/usr/src/lib/libldap5/sources/ldap/common/search.c
new file mode 100644
index 0000000000..1235234f8b
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/search.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * search.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static int nsldapi_timeval2ldaplimit( struct timeval *timeoutp,
+ int defaultvalue );
+static int nsldapi_search( LDAP *ld, const char *base, int scope,
+ const char *filter, char **attrs, int attrsonly,
+ LDAPControl **serverctrls, LDAPControl **clientctrls,
+ int timelimit, int sizelimit, int *msgidp );
+static char *find_right_paren( char *s );
+static char *put_complex_filter( BerElement *ber, char *str,
+ ber_tag_t tag, int not );
+static int unescape_filterval( char *str );
+static int hexchar2int( char c );
+static int is_valid_attr( char *a );
+static int put_simple_filter( BerElement *ber, char *str );
+static int put_substring_filter( BerElement *ber, char *type,
+ char *str );
+static int put_filter_list( BerElement *ber, char *str );
+static int nsldapi_search_s( LDAP *ld, const char *base, int scope,
+ const char *filter, char **attrs, int attrsonly,
+ LDAPControl **serverctrls, LDAPControl **clientctrls,
+ struct timeval *localtimeoutp, int timelimit, int sizelimit,
+ LDAPMessage **res );
+
+/*
+ * ldap_search - initiate an ldap search operation. Parameters:
+ *
+ * ld LDAP descriptor
+ * base DN of the base object
+ * scope the search scope - one of LDAP_SCOPE_BASE,
+ * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
+ * filter a string containing the search filter
+ * (e.g., "(|(cn=bob)(sn=bob))")
+ * attrs list of attribute types to return for matches
+ * attrsonly 1 => attributes only 0 => attributes and values
+ *
+ * Example:
+ * char *attrs[] = { "mail", "title", 0 };
+ * msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
+ * attrs, attrsonly );
+ */
+int
+LDAP_CALL
+ldap_search(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly
+)
+{
+ int msgid;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
+
+ if ( ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, NULL,
+ NULL, NULL, -1, &msgid ) == LDAP_SUCCESS ) {
+ return( msgid );
+ } else {
+ return( -1 ); /* error is in ld handle */
+ }
+}
+
+
+/*
+ * LDAPv3 extended search.
+ * Returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_search_ext(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ struct timeval *timeoutp, /* NULL means use ld->ld_timelimit */
+ int sizelimit,
+ int *msgidp
+)
+{
+ /*
+ * It is an error to pass in a zero'd timeval.
+ */
+ if ( timeoutp != NULL && timeoutp->tv_sec == 0 &&
+ timeoutp->tv_usec == 0 ) {
+ if ( ld != NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ }
+ return( LDAP_PARAM_ERROR );
+ }
+
+ return( nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
+ serverctrls, clientctrls,
+ nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, msgidp ));
+}
+
+
+/*
+ * Like ldap_search_ext() except an integer timelimit is passed instead of
+ * using the overloaded struct timeval *timeoutp.
+ */
+static int
+nsldapi_search(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ int timelimit, /* -1 means use ld->ld_timelimit */
+ int sizelimit, /* -1 means use ld->ld_sizelimit */
+ int *msgidp
+)
+{
+ BerElement *ber;
+ int rc, rc_key;
+ unsigned long key; /* XXXmcs: memcache */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( base == NULL ) {
+ base = "";
+ }
+
+ if ( filter == NULL ) {
+ filter = "(objectclass=*)";
+ }
+
+ if ( msgidp == NULL || ( scope != LDAP_SCOPE_BASE
+ && scope != LDAP_SCOPE_ONELEVEL && scope != LDAP_SCOPE_SUBTREE )
+ || ( sizelimit < -1 )) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ *msgidp = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ /*
+ * XXXmcs: should use cache function pointers to hook in memcache
+ */
+ if ( ld->ld_memcache == NULL ) {
+ rc_key = LDAP_NOT_SUPPORTED;
+ } else if (( rc_key = ldap_memcache_createkey( ld, base, scope, filter,
+ attrs, attrsonly, serverctrls, clientctrls, &key)) == LDAP_SUCCESS
+ && ldap_memcache_result( ld, *msgidp, key ) == LDAP_SUCCESS ) {
+ return LDAP_SUCCESS;
+ }
+
+ /* check the cache */
+ if ( ld->ld_cache_on && ld->ld_cache_search != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ if ( (rc = (ld->ld_cache_search)( ld, *msgidp, LDAP_REQ_SEARCH,
+ base, scope, filter, attrs, attrsonly )) != 0 ) {
+ *msgidp = rc;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ return( LDAP_SUCCESS );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+
+ /* caching off or did not find it in the cache - check the net */
+ if (( rc = nsldapi_build_search_req( ld, base, scope, filter, attrs,
+ attrsonly, serverctrls, clientctrls, timelimit, sizelimit,
+ *msgidp, &ber )) != LDAP_SUCCESS ) {
+ return( rc );
+ }
+
+ /* send the message */
+ rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_SEARCH,
+ (char *) base, ber );
+
+ /*
+ * XXXmcs: should use cache function pointers to hook in memcache
+ */
+ if ( (rc_key == LDAP_SUCCESS) && (rc >= 0) ) {
+ ldap_memcache_new( ld, rc, key, base );
+ }
+
+ *msgidp = rc;
+ return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+
+/*
+ * Convert a non-NULL timeoutp to a value in seconds that is appropriate to
+ * send in an LDAP search request. If timeoutp is NULL, return defaultvalue.
+ */
+static int
+nsldapi_timeval2ldaplimit( struct timeval *timeoutp, int defaultvalue )
+{
+ int timelimit;
+
+ if ( NULL == timeoutp ) {
+ timelimit = defaultvalue;
+ } else if ( timeoutp->tv_sec > 0 ) {
+ timelimit = timeoutp->tv_sec;
+ } else if ( timeoutp->tv_usec > 0 ) {
+ timelimit = 1; /* minimum we can express in LDAP */
+ } else {
+ /*
+ * both tv_sec and tv_usec are less than one (zero?) so
+ * to maintain compatiblity with our "zero means no limit"
+ * convention we pass no limit to the server.
+ */
+ timelimit = 0; /* no limit */
+ }
+
+ return( timelimit );
+}
+
+
+/* returns an LDAP error code and also sets it in ld */
+int
+nsldapi_build_search_req(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls, /* not used for anything yet */
+ int timelimit, /* if -1, ld->ld_timelimit is used */
+ int sizelimit, /* if -1, ld->ld_sizelimit is used */
+ int msgid,
+ BerElement **berp
+)
+{
+ BerElement *ber;
+ int err;
+ char *fdup;
+
+ /*
+ * Create the search request. It looks like this:
+ * SearchRequest := [APPLICATION 3] SEQUENCE {
+ * baseObject DistinguishedName,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefaliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizelimit INTEGER (0 .. 65535),
+ * timelimit INTEGER (0 .. 65535),
+ * attrsOnly BOOLEAN,
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ * wrapped in an ldap message.
+ */
+
+ /* create a message to send */
+ if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ if ( base == NULL ) {
+ base = "";
+ }
+
+ if ( sizelimit == -1 ) {
+ sizelimit = ld->ld_sizelimit;
+ }
+
+ if ( timelimit == -1 ) {
+ timelimit = ld->ld_timelimit;
+ }
+
+#ifdef CLDAP
+ if ( ld->ld_sbp->sb_naddr > 0 ) {
+ err = ber_printf( ber, "{ist{seeiib", msgid,
+ ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
+ sizelimit, timelimit, attrsonly );
+ } else {
+#endif /* CLDAP */
+ err = ber_printf( ber, "{it{seeiib", msgid,
+ LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
+ sizelimit, timelimit, attrsonly );
+#ifdef CLDAP
+ }
+#endif /* CLDAP */
+
+ if ( err == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ fdup = nsldapi_strdup( filter );
+ if (fdup == NULL) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_NO_MEMORY );
+ }
+ err = ldap_put_filter( ber, fdup );
+ NSLDAPI_FREE( fdup );
+
+ if ( err == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_FILTER_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_FILTER_ERROR );
+ }
+
+ if ( ber_printf( ber, "{v}}", attrs ) == -1 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ if ( (err = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( err );
+ }
+
+ *berp = ber;
+ return( LDAP_SUCCESS );
+}
+
+static char *
+find_right_paren( char *s )
+{
+ int balance, escape;
+
+ balance = 1;
+ escape = 0;
+ while ( *s && balance ) {
+ if ( escape == 0 ) {
+ if ( *s == '(' )
+ balance++;
+ else if ( *s == ')' )
+ balance--;
+ }
+ if ( *s == '\\' && ! escape )
+ escape = 1;
+ else
+ escape = 0;
+ if ( balance )
+ s++;
+ }
+
+ return( *s ? s : NULL );
+}
+
+static char *
+put_complex_filter(
+ BerElement *ber,
+ char *str,
+ ber_tag_t tag,
+ int not
+)
+{
+ char *next;
+
+ /*
+ * We have (x(filter)...) with str sitting on
+ * the x. We have to find the paren matching
+ * the one before the x and put the intervening
+ * filters by calling put_filter_list().
+ */
+
+ /* put explicit tag */
+ if ( ber_printf( ber, "t{", tag ) == -1 )
+ return( NULL );
+
+ str++;
+ if ( (next = find_right_paren( str )) == NULL )
+ return( NULL );
+
+ *next = '\0';
+ if ( put_filter_list( ber, str ) == -1 )
+ return( NULL );
+ *next++ = ')';
+
+ /* flush explicit tagged thang */
+ if ( ber_printf( ber, "}" ) == -1 )
+ return( NULL );
+
+ return( next );
+}
+
+int
+ldap_put_filter( BerElement *ber, char *str )
+{
+ char *next;
+ int parens, balance, escape;
+
+ /*
+ * A Filter looks like this:
+ * Filter ::= CHOICE {
+ * and [0] SET OF Filter,
+ * or [1] SET OF Filter,
+ * not [2] Filter,
+ * equalityMatch [3] AttributeValueAssertion,
+ * substrings [4] SubstringFilter,
+ * greaterOrEqual [5] AttributeValueAssertion,
+ * lessOrEqual [6] AttributeValueAssertion,
+ * present [7] AttributeType,,
+ * approxMatch [8] AttributeValueAssertion
+ * }
+ *
+ * SubstringFilter ::= SEQUENCE {
+ * type AttributeType,
+ * SEQUENCE OF CHOICE {
+ * initial [0] IA5String,
+ * any [1] IA5String,
+ * final [2] IA5String
+ * }
+ * }
+ * Note: tags in a choice are always explicit
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
+
+ parens = 0;
+ while ( *str ) {
+ switch ( *str ) {
+ case '(':
+ str++;
+ parens++;
+ switch ( *str ) {
+ case '&':
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
+ 0, 0, 0 );
+
+ if ( (str = put_complex_filter( ber, str,
+ LDAP_FILTER_AND, 0 )) == NULL )
+ return( -1 );
+
+ parens--;
+ break;
+
+ case '|':
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
+ 0, 0, 0 );
+
+ if ( (str = put_complex_filter( ber, str,
+ LDAP_FILTER_OR, 0 )) == NULL )
+ return( -1 );
+
+ parens--;
+ break;
+
+ case '!':
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
+ 0, 0, 0 );
+
+ if ( (str = put_complex_filter( ber, str,
+ LDAP_FILTER_NOT, 1 )) == NULL )
+ return( -1 );
+
+ parens--;
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "put_filter: simple\n", 0, 0, 0 );
+
+ balance = 1;
+ escape = 0;
+ next = str;
+ while ( *next && balance ) {
+ if ( escape == 0 ) {
+ if ( *next == '(' )
+ balance++;
+ else if ( *next == ')' )
+ balance--;
+ }
+ if ( *next == '\\' && ! escape )
+ escape = 1;
+ else
+ escape = 0;
+ if ( balance )
+ next++;
+ }
+ if ( balance != 0 )
+ return( -1 );
+
+ *next = '\0';
+ if ( put_simple_filter( ber, str ) == -1 ) {
+ return( -1 );
+ }
+ *next++ = ')';
+ str = next;
+ parens--;
+ break;
+ }
+ break;
+
+ case ')':
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
+ 0 );
+ if ( ber_printf( ber, "]" ) == -1 )
+ return( -1 );
+ str++;
+ parens--;
+ break;
+
+ case ' ':
+ str++;
+ break;
+
+ default: /* assume it's a simple type=value filter */
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
+ 0 );
+ next = strchr( str, '\0' );
+ if ( put_simple_filter( ber, str ) == -1 ) {
+ return( -1 );
+ }
+ str = next;
+ break;
+ }
+ }
+
+ return( parens ? -1 : 0 );
+}
+
+
+/*
+ * Put a list of filters like this "(filter1)(filter2)..."
+ */
+
+static int
+put_filter_list( BerElement *ber, char *str )
+{
+ char *next;
+ char save;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
+
+ while ( *str ) {
+ while ( *str && isspace( *str ) )
+ str++;
+ if ( *str == '\0' )
+ break;
+
+ if ( (next = find_right_paren( str + 1 )) == NULL )
+ return( -1 );
+ save = *++next;
+
+ /* now we have "(filter)" with str pointing to it */
+ *next = '\0';
+ if ( ldap_put_filter( ber, str ) == -1 )
+ return( -1 );
+ *next = save;
+
+ str = next;
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
+ * of a filter expression, 0 otherwise. A valid string may contain only
+ * letters, numbers, hyphens, semi-colons, colons and periods. examples:
+ * cn
+ * cn;lang-fr
+ * 1.2.3.4;binary;dynamic
+ * mail;dynamic
+ * cn:dn:1.2.3.4
+ *
+ * For compatibility with older servers, we also allow underscores in
+ * attribute types, even through they are not allowed by the LDAPv3 RFCs.
+ */
+static int
+is_valid_attr( char *a )
+{
+ for ( ; *a; a++ ) {
+ if ( !isascii( *a ) ) {
+ return( 0 );
+ } else if ( !isalnum( *a ) ) {
+ switch ( *a ) {
+ case '-':
+ case '.':
+ case ';':
+ case ':':
+ case '_':
+ break; /* valid */
+ default:
+ return( 0 );
+ }
+ }
+ }
+
+ return( 1 );
+}
+
+static char *
+find_star( char *s )
+{
+ for ( ; *s; ++s ) {
+ switch ( *s ) {
+ case '*': return s;
+ case '\\':
+ ++s;
+ if ( hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0 ) ++s;
+ default: break;
+ }
+ }
+ return NULL;
+}
+
+static int
+put_simple_filter( BerElement *ber, char *str )
+{
+ char *s, *s2, *s3, filterop;
+ char *value;
+ ber_uint_t ftype;
+ int rc, len;
+ char *oid; /* for v3 extended filter */
+ int dnattr; /* for v3 extended filter */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
+
+ rc = -1; /* pessimistic */
+
+ if (( str = nsldapi_strdup( str )) == NULL ) {
+ return( rc );
+ }
+
+ if ( (s = strchr( str, '=' )) == NULL ) {
+ goto free_and_return;
+ }
+ value = s + 1;
+ *s-- = '\0';
+ filterop = *s;
+ if ( filterop == '<' || filterop == '>' || filterop == '~' ||
+ filterop == ':' ) {
+ *s = '\0';
+ }
+
+ if ( ! is_valid_attr( str ) ) {
+ goto free_and_return;
+ }
+
+ switch ( filterop ) {
+ case '<':
+ ftype = LDAP_FILTER_LE;
+ break;
+ case '>':
+ ftype = LDAP_FILTER_GE;
+ break;
+ case '~':
+ ftype = LDAP_FILTER_APPROX;
+ break;
+ case ':': /* extended filter - v3 only */
+ /*
+ * extended filter looks like this:
+ *
+ * [type][':dn'][':'oid]':='value
+ *
+ * where one of type or :oid is required.
+ *
+ */
+ ftype = LDAP_FILTER_EXTENDED;
+ s2 = s3 = NULL;
+ if ( (s2 = strrchr( str, ':' )) == NULL ) {
+ goto free_and_return;
+ }
+ if ( strcasecmp( s2, ":dn" ) == 0 ) {
+ oid = NULL;
+ dnattr = 1;
+ *s2 = '\0';
+ } else {
+ oid = s2 + 1;
+ dnattr = 0;
+ *s2 = '\0';
+ if ( (s3 = strrchr( str, ':' )) != NULL ) {
+ if ( strcasecmp( s3, ":dn" ) == 0 ) {
+ dnattr = 1;
+ } else {
+ goto free_and_return;
+ }
+ *s3 = '\0';
+ }
+ }
+ if ( (rc = ber_printf( ber, "t{", ftype )) == -1 ) {
+ goto free_and_return;
+ }
+ if ( oid != NULL ) {
+ if ( (rc = ber_printf( ber, "ts", LDAP_TAG_MRA_OID,
+ oid )) == -1 ) {
+ goto free_and_return;
+ }
+ }
+ if ( *str != '\0' ) {
+ if ( (rc = ber_printf( ber, "ts",
+ LDAP_TAG_MRA_TYPE, str )) == -1 ) {
+ goto free_and_return;
+ }
+ }
+ if (( len = unescape_filterval( value )) < 0 ||
+ ( rc = ber_printf( ber, "totb}", LDAP_TAG_MRA_VALUE,
+ value, len, LDAP_TAG_MRA_DNATTRS, dnattr )) == -1 ) {
+ goto free_and_return;
+ }
+ rc = 0;
+ goto free_and_return;
+ /* break; */
+ default:
+ if ( find_star( value ) == NULL ) {
+ ftype = LDAP_FILTER_EQUALITY;
+ } else if ( strcmp( value, "*" ) == 0 ) {
+ ftype = LDAP_FILTER_PRESENT;
+ } else {
+ rc = put_substring_filter( ber, str, value );
+ goto free_and_return;
+ }
+ break;
+ }
+
+ if ( ftype == LDAP_FILTER_PRESENT ) {
+ rc = ber_printf( ber, "ts", ftype, str );
+ } else if (( len = unescape_filterval( value )) >= 0 ) {
+ rc = ber_printf( ber, "t{so}", ftype, str, value, len );
+ }
+ if ( rc != -1 ) {
+ rc = 0;
+ }
+
+free_and_return:
+ NSLDAPI_FREE( str );
+ return( rc );
+}
+
+
+/*
+ * Undo in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
+ * sequences within the null-terminated string 'val'. The resulting value
+ * may contain null characters.
+ *
+ * If 'val' contains invalid escape sequences we return -1.
+ * Otherwise the length of the unescaped value is returned.
+ */
+static int
+unescape_filterval( char *val )
+{
+ int escape, firstdigit, ival;
+ char *s, *d;
+
+ escape = 0;
+ for ( s = d = val; *s; s++ ) {
+ if ( escape ) {
+ /*
+ * first try LDAPv3 escape (hexadecimal) sequence
+ */
+ if (( ival = hexchar2int( *s )) < 0 ) {
+ if ( firstdigit ) {
+ /*
+ * LDAPv2 (RFC1960) escape sequence
+ */
+ *d++ = *s;
+ escape = 0;
+ } else {
+ return(-1);
+ }
+ }
+ if ( firstdigit ) {
+ *d = ( ival<<4 );
+ firstdigit = 0;
+ } else {
+ *d++ |= ival;
+ escape = 0;
+ }
+
+ } else if ( *s != '\\' ) {
+ *d++ = *s;
+ escape = 0;
+
+ } else {
+ escape = 1;
+ firstdigit = 1;
+ }
+ }
+
+ return( d - val );
+}
+
+
+/*
+ * convert character 'c' that represents a hexadecimal digit to an integer.
+ * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
+ * otherwise the converted value is returned.
+ */
+static int
+hexchar2int( char c )
+{
+ if ( c >= '0' && c <= '9' ) {
+ return( c - '0' );
+ }
+ if ( c >= 'A' && c <= 'F' ) {
+ return( c - 'A' + 10 );
+ }
+ if ( c >= 'a' && c <= 'f' ) {
+ return( c - 'a' + 10 );
+ }
+ return( -1 );
+}
+
+static int
+put_substring_filter( BerElement *ber, char *type, char *val )
+{
+ char *nextstar, gotstar = 0;
+ ber_uint_t ftype;
+ int len;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
+ val, 0 );
+
+ if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 ) {
+ return( -1 );
+ }
+
+ for ( ; val != NULL; val = nextstar ) {
+ if ( (nextstar = find_star( val )) != NULL ) {
+ *nextstar++ = '\0';
+ }
+
+ if ( gotstar == 0 ) {
+ ftype = LDAP_SUBSTRING_INITIAL;
+ } else if ( nextstar == NULL ) {
+ ftype = LDAP_SUBSTRING_FINAL;
+ } else {
+ ftype = LDAP_SUBSTRING_ANY;
+ }
+ if ( *val != '\0' ) {
+ if (( len = unescape_filterval( val )) < 0 ||
+ ber_printf( ber, "to", ftype, val, len ) == -1 ) {
+ return( -1 );
+ }
+ }
+
+ gotstar = 1;
+ }
+
+ if ( ber_printf( ber, "}}" ) == -1 ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+int
+LDAP_CALL
+ldap_search_st(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly,
+ struct timeval *timeout,
+ LDAPMessage **res
+)
+{
+ return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
+ NULL, NULL, timeout, -1, -1, res ));
+}
+
+int
+LDAP_CALL
+ldap_search_s(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly,
+ LDAPMessage **res
+)
+{
+ return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
+ NULL, NULL, NULL, -1, -1, res ));
+}
+
+int LDAP_CALL
+ldap_search_ext_s(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ struct timeval *timeoutp,
+ int sizelimit,
+ LDAPMessage **res
+)
+{
+ return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
+ serverctrls, clientctrls, timeoutp,
+ nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, res ));
+}
+
+
+static int
+nsldapi_search_s(
+ LDAP *ld,
+ const char *base,
+ int scope,
+ const char *filter,
+ char **attrs,
+ int attrsonly,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ struct timeval *localtimeoutp,
+ int timelimit, /* -1 means use ld->ld_timelimit */
+ int sizelimit, /* -1 means use ld->ld_sizelimit */
+ LDAPMessage **res
+)
+{
+ int err, msgid;
+
+ /*
+ * It is an error to pass in a zero'd timeval.
+ */
+ if ( localtimeoutp != NULL && localtimeoutp->tv_sec == 0 &&
+ localtimeoutp->tv_usec == 0 ) {
+ if ( ld != NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ }
+ if ( res != NULL ) {
+ *res = NULL;
+ }
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if (( err = nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
+ serverctrls, clientctrls, timelimit, sizelimit, &msgid ))
+ != LDAP_SUCCESS ) {
+ if ( res != NULL ) {
+ *res = NULL;
+ }
+ return( err );
+ }
+
+ if ( ldap_result( ld, msgid, 1, localtimeoutp, res ) == -1 ) {
+ /*
+ * Error. ldap_result() sets *res to NULL for us.
+ */
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) {
+ (void) ldap_abandon( ld, msgid );
+ err = LDAP_TIMEOUT;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ if ( res != NULL ) {
+ *res = NULL;
+ }
+ return( err );
+ }
+
+ return( ldap_result2error( ld, *res, 0 ) );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/secutil.c b/usr/src/lib/libldap5/sources/ldap/common/secutil.c
new file mode 100644
index 0000000000..7df5423e83
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/secutil.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+static char hexdig[] = "0123456789abcdef";
+
+char* hexa_print(char *aString, int aLen)
+{
+ char *res;
+ int i =0;
+
+ if ((res = (char *)calloc (aLen*2 + 1, 1 )) == NULL){
+ return (NULL);
+ }
+ for (;;){
+ if (aLen < 1)
+ break;
+ res[i] = hexdig[ ( *aString & 0xf0 ) >> 4 ];
+ res[i + 1] = hexdig[ *aString & 0x0f ];
+ i+= 2;
+ aLen--;
+ aString++;
+ }
+ return (res);
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/setoption.c b/usr/src/lib/libldap5/sources/ldap/common/setoption.c
new file mode 100644
index 0000000000..0988028f1c
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/setoption.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * setoption.c - ldap_set_option implementation
+ */
+
+#include "ldap-int.h"
+#ifdef _SOLARIS_SDK
+#include "solaris-priv.h"
+#endif
+
+extern int nsldapi_sasl_secprops(const char *in,
+ sasl_security_properties_t *secprops);
+
+#define LDAP_SETCLR_BITOPT(ld, bit, optdata) \
+ if (optdata != NULL) { \
+ (ld)->ld_options |= bit; \
+ } else { \
+ (ld)->ld_options &= ~bit; \
+ }
+
+
+int
+LDAP_CALL
+ldap_set_option(LDAP *ld, int option, const void *optdata)
+{
+ int rc, i;
+ char *matched, *errstr;
+
+ if (!nsldapi_initialized) {
+ nsldapi_initialize_defaults();
+ }
+
+ /*
+ * process global options (not associated with an LDAP session handle)
+ */
+ if (option == LDAP_OPT_MEMALLOC_FN_PTRS) {
+ struct lber_memalloc_fns memalloc_fns;
+
+ /* set libldap ones via a struct copy */
+ nsldapi_memalloc_fns = *((struct ldap_memalloc_fns *)optdata);
+
+ /* also set liblber memory allocation callbacks */
+ memalloc_fns.lbermem_malloc =
+ nsldapi_memalloc_fns.ldapmem_malloc;
+ memalloc_fns.lbermem_calloc =
+ nsldapi_memalloc_fns.ldapmem_calloc;
+ memalloc_fns.lbermem_realloc =
+ nsldapi_memalloc_fns.ldapmem_realloc;
+ memalloc_fns.lbermem_free =
+ nsldapi_memalloc_fns.ldapmem_free;
+ if (ber_set_option(NULL, LBER_OPT_MEMALLOC_FN_PTRS,
+ &memalloc_fns) != 0) {
+ return (-1);
+ }
+
+ return (0);
+ }
+ /*
+ * LDAP_OPT_DEBUG_LEVEL is global
+ */
+ if (LDAP_OPT_DEBUG_LEVEL == option) {
+#ifdef LDAP_DEBUG
+ ldap_debug = *((int *)optdata);
+#endif
+ return (0);
+ }
+
+ /*
+ * if ld is NULL, arrange to modify our default settings
+ */
+ if (ld == NULL) {
+ ld = &nsldapi_ld_defaults;
+#ifdef LDAP_DEBUG
+ ldap_debug = 0;
+#endif
+
+ }
+
+ /*
+ * process options that are associated with an LDAP session handle
+ */
+ if (!NSLDAPI_VALID_LDAP_POINTER(ld)) {
+ return (-1); /* punt */
+ }
+
+ rc = 0;
+ if (ld != &nsldapi_ld_defaults &&
+ option != LDAP_OPT_EXTRA_THREAD_FN_PTRS &&
+ option != LDAP_OPT_THREAD_FN_PTRS) {
+ LDAP_MUTEX_LOCK(ld, LDAP_OPTION_LOCK);
+ }
+ switch (option) {
+ /* options that can be turned on and off */
+#ifdef LDAP_DNS
+ case LDAP_OPT_DNS:
+ LDAP_SETCLR_BITOPT(ld, LDAP_BITOPT_DNS, optdata);
+ break;
+#endif
+
+ case LDAP_OPT_REFERRALS:
+ LDAP_SETCLR_BITOPT(ld, LDAP_BITOPT_REFERRALS, optdata);
+ break;
+
+#ifdef LDAP_SSLIO_HOOKS
+ case LDAP_OPT_SSL:
+ LDAP_SETCLR_BITOPT(ld, LDAP_BITOPT_SSL, optdata);
+ break;
+#endif
+
+ case LDAP_OPT_RESTART:
+ LDAP_SETCLR_BITOPT(ld, LDAP_BITOPT_RESTART, optdata);
+ break;
+
+ case LDAP_OPT_RECONNECT:
+ LDAP_SETCLR_BITOPT(ld, LDAP_BITOPT_RECONNECT, optdata);
+ break;
+
+#ifdef LDAP_ASYNC_IO
+ case LDAP_OPT_ASYNC_CONNECT:
+ LDAP_SETCLR_BITOPT(ld, LDAP_BITOPT_ASYNC, optdata);
+ break;
+#endif /* LDAP_ASYNC_IO */
+
+ /* fields in the LDAP structure */
+ case LDAP_OPT_DEREF:
+ ld->ld_deref = *((int *)optdata);
+ break;
+ case LDAP_OPT_SIZELIMIT:
+ ld->ld_sizelimit = *((int *)optdata);
+ break;
+ case LDAP_OPT_TIMELIMIT:
+ ld->ld_timelimit = *((int *)optdata);
+ break;
+ case LDAP_OPT_REFERRAL_HOP_LIMIT:
+ ld->ld_refhoplimit = *((int *)optdata);
+ break;
+ case LDAP_OPT_PROTOCOL_VERSION:
+ ld->ld_version = *((int *)optdata);
+ if (ld->ld_defconn != NULL) { /* also set in default conn. */
+ ld->ld_defconn->lconn_version = ld->ld_version;
+ }
+ break;
+ case LDAP_OPT_SERVER_CONTROLS:
+ /* nsldapi_dup_controls returns -1 and sets lderrno on error */
+ rc = nsldapi_dup_controls(ld, &ld->ld_servercontrols,
+ (LDAPControl **)optdata);
+ break;
+ case LDAP_OPT_CLIENT_CONTROLS:
+ /* nsldapi_dup_controls returns -1 and sets lderrno on error */
+ rc = nsldapi_dup_controls(ld, &ld->ld_clientcontrols,
+ (LDAPControl **)optdata);
+ break;
+
+ /* rebind proc */
+ case LDAP_OPT_REBIND_FN:
+ ld->ld_rebind_fn = (LDAP_REBINDPROC_CALLBACK *) optdata;
+ break;
+ case LDAP_OPT_REBIND_ARG:
+ ld->ld_rebind_arg = (void *) optdata;
+ break;
+
+#ifdef LDAP_SSLIO_HOOKS
+ /* i/o function pointers */
+ case LDAP_OPT_IO_FN_PTRS:
+ if ((rc = nsldapi_install_compat_io_fns(ld,
+ (struct ldap_io_fns *)optdata)) != LDAP_SUCCESS) {
+ LDAP_SET_LDERRNO(ld, rc, NULL, NULL);
+ rc = -1;
+ }
+ break;
+
+ /* extended i/o function pointers */
+ case LDAP_X_OPT_EXTIO_FN_PTRS:
+ /* denotes use of old iofns struct (no writev) */
+ if (((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_size ==
+ LDAP_X_EXTIO_FNS_SIZE_REV0) {
+ ld->ld_extio_size = LDAP_X_EXTIO_FNS_SIZE;
+ ld->ld_extclose_fn =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_close;
+ ld->ld_extconnect_fn =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_connect;
+ ld->ld_extread_fn =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_read;
+ ld->ld_extwrite_fn =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_write;
+ ld->ld_extpoll_fn =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_poll;
+ ld->ld_extnewhandle_fn =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_newhandle;
+ ld->ld_extdisposehandle_fn =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->
+ lextiof_disposehandle;
+ ld->ld_ext_session_arg =
+ ((struct ldap_x_ext_io_fns_rev0 *)optdata)->lextiof_session_arg;
+ ld->ld_extwritev_fn = NULL;
+ if (ber_sockbuf_set_option(ld->ld_sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ &(ld->ld_ext_io_fns)) != 0) {
+ return (LDAP_LOCAL_ERROR);
+ }
+ } else {
+ /* struct copy */
+ ld->ld_ext_io_fns = *((struct ldap_x_ext_io_fns *)optdata);
+ }
+ if ((rc = nsldapi_install_lber_extiofns(ld, ld->ld_sbp))
+ != LDAP_SUCCESS) {
+ LDAP_SET_LDERRNO(ld, rc, NULL, NULL);
+ rc = -1;
+ }
+ break;
+#endif
+
+ /* thread function pointers */
+ case LDAP_OPT_THREAD_FN_PTRS:
+ /*
+ * It is only safe to set the thread function pointers
+ * when one thread is using the LDAP session handle.
+ */
+ /* free existing mutexes (some are allocated by ldap_init()) */
+ nsldapi_mutex_free_all(ld);
+
+ /* struct copy */
+ ld->ld_thread = *((struct ldap_thread_fns *)optdata);
+
+ /* allocate new mutexes */
+ nsldapi_mutex_alloc_all(ld);
+
+ /* LDAP_OPTION_LOCK was never locked... so just return */
+ return (rc);
+
+ /* extra thread function pointers */
+ case LDAP_OPT_EXTRA_THREAD_FN_PTRS:
+ /* The extra thread funcs will only pick up the threadid */
+ ld->ld_thread2 = *((struct ldap_extra_thread_fns *)optdata);
+
+ /* Reset the rest of the structure preserving the threadid fn */
+ ld->ld_mutex_trylock_fn = (LDAP_TF_MUTEX_TRYLOCK_CALLBACK *)NULL;
+ ld->ld_sema_alloc_fn = (LDAP_TF_SEMA_ALLOC_CALLBACK *) NULL;
+ ld->ld_sema_free_fn = (LDAP_TF_SEMA_FREE_CALLBACK *) NULL;
+ ld->ld_sema_wait_fn = (LDAP_TF_SEMA_WAIT_CALLBACK *) NULL;
+ ld->ld_sema_post_fn = (LDAP_TF_SEMA_POST_CALLBACK *) NULL;
+
+ /* We assume that only one thread is active when replacing */
+ /* the threadid function. We will now proceed and reset all */
+ /* of the threadid/refcounts */
+ for (i = 0; i < LDAP_MAX_LOCK; i++) {
+ ld->ld_mutex_threadid[i] = (void *) -1;
+ ld->ld_mutex_refcnt[i] = 0;
+ }
+
+ return (rc);
+
+ /* DNS function pointers */
+ case LDAP_OPT_DNS_FN_PTRS:
+ /* struct copy */
+ ld->ld_dnsfn = *((struct ldap_dns_fns *)optdata);
+ break;
+
+ /* cache function pointers */
+ case LDAP_OPT_CACHE_FN_PTRS:
+ /* struct copy */
+ ld->ld_cache = *((struct ldap_cache_fns *)optdata);
+ break;
+ case LDAP_OPT_CACHE_STRATEGY:
+ ld->ld_cache_strategy = *((int *)optdata);
+ break;
+ case LDAP_OPT_CACHE_ENABLE:
+ ld->ld_cache_on = *((int *)optdata);
+ break;
+
+ case LDAP_OPT_ERROR_NUMBER:
+ LDAP_GET_LDERRNO(ld, &matched, &errstr);
+ matched = nsldapi_strdup(matched);
+ errstr = nsldapi_strdup(errstr);
+ LDAP_SET_LDERRNO(ld, *((int *)optdata), matched, errstr);
+ break;
+
+ case LDAP_OPT_ERROR_STRING:
+ rc = LDAP_GET_LDERRNO(ld, &matched, NULL);
+ matched = nsldapi_strdup(matched);
+ LDAP_SET_LDERRNO(ld, rc, matched,
+ nsldapi_strdup((char *)optdata));
+ rc = LDAP_SUCCESS;
+ break;
+
+ case LDAP_OPT_MATCHED_DN:
+ rc = LDAP_GET_LDERRNO(ld, NULL, &errstr);
+ errstr = nsldapi_strdup(errstr);
+ LDAP_SET_LDERRNO(ld, rc,
+ nsldapi_strdup((char *)optdata), errstr);
+ rc = LDAP_SUCCESS;
+ break;
+
+ case LDAP_OPT_PREFERRED_LANGUAGE:
+ if (NULL != ld->ld_preferred_language) {
+ NSLDAPI_FREE(ld->ld_preferred_language);
+ }
+ ld->ld_preferred_language = nsldapi_strdup((char *)optdata);
+ break;
+
+ case LDAP_OPT_HOST_NAME:
+ if (NULL != ld->ld_defhost) {
+ NSLDAPI_FREE(ld->ld_defhost);
+ }
+ ld->ld_defhost = nsldapi_strdup((char *)optdata);
+ break;
+
+ case LDAP_X_OPT_CONNECT_TIMEOUT:
+ ld->ld_connect_timeout = *((int *)optdata);
+ break;
+
+#ifdef _SOLARIS_SDK
+ /* recursion prevention dns functions */
+ case LDAP_X_OPT_DNS_SKIPDB:
+ rc = prldap_x_install_dns_skipdb(ld, (const char *)optdata);
+ break;
+#endif
+#ifdef LDAP_SASLIO_HOOKS
+ /* SASL options */
+ case LDAP_OPT_X_SASL_MECH:
+ if (NULL != ld->ld_def_sasl_mech) {
+
+ NSLDAPI_FREE(ld->ld_def_sasl_mech);
+ }
+ ld->ld_def_sasl_mech = nsldapi_strdup((char *)optdata);
+ break;
+ case LDAP_OPT_X_SASL_REALM:
+ if (NULL != ld->ld_def_sasl_realm) {
+ NSLDAPI_FREE(ld->ld_def_sasl_realm);
+ }
+ ld->ld_def_sasl_realm = nsldapi_strdup((char *)optdata);
+ break;
+ case LDAP_OPT_X_SASL_AUTHCID:
+ if (NULL != ld->ld_def_sasl_authcid) {
+ NSLDAPI_FREE(ld->ld_def_sasl_authcid);
+ }
+ ld->ld_def_sasl_authcid = nsldapi_strdup((char *)optdata);
+ break;
+ case LDAP_OPT_X_SASL_AUTHZID:
+ if (NULL != ld->ld_def_sasl_authzid) {
+ NSLDAPI_FREE(ld->ld_def_sasl_authzid);
+ }
+ ld->ld_def_sasl_authzid = nsldapi_strdup((char *)optdata);
+ break;
+ case LDAP_OPT_X_SASL_SSF_EXTERNAL:
+ {
+ int sc;
+ sasl_ssf_t extprops;
+ sasl_conn_t *ctx;
+ if (ld->ld_defconn == NULL ||
+ ld->ld_defconn->lconn_sb == NULL) {
+ return (-1);
+ }
+ ctx = (sasl_conn_t *)
+ (ld->ld_defconn->lconn_sb->sb_sasl_ctx);
+ if (ctx == NULL) {
+ return (-1);
+ }
+ memset(&extprops, 0L, sizeof (extprops));
+ extprops = * ((sasl_ssf_t *)optdata);
+ sc = sasl_setprop(ctx, SASL_SSF_EXTERNAL,
+ (void *) &extprops);
+ if (sc != SASL_OK) {
+ return (-1);
+ }
+ }
+ break;
+ case LDAP_OPT_X_SASL_SECPROPS:
+ {
+ int sc;
+ sc = nsldapi_sasl_secprops((char *)optdata,
+ &ld->ld_sasl_secprops);
+ return (sc == LDAP_SUCCESS ? 0 : -1);
+ }
+ case LDAP_OPT_X_SASL_SSF_MIN:
+ ld->ld_sasl_secprops.min_ssf = *((sasl_ssf_t *)optdata);
+ break;
+ case LDAP_OPT_X_SASL_SSF_MAX:
+ ld->ld_sasl_secprops.max_ssf = *((sasl_ssf_t *)optdata);
+ break;
+ case LDAP_OPT_X_SASL_MAXBUFSIZE:
+ ld->ld_sasl_secprops.maxbufsize = *((sasl_ssf_t *)optdata);
+ break;
+ case LDAP_OPT_X_SASL_SSF: /* read only */
+ LDAP_SET_LDERRNO(ld, LDAP_PARAM_ERROR, NULL, NULL);
+ rc = -1;
+ break;
+#endif
+
+ default:
+ LDAP_SET_LDERRNO(ld, LDAP_PARAM_ERROR, NULL, NULL);
+ rc = -1;
+ }
+
+ if (ld != &nsldapi_ld_defaults) {
+ LDAP_MUTEX_UNLOCK(ld, LDAP_OPTION_LOCK);
+ }
+ return (rc);
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/sort.c b/usr/src/lib/libldap5/sources/ldap/common/sort.c
new file mode 100644
index 0000000000..8e02e873cf
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/sort.c
@@ -0,0 +1,320 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * sort.c: LDAP library entry and value sort routines
+ */
+
+#include "ldap-int.h"
+
+/* This xp_qsort fixes a memory problem (ABR) on Solaris for the client.
+ * Server is welcome to use it too, but I wasn't sure if it
+ * would be ok to use XP code here. -slamm
+ *
+ * We don't want to require use of libxp when linking with libldap, so
+ * I'll leave use of xp_qsort as a MOZILLA_CLIENT-only thing for now. --mcs
+ */
+#if defined(MOZILLA_CLIENT) && defined(SOLARIS)
+#include "xp_qsort.h"
+#else
+#define XP_QSORT qsort
+#endif
+
+typedef struct keycmp {
+ void *kc_arg;
+ LDAP_KEYCMP_CALLBACK *kc_cmp;
+} keycmp_t;
+
+typedef struct keything {
+ keycmp_t *kt_cmp;
+ const struct berval *kt_key;
+ LDAPMessage *kt_msg;
+} keything_t;
+
+static int LDAP_C LDAP_CALLBACK
+ldapi_keycmp( const void *Lv, const void *Rv )
+{
+ auto keything_t **L = (keything_t**)Lv;
+ auto keything_t **R = (keything_t**)Rv;
+ auto keycmp_t *cmp = (*L)->kt_cmp;
+ return cmp->kc_cmp( cmp->kc_arg, (*L)->kt_key, (*R)->kt_key );
+}
+
+int
+LDAP_CALL
+ldap_keysort_entries(
+ LDAP *ld,
+ LDAPMessage **chain,
+ void *arg,
+ LDAP_KEYGEN_CALLBACK *gen,
+ LDAP_KEYCMP_CALLBACK *cmp,
+ LDAP_KEYFREE_CALLBACK *fre)
+{
+ size_t count, i;
+ keycmp_t kc = {0};
+ keything_t **kt;
+ LDAPMessage *e, *last;
+ LDAPMessage **ep;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )
+ || chain == NULL || cmp == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ count = ldap_count_entries( ld, *chain );
+
+ kt = (keything_t**)NSLDAPI_MALLOC( count * (sizeof(keything_t*) + sizeof(keything_t)) );
+ if ( kt == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ for ( i = 0; i < count; i++ ) {
+ kt[i] = i + (keything_t*)(kt + count);
+ }
+ kc.kc_arg = arg;
+ kc.kc_cmp = cmp;
+
+ for ( e = *chain, i = 0; i < count; i++, e = e->lm_chain ) {
+ kt[i]->kt_msg = e;
+ kt[i]->kt_cmp = &kc;
+ kt[i]->kt_key = gen( arg, ld, e );
+ if ( kt[i]->kt_key == NULL ) {
+ if ( fre ) while ( i-- > 0 ) fre( arg, kt[i]->kt_key );
+ NSLDAPI_FREE( (char*)kt );
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ }
+ last = e;
+
+ XP_QSORT( (void*)kt, count, (size_t)sizeof(keything_t*), ldapi_keycmp );
+
+ ep = chain;
+ for ( i = 0; i < count; i++ ) {
+ *ep = kt[i]->kt_msg;
+ ep = &(*ep)->lm_chain;
+ if ( fre ) fre( arg, kt[i]->kt_key );
+ }
+ *ep = last;
+ NSLDAPI_FREE( (char*)kt );
+ return( 0 );
+}
+
+
+struct entrything {
+ char **et_vals;
+ LDAPMessage *et_msg;
+};
+
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CHARCMP_CALLBACK)(char*, char*);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_VOIDCMP_CALLBACK)(const void*,
+ const void*);
+
+static LDAP_CHARCMP_CALLBACK *et_cmp_fn;
+static LDAP_VOIDCMP_CALLBACK et_cmp;
+
+int
+LDAP_C
+LDAP_CALLBACK
+ldap_sort_strcasecmp(
+ const char **a,
+ const char **b
+)
+{
+ /* XXXceb
+ * I am not 100% sure this is the way this should be handled.
+ * For now we will return a 0 on invalid.
+ */
+ if (NULL == a || NULL == b)
+ return (0);
+ return( strcasecmp( (char *)*a, (char *)*b ) );
+}
+
+static int
+LDAP_C
+LDAP_CALLBACK
+et_cmp(
+ const void *aa,
+ const void *bb
+)
+{
+ int i, rc;
+ struct entrything *a = (struct entrything *)aa;
+ struct entrything *b = (struct entrything *)bb;
+
+ if ( a->et_vals == NULL && b->et_vals == NULL )
+ return( 0 );
+ if ( a->et_vals == NULL )
+ return( -1 );
+ if ( b->et_vals == NULL )
+ return( 1 );
+
+ for ( i = 0; a->et_vals[i] && b->et_vals[i]; i++ ) {
+ if ( (rc = (*et_cmp_fn)( a->et_vals[i], b->et_vals[i] ))
+ != 0 ) {
+ return( rc );
+ }
+ }
+
+ if ( a->et_vals[i] == NULL && b->et_vals[i] == NULL )
+ return( 0 );
+ if ( a->et_vals[i] == NULL )
+ return( -1 );
+ return( 1 );
+}
+
+int
+LDAP_CALL
+ldap_multisort_entries(
+ LDAP *ld,
+ LDAPMessage **chain,
+ char **attr, /* NULL => sort by DN */
+ LDAP_CMP_CALLBACK *cmp
+)
+{
+ int i, count;
+ struct entrything *et;
+ LDAPMessage *e, *last;
+ LDAPMessage **ep;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )
+ || chain == NULL || cmp == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ count = ldap_count_entries( ld, *chain );
+
+ if ( (et = (struct entrything *)NSLDAPI_MALLOC( count *
+ sizeof(struct entrything) )) == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+
+ e = *chain;
+ for ( i = 0; i < count; i++ ) {
+ et[i].et_msg = e;
+ et[i].et_vals = NULL;
+ if ( attr == NULL ) {
+ char *dn;
+
+ dn = ldap_get_dn( ld, e );
+ et[i].et_vals = ldap_explode_dn( dn, 1 );
+ NSLDAPI_FREE( dn );
+ } else {
+ int attrcnt;
+ char **vals;
+
+ for ( attrcnt = 0; attr[attrcnt] != NULL; attrcnt++ ) {
+ vals = ldap_get_values( ld, e, attr[attrcnt] );
+ if ( ldap_charray_merge( &(et[i].et_vals), vals )
+ != 0 ) {
+ int j;
+
+ /* XXX risky: ldap_value_free( vals ); */
+ for ( j = 0; j <= i; j++ )
+ ldap_value_free( et[j].et_vals );
+ NSLDAPI_FREE( (char *) et );
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
+ NULL );
+ return( -1 );
+ }
+ if ( vals != NULL ) {
+ NSLDAPI_FREE( (char *)vals );
+ }
+ }
+ }
+
+ e = e->lm_chain;
+ }
+ last = e;
+
+ et_cmp_fn = (LDAP_CHARCMP_CALLBACK *)cmp;
+ XP_QSORT( (void *) et, (size_t) count,
+ (size_t) sizeof(struct entrything), et_cmp );
+
+ ep = chain;
+ for ( i = 0; i < count; i++ ) {
+ *ep = et[i].et_msg;
+ ep = &(*ep)->lm_chain;
+
+ ldap_value_free( et[i].et_vals );
+ }
+ *ep = last;
+ NSLDAPI_FREE( (char *) et );
+
+ return( 0 );
+}
+
+int
+LDAP_CALL
+ldap_sort_entries(
+ LDAP *ld,
+ LDAPMessage **chain,
+ char *attr, /* NULL => sort by DN */
+ LDAP_CMP_CALLBACK *cmp
+)
+{
+ char *attrs[2];
+
+ attrs[0] = attr;
+ attrs[1] = NULL;
+ return( ldap_multisort_entries( ld, chain, attr ? attrs : NULL, cmp ) );
+}
+
+int
+LDAP_CALL
+ldap_sort_values(
+ LDAP *ld,
+ char **vals,
+ LDAP_VALCMP_CALLBACK *cmp
+)
+{
+ int nel;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || cmp == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL == vals)
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+ for ( nel = 0; vals[nel] != NULL; nel++ )
+ ; /* NULL */
+
+ XP_QSORT( vals, nel, sizeof(char *), (LDAP_VOIDCMP_CALLBACK *)cmp );
+
+ return( LDAP_SUCCESS );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/sortctrl.c b/usr/src/lib/libldap5/sources/ldap/common/sortctrl.c
new file mode 100644
index 0000000000..28cac9c928
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/sortctrl.c
@@ -0,0 +1,421 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+#include "ldap-int.h"
+
+/* ldap_create_sort_control:
+
+ Parameters are
+
+ ld LDAP pointer to the desired connection
+
+ sortKeyList an array of sortkeys
+
+ ctl_iscritical Indicates whether the control is critical of not. If
+ this field is non-zero, the operation will only be car-
+ ried out if the control is recognized by the server
+ and/or client
+
+ ctrlp the address of a place to put the constructed control
+*/
+
+int
+LDAP_CALL
+ldap_create_sort_control (
+ LDAP *ld,
+ LDAPsortkey **sortKeyList,
+ const char ctl_iscritical,
+ LDAPControl **ctrlp
+)
+{
+ BerElement *ber;
+ int i, rc;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( sortKeyList == NULL || ctrlp == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return ( LDAP_PARAM_ERROR );
+ }
+
+ /* create a ber package to hold the controlValue */
+ if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+
+ /* encode the start of the sequence of sequences into the ber */
+ if ( ber_printf( ber, "{" ) == -1 ) {
+ goto encoding_error_exit;
+ }
+
+ /* the sort control value will be encoded as a sequence of sequences
+ which are each encoded as one of the following: {s} or {sts} or {stb} or {ststb}
+ since the orderingRule and reverseOrder flag are both optional */
+ for ( i = 0; sortKeyList[i] != NULL; i++ ) {
+
+ /* encode the attributeType into the ber */
+ if ( ber_printf( ber, "{s", (sortKeyList[i])->sk_attrtype )
+ == -1 ) {
+ goto encoding_error_exit;
+ }
+
+ /* encode the optional orderingRule into the ber */
+ if ( (sortKeyList[i])->sk_matchruleoid != NULL ) {
+ if ( ber_printf( ber, "ts", LDAP_TAG_SK_MATCHRULE,
+ (sortKeyList[i])->sk_matchruleoid )
+ == -1 ) {
+ goto encoding_error_exit;
+ }
+ }
+
+ /* Encode the optional reverseOrder flag into the ber. */
+ /* If the flag is false, it should be absent. */
+ if ( (sortKeyList[i])->sk_reverseorder ) {
+ if ( ber_printf( ber, "tb}", LDAP_TAG_SK_REVERSE,
+ (sortKeyList[i])->sk_reverseorder ) == -1 ) {
+ goto encoding_error_exit;
+ }
+ } else {
+ if ( ber_printf( ber, "}" ) == -1 ) {
+ goto encoding_error_exit;
+ }
+ }
+ }
+
+ /* encode the end of the sequence of sequences into the ber */
+ if ( ber_printf( ber, "}" ) == -1 ) {
+ goto encoding_error_exit;
+ }
+
+ rc = nsldapi_build_control( LDAP_CONTROL_SORTREQUEST, ber, 1,
+ ctl_iscritical, ctrlp );
+
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+
+encoding_error_exit:
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+}
+
+/* ldap_parse_sort_control:
+
+ Parameters are
+
+ ld LDAP pointer to the desired connection
+
+ ctrlp An array of controls obtained from calling
+ ldap_parse_result on the set of results returned by
+ the server
+
+ result the address of a place to put the result code
+
+ attribute the address of a place to put the name of the
+ attribute which cause the operation to fail, optionally
+ returned by the server */
+
+int
+LDAP_CALL
+ldap_parse_sort_control (
+ LDAP *ld,
+ LDAPControl **ctrlp,
+ unsigned long *result,
+ char **attribute
+)
+{
+ BerElement *ber;
+ int i, foundSortControl;
+ LDAPControl *sortCtrlp;
+ ber_len_t len;
+ ber_tag_t tag;
+ char *attr;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || result == NULL ||
+ attribute == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+
+ /* find the sortControl in the list of controls if it exists */
+ if ( ctrlp == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+ return ( LDAP_CONTROL_NOT_FOUND );
+ }
+ foundSortControl = 0;
+ for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundSortControl )); i++ ) {
+ foundSortControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_SORTRESPONSE );
+ }
+ if ( !foundSortControl ) {
+ LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+ return ( LDAP_CONTROL_NOT_FOUND );
+ } else {
+ /* let local var point to the sortControl */
+ sortCtrlp = ctrlp[i-1];
+ }
+
+ /* allocate a Ber element with the contents of the sort_control's struct berval */
+ if ( ( ber = ber_init( &sortCtrlp->ldctl_value ) ) == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+
+ /* decode the result from the Berelement */
+ if ( ber_scanf( ber, "{i", result ) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_DECODING_ERROR );
+ }
+
+ /* if the server returned one, decode the attribute from the Ber element */
+ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SR_ATTRTYPE ) {
+ if ( ber_scanf( ber, "ta", &tag, &attr ) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_DECODING_ERROR );
+ }
+ *attribute = attr;
+ } else {
+ *attribute = NULL;
+ }
+
+ if ( ber_scanf( ber, "}" ) == LBER_ERROR ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_DECODING_ERROR );
+ }
+
+ /* the ber encoding is no longer needed */
+ ber_free(ber,1);
+
+ return( LDAP_SUCCESS );
+}
+
+/* Routines for the manipulation of string-representations of sort control keylists */
+
+static int count_tokens(const char *s)
+{
+ int count = 0;
+ const char *p = s;
+ int whitespace = 1;
+ /* Loop along the string counting the number of times we see the
+ * beginning of non-whitespace. This tells us
+ * the number of tokens in the string
+ */
+ while (*p != '\0') {
+ if (whitespace) {
+ if (!isspace(*p)) {
+ whitespace = 0;
+ count++;
+ }
+ } else {
+ if (isspace(*p)) {
+ whitespace = 1;
+ }
+ }
+ p++;
+ }
+ return count;
+}
+
+
+static int read_next_token(const char **s,LDAPsortkey **key)
+{
+ char c = 0;
+ const char *pos = *s;
+ int retval = 0;
+ LDAPsortkey *new_key = NULL;
+
+ const char *matchrule_source = NULL;
+ int matchrule_size = 0;
+ const char *attrdesc_source = NULL;
+ int attrdesc_size = 0;
+ int reverse = 0;
+
+ int state = 0;
+
+ while ( ((c = *pos++) != '\0') && (state != 4) ) {
+ switch (state) {
+ case 0:
+ /* case where we've not seen the beginning of the attr yet */
+ /* If we still see whitespace, nothing to do */
+ if (!isspace(c)) {
+ /* Otherwise, something to look at */
+ /* Is it a minus sign ? */
+ if ('-' == c) {
+ reverse = 1;
+ } else {
+ attrdesc_source = pos - 1;
+ state = 1;
+ }
+ }
+ break;
+ case 1:
+ /* case where we've seen the beginning of the attr, but not the end */
+ /* Is this char either whitespace or a ';' ? */
+ if ( isspace(c) || (':' == c)) {
+ attrdesc_size = (pos - attrdesc_source) - 1;
+ if (':' == c) {
+ state = 2;
+ } else {
+ state = 4;
+ }
+ }
+ break;
+ case 2:
+ /* case where we've seen the end of the attr and want the beginning of match rule */
+ if (!isspace(c)) {
+ matchrule_source = pos - 1;
+ state = 3;
+ } else {
+ state = 4;
+ }
+ break;
+ case 3:
+ /* case where we've seen the beginning of match rule and want to find the end */
+ if (isspace(c)) {
+ matchrule_size = (pos - matchrule_source) - 1;
+ state = 4;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (3 == state) {
+ /* means we fell off the end of the string looking for the end of the marching rule */
+ matchrule_size = (pos - matchrule_source) - 1;
+ }
+
+ if (1 == state) {
+ /* means we fell of the end of the string looking for the end of the attribute */
+ attrdesc_size = (pos - attrdesc_source) - 1;
+ }
+
+ if (NULL == attrdesc_source) {
+ /* Didn't find anything */
+ return -1;
+ }
+
+ new_key = (LDAPsortkey*)NSLDAPI_MALLOC(sizeof(LDAPsortkey));
+ if (0 == new_key) {
+ return LDAP_NO_MEMORY;
+ }
+
+ /* Allocate the strings */
+ new_key->sk_attrtype = (char *)NSLDAPI_MALLOC(attrdesc_size + 1);
+ if (NULL != matchrule_source) {
+ new_key->sk_matchruleoid = (char *)NSLDAPI_MALLOC(
+ matchrule_size + 1);
+ } else {
+ new_key->sk_matchruleoid = NULL;
+ }
+ /* Copy over the strings */
+ memcpy(new_key->sk_attrtype,attrdesc_source,attrdesc_size);
+ *(new_key->sk_attrtype + attrdesc_size) = '\0';
+ if (NULL != matchrule_source) {
+ memcpy(new_key->sk_matchruleoid,matchrule_source,matchrule_size);
+ *(new_key->sk_matchruleoid + matchrule_size) = '\0';
+ }
+
+ new_key->sk_reverseorder = reverse;
+
+ *s = pos - 1;
+ *key = new_key;
+ return retval;
+}
+
+int
+LDAP_CALL
+ldap_create_sort_keylist (
+ LDAPsortkey ***sortKeyList,
+ const char *string_rep
+)
+{
+ int count = 0;
+ LDAPsortkey **pointer_array = NULL;
+ const char *current_position = NULL;
+ int retval = 0;
+ int i = 0;
+
+ /* Figure out how many there are */
+ if (NULL == string_rep) {
+ return LDAP_PARAM_ERROR;
+ }
+ if (NULL == sortKeyList) {
+ return LDAP_PARAM_ERROR;
+ }
+ count = count_tokens(string_rep);
+ if (0 == count) {
+ *sortKeyList = NULL;
+ return LDAP_PARAM_ERROR;
+ }
+ /* Allocate enough memory for the pointers */
+ pointer_array = (LDAPsortkey**)NSLDAPI_MALLOC(sizeof(LDAPsortkey*)
+ * (count + 1) );
+ if (NULL == pointer_array) {
+ return LDAP_NO_MEMORY;
+ }
+ /* Now walk along the string, allocating and filling in the LDAPsearchkey structure */
+ current_position = string_rep;
+
+ for (i = 0; i < count; i++) {
+ if (0 != (retval = read_next_token(&current_position,&(pointer_array[i])))) {
+ pointer_array[count] = NULL;
+ ldap_free_sort_keylist(pointer_array);
+ *sortKeyList = NULL;
+ return retval;
+ }
+ }
+ pointer_array[count] = NULL;
+ *sortKeyList = pointer_array;
+ return LDAP_SUCCESS;
+}
+
+void
+LDAP_CALL
+ldap_free_sort_keylist (
+ LDAPsortkey **sortKeyList
+)
+{
+ LDAPsortkey *this_one = NULL;
+ int i = 0;
+
+ if ( NULL == sortKeyList ) {
+ return;
+ }
+
+ /* Walk down the list freeing the LDAPsortkey structures */
+ for (this_one = sortKeyList[0]; this_one ; this_one = sortKeyList[++i]) {
+ /* Free the strings, if present */
+ if (NULL != this_one->sk_attrtype) {
+ NSLDAPI_FREE(this_one->sk_attrtype);
+ }
+ if (NULL != this_one->sk_matchruleoid) {
+ NSLDAPI_FREE(this_one->sk_matchruleoid);
+ }
+ NSLDAPI_FREE(this_one);
+ }
+ /* Free the pointer list */
+ NSLDAPI_FREE(sortKeyList);
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/spagectrl.c b/usr/src/lib/libldap5/sources/ldap/common/spagectrl.c
new file mode 100644
index 0000000000..7287ad16d5
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/spagectrl.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef MACOS
+#include "macos.h"
+#endif /* MACOS */
+
+#if !defined( MACOS ) && !defined( DOS )
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include "lber.h"
+#include "ldap.h"
+#include "ldap-int.h"
+
+int ldap_create_page_control(LDAP *ld, unsigned int pagesize, struct berval *cookie, char isCritical, LDAPControl **output)
+{
+ BerElement *ber;
+ int rc;
+
+ if (NULL == ld || NULL == output)
+ return (LDAP_PARAM_ERROR);
+
+ if ((ber = ber_alloc_t(LBER_USE_DER)) == NULLBER){
+ return (LDAP_NO_MEMORY);
+ }
+
+ if (ber_printf(ber, "{io}", pagesize,
+ (cookie && cookie->bv_val) ? cookie->bv_val : "",
+ (cookie && cookie->bv_val) ? cookie->bv_len : 0)
+ == LBER_ERROR) {
+ ber_free(ber, 1);
+ return (LDAP_ENCODING_ERROR);
+ }
+
+ rc = nsldapi_build_control(LDAP_CONTROL_SIMPLE_PAGE, ber, 1, isCritical,
+ output);
+
+ ld->ld_errno = rc;
+ return (rc);
+}
+
+int ldap_parse_page_control(LDAP *ld, LDAPControl **controls, unsigned int *totalcount, struct berval **cookie)
+{
+ int i, rc;
+ BerElement *theBer;
+ LDAPControl *listCtrlp;
+
+ for (i = 0; controls[i] != NULL; i++){
+ if (strcmp(controls[i]->ldctl_oid, "1.2.840.113556.1.4.319") == 0) {
+ listCtrlp = controls[i];
+ if ((theBer = ber_init(&listCtrlp->ldctl_value)) == NULLBER){
+ return (LDAP_NO_MEMORY);
+ }
+ if ((rc = ber_scanf(theBer, "{iO}", totalcount, cookie)) == LBER_ERROR){
+ ber_free(theBer, 1);
+ return (LDAP_DECODING_ERROR);
+ }
+ ber_free(theBer, 1);
+ return (LDAP_SUCCESS);
+ }
+ }
+ return (LDAP_CONTROL_NOT_FOUND);
+}
+
diff --git a/usr/src/lib/libldap5/sources/ldap/common/srchpref.c b/usr/src/lib/libldap5/sources/ldap/common/srchpref.c
new file mode 100644
index 0000000000..50105e50ab
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/srchpref.c
@@ -0,0 +1,421 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ */
+/*
+ * searchpref.c: search preferences library routines for LDAP clients
+ */
+
+#include "ldap-int.h"
+#include "srchpref.h"
+
+static void free_searchobj( struct ldap_searchobj *so );
+static int read_next_searchobj( char **bufp, long *blenp,
+ struct ldap_searchobj **sop, int soversion );
+
+
+static char *sobjoptions[] = {
+ "internal",
+ NULL
+};
+
+
+static unsigned long sobjoptvals[] = {
+ LDAP_SEARCHOBJ_OPT_INTERNAL,
+};
+
+
+int
+LDAP_CALL
+ldap_init_searchprefs( char *file, struct ldap_searchobj **solistp )
+{
+ FILE *fp;
+ char *buf;
+ long rlen, len;
+ int rc, eof;
+
+ if (( fp = fopen( file, "r" )) == NULL ) {
+ return( LDAP_SEARCHPREF_ERR_FILE );
+ }
+
+ if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */
+ fclose( fp );
+ return( LDAP_SEARCHPREF_ERR_FILE );
+ }
+
+ len = ftell( fp );
+
+ if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */
+ fclose( fp );
+ return( LDAP_SEARCHPREF_ERR_FILE );
+ }
+
+ if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
+ fclose( fp );
+ return( LDAP_SEARCHPREF_ERR_MEM );
+ }
+
+ rlen = fread( buf, 1, (size_t)len, fp );
+ eof = feof( fp );
+ fclose( fp );
+
+ if ( rlen != len && !eof ) { /* error: didn't get the whole file */
+ NSLDAPI_FREE( buf );
+ return( LDAP_SEARCHPREF_ERR_FILE );
+ }
+
+ rc = ldap_init_searchprefs_buf( buf, rlen, solistp );
+ NSLDAPI_FREE( buf );
+
+ return( rc );
+}
+
+
+int
+LDAP_CALL
+ldap_init_searchprefs_buf( char *buf, long buflen,
+ struct ldap_searchobj **solistp )
+{
+ int rc = 0, version;
+ char **toks;
+ struct ldap_searchobj *prevso, *so;
+
+ *solistp = prevso = NULLSEARCHOBJ;
+
+ if ( ldap_next_line_tokens( &buf, &buflen, &toks ) != 2 ||
+ strcasecmp( toks[ 0 ], "version" ) != 0 ) {
+ ldap_free_strarray( toks );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ version = atoi( toks[ 1 ] );
+ ldap_free_strarray( toks );
+ if ( version != LDAP_SEARCHPREF_VERSION &&
+ version != LDAP_SEARCHPREF_VERSION_ZERO ) {
+ return( LDAP_SEARCHPREF_ERR_VERSION );
+ }
+
+ while ( buflen > 0 && ( rc = read_next_searchobj( &buf, &buflen, &so,
+ version )) == 0 && so != NULLSEARCHOBJ ) {
+ if ( prevso == NULLSEARCHOBJ ) {
+ *solistp = so;
+ } else {
+ prevso->so_next = so;
+ }
+ prevso = so;
+ }
+
+ if ( rc != 0 ) {
+ ldap_free_searchprefs( *solistp );
+ }
+
+ return( rc );
+}
+
+
+
+void
+LDAP_CALL
+ldap_free_searchprefs( struct ldap_searchobj *solist )
+{
+ struct ldap_searchobj *so, *nextso;
+
+ if ( solist != NULL ) {
+ for ( so = solist; so != NULL; so = nextso ) {
+ nextso = so->so_next;
+ free_searchobj( so );
+ }
+ }
+ /* XXX XXX need to do some work here */
+}
+
+
+static void
+free_searchobj( struct ldap_searchobj *so )
+{
+ if ( so != NULL ) {
+ if ( so->so_objtypeprompt != NULL ) {
+ NSLDAPI_FREE( so->so_objtypeprompt );
+ }
+ if ( so->so_prompt != NULL ) {
+ NSLDAPI_FREE( so->so_prompt );
+ }
+ if ( so->so_filterprefix != NULL ) {
+ NSLDAPI_FREE( so->so_filterprefix );
+ }
+ if ( so->so_filtertag != NULL ) {
+ NSLDAPI_FREE( so->so_filtertag );
+ }
+ if ( so->so_defaultselectattr != NULL ) {
+ NSLDAPI_FREE( so->so_defaultselectattr );
+ }
+ if ( so->so_defaultselecttext != NULL ) {
+ NSLDAPI_FREE( so->so_defaultselecttext );
+ }
+ if ( so->so_salist != NULL ) {
+ struct ldap_searchattr *sa, *nextsa;
+ for ( sa = so->so_salist; sa != NULL; sa = nextsa ) {
+ nextsa = sa->sa_next;
+ if ( sa->sa_attrlabel != NULL ) {
+ NSLDAPI_FREE( sa->sa_attrlabel );
+ }
+ if ( sa->sa_attr != NULL ) {
+ NSLDAPI_FREE( sa->sa_attr );
+ }
+ if ( sa->sa_selectattr != NULL ) {
+ NSLDAPI_FREE( sa->sa_selectattr );
+ }
+ if ( sa->sa_selecttext != NULL ) {
+ NSLDAPI_FREE( sa->sa_selecttext );
+ }
+ NSLDAPI_FREE( sa );
+ }
+ }
+ if ( so->so_smlist != NULL ) {
+ struct ldap_searchmatch *sm, *nextsm;
+ for ( sm = so->so_smlist; sm != NULL; sm = nextsm ) {
+ nextsm = sm->sm_next;
+ if ( sm->sm_matchprompt != NULL ) {
+ NSLDAPI_FREE( sm->sm_matchprompt );
+ }
+ if ( sm->sm_filter != NULL ) {
+ NSLDAPI_FREE( sm->sm_filter );
+ }
+ NSLDAPI_FREE( sm );
+ }
+ }
+ NSLDAPI_FREE( so );
+ }
+}
+
+
+
+struct ldap_searchobj *
+LDAP_CALL
+ldap_first_searchobj( struct ldap_searchobj *solist )
+{
+ return( solist );
+}
+
+
+struct ldap_searchobj *
+LDAP_CALL
+ldap_next_searchobj( struct ldap_searchobj *solist, struct ldap_searchobj *so )
+{
+ return( so == NULLSEARCHOBJ ? so : so->so_next );
+}
+
+
+
+static int
+read_next_searchobj( char **bufp, long *blenp, struct ldap_searchobj **sop,
+ int soversion )
+{
+ int i, j, tokcnt;
+ char **toks;
+ struct ldap_searchobj *so;
+ struct ldap_searchattr **sa;
+ struct ldap_searchmatch **sm;
+
+ *sop = NULL;
+
+ /*
+ * Object type prompt comes first
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ return( tokcnt == 0 ? 0 : LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+
+ if (( so = (struct ldap_searchobj *)NSLDAPI_CALLOC( 1,
+ sizeof( struct ldap_searchobj ))) == NULL ) {
+ ldap_free_strarray( toks );
+ return( LDAP_SEARCHPREF_ERR_MEM );
+ }
+ so->so_objtypeprompt = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * if this is post-version zero, options come next
+ */
+ if ( soversion > LDAP_SEARCHPREF_VERSION_ZERO ) {
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) < 1 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ for ( i = 0; toks[ i ] != NULL; ++i ) {
+ for ( j = 0; sobjoptions[ j ] != NULL; ++j ) {
+ if ( strcasecmp( toks[ i ], sobjoptions[ j ] ) == 0 ) {
+ so->so_options |= sobjoptvals[ j ];
+ }
+ }
+ }
+ ldap_free_strarray( toks );
+ }
+
+ /*
+ * "Fewer choices" prompt is next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ so->so_prompt = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * Filter prefix for "More Choices" searching is next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ so->so_filterprefix = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * "Fewer Choices" filter tag comes next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ so->so_filtertag = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * Selection (disambiguation) attribute comes next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ so->so_defaultselectattr = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * Label for selection (disambiguation) attribute
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ so->so_defaultselecttext = toks[ 0 ];
+ NSLDAPI_FREE( (char *)toks );
+
+ /*
+ * Search scope is next
+ */
+ if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ if ( !strcasecmp(toks[ 0 ], "subtree" )) {
+ so->so_defaultscope = LDAP_SCOPE_SUBTREE;
+ } else if ( !strcasecmp(toks[ 0 ], "onelevel" )) {
+ so->so_defaultscope = LDAP_SCOPE_ONELEVEL;
+ } else if ( !strcasecmp(toks[ 0 ], "base" )) {
+ so->so_defaultscope = LDAP_SCOPE_BASE;
+ } else {
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ ldap_free_strarray( toks );
+
+
+ /*
+ * "More Choices" search option list comes next
+ */
+ sa = &( so->so_salist );
+ while (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+ if ( tokcnt < 5 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ if (( *sa = ( struct ldap_searchattr * )NSLDAPI_CALLOC( 1,
+ sizeof( struct ldap_searchattr ))) == NULL ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_MEM );
+ }
+ ( *sa )->sa_attrlabel = toks[ 0 ];
+ ( *sa )->sa_attr = toks[ 1 ];
+ ( *sa )->sa_selectattr = toks[ 3 ];
+ ( *sa )->sa_selecttext = toks[ 4 ];
+ /* Deal with bitmap */
+ ( *sa )->sa_matchtypebitmap = 0;
+ for ( i = strlen( toks[ 2 ] ) - 1, j = 0; i >= 0; i--, j++ ) {
+ if ( toks[ 2 ][ i ] == '1' ) {
+ ( *sa )->sa_matchtypebitmap |= (1 << j);
+ }
+ }
+ NSLDAPI_FREE( toks[ 2 ] );
+ NSLDAPI_FREE( ( char * ) toks );
+ sa = &(( *sa )->sa_next);
+ }
+ *sa = NULL;
+
+ /*
+ * Match types are last
+ */
+ sm = &( so->so_smlist );
+ while (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+ if ( tokcnt < 2 ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_SYNTAX );
+ }
+ if (( *sm = ( struct ldap_searchmatch * )NSLDAPI_CALLOC( 1,
+ sizeof( struct ldap_searchmatch ))) == NULL ) {
+ ldap_free_strarray( toks );
+ ldap_free_searchprefs( so );
+ return( LDAP_SEARCHPREF_ERR_MEM );
+ }
+ ( *sm )->sm_matchprompt = toks[ 0 ];
+ ( *sm )->sm_filter = toks[ 1 ];
+ NSLDAPI_FREE( ( char * ) toks );
+ sm = &(( *sm )->sm_next );
+ }
+ *sm = NULL;
+
+ *sop = so;
+ return( 0 );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/tmplout.c b/usr/src/lib/libldap5/sources/ldap/common/tmplout.c
new file mode 100644
index 0000000000..91b2c7ef4a
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/tmplout.c
@@ -0,0 +1,1140 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * tmplout.c: display template library output routines for LDAP clients
+ *
+ */
+
+#include "ldap-int.h"
+#include "disptmpl.h"
+
+#if defined(_WINDOWS) || defined(aix) || defined(SCOOS) || defined(OSF1) || defined(SOLARIS)
+#include <time.h> /* for struct tm and ctime */
+#endif
+
+
+/* This is totally lame, since it should be coming from time.h, but isn't. */
+#if defined(SOLARIS)
+char *ctime_r(const time_t *, char *, int);
+#endif
+
+static int do_entry2text( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
+ struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+ writeptype writeproc, void *writeparm, char *eol, int rdncount,
+ unsigned long opts, char *urlprefix );
+static int do_entry2text_search( LDAP *ld, char *dn, char *base,
+ LDAPMessage *entry, struct ldap_disptmpl *tmpllist, char **defattrs,
+ char ***defvals, writeptype writeproc, void *writeparm, char *eol,
+ int rdncount, unsigned long opts, char *urlprefix );
+static int do_vals2text( LDAP *ld, char *buf, char **vals, char *label,
+ int labelwidth, unsigned long syntaxid, writeptype writeproc,
+ void *writeparm, char *eol, int rdncount, char *urlprefix );
+static int max_label_len( struct ldap_disptmpl *tmpl );
+static int output_label( char *buf, char *label, int width,
+ writeptype writeproc, void *writeparm, char *eol, int html );
+static int output_dn( char *buf, char *dn, int width, int rdncount,
+ writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
+static void strcat_escaped( char *s1, char *s2 );
+static char *time2text( char *ldtimestr, int dateonly );
+static long gtime( struct tm *tm );
+static int searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
+ char *dn, struct ldap_tmplitem *tip, int labelwidth, int rdncount,
+ writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
+
+#define DEF_LABEL_WIDTH 15
+#define SEARCH_TIMEOUT_SECS 120
+#define OCATTRNAME "objectClass"
+
+
+#define NONFATAL_LDAP_ERR( err ) ( err == LDAP_SUCCESS || \
+ err == LDAP_TIMELIMIT_EXCEEDED || err == LDAP_SIZELIMIT_EXCEEDED )
+
+#define DEF_LDAP_URL_PREFIX "ldap:///"
+
+
+int
+LDAP_CALL
+ldap_entry2text(
+ LDAP *ld,
+ char *buf, /* NULL for "use internal" */
+ LDAPMessage *entry,
+ struct ldap_disptmpl *tmpl,
+ char **defattrs,
+ char ***defvals,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount,
+ unsigned long opts
+)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2text\n", 0, 0, 0 );
+
+ return( do_entry2text( ld, buf, NULL, entry, tmpl, defattrs, defvals,
+ writeproc, writeparm, eol, rdncount, opts, NULL ));
+
+}
+
+
+
+int
+LDAP_CALL
+ldap_entry2html(
+ LDAP *ld,
+ char *buf, /* NULL for "use internal" */
+ LDAPMessage *entry,
+ struct ldap_disptmpl *tmpl,
+ char **defattrs,
+ char ***defvals,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount,
+ unsigned long opts,
+ char *base,
+ char *urlprefix
+)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2html\n", 0, 0, 0 );
+
+ if ( urlprefix == NULL ) {
+ urlprefix = DEF_LDAP_URL_PREFIX;
+ }
+
+ return( do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
+ writeproc, writeparm, eol, rdncount, opts, urlprefix ));
+}
+
+
+static int
+do_entry2text(
+ LDAP *ld,
+ char *buf, /* NULL for use-internal */
+ char *base, /* used for search actions */
+ LDAPMessage *entry,
+ struct ldap_disptmpl *tmpl,
+ char **defattrs,
+ char ***defvals,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount,
+ unsigned long opts,
+ char *urlprefix /* if non-NULL, do HTML */
+)
+{
+ int i, err, html, show, labelwidth;
+ int freebuf, freevals;
+ char *dn, **vals;
+ struct ldap_tmplitem *rowp, *colp;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( writeproc == NULL ||
+ !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+ err = LDAP_PARAM_ERROR;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ if ( buf == NULL ) {
+ if (( buf = NSLDAPI_MALLOC( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ NSLDAPI_FREE( dn );
+ return( err );
+ }
+ freebuf = 1;
+ } else {
+ freebuf = 0;
+ }
+
+ html = ( urlprefix != NULL );
+
+ if ( html ) {
+ /*
+ * add HTML intro. and title
+ */
+ if (!(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
+ sprintf( buf, "<HTML>%s<HEAD>%s<TITLE>%s%s - ", eol, eol, eol,
+ ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+ sprintf( buf, "%s</TITLE>%s</HEAD>%s<BODY>%s<H3>%s - ", eol, eol,
+ eol, eol, ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+ sprintf( buf, "</H3>%s", eol );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ }
+
+ if (( opts & LDAP_DISP_OPT_NONLEAF ) != 0 &&
+ ( vals = ldap_explode_dn( dn, 0 )) != NULL ) {
+ char *untagged;
+
+ /*
+ * add "Move Up" link
+ */
+ sprintf( buf, "<A HREF=\"%s", urlprefix );
+ for ( i = 1; vals[ i ] != NULL; ++i ) {
+ if ( i > 1 ) {
+ strcat_escaped( buf, ", " );
+ }
+ strcat_escaped( buf, vals[ i ] );
+ }
+ if ( vals[ 1 ] != NULL ) {
+ untagged = strchr( vals[ 1 ], '=' );
+ } else {
+ untagged = "=The World";
+ }
+ sprintf( buf + strlen( buf ),
+ "%s\">Move Up To <EM>%s</EM></A>%s<BR>",
+ ( vals[ 1 ] == NULL ) ? "??one" : "",
+ ( untagged != NULL ) ? untagged + 1 : vals[ 1 ], eol );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+
+ /*
+ * add "Browse" link
+ */
+ untagged = strchr( vals[ 0 ], '=' );
+ sprintf( buf, "<A HREF=\"%s", urlprefix );
+ strcat_escaped( buf, dn );
+ sprintf( buf + strlen( buf ), "??one?(!(objectClass=dsa))\">Browse Below <EM>%s</EM></A>%s%s",
+ ( untagged != NULL ) ? untagged + 1 : vals[ 0 ], eol, eol );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+
+ ldap_value_free( vals );
+ }
+
+ (*writeproc)( writeparm, "<HR>", 4 ); /* horizontal rule */
+ } else {
+ (*writeproc)( writeparm, "\"", 1 );
+ output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+ sprintf( buf, "\"%s", eol );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ }
+
+ if ( tmpl != NULL && ( opts & LDAP_DISP_OPT_AUTOLABELWIDTH ) != 0 ) {
+ labelwidth = max_label_len( tmpl ) + 3;
+ } else {
+ labelwidth = DEF_LABEL_WIDTH;;
+ }
+
+ err = LDAP_SUCCESS;
+
+ if ( tmpl == NULL ) {
+ BerElement *ber;
+ char *attr;
+
+ ber = NULL;
+ for ( attr = ldap_first_attribute( ld, entry, &ber );
+ NONFATAL_LDAP_ERR( err ) && attr != NULL;
+ attr = ldap_next_attribute( ld, entry, ber )) {
+ if (( vals = ldap_get_values( ld, entry, attr )) == NULL ) {
+ freevals = 0;
+ if ( defattrs != NULL ) {
+ for ( i = 0; defattrs[ i ] != NULL; ++i ) {
+ if ( strcasecmp( attr, defattrs[ i ] ) == 0 ) {
+ break;
+ }
+ }
+ if ( defattrs[ i ] != NULL ) {
+ vals = defvals[ i ];
+ }
+ }
+ } else {
+ freevals = 1;
+ }
+
+ if ( islower( *attr )) { /* cosmetic -- upcase attr. name */
+ *attr = toupper( *attr );
+ }
+
+ err = do_vals2text( ld, buf, vals, attr, labelwidth,
+ LDAP_SYN_CASEIGNORESTR, writeproc, writeparm, eol,
+ rdncount, urlprefix );
+ if ( freevals ) {
+ ldap_value_free( vals );
+ }
+ }
+ if ( ber == NULL ) {
+ ber_free( ber, 0 );
+ }
+ /*
+ * XXX check for errors in ldap_first_attribute/ldap_next_attribute
+ * here (but what should we do if there was one?)
+ */
+
+ } else {
+ for ( rowp = ldap_first_tmplrow( tmpl );
+ NONFATAL_LDAP_ERR( err ) && rowp != NULLTMPLITEM;
+ rowp = ldap_next_tmplrow( tmpl, rowp )) {
+ for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+ colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+ vals = NULL;
+ if ( colp->ti_attrname == NULL || ( vals = ldap_get_values( ld,
+ entry, colp->ti_attrname )) == NULL ) {
+ freevals = 0;
+ if ( !LDAP_IS_TMPLITEM_OPTION_SET( colp,
+ LDAP_DITEM_OPT_HIDEIFEMPTY ) && defattrs != NULL
+ && colp->ti_attrname != NULL ) {
+ for ( i = 0; defattrs[ i ] != NULL; ++i ) {
+ if ( strcasecmp( colp->ti_attrname, defattrs[ i ] )
+ == 0 ) {
+ break;
+ }
+ }
+ if ( defattrs[ i ] != NULL ) {
+ vals = defvals[ i ];
+ }
+ }
+ } else {
+ freevals = 1;
+ if ( LDAP_IS_TMPLITEM_OPTION_SET( colp,
+ LDAP_DITEM_OPT_SORTVALUES ) && vals[ 0 ] != NULL
+ && vals[ 1 ] != NULL ) {
+ ldap_sort_values(ld, vals, ldap_sort_strcasecmp);
+ }
+ }
+
+ /*
+ * don't bother even calling do_vals2text() if no values
+ * or boolean with value false and "hide if false" option set
+ */
+ show = ( vals != NULL && vals[ 0 ] != NULL );
+ if ( show && LDAP_GET_SYN_TYPE( colp->ti_syntaxid )
+ == LDAP_SYN_TYPE_BOOLEAN && LDAP_IS_TMPLITEM_OPTION_SET(
+ colp, LDAP_DITEM_OPT_HIDEIFFALSE ) &&
+ toupper( vals[ 0 ][ 0 ] ) != 'T' ) {
+ show = 0;
+ }
+
+ if ( colp->ti_syntaxid == LDAP_SYN_SEARCHACTION ) {
+ if (( opts & LDAP_DISP_OPT_DOSEARCHACTIONS ) != 0 ) {
+ if ( colp->ti_attrname == NULL || ( show &&
+ toupper( vals[ 0 ][ 0 ] ) == 'T' )) {
+ err = searchaction( ld, buf, base, entry, dn, colp,
+ labelwidth, rdncount, writeproc,
+ writeparm, eol, urlprefix );
+ }
+ }
+ show = 0;
+ }
+
+ if ( show ) {
+ err = do_vals2text( ld, buf, vals, colp->ti_label,
+ labelwidth, colp->ti_syntaxid, writeproc, writeparm,
+ eol, rdncount, urlprefix );
+ }
+
+ if ( freevals ) {
+ ldap_value_free( vals );
+ }
+ }
+ }
+ }
+
+ if ( html && !(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
+ sprintf( buf, "</BODY>%s</HTML>%s", eol, eol );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ }
+
+ NSLDAPI_FREE( dn );
+ if ( freebuf ) {
+ NSLDAPI_FREE( buf );
+ }
+
+ return( err );
+}
+
+
+int
+LDAP_CALL
+ldap_entry2text_search(
+ LDAP *ld,
+ char *dn, /* if NULL, use entry */
+ char *base, /* if NULL, no search actions */
+ LDAPMessage *entry, /* if NULL, use dn */
+ struct ldap_disptmpl* tmpllist, /* if NULL, load default file */
+ char **defattrs,
+ char ***defvals,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount, /* if 0, display full DN */
+ unsigned long opts
+)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2text_search\n", 0, 0, 0 );
+
+ return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
+ defvals, writeproc, writeparm, eol, rdncount, opts, NULL ));
+}
+
+
+
+int
+LDAP_CALL
+ldap_entry2html_search(
+ LDAP *ld,
+ char *dn, /* if NULL, use entry */
+ char *base, /* if NULL, no search actions */
+ LDAPMessage *entry, /* if NULL, use dn */
+ struct ldap_disptmpl* tmpllist, /* if NULL, load default file */
+ char **defattrs,
+ char ***defvals,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount, /* if 0, display full DN */
+ unsigned long opts,
+ char *urlprefix
+)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2html_search\n", 0, 0, 0 );
+
+ return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
+ defvals, writeproc, writeparm, eol, rdncount, opts, urlprefix ));
+}
+
+
+static int
+do_entry2text_search(
+ LDAP *ld,
+ char *dn, /* if NULL, use entry */
+ char *base, /* if NULL, no search actions */
+ LDAPMessage *entry, /* if NULL, use dn */
+ struct ldap_disptmpl* tmpllist, /* if NULL, no template used */
+ char **defattrs,
+ char ***defvals,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount, /* if 0, display full DN */
+ unsigned long opts,
+ char *urlprefix
+)
+{
+ int err, freedn, html;
+ char *buf, **fetchattrs, **vals;
+ LDAPMessage *ldmp;
+ struct ldap_disptmpl *tmpl;
+ struct timeval timeout;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( dn == NULL && entry == NULLMSG ) {
+ err = LDAP_PARAM_ERROR;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ html = ( urlprefix != NULL );
+
+ timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+ timeout.tv_usec = 0;
+
+ if (( buf = NSLDAPI_MALLOC( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ freedn = 0;
+ tmpl = NULL;
+
+ if ( dn == NULL ) {
+ if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
+ NSLDAPI_FREE( buf );
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+ freedn = 1;
+ }
+
+
+ if ( tmpllist != NULL ) {
+ ldmp = NULLMSG;
+
+ if ( entry == NULL ) {
+ char *ocattrs[2];
+
+ ocattrs[0] = OCATTRNAME;
+ ocattrs[1] = NULL;
+#ifdef CLDAP
+ if ( LDAP_IS_CLDAP( ld ))
+ err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE,
+ "objectClass=*", ocattrs, 0, &ldmp, NULL );
+ else
+#endif /* CLDAP */
+ err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE,
+ "objectClass=*", ocattrs, 0, &timeout, &ldmp );
+
+ if ( err == LDAP_SUCCESS ) {
+ entry = ldap_first_entry( ld, ldmp );
+ }
+ }
+
+ if ( entry != NULL ) {
+ vals = ldap_get_values( ld, entry, OCATTRNAME );
+ tmpl = ldap_oc2template( vals, tmpllist );
+ if ( vals != NULL ) {
+ ldap_value_free( vals );
+ }
+ }
+ if ( ldmp != NULL ) {
+ ldap_msgfree( ldmp );
+ }
+ }
+
+ entry = NULL;
+
+ if ( tmpl == NULL ) {
+ fetchattrs = NULL;
+ } else {
+ fetchattrs = ldap_tmplattrs( tmpl, NULL, 1, LDAP_SYN_OPT_DEFER );
+ }
+
+#ifdef CLDAP
+ if ( LDAP_IS_CLDAP( ld ))
+ err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+ fetchattrs, 0, &ldmp, NULL );
+ else
+#endif /* CLDAP */
+ err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+ fetchattrs, 0, &timeout, &ldmp );
+
+ if ( freedn ) {
+ NSLDAPI_FREE( dn );
+ }
+ if ( fetchattrs != NULL ) {
+ ldap_value_free( fetchattrs );
+ }
+
+ if ( err != LDAP_SUCCESS ||
+ ( entry = ldap_first_entry( ld, ldmp )) == NULL ) {
+ NSLDAPI_FREE( buf );
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ err = do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
+ writeproc, writeparm, eol, rdncount, opts, urlprefix );
+
+ NSLDAPI_FREE( buf );
+ ldap_msgfree( ldmp );
+ return( err );
+}
+
+
+int
+LDAP_CALL
+ldap_vals2text(
+ LDAP *ld,
+ char *buf, /* NULL for "use internal" */
+ char **vals,
+ char *label,
+ int labelwidth, /* 0 means use default */
+ unsigned long syntaxid,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount
+)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_vals2text\n", 0, 0, 0 );
+
+ return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
+ writeproc, writeparm, eol, rdncount, NULL ));
+}
+
+
+int
+LDAP_CALL
+ldap_vals2html(
+ LDAP *ld,
+ char *buf, /* NULL for "use internal" */
+ char **vals,
+ char *label,
+ int labelwidth, /* 0 means use default */
+ unsigned long syntaxid,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount,
+ char *urlprefix
+)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_vals2html\n", 0, 0, 0 );
+
+ if ( urlprefix == NULL ) {
+ urlprefix = DEF_LDAP_URL_PREFIX;
+ }
+
+ return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
+ writeproc, writeparm, eol, rdncount, urlprefix ));
+}
+
+
+static int
+do_vals2text(
+ LDAP *ld,
+ char *buf, /* NULL for "use internal" */
+ char **vals,
+ char *label,
+ int labelwidth, /* 0 means use default */
+ unsigned long syntaxid,
+ writeptype writeproc,
+ void *writeparm,
+ char *eol,
+ int rdncount,
+ char *urlprefix
+)
+{
+ int err, i, html, writeoutval, freebuf, notascii;
+ char *p, *s, *outval;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || writeproc == NULL ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( vals == NULL ) {
+ return( LDAP_SUCCESS );
+ }
+
+ html = ( urlprefix != NULL );
+
+ switch( LDAP_GET_SYN_TYPE( syntaxid )) {
+ case LDAP_SYN_TYPE_TEXT:
+ case LDAP_SYN_TYPE_BOOLEAN:
+ break; /* we only bother with these two types... */
+ default:
+ return( LDAP_SUCCESS );
+ }
+
+ if ( labelwidth == 0 || labelwidth < 0 ) {
+ labelwidth = DEF_LABEL_WIDTH;
+ }
+
+ if ( buf == NULL ) {
+ if (( buf = NSLDAPI_MALLOC( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+ freebuf = 1;
+ } else {
+ freebuf = 0;
+ }
+
+ output_label( buf, label, labelwidth, writeproc, writeparm, eol, html );
+
+ for ( i = 0; vals[ i ] != NULL; ++i ) {
+ for ( p = vals[ i ]; *p != '\0'; ++p ) {
+ if ( !isascii( *p )) {
+ break;
+ }
+ }
+ notascii = ( *p != '\0' );
+ outval = notascii ? dgettext(TEXT_DOMAIN,
+ "(unable to display non-ASCII text value)")
+ : vals[ i ];
+
+ writeoutval = 0; /* if non-zero, write outval after switch */
+
+ switch( syntaxid ) {
+ case LDAP_SYN_CASEIGNORESTR:
+ ++writeoutval;
+ break;
+
+ case LDAP_SYN_RFC822ADDR:
+ if ( html ) {
+ strcpy( buf, "<DD><A HREF=\"mailto:" );
+ strcat_escaped( buf, outval );
+ sprintf( buf + strlen( buf ), "\">%s</A><BR>%s", outval, eol );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ } else {
+ ++writeoutval;
+ }
+ break;
+
+ case LDAP_SYN_DN: /* for now */
+ output_dn( buf, outval, labelwidth, rdncount, writeproc,
+ writeparm, eol, urlprefix );
+ break;
+
+ case LDAP_SYN_MULTILINESTR:
+ if ( i > 0 && !html ) {
+ output_label( buf, label, labelwidth, writeproc,
+ writeparm, eol, html );
+ }
+
+ p = s = outval;
+ while (( s = strchr( s, '$' )) != NULL ) {
+ *s++ = '\0';
+ while ( ldap_utf8isspace( s )) {
+ ++s;
+ }
+ if ( html ) {
+ sprintf( buf, "<DD>%s<BR>%s", p, eol );
+ } else {
+ sprintf( buf, "%-*s%s%s", labelwidth, " ", p, eol );
+ }
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ p = s;
+ }
+ outval = p;
+ ++writeoutval;
+ break;
+
+ case LDAP_SYN_BOOLEAN:
+ outval = toupper( outval[ 0 ] ) == 'T' ?
+ dgettext(TEXT_DOMAIN, "TRUE") : dgettext(TEXT_DOMAIN, "FALSE");
+ ++writeoutval;
+ break;
+
+ case LDAP_SYN_TIME:
+ case LDAP_SYN_DATE:
+ outval = time2text( outval, syntaxid == LDAP_SYN_DATE );
+ ++writeoutval;
+ break;
+
+ case LDAP_SYN_LABELEDURL:
+ if ( !notascii && ( p = strchr( outval, '$' )) != NULL ) {
+ *p++ = '\0';
+ while ( ldap_utf8isspace( p )) {
+ ++p;
+ }
+ s = outval;
+ } else if ( !notascii && ( s = strchr( outval, ' ' )) != NULL ) {
+ *s++ = '\0';
+ while ( ldap_utf8isspace( s )) {
+ ++s;
+ }
+ p = outval;
+ } else {
+ s = "URL";
+ p = outval;
+ }
+
+ /*
+ * at this point `s' points to the label & `p' to the URL
+ */
+ if ( html ) {
+ sprintf( buf, "<DD><A HREF=\"%s\">%s</A><BR>%s", p, s, eol );
+ } else {
+ sprintf( buf, "%-*s%s%s%-*s%s%s", labelwidth, " ",
+ s, eol, labelwidth + 2, " ",p , eol );
+ }
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ break;
+
+ default:
+ sprintf( buf, dgettext(TEXT_DOMAIN,
+ " Can't display item type %ld%s"),
+ syntaxid, eol );
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ }
+
+ if ( writeoutval ) {
+ if ( html ) {
+ sprintf( buf, "<DD>%s<BR>%s", outval, eol );
+ } else {
+ sprintf( buf, "%-*s%s%s", labelwidth, " ", outval, eol );
+ }
+ (*writeproc)( writeparm, buf, strlen( buf ));
+ }
+ }
+
+ if ( freebuf ) {
+ NSLDAPI_FREE( buf );
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+static int
+max_label_len( struct ldap_disptmpl *tmpl )
+{
+ struct ldap_tmplitem *rowp, *colp;
+ int len, maxlen;
+
+ maxlen = 0;
+
+ for ( rowp = ldap_first_tmplrow( tmpl ); rowp != NULLTMPLITEM;
+ rowp = ldap_next_tmplrow( tmpl, rowp )) {
+ for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+ colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+ if (( len = strlen( colp->ti_label )) > maxlen ) {
+ maxlen = len;
+ }
+ }
+ }
+
+ return( maxlen );
+}
+
+
+static int
+output_label( char *buf, char *label, int width, writeptype writeproc,
+ void *writeparm, char *eol, int html )
+{
+ char *p;
+
+ if ( html ) {
+ sprintf( buf, "<DT><B>%s</B>", label );
+ } else {
+ auto size_t w;
+ sprintf( buf, " %s:", label );
+ p = buf + strlen( buf );
+
+ for (w = ldap_utf8characters(buf); w < (size_t)width; ++w) {
+ *p++ = ' ';
+ }
+
+ *p = '\0';
+ strcat( buf, eol );
+ }
+
+ return ((*writeproc)( writeparm, buf, strlen( buf )));
+}
+
+
+static int
+output_dn( char *buf, char *dn, int width, int rdncount,
+ writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
+{
+ char **dnrdns;
+ int i;
+
+ if (( dnrdns = ldap_explode_dn( dn, 1 )) == NULL ) {
+ return( -1 );
+ }
+
+ if ( urlprefix != NULL ) {
+ sprintf( buf, "<DD><A HREF=\"%s", urlprefix );
+ strcat_escaped( buf, dn );
+ strcat( buf, "\">" );
+ } else if ( width > 0 ) {
+ sprintf( buf, "%-*s", width, " " );
+ } else {
+ *buf = '\0';
+ }
+
+ for ( i = 0; dnrdns[ i ] != NULL && ( rdncount == 0 || i < rdncount );
+ ++i ) {
+ if ( i > 0 ) {
+ strcat( buf, ", " );
+ }
+ strcat( buf, dnrdns[ i ] );
+ }
+
+ if ( urlprefix != NULL ) {
+ strcat( buf, "</A><BR>" );
+ }
+
+ ldap_value_free( dnrdns );
+
+ strcat( buf, eol );
+
+ return ((*writeproc)( writeparm, buf, strlen( buf )));
+}
+
+
+
+#define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \
+ ( c >= '@' && c <= 'Z' ) || \
+ ( c == '_' ) || \
+ ( c >= 'a' && c <= 'z' ))
+
+static void
+strcat_escaped( char *s1, char *s2 )
+{
+ char *p, *q;
+ char *hexdig = "0123456789ABCDEF";
+
+ p = s1 + strlen( s1 );
+ for ( q = s2; *q != '\0'; ++q ) {
+ if ( HREF_CHAR_ACCEPTABLE( *q )) {
+ *p++ = *q;
+ } else {
+ *p++ = '%';
+ *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ];
+ *p++ = hexdig[ 0x0F & *q ];
+ }
+ }
+
+ *p = '\0';
+}
+
+
+#define GET2BYTENUM( p ) (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
+
+static char *
+time2text( char *ldtimestr, int dateonly )
+{
+ int len;
+ struct tm t;
+ char *p, *timestr, zone, *fmterr =
+ dgettext(TEXT_DOMAIN, "badly formatted time");
+ time_t gmttime;
+/* CTIME for this platform doesn't use this. */
+#if !defined(SUNOS4) && !defined(BSDI) && !defined(LINUX1_2) && \
+ !defined(SNI) && !defined(_WIN32) && !defined(macintosh) && !defined(LINUX)
+ char buf[26];
+#endif
+
+ memset( (char *)&t, 0, sizeof( struct tm ));
+ if (( len = (int)strlen( ldtimestr )) < 13 ) {
+ return( fmterr );
+ }
+ if ( len > 15 ) { /* throw away excess from 4-digit year time string */
+ len = 15;
+ } else if ( len == 14 ) {
+ len = 13; /* assume we have a time w/2-digit year (len=13) */
+ }
+
+ for ( p = ldtimestr; p - ldtimestr + 1 < len; ++p ) {
+ if ( !isdigit( *p )) {
+ return( fmterr );
+ }
+ }
+
+ p = ldtimestr;
+ t.tm_year = GET2BYTENUM( p ); p += 2;
+ if ( len == 15 ) {
+ t.tm_year = 100 * (t.tm_year - 19);
+ t.tm_year += GET2BYTENUM( p ); p += 2;
+ }
+ else {
+ /* 2 digit years...assumed to be in the range (19)70 through
+ (20)69 ...less than 70 (for now, 38) means 20xx */
+ if(t.tm_year < 70) {
+ t.tm_year += 100;
+ }
+ }
+ t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
+ t.tm_mday = GET2BYTENUM( p ); p += 2;
+ t.tm_hour = GET2BYTENUM( p ); p += 2;
+ t.tm_min = GET2BYTENUM( p ); p += 2;
+ t.tm_sec = GET2BYTENUM( p ); p += 2;
+
+ if (( zone = *p ) == 'Z' ) { /* GMT */
+ zone = '\0'; /* no need to indicate on screen, so we make it null */
+ }
+
+ gmttime = gtime( &t );
+ timestr = NSLDAPI_CTIME( &gmttime, buf, sizeof(buf) );
+
+ timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
+ if ( dateonly ) {
+ strcpy( timestr + 11, timestr + 20 );
+ }
+
+ return( timestr );
+}
+
+
+
+/* gtime.c - inverse gmtime */
+
+#if !defined( macintosh ) && !defined( _WINDOWS ) && !defined( DOS ) && !defined(XP_OS2)
+#include <sys/time.h>
+#endif /* !macintosh */
+
+/* gtime(): the inverse of localtime().
+ This routine was supplied by Mike Accetta at CMU many years ago.
+ */
+
+static int dmsize[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define dysize(y) \
+ (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
+
+/*
+#define YEAR(y) ((y) >= 100 ? (y) : (y) + 1900)
+*/
+#define YEAR(y) (((y) < 1900) ? ((y) + 1900) : (y))
+
+/* */
+
+static long gtime ( struct tm *tm )
+{
+ register int i,
+ sec,
+ mins,
+ hour,
+ mday,
+ mon,
+ year;
+ register long result;
+
+ if ((sec = tm -> tm_sec) < 0 || sec > 59
+ || (mins = tm -> tm_min) < 0 || mins > 59
+ || (hour = tm -> tm_hour) < 0 || hour > 24
+ || (mday = tm -> tm_mday) < 1 || mday > 31
+ || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
+ return ((long) -1);
+ if (hour == 24) {
+ hour = 0;
+ mday++;
+ }
+ year = YEAR (tm -> tm_year);
+
+ result = 0L;
+ for (i = 1970; i < year; i++)
+ result += dysize (i);
+ if (dysize (year) == 366 && mon >= 3)
+ result++;
+ while (--mon)
+ result += dmsize[mon - 1];
+ result += mday - 1;
+ result = 24 * result + hour;
+ result = 60 * result + mins;
+ result = 60 * result + sec;
+
+ return result;
+}
+
+static int
+searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry, char *dn,
+ struct ldap_tmplitem *tip, int labelwidth, int rdncount,
+ writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
+{
+ int err = LDAP_SUCCESS, lderr, i, count, html;
+ char **vals, **members;
+ char *value, *filtpattern, *attr, *selectname;
+ char *retattrs[2], filter[ 256 ];
+ LDAPMessage *ldmp;
+ struct timeval timeout;
+
+ html = ( urlprefix != NULL );
+
+ for ( i = 0; tip->ti_args != NULL && tip->ti_args[ i ] != NULL; ++i ) {
+ ;
+ }
+ if ( i < 3 ) {
+ return( LDAP_PARAM_ERROR );
+ }
+ attr = tip->ti_args[ 0 ];
+ filtpattern = tip->ti_args[ 1 ];
+ retattrs[ 0 ] = tip->ti_args[ 2 ];
+ retattrs[ 1 ] = NULL;
+ selectname = tip->ti_args[ 3 ];
+
+ vals = NULL;
+ if ( attr == NULL ) {
+ value = NULL;
+ } else if ( strcasecmp( attr, "-dnb" ) == 0 ) {
+ return( LDAP_PARAM_ERROR );
+ } else if ( strcasecmp( attr, "-dnt" ) == 0 ) {
+ value = dn;
+ } else if (( vals = ldap_get_values( ld, entry, attr )) != NULL ) {
+ value = vals[ 0 ];
+ } else {
+ value = NULL;
+ }
+
+ ldap_build_filter( filter, sizeof( filter ), filtpattern, NULL, NULL, NULL,
+ value, NULL );
+
+ if ( html ) {
+ /*
+ * if we are generating HTML, we add an HREF link that embodies this
+ * search action as an LDAP URL, instead of actually doing the search
+ * now.
+ */
+ sprintf( buf, "<DT><A HREF=\"%s", urlprefix );
+ if ( base != NULL ) {
+ strcat_escaped( buf, base );
+ }
+ strcat( buf, "??sub?" );
+ strcat_escaped( buf, filter );
+ sprintf( buf + strlen( buf ), "\"><B>%s</B></A><DD><BR>%s",
+ tip->ti_label, eol );
+ if ((*writeproc)( writeparm, buf, strlen( buf )) < 0 ) {
+ return( LDAP_LOCAL_ERROR );
+ }
+ return( LDAP_SUCCESS );
+ }
+
+ timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+ timeout.tv_usec = 0;
+
+#ifdef CLDAP
+ if ( LDAP_IS_CLDAP( ld ))
+ lderr = cldap_search_s( ld, base, LDAP_SCOPE_SUBTREE, filter, retattrs,
+ 0, &ldmp, NULL );
+ else
+#endif /* CLDAP */
+ lderr = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE, filter,
+ retattrs, 0, &timeout, &ldmp );
+
+ if ( lderr == LDAP_SUCCESS || NONFATAL_LDAP_ERR( lderr )) {
+ if (( count = ldap_count_entries( ld, ldmp )) > 0 ) {
+ if (( members = (char **)NSLDAPI_MALLOC( (count + 1)
+ * sizeof(char *))) == NULL ) {
+ err = LDAP_NO_MEMORY;
+ } else {
+ for ( i = 0, entry = ldap_first_entry( ld, ldmp );
+ entry != NULL;
+ entry = ldap_next_entry( ld, entry ), ++i ) {
+ members[ i ] = ldap_get_dn( ld, entry );
+ }
+ members[ i ] = NULL;
+
+ ldap_sort_values(ld,members, ldap_sort_strcasecmp);
+
+ err = do_vals2text( ld, NULL, members, tip->ti_label,
+ html ? -1 : 0, LDAP_SYN_DN, writeproc, writeparm,
+ eol, rdncount, urlprefix );
+
+ ldap_value_free( members );
+ }
+ }
+ ldap_msgfree( ldmp );
+ }
+
+
+ if ( vals != NULL ) {
+ ldap_value_free( vals );
+ }
+
+ return(( err == LDAP_SUCCESS ) ? lderr : err );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/ufn.c b/usr/src/lib/libldap5/sources/ldap/common/ufn.c
new file mode 100644
index 0000000000..7fbffcbdb6
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/ufn.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+/*
+ * ufn.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+typedef int (LDAP_CALL *cancelptype)( void *cancelparm );
+
+static int ldap_ufn_search_ctx( LDAP *ld, char **ufncomp, int ncomp,
+ char *prefix, char **attrs, int attrsonly,
+ LDAPMessage **res, LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm,
+ char *tag1, char *tag2, char *tag3 );
+static LDAPMessage *ldap_msg_merge( LDAP *ld, LDAPMessage *a, LDAPMessage *b );
+static LDAPMessage *ldap_ufn_expand( LDAP *ld,
+ LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm, char **dns,
+ char *filter, int scope, char **attrs, int aonly, int *err );
+
+/*
+ * ldap_ufn_search_ctx - do user friendly searching; provide cancel feature;
+ * specify ldapfilter.conf tags for each phase of search
+ *
+ * ld LDAP descriptor
+ * ufncomp the exploded user friendly name to look for
+ * ncomp number of elements in ufncomp
+ * prefix where to start searching
+ * attrs list of attribute types to return for matches
+ * attrsonly 1 => attributes only 0 => attributes and values
+ * res will contain the result of the search
+ * cancelproc routine that returns non-zero if operation should be
+ * cancelled. This can be NULL. If it is non-NULL, the
+ * routine will be called periodically.
+ * cancelparm void * that is passed to cancelproc
+ * tag[123] the ldapfilter.conf tag that will be used in phases
+ * 1, 2, and 3 of the search, respectively
+ *
+ * Example:
+ * char *attrs[] = { "mail", "title", 0 };
+ * char *ufncomp[] = { "howes", "umich", "us", 0 }
+ * LDAPMessage *res;
+ * error = ldap_ufn_search_ctx( ld, ufncomp, 3, NULL, attrs, attrsonly,
+ * &res, acancelproc, along, "ufn first",
+ * "ufn intermediate", "ufn last" );
+ */
+
+static int
+ldap_ufn_search_ctx(
+ LDAP *ld,
+ char **ufncomp,
+ int ncomp,
+ char *prefix,
+ char **attrs,
+ int attrsonly,
+ LDAPMessage **res,
+ LDAP_CANCELPROC_CALLBACK *cancelproc,
+ void *cancelparm,
+ char *tag1,
+ char *tag2,
+ char *tag3
+)
+{
+ char *dn, *ftag = NULL;
+ char **dns = NULL;
+ int max, i, err, scope = 0, phase, tries;
+ LDAPFiltInfo *fi;
+ LDAPMessage *tmpcand;
+ LDAPMessage *candidates;
+ static char *objattrs[] = { "objectClass", NULL };
+
+ /*
+ * look up ufn components from most to least significant.
+ * there are 3 phases.
+ * phase 1 search the root for orgs or countries
+ * phase 2 search for orgs
+ * phase 3 search for a person
+ * in phases 1 and 2, we are building a list of candidate DNs,
+ * below which we will search for the final component of the ufn.
+ * for each component we try the filters listed in the
+ * filterconfig file, first one-level (except the last compoment),
+ * then subtree. if any of them produce any results, we go on to
+ * the next component.
+ */
+
+ *res = NULL;
+ candidates = NULL;
+ phase = 1;
+ for ( ncomp--; ncomp != -1; ncomp-- ) {
+ if ( *ufncomp[ncomp] == '"' ) {
+ char *quote;
+
+ if ( (quote = strrchr( ufncomp[ncomp], '"' )) != NULL )
+ *quote = '\0';
+ strcpy( ufncomp[ncomp], ufncomp[ncomp] + 1 );
+ }
+ if ( ncomp == 0 )
+ phase = 3;
+
+ switch ( phase ) {
+ case 1:
+ ftag = tag1;
+ scope = LDAP_SCOPE_ONELEVEL;
+ break;
+ case 2:
+ ftag = tag2;
+ scope = LDAP_SCOPE_ONELEVEL;
+ break;
+ case 3:
+ ftag = tag3;
+ scope = LDAP_SCOPE_SUBTREE;
+ break;
+ }
+
+ /*
+ * construct an array of DN's to search below from the
+ * list of candidates.
+ */
+
+ if ( candidates == NULL ) {
+ if ( prefix != NULL ) {
+ if ( (dns = (char **)NSLDAPI_MALLOC(
+ sizeof(char *) * 2 )) == NULL ) {
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+ dns[0] = nsldapi_strdup( prefix );
+ dns[1] = NULL;
+ } else {
+ dns = NULL;
+ }
+ } else {
+ i = 0, max = 0;
+ for ( tmpcand = candidates; tmpcand != NULL &&
+ tmpcand->lm_msgtype != LDAP_RES_SEARCH_RESULT;
+ tmpcand = tmpcand->lm_chain )
+ {
+ if ( (dn = ldap_get_dn( ld, tmpcand )) == NULL )
+ continue;
+
+ if ( dns == NULL ) {
+ if ( (dns = (char **)NSLDAPI_MALLOC(
+ sizeof(char *) * 8 )) == NULL ) {
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err,
+ NULL, NULL );
+ return( err );
+ }
+ max = 8;
+ } else if ( i >= max ) {
+ if ( (dns = (char **)NSLDAPI_REALLOC(
+ dns, sizeof(char *) * 2 * max ))
+ == NULL ) {
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err,
+ NULL, NULL );
+ return( err );
+ }
+ max *= 2;
+ }
+ dns[i++] = dn;
+ dns[i] = NULL;
+ }
+ ldap_msgfree( candidates );
+ candidates = NULL;
+ }
+ tries = 0;
+ tryagain:
+ tries++;
+ for ( fi = ldap_getfirstfilter( ld->ld_filtd, ftag,
+ ufncomp[ncomp] ); fi != NULL;
+ fi = ldap_getnextfilter( ld->ld_filtd ) )
+ {
+ if ( (candidates = ldap_ufn_expand( ld, cancelproc,
+ cancelparm, dns, fi->lfi_filter, scope,
+ phase == 3 ? attrs : objattrs,
+ phase == 3 ? attrsonly : 1, &err )) != NULL )
+ {
+ break;
+ }
+
+ if ( err == -1 || err == LDAP_USER_CANCELLED ) {
+ if ( dns != NULL ) {
+ ldap_value_free( dns );
+ dns = NULL;
+ }
+ return( err );
+ }
+ }
+
+ if ( candidates == NULL ) {
+ if ( tries < 2 && phase != 3 ) {
+ scope = LDAP_SCOPE_SUBTREE;
+ goto tryagain;
+ } else {
+ if ( dns != NULL ) {
+ ldap_value_free( dns );
+ dns = NULL;
+ }
+ return( err );
+ }
+ }
+
+ /* go on to the next component */
+ if ( phase == 1 )
+ phase++;
+ if ( dns != NULL ) {
+ ldap_value_free( dns );
+ dns = NULL;
+ }
+ }
+ *res = candidates;
+
+ return( err );
+}
+
+int
+LDAP_CALL
+ldap_ufn_search_ct( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+ LDAPMessage **res, LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm,
+ char *tag1, char *tag2, char *tag3 )
+{
+ char **ufncomp, **prefixcomp;
+ char *pbuf;
+ int ncomp, pcomp, i, err = 0;
+
+ /* getfilter stuff must be inited before we are called */
+ if ( ld->ld_filtd == NULL ) {
+ err = LDAP_PARAM_ERROR;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ /* call ldap_explode_dn() to break the ufn into its components */
+ if ( (ufncomp = ldap_explode_dn( ufn, 0 )) == NULL ) {
+ err = LDAP_LOCAL_ERROR;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+ for ( ncomp = 0; ufncomp[ncomp] != NULL; ncomp++ )
+ ; /* NULL */
+
+ /* more than two components => try it fully qualified first */
+ if ( ncomp > 2 || ld->ld_ufnprefix == NULL ) {
+ err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, NULL, attrs,
+ attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
+
+ if ( ldap_count_entries( ld, *res ) > 0 ) {
+ ldap_value_free( ufncomp );
+ return( err );
+ } else {
+ ldap_msgfree( *res );
+ *res = NULL;
+ }
+ }
+
+ if ( ld->ld_ufnprefix == NULL ) {
+ ldap_value_free( ufncomp );
+ return( err );
+ }
+
+ /* if that failed, or < 2 components, use the prefix */
+ if ( (prefixcomp = ldap_explode_dn( ld->ld_ufnprefix, 0 )) == NULL ) {
+ ldap_value_free( ufncomp );
+ err = LDAP_LOCAL_ERROR;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+ for ( pcomp = 0; prefixcomp[pcomp] != NULL; pcomp++ )
+ ; /* NULL */
+ if ( (pbuf = (char *)NSLDAPI_MALLOC( strlen( ld->ld_ufnprefix ) + 1 ))
+ == NULL ) {
+ ldap_value_free( ufncomp );
+ ldap_value_free( prefixcomp );
+ err = LDAP_NO_MEMORY;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ for ( i = 0; i < pcomp; i++ ) {
+ int j;
+
+ *pbuf = '\0';
+ for ( j = i; j < pcomp; j++ ) {
+ strcat( pbuf, prefixcomp[j] );
+ if ( j + 1 < pcomp )
+ strcat( pbuf, "," );
+ }
+ err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, pbuf, attrs,
+ attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
+
+ if ( ldap_count_entries( ld, *res ) > 0 ) {
+ break;
+ } else {
+ ldap_msgfree( *res );
+ *res = NULL;
+ }
+ }
+
+ ldap_value_free( ufncomp );
+ ldap_value_free( prefixcomp );
+ NSLDAPI_FREE( pbuf );
+
+ return( err );
+}
+
+/*
+ * same as ldap_ufn_search_ct, except without the ability to specify
+ * ldapfilter.conf tags.
+ */
+int
+LDAP_CALL
+ldap_ufn_search_c( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+ LDAPMessage **res, LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm )
+{
+ return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res, cancelproc,
+ cancelparm, "ufn first", "ufn intermediate", "ufn last" ) );
+}
+
+/*
+ * same as ldap_ufn_search_c without the cancel function
+ */
+int
+LDAP_CALL
+ldap_ufn_search_s( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+ LDAPMessage **res )
+{
+ struct timeval tv;
+
+ tv.tv_sec = ld->ld_timelimit;
+
+ return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res,
+ ld->ld_timelimit ? ldap_ufn_timeout : NULL,
+ ld->ld_timelimit ? (void *) &tv : NULL,
+ "ufn first", "ufn intermediate", "ufn last" ) );
+}
+
+
+/*
+ * ldap_msg_merge - merge two ldap search result chains. the more
+ * serious of the two error result codes is kept.
+ */
+
+static LDAPMessage *
+ldap_msg_merge( LDAP *ld, LDAPMessage *a, LDAPMessage *b )
+{
+ LDAPMessage *end, *aprev, *aend, *bprev, *bend;
+
+ if ( a == NULL )
+ return( b );
+
+ if ( b == NULL )
+ return( a );
+
+ /* find the ends of the a and b chains */
+ aprev = NULL;
+ for ( aend = a; aend->lm_chain != NULL; aend = aend->lm_chain )
+ aprev = aend;
+ bprev = NULL;
+ for ( bend = b; bend->lm_chain != NULL; bend = bend->lm_chain )
+ bprev = bend;
+
+ /* keep result a */
+ if ( ldap_result2error( ld, aend, 0 ) != LDAP_SUCCESS ) {
+ /* remove result b */
+ ldap_msgfree( bend );
+ if ( bprev != NULL )
+ bprev->lm_chain = NULL;
+ else
+ b = NULL;
+ end = aend;
+ if ( aprev != NULL )
+ aprev->lm_chain = NULL;
+ else
+ a = NULL;
+ /* keep result b */
+ } else {
+ /* remove result a */
+ ldap_msgfree( aend );
+ if ( aprev != NULL )
+ aprev->lm_chain = NULL;
+ else
+ a = NULL;
+ end = bend;
+ if ( bprev != NULL )
+ bprev->lm_chain = NULL;
+ else
+ b = NULL;
+ }
+
+ if ( (a == NULL && b == NULL) || (a == NULL && bprev == NULL) ||
+ (b == NULL && aprev == NULL) )
+ return( end );
+
+ if ( a == NULL ) {
+ bprev->lm_chain = end;
+ return( b );
+ } else if ( b == NULL ) {
+ aprev->lm_chain = end;
+ return( a );
+ } else {
+ bprev->lm_chain = end;
+ aprev->lm_chain = b;
+ return( a );
+ }
+}
+
+static LDAPMessage *
+ldap_ufn_expand( LDAP *ld, LDAP_CANCELPROC_CALLBACK *cancelproc,
+ void *cancelparm, char **dns, char *filter, int scope,
+ char **attrs, int aonly, int *err )
+{
+ LDAPMessage *tmpcand, *tmpres;
+ char *dn;
+ int i, msgid;
+ struct timeval tv;
+
+ /* search for this component below the current candidates */
+ tmpcand = NULL;
+ i = 0;
+ do {
+ if ( dns != NULL )
+ dn = dns[i];
+ else
+ dn = "";
+
+ if (( msgid = ldap_search( ld, dn, scope, filter, attrs,
+ aonly )) == -1 ) {
+ ldap_msgfree( tmpcand );
+ *err = LDAP_GET_LDERRNO( ld, NULL, NULL );
+ return( NULL );
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000; /* 1/10 of a second */
+
+ do {
+ *err = ldap_result( ld, msgid, 1, &tv, &tmpres );
+ if ( *err == 0 && cancelproc != NULL &&
+ (*cancelproc)( cancelparm ) != 0 ) {
+ ldap_abandon( ld, msgid );
+ *err = LDAP_USER_CANCELLED;
+ LDAP_SET_LDERRNO( ld, *err, NULL, NULL );
+ }
+ } while ( *err == 0 );
+
+ if ( *err == LDAP_USER_CANCELLED || *err < 0 ||
+ ( *err = ldap_result2error( ld, tmpres, 0 )) == -1 ) {
+ ldap_msgfree( tmpcand );
+ return( NULL );
+ }
+
+ tmpcand = ldap_msg_merge( ld, tmpcand, tmpres );
+
+ i++;
+ } while ( dns != NULL && dns[i] != NULL );
+
+ if ( ldap_count_entries( ld, tmpcand ) > 0 ) {
+ return( tmpcand );
+ } else {
+ ldap_msgfree( tmpcand );
+ return( NULL );
+ }
+}
+
+/*
+ * ldap_ufn_setfilter - set the filter config file used in ufn searching
+ */
+
+LDAPFiltDesc *
+LDAP_CALL
+ldap_ufn_setfilter( LDAP *ld, char *fname )
+{
+ if ( ld->ld_filtd != NULL )
+ ldap_getfilter_free( ld->ld_filtd );
+
+ return( ld->ld_filtd = ldap_init_getfilter( fname ) );
+}
+
+void
+LDAP_CALL
+ldap_ufn_setprefix( LDAP *ld, char *prefix )
+{
+ if ( ld->ld_ufnprefix != NULL )
+ NSLDAPI_FREE( ld->ld_ufnprefix );
+
+ ld->ld_ufnprefix = nsldapi_strdup( prefix );
+}
+
+int
+LDAP_C
+ldap_ufn_timeout( void *tvparam )
+{
+ struct timeval *tv;
+
+ tv = (struct timeval *)tvparam;
+
+ if ( tv->tv_sec != 0 ) {
+ tv->tv_usec = tv->tv_sec * 1000000; /* sec => micro sec */
+ tv->tv_sec = 0;
+ }
+ tv->tv_usec -= 100000; /* 1/10 of a second */
+
+ return( tv->tv_usec <= 0 ? 1 : 0 );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/unbind.c b/usr/src/lib/libldap5/sources/ldap/common/unbind.c
new file mode 100644
index 0000000000..5e786a1bf4
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/unbind.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+
+/*
+ * unbind.c
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+int
+LDAP_CALL
+ldap_unbind( LDAP *ld )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_unbind\n", 0, 0, 0 );
+
+ return( ldap_ld_free( ld, NULL, NULL, 1 ) );
+}
+
+
+int
+LDAP_CALL
+ldap_unbind_s( LDAP *ld )
+{
+ return( ldap_ld_free( ld, NULL, NULL, 1 ));
+}
+
+
+int
+LDAP_CALL
+ldap_unbind_ext( LDAP *ld, LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
+{
+ return( ldap_ld_free( ld, serverctrls, clientctrls, 1 ));
+}
+
+
+/*
+ * Dispose of the LDAP session ld, including all associated connections
+ * and resources. If close is non-zero, an unbind() request is sent as well.
+ */
+int
+ldap_ld_free( LDAP *ld, LDAPControl **serverctrls,
+ LDAPControl **clientctrls, int close )
+{
+ LDAPMessage *lm, *next;
+ int err = LDAP_SUCCESS;
+ LDAPRequest *lr, *nextlr;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ld->ld_sbp->sb_naddr == 0 ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+ /* free LDAP structure and outstanding requests/responses */
+ for ( lr = ld->ld_requests; lr != NULL; lr = nextlr ) {
+ nextlr = lr->lr_next;
+ nsldapi_free_request( ld, lr, 0 );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+
+ /* free and unbind from all open connections */
+ LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+ while ( ld->ld_conns != NULL ) {
+ nsldapi_free_connection( ld, ld->ld_conns, serverctrls,
+ clientctrls, 1, close );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+ } else {
+ int i;
+
+ for ( i = 0; i < ld->ld_sbp->sb_naddr; ++i ) {
+ NSLDAPI_FREE( ld->ld_sbp->sb_addrs[ i ] );
+ }
+ NSLDAPI_FREE( ld->ld_sbp->sb_addrs );
+ NSLDAPI_FREE( ld->ld_sbp->sb_fromaddr );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+ for ( lm = ld->ld_responses; lm != NULL; lm = next ) {
+ next = lm->lm_next;
+ ldap_msgfree( lm );
+ }
+ LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+
+ /* call cache unbind function to allow it to clean up after itself */
+ if ( ld->ld_cache_unbind != NULL ) {
+ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+ (void)ld->ld_cache_unbind( ld, 0, 0 );
+ LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+ }
+
+ /* call the dispose handle I/O callback if one is defined */
+ if ( ld->ld_extdisposehandle_fn != NULL ) {
+ /*
+ * We always pass the session extended I/O argument to
+ * the dispose handle callback.
+ */
+ ld->ld_extdisposehandle_fn( ld, ld->ld_ext_session_arg );
+ }
+
+ if ( ld->ld_error != NULL )
+ NSLDAPI_FREE( ld->ld_error );
+ if ( ld->ld_matched != NULL )
+ NSLDAPI_FREE( ld->ld_matched );
+ if ( ld->ld_host != NULL )
+ NSLDAPI_FREE( ld->ld_host );
+ if ( ld->ld_ufnprefix != NULL )
+ NSLDAPI_FREE( ld->ld_ufnprefix );
+ if ( ld->ld_filtd != NULL )
+ ldap_getfilter_free( ld->ld_filtd );
+ if ( ld->ld_abandoned != NULL )
+ NSLDAPI_FREE( ld->ld_abandoned );
+ if ( ld->ld_sbp != NULL )
+ ber_sockbuf_free( ld->ld_sbp );
+ if ( ld->ld_defhost != NULL )
+ NSLDAPI_FREE( ld->ld_defhost );
+ if ( ld->ld_servercontrols != NULL )
+ ldap_controls_free( ld->ld_servercontrols );
+ if ( ld->ld_clientcontrols != NULL )
+ ldap_controls_free( ld->ld_clientcontrols );
+ if ( ld->ld_preferred_language != NULL )
+ NSLDAPI_FREE( ld->ld_preferred_language );
+ nsldapi_iostatus_free( ld );
+#ifdef LDAP_SASLIO_HOOKS
+ if ( ld->ld_def_sasl_mech != NULL )
+ NSLDAPI_FREE( ld->ld_def_sasl_mech );
+ if ( ld->ld_def_sasl_realm != NULL )
+ NSLDAPI_FREE( ld->ld_def_sasl_realm );
+ if ( ld->ld_def_sasl_authcid != NULL )
+ NSLDAPI_FREE( ld->ld_def_sasl_authcid );
+ if ( ld->ld_def_sasl_authzid != NULL )
+ NSLDAPI_FREE( ld->ld_def_sasl_authzid );
+#endif
+
+ /*
+ * XXXmcs: should use cache function pointers to hook in memcache
+ */
+ if ( ld->ld_memcache != NULL ) {
+ ldap_memcache_set( ld, NULL );
+ }
+
+ /* free all mutexes we have allocated */
+ nsldapi_mutex_free_all( ld );
+ NSLDAPI_FREE( ld->ld_mutex );
+
+ NSLDAPI_FREE( (char *) ld );
+
+ return( err );
+}
+
+
+
+int
+nsldapi_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
+{
+ BerElement *ber;
+ int err, msgid;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_unbind\n", 0, 0, 0 );
+
+ /* create a message to send */
+ if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+ != LDAP_SUCCESS ) {
+ return( err );
+ }
+
+ /* fill it in */
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ msgid = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ if ( ber_printf( ber, "{itn", msgid, LDAP_REQ_UNBIND ) == -1 ) {
+ ber_free( ber, 1 );
+ err = LDAP_ENCODING_ERROR;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ if (( err = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+ != LDAP_SUCCESS ) {
+ ber_free( ber, 1 );
+ return( err );
+ }
+
+ /* send the message */
+ if ( nsldapi_ber_flush( ld, sb, ber, 1, 0 ) != 0 ) {
+ ber_free( ber, 1 );
+ err = LDAP_SERVER_DOWN;
+ LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+ return( err );
+ }
+
+ return( LDAP_SUCCESS );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/unescape.c b/usr/src/lib/libldap5/sources/ldap/common/unescape.c
new file mode 100644
index 0000000000..65de7c03b4
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/unescape.c
@@ -0,0 +1,68 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * LIBLDAP unescape.c -- LDAP URL un-escape routines
+ * We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
+ */
+
+#include "ldap-int.h"
+
+
+static int unhex( char c );
+
+
+void
+nsldapi_hex_unescape( char *s )
+{
+/*
+ * Remove URL hex escapes from s... done in place. The basic concept for
+ * this routine is borrowed from the WWW library HTUnEscape() routine.
+ */
+ char *p;
+
+ for ( p = s; *s != '\0'; ++s ) {
+ if ( *s == '%' ) {
+ if ( *++s != '\0' ) {
+ *p = unhex( *s ) << 4;
+ }
+ if ( *++s != '\0' ) {
+ *p++ += unhex( *s );
+ }
+ } else {
+ *p++ = *s;
+ }
+ }
+
+ *p = '\0';
+}
+
+
+static int
+unhex( char c )
+{
+ return( c >= '0' && c <= '9' ? c - '0'
+ : c >= 'A' && c <= 'F' ? c - 'A' + 10
+ : c - 'a' + 10 );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/common/url.c b/usr/src/lib/libldap5/sources/ldap/common/url.c
new file mode 100644
index 0000000000..fc0e1460f8
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/url.c
@@ -0,0 +1,853 @@
+/*
+ * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ */
+/* LIBLDAP url.c -- LDAP URL related routines
+ *
+ * LDAP URLs look like this:
+ * l d a p : / / hostport / dn [ ? attributes [ ? scope [ ? filter ] ] ]
+ *
+ * where:
+ * attributes is a comma separated list
+ * scope is one of these three strings: base one sub (default=base)
+ * filter is an string-represented filter as in RFC 1558
+ *
+ * e.g., ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich
+ *
+ * We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
+ */
+
+#if 0
+#ifndef lint
+static char copyright[] = "@(#) Copyright (c) 1996 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+
+static int skip_url_prefix( const char **urlp, int *enclosedp, int *securep );
+
+
+int
+LDAP_CALL
+ldap_is_ldap_url( const char *url )
+{
+ int enclosed, secure;
+
+ return( url != NULL
+ && skip_url_prefix( &url, &enclosed, &secure ));
+}
+
+
+static int
+skip_url_prefix( const char **urlp, int *enclosedp, int *securep )
+{
+/*
+ * return non-zero if this looks like a LDAP URL; zero if not
+ * if non-zero returned, *urlp will be moved past "ldap://" part of URL
+ * The data that *urlp points to is not changed by this function.
+ */
+ if ( *urlp == NULL ) {
+ return( 0 );
+ }
+
+ /* skip leading '<' (if any) */
+ if ( **urlp == '<' ) {
+ *enclosedp = 1;
+ ++*urlp;
+ } else {
+ *enclosedp = 0;
+ }
+
+ /* skip leading "URL:" (if any) */
+ if ( strlen( *urlp ) >= LDAP_URL_URLCOLON_LEN && strncasecmp(
+ *urlp, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
+ *urlp += LDAP_URL_URLCOLON_LEN;
+ }
+
+ /* check for an "ldap://" prefix */
+ if ( strlen( *urlp ) >= LDAP_URL_PREFIX_LEN && strncasecmp( *urlp,
+ LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
+ /* skip over URL prefix and return success */
+ *urlp += LDAP_URL_PREFIX_LEN;
+ *securep = 0;
+ return( 1 );
+ }
+
+ /* check for an "ldaps://" prefix */
+ if ( strlen( *urlp ) >= LDAPS_URL_PREFIX_LEN && strncasecmp( *urlp,
+ LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
+ /* skip over URL prefix and return success */
+ *urlp += LDAPS_URL_PREFIX_LEN;
+ *securep = 1;
+ return( 1 );
+ }
+
+ return( 0 ); /* not an LDAP URL */
+}
+
+
+int
+LDAP_CALL
+ldap_url_parse( const char *url, LDAPURLDesc **ludpp )
+{
+/*
+ * Pick apart the pieces of an LDAP URL.
+ */
+ int rc;
+
+ if (( rc = nsldapi_url_parse( url, ludpp, 1 )) == 0 ) {
+ if ( (*ludpp)->lud_scope == -1 ) {
+ (*ludpp)->lud_scope = LDAP_SCOPE_BASE;
+ }
+ if ( (*ludpp)->lud_filter == NULL ) {
+ (*ludpp)->lud_filter = "(objectclass=*)";
+ }
+ if ( *((*ludpp)->lud_dn) == '\0' ) {
+ (*ludpp)->lud_dn = NULL;
+ }
+ }
+
+ return( rc );
+}
+
+/* same as ldap_url_parse(), but dn is not require */
+int
+LDAP_CALL
+ldap_url_parse_nodn(const char *url, LDAPURLDesc **ludpp)
+{
+/*
+ * Pick apart the pieces of an LDAP URL.
+ */
+ int rc;
+
+ if ((rc = nsldapi_url_parse(url, ludpp, 0)) == 0) {
+ if ((*ludpp)->lud_scope == -1) {
+ (*ludpp)->lud_scope = LDAP_SCOPE_BASE;
+ }
+ if ((*ludpp)->lud_filter == NULL) {
+ (*ludpp)->lud_filter = "(objectclass=*)";
+ }
+ if ((*ludpp)->lud_dn && *((*ludpp)->lud_dn) == '\0') {
+ (*ludpp)->lud_dn = NULL;
+ }
+ }
+
+ return (rc);
+}
+
+
+/*
+ * like ldap_url_parse() with a few exceptions:
+ * 1) if dn_required is zero, a missing DN does not generate an error
+ * (we just leave the lud_dn field NULL)
+ * 2) no defaults are set for lud_scope and lud_filter (they are set to -1
+ * and NULL respectively if no SCOPE or FILTER are present in the URL).
+ * 3) when there is a zero-length DN in a URL we do not set lud_dn to NULL.
+ * 4) if an LDAPv3 URL extensions are included,
+ */
+int
+nsldapi_url_parse( const char *url, LDAPURLDesc **ludpp, int dn_required )
+{
+
+ LDAPURLDesc *ludp;
+ char *urlcopy, *attrs, *scope, *extensions = NULL, *p, *q;
+ int enclosed, secure, i, nattrs, at_start;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_url_parse(%s)\n", url, 0, 0 );
+
+ if ( url == NULL || ludpp == NULL ) {
+ return( LDAP_URL_ERR_PARAM );
+ }
+
+ *ludpp = NULL; /* pessimistic */
+
+ if ( !skip_url_prefix( &url, &enclosed, &secure )) {
+ return( LDAP_URL_ERR_NOTLDAP );
+ }
+
+ /* allocate return struct */
+ if (( ludp = (LDAPURLDesc *)NSLDAPI_CALLOC( 1, sizeof( LDAPURLDesc )))
+ == NULLLDAPURLDESC ) {
+ return( LDAP_URL_ERR_MEM );
+ }
+
+ if ( secure ) {
+ ludp->lud_options |= LDAP_URL_OPT_SECURE;
+ }
+
+ /* make working copy of the remainder of the URL */
+ if (( urlcopy = nsldapi_strdup( url )) == NULL ) {
+ ldap_free_urldesc( ludp );
+ return( LDAP_URL_ERR_MEM );
+ }
+
+ if ( enclosed && *((p = urlcopy + strlen( urlcopy ) - 1)) == '>' ) {
+ *p = '\0';
+ }
+
+ /* initialize scope and filter */
+ ludp->lud_scope = -1;
+ ludp->lud_filter = NULL;
+
+ /* lud_string is the only malloc'd string space we use */
+ ludp->lud_string = urlcopy;
+
+ /* scan forward for '/' that marks end of hostport and begin. of dn */
+ if (( ludp->lud_dn = strchr( urlcopy, '/' )) == NULL ) {
+ if ( dn_required ) {
+ ldap_free_urldesc( ludp );
+ return( LDAP_URL_ERR_NODN );
+ }
+ } else {
+ /* terminate hostport; point to start of dn */
+ *ludp->lud_dn++ = '\0';
+ }
+
+
+ if ( *urlcopy == '\0' ) {
+ ludp->lud_host = NULL;
+ } else {
+ ludp->lud_host = urlcopy;
+ nsldapi_hex_unescape( ludp->lud_host );
+
+ /*
+ * Locate and strip off optional port number (:#) in host
+ * portion of URL.
+ *
+ * If more than one space-separated host is listed, we only
+ * look for a port number within the right-most one since
+ * ldap_init() will handle host parameters that look like
+ * host:port anyway.
+ */
+ if (( p = strrchr( ludp->lud_host, ' ' )) == NULL ) {
+ p = ludp->lud_host;
+ } else {
+ ++p;
+ }
+ if ( *p == '[' && ( q = strchr( p, ']' )) != NULL ) {
+ /* square brackets present -- skip past them */
+ p = q++;
+ }
+ if (( p = strchr( p, ':' )) != NULL ) {
+ *p++ = '\0';
+ ludp->lud_port = atoi( p );
+ if ( *ludp->lud_host == '\0' ) {
+ /*
+ * no hostname and a port: invalid hostcode
+ * according to RFC 1738
+ */
+ ldap_free_urldesc(ludp);
+ return (LDAP_URL_ERR_HOSTPORT);
+ }
+ }
+ }
+
+ /* scan for '?' that marks end of dn and beginning of attributes */
+ attrs = NULL;
+ if ( ludp->lud_dn != NULL &&
+ ( attrs = strchr( ludp->lud_dn, '?' )) != NULL ) {
+ /* terminate dn; point to start of attrs. */
+ *attrs++ = '\0';
+
+ /* scan for '?' that marks end of attrs and begin. of scope */
+ if (( p = strchr( attrs, '?' )) != NULL ) {
+ /*
+ * terminate attrs; point to start of scope and scan for
+ * '?' that marks end of scope and begin. of filter
+ */
+ *p++ = '\0';
+ scope = p;
+
+ if (( p = strchr( scope, '?' )) != NULL ) {
+ /* terminate scope; point to start of filter */
+ *p++ = '\0';
+ if ( *p != '\0' ) {
+ ludp->lud_filter = p;
+ /*
+ * scan for the '?' that marks the end
+ * of the filter and the start of any
+ * extensions
+ */
+ if (( p = strchr( ludp->lud_filter, '?' ))
+ != NULL ) {
+ *p++ = '\0'; /* term. filter */
+ extensions = p;
+ }
+ if ( *ludp->lud_filter == '\0' ) {
+ ludp->lud_filter = NULL;
+ } else {
+ nsldapi_hex_unescape( ludp->lud_filter );
+ }
+ }
+ }
+
+
+ if ( strcasecmp( scope, "one" ) == 0 ) {
+ ludp->lud_scope = LDAP_SCOPE_ONELEVEL;
+ } else if ( strcasecmp( scope, "base" ) == 0 ) {
+ ludp->lud_scope = LDAP_SCOPE_BASE;
+ } else if ( strcasecmp( scope, "sub" ) == 0 ) {
+ ludp->lud_scope = LDAP_SCOPE_SUBTREE;
+ } else if ( *scope != '\0' ) {
+ ldap_free_urldesc( ludp );
+ return( LDAP_URL_ERR_BADSCOPE );
+ }
+ }
+ }
+
+ if ( ludp->lud_dn != NULL ) {
+ nsldapi_hex_unescape( ludp->lud_dn );
+ }
+
+ /*
+ * if attrs list was included, turn it into a null-terminated array
+ */
+ if ( attrs != NULL && *attrs != '\0' ) {
+ nsldapi_hex_unescape( attrs );
+ for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) {
+ if ( *p == ',' ) {
+ ++nattrs;
+ }
+ }
+
+ if (( ludp->lud_attrs = (char **)NSLDAPI_CALLOC( nattrs + 1,
+ sizeof( char * ))) == NULL ) {
+ ldap_free_urldesc( ludp );
+ return( LDAP_URL_ERR_MEM );
+ }
+
+ for ( i = 0, p = attrs; i < nattrs; ++i ) {
+ ludp->lud_attrs[ i ] = p;
+ if (( p = strchr( p, ',' )) != NULL ) {
+ *p++ ='\0';
+ }
+ nsldapi_hex_unescape( ludp->lud_attrs[ i ] );
+ }
+ }
+
+ /* if extensions list was included, check for critical ones */
+ if ( extensions != NULL && *extensions != '\0' ) {
+ /* Note: at present, we do not recognize ANY extensions */
+ at_start = 1;
+ for ( p = extensions; *p != '\0'; ++p ) {
+ if ( at_start ) {
+ if ( *p == '!' ) { /* critical extension */
+ ldap_free_urldesc( ludp );
+ /* this is what iplanet did *
+ return( LDAP_URL_UNRECOGNIZED_CRITICAL_EXTENSION );
+ * and this is what we do */
+ return( LDAP_URL_ERR_PARAM );
+ }
+ at_start = 0;
+ } else if ( *p == ',' ) {
+ at_start = 1;
+ }
+ }
+ }
+
+
+ *ludpp = ludp;
+
+ return( 0 );
+}
+
+
+void
+LDAP_CALL
+ldap_free_urldesc( LDAPURLDesc *ludp )
+{
+ if ( ludp != NULLLDAPURLDESC ) {
+ if ( ludp->lud_string != NULL ) {
+ NSLDAPI_FREE( ludp->lud_string );
+ }
+ if ( ludp->lud_attrs != NULL ) {
+ NSLDAPI_FREE( ludp->lud_attrs );
+ }
+ NSLDAPI_FREE( ludp );
+ }
+}
+
+
+int
+LDAP_CALL
+ldap_url_search( LDAP *ld, const char *url, int attrsonly )
+{
+ int err, msgid;
+ LDAPURLDesc *ludp;
+ BerElement *ber;
+ LDAPServer *srv;
+ char *host;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( -1 ); /* punt */
+ }
+
+ if ( ldap_url_parse( url, &ludp ) != 0 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( -1 );
+ }
+
+ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+ msgid = ++ld->ld_msgid;
+ LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+ if ( nsldapi_build_search_req( ld, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, ludp->lud_attrs, attrsonly, NULL, NULL,
+ -1, -1, msgid, &ber ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+
+ err = 0;
+
+ if ( ludp->lud_host == NULL ) {
+ host = ld->ld_defhost;
+ } else {
+ host = ludp->lud_host;
+ }
+
+ if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer )))
+ == NULL || ( host != NULL &&
+ ( srv->lsrv_host = nsldapi_strdup( host )) == NULL )) {
+ if ( srv != NULL ) {
+ NSLDAPI_FREE( srv );
+ }
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ err = -1;
+ } else {
+ if ( ludp->lud_port != 0 ) {
+ /* URL includes a port - use it */
+ srv->lsrv_port = ludp->lud_port;
+ } else if ( ludp->lud_host == NULL ) {
+ /* URL has no port or host - use port from ld */
+ srv->lsrv_port = ld->ld_defport;
+ } else if (( ludp->lud_options & LDAP_URL_OPT_SECURE ) == 0 ) {
+ /* ldap URL has a host but no port - use std. port */
+ srv->lsrv_port = LDAP_PORT;
+ } else {
+ /* ldaps URL has a host but no port - use std. port */
+ srv->lsrv_port = LDAPS_PORT;
+ }
+ }
+
+ if (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 ) {
+ srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
+ }
+
+ if ( err != 0 ) {
+ ber_free( ber, 1 );
+ } else {
+ err = nsldapi_send_server_request( ld, ber, msgid, NULL, srv,
+ NULL, NULL, 1 );
+ }
+
+ ldap_free_urldesc( ludp );
+ return( err );
+}
+
+
+int
+LDAP_CALL
+ldap_url_search_st( LDAP *ld, const char *url, int attrsonly,
+ struct timeval *timeout, LDAPMessage **res )
+{
+ int msgid;
+
+ /*
+ * It is an error to pass in a zero'd timeval.
+ */
+ if ( timeout != NULL && timeout->tv_sec == 0 &&
+ timeout->tv_usec == 0 ) {
+ if ( ld != NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ }
+ if ( res != NULL ) {
+ *res = NULL;
+ }
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) {
+ (void) ldap_abandon( ld, msgid );
+ LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
+ return( LDAP_TIMEOUT );
+ }
+
+ return( ldap_result2error( ld, *res, 0 ));
+}
+
+
+int
+LDAP_CALL
+ldap_url_search_s( LDAP *ld, const char *url, int attrsonly, LDAPMessage **res )
+{
+ int msgid;
+
+ if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, res ) == -1 ) {
+ return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ }
+
+ return( ldap_result2error( ld, *res, 0 ));
+}
+
+#ifdef _SOLARIS_SDK
+/*
+ * Locate the LDAP URL associated with a DNS domain name.
+ *
+ * The supplied DNS domain name is converted into a distinguished
+ * name. The directory entry specified by that distinguished name
+ * is searched for a labeledURI attribute. If successful then the
+ * LDAP URL is returned. If unsuccessful then that entry's parent
+ * is searched and so on until the target distinguished name is
+ * reduced to only two nameparts.
+ *
+ * For example, if 'ny.eng.wiz.com' is the DNS domain then the
+ * following entries are searched until one succeeds:
+ * dc=ny,dc=eng,dc=wiz,dc=com
+ * dc=eng,dc=wiz,dc=com
+ * dc=wiz,dc=com
+ *
+ * If dns_name is NULL then the environment variable LOCALDOMAIN is used.
+ * If attrs is not NULL then it is appended to the URL's attribute list.
+ * If scope is not NULL then it overrides the URL's scope.
+ * If filter is not NULL then it is merged with the URL's filter.
+ *
+ * If an error is encountered then zero is returned, otherwise a string
+ * URL is returned. The caller should free the returned string if it is
+ * non-zero.
+ */
+
+char *
+ldap_dns_to_url(
+ LDAP *ld,
+ char *dns_name,
+ char *attrs,
+ char *scope,
+ char *filter
+)
+{
+ char *dn;
+ char *url = 0;
+ char *url2 = 0;
+ LDAPURLDesc *urldesc;
+ char *cp;
+ char *cp2;
+ size_t attrs_len = 0;
+ size_t scope_len = 0;
+ size_t filter_len = 0;
+ int nameparts;
+ int no_attrs = 0;
+ int no_scope = 0;
+
+ if (dns_name == 0) {
+ dns_name = (char *)getenv("LOCALDOMAIN");
+ }
+
+ if ((ld == NULL) || ((dn = ldap_dns_to_dn(dns_name, &nameparts)) ==
+ NULL))
+ return (0);
+
+ if ((url = ldap_dn_to_url(ld, dn, nameparts)) == NULL) {
+ free(dn);
+ return (0);
+ }
+ free(dn);
+
+ /* merge filter and/or scope and/or attributes with URL */
+ if (attrs || scope || filter) {
+
+ if (attrs)
+ attrs_len = strlen(attrs) + 2; /* for comma and NULL */
+
+ if (scope)
+ scope_len = strlen(scope) + 1; /* for NULL */
+
+ if (filter)
+ filter_len = strlen(filter) + 4;
+ /* for ampersand, parentheses and NULL */
+
+ if (ldap_is_ldap_url(url)) {
+
+ if ((url2 = (char *)malloc(attrs_len + scope_len +
+ filter_len + strlen(url) + 1)) == NULL) {
+ return (0);
+ }
+ cp = url;
+ cp2 = url2;
+
+ /* copy URL scheme, hostname, port number and DN */
+ while (*cp && (*cp != '?')) {
+ *cp2++ = *cp++;
+ }
+
+ /* handle URL attributes */
+
+ if (*cp == '?') { /* test first '?' */
+ *cp2++ = *cp++; /* copy first '?' */
+
+ if (*cp == '?') { /* test second '?' */
+
+ /* insert supplied attributes */
+ if (attrs) {
+ while (*attrs) {
+ *cp2++ = *attrs++;
+ }
+ } else {
+ no_attrs = 1;
+ }
+
+ } else {
+
+ /* copy URL attributes */
+ while (*cp && (*cp != '?')) {
+ *cp2++ = *cp++;
+ }
+
+ /* append supplied attributes */
+ if (attrs) {
+ *cp2++ = ',';
+ while (*attrs) {
+ *cp2++ = *attrs++;
+ }
+ }
+ }
+
+ } else {
+ /* append supplied attributes */
+ if (attrs) {
+ *cp2++ = '?';
+ while (*attrs) {
+ *cp2++ = *attrs++;
+ }
+ } else {
+ no_attrs = 1;
+ }
+ }
+
+ /* handle URL scope */
+
+ if (*cp == '?') { /* test second '?' */
+ *cp2++ = *cp++; /* copy second '?' */
+
+ if (*cp == '?') { /* test third '?' */
+
+ /* insert supplied scope */
+ if (scope) {
+ while (*scope) {
+ *cp2++ = *scope++;
+ }
+ } else {
+ no_scope = 1;
+ }
+
+ } else {
+
+ if (scope) {
+ /* skip over URL scope */
+ while (*cp && (*cp != '?')) {
+ *cp++;
+ }
+ /* insert supplied scope */
+ while (*scope) {
+ *cp2++ = *scope++;
+ }
+ } else {
+
+ /* copy URL scope */
+ while (*cp && (*cp != '?')) {
+ *cp2++ = *cp++;
+ }
+ }
+ }
+
+ } else {
+ /* append supplied scope */
+ if (scope) {
+ if (no_attrs) {
+ *cp2++ = '?';
+ }
+ *cp2++ = '?';
+ while (*scope) {
+ *cp2++ = *scope++;
+ }
+ } else {
+ no_scope = 1;
+ }
+ }
+
+ /* handle URL filter */
+
+ if (*cp == '?') { /* test third '?' */
+ *cp2++ = *cp++; /* copy third '?' */
+
+ if (filter) {
+
+ /* merge URL and supplied filters */
+
+ *cp2++ = '(';
+ *cp2++ = '&';
+ /* copy URL filter */
+ while (*cp) {
+ *cp2++ = *cp++;
+ }
+ /* append supplied filter */
+ while (*filter) {
+ *cp2++ = *filter++;
+ }
+ *cp2++ = ')';
+ } else {
+
+ /* copy URL filter */
+ while (*cp) {
+ *cp2++ = *cp++;
+ }
+ }
+
+ } else {
+ /* append supplied filter */
+ if (filter) {
+ if (no_scope) {
+ if (no_attrs) {
+ *cp2++ = '?';
+ }
+ *cp2++ = '?';
+ }
+ *cp2++ = '?';
+ while (*filter) {
+ *cp2++ = *filter++;
+ }
+ }
+ }
+
+ *cp2++ = '\0';
+ free (url);
+ url = url2;
+
+ } else {
+ return (0); /* not an LDAP URL */
+ }
+ }
+ return (url);
+}
+
+/*
+ * Locate the LDAP URL associated with a distinguished name.
+ *
+ * The number of nameparts in the supplied distinguished name must be
+ * provided. The specified directory entry is searched for a labeledURI
+ * attribute. If successful then the LDAP URL is returned. If unsuccessful
+ * then that entry's parent is searched and so on until the target
+ * distinguished name is reduced to only two nameparts.
+ *
+ * For example, if 'l=ny,ou=eng,o=wiz,c=us' is the distinguished name
+ * then the following entries are searched until one succeeds:
+ * l=ny,ou=eng,o=wiz,c=us
+ * ou=eng,o=wiz,c=us
+ * o=wiz,c=us
+ *
+ * If an error is encountered then zero is returned, otherwise a string
+ * URL is returned. The caller should free the returned string if it is
+ * non-zero.
+ */
+
+char *
+ldap_dn_to_url(
+ LDAP *ld,
+ char *dn,
+ int nameparts
+)
+{
+ char *next_dn = dn;
+ char *url = 0;
+ char *attrs[2] = {"labeledURI", 0};
+ LDAPMessage *res, *e;
+ char **vals;
+
+ /*
+ * Search for a URL in the named entry or its parent entry.
+ * Continue until only 2 nameparts remain.
+ */
+ while (dn && (nameparts > 1) && (! url)) {
+
+ /* search for the labeledURI attribute */
+ if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE,
+ "(objectClass=*)", attrs, 0, &res) == LDAP_SUCCESS) {
+
+ /* locate the first entry returned */
+ if ((e = ldap_first_entry(ld, res)) != NULL) {
+
+ /* locate the labeledURI attribute */
+ if ((vals =
+ ldap_get_values(ld, e, "labeledURI")) !=
+ NULL) {
+
+ /* copy the attribute value */
+ if ((url = strdup((char *)vals[0])) !=
+ NULL) {
+ ldap_value_free(vals);
+ }
+ }
+ }
+ /* free the search results */
+ if (res != NULL) {
+ ldap_msgfree(res);
+ }
+ }
+
+ if (! url) {
+ /* advance along the DN by one namepart */
+ if (next_dn = strchr(dn, ',')) {
+ next_dn++;
+ dn = next_dn;
+ nameparts--;
+ }
+ }
+ }
+
+ return (url);
+}
+
+#endif /* _SOLARIS_SDK */
diff --git a/usr/src/lib/libldap5/sources/ldap/common/vlistctrl.c b/usr/src/lib/libldap5/sources/ldap/common/vlistctrl.c
new file mode 100644
index 0000000000..c4e85aeb33
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/common/vlistctrl.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/* vlistctrl.c - virtual list control implementation. */
+#include "ldap-int.h"
+
+
+
+/*
+ * function to create a VirtualListViewRequest control that can be passed
+ * to ldap_search_ext() or ldap_search_ext_s(). *ctrlp will be set to a
+ * freshly allocated LDAPControl structure. Returns an LDAP error code
+ * (LDAP_SUCCESS if all goes well).
+ *
+ * Parameters
+ * ld LDAP pointer to the desired connection
+ *
+ * ldvlistp the control structure.
+ *
+ * ctrlp the address of a place to put the constructed control
+
+ The controlValue is an OCTET STRING
+ whose value is the BER-encoding of the following SEQUENCE:
+
+ VirtualListViewRequest ::= SEQUENCE {
+ beforeCount INTEGER (0 .. maxInt),
+ afterCount INTEGER (0 .. maxInt),
+ CHOICE {
+ byIndex [0] SEQUENCE {
+ index INTEGER (0 .. maxInt),
+ contentCount INTEGER (0 .. maxInt) }
+ byValue [1] greaterThanOrEqual assertionValue }
+
+ beforeCount indicates how many entries before the target entry the
+ client wants the server to send. afterCount indicates the number of
+ entries after the target entry the client wants the server to send.
+ index and contentCount identify the target entry
+ greaterThanOrEqual is an attribute assertion value defined in
+ [LDAPv3]. If present, the value supplied in greaterThanOrEqual is used
+ to determine the target entry by comparison with the values of the
+ attribute specified as the primary sort key. The first list entry who's
+ value is no less than the supplied value is the target entry.
+
+ */
+
+int
+LDAP_CALL
+ldap_create_virtuallist_control(
+ LDAP *ld,
+ LDAPVirtualList *ldvlistp,
+ LDAPControl **ctrlp
+)
+{
+ BerElement *ber;
+ int rc;
+
+ if (!NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+
+ if ( NULL == ctrlp || NULL == ldvlistp ) {
+ LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return ( LDAP_PARAM_ERROR );
+ }
+
+ /* create a ber package to hold the controlValue */
+ if ( LDAP_SUCCESS != nsldapi_alloc_ber_with_options( ld, &ber ) )
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+
+ if ( LBER_ERROR == ber_printf( ber,
+ "{ii",
+ (int)ldvlistp->ldvlist_before_count,
+ (int)ldvlistp->ldvlist_after_count ))
+ /* XXX lossy casts */
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+
+ if (NULL == ldvlistp->ldvlist_attrvalue)
+ {
+ if ( LBER_ERROR == ber_printf( ber,
+ "t{ii}}",
+ LDAP_TAG_VLV_BY_INDEX,
+ (int)ldvlistp->ldvlist_index,
+ (int)ldvlistp->ldvlist_size ) )
+ /* XXX lossy casts */
+ {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+ }
+ else
+ {
+ if ( LBER_ERROR == ber_printf( ber,
+ "to}",
+ LDAP_TAG_VLV_BY_VALUE,
+ ldvlistp->ldvlist_attrvalue,
+ (int)strlen( ldvlistp->ldvlist_attrvalue )) ) {
+ LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_ENCODING_ERROR );
+ }
+ }
+
+
+ rc = nsldapi_build_control( LDAP_CONTROL_VLVREQUEST ,
+ ber,
+ 1,
+ 1,
+ ctrlp );
+
+ LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+ return( rc );
+
+}
+
+
+/*
+ * function to find and parse a VirtualListViewResponse control contained in
+ * "ctrls" *target_posp, *list_sizep, and *errcodep are set based on its
+ * contents. Returns an LDAP error code that indicates whether the parsing
+ * itself was successful (LDAP_SUCCESS if all goes well).
+
+ The controlValue is an OCTET STRING, whose value
+ is the BER encoding of a value of the following SEQUENCE:
+
+ VirtualListViewResponse ::= SEQUENCE {
+ targetPosition INTEGER (0 .. maxInt),
+ contentCount INTEGER (0 .. maxInt),
+ virtualListViewResult ENUMERATED {
+ success (0),
+ operatonsError (1),
+ unwillingToPerform (53),
+ insufficientAccessRights (50),
+ busy (51),
+ timeLimitExceeded (3),
+ adminLimitExceeded (11),
+ sortControlMissing (60),
+ indexRangeError (61),
+ other (80) } }
+
+ */
+int
+LDAP_CALL
+ldap_parse_virtuallist_control
+(
+ LDAP *ld,
+ LDAPControl **ctrls,
+ unsigned long *target_posp,
+ unsigned long *list_sizep,
+ int *errcodep
+)
+{
+ BerElement *ber;
+ int i, foundListControl, errcode;
+ LDAPControl *listCtrlp;
+ unsigned long target_pos, list_size;
+ int target_pos_int, list_size_int;
+
+ if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /* only ldapv3 or higher can do virtual lists. */
+ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+ return( LDAP_NOT_SUPPORTED );
+ }
+
+ /* find the listControl in the list of controls if it exists */
+ if ( ctrls == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+ return ( LDAP_CONTROL_NOT_FOUND );
+ }
+
+ foundListControl = 0;
+ for ( i = 0; (( ctrls[i] != NULL ) && ( !foundListControl )); i++ ) {
+ foundListControl = !strcmp( ctrls[i]->ldctl_oid,
+ LDAP_CONTROL_VLVRESPONSE );
+ }
+ if ( !foundListControl ) {
+ LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+ return ( LDAP_CONTROL_NOT_FOUND );
+ } else {
+ /* let local var point to the listControl */
+ listCtrlp = ctrls[i-1];
+ }
+
+ /* allocate a Ber element with the contents of the list_control's struct berval */
+ if ( ( ber = ber_init( &listCtrlp->ldctl_value ) ) == NULL ) {
+ LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+
+ /* decode the result from the Berelement */
+ if ( LBER_ERROR == ber_scanf( ber, "{iie}", &target_pos_int, &list_size_int,
+ &errcode ) ) {
+ LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+ ber_free( ber, 1 );
+ return( LDAP_DECODING_ERROR );
+ }
+
+ target_pos = target_pos_int;
+ list_size = list_size_int;
+
+ if ( target_posp != NULL ) {
+ *target_posp = target_pos;
+ }
+ if ( list_sizep != NULL ) {
+ *list_sizep = list_size;
+ }
+ if ( errcodep != NULL ) {
+ *errcodep = errcode;
+ }
+
+ /* the ber encoding is no longer needed */
+ ber_free(ber,1);
+
+ return(LDAP_SUCCESS);
+
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-dns.c b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-dns.c
new file mode 100644
index 0000000000..7c49225109
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-dns.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * DNS callback functions for libldap that use the NSPR (Netscape
+ * Portable Runtime) thread API.
+ *
+ */
+
+#ifdef _SOLARIS_SDK
+#include "solaris-int.h"
+#include <libintl.h>
+#include <syslog.h>
+#include <nsswitch.h>
+#include <synch.h>
+#include <nss_dbdefs.h>
+#include <netinet/in.h>
+static char *host_service = NULL;
+static DEFINE_NSS_DB_ROOT(db_root_hosts);
+#endif
+
+#include "ldappr-int.h"
+
+static LDAPHostEnt *prldap_gethostbyname( const char *name,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata );
+static LDAPHostEnt *prldap_gethostbyaddr( const char *addr, int length,
+ int type, LDAPHostEnt *result, char *buffer, int buflen,
+ int *statusp, void *extradata );
+static int prldap_getpeername( LDAP *ld, struct sockaddr *addr,
+ char *buffer, int buflen );
+static LDAPHostEnt *prldap_convert_hostent( LDAPHostEnt *ldhp,
+ PRHostEnt *prhp );
+
+#ifdef _SOLARIS_SDK
+static LDAPHostEnt *
+prldap_gethostbyname1(const char *name, LDAPHostEnt *result,
+ char *buffer, int buflen, int *statusp, void *extradata);
+extern int
+str2hostent(const char *instr, int lenstr, void *ent, char *buffer,
+ int buflen);
+#endif /* _SOLARIS_SDK */
+
+
+/*
+ * Install NSPR DNS functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_dns_functions( LDAP *ld )
+{
+ struct ldap_dns_fns dnsfns;
+
+ memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) );
+ dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
+ dnsfns.lddnsfn_gethostbyname = prldap_gethostbyname;
+ dnsfns.lddnsfn_gethostbyaddr = prldap_gethostbyaddr;
+ dnsfns.lddnsfn_getpeername = prldap_getpeername;
+ if ( ldap_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns ) != 0 ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static LDAPHostEnt *
+prldap_gethostbyname( const char *name, LDAPHostEnt *result,
+ char *buffer, int buflen, int *statusp, void *extradata )
+{
+ PRHostEnt prhent;
+
+ if( !statusp || ( *statusp = (int)PR_GetIPNodeByName( name,
+ PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT,
+ buffer, buflen, &prhent )) == PR_FAILURE ) {
+ return( NULL );
+ }
+
+ return( prldap_convert_hostent( result, &prhent ));
+}
+
+
+static LDAPHostEnt *
+prldap_gethostbyaddr( const char *addr, int length, int type,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata )
+{
+ PRHostEnt prhent;
+ PRNetAddr iaddr;
+
+ if ( PR_SetNetAddr(PR_IpAddrNull, PRLDAP_DEFAULT_ADDRESS_FAMILY,
+ 0, &iaddr) == PR_FAILURE
+ || PR_StringToNetAddr( addr, &iaddr ) == PR_FAILURE ) {
+ return( NULL );
+ }
+
+ if( !statusp || (*statusp = PR_GetHostByAddr(&iaddr, buffer,
+ buflen, &prhent )) == PR_FAILURE ) {
+ return( NULL );
+ }
+ return( prldap_convert_hostent( result, &prhent ));
+}
+
+static int
+prldap_getpeername( LDAP *ld, struct sockaddr *addr, char *buffer, int buflen)
+{
+ PRLDAPIOSocketArg *sa;
+ PRFileDesc *fd;
+ PRNetAddr iaddr;
+ int ret;
+
+ if (NULL != ld) {
+ ret = prldap_socket_arg_from_ld( ld, &sa );
+ if (ret != LDAP_SUCCESS) {
+ return (-1);
+ }
+ ret = PR_GetPeerName(sa->prsock_prfd, &iaddr);
+ if( ret == PR_FAILURE ) {
+ return( -1 );
+ }
+ *addr = *((struct sockaddr *)&iaddr.raw);
+ ret = PR_NetAddrToString(&iaddr, buffer, buflen);
+ if( ret == PR_FAILURE ) {
+ return( -1 );
+ }
+ return (0);
+ }
+ return (-1);
+}
+
+
+/*
+ * Function: prldap_convert_hostent()
+ * Description: copy the fields of a PRHostEnt struct to an LDAPHostEnt
+ * Returns: the LDAPHostEnt pointer passed in.
+ */
+static LDAPHostEnt *
+prldap_convert_hostent( LDAPHostEnt *ldhp, PRHostEnt *prhp )
+{
+ ldhp->ldaphe_name = prhp->h_name;
+ ldhp->ldaphe_aliases = prhp->h_aliases;
+ ldhp->ldaphe_addrtype = prhp->h_addrtype;
+ ldhp->ldaphe_length = prhp->h_length;
+ ldhp->ldaphe_addr_list = prhp->h_addr_list;
+ return( ldhp );
+}
+
+#ifdef _SOLARIS_SDK
+/*
+ * prldap_x_install_dns_skipdb attempts to prevent recursion in resolving
+ * the hostname to an IP address when a host name is given to LDAP user.
+ *
+ * For example, libsldap cannot use LDAP to resolve the host name to an
+ * address because of recursion. The caller is instructing libldap to skip
+ * the specified name service when resolving addresses for the specified
+ * ldap connection.
+ *
+ * Note:
+ * This only supports ipv4 addresses currently.
+ *
+ * Since host_service applies to all connections, calling
+ * prldap_x_install_dns_skipdb with name services other than
+ * ldap or what uses ldap (for example nis+ might use ldap) to
+ * skip will lead to unpredictable results.
+ *
+ * Returns:
+ * 0 if success and data base found
+ * -1 if failure
+ */
+
+int
+prldap_x_install_dns_skipdb(LDAP *ld, const char *skip)
+{
+ enum __nsw_parse_err pserr;
+ struct __nsw_switchconfig *conf;
+ struct __nsw_lookup *lkp;
+ struct ldap_dns_fns dns_fns;
+ char *name_list = NULL;
+ char *tmp;
+ const char *name;
+ int len;
+ boolean_t got_skip = B_FALSE;
+
+ /*
+ * db_root_hosts.lock mutex is used to ensure that the name list
+ * is not in use by the name service switch while we are updating
+ * the host_service
+ */
+
+ (void) mutex_lock(&db_root_hosts.lock);
+ conf = __nsw_getconfig("hosts", &pserr);
+ if (conf == NULL) {
+ (void) mutex_unlock(&db_root_hosts.lock);
+ return (0);
+ }
+
+ /* check for skip and count other backends */
+ for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
+ name = lkp->service_name;
+ if (strcmp(name, skip) == 0) {
+ got_skip = B_TRUE;
+ continue;
+ }
+ if (name_list == NULL)
+ name_list = strdup(name);
+ else {
+ len = strlen(name_list);
+ tmp = realloc(name_list, len + strlen(name) + 2);
+ if (tmp == NULL) {
+ free(name_list);
+ name_list = NULL;
+ } else {
+ name_list = tmp;
+ name_list[len++] = ' ';
+ (void) strcpy(name_list+len, name);
+ }
+ }
+ if (name_list == NULL) { /* alloc error */
+ (void) mutex_unlock(&db_root_hosts.lock);
+ __nsw_freeconfig(conf);
+ return (-1);
+ }
+ }
+ __nsw_freeconfig(conf);
+ if (!got_skip) {
+ /*
+ * Since skip name service not used for hosts, we do not need
+ * to install our private address resolution function
+ */
+ (void) mutex_unlock(&db_root_hosts.lock);
+ if (name_list != NULL)
+ free(name_list);
+ return (0);
+ }
+ if (host_service != NULL)
+ free(host_service);
+ host_service = name_list;
+ (void) mutex_unlock(&db_root_hosts.lock);
+
+ if (ldap_get_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
+ return (-1);
+ dns_fns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
+ dns_fns.lddnsfn_gethostbyname = prldap_gethostbyname1;
+ if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * prldap_initf_hosts is passed to and called by nss_search() as a
+ * service routine.
+ *
+ * Returns:
+ * None
+ */
+
+static void
+prldap_initf_hosts(nss_db_params_t *p)
+{
+ static char *no_service = "";
+
+ p->name = NSS_DBNAM_HOSTS;
+ p->flags |= NSS_USE_DEFAULT_CONFIG;
+ p->default_config = host_service == NULL ? no_service : host_service;
+}
+
+/*
+ * called by prldap_gethostbyname1()
+ */
+/*
+ * prldap_switch_gethostbyname_r is called by prldap_gethostbyname1 as a
+ * substitute for gethostbyname_r(). A method which prevents recursion. see
+ * prldap_gethostbyname1() and prldap_x_install_dns_skipdb().
+ *
+ * Returns:
+ * Valid pointer to hostent if success
+ * PR_FAILURE if failure
+ */
+
+static struct hostent *
+prldap_switch_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer, int buflen,
+ int *h_errnop)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ /*
+ * Log the information indicating that we are trying to
+ * resolve the LDAP server name.
+ */
+ syslog(LOG_INFO, "libldap: Resolving server name \"%s\"", name);
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
+
+ arg.key.name = name;
+ arg.stayopen = 0;
+
+ res = nss_search(&db_root_hosts, prldap_initf_hosts,
+ NSS_DBOP_HOSTS_BYNAME, &arg);
+ arg.status = res;
+ *h_errnop = arg.h_errno;
+ return (struct hostent *)NSS_XbyY_FINI(&arg);
+}
+
+/*
+ * prldap_gethostbyname1 is used to be a substitute gethostbyname_r for
+ * libldap when it is unsafe to use the normal nameservice functions.
+ *
+ * Returns:
+ * pointer to LDAPHostEnt: if success contains the address
+ * NULL pointer: if failure
+ */
+
+static LDAPHostEnt *
+prldap_gethostbyname1(const char *name, LDAPHostEnt *result,
+ char *buffer, int buflen, int *statusp, void *extradata)
+{
+ int h_errno;
+ LDAPHostEnt prhent;
+
+ if (!statusp || ( *statusp = prldap_switch_gethostbyname_r(name,
+ &prhent, buffer, buflen, &h_errno )) == PR_FAILURE) {
+ /*
+ * If we got here, it means that we are not able to
+ * resolve the LDAP server name and so warn the system
+ * adminstrator accordingly.
+ */
+ syslog(LOG_WARNING, "libldap: server name \"%s\" could not "
+ "be resolved", name);
+ return (NULL);
+ }
+
+ return (prldap_convert_hostent(result, &prhent));
+}
+
+#endif /* _SOLARIS_SDK */
diff --git a/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-error.c b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-error.c
new file mode 100644
index 0000000000..83f41bb54c
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-error.c
@@ -0,0 +1,229 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * Utilities for manageing the relationship between NSPR errors and
+ * OS (errno-style) errors.
+ *
+ * The overall strategy used is to map NSPR errors into OS errors.
+ */
+
+#include "ldappr-int.h"
+
+
+void
+prldap_set_system_errno( int oserrno )
+{
+ PR_SetError( PR_UNKNOWN_ERROR, oserrno );
+}
+
+
+int
+prldap_get_system_errno( void )
+{
+ return( PR_GetOSError());
+}
+
+/*
+ * Retrieve the NSPR error number, convert to a system error code, and return
+ * the result.
+ */
+struct prldap_errormap_entry {
+ PRInt32 erm_nspr; /* NSPR error code */
+ int erm_system; /* corresponding system error code */
+};
+
+/* XXX: not sure if this extra mapping for Windows is good or correct */
+#ifdef _WINDOWS
+#ifndef ENOTSUP
+#define ENOTSUP -1
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT WSAETIMEDOUT
+#endif
+#ifndef EADDRNOTAVAIL
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#endif
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#ifndef EISCONN
+#define EISCONN WSAEISCONN
+#endif
+#ifndef EADDRINUSE
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#ifndef ENOTCONN
+#define ENOTCONN WSAENOTCONN
+#endif
+#ifndef ENOTSOCK
+#define ENOTSOCK WSAENOTSOCK
+#endif
+#ifndef EPROTOTYPE
+#define EPROTOTYPE WSAEPROTOTYPE
+#endif
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#endif
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#endif
+#ifndef EOVERFLOW
+#define EOVERFLOW -1
+#endif
+#ifndef ECONNRESET
+#define ECONNRESET WSAECONNRESET
+#endif
+#ifndef ELOOP
+#define ELOOP WSAELOOP
+#endif
+#ifndef ENOTBLK
+#define ENOTBLK -1
+#endif
+#ifndef ETXTBSY
+#define ETXTBSY -1
+#endif
+#ifndef ENETDOWN
+#define ENETDOWN WSAENETDOWN
+#endif
+#ifndef ESHUTDOWN
+#define ESHUTDOWN WSAESHUTDOWN
+#endif
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif
+#endif /* _WINDOWS */
+
+/* XXX: need to verify that the -1 entries are correct (no mapping) */
+static struct prldap_errormap_entry prldap_errormap[] = {
+ { PR_OUT_OF_MEMORY_ERROR, ENOMEM },
+ { PR_BAD_DESCRIPTOR_ERROR, EBADF },
+ { PR_WOULD_BLOCK_ERROR, EAGAIN },
+ { PR_ACCESS_FAULT_ERROR, EFAULT },
+ { PR_INVALID_METHOD_ERROR, EINVAL }, /* XXX: correct mapping ? */
+ { PR_ILLEGAL_ACCESS_ERROR, EACCES }, /* XXX: correct mapping ? */
+ { PR_UNKNOWN_ERROR, -1 },
+ { PR_PENDING_INTERRUPT_ERROR, -1 },
+ { PR_NOT_IMPLEMENTED_ERROR, ENOTSUP },
+ { PR_IO_ERROR, EIO },
+ { PR_IO_TIMEOUT_ERROR, ETIMEDOUT }, /* XXX: correct mapping ? */
+ { PR_IO_PENDING_ERROR, -1 },
+ { PR_DIRECTORY_OPEN_ERROR, ENOTDIR },
+ { PR_INVALID_ARGUMENT_ERROR, EINVAL },
+ { PR_ADDRESS_NOT_AVAILABLE_ERROR, EADDRNOTAVAIL },
+ { PR_ADDRESS_NOT_SUPPORTED_ERROR, EAFNOSUPPORT },
+ { PR_IS_CONNECTED_ERROR, EISCONN },
+ { PR_BAD_ADDRESS_ERROR, EFAULT }, /* XXX: correct mapping ? */
+ { PR_ADDRESS_IN_USE_ERROR, EADDRINUSE },
+ { PR_CONNECT_REFUSED_ERROR, ECONNREFUSED },
+ { PR_NETWORK_UNREACHABLE_ERROR, EHOSTUNREACH },
+ { PR_CONNECT_TIMEOUT_ERROR, ETIMEDOUT },
+ { PR_NOT_CONNECTED_ERROR, ENOTCONN },
+ { PR_LOAD_LIBRARY_ERROR, -1 },
+ { PR_UNLOAD_LIBRARY_ERROR, -1 },
+ { PR_FIND_SYMBOL_ERROR, -1 },
+ { PR_INSUFFICIENT_RESOURCES_ERROR, -1 },
+ { PR_DIRECTORY_LOOKUP_ERROR, -1 },
+ { PR_TPD_RANGE_ERROR, -1 },
+ { PR_PROC_DESC_TABLE_FULL_ERROR, -1 },
+ { PR_SYS_DESC_TABLE_FULL_ERROR, -1 },
+ { PR_NOT_SOCKET_ERROR, ENOTSOCK },
+ { PR_NOT_TCP_SOCKET_ERROR, EPROTOTYPE },
+ { PR_SOCKET_ADDRESS_IS_BOUND_ERROR, -1 },
+ { PR_NO_ACCESS_RIGHTS_ERROR, EACCES }, /* XXX: correct mapping ? */
+ { PR_OPERATION_NOT_SUPPORTED_ERROR, EOPNOTSUPP },
+ { PR_PROTOCOL_NOT_SUPPORTED_ERROR, EPROTONOSUPPORT },
+ { PR_REMOTE_FILE_ERROR, -1 },
+#if defined(OSF1)
+ { PR_BUFFER_OVERFLOW_ERROR, -1 },
+#else
+ { PR_BUFFER_OVERFLOW_ERROR, EOVERFLOW },
+#endif /* OSF1 */
+ { PR_CONNECT_RESET_ERROR, ECONNRESET },
+ { PR_RANGE_ERROR, ERANGE },
+ { PR_DEADLOCK_ERROR, EDEADLK },
+#if defined(HPUX11) || defined(AIX4_3) || defined(OSF1)
+ { PR_FILE_IS_LOCKED_ERROR, -1 }, /* XXX: correct mapping ? */
+#else
+ { PR_FILE_IS_LOCKED_ERROR, EDEADLOCK }, /* XXX: correct mapping ? */
+#endif /* HPUX11 */
+ { PR_FILE_TOO_BIG_ERROR, EFBIG },
+ { PR_NO_DEVICE_SPACE_ERROR, ENOSPC },
+ { PR_PIPE_ERROR, EPIPE },
+ { PR_NO_SEEK_DEVICE_ERROR, ESPIPE },
+ { PR_IS_DIRECTORY_ERROR, EISDIR },
+ { PR_LOOP_ERROR, ELOOP },
+ { PR_NAME_TOO_LONG_ERROR, ENAMETOOLONG },
+ { PR_FILE_NOT_FOUND_ERROR, ENOENT },
+ { PR_NOT_DIRECTORY_ERROR, ENOTDIR },
+ { PR_READ_ONLY_FILESYSTEM_ERROR, EROFS },
+ { PR_DIRECTORY_NOT_EMPTY_ERROR, ENOTEMPTY },
+ { PR_FILESYSTEM_MOUNTED_ERROR, EBUSY },
+ { PR_NOT_SAME_DEVICE_ERROR, EXDEV },
+ { PR_DIRECTORY_CORRUPTED_ERROR, -1 },
+ { PR_FILE_EXISTS_ERROR, EEXIST },
+ { PR_MAX_DIRECTORY_ENTRIES_ERROR, -1 },
+ { PR_INVALID_DEVICE_STATE_ERROR, ENOTBLK }, /* XXX: correct mapping ? */
+ { PR_DEVICE_IS_LOCKED_ERROR, -2 },
+ { PR_NO_MORE_FILES_ERROR, ENFILE },
+ { PR_END_OF_FILE_ERROR, -1 },
+ { PR_FILE_SEEK_ERROR, ESPIPE }, /* XXX: correct mapping ? */
+ { PR_FILE_IS_BUSY_ERROR, ETXTBSY },
+ { PR_OPERATION_ABORTED_ERROR, -1 },
+ { PR_IN_PROGRESS_ERROR, -1 },
+ { PR_ALREADY_INITIATED_ERROR, -1 },
+ { PR_GROUP_EMPTY_ERROR, -1 },
+ { PR_INVALID_STATE_ERROR, -1 },
+ { PR_NETWORK_DOWN_ERROR, ENETDOWN },
+ { PR_SOCKET_SHUTDOWN_ERROR, ESHUTDOWN },
+ { PR_CONNECT_ABORTED_ERROR, ECONNABORTED },
+ { PR_HOST_UNREACHABLE_ERROR, EHOSTUNREACH },
+ { PR_MAX_ERROR, -1 },
+};
+
+
+int
+prldap_prerr2errno( void )
+{
+ int oserr, i;
+ PRInt32 nsprerr;
+
+ nsprerr = PR_GetError();
+
+ oserr = -1; /* unknown */
+ for ( i = 0; prldap_errormap[i].erm_nspr != PR_MAX_ERROR; ++i ) {
+ if ( prldap_errormap[i].erm_nspr == nsprerr ) {
+ oserr = prldap_errormap[i].erm_system;
+ break;
+ }
+ }
+
+ return( oserr );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-int.h b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-int.h
new file mode 100644
index 0000000000..79fbeff849
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-int.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * Internal header for libprldap -- glue NSPR (Netscape Portable Runtime)
+ * to libldap.
+ *
+ */
+
+#include <ldap.h>
+#include <nspr.h>
+#include <ldappr.h>
+
+#include <errno.h>
+#include <string.h>
+
+#ifdef _SOLARIS_SDK
+#include "solaris-int.h"
+#endif
+
+/*
+ * All of the sockets we use are IPv6 capable.
+ * Change the following #define to PR_AF_INET to support IPv4 only.
+ */
+#define PRLDAP_DEFAULT_ADDRESS_FAMILY PR_AF_INET6
+
+/*
+ * Data structures:
+ */
+
+/* data structure that populates the I/O callback session arg. */
+typedef struct lextiof_session_private {
+ PRPollDesc *prsess_pollds; /* for poll callback */
+ int prsess_pollds_count; /* # of elements in pollds */
+ int prsess_io_max_timeout; /* in milliseconds */
+ void *prsess_appdata; /* application specific data */
+} PRLDAPIOSessionArg;
+
+/* data structure that populates the I/O callback socket-specific arg. */
+typedef struct lextiof_socket_private {
+ PRFileDesc *prsock_prfd; /* associated NSPR file desc. */
+ int prsock_io_max_timeout; /* in milliseconds */
+ void *prsock_appdata; /* application specific data */
+} PRLDAPIOSocketArg;
+
+
+/*
+ * Function prototypes:
+ */
+
+/*
+ * From ldapprio.c:
+ */
+int prldap_install_io_functions( LDAP *ld, int shared );
+int prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp );
+int prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp,
+ int io_max_timeout );
+int prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp,
+ int *io_max_timeoutp );
+int prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp );
+
+
+/*
+ * From ldapprthreads.c:
+ */
+int prldap_install_thread_functions( LDAP *ld, int shared );
+int prldap_thread_new_handle( LDAP *ld, void *sessionarg );
+void prldap_thread_dispose_handle( LDAP *ld, void *sessionarg );
+
+
+/*
+ * From ldapprdns.c:
+ */
+int prldap_install_dns_functions( LDAP *ld );
+#ifdef _SOLARIS_SDK
+int prldap_x_install_dns_skipdb( LDAP *ld, const char *skip );
+#endif
+
+
+
+/*
+ * From ldapprerror.c:
+ */
+void prldap_set_system_errno( int e );
+int prldap_get_system_errno( void );
+int prldap_prerr2errno( void );
diff --git a/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c
new file mode 100644
index 0000000000..824a8ca212
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c
@@ -0,0 +1,721 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * Extended I/O callback functions for libldap that use
+ * NSPR (Netscape Portable Runtime) I/O.
+ *
+ * High level strategy: we use the socket-specific arg to hold our own data
+ * structure that includes the NSPR file handle (PRFileDesc *), among other
+ * useful information. We use the default argument to hold an LDAP session
+ * handle specific data structure.
+ */
+
+#include "ldappr-int.h"
+#include <string.h>
+
+#define PRLDAP_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
+
+/*
+ * Local function prototypes:
+ */
+static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout );
+static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds,
+ int timeout, struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport,
+ int timeout, unsigned long options,
+ struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp
+#ifdef _SOLARIS_SDK
+ , void **dhost );
+#else
+ );
+#endif /* _SOLARIS_SDK */
+static int LDAP_CALLBACK prldap_close( int s,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_newhandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static PRLDAPIOSessionArg *prldap_session_arg_alloc( void );
+static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp );
+static PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg );
+static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp );
+static void *prldap_safe_realloc( void *ptr, PRUint32 size );
+
+
+
+/*
+ * Local macros:
+ */
+/* given a socket-specific arg, return the corresponding PRFileDesc * */
+#define PRLDAP_GET_PRFD( socketarg ) \
+ (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
+
+/*
+ * Static variables.
+ */
+static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+
+/*
+ * Install NSPR I/O functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_io_functions( LDAP *ld, int shared )
+{
+ struct ldap_x_ext_io_fns iofns;
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ iofns.lextiof_read = prldap_read;
+ iofns.lextiof_write = prldap_write;
+ iofns.lextiof_poll = prldap_poll;
+ iofns.lextiof_connect = prldap_connect;
+ iofns.lextiof_close = prldap_close;
+ if ( shared ) {
+ iofns.lextiof_newhandle = prldap_shared_newhandle;
+ iofns.lextiof_disposehandle = prldap_shared_disposehandle;
+ } else {
+ iofns.lextiof_newhandle = prldap_newhandle;
+ iofns.lextiof_disposehandle = prldap_disposehandle;
+ }
+ if ( NULL != ld ) {
+ /*
+ * If we are dealing with a real ld, we allocate the session specific
+ * data structure now. If not allocated here, it will be allocated
+ * inside prldap_newhandle() or prldap_shared_newhandle().
+ */
+ if ( NULL ==
+ ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+ ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ } else {
+ iofns.lextiof_session_arg = NULL;
+ }
+
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) {
+ prldap_session_arg_free(
+ (PRLDAPIOSessionArg **) &iofns.lextiof_session_arg );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static PRIntervalTime
+prldap_timeout2it( int ms_timeout, int ms_maxtimeout )
+{
+ PRIntervalTime prit;
+
+ if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) {
+ prit = PR_INTERVAL_NO_WAIT;
+ } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) {
+ prit = PR_INTERVAL_NO_TIMEOUT;
+ } else {
+ prit = PR_MillisecondsToInterval( ms_timeout );
+ }
+
+ /* cap at maximum I/O timeout */
+ if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) {
+ prit = LDAP_X_IO_TIMEOUT_NO_WAIT;
+ } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) {
+ if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ||
+ ms_timeout > ms_maxtimeout ) {
+ prit = PR_MillisecondsToInterval( ms_maxtimeout );
+ }
+ }
+
+#ifdef PRLDAP_DEBUG
+ if ( PR_INTERVAL_NO_WAIT == prit ) {
+ fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" );
+ } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) {
+ fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" );
+ } else {
+ fprintf( stderr, "prldap_timeout2it: %dms\n",
+ PR_IntervalToMilliseconds(prit));
+ }
+#endif /* PRLDAP_DEBUG */
+
+ return( prit );
+}
+
+
+static int LDAP_CALLBACK
+prldap_read( int s, void *buf, int bufsize,
+ struct lextiof_socket_private *socketarg )
+{
+ PRIntervalTime prit;
+
+ prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+ socketarg->prsock_io_max_timeout );
+ return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit ));
+}
+
+
+static int LDAP_CALLBACK
+prldap_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *socketarg )
+{
+ PRIntervalTime prit;
+
+ prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+ socketarg->prsock_io_max_timeout );
+
+ /*
+ * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
+ * must always be 0
+ */
+ return( PR_Send( PRLDAP_GET_PRFD(socketarg), buf, len, 0, prit ));
+}
+
+
+struct prldap_eventmap_entry {
+ PRInt16 evm_nspr; /* corresponding NSPR PR_Poll() event */
+ int evm_ldap; /* LDAP poll event */
+};
+
+static struct prldap_eventmap_entry prldap_eventmap[] = {
+ { PR_POLL_READ, LDAP_X_POLLIN },
+ { PR_POLL_EXCEPT, LDAP_X_POLLPRI },
+ { PR_POLL_WRITE, LDAP_X_POLLOUT },
+ { PR_POLL_ERR, LDAP_X_POLLERR },
+ { PR_POLL_HUP, LDAP_X_POLLHUP },
+ { PR_POLL_NVAL, LDAP_X_POLLNVAL },
+};
+
+#define PRLDAP_EVENTMAP_ENTRIES \
+ sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
+
+static int LDAP_CALLBACK
+prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
+ struct lextiof_session_private *sessionarg )
+{
+ PRLDAPIOSessionArg *prsessp = sessionarg;
+ PRPollDesc *pds;
+ int i, j, rc;
+
+ if ( NULL == prsessp ) {
+ prldap_set_system_errno( EINVAL );
+ return( -1 );
+ }
+
+ /* allocate or resize NSPR poll descriptor array */
+ if ( prsessp->prsess_pollds_count < nfds ) {
+ pds = prldap_safe_realloc( prsessp->prsess_pollds,
+ ( nfds + PRLDAP_POLL_ARRAY_GROWTH )
+ * sizeof( PRPollDesc ));
+ if ( NULL == pds ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ return( -1 );
+ }
+ prsessp->prsess_pollds = pds;
+ prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
+ } else {
+ pds = prsessp->prsess_pollds;
+ }
+
+ /* populate NSPR poll info. based on LDAP info. */
+ for ( i = 0; i < nfds; ++i ) {
+ if ( NULL == fds[i].lpoll_socketarg ) {
+ pds[i].fd = NULL;
+ } else {
+ pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg );
+ }
+ pds[i].in_flags = pds[i].out_flags = 0;
+ if ( fds[i].lpoll_fd >= 0 ) {
+ for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+ if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap )
+ != 0 ) {
+ pds[i].in_flags |= prldap_eventmap[j].evm_nspr;
+ }
+ }
+ }
+ fds[i].lpoll_revents = 0; /* clear revents */
+ }
+
+ /* call PR_Poll() to do the real work */
+ rc = PR_Poll( pds, nfds,
+ prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout ));
+
+ /* populate LDAP info. based on NSPR results */
+ for ( i = 0; i < nfds; ++i ) {
+ if ( pds[i].fd != NULL ) {
+ for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+ if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr )
+ != 0 ) {
+ fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap;
+ }
+ }
+ }
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Utility function to try one TCP connect()
+ * Returns 1 if successful and -1 if not. Sets the NSPR fd inside prsockp.
+ */
+static int
+prldap_try_one_address( struct lextiof_socket_private *prsockp,
+ PRNetAddr *addrp, int port, int timeout, unsigned long options )
+{
+ /*
+ * Set up address and open a TCP socket:
+ */
+ if ( PR_SUCCESS != PR_SetNetAddr( PR_IpAddrNull, /* don't touch IP addr. */
+ PRLDAP_DEFAULT_ADDRESS_FAMILY, (PRUint16)port, addrp )) {
+ return( -1 );
+ }
+
+ if (( prsockp->prsock_prfd = PR_OpenTCPSocket(
+ PRLDAP_DEFAULT_ADDRESS_FAMILY )) == NULL ) {
+ return( -1 );
+ }
+
+ /*
+ * Set nonblocking option if requested:
+ */
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) {
+ PRSocketOptionData optdata;
+
+ optdata.option = PR_SockOpt_Nonblocking;
+ optdata.value.non_blocking = PR_TRUE;
+ if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata )
+ != PR_SUCCESS ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ PR_Close( prsockp->prsock_prfd );
+ return( -1 );
+ }
+ }
+
+#ifdef PRLDAP_DEBUG
+ {
+ char buf[ 256 ], *p, *fmtstr;
+
+ if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) {
+ strcpy( buf, "conversion failed!" );
+ }
+ if ( strncmp( buf, "::ffff:", 7 ) == 0 ) {
+ /* IPv4 address mapped into IPv6 address space */
+ p = buf + 7;
+ fmtstr = "prldap_try_one_address(): Trying %s:%d...\n";
+ } else {
+ p = buf;
+ fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n";
+ }
+ fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port ));
+ }
+#endif /* PRLDAP_DEBUG */
+
+ /*
+ * Try to open the TCP connection itself:
+ */
+ if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp,
+ prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))) {
+ PR_Close( prsockp->prsock_prfd );
+ prsockp->prsock_prfd = NULL;
+ return( -1 );
+ }
+
+#ifdef PRLDAP_DEBUG
+ fputs( "prldap_try_one_address(): Connected.\n", stderr );
+#endif /* PRLDAP_DEBUG */
+
+ /*
+ * Success. Return a valid file descriptor (1 is always valid)
+ */
+ return( 1 );
+}
+
+
+/*
+ * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
+ */
+static int LDAP_CALLBACK
+prldap_connect( const char *hostlist, int defport, int timeout,
+ unsigned long options, struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp
+#ifdef _SOLARIS_SDK
+ , void **dhost )
+#else
+ )
+#endif /* _SOLARIS_SDK */
+{
+ int rc, parse_err, port;
+ char *host, hbuf[ PR_NETDB_BUF_SIZE ];
+ struct ldap_x_hostlist_status *status;
+ struct lextiof_socket_private *prsockp;
+ PRNetAddr addr;
+ PRHostEnt hent;
+#ifdef _SOLARIS_SDK
+ char *hostname = NULL;
+ char *nsldapi_strdup(char *);
+#endif /* _SOLARIS_SDK */
+
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
+ prldap_set_system_errno( EINVAL );
+ return( -1 );
+ }
+
+ if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ return( -1 );
+ }
+
+ rc = -1; /* pessimistic */
+ for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
+ &status );
+ rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
+ parse_err = ldap_x_hostlist_next( &host, &port, status )) {
+
+ if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) {
+
+ if ( PRLDAP_DEFAULT_ADDRESS_FAMILY == PR_AF_INET6 &&
+ PR_AF_INET == PR_NetAddrFamily( &addr )) {
+ PRUint32 ipv4ip = addr.inet.ip;
+ memset( &addr, 0, sizeof(addr));
+ PR_ConvertIPv4AddrToIPv6( ipv4ip, &addr.ipv6.ip );
+ addr.ipv6.family = PR_AF_INET6;
+
+ }
+ rc = prldap_try_one_address( prsockp, &addr, port,
+ timeout, options );
+ } else {
+ if ( PR_SUCCESS == PR_GetIPNodeByName( host,
+ PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT | PR_AI_ALL, hbuf,
+ sizeof( hbuf ), &hent )) {
+ PRIntn enumIndex = 0;
+
+ while ( rc < 0 && ( enumIndex = PR_EnumerateHostEnt(
+ enumIndex, &hent, (PRUint16)port, &addr )) > 0 ) {
+ rc = prldap_try_one_address( prsockp, &addr, port,
+ timeout, options );
+ }
+ }
+ }
+
+#ifdef _SOLARIS_SDK
+ if ( NULL != hostname ) ldap_memfree(hostname);
+ hostname = nsldapi_strdup(host);
+#endif /* _SOLARIS_SDK */
+ ldap_memfree( host );
+ }
+
+ ldap_x_hostlist_statusfree( status );
+
+ if ( rc < 0 ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ prldap_socket_arg_free( &prsockp );
+ } else {
+ *socketargp = prsockp;
+ }
+
+#ifdef _SOLARIS_SDK
+ if ( NULL != hostname && NULL != dhost ) *dhost = hostname;
+ else if ( NULL != hostname ) ldap_memfree(hostname);
+#endif /* _SOLARIS_SDK */
+
+ return( rc );
+}
+
+
+static int LDAP_CALLBACK
+prldap_close( int s, struct lextiof_socket_private *socketarg )
+{
+ int rc;
+
+ rc = 0;
+ if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) {
+ rc = -1;
+ prldap_set_system_errno( prldap_prerr2errno());
+ }
+ prldap_socket_arg_free( &socketarg );
+
+ return( rc );
+}
+
+
+/*
+ * LDAP session handle creation callback.
+ *
+ * Allocate a session argument if not already done, and then call the
+ * thread's new handle function.
+ */
+static int LDAP_CALLBACK
+prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+
+ if ( NULL == sessionarg ) {
+ struct ldap_x_ext_io_fns iofns;
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+ if ( NULL ==
+ ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+ return( LDAP_NO_MEMORY );
+ }
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/* only called/installed if shared is non-zero. */
+static int LDAP_CALLBACK
+prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+ int rc;
+
+ if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) {
+ rc = prldap_thread_new_handle( ld, sessionarg );
+ }
+
+ return( rc );
+}
+
+
+static void LDAP_CALLBACK
+prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+ prldap_session_arg_free( &sessionarg );
+}
+
+
+/* only called/installed if shared is non-zero */
+static void LDAP_CALLBACK
+prldap_shared_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg )
+{
+ prldap_thread_dispose_handle( ld, sessionarg );
+ prldap_disposehandle( ld, sessionarg );
+}
+
+
+/*
+ * Allocate a session argument.
+ */
+static PRLDAPIOSessionArg *
+prldap_session_arg_alloc( void )
+{
+ PRLDAPIOSessionArg *prsessp;
+
+ prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg ));
+
+ if ( NULL != prsessp ) {
+ /* copy global defaults to the new session handle */
+ prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout;
+ }
+
+ return( prsessp );
+}
+
+
+static void
+prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp )
+{
+ if ( NULL != prsesspp && NULL != *prsesspp ) {
+ if ( NULL != (*prsesspp)->prsess_pollds ) {
+ PR_Free( (*prsesspp)->prsess_pollds );
+ (*prsesspp)->prsess_pollds = NULL;
+ }
+ PR_Free( *prsesspp );
+ *prsesspp = NULL;
+ }
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a session argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp )
+{
+ struct ldap_x_ext_io_fns iofns;
+
+ if ( NULL == ld || NULL == sessargpp ) {
+ /* XXXmcs: NULL ld's are not supported */
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ if ( NULL == iofns.lextiof_session_arg ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ *sessargpp = iofns.lextiof_session_arg;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a socket argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp )
+{
+ Sockbuf *sbp;
+ struct lber_x_ext_io_fns extiofns;
+
+ if ( NULL == ld || NULL == sockargpp ) {
+ /* XXXmcs: NULL ld's are not supported */
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ memset( &extiofns, 0, sizeof(extiofns));
+ extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ if ( ber_sockbuf_get_option( sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ (void *)&extiofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ if ( NULL == extiofns.lbextiofn_socket_arg ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ *sockargpp = extiofns.lbextiofn_socket_arg;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Allocate a socket argument.
+ */
+static PRLDAPIOSocketArg *
+prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg )
+{
+ PRLDAPIOSocketArg *prsockp;
+
+ prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg ));
+
+ if ( NULL != prsockp && NULL != sessionarg ) {
+ /* copy socket defaults from the session */
+ prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout;
+ }
+
+ return( prsockp );
+}
+
+
+static void
+prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp )
+{
+ if ( NULL != prsockpp && NULL != *prsockpp ) {
+ PR_Free( *prsockpp );
+ *prsockpp = NULL;
+ }
+}
+
+
+static void *
+prldap_safe_realloc( void *ptr, PRUint32 size )
+{
+ void *p;
+
+ if ( NULL == ptr ) {
+ p = PR_Malloc( size );
+ } else {
+ p = PR_Realloc( ptr, size );
+ }
+
+ return( p );
+}
+
+
+
+/* returns an LDAP result code */
+int
+prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+
+ if ( NULL == prsessp ) {
+ prldap_default_io_max_timeout = io_max_timeout;
+ } else {
+ prsessp->prsess_io_max_timeout = io_max_timeout;
+ }
+
+ return( rc );
+}
+
+
+/* returns an LDAP result code */
+int
+prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+
+ if ( NULL == io_max_timeoutp ) {
+ rc = LDAP_PARAM_ERROR;
+ } else if ( NULL == prsessp ) {
+ *io_max_timeoutp = prldap_default_io_max_timeout;
+ } else {
+ *io_max_timeoutp = prsessp->prsess_io_max_timeout;
+ }
+
+ return( rc );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-public.c b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-public.c
new file mode 100644
index 0000000000..ad36e53e04
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-public.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * Public interface for libprldap -- use NSPR (Netscape Portable Runtime)
+ * I/O, threads, etc. with libldap.
+ *
+ */
+
+#include "ldappr-int.h"
+
+
+/*
+ * Function: prldap_init().
+ *
+ * Create a new LDAP session handle, but with NSPR I/O, threading, and DNS
+ * functions installed.
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * prldap_init() returns an LDAP session handle (or NULL if an error occurs).
+ */
+LDAP * LDAP_CALL
+prldap_init( const char *defhost, int defport, int shared )
+{
+ LDAP *ld;
+
+ if (( ld = ldap_init( defhost, defport )) != NULL ) {
+ if ( prldap_install_routines( ld, shared ) != LDAP_SUCCESS ) {
+ prldap_set_system_errno( EINVAL ); /* XXXmcs: just a guess! */
+ ldap_unbind( ld );
+ ld = NULL;
+ }
+ }
+
+ return( ld );
+}
+
+
+/*
+ * Function: prldap_install_routines().
+ *
+ * Install NSPR I/O, threading, and DNS functions so they will be used by
+ * 'ld'.
+ *
+ * If 'ld' is NULL, the functions are installed as the default functions
+ * for all new LDAP * handles).
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * prldap_install_routines() returns an LDAP API error code (LDAP_SUCCESS
+ * if all goes well).
+ */
+int LDAP_CALL
+prldap_install_routines( LDAP *ld, int shared )
+{
+
+ if ( prldap_install_io_functions( ld, shared ) != 0
+ || prldap_install_thread_functions( ld, shared ) != 0
+ || prldap_install_dns_functions( ld ) != 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+#ifndef _SOLARIS_SDK /* Not used, left in to stay in sync with iplanet */
+/*
+ * Function: prldap_set_session_option().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * SOCKET, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, set
+ * an option that affects the prldap layer.
+ *
+ * If 'ld' and 'session" are both NULL, the option is set as the default
+ * for all new prldap sessions.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL
+prldap_set_session_option( LDAP *ld, void *sessionarg, int option, ... )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+ PRLDAPIOSessionArg *prsessp = NULL;
+ va_list ap;
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ }
+
+ va_start( ap, option );
+ switch ( option ) {
+ case PRLDAP_OPT_IO_MAX_TIMEOUT:
+ rc = prldap_set_io_max_timeout( prsessp, va_arg( ap, int ));
+ break;
+ default:
+ rc = LDAP_PARAM_ERROR;
+ }
+ va_end( ap );
+
+ return( rc );
+}
+
+
+/*
+ * Function: prldap_get_session_option().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * SOCKET, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, retrieve
+ * the setting for an option that affects the prldap layer.
+ *
+ * If 'ld' and 'session" are both NULL, the default option value for all new
+ * new prldap sessions is retrieved.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_get_session_option( LDAP *ld, void *sessionarg,
+ int option, ... )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+ PRLDAPIOSessionArg *prsessp = NULL;
+ va_list ap;
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ }
+
+ va_start( ap, option );
+ switch ( option ) {
+ case PRLDAP_OPT_IO_MAX_TIMEOUT:
+ rc = prldap_get_io_max_timeout( prsessp, va_arg( ap, int * ));
+ break;
+ default:
+ rc = LDAP_PARAM_ERROR;
+ }
+ va_end( ap );
+
+ return( rc );
+}
+#endif /* !_SOLARIS_SDK */
+
+
+/*
+ * Function: prldap_set_session_info().
+ *
+ * Given an LDAP session handle, set some application-specific data.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL
+prldap_set_session_info( LDAP *ld, void *sessionarg, PRLDAPSessionInfo *seip )
+{
+ int rc;
+ PRLDAPIOSessionArg *prsessp;
+
+ if ( seip == NULL || PRLDAP_SESSIONINFO_SIZE != seip->seinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsessp->prsess_appdata = seip->seinfo_appdata;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_session_info().
+ *
+ * Given an LDAP session handle, retrieve some application-specific data.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that seip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_session_info( LDAP *ld, void *sessionarg, PRLDAPSessionInfo *seip )
+{
+ int rc;
+ PRLDAPIOSessionArg *prsessp;
+
+ if ( seip == NULL || PRLDAP_SESSIONINFO_SIZE != seip->seinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ seip->seinfo_appdata = prsessp->prsess_appdata;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_socket_info().
+ *
+ * Given an integer fd and a void * argument such as those passed to the
+ * extended I/O callback functions, set socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ *
+ * Note: it is only safe to change soinfo_prfd from within the SOCKET
+ * extended I/O callback function.
+ */
+int LDAP_CALL
+prldap_set_socket_info( int fd, void *socketarg, PRLDAPSocketInfo *soip )
+{
+ PRLDAPIOSocketArg *prsockp;
+
+ if ( NULL == socketarg || NULL == soip ||
+ PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsockp = (PRLDAPIOSocketArg *)socketarg;
+ prsockp->prsock_prfd = soip->soinfo_prfd;
+ prsockp->prsock_appdata = soip->soinfo_appdata;
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_socket_info().
+ *
+ * Given an integer fd and a void * argument such as those passed to the
+ * extended I/O callback functions, retrieve socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_socket_info( int fd, void *socketarg, PRLDAPSocketInfo *soip )
+{
+ PRLDAPIOSocketArg *prsockp;
+
+ if ( NULL == socketarg || NULL == soip ||
+ PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsockp = (PRLDAPIOSocketArg *)socketarg;
+ soip->soinfo_prfd = prsockp->prsock_prfd;
+ soip->soinfo_appdata = prsockp->prsock_appdata;
+
+ return( LDAP_SUCCESS );
+}
+
+/*
+ * Function: prldap_get_default_socket_info().
+ *
+ * Given an LDAP session handle, retrieve socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip )
+{
+ int rc;
+ PRLDAPIOSocketArg *prsockp;
+
+
+ if ( NULL == soip || PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_socket_arg_from_ld( ld, &prsockp ))) {
+ return( rc );
+ }
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ soip->soinfo_prfd = prsockp->prsock_prfd;
+ soip->soinfo_appdata = prsockp->prsock_appdata;
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_default_socket_info().
+ *
+ * Given an LDAP session handle, set socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_set_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip )
+{
+ int rc;
+ PRLDAPIOSocketArg *prsockp;
+
+
+ if ( NULL == soip || PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_socket_arg_from_ld( ld, &prsockp ))) {
+ return( rc );
+ }
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsockp->prsock_prfd = soip->soinfo_prfd;
+ prsockp->prsock_appdata = soip->soinfo_appdata;
+
+ return( LDAP_SUCCESS );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-threads.c b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-threads.c
new file mode 100644
index 0000000000..b6b8a0e27a
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-threads.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * Thread callback functions for libldap that use the NSPR (Netscape
+ * Portable Runtime) thread API.
+ *
+ */
+
+#ifdef _SOLARIS_SDK
+#include <thread.h>
+#include <synch.h>
+#include <prinit.h>
+#include <prthread.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+extern int errno;
+#endif /* _SOLARIS_SDK */
+
+#include "ldappr-int.h"
+
+#ifndef _SOLARIS_SDK
+/*
+ * Macros:
+ */
+/*
+ * Grow thread private data arrays 10 elements at a time.
+ */
+#define PRLDAP_TPD_ARRAY_INCREMENT 10
+
+/*
+ * Structures and types:
+ */
+/*
+ * Structure used by libldap thread callbacks to maintain error information.
+ */
+typedef struct prldap_errorinfo {
+ int plei_lderrno;
+ char *plei_matched;
+ char *plei_errmsg;
+} PRLDAP_ErrorInfo;
+
+/*
+ * Structure used to maintain thread-private data. At the present time,
+ * only error info. is thread-private. One of these structures is allocated
+ * for each thread.
+ */
+typedef struct prldap_tpd_header {
+ int ptpdh_tpd_count; /* # of data items allocated */
+ void **ptpdh_dataitems; /* array of data items */
+} PRLDAP_TPDHeader;
+
+/*
+ * Structure used by associate a PRLDAP thread-private data index with an
+ * LDAP session handle. One of these exists for each active LDAP session
+ * handle.
+ */
+typedef struct prldap_tpd_map {
+ LDAP *prtm_ld; /* non-NULL if in use */
+ PRUintn prtm_index; /* index into TPD array */
+ struct prldap_tpd_map *prtm_next;
+} PRLDAP_TPDMap;
+
+#ifdef _SOLARIS_SDK
+extern mutex_t inited_mutex;
+#endif /* _SOLARIS_SDK */
+
+/*
+ * Static Variables:
+ */
+/*
+ * prldap_map_list points to all of the PRLDAP_TPDMap structures
+ * we have ever allocated. We recycle them as we open and close LDAP
+ * sessions.
+ */
+static PRLDAP_TPDMap *prldap_map_list = NULL;
+
+
+/*
+ * The prldap_map_mutex is used to protect access to the prldap_map_list.
+ */
+static PRLock *prldap_map_mutex = NULL;
+
+/*
+ * The prldap_tpd_maxindex value is used to track the largest TPD array
+ * index we have used.
+ */
+static PRInt32 prldap_tpd_maxindex = -1;
+
+/*
+ * prldap_tpdindex is an NSPR thread private data index we use to
+ * maintain our own thread-private data. It is initialized inside
+ * prldap_init_tpd().
+ */
+static PRUintn prldap_tpdindex = 0;
+
+/*
+ * The prldap_callonce_init_tpd structure is used by NSPR to ensure
+ * that prldap_init_tpd() is called at most once.
+ */
+static PRCallOnceType prldap_callonce_init_tpd = { 0, 0, 0 };
+
+
+/*
+ * Private function prototypes:
+ */
+static void prldap_set_ld_error( int err, char *matched, char *errmsg,
+ void *errorarg );
+static int prldap_get_ld_error( char **matchedp, char **errmsgp,
+ void *errorarg );
+#endif
+static void *prldap_mutex_alloc( void );
+static void prldap_mutex_free( void *mutex );
+static int prldap_mutex_lock( void *mutex );
+static int prldap_mutex_unlock( void *mutex );
+static void *prldap_get_thread_id( void );
+#ifndef _SOLARIS_SDK
+static PRStatus prldap_init_tpd( void );
+static PRLDAP_TPDMap *prldap_allocate_map( LDAP *ld );
+static void prldap_return_map( PRLDAP_TPDMap *map );
+static PRUintn prldap_new_tpdindex( void );
+static int prldap_set_thread_private( PRInt32 tpdindex, void *priv );
+static void *prldap_get_thread_private( PRInt32 tpdindex );
+static PRLDAP_TPDHeader *prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr,
+ int maxindex );
+static void prldap_tsd_destroy( void *priv );
+#endif
+
+
+/*
+ * Install NSPR thread functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_thread_functions( LDAP *ld, int shared )
+{
+ struct ldap_thread_fns tfns;
+ struct ldap_extra_thread_fns xtfns;
+
+#ifndef _SOLARIS_SDK
+ if ( PR_CallOnce( &prldap_callonce_init_tpd, prldap_init_tpd )
+ != PR_SUCCESS ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( -1 );
+ }
+#endif /* _SOLARIS_SDK */
+
+ /* set thread function pointers */
+ memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
+ tfns.ltf_get_errno = prldap_get_system_errno;
+ tfns.ltf_set_errno = prldap_set_system_errno;
+ if ( shared ) {
+ tfns.ltf_mutex_alloc = prldap_mutex_alloc;
+ tfns.ltf_mutex_free = prldap_mutex_free;
+ tfns.ltf_mutex_lock = prldap_mutex_lock;
+ tfns.ltf_mutex_unlock = prldap_mutex_unlock;
+#ifdef _SOLARIS_SDK
+ tfns.ltf_get_lderrno = NULL;
+ tfns.ltf_set_lderrno = NULL;
+#else
+ tfns.ltf_get_lderrno = prldap_get_ld_error;
+ tfns.ltf_set_lderrno = prldap_set_ld_error;
+ if ( ld != NULL ) {
+ /*
+ * If this is a real ld (i.e., we are not setting the global
+ * defaults) allocate thread private data for error information.
+ * If ld is NULL we do not do this here but it is done in
+ * prldap_thread_new_handle().
+ */
+ if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld ))
+ == NULL ) {
+ return( -1 );
+ }
+ }
+#endif
+ }
+
+ if ( ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&tfns ) != 0 ) {
+#ifndef _SOLARIS_SDK
+ prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
+#endif
+ return( -1 );
+ }
+
+ /* set extended thread function pointers */
+ memset( &xtfns, '\0', sizeof(struct ldap_extra_thread_fns) );
+ xtfns.ltf_threadid_fn = prldap_get_thread_id;
+ if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
+ (void *)&xtfns ) != 0 ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static void *
+prldap_mutex_alloc( void )
+{
+ return( (void *)PR_NewLock());
+}
+
+
+static void
+prldap_mutex_free( void *mutex )
+{
+ PR_DestroyLock( (PRLock *)mutex );
+}
+
+
+static int
+prldap_mutex_lock( void *mutex )
+{
+ PR_Lock( (PRLock *)mutex );
+ return( 0 );
+}
+
+
+static int
+prldap_mutex_unlock( void *mutex )
+{
+ if ( PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static void *
+prldap_get_thread_id( void )
+{
+#ifdef _SOLARIS_SDK
+ return ((void *)thr_self());
+#else
+ return( (void *)PR_GetCurrentThread());
+#endif
+}
+
+#ifndef _SOLARIS_SDK
+static int
+prldap_get_ld_error( char **matchedp, char **errmsgp, void *errorarg )
+{
+ PRLDAP_TPDMap *map;
+ PRLDAP_ErrorInfo *eip;
+
+ if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL && ( eip =
+ (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+ map->prtm_index )) != NULL ) {
+ if ( matchedp != NULL ) {
+ *matchedp = eip->plei_matched;
+ }
+ if ( errmsgp != NULL ) {
+ *errmsgp = eip->plei_errmsg;
+ }
+ return( eip->plei_lderrno );
+ } else {
+ if ( matchedp != NULL ) {
+ *matchedp = NULL;
+ }
+ if ( errmsgp != NULL ) {
+ *errmsgp = NULL;
+ }
+ return( LDAP_LOCAL_ERROR ); /* punt */
+ }
+}
+
+
+static void
+prldap_set_ld_error( int err, char *matched, char *errmsg, void *errorarg )
+{
+ PRLDAP_TPDMap *map;
+ PRLDAP_ErrorInfo *eip;
+
+ if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL ) {
+ if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+ map->prtm_index )) == NULL ) {
+ /*
+ * Error info. has not yet been allocated for this thread.
+ * Do so now. Note that we free this memory only for the
+ * thread that calls prldap_thread_dispose_handle(), which
+ * should be the one that called ldap_unbind() -- see
+ * prldap_return_map(). Not freeing the memory used by
+ * other threads is deemed acceptable since it will be
+ * recycled and used by other LDAP sessions. All of the
+ * thread-private memory is freed when a thread exits
+ * (inside the prldap_tsd_destroy() function).
+ */
+ eip = (PRLDAP_ErrorInfo *)PR_Calloc( 1,
+ sizeof( PRLDAP_ErrorInfo ));
+ if ( eip == NULL ) {
+ return; /* punt */
+ }
+ (void)prldap_set_thread_private( map->prtm_index, eip );
+ }
+
+ eip->plei_lderrno = err;
+ if ( eip->plei_matched != NULL ) {
+ ldap_memfree( eip->plei_matched );
+ }
+ eip->plei_matched = matched;
+ if ( eip->plei_errmsg != NULL ) {
+ ldap_memfree( eip->plei_errmsg );
+ }
+ eip->plei_errmsg = errmsg;
+ }
+}
+#endif
+
+
+/*
+ * Called when a new LDAP * session handle is allocated.
+ * Allocate thread-private data for error information, but only if
+ * it has not already been allocated and the get_ld_error callback has
+ * been installed. If ld is not NULL when prldap_install_thread_functions()
+ * is called, we will have already allocated the thread-private data there.
+ */
+int
+prldap_thread_new_handle( LDAP *ld, void *sessionarg )
+{
+ struct ldap_thread_fns tfns;
+
+#ifndef _SOLARIS_SDK
+ if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *)&tfns ) != 0 ) {
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ if ( tfns.ltf_lderrno_arg == NULL && tfns.ltf_get_lderrno != NULL ) {
+ if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld )) == NULL
+ || ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&tfns ) != 0 ) {
+ return( LDAP_LOCAL_ERROR );
+ }
+ }
+#endif
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Called when an LDAP * session handle is being destroyed.
+ * Clean up our thread private data map.
+ */
+void
+prldap_thread_dispose_handle( LDAP *ld, void *sessionarg )
+{
+#ifndef _SOLARIS_SDK
+ struct ldap_thread_fns tfns;
+
+ if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&tfns ) == 0 &&
+ tfns.ltf_lderrno_arg != NULL ) {
+ prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
+ }
+#endif
+}
+
+
+#ifndef _SOLARIS_SDK
+static PRStatus
+prldap_init_tpd( void )
+{
+ if (( prldap_map_mutex = PR_NewLock()) == NULL || PR_NewThreadPrivateIndex(
+ &prldap_tpdindex, prldap_tsd_destroy ) != PR_SUCCESS ) {
+ return( PR_FAILURE );
+ }
+
+ prldap_map_list = NULL;
+
+ return( PR_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_allocate_map()
+ * Description: allocate a thread-private data map to use for a new
+ * LDAP session handle.
+ * Returns: a pointer to the TPD map or NULL if none available.
+ */
+static PRLDAP_TPDMap *
+prldap_allocate_map( LDAP *ld )
+{
+ PRLDAP_TPDMap *map, *prevmap;
+
+ PR_Lock( prldap_map_mutex );
+
+ /*
+ * first look for a map that is already allocated but free to be re-used
+ */
+ prevmap = NULL;
+ for ( map = prldap_map_list; map != NULL; map = map->prtm_next ) {
+ if ( map->prtm_ld == NULL ) {
+ break;
+ }
+ prevmap = map;
+ }
+
+ /*
+ * if none we found (map == NULL), try to allocate a new one and add it
+ * to the end of our global list.
+ */
+ if ( map == NULL ) {
+ PRUintn tpdindex;
+
+ tpdindex = prldap_new_tpdindex();
+ map = (PRLDAP_TPDMap *)PR_Malloc( sizeof( PRLDAP_TPDMap ));
+ if ( map != NULL ) {
+ map->prtm_index = tpdindex;
+ map->prtm_next = NULL;
+ if ( prevmap == NULL ) {
+ prldap_map_list = map;
+ } else {
+ prevmap->prtm_next = map;
+ }
+ }
+ }
+
+ if ( map != NULL ) {
+ map->prtm_ld = ld; /* now marked as "in use" */
+ /* since we are reusing...reset */
+ /* to initial state */
+ (void)prldap_set_thread_private( map->prtm_index, NULL );
+ }
+
+ PR_Unlock( prldap_map_mutex );
+
+ return( map );
+}
+
+
+/*
+ * Function: prldap_return_map()
+ * Description: return a thread-private data map to the pool of ones
+ * available for re-use.
+ */
+static void
+prldap_return_map( PRLDAP_TPDMap *map )
+{
+ PRLDAP_ErrorInfo *eip;
+
+ PR_Lock( prldap_map_mutex );
+
+ /*
+ * Dispose of thread-private LDAP error information. Note that this
+ * only disposes of the memory consumed on THIS thread, but that is
+ * okay. See the comment in prldap_set_ld_error() for the reason why.
+ */
+ if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+ map->prtm_index )) != NULL &&
+ prldap_set_thread_private( map->prtm_index, NULL ) == 0 ) {
+ if ( eip->plei_matched != NULL ) {
+ ldap_memfree( eip->plei_matched );
+ }
+ if ( eip->plei_errmsg != NULL ) {
+ ldap_memfree( eip->plei_errmsg );
+ }
+
+ PR_Free( eip );
+ }
+
+ /* mark map as available for re-use */
+ map->prtm_ld = NULL;
+
+ PR_Unlock( prldap_map_mutex );
+}
+
+
+/*
+ * Function: prldap_new_tpdindex()
+ * Description: allocate a thread-private data index.
+ * Returns: the new index.
+ */
+static PRUintn
+prldap_new_tpdindex( void )
+{
+ PRUintn tpdindex;
+
+ tpdindex = (PRUintn)PR_AtomicIncrement( &prldap_tpd_maxindex );
+ return( tpdindex );
+}
+
+
+/*
+ * Function: prldap_set_thread_private()
+ * Description: store a piece of thread-private data.
+ * Returns: 0 if successful and -1 if not.
+ */
+static int
+prldap_set_thread_private( PRInt32 tpdindex, void *priv )
+{
+ PRLDAP_TPDHeader *tsdhdr;
+
+ if ( tpdindex > prldap_tpd_maxindex ) {
+ return( -1 ); /* bad index */
+ }
+
+ tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
+ if ( tsdhdr == NULL || tpdindex >= tsdhdr->ptpdh_tpd_count ) {
+ tsdhdr = prldap_tsd_realloc( tsdhdr, tpdindex );
+ if ( tsdhdr == NULL ) {
+ return( -1 ); /* realloc failed */
+ }
+ }
+
+ tsdhdr->ptpdh_dataitems[ tpdindex ] = priv;
+ return( 0 );
+}
+
+
+/*
+ * Function: prldap_get_thread_private()
+ * Description: retrieve a piece of thread-private data. If not set,
+ * NULL is returned.
+ * Returns: 0 if successful and -1 if not.
+ */
+static void *
+prldap_get_thread_private( PRInt32 tpdindex )
+{
+ PRLDAP_TPDHeader *tsdhdr;
+
+ tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
+ if ( tsdhdr == NULL ) {
+ return( NULL ); /* no thread private data */
+ }
+
+ if ( tpdindex >= tsdhdr->ptpdh_tpd_count
+ || tsdhdr->ptpdh_dataitems == NULL ) {
+ return( NULL ); /* fewer data items than requested index */
+ }
+
+ return( tsdhdr->ptpdh_dataitems[ tpdindex ] );
+}
+
+
+/*
+ * Function: prldap_tsd_realloc()
+ * Description: enlarge the thread-private data array.
+ * Returns: the new PRLDAP_TPDHeader value (non-NULL if successful).
+ * Note: tsdhdr can be NULL (allocates a new PRLDAP_TPDHeader).
+ */
+static PRLDAP_TPDHeader *
+prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr, int maxindex )
+{
+ void *newdataitems = NULL;
+ int count;
+
+ if ( tsdhdr == NULL ) {
+ /* allocate a new thread private data header */
+ if (( tsdhdr = PR_Calloc( 1, sizeof( PRLDAP_TPDHeader ))) == NULL ) {
+ return( NULL );
+ }
+ (void)PR_SetThreadPrivate( prldap_tpdindex, tsdhdr );
+ }
+
+ /*
+ * Make the size of the new array the next highest multiple of
+ * the array increment value that is greater than maxindex.
+ */
+ count = PRLDAP_TPD_ARRAY_INCREMENT *
+ ( 1 + ( maxindex / PRLDAP_TPD_ARRAY_INCREMENT ));
+
+ /* increase the size of the data item array if necessary */
+ if ( count > tsdhdr->ptpdh_tpd_count ) {
+ newdataitems = (PRLDAP_ErrorInfo *)PR_Calloc( count, sizeof( void * ));
+ if ( newdataitems == NULL ) {
+ return( NULL );
+ }
+ if ( tsdhdr->ptpdh_dataitems != NULL ) { /* preserve old data */
+ memcpy( newdataitems, tsdhdr->ptpdh_dataitems,
+ tsdhdr->ptpdh_tpd_count * sizeof( void * ));
+ PR_Free( tsdhdr->ptpdh_dataitems );
+ }
+
+ tsdhdr->ptpdh_tpd_count = count;
+ tsdhdr->ptpdh_dataitems = newdataitems;
+ }
+
+ return( tsdhdr );
+}
+
+
+/*
+ * Function: prldap_tsd_destroy()
+ * Description: Free a thread-private data array. Installed as an NSPR TPD
+ * destructor function
+ * Returns: nothing.
+ * Note: this function assumes that each TPD item installed at the PRLDAP
+ * level can be freed with a call to PR_Free().
+ */
+static void
+prldap_tsd_destroy( void *priv )
+{
+ PRLDAP_TPDHeader *tsdhdr;
+ int i;
+
+ tsdhdr = (PRLDAP_TPDHeader *)priv;
+ if ( tsdhdr != NULL ) {
+ if ( tsdhdr->ptpdh_dataitems != NULL ) {
+ for ( i = 0; i < tsdhdr->ptpdh_tpd_count; ++i ) {
+ if ( tsdhdr->ptpdh_dataitems[ i ] != NULL ) {
+ PR_Free( tsdhdr->ptpdh_dataitems[ i ] );
+ tsdhdr->ptpdh_dataitems[ i ] = NULL;
+ }
+ }
+ PR_Free( tsdhdr->ptpdh_dataitems );
+ tsdhdr->ptpdh_dataitems = NULL;
+ }
+ PR_Free( tsdhdr );
+ }
+}
+#endif
+
+#ifdef _SOLARIS_SDK
+#pragma init(prldap_nspr_init)
+static mutex_t nspr_init_lock = DEFAULTMUTEX;
+static mutex_t nspr_idle_lock = DEFAULTMUTEX;
+static cond_t nspr_idle_cond = DEFAULTCV;
+static int nspr_pr_init_is_done = 0;
+static int nspr_initialized = 0;
+
+void *
+prldap_nspr_idle_primordial_thread(void *arg) {
+ /*
+ * Make sure PR_Init finishes before any other thread can continue
+ */
+ (void) mutex_lock(&nspr_idle_lock);
+ if (PR_Initialized() == PR_FALSE)
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ nspr_pr_init_is_done = 1;
+ (void) cond_signal(&nspr_idle_cond);
+ (void) mutex_unlock(&nspr_idle_lock);
+
+ /* Debug only */
+ syslog(LOG_DEBUG, "NSPR is initialized by the"
+ "idle primordial thread tid %ld created by thread "
+ "tid %ld", thr_self(), (long)arg);
+ pause();
+
+}
+
+/*
+ * Initialize NSPR once
+ *
+ * Ideally this should be done in .init of NSPR.
+ * This is a workaround so only main thread can initialize
+ * NSPR but main() does not need to call PR_Init().
+ * The future direction is NSPR free so we don't want programs
+ * to call PR_Init().
+ *
+ * For most of cases, programs link libldap (-lldap)
+ * and .init is executed before the control is transfered to
+ * main().
+ * But for programs linking libnsl (-lnsl), libldap is loaded
+ * via dlopen("nss_ldap.so.1", RTLD_LAZY) so the thread loads
+ * libldap is not necessary a main or a primordial
+ * thread. In the latter case, an idle primordial thread is created
+ * to initialize NSPR so NSPR won't be initialized by non-primordial
+ * threads.
+ * libldap is built with "-z nodelete" so libldap and libnspr4.so
+ * are persistent in the address space.
+ */
+void
+prldap_nspr_init(void) {
+ struct sigaction action;
+
+ /*
+ * For performance reason, test it here first
+ */
+ if (nspr_initialized != 0)
+ return;
+
+ (void) mutex_lock(&nspr_init_lock);
+ /* Make sure PR_Init() is executed only once */
+ if (nspr_initialized == 0) {
+ /*
+ * PR_Init changes the signal handler of SIGPIPE to SIG_IGN.
+ * Save the original and restore it after PR_Init.
+ */
+ (void) sigaction(SIGPIPE, NULL, &action);
+
+ if (thr_self() == 1) {
+ /* main thread */
+ if (PR_Initialized() == PR_FALSE)
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ nspr_initialized = 1;
+ } else {
+ if (thr_create(NULL, NULL,
+ prldap_nspr_idle_primordial_thread,
+ (void *)thr_self(), THR_DETACHED, NULL) != 0) {
+ syslog(LOG_ERR,
+ "libldap:.init: Can't create thread. "
+ "%s", strerror(errno));
+ } else {
+ /*
+ * Make sure PR_Init finishes before any other thread
+ * can continue.
+ * It's unlikely, but not impossible that this thread
+ * finishes dlopen and starts to call
+ * LDAP API when the idle thread still has not
+ * finished PR_Init() yet.
+ */
+ (void) mutex_lock(&nspr_idle_lock);
+ while (nspr_pr_init_is_done == 0) {
+ (void) cond_wait(&nspr_idle_cond,
+ &nspr_idle_lock);
+
+ }
+ (void) mutex_unlock(&nspr_idle_lock);
+ nspr_initialized = 1;
+ }
+ }
+ /*
+ * Restore signal handling attributes of SIGPIPE
+ */
+ (void) sigaction(SIGPIPE, &action, NULL);
+
+ }
+ (void) mutex_unlock(&nspr_init_lock);
+}
+#endif
diff --git a/usr/src/lib/libldap5/sources/ldap/ssldap/clientinit.c b/usr/src/lib/libldap5/sources/ldap/ssldap/clientinit.c
new file mode 100644
index 0000000000..d3b5aab6d4
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ssldap/clientinit.c
@@ -0,0 +1,880 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * clientinit.c
+ */
+
+#if defined(NET_SSL)
+
+
+#if defined( _WINDOWS )
+#include <windows.h>
+#include "proto-ntutil.h"
+#endif
+
+#include <nspr.h>
+#include <plstr.h>
+#include <synch.h>
+#include <cert.h>
+#include <key.h>
+#include <ssl.h>
+#include <sslproto.h>
+#include <ldap.h>
+#include <ldappr.h>
+#include <solaris-int.h>
+
+
+#include <nss.h>
+
+/* XXX:mhein The following is a workaround for the redefinition of */
+/* const problem on OSF. Fix to be provided by NSS */
+/* This is a pretty benign workaround for us which */
+/* should not cause problems in the future even if */
+/* we forget to take it out :-) */
+
+#ifdef OSF1V4D
+#ifndef __STDC__
+# define __STDC__
+#endif /* __STDC__ */
+#endif /* OSF1V4D */
+
+#ifndef FILE_PATHSEP
+#define FILE_PATHSEP '/'
+#endif
+
+/*
+ * StartTls()
+ */
+
+#define START_TLS_OID "1.3.6.1.4.1.1466.20037"
+
+static PRStatus local_SSLPLCY_Install(void);
+
+/*
+ * This little tricky guy keeps us from initializing twice
+ */
+static int inited = 0;
+#ifdef _SOLARIS_SDK
+mutex_t inited_mutex = DEFAULTMUTEX;
+#else
+static mutex_t inited_mutex = DEFAULTMUTEX;
+#endif /* _SOLARIS_SDK */
+#if 0 /* UNNEEDED BY LIBLDAP */
+static char tokDes[34] = "Internal (Software) Database ";
+static char ptokDes[34] = "Internal (Software) Token ";
+#endif /* UNNEEDED BY LIBLDAP */
+
+
+/* IN: */
+/* string: /u/mhein/.netscape/mykey3.db */
+/* OUT: */
+/* dir: /u/mhein/.netscape/ */
+/* prefix: my */
+/* key: key3.db */
+
+static int
+splitpath(char *string, char *dir, char *prefix, char *key) {
+ char *k;
+ char *s;
+ char *d = string;
+ char *l;
+ int len = 0;
+
+
+ if (string == NULL)
+ return (-1);
+
+ /* goto the end of the string, and walk backwards until */
+ /* you get to the first pathseparator */
+ len = PL_strlen(string);
+ l = string + len - 1;
+ while (l != string && *l != '/' && *l != '\\')
+ l--;
+ /* search for the .db */
+ if ((k = PL_strstr(l, ".db")) != NULL) {
+ /* now we are sitting on . of .db */
+
+ /* move backward to the first 'c' or 'k' */
+ /* indicating cert or key */
+ while (k != l && *k != 'c' && *k != 'k')
+ k--;
+
+ /* move backwards to the first path separator */
+ if (k != d && k > d)
+ s = k - 1;
+ while (s != d && *s != '/' && *s != '\\')
+ s--;
+
+ /* if we are sitting on top of a path */
+ /* separator there is no prefix */
+ if (s + 1 == k) {
+ /* we know there is no prefix */
+ prefix = '\0';
+ PL_strcpy(key, k);
+ *k = '\0';
+ PL_strcpy(dir, d);
+ } else {
+ /* grab the prefix */
+ PL_strcpy(key, k);
+ *k = '\0';
+ PL_strcpy(prefix, ++s);
+ *s = '\0';
+ PL_strcpy(dir, d);
+ }
+ } else {
+ /* neither *key[0-9].db nor *cert[0=9].db found */
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+static PRStatus local_SSLPLCY_Install(void)
+{
+ SECStatus s;
+
+#ifdef NS_DOMESTIC
+ s = NSS_SetDomesticPolicy();
+#elif NS_EXPORT
+ s = NSS_SetExportPolicy();
+#else
+ s = PR_FAILURE;
+#endif
+ return s?PR_FAILURE:PR_SUCCESS;
+}
+
+
+
+static void
+ldapssl_basic_init( void )
+{
+#ifndef _SOLARIS_SDK
+ /*
+ * NSPR is initialized in .init on SOLARIS
+ */
+ /* PR_Init() must to be called before everything else... */
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+#endif
+
+ PR_SetConcurrency( 4 ); /* work around for NSPR 3.x I/O hangs */
+}
+
+
+
+/*
+ * Cover functions for malloc(), calloc(), strdup() and free() that are
+ * compatible with the NSS libraries (they seem to use the C runtime
+ * library malloc/free so these functions are quite simple right now).
+ */
+static void *
+ldapssl_malloc( size_t size )
+{
+ void *p;
+
+ p = malloc( size );
+ return p;
+}
+
+
+static void *
+ldapssl_calloc( int nelem, size_t elsize )
+{
+ void *p;
+
+ p = calloc( nelem, elsize );
+ return p;
+}
+
+
+static char *
+ldapssl_strdup( const char *s )
+{
+ char *scopy;
+
+ if ( NULL == s ) {
+ scopy = NULL;
+ } else {
+ scopy = strdup( s );
+ }
+ return scopy;
+}
+
+
+static void
+ldapssl_free( void **pp )
+{
+ if ( NULL != pp && NULL != *pp ) {
+ free( (void *)*pp );
+ *pp = NULL;
+ }
+}
+
+
+static char *
+buildDBName(const char *basename, const char *dbname)
+{
+ char *result;
+ PRUint32 len, pathlen, addslash;
+
+ if (basename)
+ {
+ if (( len = PL_strlen( basename )) > 3
+ && PL_strcasecmp( ".db", basename + len - 3 ) == 0 ) {
+ return (ldapssl_strdup(basename));
+ }
+
+ pathlen = len;
+ len = pathlen + PL_strlen(dbname) + 1;
+ addslash = ( pathlen > 0 &&
+ (( *(basename + pathlen - 1) != FILE_PATHSEP ) ||
+ ( *(basename + pathlen - 1) != '\\' )));
+
+ if ( addslash ) {
+ ++len;
+ }
+ if (( result = ldapssl_malloc( len )) != NULL ) {
+ PL_strcpy( result, basename );
+ if ( addslash ) {
+ *(result+pathlen) = FILE_PATHSEP; /* replaces '\0' */
+ ++pathlen;
+ }
+ PL_strcpy(result+pathlen, dbname);
+ }
+
+ }
+
+
+ return result;
+}
+
+char *
+GetCertDBName(void *alias, int dbVersion)
+{
+ char *source;
+ char dbname[128];
+
+ source = (char *)alias;
+
+ if (!source)
+ {
+ source = "";
+ }
+
+ sprintf(dbname, "cert%d.db",dbVersion);
+ return(buildDBName(source, dbname));
+
+
+}
+
+/*
+ * return database name by appending "dbname" to "path".
+ * this code doesn't need to be terribly efficient (not called often).
+ */
+/* XXXceb this is the old function. To be removed eventually */
+static char *
+GetDBName(const char *dbname, const char *path)
+{
+ char *result;
+ PRUint32 len, pathlen;
+ int addslash;
+
+ if ( dbname == NULL ) {
+ dbname = "";
+ }
+
+ if ((path == NULL) || (*path == 0)) {
+ result = ldapssl_strdup(dbname);
+ } else {
+ pathlen = PL_strlen(path);
+ len = pathlen + PL_strlen(dbname) + 1;
+ addslash = ( path[pathlen - 1] != '/' );
+ if ( addslash ) {
+ ++len;
+ }
+ if (( result = ldapssl_malloc( len )) != NULL ) {
+ PL_strcpy( result, path );
+ if ( addslash ) {
+ *(result+pathlen) = '/'; /* replaces '\0' */
+ ++pathlen;
+ }
+ PL_strcpy(result+pathlen, dbname);
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Initialize ns/security so it can be used for SSL client authentication.
+ * It is safe to call this more than once.
+ *
+ * If needkeydb == 0, no key database is opened and SSL server authentication
+ * is supported but not client authentication.
+ *
+ * If "certdbpath" is NULL or "", the default cert. db is used (typically
+ * ~/.netscape/cert7.db).
+ *
+ * If "certdbpath" ends with ".db" (case-insensitive compare), then
+ * it is assumed to be a full path to the cert. db file; otherwise,
+ * it is assumed to be a directory that contains a file called
+ * "cert7.db" or "cert.db".
+ *
+ * If certdbhandle is non-NULL, it is assumed to be a pointer to a
+ * SECCertDBHandle structure. It is fine to pass NULL since this
+ * routine will allocate one for you (CERT_GetDefaultDB() can be
+ * used to retrieve the cert db handle).
+ *
+ * If "keydbpath" is NULL or "", the default key db is used (typically
+ * ~/.netscape/key3.db).
+ *
+ * If "keydbpath" ends with ".db" (case-insensitive compare), then
+ * it is assumed to be a full path to the key db file; otherwise,
+ * it is assumed to be a directory that contains a file called
+ * "key3.db"
+ *
+ * If certdbhandle is non-NULL< it is assumed to be a pointed to a
+ * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
+ * routine will allocate one for you (SECKEY_GetDefaultDB() can be
+ * used to retrieve the cert db handle).
+ */
+int
+LDAP_CALL
+ldapssl_clientauth_init( const char *certdbpath, void *certdbhandle,
+ const int needkeydb, const char *keydbpath, void *keydbhandle )
+
+{
+
+ int rc;
+
+ /*
+ * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_clientauth_init\n",0 ,0 ,0);
+ */
+
+ mutex_lock(&inited_mutex);
+ if ( inited ) {
+ mutex_unlock(&inited_mutex);
+ return( 0 );
+ }
+
+ ldapssl_basic_init();
+
+
+ /* Open the certificate database */
+ rc = NSS_Init(certdbpath);
+ if (rc != 0) {
+ if ((rc = PR_GetError()) >= 0)
+ rc = -1;
+ mutex_unlock(&inited_mutex);
+ return (rc);
+ }
+
+ if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
+ || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
+ if (( rc = PR_GetError()) >= 0 ) {
+ rc = -1;
+ }
+ mutex_unlock(&inited_mutex);
+ return( rc );
+ }
+
+
+
+#if defined(NS_DOMESTIC)
+ if (local_SSLPLCY_Install() == PR_FAILURE) {
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+ }
+#elif(NS_EXPORT)
+ if (local_SSLPLCY_Install() == PR_FAILURE) {
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+ }
+#else
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+#endif
+
+ inited = 1;
+ mutex_unlock(&inited_mutex);
+
+ return( 0 );
+
+}
+
+/*
+ * Initialize ns/security so it can be used for SSL client authentication.
+ * It is safe to call this more than once.
+ *
+ * If needkeydb == 0, no key database is opened and SSL server authentication
+ * is supported but not client authentication.
+ *
+ * If "certdbpath" is NULL or "", the default cert. db is used (typically
+ * ~/.netscape/cert7.db).
+ *
+ * If "certdbpath" ends with ".db" (case-insensitive compare), then
+ * it is assumed to be a full path to the cert. db file; otherwise,
+ * it is assumed to be a directory that contains a file called
+ * "cert7.db" or "cert.db".
+ *
+ * If certdbhandle is non-NULL, it is assumed to be a pointer to a
+ * SECCertDBHandle structure. It is fine to pass NULL since this
+ * routine will allocate one for you (CERT_GetDefaultDB() can be
+ * used to retrieve the cert db handle).
+ *
+ * If "keydbpath" is NULL or "", the default key db is used (typically
+ * ~/.netscape/key3.db).
+ *
+ * If "keydbpath" ends with ".db" (case-insensitive compare), then
+ * it is assumed to be a full path to the key db file; otherwise,
+ * it is assumed to be a directory that contains a file called
+ * "key3.db"
+ *
+ * If certdbhandle is non-NULL< it is assumed to be a pointed to a
+ * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
+ * routine will allocate one for you (SECKEY_GetDefaultDB() can be
+ * used to retrieve the cert db handle). */
+int
+LDAP_CALL
+ldapssl_advclientauth_init(
+ const char *certdbpath, void *certdbhandle,
+ const int needkeydb, const char *keydbpath, void *keydbhandle,
+ const int needsecmoddb, const char *secmoddbpath,
+ const int sslstrength )
+{
+ int rc;
+
+ mutex_lock(&inited_mutex);
+ if ( inited ) {
+ mutex_unlock(&inited_mutex);
+ return( 0 );
+ }
+
+ /*
+ * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_advclientauth_init\n",0 ,0 ,0);
+ */
+
+ ldapssl_basic_init();
+
+ rc = NSS_Init(certdbpath);
+ if (rc != 0) {
+ if ((rc = PR_GetError()) >= 0)
+ rc = -1;
+ mutex_unlock(&inited_mutex);
+ return (rc);
+ }
+
+#if defined(NS_DOMESTIC)
+ if (local_SSLPLCY_Install() == PR_FAILURE) {
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+ }
+#elif(NS_EXPORT)
+ if (local_SSLPLCY_Install() == PR_FAILURE) {
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+ }
+#else
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+#endif
+
+ inited = 1;
+ mutex_unlock(&inited_mutex);
+
+ return( ldapssl_set_strength( NULL, sslstrength));
+
+}
+
+
+/*
+ * Initialize ns/security so it can be used for SSL client authentication.
+ * It is safe to call this more than once.
+ */
+
+/*
+ * XXXceb This is a hack until the new IO functions are done.
+ * this function lives in ldapsinit.c
+ */
+void set_using_pkcs_functions( int val );
+
+int
+LDAP_CALL
+ldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns )
+{
+
+ char *certdbName, *s, *keydbpath;
+ char *certdbPrefix, *keydbPrefix;
+ char *confDir, *keydbName;
+ static char *secmodname = "secmod.db";
+ int rc;
+
+ mutex_lock(&inited_mutex);
+ if ( inited ) {
+ mutex_unlock(&inited_mutex);
+ return( 0 );
+ }
+/*
+ * XXXceb This is a hack until the new IO functions are done.
+ * this function MUST be called before ldap_enable_clienauth.
+ *
+ */
+ set_using_pkcs_functions( 1 );
+
+ /*
+ * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_pkcs_init\n",0 ,0 ,0);
+ */
+
+
+ ldapssl_basic_init();
+
+ pfns->pkcs_getcertpath( NULL, &s);
+ confDir = ldapssl_strdup( s );
+ certdbPrefix = ldapssl_strdup( s );
+ certdbName = ldapssl_strdup( s );
+ *certdbPrefix = 0;
+ splitpath(s, confDir, certdbPrefix, certdbName);
+
+ pfns->pkcs_getkeypath( NULL, &s);
+ keydbpath = ldapssl_strdup( s );
+ keydbPrefix = ldapssl_strdup( s );
+ keydbName = ldapssl_strdup( s );
+ *keydbPrefix = 0;
+ splitpath(s, keydbpath, keydbPrefix, keydbName);
+
+
+ /* verify confDir == keydbpath and adjust as necessary */
+ ldapssl_free((void **)&certdbName);
+ ldapssl_free((void **)&keydbName);
+ ldapssl_free((void **)&keydbpath);
+
+ rc = NSS_Initialize(confDir,certdbPrefix,keydbPrefix,secmodname,
+ NSS_INIT_READONLY);
+
+ ldapssl_free((void **)&certdbPrefix);
+ ldapssl_free((void **)&keydbPrefix);
+ ldapssl_free((void **)&confDir);
+
+ if (rc != 0) {
+ if ((rc = PR_GetError()) >= 0)
+ rc = -1;
+ mutex_unlock(&inited_mutex);
+ return (rc);
+ }
+
+
+#if 0 /* UNNEEDED BY LIBLDAP */
+ /* this is odd */
+ PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
+#endif /* UNNEEDED BY LIBLDAP */
+
+ if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
+ || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
+ if (( rc = PR_GetError()) >= 0 ) {
+ rc = -1;
+ }
+
+ mutex_unlock(&inited_mutex);
+ return( rc );
+ }
+
+#if defined(NS_DOMESTIC)
+ if (local_SSLPLCY_Install() == PR_FAILURE) {
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+ }
+#elif(NS_EXPORT)
+ if (local_SSLPLCY_Install() == PR_FAILURE) {
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+ }
+#else
+ mutex_unlock(&inited_mutex);
+ return( -1 );
+#endif
+
+ inited = 1;
+
+ if ( certdbName != NULL ) {
+ ldapssl_free((void **) &certdbName );
+ }
+
+ return( ldapssl_set_strength( NULL, LDAPSSL_AUTH_CNCHECK));
+}
+
+
+/*
+ * ldapssl_client_init() is a server-authentication only version of
+ * ldapssl_clientauth_init().
+ */
+int
+LDAP_CALL
+ldapssl_client_init(const char* certdbpath, void *certdbhandle )
+{
+ return( ldapssl_clientauth_init( certdbpath, certdbhandle,
+ 0, NULL, NULL ));
+}
+/*
+ * ldapssl_serverauth_init() is a server-authentication only version of
+ * ldapssl_clientauth_init(). This function allows the sslstrength
+ * to be passed in. The sslstrength can take one of the following
+ * values:
+ * LDAPSSL_AUTH_WEAK: indicate that you accept the server's
+ * certificate without checking the CA who
+ * issued the certificate
+ * LDAPSSL_AUTH_CERT: indicates that you accept the server's
+ * certificate only if you trust the CA who
+ * issued the certificate
+ * LDAPSSL_AUTH_CNCHECK:
+ indicates that you accept the server's
+ * certificate only if you trust the CA who
+ * issued the certificate and if the value
+ * of the cn attribute in the DNS hostname
+ * of the server
+ */
+int
+LDAP_CALL
+ldapssl_serverauth_init(const char* certdbpath,
+ void *certdbhandle,
+ const int sslstrength )
+{
+ if ( ldapssl_set_strength( NULL, sslstrength ) != 0) {
+ return ( -1 );
+ }
+
+ return( ldapssl_clientauth_init( certdbpath, certdbhandle,
+ 0, NULL, NULL ));
+}
+
+/*
+ * Function that makes an asynchronous Start TLS extended operation request.
+ */
+static int ldapssl_tls_start(LDAP *ld, int *msgidp)
+{
+ int version, rc;
+ BerValue extreq_data;
+
+ /* Start TLS extended operation requires an absent "requestValue" field. */
+
+ extreq_data.bv_val = NULL;
+ extreq_data.bv_len = 0;
+
+ /* Make sure version is set to LDAPv3 for extended operations to be
+ supported. */
+
+ version = LDAP_VERSION3;
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
+
+ /* Send the Start TLS request (OID: 1.3.6.1.4.1.1466.20037) */
+ rc = ldap_extended_operation( ld, START_TLS_OID, &extreq_data,
+ NULL, NULL, msgidp );
+
+ return rc;
+}
+
+
+/*
+ * Function that enables SSL on an already open non-secured LDAP connection.
+ * (i.e. the connection is henceforth secured)
+ */
+static int ldapssl_enableSSL_on_open_connection(LDAP *ld, int defsecure,
+ char *certdbpath, char *keydbpath)
+{
+ PRLDAPSocketInfo soi;
+
+
+ if ( ldapssl_clientauth_init( certdbpath, NULL, 1, keydbpath, NULL ) < 0 ) {
+ goto ssl_setup_failure;
+ }
+
+ /*
+ * Retrieve socket info. so we have the PRFileDesc.
+ */
+ memset( &soi, 0, sizeof(soi));
+ soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
+ if ( prldap_get_default_socket_info( ld, &soi ) < 0 ) {
+ goto ssl_setup_failure;
+ }
+
+ if ( ldapssl_install_routines( ld ) < 0 ) {
+ goto ssl_setup_failure;
+ }
+
+
+ if (soi.soinfo_prfd == NULL) {
+ int sd;
+ ldap_get_option( ld, LDAP_OPT_DESC, &sd );
+ soi.soinfo_prfd = (PRFileDesc *) PR_ImportTCPSocket( sd );
+ }
+ /* set the socket information back into the connection handle,
+ * because ldapssl_install_routines() resets the socket_arg info in the
+ * socket buffer. */
+ if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
+ goto ssl_setup_failure;
+ }
+
+ if ( ldap_set_option( ld, LDAP_OPT_SSL,
+ defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) < 0 ) {
+ goto ssl_setup_failure;
+ }
+
+ if ( ldapssl_import_fd( ld, defsecure ) < 0 ) {
+ goto ssl_setup_failure;
+ }
+
+ return 0;
+
+ssl_setup_failure:
+ ldapssl_reset_to_nonsecure( ld );
+
+ /* we should here warn the server that we switch back to a non-secure
+ connection */
+
+ return( -1 );
+}
+
+
+/*
+ * ldapssl_tls_start_s() performs a synchronous Start TLS extended operation
+ * request.
+ *
+ * The function returns the result code of the extended operation response
+ * sent by the server.
+ *
+ * In case of a successfull response (LDAP_SUCCESS returned), by the time
+ * this function returns the LDAP session designed by ld will have been
+ * secured, i.e. the connection will have been imported into SSL.
+ *
+ * Should the Start TLS request be rejected by the server, the result code
+ * returned will be one of the following:
+ * LDAP_OPERATIONS_ERROR,
+ * LDAP_PROTOCOL_ERROR,
+ * LDAP_REFERRAL,
+ * LDAP_UNAVAILABLE.
+ *
+ * Any other error code returned will be due to a failure in the course
+ * of operations done on the client side.
+ *
+ * "certdbpath" and "keydbpath" should contain the path to the client's
+ * certificate and key databases respectively. Either the path to the
+ * directory containing "default name" databases (i.e. cert7.db and key3.db)
+ * can be specified or the actual filenames can be included.
+ * If any of these parameters is NULL, the function will assume the database
+ * is the same used by Netscape Communicator, which is usually under
+ * ~/.netsca /)
+ *
+ * "referralsp" is a pointer to a list of referrals the server might
+ * eventually send back with an LDAP_REFERRAL result code.
+ *
+ */
+
+int
+LDAP_CALL
+ldapssl_tls_start_s(LDAP *ld,int defsecure, char *certdbpath, char *keydbpath,
+ char ***referralsp)
+{
+ int rc, resultCode, msgid;
+ char *extresp_oid;
+ BerValue *extresp_data;
+ LDAPMessage *res;
+
+ rc = ldapssl_tls_start( ld, &msgid );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ rc = ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res );
+ if ( rc != LDAP_RES_EXTENDED ) {
+
+ /* the first response received must be an extended response to an
+ Start TLS request */
+
+ ldap_msgfree( res );
+ return( -1 );
+
+ }
+
+ rc = ldap_parse_extended_result( ld, res, &extresp_oid, &extresp_data, 0 );
+
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_msgfree( res );
+ return rc;
+ }
+
+ if ( strcasecmp( extresp_oid, START_TLS_OID ) != 0 ) {
+
+ /* the extended response received doesn't correspond to the
+ Start TLS request */
+
+ ldap_msgfree( res );
+ return -1;
+ }
+
+ resultCode = ldap_get_lderrno( ld, NULL, NULL );
+
+ /* Analyze the server's response */
+ switch (resultCode) {
+ case LDAP_REFERRAL:
+ {
+ rc = ldap_parse_result( ld, res, NULL, NULL, NULL, referralsp, NULL, 0 );
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_msgfree( res );
+ return rc;
+ }
+ }
+ case LDAP_OPERATIONS_ERROR:
+
+ case LDAP_PROTOCOL_ERROR:
+
+ case LDAP_UNAVAILABLE:
+ goto free_msg_and_return;
+ case LDAP_SUCCESS:
+ {
+ /*
+ * If extended response successfull, get connection ready for
+ * communicating with the server over SSL/TLS.
+ */
+
+ if ( ldapssl_enableSSL_on_open_connection( ld, defsecure,
+ certdbpath, keydbpath ) < 0 ) {
+ resultCode = -1;
+ }
+
+ } /* case LDAP_SUCCESS */
+ default:
+ goto free_msg_and_return;
+ } /* switch */
+
+free_msg_and_return:
+ ldap_msgfree( res );
+ return resultCode;
+}
+
+#endif /* NET_SSL */
diff --git a/usr/src/lib/libldap5/sources/ldap/ssldap/errormap.c b/usr/src/lib/libldap5/sources/ldap/ssldap/errormap.c
new file mode 100644
index 0000000000..b3c276f446
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ssldap/errormap.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * errormap.c - map NSPR and OS errors to strings
+ *
+ * CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF NETSCAPE COMMUNICATIONS
+ * CORPORATION
+ *
+ * Copyright (C) 1998-9 Netscape Communications Corporation. All Rights Reserved.
+ *
+ * Use of this Source Code is subject to the terms of the applicable license
+ * agreement from Netscape Communications Corporation.
+ *
+ * The copyright notice(s) in this Source Code does not indicate actual or
+ * intended publication of this Source Code.
+ */
+
+/* XXX ceb
+ * This code was stolen from Directory server.
+ * ns/netsite/ldap/servers/slapd/errormap.c
+ * OS errors are not handled, so the os error has been removed.
+ */
+
+
+#if defined( _WINDOWS )
+#include <windows.h>
+#include "proto-ntutil.h"
+#endif
+
+#include <nspr.h>
+#include <ssl.h>
+
+#include <ldap.h>
+
+#ifdef _SOLARIS_SDK
+#include <synch.h>
+#include <libintl.h>
+#endif /* _SOLARIS_SDK */
+
+
+/*
+ * function protoypes
+ */
+static const char *SECU_Strerror(PRErrorCode errNum);
+
+
+
+/*
+ * return the string equivalent of an NSPR error
+ */
+
+const char *
+LDAP_CALL
+ldapssl_err2string( const int prerrno )
+{
+ const char *s;
+
+ if (( s = SECU_Strerror( (PRErrorCode)prerrno )) == NULL ) {
+ s = dgettext(TEXT_DOMAIN, "unknown");
+ }
+
+ return( s );
+}
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/secerror.c on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ * Last updated from there: 14-July-1999 by chuck boatwright <cboatwri>
+ *
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DIRECTORY.
+ ****************************************************************************
+ */
+#include "nspr.h"
+
+/*
+ * XXXceb as a hack, we will locally define NS_DIRECTORY
+ */
+#define NS_DIRECTORY 1
+
+struct tuple_str {
+ PRErrorCode errNum;
+ const char * errString;
+};
+
+typedef struct tuple_str tuple_str;
+
+#ifndef _SOLARIS_SDK
+#define ER2(a,b) {a, b},
+#define ER3(a,b,c) {a, c},
+#else
+#define ER2(a,b) {a, NULL},
+#define ER3(a,b,c) {a, NULL},
+#endif
+
+#include "secerr.h"
+#include "sslerr.h"
+
+#ifndef _SOLARIS_SDK
+const tuple_str errStrings[] = {
+#else
+tuple_str errStrings[] = {
+#endif
+
+/* keep this list in asceding order of error numbers */
+#ifdef NS_DIRECTORY
+#include "sslerrstrs.h"
+#include "secerrstrs.h"
+#include "prerrstrs.h"
+/*
+ * XXXceb -- LDAPSDK won't care about disconnect
+#include "disconnect_error_strings.h"
+ */
+
+#else /* NS_DIRECTORY */
+#include "SSLerrs.h"
+#include "SECerrs.h"
+#include "NSPRerrs.h"
+#endif /* NS_DIRECTORY */
+
+};
+
+const PRInt32 numStrings = sizeof(errStrings) / sizeof(tuple_str);
+
+/* Returns a UTF-8 encoded constant error string for "errNum".
+ * Returns NULL of errNum is unknown.
+ */
+#ifndef _SOLARIS_SDK
+#ifdef NS_DIRECTORY
+static
+#endif /* NS_DIRECTORY */
+const char *
+SECU_Strerror(PRErrorCode errNum) {
+ PRInt32 low = 0;
+ PRInt32 high = numStrings - 1;
+ PRInt32 i;
+ PRErrorCode num;
+ static int initDone;
+
+ /* make sure table is in ascending order.
+ * binary search depends on it.
+ */
+ if (!initDone) {
+ PRErrorCode lastNum = 0x80000000;
+ for (i = low; i <= high; ++i) {
+ num = errStrings[i].errNum;
+ if (num <= lastNum) {
+
+/*
+ * XXXceb
+ * We aren't handling out of sequence errors.
+ */
+
+
+#if 0
+#ifdef NS_DIRECTORY
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "sequence error in error strings at item %d\n"
+ "error %d (%s)\n",
+ i, lastNum, errStrings[i-1].errString );
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "should come after \n"
+ "error %d (%s)\n",
+ num, errStrings[i].errString, 0 );
+#else /* NS_DIRECTORY */
+ fprintf(stderr,
+"sequence error in error strings at item %d\n"
+"error %d (%s)\n"
+"should come after \n"
+"error %d (%s)\n",
+ i, lastNum, errStrings[i-1].errString,
+ num, errStrings[i].errString);
+#endif /* NS_DIRECTORY */
+#endif /* 0 */
+ }
+ lastNum = num;
+ }
+ initDone = 1;
+ }
+
+ /* Do binary search of table. */
+ while (low + 1 < high) {
+ i = (low + high) / 2;
+ num = errStrings[i].errNum;
+ if (errNum == num)
+ return errStrings[i].errString;
+ if (errNum < num)
+ high = i;
+ else
+ low = i;
+ }
+ if (errNum == errStrings[low].errNum)
+ return errStrings[low].errString;
+ if (errNum == errStrings[high].errNum)
+ return errStrings[high].errString;
+ return NULL;
+}
+#else /* _SOLARIS_SDK */
+#undef ER3
+#define ER3(x, y, z) case (x): \
+ s = (z); \
+ break;
+#undef ER2
+#define ER2(x, y) case (x): \
+ s = (y); \
+ break;
+
+static mutex_t err_mutex = DEFAULTMUTEX;
+
+static const char *
+getErrString(PRInt32 i, PRErrorCode errNum)
+{
+ char *s;
+
+ mutex_lock(&err_mutex);
+
+ if (errStrings[i].errString != NULL) {
+ mutex_unlock(&err_mutex);
+ return (errStrings[i].errString);
+ }
+
+ switch (errNum) {
+#include "sslerrstrs.h"
+#include "secerrstrs.h"
+#include "prerrstrs.h"
+ default:
+ s = NULL;
+ break;
+ }
+ errStrings[i].errString = s;
+ mutex_unlock(&err_mutex);
+ return (s);
+}
+
+static
+const char *
+SECU_Strerror(PRErrorCode errNum) {
+ PRInt32 low = 0;
+ PRInt32 high = numStrings - 1;
+ PRInt32 i;
+ PRErrorCode num;
+
+ /* ASSUME table is in ascending order.
+ * binary search depends on it.
+ */
+
+ /* Do binary search of table. */
+ while (low + 1 < high) {
+ i = (low + high) / 2;
+ num = errStrings[i].errNum;
+ if (errNum == num)
+ return getErrString(i, errNum);
+ if (errNum < num)
+ high = i;
+ else
+ low = i;
+ }
+ if (errNum == errStrings[low].errNum)
+ return getErrString(low, errNum);
+ if (errNum == errStrings[high].errNum)
+ return getErrString(high, errNum);
+ return NULL;
+}
+#endif
diff --git a/usr/src/lib/libldap5/sources/ldap/ssldap/ldapsinit.c b/usr/src/lib/libldap5/sources/ldap/ssldap/ldapsinit.c
new file mode 100644
index 0000000000..795b727ff2
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ssldap/ldapsinit.c
@@ -0,0 +1,1317 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ldapsinit.c
+ */
+
+#if defined(NET_SSL)
+
+#if defined( _WINDOWS )
+#include <windows.h>
+#endif
+
+/* XXX:mhein The following is a workaround for the redefinition of */
+/* const problem on OSF. Fix to be provided by NSS */
+/* This is a pretty benign workaround for us which */
+/* should not cause problems in the future even if */
+/* we forget to take it out :-) */
+
+#ifdef OSF1V4D
+#ifndef __STDC__
+# define __STDC__
+#endif /* __STDC__ */
+#endif /* OSF1V4D */
+
+#include <errno.h>
+#include <nspr.h>
+#include <cert.h>
+#include <key.h>
+#include <ssl.h>
+#include <sslproto.h>
+#include <sslerr.h>
+#include <prnetdb.h>
+
+#include <ldap.h>
+
+#include <ldappr.h>
+#include <pk11func.h>
+
+#ifdef _SOLARIS_SDK
+#include "solaris-int.h"
+#include <libintl.h>
+#include <syslog.h>
+#include <nsswitch.h>
+#include <synch.h>
+#include <nss_dbdefs.h>
+#include <netinet/in.h>
+
+#define HOST_BUF_SIZE 2048
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1)
+#endif
+
+extern int
+str2hostent(const char *instr, int lenstr, void *ent, char *buffer,
+ int buflen);
+
+extern int
+str2hostent6(const char *instr, int lenstr, void *ent, char *buffer,
+ int buflen);
+
+extern LDAPHostEnt *
+_ns_gethostbyaddr(LDAP *ld, const char *addr, int length, int type,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata);
+
+static char *host_service = NULL;
+
+static DEFINE_NSS_DB_ROOT(db_root_hosts);
+static DEFINE_NSS_DB_ROOT(db_root_ipnodes);
+#endif
+
+/*
+ * Data structure to hold the standard NSPR I/O function pointers set by
+ * libprldap. We save them in our session data structure so we can call
+ * them from our own I/O functions (we add functionality to support SSL
+ * while using libprldap's functions as much as possible).
+ */
+typedef struct ldapssl_std_functions {
+ LDAP_X_EXTIOF_CLOSE_CALLBACK *lssf_close_fn;
+ LDAP_X_EXTIOF_CONNECT_CALLBACK *lssf_connect_fn;
+ LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *lssf_disposehdl_fn;
+} LDAPSSLStdFunctions;
+
+
+
+/*
+ * LDAP session data structure.
+ */
+typedef struct ldapssl_session_info {
+ int lssei_using_pcks_fns;
+ int lssei_ssl_strength;
+ char *lssei_certnickname;
+ char *lssei_keypasswd;
+ LDAPSSLStdFunctions lssei_std_functions;
+ CERTCertDBHandle *lssei_certdbh;
+#ifdef _SOLARIS_SDK
+ /*
+ * This is a hack.
+ * ld is used so that we can use libldap's gethostbyaddr
+ * resolver. This is needed to prevent recursion with libsldap.
+ */
+ LDAP *ld;
+#endif /* _SOLARIS_SDK */
+} LDAPSSLSessionInfo;
+
+
+/*
+ * LDAP socket data structure.
+ */
+typedef struct ldapssl_socket_info {
+ LDAPSSLSessionInfo *soi_sessioninfo; /* session info */
+} LDAPSSLSocketInfo;
+
+
+/*
+ * XXXceb This is a hack until the new IO functions are done.
+ * this function MUST be called before ldap_enable_clienauth.
+ * right now, this function is called in ldapssl_pkcs_init();
+ */
+
+static int using_pkcs_functions = 0;
+
+void set_using_pkcs_functions( int val )
+{
+ using_pkcs_functions = val;
+}
+
+
+/*
+ * Utility functions:
+ */
+static void ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp );
+static void ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp );
+
+
+/*
+ * SSL Stuff
+ */
+
+static int ldapssl_AuthCertificate(void *sessionarg, PRFileDesc *fd,
+ PRBool checkSig, PRBool isServer);
+
+/*
+ * client auth stuff
+ */
+static int get_clientauth_data( void *sessionarg, PRFileDesc *prfd,
+ CERTDistNames *caNames, CERTCertificate **pRetCert,
+ SECKEYPrivateKey **pRetKey );
+static int get_keyandcert( LDAPSSLSessionInfo *ssip,
+ CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey,
+ char **errmsgp );
+static int check_clientauth_nicknames_and_passwd( LDAP *ld,
+ LDAPSSLSessionInfo *ssip );
+static char *get_keypassword( PK11SlotInfo *slot, PRBool retry,
+ void *sessionarg );
+
+/*
+ * Static variables.
+ */
+#ifdef _SOLARIS_SDK
+static int default_ssl_strength = LDAPSSL_AUTH_CNCHECK;
+#else
+static int default_ssl_strength = LDAPSSL_AUTH_CERT;
+#endif
+
+/*
+ * Like ldap_init(), except also install I/O routines from libsec so we
+ * can support SSL. If defsecure is non-zero, SSL is enabled for the
+ * default connection as well.
+ */
+LDAP *
+LDAP_CALL
+ldapssl_init( const char *defhost, int defport, int defsecure )
+{
+ LDAP *ld;
+
+
+#ifndef LDAP_SSLIO_HOOKS
+ return( NULL );
+#else
+ if (0 ==defport)
+ defport = LDAPS_PORT;
+
+ if (( ld = ldap_init( defhost, defport )) == NULL ) {
+ return( NULL );
+ }
+
+ if ( ldapssl_install_routines( ld ) < 0 || ldap_set_option( ld,
+ LDAP_OPT_SSL, defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) != 0 ) {
+ PR_SetError( PR_UNKNOWN_ERROR, EINVAL ); /* XXXmcs: just a guess! */
+ ldap_unbind( ld );
+ return( NULL );
+ }
+
+ return( ld );
+#endif
+}
+
+
+static int
+ldapssl_close(int s, struct lextiof_socket_private *socketarg)
+{
+ PRLDAPSocketInfo soi;
+ LDAPSSLSocketInfo *ssoip;
+ LDAPSSLSessionInfo *sseip;
+
+ memset( &soi, 0, sizeof(soi));
+ soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
+ if ( prldap_get_socket_info( s, socketarg, &soi ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+
+ ssoip = (LDAPSSLSocketInfo *)soi.soinfo_appdata;
+ sseip = ssoip->soi_sessioninfo;
+
+ ldapssl_free_socket_info( (LDAPSSLSocketInfo **)&soi.soinfo_appdata );
+
+ return( (*(sseip->lssei_std_functions.lssf_close_fn))( s, socketarg ));
+}
+
+static int
+do_ldapssl_connect(const char *hostlist, int defport, int timeout,
+ unsigned long options, struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp, int clientauth )
+{
+ int intfd = -1;
+ PRBool secure;
+ PRLDAPSessionInfo sei;
+ PRLDAPSocketInfo soi;
+ LDAPSSLSocketInfo *ssoip = NULL;
+ LDAPSSLSessionInfo *sseip;
+ PRFileDesc *sslfd = NULL;
+#ifdef _SOLARIS_SDK
+ int port;
+ int parse_err;
+ char *host = NULL;
+ char *name;
+ struct ldap_x_hostlist_status
+ *status = NULL;
+ in_addr_t addr_ipv4;
+ in6_addr_t addr_ipv6;
+ char *host_buf;
+ LDAPHostEnt *hent;
+ LDAPHostEnt host_ent;
+ int stat;
+ int type;
+#endif /* _SOLARIS_SDK */
+
+ /*
+ * Determine if secure option is set. Also, clear secure bit in options
+ * the we pass to the standard connect() function (since it doesn't know
+ * how to handle the secure option).
+ */
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
+ secure = PR_TRUE;
+ options &= ~LDAP_X_EXTIOF_OPT_SECURE;
+ } else {
+ secure = PR_FALSE;
+ }
+
+ /*
+ * Retrieve session info. so we can store a pointer to our session info.
+ * in our socket info. later.
+ */
+ memset( &sei, 0, sizeof(sei));
+ sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
+ if ( prldap_get_session_info( NULL, sessionarg, &sei ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+ sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
+
+ /*
+ * Call the standard connect() callback to make the TCP connection.
+ * If it succeeds, *socketargp is set.
+ */
+
+ intfd = (*(sseip->lssei_std_functions.lssf_connect_fn))( hostlist, defport,
+ timeout, options, sessionarg, socketargp
+#ifdef _SOLARIS_SDK
+ , &host );
+#else
+ );
+#endif /* _SOLARIS_SDK */
+
+ if ( intfd < 0 ) {
+ return( intfd );
+ }
+
+#ifdef _SOLARIS_SDK
+ /*
+ * Determine if the "host name" is an ip address. If so,
+ * we must look up the actual host name corresponding to
+ * it.
+ */
+ if ( NULL == host ) {
+ goto close_socket_and_exit_with_error;
+ }
+ type = AF_UNSPEC;
+ if (strlen(host) < INET6_ADDRSTRLEN &&
+ inet_pton(AF_INET6, host, &addr_ipv6) == 1) {
+ type = AF_INET6;
+ } else if (strlen(host) < INET_ADDRSTRLEN &&
+ inet_pton(AF_INET, host, &addr_ipv4) == 1) {
+ type = AF_INET;
+ }
+ if (type == AF_INET || type == AF_INET6) {
+ host_buf = malloc(HOST_BUF_SIZE);
+ if (host_buf == NULL) {
+ /* will free host in close_socket_and_exit_with_error */
+ goto close_socket_and_exit_with_error;
+ }
+
+ /* Call ldap layer's gethostbyaddr resolver */
+ hent = _ns_gethostbyaddr(sseip->ld, host, strlen(host), type,
+ &host_ent, host_buf, HOST_BUF_SIZE, &stat, NULL);
+
+ /* If we are unable to lookup the host addr, we fail! */
+ if (hent == NULL) {
+ syslog(LOG_WARNING,
+ "libldap: do_ldapssl_connect: "
+ "Unable to resolve '%s'", host);
+ free(host_buf);
+ /* will free host in close_socket_and_exit_with_error */
+ goto close_socket_and_exit_with_error;
+ }
+ /* We support only the primary host name */
+ else {
+ if (hent->ldaphe_name != NULL)
+ name = strdup(hent->ldaphe_name);
+ free(host_buf);
+ if (name == NULL)
+ goto close_socket_and_exit_with_error;
+ else
+ ldap_memfree(host); host = NULL;
+ host = name;
+ }
+ }
+#endif /* _SOLARIS_SDK */
+
+ /*
+ * Retrieve socket info. so we have the PRFileDesc.
+ */
+ memset( &soi, 0, sizeof(soi));
+ soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
+ if ( prldap_get_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) {
+ goto close_socket_and_exit_with_error;
+ }
+
+ /*
+ * Allocate a structure to hold our socket-specific data.
+ */
+ if ( NULL == ( ssoip = PR_Calloc( 1, sizeof( LDAPSSLSocketInfo )))) {
+ goto close_socket_and_exit_with_error;
+ }
+ ssoip->soi_sessioninfo = sseip;
+
+ /*
+ * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
+ */
+ if (( sslfd = SSL_ImportFD( NULL, soi.soinfo_prfd )) == NULL ) {
+ goto close_socket_and_exit_with_error;
+ }
+
+ if ( SSL_OptionSet( sslfd, SSL_SECURITY, secure ) != SECSuccess ||
+ SSL_OptionSet( sslfd, SSL_HANDSHAKE_AS_CLIENT, secure )
+ != SECSuccess || ( secure && SSL_ResetHandshake( sslfd,
+ PR_FALSE ) != SECSuccess )) {
+ goto close_socket_and_exit_with_error;
+ }
+
+ /*
+ * Let the standard NSPR to LDAP layer know about the new socket and
+ * our own socket-specific data.
+ */
+ soi.soinfo_prfd = sslfd;
+ soi.soinfo_appdata = (void *)ssoip;
+ if ( prldap_set_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) {
+ goto close_socket_and_exit_with_error;
+ }
+
+#ifdef _SOLARIS_SDK
+ /*
+ * Set hostname which will be retrieved (depending on ssl strength) when
+ * using client or server auth.
+ */
+ if (SSL_SetURL(sslfd, host) != SECSuccess)
+ goto close_socket_and_exit_with_error;
+ ldap_memfree(host);
+ host = NULL;
+#endif /* _SOLARIS_SDK */
+
+ sslfd = NULL; /* so we don't close the socket twice upon error */
+
+ /*
+ * Install certificate hook function.
+ */
+ SSL_AuthCertificateHook( soi.soinfo_prfd,
+ (SSLAuthCertificate)ldapssl_AuthCertificate,
+ (void *)sseip);
+
+ if ( SSL_GetClientAuthDataHook( soi.soinfo_prfd,
+ get_clientauth_data, clientauth ? sseip : NULL ) != 0 ) {
+ goto close_socket_and_exit_with_error;
+ }
+
+ return( intfd ); /* success */
+
+close_socket_and_exit_with_error:
+#ifdef _SOLARIS_SDK
+ if ( NULL != host ) ldap_memfree(host);
+#endif /* _SOLARIS_SDK */
+ if ( NULL != sslfd ) {
+ PR_Close( sslfd );
+ }
+ if ( NULL != ssoip ) {
+ ldapssl_free_socket_info( &ssoip );
+ }
+ if ( intfd >= 0 && NULL != *socketargp ) {
+ (*(sseip->lssei_std_functions.lssf_close_fn))( intfd, *socketargp );
+ }
+ return( -1 );
+}
+
+
+static int
+ldapssl_connect(const char *hostlist, int defport, int timeout,
+ unsigned long options, struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp )
+{
+ return( do_ldapssl_connect( hostlist, defport, timeout, options,
+ sessionarg, socketargp, 0 ));
+}
+
+
+static int
+ldapssl_clientauth_connect(const char *hostlist, int defport, int timeout,
+ unsigned long options, struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp )
+{
+ return( do_ldapssl_connect( hostlist, defport, timeout, options,
+ sessionarg, socketargp, 1 ));
+}
+
+
+static void
+ldapssl_disposehandle(LDAP *ld, struct lextiof_session_private *sessionarg)
+{
+ PRLDAPSessionInfo sei;
+ LDAPSSLSessionInfo *sseip;
+ LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *disposehdl_fn;
+
+ memset( &sei, 0, sizeof( sei ));
+ sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
+ if ( prldap_get_session_info( ld, NULL, &sei ) == LDAP_SUCCESS ) {
+ sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
+ disposehdl_fn = sseip->lssei_std_functions.lssf_disposehdl_fn;
+ ldapssl_free_session_info( &sseip );
+ (*disposehdl_fn)( ld, sessionarg );
+ }
+}
+
+
+/*
+ * Install I/O routines from libsec and NSPR into libldap to allow libldap
+ * to do SSL.
+ *
+ * We rely on libprldap to provide most of the functions, and then we override
+ * a few of them to support SSL.
+ */
+int
+LDAP_CALL
+ldapssl_install_routines( LDAP *ld )
+{
+#ifndef LDAP_SSLIO_HOOKS
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( -1 );
+#else
+ struct ldap_x_ext_io_fns iofns;
+ LDAPSSLSessionInfo *ssip;
+ PRLDAPSessionInfo sei;
+
+/*
+ * This is done within ldap_init() and
+ * ldap_init() is called from ldapssl_init()
+ */
+#ifndef _SOLARIS_SDK
+ if ( prldap_install_routines(
+ ld,
+ 1 /* shared -- we have to assume it is */ )
+ != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+#endif /*_SOLARIS_SDK*/
+
+ /*
+ * Allocate our own session information.
+ */
+ if ( NULL == ( ssip = (LDAPSSLSessionInfo *)PR_Calloc( 1,
+ sizeof( LDAPSSLSessionInfo )))) {
+ ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ /*
+ * Initialize session info.
+ * XXX: it would be nice to be able to set these on a per-session basis:
+ * lssei_using_pcks_fns
+ * lssei_certdbh
+ */
+ ssip->lssei_ssl_strength = default_ssl_strength;
+ ssip->lssei_using_pcks_fns = using_pkcs_functions;
+ ssip->lssei_certdbh = CERT_GetDefaultCertDB();
+#ifdef _SOLARIS_SDK
+ /*
+ * This is part of a hack to allow the ssl portion of the
+ * library to call the ldap library gethostbyaddr resolver.
+ */
+ ssip->ld = ld;
+#endif /* _SOLARIS_SDK */
+
+ /*
+ * override a few functions, saving a pointer to the standard function
+ * in each case so we can call it from our SSL savvy functions.
+ */
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
+ ldapssl_free_session_info( &ssip );
+ return( -1 );
+ }
+
+ /* override socket, connect, and ioctl */
+ ssip->lssei_std_functions.lssf_connect_fn = iofns.lextiof_connect;
+ iofns.lextiof_connect = ldapssl_connect;
+ ssip->lssei_std_functions.lssf_close_fn = iofns.lextiof_close;
+ iofns.lextiof_close = ldapssl_close;
+ ssip->lssei_std_functions.lssf_disposehdl_fn = iofns.lextiof_disposehandle;
+ iofns.lextiof_disposehandle = ldapssl_disposehandle;
+
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
+ ldapssl_free_session_info( &ssip );
+ return( -1 );
+ }
+
+ /*
+ * Store session info. for later retrieval.
+ */
+ sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
+ sei.seinfo_appdata = (void *)ssip;
+ if ( prldap_set_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+
+ return( 0 );
+#endif
+}
+
+
+/*
+ * Set the SSL strength for an existing SSL-enabled LDAP session handle.
+ *
+ * See the description of ldapssl_serverauth_init() above for valid
+ * sslstrength values. If ld is NULL, the default for new LDAP session
+ * handles is set.
+ *
+ * Returns 0 if all goes well and -1 if an error occurs.
+ */
+int
+LDAP_CALL
+ldapssl_set_strength( LDAP *ld, int sslstrength )
+{
+ int rc = 0; /* assume success */
+
+ if ( sslstrength != LDAPSSL_AUTH_WEAK &&
+ sslstrength != LDAPSSL_AUTH_CERT &&
+ sslstrength != LDAPSSL_AUTH_CNCHECK ) {
+ rc = -1;
+ } else {
+ if ( NULL == ld ) { /* set default strength */
+ default_ssl_strength = sslstrength;
+ } else { /* set session-specific strength */
+ PRLDAPSessionInfo sei;
+ LDAPSSLSessionInfo *sseip;
+
+ memset( &sei, 0, sizeof( sei ));
+ sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
+ if ( prldap_get_session_info( ld, NULL, &sei ) == LDAP_SUCCESS )
+{
+ sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
+ sseip->lssei_ssl_strength = sslstrength;
+ } else {
+ rc = -1;
+ }
+ }
+ }
+
+ return( rc );
+}
+
+int
+LDAP_CALL
+ldapssl_enable_clientauth( LDAP *ld, char *keynickname,
+ char *keypasswd, char *certnickname )
+{
+#ifndef LDAP_SSLIO_HOOKS
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( -1 );
+#else
+ struct ldap_x_ext_io_fns iofns;
+ LDAPSSLSessionInfo *ssip;
+ PRLDAPSessionInfo sei;
+
+ /*
+ * Check parameters
+ */
+ if ( certnickname == NULL || keypasswd == NULL ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( -1 );
+ }
+
+ /*
+ * Update session info. data structure.
+ */
+ sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
+ if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+ ssip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
+ if ( NULL == ssip ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( -1 );
+ }
+ ssip->lssei_certnickname = PL_strdup( certnickname );
+ ssip->lssei_keypasswd = PL_strdup( keypasswd );
+
+ if ( NULL == ssip->lssei_certnickname || NULL == ssip->lssei_keypasswd ) {
+ ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+
+ if ( check_clientauth_nicknames_and_passwd( ld, ssip ) != 0 ) {
+ return( -1 );
+ }
+
+ /*
+ * replace standard SSL CONNECT function with client auth aware one
+ */
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
+ != 0 ) {
+ return( -1 );
+ }
+
+ if ( iofns.lextiof_connect != ldapssl_connect ) {
+ /* standard SSL setup has not done */
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( -1 );
+ }
+
+ iofns.lextiof_connect = ldapssl_clientauth_connect;
+
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
+ != 0 ) {
+ return( -1 );
+ }
+
+ return( 0 );
+#endif
+}
+
+
+static void
+ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp )
+{
+ if ( NULL != ssipp && NULL != *ssipp ) {
+ if ( NULL != (*ssipp)->lssei_certnickname ) {
+ PL_strfree( (*ssipp)->lssei_certnickname );
+ (*ssipp)->lssei_certnickname = NULL;
+ }
+ if ( NULL != (*ssipp)->lssei_keypasswd ) {
+ PL_strfree( (*ssipp)->lssei_keypasswd );
+ (*ssipp)->lssei_keypasswd = NULL;
+ }
+ PR_Free( *ssipp );
+ *ssipp = NULL;
+ }
+}
+
+
+static void
+ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp )
+{
+ if ( NULL != soipp && NULL != *soipp ) {
+ PR_Free( *soipp );
+ *soipp = NULL;
+ }
+}
+
+
+/* this function provides cert authentication. This is called during
+ * the SSL_Handshake process. Once the cert has been retrieved from
+ * the server, the it is checked, using VerifyCertNow(), then
+ * the cn is checked against the host name, set with SSL_SetURL()
+ */
+
+static int
+ldapssl_AuthCertificate(void *sessionarg, PRFileDesc *fd, PRBool checkSig,
+ PRBool isServer)
+{
+ SECStatus rv = SECFailure;
+ LDAPSSLSessionInfo *sseip;
+ CERTCertificate *cert;
+ SECCertUsage certUsage;
+ char *hostname = (char *)0;
+
+ if (!sessionarg || !socket)
+ return rv;
+
+ sseip = (LDAPSSLSessionInfo *)sessionarg;
+
+ if (LDAPSSL_AUTH_WEAK == sseip->lssei_ssl_strength ) { /* no check */
+ return SECSuccess;
+ }
+
+ if ( isServer ) {
+ certUsage = certUsageSSLClient;
+ } else {
+ certUsage = certUsageSSLServer;
+ }
+ cert = SSL_PeerCertificate( fd );
+
+ rv = CERT_VerifyCertNow(sseip->lssei_certdbh, cert, checkSig,
+ certUsage, NULL);
+
+ if ( rv != SECSuccess || isServer )
+ return rv;
+
+ if ( LDAPSSL_AUTH_CNCHECK == sseip->lssei_ssl_strength )
+ {
+ /* cert is OK. This is the client side of an SSL connection.
+ * Now check the name field in the cert against the desired hostname.
+ * NB: This is our only defense against Man-In-The-Middle (MITM)
+ * attacks!
+ */
+
+ hostname = SSL_RevealURL( fd );
+
+ if (hostname && hostname[0]) {
+ rv = CERT_VerifyCertName(cert, hostname);
+ } else {
+ rv = SECFailure;
+ }
+ if (hostname)
+ PORT_Free(hostname);
+ if (rv != SECSuccess)
+ PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
+ }
+
+ return((int)rv);
+}
+
+
+/*
+ * called during SSL client auth. when server wants our cert and key.
+ * return 0 if we succeeded and set *pRetCert and *pRetKey, -1 otherwise.
+ * if -1 is returned SSL will proceed without sending a cert.
+ */
+
+static int
+get_clientauth_data( void *sessionarg, PRFileDesc *prfd,
+ CERTDistNames *caNames, CERTCertificate **pRetCert,
+ SECKEYPrivateKey **pRetKey )
+
+{
+ LDAPSSLSessionInfo *ssip;
+
+ if (( ssip = (LDAPSSLSessionInfo *)sessionarg ) == NULL ) {
+ return( -1 ); /* client auth. not enabled */
+ }
+
+ return( get_keyandcert( ssip, pRetCert, pRetKey, NULL ));
+}
+
+static int
+get_keyandcert( LDAPSSLSessionInfo *ssip,
+ CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey,
+ char **errmsgp )
+{
+ CERTCertificate *cert;
+ SECKEYPrivateKey *key;
+
+ if (( cert = PK11_FindCertFromNickname( ssip->lssei_certnickname, NULL ))
+ == NULL ) {
+ if ( errmsgp != NULL ) {
+ *errmsgp = dgettext(TEXT_DOMAIN, "unable to find certificate");
+ }
+ return( -1 );
+ }
+
+ {
+ PK11_SetPasswordFunc( get_keypassword );
+ }
+
+
+
+ if (( key = PK11_FindKeyByAnyCert( cert, (void *)ssip )) == NULL ) {
+ CERT_DestroyCertificate( cert );
+ if ( errmsgp != NULL ) {
+ *errmsgp = dgettext(TEXT_DOMAIN, "bad key or key password");
+ }
+ return( -1 );
+ }
+
+ *pRetCert = cert;
+ *pRetKey = key;
+ return( 0 );
+}
+
+
+/*
+ * This function returns the password to NSS.
+ * This function is enable through PK11_SetPasswordFunc
+ * only if pkcs functions are not being used.
+ */
+
+static char *
+get_keypassword( PK11SlotInfo *slot, PRBool retry, void *sessionarg )
+{
+ LDAPSSLSessionInfo *ssip;
+
+ if ( retry)
+ return (NULL);
+
+ ssip = (LDAPSSLSessionInfo *)sessionarg;
+ if ( NULL == ssip ) {
+ return( NULL );
+ }
+
+ return( ssip->lssei_keypasswd );
+}
+
+
+/*
+ * performs some basic checks on clientauth cert and key/password
+ *
+ * XXXmcs: could perform additional checks... see servers/slapd/ssl.c
+ * 1) check expiration
+ * 2) check that public key in cert matches private key
+ * see ns/netsite/ldap/servers/slapd/ssl.c:slapd_ssl_init() for example code.
+ */
+static int
+check_clientauth_nicknames_and_passwd( LDAP *ld, LDAPSSLSessionInfo *ssip )
+{
+ char *errmsg = NULL;
+ CERTCertificate *cert = NULL;
+ SECKEYPrivateKey *key = NULL;
+ int rv;
+
+ rv = get_keyandcert( ssip, &cert, &key, &errmsg );
+
+ if ( rv != 0 ) {
+ if ( errmsg != NULL ) {
+ errmsg = strdup( errmsg );
+ }
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, errmsg );
+ return( -1 );
+ }
+
+ if ( cert != NULL ) {
+ CERT_DestroyCertificate( cert );
+ }
+ if ( key != NULL ) {
+ SECKEY_DestroyPrivateKey( key );
+ }
+ return( 0 );
+}
+
+
+#if 0 /* NOT_NEEDED_IN_LIBLDAP */
+/* there are patches and kludges. this is both. force some linkers to
+ * link this stuff in
+ */
+int stubs_o_stuff( void )
+{
+ PRExplodedTime exploded;
+ PLArenaPool pool;
+
+ const char *name ="t";
+ PRUint32 size = 0, align = 0;
+
+ PR_ImplodeTime( &exploded );
+ PL_InitArenaPool( &pool, name, size, align);
+ PR_Cleanup();
+ PR_fprintf((PRFileDesc*)stderr, "Bad IDEA!!");
+
+ return 0;
+
+}
+#endif /* NOT_NEEDED_IN_LIBLDAP */
+
+
+/*
+ * Import the file descriptor corresponding to the socket of an already
+ * open LDAP connection into SSL, and update the socket and session
+ * information accordingly.
+ */
+int ldapssl_import_fd ( LDAP *ld, int secure )
+{
+ PRLDAPSessionInfo sei;
+ PRLDAPSocketInfo soi;
+ LDAPSSLSocketInfo *ssoip = NULL;
+ LDAPSSLSessionInfo *sseip;
+ PRFileDesc *sslfd = NULL;
+
+
+ /*
+ * Retrieve session info. so we can store a pointer to our session info.
+ * in our socket info. later.
+ */
+ memset( &sei, 0, sizeof(sei));
+ sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
+ if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+ sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
+
+
+ /*
+ * Retrieve socket info. so we have the PRFileDesc.
+ */
+ memset( &soi, 0, sizeof(soi));
+ soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
+ if ( prldap_get_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+
+ /*
+ * Allocate a structure to hold our socket-specific data.
+ */
+ if ( NULL == ( ssoip = PR_Calloc( 1, sizeof( LDAPSSLSocketInfo )))) {
+ goto reset_socket_and_exit_with_error;
+ }
+ ssoip->soi_sessioninfo = sseip;
+
+ /*
+ * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
+ */
+ if (( sslfd = SSL_ImportFD( NULL, soi.soinfo_prfd )) == NULL ) {
+ goto reset_socket_and_exit_with_error;
+ }
+
+ if ( SSL_OptionSet( sslfd, SSL_SECURITY, secure ) != SECSuccess ||
+ SSL_OptionSet( sslfd, SSL_HANDSHAKE_AS_CLIENT, secure )
+ != SECSuccess || ( secure && SSL_ResetHandshake( sslfd,
+ PR_FALSE ) != SECSuccess )) {
+ goto reset_socket_and_exit_with_error;
+ }
+
+ /*
+ * Let the standard NSPR to LDAP layer know about the new socket and
+ * our own socket-specific data.
+ */
+ soi.soinfo_prfd = sslfd;
+ soi.soinfo_appdata = (void *)ssoip;
+ if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
+ goto reset_socket_and_exit_with_error;
+ }
+
+ /*
+ * Install certificate hook function.
+ */
+ if ( SSL_AuthCertificateHook( soi.soinfo_prfd,
+ (SSLAuthCertificate)ldapssl_AuthCertificate,
+ (void *)CERT_GetDefaultCertDB()) != 0 ) {
+ goto reset_socket_and_exit_with_error;
+ }
+
+ if ( SSL_GetClientAuthDataHook( soi.soinfo_prfd,
+ get_clientauth_data, sseip->lssei_certnickname ? sseip : NULL )
+ != 0 ) {
+ goto reset_socket_and_exit_with_error;
+ }
+
+ return 0;
+
+ reset_socket_and_exit_with_error:
+ if ( NULL != sslfd ) {
+ /*
+ * "Unimport" the socket from SSL, i.e. get rid of the upper layer of
+ * the file descriptor stack, which represents SSL.
+ */
+ soi.soinfo_prfd = sslfd;
+ sslfd = PR_PopIOLayer( soi.soinfo_prfd, PR_TOP_IO_LAYER );
+ sslfd->dtor( sslfd );
+ }
+ if ( NULL != ssoip ) {
+ ldapssl_free_socket_info( &ssoip );
+ soi.soinfo_appdata = NULL;
+ }
+ prldap_set_default_socket_info( ld, &soi );
+
+ return( -1 );
+}
+
+
+/*
+ * Reset an LDAP session from SSL to a non-secure status.
+ * Basically, this function undoes the work done by ldapssl_install_routines.
+ */
+int ldapssl_reset_to_nonsecure ( LDAP *ld )
+{
+ PRLDAPSessionInfo sei;
+ LDAPSSLSessionInfo *sseip;
+
+ struct ldap_x_ext_io_fns iofns;
+ int rc = 0;
+
+ /*
+ * Retrieve session info.
+ */
+ memset( &sei, 0, sizeof(sei));
+ sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
+ if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
+ return( -1 );
+ }
+ sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
+
+ if ( sseip != NULL ) {
+ /*
+ * Reset the standard extended io functions.
+ */
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
+ < 0) {
+ rc = -1;
+ goto free_session_info;
+ }
+
+ /* reset socket, connect, and ioctl */
+ iofns.lextiof_connect = sseip->lssei_std_functions.lssf_connect_fn;
+ iofns.lextiof_close = sseip->lssei_std_functions.lssf_close_fn;
+ iofns.lextiof_disposehandle =
+ sseip->lssei_std_functions.lssf_disposehdl_fn;
+
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
+ < 0) {
+ rc = -1;
+ goto free_session_info;
+ }
+
+free_session_info:
+ ldapssl_free_session_info( &sseip );
+ sei.seinfo_appdata = NULL;
+ if ( prldap_set_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
+ rc = -1;
+ }
+ } /* if ( sseip && *sseip ) */
+
+ if ( ldap_set_option( ld, LDAP_OPT_SSL, LDAP_OPT_OFF ) < 0 ) {
+ return (-1);
+ }
+
+ return rc;
+}
+
+
+#ifdef _SOLARIS_SDK
+static void
+_nss_initf_ipnodes(nss_db_params_t *p)
+{
+ static char *no_service = "";
+
+ p->name = NSS_DBNAM_IPNODES;
+ p->flags |= NSS_USE_DEFAULT_CONFIG;
+ p->default_config = host_service == NULL ? no_service : host_service;
+}
+
+static void
+_nss_initf_hosts(nss_db_params_t *p)
+{
+ static char *no_service = "";
+
+ p->name = NSS_DBNAM_HOSTS;
+ p->flags |= NSS_USE_DEFAULT_CONFIG;
+ p->default_config = host_service == NULL ? no_service : host_service;
+}
+
+static struct hostent *
+_switch_gethostbyaddr_r(const char *addr, int len, int type,
+ struct hostent *result, char *buffer, int buflen,
+ int *h_errnop)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+ int (*str2ent)();
+ void (*nss_initf)();
+ nss_db_root_t *nss_db_root;
+
+ if (AF_INET == type) {
+ str2ent = str2hostent;
+ nss_initf = _nss_initf_hosts;
+ nss_db_root = &db_root_hosts;
+ } else if (AF_INET6 == type) {
+ str2ent = str2hostent6;
+ nss_initf = _nss_initf_ipnodes;
+ nss_db_root = &db_root_ipnodes;
+ } else {
+ return NULL;
+ }
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent);
+
+ arg.key.hostaddr.addr = addr;
+ arg.key.hostaddr.len = len;
+ arg.key.hostaddr.type = type;
+ arg.stayopen = 0;
+
+ res = nss_search(nss_db_root, nss_initf,
+ NSS_DBOP_HOSTS_BYADDR, &arg);
+ arg.status = res;
+ *h_errnop = arg.h_errno;
+ return (struct hostent *)NSS_XbyY_FINI(&arg);
+}
+
+/*
+ * ns_gethostbyaddr is used to be a substitute gethostbyaddr for
+ * libldap when ssl will need to determine the fully qualified
+ * host name from an address when it is unsafe to use the normal
+ * nameservice functions.
+ *
+ * Note that the ldap name service resolver calls this with the address as
+ * a character string - which we must convert into address form.
+ */
+
+/*ARGSUSED*/
+static LDAPHostEnt *
+ns_gethostbyaddr(const char *addr, int len, int type,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata)
+{
+ LDAPHostEnt *ldap_hent;
+ int h_errno;
+ struct hostent h_ent;
+ struct hostent *h_e = NULL;
+ struct in_addr a;
+ struct in6_addr a6;
+ int inet_error; /* error returned by inet_pton */
+
+
+ if (addr == NULL || result == NULL || buffer == NULL ||
+ (type != AF_INET && type != AF_INET6))
+ return (NULL);
+
+
+ (void) memset(&h_ent, 0, sizeof (h_ent));
+
+ if (AF_INET == type) {
+ if (inet_pton(type, addr, &a.s_addr) == 1) {
+ h_e = _switch_gethostbyaddr_r((char *)&a,
+ sizeof (a.s_addr), type, &h_ent,
+ buffer, buflen, &h_errno);
+ }
+ } else if (AF_INET6 == type) {
+ if (inet_pton(type, addr, &a6.s6_addr) == 1) {
+ h_e = _switch_gethostbyaddr_r((char *)&a6,
+ sizeof (a6.s6_addr), type, &h_ent,
+ buffer, buflen, &h_errno);
+ }
+ }
+
+ if (h_e == NULL) {
+ ldap_hent = NULL;
+ } else {
+ (void) memset(result, 0, sizeof (LDAPHostEnt));
+ ldap_hent = result;
+ result->ldaphe_name = h_e->h_name;
+ result->ldaphe_aliases = h_e->h_aliases;
+ result->ldaphe_addrtype = h_e->h_addrtype;
+ result->ldaphe_length = h_e->h_length;
+ result->ldaphe_addr_list = h_e->h_addr_list;
+ }
+ return (ldap_hent);
+}
+
+/*
+ * ldapssl_install_gethostbyaddr attempts to prevent recursion in
+ * gethostbyaddr calls when an ip address is given to ssl. This ip address
+ * must be resolved to a host name.
+ *
+ * For example, libsldap cannot use LDAP to resolve this address to a
+ * name because of recursion. The caller is instructing libldap to skip
+ * the specified name service when resolving addresses for the specified
+ * ldap connection.
+ *
+ * Currently only ldap and dns name services always return fully qualified
+ * names. The other name services (files, nis, and nisplus) will returned
+ * fully qualified names if the host names are stored as fully qualified names
+ * in these name services.
+ *
+ * Note:
+ *
+ * Since host_service applies to all connections, calling
+ * ldapssl_install_gethostbyaddr with different name services to
+ * skip will lead to unpredictable results.
+ *
+ * Returns:
+ * 0 if success
+ * -1 if failure
+ */
+
+int
+ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip)
+{
+ enum __nsw_parse_err pserr;
+ struct __nsw_switchconfig *conf;
+ struct __nsw_lookup *lkp;
+ struct ldap_dns_fns dns_fns;
+ char *name_list = NULL;
+ char *tmp;
+ const char *name;
+ int len;
+ boolean_t got_skip = B_FALSE;
+
+ /*
+ * db_root_hosts.lock mutex is used to ensure that the name list
+ * is not in use by the name service switch while we are updating
+ * the host_service
+ */
+
+ (void) mutex_lock(&db_root_hosts.lock);
+ conf = __nsw_getconfig("hosts", &pserr);
+ if (conf == NULL) {
+ (void) mutex_unlock(&db_root_hosts.lock);
+ return (0);
+ }
+
+ /* check for ldap and count other backends */
+ for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
+ name = lkp->service_name;
+ if (strcmp(name, skip) == 0) {
+ got_skip = B_TRUE;
+ continue;
+ }
+ if (name_list == NULL)
+ name_list = strdup(name);
+ else {
+ len = strlen(name_list);
+ tmp = realloc(name_list, len + strlen(name) + 2);
+ if (tmp == NULL) {
+ free(name_list);
+ name_list = NULL;
+ } else {
+ name_list = tmp;
+ name_list[len++] = ' ';
+ (void) strcpy(name_list+len, name);
+ }
+ }
+ if (name_list == NULL) { /* alloc error */
+ (void) mutex_unlock(&db_root_hosts.lock);
+ __nsw_freeconfig(conf);
+ return (-1);
+ }
+ }
+ __nsw_freeconfig(conf);
+ if (!got_skip) {
+ /*
+ * Since skip name service not used for hosts, we do not need
+ * to install our private address resolution function
+ */
+ (void) mutex_unlock(&db_root_hosts.lock);
+ if (name_list != NULL)
+ free(name_list);
+ return (0);
+ }
+ if (host_service != NULL)
+ free(host_service);
+ host_service = name_list;
+ (void) mutex_unlock(&db_root_hosts.lock);
+
+ if (ldap_get_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
+ return (-1);
+ dns_fns.lddnsfn_gethostbyaddr = ns_gethostbyaddr;
+ if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
+ return (-1);
+ return (0);
+}
+#endif /* _SOLARIS_SDK */
+#endif /* NET_SSL */
diff --git a/usr/src/lib/libldap5/sources/ldap/ssldap/prerrstrs.h b/usr/src/lib/libldap5/sources/ldap/ssldap/prerrstrs.h
new file mode 100644
index 0000000000..73be5267d6
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ssldap/prerrstrs.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * pserrstrs.h - map NSPR errors to strings (used by errormap.c)
+ *
+ */
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/NSPRerrs.h on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DIRECTORY.
+ ****************************************************************************
+ */
+/* General NSPR 2.0 errors */
+/* Caller must #include "prerror.h" */
+
+ER2( PR_OUT_OF_MEMORY_ERROR, dgettext(TEXT_DOMAIN,
+ "Memory allocation attempt failed.") )
+ER2( PR_BAD_DESCRIPTOR_ERROR, dgettext(TEXT_DOMAIN,
+ "Invalid file descriptor.") )
+ER2( PR_WOULD_BLOCK_ERROR, dgettext(TEXT_DOMAIN,
+ "The operation would have blocked.") )
+ER2( PR_ACCESS_FAULT_ERROR, dgettext(TEXT_DOMAIN,
+ "Invalid memory address argument.") )
+ER2( PR_INVALID_METHOD_ERROR, dgettext(TEXT_DOMAIN,
+ "Invalid function for file type.") )
+ER2( PR_ILLEGAL_ACCESS_ERROR, dgettext(TEXT_DOMAIN,
+ "Invalid memory address argument.") )
+ER2( PR_UNKNOWN_ERROR, dgettext(TEXT_DOMAIN,
+ "Some unknown error has occurred.") )
+ER2( PR_PENDING_INTERRUPT_ERROR,dgettext(TEXT_DOMAIN,
+ "Operation interrupted by another thread.") )
+ER2( PR_NOT_IMPLEMENTED_ERROR, dgettext(TEXT_DOMAIN,
+ "function not implemented.") )
+ER2( PR_IO_ERROR, dgettext(TEXT_DOMAIN,
+ "I/O function error.") )
+ER2( PR_IO_TIMEOUT_ERROR, dgettext(TEXT_DOMAIN,
+ "I/O operation timed out.") )
+ER2( PR_IO_PENDING_ERROR, dgettext(TEXT_DOMAIN,
+ "I/O operation on busy file descriptor.") )
+ER2( PR_DIRECTORY_OPEN_ERROR, dgettext(TEXT_DOMAIN,
+ "The directory could not be opened.") )
+ER2( PR_INVALID_ARGUMENT_ERROR, dgettext(TEXT_DOMAIN,
+ "Invalid function argument.") )
+ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, dgettext(TEXT_DOMAIN,
+ "Network address not available (in use?).") )
+ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, dgettext(TEXT_DOMAIN,
+ "Network address type not supported.") )
+ER2( PR_IS_CONNECTED_ERROR, dgettext(TEXT_DOMAIN,
+ "Already connected.") )
+ER2( PR_BAD_ADDRESS_ERROR, dgettext(TEXT_DOMAIN,
+ "Network address is invalid.") )
+ER2( PR_ADDRESS_IN_USE_ERROR, dgettext(TEXT_DOMAIN,
+ "Local Network address is in use.") )
+ER2( PR_CONNECT_REFUSED_ERROR, dgettext(TEXT_DOMAIN,
+ "Connection refused by peer.") )
+ER2( PR_NETWORK_UNREACHABLE_ERROR, dgettext(TEXT_DOMAIN,
+ "Network address is presently unreachable.") )
+ER2( PR_CONNECT_TIMEOUT_ERROR, dgettext(TEXT_DOMAIN,
+ "Connection attempt timed out.") )
+ER2( PR_NOT_CONNECTED_ERROR, dgettext(TEXT_DOMAIN,
+ "Network file descriptor is not connected.") )
+ER2( PR_LOAD_LIBRARY_ERROR, dgettext(TEXT_DOMAIN,
+ "Failure to load dynamic library.") )
+ER2( PR_UNLOAD_LIBRARY_ERROR, dgettext(TEXT_DOMAIN,
+ "Failure to unload dynamic library.") )
+ER2( PR_FIND_SYMBOL_ERROR, dgettext(TEXT_DOMAIN,
+ "Symbol not found in any of the loaded dynamic libraries.") )
+ER2( PR_INSUFFICIENT_RESOURCES_ERROR, dgettext(TEXT_DOMAIN,
+ "Insufficient system resources.") )
+ER2( PR_DIRECTORY_LOOKUP_ERROR, dgettext(TEXT_DOMAIN,
+ "A directory lookup on a network address has failed.") )
+ER2( PR_TPD_RANGE_ERROR, dgettext(TEXT_DOMAIN,
+ "Attempt to access a TPD key that is out of range.") )
+ER2( PR_PROC_DESC_TABLE_FULL_ERROR, dgettext(TEXT_DOMAIN,
+ "Process open FD table is full.") )
+ER2( PR_SYS_DESC_TABLE_FULL_ERROR, dgettext(TEXT_DOMAIN,
+ "System open FD table is full.") )
+ER2( PR_NOT_SOCKET_ERROR, dgettext(TEXT_DOMAIN,
+ "Network operation attempted on non-network file descriptor.") )
+ER2( PR_NOT_TCP_SOCKET_ERROR, dgettext(TEXT_DOMAIN,
+ "TCP-specific function attempted on a non-TCP file descriptor.") )
+ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, dgettext(TEXT_DOMAIN,
+ "TCP file descriptor is already bound.") )
+ER2( PR_NO_ACCESS_RIGHTS_ERROR, dgettext(TEXT_DOMAIN,
+ "Access Denied.") )
+ER2( PR_OPERATION_NOT_SUPPORTED_ERROR, dgettext(TEXT_DOMAIN,
+ "The requested operation is not supported by the platform.") )
+ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR, dgettext(TEXT_DOMAIN,
+ "The host operating system does not support the protocol requested.") )
+ER2( PR_REMOTE_FILE_ERROR, dgettext(TEXT_DOMAIN,
+ "Access to the remote file has been severed.") )
+ER2( PR_BUFFER_OVERFLOW_ERROR, dgettext(TEXT_DOMAIN,
+ "The value requested is too large to be stored in the data buffer provided.") )
+ER2( PR_CONNECT_RESET_ERROR, dgettext(TEXT_DOMAIN,
+ "TCP connection reset by peer.") )
+ER2( PR_RANGE_ERROR, dgettext(TEXT_DOMAIN,
+ "Unused.") )
+ER2( PR_DEADLOCK_ERROR, dgettext(TEXT_DOMAIN,
+ "The operation would have deadlocked.") )
+ER2( PR_FILE_IS_LOCKED_ERROR, dgettext(TEXT_DOMAIN,
+ "The file is already locked.") )
+ER2( PR_FILE_TOO_BIG_ERROR, dgettext(TEXT_DOMAIN,
+ "Write would result in file larger than the system allows.") )
+ER2( PR_NO_DEVICE_SPACE_ERROR, dgettext(TEXT_DOMAIN,
+ "The device for storing the file is full.") )
+ER2( PR_PIPE_ERROR, dgettext(TEXT_DOMAIN,
+ "Unused.") )
+ER2( PR_NO_SEEK_DEVICE_ERROR, dgettext(TEXT_DOMAIN,
+ "Unused.") )
+ER2( PR_IS_DIRECTORY_ERROR, dgettext(TEXT_DOMAIN,
+ "Cannot perform a normal file operation on a directory.") )
+ER2( PR_LOOP_ERROR, dgettext(TEXT_DOMAIN,
+ "Symbolic link loop.") )
+ER2( PR_NAME_TOO_LONG_ERROR, dgettext(TEXT_DOMAIN,
+ "File name is too long.") )
+ER2( PR_FILE_NOT_FOUND_ERROR, dgettext(TEXT_DOMAIN,
+ "File not found.") )
+ER2( PR_NOT_DIRECTORY_ERROR, dgettext(TEXT_DOMAIN,
+ "Cannot perform directory operation on a normal file.") )
+ER2( PR_READ_ONLY_FILESYSTEM_ERROR, dgettext(TEXT_DOMAIN,
+ "Cannot write to a read-only file system.") )
+ER2( PR_DIRECTORY_NOT_EMPTY_ERROR, dgettext(TEXT_DOMAIN,
+ "Cannot delete a directory that is not empty.") )
+ER2( PR_FILESYSTEM_MOUNTED_ERROR, dgettext(TEXT_DOMAIN,
+ "Cannot delete or rename a file object while the file system is busy.") )
+ER2( PR_NOT_SAME_DEVICE_ERROR, dgettext(TEXT_DOMAIN,
+ "Cannot rename a file to a file system on another device.") )
+ER2( PR_DIRECTORY_CORRUPTED_ERROR, dgettext(TEXT_DOMAIN,
+ "The directory object in the file system is corrupted.") )
+ER2( PR_FILE_EXISTS_ERROR, dgettext(TEXT_DOMAIN,
+ "Cannot create or rename a filename that already exists.") )
+ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR, dgettext(TEXT_DOMAIN,
+ "Directory is full. No additional filenames may be added.") )
+ER2( PR_INVALID_DEVICE_STATE_ERROR, dgettext(TEXT_DOMAIN,
+ "The required device was in an invalid state.") )
+ER2( PR_DEVICE_IS_LOCKED_ERROR, dgettext(TEXT_DOMAIN,
+ "The device is locked.") )
+ER2( PR_NO_MORE_FILES_ERROR, dgettext(TEXT_DOMAIN,
+ "No more entries in the directory.") )
+ER2( PR_END_OF_FILE_ERROR, dgettext(TEXT_DOMAIN,
+ "Encountered end of file.") )
+ER2( PR_FILE_SEEK_ERROR, dgettext(TEXT_DOMAIN,
+ "Seek error.") )
+ER2( PR_FILE_IS_BUSY_ERROR, dgettext(TEXT_DOMAIN,
+ "The file is busy.") )
+ER2( PR_IN_PROGRESS_ERROR, dgettext(TEXT_DOMAIN,
+ "Operation is still in progress (probably a non-blocking connect).") )
+ER2( PR_ALREADY_INITIATED_ERROR, dgettext(TEXT_DOMAIN,
+ "Operation has already been initiated (probably a non-blocking connect).") )
+
+#ifdef PR_GROUP_EMPTY_ERROR
+ER2( PR_GROUP_EMPTY_ERROR, dgettext(TEXT_DOMAIN,
+ "The wait group is empty.") )
+#endif
+
+#ifdef PR_INVALID_STATE_ERROR
+ER2( PR_INVALID_STATE_ERROR, dgettext(TEXT_DOMAIN,
+ "Object state improper for request.") )
+#endif
+
+ER2( PR_MAX_ERROR, "Placeholder for the end of the list" )
diff --git a/usr/src/lib/libldap5/sources/ldap/ssldap/secerrstrs.h b/usr/src/lib/libldap5/sources/ldap/ssldap/secerrstrs.h
new file mode 100644
index 0000000000..229fb529d0
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ssldap/secerrstrs.h
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * secerrstrs.h - map security errors to strings (used by errormap.c)
+ *
+ */
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/SECerrs.h on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DIRECTORY.
+ ****************************************************************************
+ */
+
+/* General security error codes */
+/* Caller must #include "secerr.h" */
+
+
+ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0,
+dgettext(TEXT_DOMAIN,
+"An I/O error occurred during security authorization."))
+
+ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1,
+dgettext(TEXT_DOMAIN,
+"security library failure."))
+
+ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2,
+dgettext(TEXT_DOMAIN,
+"security library: received bad data."))
+
+ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3,
+dgettext(TEXT_DOMAIN,
+"security library: output length error."))
+
+ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4,
+dgettext(TEXT_DOMAIN,
+"security library has experienced an input length error."))
+
+ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5,
+dgettext(TEXT_DOMAIN,
+"security library: invalid arguments."))
+
+ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6,
+dgettext(TEXT_DOMAIN,
+"security library: invalid algorithm."))
+
+ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7,
+dgettext(TEXT_DOMAIN,
+"security library: invalid AVA."))
+
+ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8,
+dgettext(TEXT_DOMAIN,
+"security library: invalid time."))
+
+ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9,
+dgettext(TEXT_DOMAIN,
+"security library: improperly formatted DER-encoded message."))
+
+ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10,
+dgettext(TEXT_DOMAIN,
+"Peer's certificate has an invalid signature."))
+
+ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11,
+dgettext(TEXT_DOMAIN,
+"Peer's Certificate has expired."))
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12,
+dgettext(TEXT_DOMAIN,
+"Peer's Certificate has been revoked."))
+
+ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13,
+dgettext(TEXT_DOMAIN,
+"Peer's Certificate issuer is not recognized."))
+
+ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14,
+dgettext(TEXT_DOMAIN,
+"Peer's public key is invalid."))
+
+ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15,
+dgettext(TEXT_DOMAIN,
+"The security password entered is incorrect."))
+
+ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16,
+dgettext(TEXT_DOMAIN,
+"New password entered incorrectly. Please try again."))
+
+ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17,
+dgettext(TEXT_DOMAIN,
+"security library: no nodelock."))
+
+ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18,
+dgettext(TEXT_DOMAIN,
+"security library: bad database."))
+
+ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19,
+dgettext(TEXT_DOMAIN,
+"security library: memory allocation failure."))
+
+ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20,
+dgettext(TEXT_DOMAIN,
+"Peer's certificate issuer has been marked as not trusted by the user."))
+
+ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21,
+dgettext(TEXT_DOMAIN,
+"Peer's certificate has been marked as not trusted by the user."))
+
+ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22),
+dgettext(TEXT_DOMAIN,
+"Certificate already exists in your database."))
+
+ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23),
+dgettext(TEXT_DOMAIN,
+"Downloaded certificate's name duplicates one already in your database."))
+
+ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24),
+dgettext(TEXT_DOMAIN,
+"Error adding certificate to database."))
+
+ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25),
+dgettext(TEXT_DOMAIN,
+"Error refiling the key for this certificate."))
+
+ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26),
+dgettext(TEXT_DOMAIN,
+"The private key for this certificate cannot be found in key database"))
+
+ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27),
+dgettext(TEXT_DOMAIN,
+"This certificate is valid."))
+
+ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28),
+dgettext(TEXT_DOMAIN,
+"This certificate is not valid."))
+
+ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29),
+dgettext(TEXT_DOMAIN,
+"Cert Library: No Response"))
+
+ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30),
+dgettext(TEXT_DOMAIN,
+"The certificate issuer's certificate has expired. Check your system date and time."))
+
+ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31),
+dgettext(TEXT_DOMAIN,
+"The CRL for the certificate's issuer has expired. Update it or check your system data and time."))
+
+ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32),
+dgettext(TEXT_DOMAIN,
+"The CRL for the certificate's issuer has an invalid signature."))
+
+ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33),
+dgettext(TEXT_DOMAIN,
+"New CRL has an invalid format."))
+
+ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34),
+dgettext(TEXT_DOMAIN,
+"Certificate extension value is invalid."))
+
+ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35),
+dgettext(TEXT_DOMAIN,
+"Certificate extension not found."))
+
+ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36),
+dgettext(TEXT_DOMAIN,
+"Issuer certificate is invalid."))
+
+ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37),
+dgettext(TEXT_DOMAIN,
+"Certificate path length constraint is invalid."))
+
+ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38),
+dgettext(TEXT_DOMAIN,
+"Certificate usages field is invalid."))
+
+ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39),
+dgettext(TEXT_DOMAIN,
+"**Internal ONLY module**"))
+
+ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40),
+dgettext(TEXT_DOMAIN,
+"The key does not support the requested operation."))
+
+ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41),
+dgettext(TEXT_DOMAIN,
+"Certificate contains unknown critical extension."))
+
+ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42),
+dgettext(TEXT_DOMAIN,
+"New CRL is not later than the current one."))
+
+ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43),
+dgettext(TEXT_DOMAIN,
+"Not encrypted or signed: you do not yet have an email certificate."))
+
+ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44),
+dgettext(TEXT_DOMAIN,
+"Not encrypted: you do not have certificates for each of the recipients."))
+
+ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45),
+dgettext(TEXT_DOMAIN,
+"Cannot decrypt: you are not a recipient, or matching certificate and \
+private key not found."))
+
+ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46),
+dgettext(TEXT_DOMAIN,
+"Cannot decrypt: key encryption algorithm does not match your certificate."))
+
+ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47),
+dgettext(TEXT_DOMAIN,
+"Signature verification failed: no signer found, too many signers found, \
+or improper or corrupted data."))
+
+ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48),
+dgettext(TEXT_DOMAIN,
+"Unsupported or unknown key algorithm."))
+
+ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49),
+dgettext(TEXT_DOMAIN,
+"Cannot decrypt: encrypted using a disallowed algorithm or key size."))
+
+
+/* Fortezza Alerts */
+ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50),
+dgettext(TEXT_DOMAIN,
+"Fortezza card has not been properly initialized. \
+Please remove it and return it to your issuer."))
+
+ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51),
+dgettext(TEXT_DOMAIN,
+"No Fortezza cards Found"))
+
+ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52),
+dgettext(TEXT_DOMAIN,
+"No Fortezza card selected"))
+
+ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53),
+dgettext(TEXT_DOMAIN,
+"Please select a personality to get more info on"))
+
+ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54),
+dgettext(TEXT_DOMAIN,
+"Personality not found"))
+
+ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55),
+dgettext(TEXT_DOMAIN,
+"No more information on that Personality"))
+
+ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56),
+dgettext(TEXT_DOMAIN,
+"Invalid Pin"))
+
+ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57),
+dgettext(TEXT_DOMAIN,
+"Couldn't initialize Fortezza personalities."))
+/* end fortezza alerts. */
+
+ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58),
+dgettext(TEXT_DOMAIN,
+"No KRL for this site's certificate has been found."))
+
+ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59),
+dgettext(TEXT_DOMAIN,
+"The KRL for this site's certificate has expired."))
+
+ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60),
+dgettext(TEXT_DOMAIN,
+"The KRL for this site's certificate has an invalid signature."))
+
+ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61),
+dgettext(TEXT_DOMAIN,
+"The key for this site's certificate has been revoked."))
+
+ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62),
+dgettext(TEXT_DOMAIN,
+"New KRL has an invalid format."))
+
+ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63),
+dgettext(TEXT_DOMAIN,
+"security library: need random data."))
+
+ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64),
+dgettext(TEXT_DOMAIN,
+"security library: no security module can perform the requested operation."))
+
+ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65),
+dgettext(TEXT_DOMAIN,
+"The security card or token does not exist, needs to be initialized, or has been removed."))
+
+ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66),
+dgettext(TEXT_DOMAIN,
+"security library: read-only database."))
+
+ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67),
+dgettext(TEXT_DOMAIN,
+"No slot or token was selected."))
+
+ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68),
+dgettext(TEXT_DOMAIN,
+"A certificate with the same nickname already exists."))
+
+ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69),
+dgettext(TEXT_DOMAIN,
+"A key with the same nickname already exists."))
+
+ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70),
+dgettext(TEXT_DOMAIN,
+"error while creating safe object"))
+
+ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71),
+dgettext(TEXT_DOMAIN,
+"error while creating baggage object"))
+
+ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72),
+dgettext(TEXT_DOMAIN,
+"Couldn't remove the principal"))
+
+ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73),
+dgettext(TEXT_DOMAIN,
+"Couldn't delete the privilege"))
+
+ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74),
+dgettext(TEXT_DOMAIN,
+"This principal doesn't have a certificate"))
+
+ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75),
+dgettext(TEXT_DOMAIN,
+"Required algorithm is not allowed."))
+
+ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76),
+dgettext(TEXT_DOMAIN,
+"Error attempting to export certificates."))
+
+ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77),
+dgettext(TEXT_DOMAIN,
+"Error attempting to import certificates."))
+
+ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Decoding error. File not valid."))
+
+ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Invalid MAC. Incorrect password or corrupt file."))
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80),
+dgettext(TEXT_DOMAIN,
+"Unable to import. MAC algorithm not supported."))
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Only password integrity and privacy modes supported."))
+
+ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82),
+dgettext(TEXT_DOMAIN,
+"Unable to import. File structure is corrupt."))
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Encryption algorithm not supported."))
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84),
+dgettext(TEXT_DOMAIN,
+"Unable to import. File version not supported."))
+
+ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Incorrect privacy password."))
+
+ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Same nickname already exists in database."))
+
+ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87),
+dgettext(TEXT_DOMAIN,
+"The user pressed cancel."))
+
+ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88),
+dgettext(TEXT_DOMAIN,
+"Not imported, already in database."))
+
+ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89),
+dgettext(TEXT_DOMAIN,
+"Message not sent."))
+
+ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90),
+dgettext(TEXT_DOMAIN,
+"Certificate key usage inadequate for attempted operation."))
+
+ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91),
+dgettext(TEXT_DOMAIN,
+"Certificate type not approved for application."))
+
+ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92),
+dgettext(TEXT_DOMAIN,
+"Address in signing certificate does not match address in message headers."))
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Error attempting to import private key."))
+
+ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Error attempting to import certificate chain."))
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95),
+dgettext(TEXT_DOMAIN,
+"Unable to export. Unable to locate certificate or key by nickname."))
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96),
+dgettext(TEXT_DOMAIN,
+"Unable to export. Private Key could not be located and exported."))
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97),
+dgettext(TEXT_DOMAIN,
+"Unable to export. Unable to write the export file."))
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98),
+dgettext(TEXT_DOMAIN,
+"Unable to import. Unable to read the import file."))
+
+ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99),
+dgettext(TEXT_DOMAIN,
+"Unable to export. Key database corrupt or deleted."))
+
+ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100),
+dgettext(TEXT_DOMAIN,
+"Unable to generate public/private key pair."))
+
+ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101),
+dgettext(TEXT_DOMAIN,
+"Password entered is invalid. Please pick a different one."))
+
+ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102),
+dgettext(TEXT_DOMAIN,
+"Old password entered incorrectly. Please try again."))
+
+ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103),
+dgettext(TEXT_DOMAIN,
+"Certificate nickname already in use."))
+
+ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104),
+dgettext(TEXT_DOMAIN,
+"Peer FORTEZZA chain has a non-FORTEZZA Certificate."))
+
+/* ER3(SEC_ERROR_UNKNOWN, (SEC_ERROR_BASE + 105), */
+
+ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106),
+dgettext(TEXT_DOMAIN,
+"Invalid module name."))
+
+ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107),
+dgettext(TEXT_DOMAIN,
+"Invalid module path/filename"))
+
+ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108),
+dgettext(TEXT_DOMAIN,
+"Unable to add module"))
+
+ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109),
+dgettext(TEXT_DOMAIN,
+"Unable to delete module"))
+
+ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110),
+dgettext(TEXT_DOMAIN,
+"New KRL is not later than the current one."))
+
+ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111),
+dgettext(TEXT_DOMAIN,
+"New CKL has different issuer than current CKL. Delete current CKL."))
+
+#if 0 /* This was defined AFTER HCL 1.5 was released. */
+ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112),
+"The Certifying Authority for this certifcate is not permitted to issue a \
+certifcate with this name."))
+#endif
+
+
+
diff --git a/usr/src/lib/libldap5/sources/ldap/ssldap/sslerrstrs.h b/usr/src/lib/libldap5/sources/ldap/ssldap/sslerrstrs.h
new file mode 100644
index 0000000000..a579708c62
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/ssldap/sslerrstrs.h
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+/*
+ * sslerrstrs.h - map SSL errors to strings (used by errormap.c)
+ *
+ */
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/SSLerrs.h on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DIRECTORY.
+ ****************************************************************************
+ */
+
+/* SSL-specific security error codes */
+/* caller must include "sslerr.h" */
+
+ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0,
+dgettext(TEXT_DOMAIN,
+"Unable to communicate securely. Peer does not support high-grade encryption."))
+
+ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1,
+dgettext(TEXT_DOMAIN,
+"Unable to communicate securely. Peer requires high-grade encryption which is not supported."))
+
+ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2,
+dgettext(TEXT_DOMAIN,
+"Cannot communicate securely with peer: no common encryption algorithm(s)."))
+
+ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3,
+dgettext(TEXT_DOMAIN,
+"Unable to find the certificate or key necessary for authentication."))
+
+ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4,
+dgettext(TEXT_DOMAIN,
+"Unable to communicate securely with peer: peers's certificate was rejected."))
+
+/* unused (SSL_ERROR_BASE + 5),*/
+
+ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6,
+dgettext(TEXT_DOMAIN,
+"The server has encountered bad data from the client."))
+
+ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7,
+dgettext(TEXT_DOMAIN,
+"The client has encountered bad data from the server."))
+
+ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8,
+dgettext(TEXT_DOMAIN,
+"Unsupported certificate type."))
+
+ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9,
+dgettext(TEXT_DOMAIN,
+"Peer using unsupported version of security protocol."))
+
+/* unused (SSL_ERROR_BASE + 10),*/
+
+ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11,
+dgettext(TEXT_DOMAIN,
+"Client authentication failed: private key in key database does not match public key in certificate database."))
+
+ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12,
+dgettext(TEXT_DOMAIN,
+"Unable to communicate securely with peer: requested domain name does not match the server's certificate."))
+
+/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13),
+ defined in sslerr.h
+*/
+
+ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14),
+dgettext(TEXT_DOMAIN,
+"Peer only supports SSL version 2, which is locally disabled."))
+
+
+ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15),
+dgettext(TEXT_DOMAIN,
+"SSL received a record with an incorrect Message Authentication Code."))
+
+ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16),
+dgettext(TEXT_DOMAIN,
+"SSL peer reports incorrect Message Authentication Code."))
+
+ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17),
+dgettext(TEXT_DOMAIN,
+"SSL peer cannot verify your certificate."))
+
+ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18),
+dgettext(TEXT_DOMAIN,
+"SSL peer rejected your certificate as revoked."))
+
+ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19),
+dgettext(TEXT_DOMAIN,
+"SSL peer rejected your certificate as expired."))
+
+ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20),
+dgettext(TEXT_DOMAIN,
+"Cannot connect: SSL is disabled."))
+
+ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21),
+dgettext(TEXT_DOMAIN,
+"Cannot connect: SSL peer is in another FORTEZZA domain."))
+
+ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22),
+dgettext(TEXT_DOMAIN,
+"An unknown SSL cipher suite has been requested."))
+
+ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23),
+dgettext(TEXT_DOMAIN,
+"No cipher suites are present and enabled in this program."))
+
+ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24),
+dgettext(TEXT_DOMAIN,
+"SSL received a record with bad block padding."))
+
+ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25),
+dgettext(TEXT_DOMAIN,
+"SSL received a record that exceeded the maximum permissible length."))
+
+ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26),
+dgettext(TEXT_DOMAIN,
+"SSL attempted to send a record that exceeded the maximum permissible length."))
+
+/*
+ * Received a malformed (too long or short or invalid content) SSL handshake.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Hello Request handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Client Hello handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Server Hello handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Certificate handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Server Key Exchange handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Certificate Request handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Server Hello Done handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Certificate Verify handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Client Key Exchange handshake message."))
+
+ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Finished handshake message."))
+
+/*
+ * Received a malformed (too long or short) SSL record.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Change Cipher Spec record."))
+
+ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Alert record."))
+
+ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Handshake record."))
+
+ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40),
+dgettext(TEXT_DOMAIN,
+"SSL received a malformed Application Data record."))
+
+/*
+ * Received an SSL handshake that was inappropriate for the state we're in.
+ * E.g. Server received message from server, or wrong state in state machine.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Hello Request handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Client Hello handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Server Hello handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Certificate handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Server Key Exchange handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Certificate Request handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Server Hello Done handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Certificate Verify handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Cllient Key Exchange handshake message."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Finished handshake message."))
+
+/*
+ * Received an SSL record that was inappropriate for the state we're in.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Change Cipher Spec record."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Alert record."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Handshake record."))
+
+ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54),
+dgettext(TEXT_DOMAIN,
+"SSL received an unexpected Application Data record."))
+
+/*
+ * Received record/message with unknown discriminant.
+ */
+ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55),
+dgettext(TEXT_DOMAIN,
+"SSL received a record with an unknown content type."))
+
+ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56),
+dgettext(TEXT_DOMAIN,
+"SSL received a handshake message with an unknown message type."))
+
+ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57),
+dgettext(TEXT_DOMAIN,
+"SSL received an alert record with an unknown alert description."))
+
+/*
+ * Received an alert reporting what we did wrong. (more alerts above)
+ */
+ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58),
+dgettext(TEXT_DOMAIN,
+"SSL peer has closed this connection."))
+
+ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59),
+dgettext(TEXT_DOMAIN,
+"SSL peer was not expecting a handshake message it received."))
+
+ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60),
+dgettext(TEXT_DOMAIN,
+"SSL peer was unable to succesfully decompress an SSL record it received."))
+
+ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61),
+dgettext(TEXT_DOMAIN,
+"SSL peer was unable to negotiate an acceptable set of security parameters."))
+
+ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62),
+dgettext(TEXT_DOMAIN,
+"SSL peer rejected a handshake message for unacceptable content."))
+
+ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63),
+dgettext(TEXT_DOMAIN,
+"SSL peer does not support certificates of the type it received."))
+
+ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64),
+dgettext(TEXT_DOMAIN,
+"SSL peer had some unspecified issue with the certificate it received."))
+
+ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65),
+dgettext(TEXT_DOMAIN,
+"SSL experienced a failure of its random number generator."))
+
+ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66),
+dgettext(TEXT_DOMAIN,
+"Unable to digitally sign data required to verify your certificate."))
+
+ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67),
+dgettext(TEXT_DOMAIN,
+"SSL was unable to extract the public key from the peer's certificate."))
+
+ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68),
+dgettext(TEXT_DOMAIN,
+"Unspecified failure while processing SSL Server Key Exchange handshake."))
+
+ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69),
+dgettext(TEXT_DOMAIN,
+"Unspecified failure while processing SSL Client Key Exchange handshake."))
+
+ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70),
+dgettext(TEXT_DOMAIN,
+"Bulk data encryption algorithm failed in selected cipher suite."))
+
+ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71),
+dgettext(TEXT_DOMAIN,
+"Bulk data decryption algorithm failed in selected cipher suite."))
+
+ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72),
+dgettext(TEXT_DOMAIN,
+"Attempt to write encrypted data to underlying socket failed."))
+
+ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73),
+dgettext(TEXT_DOMAIN,
+"MD5 digest function failed."))
+
+ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74),
+dgettext(TEXT_DOMAIN,
+"SHA-1 digest function failed."))
+
+ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75),
+dgettext(TEXT_DOMAIN,
+"MAC computation failed."))
+
+ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76),
+dgettext(TEXT_DOMAIN,
+"Failure to create Symmetric Key context."))
+
+ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77),
+dgettext(TEXT_DOMAIN,
+"Failure to unwrap the Symmetric key in Client Key Exchange message."))
+
+ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78),
+dgettext(TEXT_DOMAIN,
+"SSL Server attempted to use domestic-grade public key with export cipher suite."))
+
+ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79),
+dgettext(TEXT_DOMAIN,
+"PKCS11 code failed to translate an IV into a param."))
+
+ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80),
+dgettext(TEXT_DOMAIN,
+"Failed to initialize the selected cipher suite."))
+
+ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81),
+dgettext(TEXT_DOMAIN,
+"Client failed to generate session keys for SSL session."))
+
+ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82),
+dgettext(TEXT_DOMAIN,
+"Server has no key for the attempted key exchange algorithm."))
+
+ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83),
+dgettext(TEXT_DOMAIN,
+"PKCS#11 token was inserted or removed while operation was in progress."))
+
+ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84),
+dgettext(TEXT_DOMAIN,
+"No PKCS#11 token could be found to do a required operation."))
+
+ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85),
+dgettext(TEXT_DOMAIN,
+"Cannot communicate securely with peer: no common compression algorithm(s)."))
+
+ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86),
+dgettext(TEXT_DOMAIN,
+"Cannot initiate another SSL handshake until current handshake is complete."))
+
+ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87),
+dgettext(TEXT_DOMAIN,
+"Received incorrect handshakes hash values from peer."))
+
+ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88),
+dgettext(TEXT_DOMAIN,
+"The certificate provided cannot be used with the selected key exchange algorithm."))
diff --git a/usr/src/lib/libldap5/sources/ldap/util/line64.c b/usr/src/lib/libldap5/sources/ldap/util/line64.c
new file mode 100644
index 0000000000..06bd75daca
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/util/line64.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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 Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/* line64.c - routines for dealing with the slapd line format */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef macintosh
+#include <sys/types.h>
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#elif !defined( macintosh )
+#include <sys/socket.h>
+#endif
+#include "ldaplog.h"
+#include "ldif.h"
+
+#ifndef isascii
+#define isascii( c ) (!((c) & ~0177))
+#endif
+
+#define RIGHT2 0x03
+#define RIGHT4 0x0f
+#define CONTINUED_LINE_MARKER '\001'
+
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') /* not "\r\v\f" */
+
+#define LDIF_OPT_ISSET( value, opt ) (((value) & (opt)) != 0 )
+
+static char nib2b64[0x40] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned char b642nib[0x80] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static int ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen,
+ int lenused, int wraplen );
+
+/*
+ * str_parse_line - takes a line of the form "type:[:] value" and splits it
+ * into components "type" and "value". if a double colon separates type from
+ * value, then value is encoded in base 64, and parse_line un-decodes it
+ * (in place) before returning.
+ */
+
+int
+str_parse_line(
+ char *line,
+ char **type,
+ char **value,
+ int *vlen
+)
+{
+ char *p, *s, *d;
+ int b64;
+
+ /* skip any leading space */
+ while ( ISBLANK( *line ) ) {
+ line++;
+ }
+ *type = line;
+
+ for ( s = line; *s && *s != ':'; s++ )
+ ; /* NULL */
+ if ( *s == '\0' ) {
+
+ /* Comment-out while we address calling libldif from ns-back-ldbm
+ on NT. 1 of 3 */
+#if defined( _WIN32 )
+ /*
+#endif
+ LDAPDebug( LDAP_DEBUG_PARSE, "str_parse_line: missing ':' "
+ "on line \"%s\"\n", line, 0, 0 );
+#if defined( _WIN32 )
+ */
+#endif
+ return( -1 );
+ }
+
+ /* trim any space between type and : */
+ for ( p = s - 1; p > line && ISBLANK( *p ); p-- ) {
+ *p = '\0';
+ }
+ *s++ = '\0';
+
+ /* check for double : - indicates base 64 encoded value */
+ if ( *s == ':' ) {
+ s++;
+ b64 = 1;
+
+ /* single : - normally encoded value */
+ } else {
+ b64 = 0;
+ }
+
+ /* skip space between : and value */
+ while ( ISBLANK( *s ) ) {
+ s++;
+ }
+
+ /*
+ * If no value is present, return a zero-length string for
+ * *value, with *vlen set to zero.
+ */
+ if ( *s == '\0' ) {
+ *value = s;
+ *vlen = 0;
+ return( 0 );
+ }
+
+ /* check for continued line markers that should be deleted */
+ for ( p = s, d = s; *p; p++ ) {
+ if ( *p != CONTINUED_LINE_MARKER )
+ *d++ = *p;
+ }
+ *d = '\0';
+
+ *value = s;
+ if ( b64 ) {
+ if (( *vlen = ldif_base64_decode( s, (unsigned char *)s ))
+ < 0 ) {
+ /* Comment-out while we address calling libldif from ns-back-ldbm
+ on NT. 3 of 3 */
+#if defined( _WIN32 )
+ /*
+#endif
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "str_parse_line: invalid base 64 char on line \"%s\"\n",
+ line, 0, 0 );
+#if defined( _WIN32 )
+ */
+#endif
+ return( -1 );
+ }
+ s[ *vlen ] = '\0';
+ } else {
+ *vlen = (int) (d - s);
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * ldif_base64_decode - take the BASE64-encoded characters in "src"
+ * (a zero-terminated string) and decode them into the the buffer "dst".
+ * "src" and "dst" can be the same if in-place decoding is desired.
+ * "dst" must be large enough to hold the decoded octets. No more than
+ * 3 * strlen( src ) / 4 bytes will be produced.
+ * "dst" may contain zero octets anywhere within it, but it is not
+ * zero-terminated by this function.
+ *
+ * The number of bytes copied to "dst" is returned if all goes well.
+ * -1 is returned if the BASE64 encoding in "src" is invalid.
+ */
+
+int
+ldif_base64_decode( char *src, unsigned char *dst )
+{
+ char *p, *stop;
+ unsigned char nib, *byte;
+ int i, len;
+
+ stop = strchr( src, '\0' );
+ byte = dst;
+ for ( p = src, len = 0; p < stop; p += 4, len += 3 ) {
+ for ( i = 0; i < 4; i++ ) {
+ if ( p[i] != '=' && (p[i] & 0x80 ||
+ b642nib[ p[i] & 0x7f ] > 0x3f) ) {
+ return( -1 );
+ }
+ }
+
+ /* first digit */
+ nib = b642nib[ p[0] & 0x7f ];
+ byte[0] = nib << 2;
+
+ /* second digit */
+ nib = b642nib[ p[1] & 0x7f ];
+ byte[0] |= nib >> 4;
+
+ /* third digit */
+ if ( p[2] == '=' ) {
+ len += 1;
+ break;
+ }
+ byte[1] = (nib & RIGHT4) << 4;
+ nib = b642nib[ p[2] & 0x7f ];
+ byte[1] |= nib >> 2;
+
+ /* fourth digit */
+ if ( p[3] == '=' ) {
+ len += 2;
+ break;
+ }
+ byte[2] = (nib & RIGHT2) << 6;
+ nib = b642nib[ p[3] & 0x7f ];
+ byte[2] |= nib;
+
+ byte += 3;
+ }
+
+ return( len );
+}
+
+/*
+ * str_getline - return the next "line" (minus newline) of input from a
+ * string buffer of lines separated by newlines, terminated by \n\n
+ * or \0. this routine handles continued lines, bundling them into
+ * a single big line before returning. if a line begins with a white
+ * space character, it is a continuation of the previous line. the white
+ * space character (nb: only one char), and preceeding newline are changed
+ * into CONTINUED_LINE_MARKER chars, to be deleted later by the
+ * str_parse_line() routine above.
+ *
+ * it takes a pointer to a pointer to the buffer on the first call,
+ * which it updates and must be supplied on subsequent calls.
+ *
+ * XXX need to update this function to also support <CR><LF> as EOL.
+ * XXX supports <CR><LF> as of 07/29/1998 (richm)
+ */
+
+char *
+str_getline( char **next )
+{
+ char *l;
+ char c;
+ char *p;
+
+ if ( *next == NULL || **next == '\n' || **next == '\0' ) {
+ return( NULL );
+ }
+
+ while ( **next == '#' ) { /* skip comment lines */
+ if (( *next = strchr( *next, '\n' )) == NULL ) {
+ return( NULL );
+ }
+ (*next)++;
+ }
+
+ l = *next;
+ while ( (*next = strchr( *next, '\n' )) != NULL ) {
+ p = *next - 1; /* pointer to character previous to the newline */
+ c = *(*next + 1); /* character after the newline */
+ if ( ISBLANK( c ) && c != '\n' ) {
+ /* DOS EOL is \r\n, so if the character before */
+ /* the \n is \r, continue it too */
+ if (*p == '\r')
+ *p = CONTINUED_LINE_MARKER;
+ **next = CONTINUED_LINE_MARKER;
+ *(*next+1) = CONTINUED_LINE_MARKER;
+ } else {
+ /* DOS EOL is \r\n, so if the character before */
+ /* the \n is \r, null it too */
+ if (*p == '\r')
+ *p = '\0';
+ *(*next)++ = '\0';
+ break;
+ }
+ (*next)++;
+ }
+
+ return( l );
+}
+
+
+#define LDIF_SAFE_CHAR( c ) ( (c) != '\r' && (c) != '\n' )
+#define LDIF_CONSERVATIVE_CHAR( c ) ( LDIF_SAFE_CHAR(c) && isascii((c)) \
+ && ( isprint((c)) || (c) == '\t' ))
+#define LDIF_SAFE_INITCHAR( c ) ( LDIF_SAFE_CHAR(c) && (c) != ':' \
+ && (c) != ' ' && (c) != '<' )
+#define LDIF_CONSERVATIVE_INITCHAR( c ) ( LDIF_SAFE_INITCHAR( c ) && \
+ ! ( isascii((c)) && isspace((c))))
+#define LDIF_CONSERVATIVE_FINALCHAR( c ) ( (c) != ' ' )
+
+
+void
+ldif_put_type_and_value_with_options( char **out, char *t, char *val,
+ int vlen, unsigned long options )
+{
+ unsigned char *p, *byte, *stop;
+ char *save;
+ int b64, len, savelen, wraplen;
+ len = 0;
+
+ if ( LDIF_OPT_ISSET( options, LDIF_OPT_NOWRAP )) {
+ wraplen = -1;
+ } else {
+ wraplen = LDIF_MAX_LINE_WIDTH;
+ }
+
+ /* put the type + ": " */
+ for ( p = (unsigned char *) t; *p; p++, len++ ) {
+ *(*out)++ = *p;
+ }
+ *(*out)++ = ':';
+ len++;
+ if ( LDIF_OPT_ISSET( options, LDIF_OPT_VALUE_IS_URL )) {
+ *(*out)++ = '<'; /* add '<' for URLs */
+ len++;
+ }
+ save = *out;
+ savelen = len;
+ b64 = 0;
+
+ stop = (unsigned char *)val;
+ if ( val && vlen > 0 ) {
+ *(*out)++ = ' ';
+ stop = (unsigned char *) (val + vlen);
+ if ( LDIF_OPT_ISSET( options, LDIF_OPT_MINIMAL_ENCODING )) {
+ if ( !LDIF_SAFE_INITCHAR( val[0] )) {
+ b64 = 1;
+ }
+ } else {
+ if ( !LDIF_CONSERVATIVE_INITCHAR( val[0] ) ||
+ !LDIF_CONSERVATIVE_FINALCHAR( val[vlen-1] )) {
+ b64 = 1;
+ }
+ }
+ }
+
+ if ( !b64 ) {
+ for ( byte = (unsigned char *) val; byte < stop;
+ byte++, len++ ) {
+ if ( LDIF_OPT_ISSET( options,
+ LDIF_OPT_MINIMAL_ENCODING )) {
+ if ( !LDIF_SAFE_CHAR( *byte )) {
+ b64 = 1;
+ break;
+ }
+ } else if ( !LDIF_CONSERVATIVE_CHAR( *byte )) {
+ b64 = 1;
+ break;
+ }
+
+ if ( wraplen != -1 && len > wraplen ) {
+ *(*out)++ = '\n';
+ *(*out)++ = ' ';
+ len = 1;
+ }
+ *(*out)++ = *byte;
+ }
+ }
+
+ if ( b64 ) {
+ *out = save;
+ *(*out)++ = ':';
+ *(*out)++ = ' ';
+ len = ldif_base64_encode_internal( (unsigned char *)val, *out, vlen,
+ savelen + 2, wraplen );
+ *out += len;
+ }
+
+ *(*out)++ = '\n';
+}
+
+void
+ldif_put_type_and_value( char **out, char *t, char *val, int vlen )
+{
+ ldif_put_type_and_value_with_options( out, t, val, vlen, 0 );
+}
+
+void
+ldif_put_type_and_value_nowrap( char **out, char *t, char *val, int vlen )
+{
+ ldif_put_type_and_value_with_options( out, t, val, vlen, LDIF_OPT_NOWRAP );
+}
+
+/*
+ * ldif_base64_encode_internal - encode "srclen" bytes in "src", place BASE64
+ * encoded bytes in "dst" and return the length of the BASE64
+ * encoded string. "dst" is also zero-terminated by this function.
+ *
+ * If "lenused" >= 0, newlines will be included in "dst" and "lenused" if
+ * appropriate. "lenused" should be a count of characters already used
+ * on the current line. The LDIF lines we create will contain at most
+ * "wraplen" characters on each line, unless "wraplen" is -1, in which
+ * case output line length is unlimited.
+ *
+ * If "lenused" < 0, no newlines will be included, and the LDIF_BASE64_LEN()
+ * macro can be used to determine how many bytes will be placed in "dst."
+ */
+
+static int
+ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen, int lenused, int wraplen )
+{
+ unsigned char *byte, *stop;
+ unsigned char buf[3];
+ char *out;
+ unsigned long bits;
+ int i, pad, len;
+
+ len = 0;
+ out = dst;
+ stop = src + srclen;
+
+ /* convert to base 64 (3 bytes => 4 base 64 digits) */
+ for ( byte = src; byte < stop - 2; byte += 3 ) {
+ bits = (byte[0] & 0xff) << 16;
+ bits |= (byte[1] & 0xff) << 8;
+ bits |= (byte[2] & 0xff);
+
+ for ( i = 0; i < 4; i++, bits <<= 6 ) {
+ if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) {
+ *out++ = '\n';
+ *out++ = ' ';
+ lenused = 2;
+ }
+
+ /* get b64 digit from high order 6 bits */
+ *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+ }
+ }
+
+ /* add padding if necessary */
+ if ( byte < stop ) {
+ for ( i = 0; byte + i < stop; i++ ) {
+ buf[i] = byte[i];
+ }
+ for ( pad = 0; i < 3; i++, pad++ ) {
+ buf[i] = '\0';
+ }
+ byte = buf;
+ bits = (byte[0] & 0xff) << 16;
+ bits |= (byte[1] & 0xff) << 8;
+ bits |= (byte[2] & 0xff);
+
+ for ( i = 0; i < 4; i++, bits <<= 6 ) {
+ if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) {
+ *out++ = '\n';
+ *out++ = ' ';
+ lenused = 2;
+ }
+
+ if (( i == 3 && pad > 0 ) || ( i == 2 && pad == 2 )) {
+ /* Pad as appropriate */
+ *out++ = '=';
+ } else {
+ /* get b64 digit from low order 6 bits */
+ *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+ }
+ }
+ }
+
+ *out = '\0';
+
+ return( out - dst );
+}
+
+int
+ldif_base64_encode( unsigned char *src, char *dst, int srclen, int lenused )
+{
+ return ldif_base64_encode_internal( src, dst, srclen, lenused, LDIF_MAX_LINE_WIDTH );
+}
+
+int
+ldif_base64_encode_nowrap( unsigned char *src, char *dst, int srclen, int lenused )
+{
+ return ldif_base64_encode_internal( src, dst, srclen, lenused, -1 );
+}
+
+
+/*
+ * return malloc'd, zero-terminated LDIF line
+ */
+char *
+ldif_type_and_value_with_options( char *type, char *val, int vlen,
+ unsigned long options )
+{
+ char *buf, *p;
+ int tlen;
+
+ tlen = strlen( type );
+ if (( buf = (char *)malloc( LDIF_SIZE_NEEDED( tlen, vlen ) + 1 )) !=
+ NULL ) {
+ p = buf;
+ ldif_put_type_and_value_with_options( &p, type, val, vlen, options );
+ *p = '\0';
+ }
+
+ return( buf );
+}
+
+char *
+ldif_type_and_value( char *type, char *val, int vlen )
+{
+ return ldif_type_and_value_with_options( type, val, vlen, 0 );
+}
+
+char *
+ldif_type_and_value_nowrap( char *type, char *val, int vlen )
+{
+ return ldif_type_and_value_with_options( type, val, vlen, LDIF_OPT_NOWRAP );
+}
+
+/*
+ * ldif_get_entry - read the next ldif entry from the FILE referenced
+ * by fp. return a pointer to a malloc'd, null-terminated buffer. also
+ * returned is the last line number read, in *lineno.
+ */
+char *
+ldif_get_entry( FILE *fp, int *lineno )
+{
+ char line[BUFSIZ];
+ char *buf;
+ int max, cur, len, gotsome;
+
+ buf = NULL;
+ max = cur = gotsome = 0;
+ while ( fgets( line, sizeof(line), fp ) != NULL ) {
+ if ( lineno != NULL ) {
+ (*lineno)++;
+ }
+ /* ldif entries are terminated by a \n on a line by itself */
+ if ( line[0] == '\0' || line[0] == '\n'
+#if !defined( XP_WIN32 )
+ || ( line[0] == '\r' && line[1] == '\n' ) /* DOS format */
+#endif
+ ) {
+ if ( gotsome ) {
+ break;
+ } else {
+ continue;
+ }
+ } else if ( line[0] == '#' ) {
+ continue;
+ }
+ gotsome = 1;
+ len = strlen( line );
+#if !defined( XP_WIN32 )
+ /* DOS format */
+ if ( len > 0 && line[len-1] == '\r' ) {
+ --len;
+ line[len] = '\0';
+ } else if ( len > 1 && line[len-2] == '\r' && line[len-1] == '\n' ) {
+ --len;
+ line[len-1] = line[len];
+ line[len] = '\0';
+ }
+#endif
+ while ( cur + (len + 1) > max ) {
+ if ( buf == NULL ) {
+ max += BUFSIZ;
+ buf = (char *) malloc( max );
+ } else {
+ max *= 2;
+ buf = (char *) realloc( buf, max );
+ }
+ if ( buf == NULL ) {
+ return( NULL );
+ }
+ }
+
+ memcpy( buf + cur, line, len + 1 );
+ cur += len;
+ }
+
+ return( buf );
+}
diff --git a/usr/src/lib/libldap5/sources/ldap/util/log.c b/usr/src/lib/libldap5/sources/ldap/util/log.c
new file mode 100644
index 0000000000..3e8780a381
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/util/log.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <nl_types.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <syslog.h>
+#include <portable.h>
+/* #include <lthread.h> */
+#include <pthread.h>
+#include <thread.h>
+
+#include "log.h"
+
+#define LDAP_DEBUG_ANY 0xffff
+
+static pthread_mutex_t log_mutex;
+static char logfile[PATH_MAX] =
+ "/var/opt/SUNWconn/ldap/log/slapd.log";
+static int logsize = 512000;
+static int logtime = 1;
+static FILE *logfd = NULL;
+static int syslogopen = 0;
+pthread_mutex_t systime_mutex;
+nl_catd sundscat;
+static int log_debug = LDAP_DEBUG_STATS;
+
+typedef struct _logctx {
+ char *logfile;
+ int syslogopen;
+ int logsize;
+ pthread_mutex_t log_mutex;
+ int log_debug;
+ int log_syslog;
+
+} LogCtx;
+
+void
+ldaplogconfig(char *logf, int size)
+{
+ strcpy(logfile, logf);
+ logsize = size * 1024;
+}
+
+void
+ldaplogconfigf(FILE *fd)
+{
+ logfd = fd;
+ logsize = 0;
+}
+
+void
+ldaploginit(char *name, int facility)
+{
+ openlog(name, OPENLOG_OPTIONS, facility);
+ syslogopen = 1;
+ pthread_mutex_init(&log_mutex, NULL);
+}
+
+void
+ldaploginitlevel(char *name, int facility, int level)
+{
+ ldaploginit(name, facility);
+ log_debug = level;
+}
+
+LogCtx *
+sundsloginit(char *name, int facility, int debug_level, int syslog_level)
+{
+ LogCtx *returnCtx = NULL;
+
+ if ((returnCtx = (LogCtx *)malloc(sizeof (LogCtx))) == NULL)
+ return (NULL);
+ if ((returnCtx->logfile = strdup(name)) == NULL) {
+ free(returnCtx);
+ return (NULL);
+ }
+ openlog(returnCtx->logfile, OPENLOG_OPTIONS, facility);
+ returnCtx->syslogopen = 1;
+ pthread_mutex_init(&(returnCtx->log_mutex), NULL);
+ returnCtx->log_debug = debug_level;
+ returnCtx->log_syslog = syslog_level;
+ return (returnCtx);
+}
+
+static char timestr[128];
+static time_t timelast = 0;
+
+/*VARARGS*/
+void
+ldaplog(int level, char *fmt, ...)
+{
+ va_list ap;
+ struct stat statbuf = {0};
+ char newlog1[PATH_MAX];
+ char newlog2[PATH_MAX];
+ time_t now;
+ int i;
+
+ if (!(log_debug & level))
+ return;
+
+ va_start(ap, fmt);
+
+ if (level == LDAP_DEBUG_ANY) {
+ /*
+ * this message is probably an error message, send it to syslog
+ */
+ if (syslogopen) {
+ vsyslog(LOG_ERR, fmt, ap);
+ } /* end if */
+ /* and sent it also on stderr */
+ vfprintf(stderr, fmt, ap);
+ } /* end if */
+
+ /*
+ * check that the log file is not already too big
+ */
+ pthread_mutex_lock(&log_mutex);
+ if ((logsize > 0) && (stat(logfile, &statbuf) == 0 &&
+ statbuf.st_size > logsize)) {
+ for (i = 9; i > 1; i--) {
+ (void) sprintf(newlog1, "%s.%d", logfile, i-1);
+ (void) sprintf(newlog2, "%s.%d", logfile, i);
+ (void) rename(newlog1, newlog2);
+ } /* end for */
+ if (logfd) {
+ fclose(logfd);
+ logfd = NULL;
+ } /* end if */
+ (void) rename(logfile, newlog1);
+ } /* end if */
+ /*
+ * send the message into a regular log file
+ */
+ if (!logfd) {
+ logfd = fopen(logfile, "a");
+ } /* end if */
+ /*
+ * finally write the message into the log file
+ */
+ if (logfd) {
+ if (logtime) {
+ time(&now);
+ if (now-timelast > 60) {
+ pthread_mutex_lock(&systime_mutex);
+ timelast = now;
+ ctime_r(&now, timestr, 128);
+ pthread_mutex_unlock(&systime_mutex);
+ } /* end if */
+ fprintf(logfd, "%.16s : ", timestr);
+ } /* end if */
+ vfprintf(logfd, fmt, ap);
+ fflush(logfd);
+ } /* end if */
+ pthread_mutex_unlock(&log_mutex);
+ va_end(ap);
+}