Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
ingo Voss
OpenLDAP
Commits
26a48389
Commit
26a48389
authored
Apr 18, 2002
by
Kurt Zeilenga
Browse files
More resyncing with HEAD
parent
2e64f2fc
Changes
12
Hide whitespace changes
Inline
Side-by-side
include/ldap.h
View file @
26a48389
...
...
@@ -1259,6 +1259,12 @@ ldap_explode_rdn LDAP_P(( /* deprecated */
LDAP_CONST
char
*
rdn
,
int
notypes
));
typedef
int
LDAPDN_rewrite_func
LDAP_P
((
LDAPDN
*
dn
,
unsigned
flags
));
LDAP_F
(
int
)
ldap_X509dn2bv
LDAP_P
((
void
*
x509_name
,
struct
berval
*
dn
,
LDAPDN_rewrite_func
*
func
,
unsigned
flags
));
LDAP_F
(
char
*
)
ldap_dn2dcedn
LDAP_P
((
LDAP_CONST
char
*
dn
));
/* deprecated */
...
...
include/ldap_pvt.h
View file @
26a48389
...
...
@@ -179,8 +179,12 @@ LDAP_F (void *) ldap_pvt_tls_sb_ctx LDAP_P(( Sockbuf *sb ));
LDAP_F
(
int
)
ldap_pvt_tls_init_default_ctx
LDAP_P
((
void
));
LDAP_F
(
char
*
)
ldap_pvt_tls_get_peer
LDAP_P
((
void
*
ctx
));
LDAP_F
(
char
*
)
ldap_pvt_tls_get_peer_dn
LDAP_P
((
void
*
ctx
));
typedef
int
LDAPDN_rewrite_dummy
LDAP_P
((
void
*
dn
,
unsigned
flags
));
LDAP_F
(
char
*
)
ldap_pvt_tls_get_my_dn
LDAP_P
((
void
*
ctx
,
LDAPDN_rewrite_dummy
*
func
,
unsigned
flags
));
LDAP_F
(
char
*
)
ldap_pvt_tls_get_peer_dn
LDAP_P
((
void
*
ctx
,
LDAPDN_rewrite_dummy
*
func
,
unsigned
flags
));
LDAP_F
(
int
)
ldap_pvt_tls_get_strength
LDAP_P
((
void
*
ctx
));
LDAP_END_DECL
...
...
libraries/libldap/cyrus.c
View file @
26a48389
...
...
@@ -619,6 +619,9 @@ ldap_int_sasl_bind(
if
(
(
saslrc
!=
SASL_OK
)
&&
(
saslrc
!=
SASL_CONTINUE
)
)
{
ld
->
ld_errno
=
sasl_err2ldap
(
saslrc
);
#if SASL_VERSION_MAJOR >= 2
ld
->
ld_error
=
(
char
*
)
sasl_errdetail
(
ctx
);
#endif
return
ld
->
ld_errno
;
}
...
...
@@ -712,6 +715,9 @@ ldap_int_sasl_bind(
if
(
(
saslrc
!=
SASL_OK
)
&&
(
saslrc
!=
SASL_CONTINUE
)
)
{
ld
->
ld_errno
=
sasl_err2ldap
(
saslrc
);
#if SASL_VERSION_MAJOR >= 2
ld
->
ld_error
=
(
char
*
)
sasl_errdetail
(
ctx
);
#endif
return
ld
->
ld_errno
;
}
}
while
(
rc
==
LDAP_SASL_BIND_IN_PROGRESS
);
...
...
@@ -721,6 +727,9 @@ ldap_int_sasl_bind(
}
if
(
saslrc
!=
SASL_OK
)
{
#if SASL_VERSION_MAJOR >= 2
ld
->
ld_error
=
(
char
*
)
sasl_errdetail
(
ctx
);
#endif
return
ld
->
ld_errno
=
sasl_err2ldap
(
saslrc
);
}
...
...
@@ -779,6 +788,8 @@ ldap_int_sasl_external(
#if SASL_VERSION_MAJOR >= 2
sc
=
sasl_setprop
(
ctx
,
SASL_SSF_EXTERNAL
,
&
ssf
);
if
(
sc
==
SASL_OK
)
sc
=
sasl_setprop
(
ctx
,
SASL_AUTH_EXTERNAL
,
authid
);
#else
memset
(
&
extprops
,
'\0'
,
sizeof
(
extprops
)
);
extprops
.
ssf
=
ssf
;
...
...
libraries/libldap/getdn.c
View file @
26a48389
...
...
@@ -3291,3 +3291,108 @@ return_results:;
return
(
rc
);
}
#ifdef HAVE_TLS
#include
<openssl/x509.h>
#include
<openssl/err.h>
/* Convert a structured DN from an X.509 certificate into an LDAPV3 DN.
* x509_name must be an (X509_NAME *). If func is non-NULL, the
* constructed DN will use numeric OIDs to identify attributeTypes,
* and the func() will be invoked to rewrite the DN with the given
* flags.
*
* Otherwise the DN will use shortNames as defined in the OpenSSL
* library.
*
* It's preferable to let slapd do the OID to attributeType mapping,
* because the OpenSSL tables are known to have many typos in versions
* up to (at least) 0.9.6c. However, the LDAP client has no schema tables,
* so we're forced to use OpenSSL's mapping there.
* -- Howard Chu 2002-04-18
*/
int
ldap_X509dn2bv
(
void
*
x509_name
,
struct
berval
*
bv
,
LDAPDN_rewrite_func
*
func
,
unsigned
flags
)
{
LDAPDN
*
newDN
=
NULL
;
LDAPRDN
*
newRDN
=
NULL
;
X509_NAME_ENTRY
*
ne
;
ASN1_OBJECT
*
obj
;
ASN1_STRING
*
str
;
char
oidbuf
[
2048
];
int
i
,
j
,
nrdns
,
rc
=
LDAP_NO_MEMORY
;
struct
berval
Type
;
struct
berval
Val
;
assert
(
bv
);
bv
->
bv_len
=
0
;
bv
->
bv_val
=
NULL
;
nrdns
=
X509_NAME_entry_count
(
x509_name
);
newDN
=
(
LDAPDN
*
)
LDAP_MALLOC
(
sizeof
(
LDAPDN
)
+
sizeof
(
LDAPRDN
*
)
*
(
nrdns
+
1
)
);
if
(
newDN
==
NULL
)
return
LDAP_NO_MEMORY
;
newDN
[
0
]
=
(
LDAPRDN
**
)(
newDN
+
1
);
/* Retrieve RDNs in reverse order; LDAP is backwards from X.500.
* The OpenSSL library appears to allow only 1 AVA per RDN.
*/
for
(
i
=
nrdns
-
1
,
j
=
0
;
i
>=
0
;
i
--
,
j
++
)
{
newDN
[
0
][
j
]
=
NULL
;
ne
=
X509_NAME_get_entry
(
x509_name
,
i
);
obj
=
X509_NAME_ENTRY_get_object
(
ne
);
str
=
X509_NAME_ENTRY_get_data
(
ne
);
if
(
!
func
)
{
int
n
=
OBJ_obj2nid
(
obj
);
if
(
n
==
NID_undef
)
goto
get_oid
;
Type
.
bv_val
=
(
char
*
)
OBJ_nid2sn
(
n
);
Type
.
bv_len
=
strlen
(
Type
.
bv_val
);
}
else
{
get_oid:
Type
.
bv_val
=
oidbuf
;
Type
.
bv_len
=
OBJ_obj2txt
(
oidbuf
,
sizeof
(
oidbuf
),
obj
,
1
);
}
Val
.
bv_len
=
str
->
length
;
Val
.
bv_val
=
str
->
data
;
newRDN
=
(
LDAPRDN
*
)
LDAP_MALLOC
(
sizeof
(
LDAPRDN
)
+
sizeof
(
LDAPAVA
*
)
*
2
);
if
(
newRDN
==
NULL
)
goto
nomem
;
newRDN
[
0
]
=
(
LDAPAVA
**
)(
newRDN
+
1
);
newRDN
[
0
][
0
]
=
ldapava_new
(
&
Type
,
&
Val
,
LDAP_AVA_STRING
);
if
(
newRDN
[
0
][
0
]
==
NULL
)
goto
nomem
;
newRDN
[
0
][
1
]
=
NULL
;
newDN
[
0
][
j
]
=
newRDN
;
newRDN
=
NULL
;
}
newDN
[
0
][
j
]
=
NULL
;
if
(
func
)
{
rc
=
func
(
newDN
,
flags
);
if
(
rc
!=
LDAP_SUCCESS
)
goto
nomem
;
}
rc
=
ldap_dn2bv
(
newDN
,
bv
,
LDAP_DN_FORMAT_LDAPV3
);
ldap_dnfree
(
newDN
);
return
rc
;
nomem:
if
(
newRDN
)
LDAP_FREE
(
newRDN
);
if
(
newDN
)
ldap_dnfree
(
newDN
);
return
rc
;
}
#endif
/* HAVE_TLS */
libraries/libldap/tls.c
View file @
26a48389
...
...
@@ -788,6 +788,23 @@ ldap_pvt_tls_get_strength( void *s )
}
char
*
ldap_pvt_tls_get_my_dn
(
void
*
s
,
LDAPDN_rewrite_dummy
*
func
,
unsigned
flags
)
{
X509
*
x
;
X509_NAME
*
xn
;
struct
berval
dn
;
x
=
SSL_get_certificate
((
SSL
*
)
s
);
if
(
!
x
)
return
NULL
;
xn
=
X509_get_subject_name
(
x
);
ldap_X509dn2bv
(
xn
,
&
dn
,
(
LDAPDN_rewrite_func
*
)
func
,
flags
);
X509_free
(
x
);
return
dn
.
bv_val
;
}
static
X509
*
tls_get_cert
(
SSL
*
s
)
{
...
...
@@ -803,42 +820,20 @@ tls_get_cert( SSL *s )
}
char
*
ldap_pvt_tls_get_peer
(
void
*
s
)
{
X509
*
x
;
X509_NAME
*
xn
;
char
buf
[
2048
],
*
p
;
x
=
tls_get_cert
((
SSL
*
)
s
);
if
(
!
x
)
return
NULL
;
xn
=
X509_get_subject_name
(
x
);
p
=
LDAP_STRDUP
(
X509_NAME_oneline
(
xn
,
buf
,
sizeof
(
buf
)));
X509_free
(
x
);
return
p
;
}
char
*
ldap_pvt_tls_get_peer_dn
(
void
*
s
)
ldap_pvt_tls_get_peer_dn
(
void
*
s
,
LDAPDN_rewrite_dummy
*
func
,
unsigned
flags
)
{
X509
*
x
;
X509_NAME
*
xn
;
char
buf
[
2048
],
*
p
,
*
dn
;
struct
berval
dn
;
x
=
tls_get_cert
((
SSL
*
)
s
);
if
(
!
x
)
return
NULL
;
xn
=
X509_get_subject_name
(
x
);
p
=
X509_NAME_oneline
(
xn
,
buf
,
sizeof
(
buf
));
dn
=
ldap_dcedn2dn
(
p
);
ldap_X509dn2bv
(
xn
,
&
dn
,
(
LDAPDN_rewrite_func
*
)
func
,
flags
);
X509_free
(
x
);
return
dn
;
return
dn
.
bv_val
;
}
char
*
...
...
@@ -983,7 +978,7 @@ ldap_pvt_tls_check_hostname( void *s, const char *name_in )
const
char
*
ldap_pvt_tls_get_peer_issuer
(
void
*
s
)
{
#if 0 /* currently unused; see ldap_pvt_tls_get_peer() if needed */
#if 0 /* currently unused; see ldap_pvt_tls_get_peer
_dn
() if needed */
X509 *x;
X509_NAME *xn;
char buf[2048], *p;
...
...
@@ -1256,9 +1251,10 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
/* we need to let SASL know */
ssf
=
ldap_pvt_tls_get_strength
(
ssl
);
authid
=
ldap_pvt_tls_get_
peer
(
ssl
);
authid
=
ldap_pvt_tls_get_
my_dn
(
ssl
,
NULL
,
0
);
(
void
)
ldap_int_sasl_external
(
ld
,
conn
,
authid
,
ssf
);
LDAP_FREE
(
authid
);
}
return
LDAP_SUCCESS
;
...
...
servers/slapd/ad.c
0 → 100644
View file @
26a48389
/* $OpenLDAP$ */
/*
* Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
/* ad.c - routines for dealing with attribute descriptions */
#include
"portable.h"
#include
<stdio.h>
#include
<ac/ctype.h>
#include
<ac/errno.h>
#include
<ac/socket.h>
#include
<ac/string.h>
#include
<ac/time.h>
#include
"ldap_pvt.h"
#include
"slap.h"
static
int
ad_keystring
(
struct
berval
*
bv
)
{
ber_len_t
i
;
if
(
!
AD_CHAR
(
bv
->
bv_val
[
0
]
)
)
{
return
1
;
}
for
(
i
=
1
;
i
<
bv
->
bv_len
;
i
++
)
{
if
(
!
AD_CHAR
(
bv
->
bv_val
[
i
]
)
)
{
return
1
;
}
}
return
0
;
}
void
ad_destroy
(
AttributeDescription
*
ad
)
{
AttributeDescription
*
n
;
for
(;
ad
!=
NULL
;
ad
=
n
)
{
n
=
ad
->
ad_next
;
ldap_memfree
(
ad
);
}
}
/* Is there an AttributeDescription for this type that uses this language? */
AttributeDescription
*
ad_find_lang
(
AttributeType
*
type
,
struct
berval
*
lang
)
{
AttributeDescription
*
ad
;
ldap_pvt_thread_mutex_lock
(
&
type
->
sat_ad_mutex
);
for
(
ad
=
type
->
sat_ad
;
ad
;
ad
=
ad
->
ad_next
)
{
if
(
ad
->
ad_lang
.
bv_len
==
lang
->
bv_len
&&
!
strcasecmp
(
ad
->
ad_lang
.
bv_val
,
lang
->
bv_val
))
break
;
}
ldap_pvt_thread_mutex_unlock
(
&
type
->
sat_ad_mutex
);
return
ad
;
}
int
slap_str2ad
(
const
char
*
str
,
AttributeDescription
**
ad
,
const
char
**
text
)
{
struct
berval
bv
;
bv
.
bv_val
=
(
char
*
)
str
;
bv
.
bv_len
=
strlen
(
str
);
return
slap_bv2ad
(
&
bv
,
ad
,
text
);
}
static
char
*
strchrlen
(
const
char
*
p
,
const
char
ch
,
int
*
len
)
{
int
i
;
for
(
i
=
0
;
p
[
i
];
i
++
)
{
if
(
p
[
i
]
==
ch
)
{
*
len
=
i
;
return
(
char
*
)
&
p
[
i
];
}
}
*
len
=
i
;
return
NULL
;
}
int
slap_bv2ad
(
struct
berval
*
bv
,
AttributeDescription
**
ad
,
const
char
**
text
)
{
int
rtn
=
LDAP_UNDEFINED_TYPE
;
AttributeDescription
desc
,
*
d2
;
char
*
name
,
*
options
;
char
*
opt
,
*
next
;
int
nlang
;
int
langlen
;
/* hardcoded limits for speed */
#define MAX_LANG_OPTIONS 128
struct
berval
langs
[
MAX_LANG_OPTIONS
+
1
];
#define MAX_LANG_LEN 1024
char
langbuf
[
MAX_LANG_LEN
];
assert
(
ad
!=
NULL
);
assert
(
*
ad
==
NULL
);
/* temporary */
if
(
bv
==
NULL
||
bv
->
bv_len
==
0
)
{
*
text
=
"empty attribute description"
;
return
rtn
;
}
/* make sure description is IA5 */
if
(
ad_keystring
(
bv
)
)
{
*
text
=
"attribute description contains inappropriate characters"
;
return
rtn
;
}
/* find valid base attribute type; parse in place */
memset
(
&
desc
,
0
,
sizeof
(
desc
));
desc
.
ad_cname
=
*
bv
;
name
=
bv
->
bv_val
;
options
=
strchr
(
name
,
';'
);
if
(
options
!=
NULL
)
{
desc
.
ad_cname
.
bv_len
=
options
-
name
;
}
desc
.
ad_type
=
at_bvfind
(
&
desc
.
ad_cname
);
if
(
desc
.
ad_type
==
NULL
)
{
*
text
=
"attribute type undefined"
;
return
rtn
;
}
if
(
is_at_operational
(
desc
.
ad_type
)
&&
options
!=
NULL
)
{
*
text
=
"operational attribute with options undefined"
;
return
rtn
;
}
/*
* parse options in place
*/
nlang
=
0
;
memset
(
langs
,
0
,
sizeof
(
langs
));
langlen
=
0
;
for
(
opt
=
options
;
opt
!=
NULL
;
opt
=
next
)
{
int
optlen
;
opt
++
;
next
=
strchrlen
(
opt
,
';'
,
&
optlen
);
if
(
optlen
==
0
)
{
*
text
=
"zero length option is invalid"
;
return
rtn
;
}
else
if
(
optlen
==
sizeof
(
"binary"
)
-
1
&&
strncasecmp
(
opt
,
"binary"
,
sizeof
(
"binary"
)
-
1
)
==
0
)
{
/* binary option */
if
(
slap_ad_is_binary
(
&
desc
)
)
{
*
text
=
"option
\"
binary
\"
specified multiple times"
;
return
rtn
;
}
if
(
!
slap_syntax_is_binary
(
desc
.
ad_type
->
sat_syntax
))
{
/* not stored in binary, disallow option */
*
text
=
"option
\"
binary
\"
not supported with type"
;
return
rtn
;
}
desc
.
ad_flags
|=
SLAP_DESC_BINARY
;
continue
;
}
else
if
(
optlen
>=
sizeof
(
"lang-"
)
-
1
&&
strncasecmp
(
opt
,
"lang-"
,
sizeof
(
"lang-"
)
-
1
)
==
0
)
{
int
i
;
if
(
opt
[
optlen
-
1
]
==
'-'
)
{
desc
.
ad_flags
|=
SLAP_DESC_LANG_RANGE
;
}
if
(
nlang
>=
MAX_LANG_OPTIONS
)
{
*
text
=
"too many language options"
;
return
rtn
;
}
/*
* tags should be presented in sorted order,
* so run the array in reverse.
*/
for
(
i
=
nlang
-
1
;
i
>=
0
;
i
--
)
{
int
rc
;
rc
=
strncasecmp
(
opt
,
langs
[
i
].
bv_val
,
(
unsigned
)
optlen
<
langs
[
i
].
bv_len
?
optlen
:
langs
[
i
].
bv_len
);
if
(
rc
==
0
&&
(
unsigned
)
optlen
==
langs
[
i
].
bv_len
)
{
/* duplicate (ignore) */
goto
done
;
}
else
if
(
rc
>
0
||
(
rc
==
0
&&
(
unsigned
)
optlen
>
langs
[
i
].
bv_len
))
{
AC_MEMCPY
(
&
langs
[
i
+
1
],
&
langs
[
i
],
(
nlang
-
i
)
*
sizeof
(
struct
berval
)
);
langs
[
i
].
bv_val
=
opt
;
langs
[
i
].
bv_len
=
optlen
;
goto
done
;
}
}
if
(
nlang
)
{
AC_MEMCPY
(
&
langs
[
1
],
&
langs
[
0
],
nlang
*
sizeof
(
struct
berval
)
);
}
langs
[
0
].
bv_val
=
opt
;
langs
[
0
].
bv_len
=
optlen
;
done:
;
langlen
+=
optlen
+
1
;
nlang
++
;
}
else
{
*
text
=
"unrecognized option"
;
return
rtn
;
}
}
if
(
nlang
>
0
)
{
int
i
;
if
(
langlen
>
MAX_LANG_LEN
)
{
*
text
=
"language options too long"
;
return
rtn
;
}
desc
.
ad_lang
.
bv_val
=
langbuf
;
langlen
=
0
;
for
(
i
=
0
;
i
<
nlang
;
i
++
)
{
AC_MEMCPY
(
&
desc
.
ad_lang
.
bv_val
[
langlen
],
langs
[
i
].
bv_val
,
langs
[
i
].
bv_len
);
langlen
+=
langs
[
i
].
bv_len
;
desc
.
ad_lang
.
bv_val
[
langlen
++
]
=
';'
;
}
desc
.
ad_lang
.
bv_val
[
--
langlen
]
=
'\0'
;
desc
.
ad_lang
.
bv_len
=
langlen
;
}
/* see if a matching description is already cached */
for
(
d2
=
desc
.
ad_type
->
sat_ad
;
d2
;
d2
=
d2
->
ad_next
)
{
if
(
d2
->
ad_flags
!=
desc
.
ad_flags
)
{
continue
;
}
if
(
d2
->
ad_lang
.
bv_len
!=
desc
.
ad_lang
.
bv_len
)
{
continue
;
}
if
(
d2
->
ad_lang
.
bv_len
==
0
)
{
break
;
}
if
(
strncasecmp
(
d2
->
ad_lang
.
bv_val
,
desc
.
ad_lang
.
bv_val
,
desc
.
ad_lang
.
bv_len
)
==
0
)
{
break
;
}
}
/* Not found, add new one */
while
(
d2
==
NULL
)
{
size_t
dlen
=
0
;
ldap_pvt_thread_mutex_lock
(
&
desc
.
ad_type
->
sat_ad_mutex
);
/* check again now that we've locked */
for
(
d2
=
desc
.
ad_type
->
sat_ad
;
d2
;
d2
=
d2
->
ad_next
)
{
if
(
d2
->
ad_flags
!=
desc
.
ad_flags
)
continue
;
if
(
d2
->
ad_lang
.
bv_len
!=
desc
.
ad_lang
.
bv_len
)
continue
;
if
(
d2
->
ad_lang
.
bv_len
==
0
)
break
;
if
(
strncasecmp
(
d2
->
ad_lang
.
bv_val
,
desc
.
ad_lang
.
bv_val
,
desc
.
ad_lang
.
bv_len
)
==
0
)
break
;
}
if
(
d2
)
{
ldap_pvt_thread_mutex_unlock
(
&
desc
.
ad_type
->
sat_ad_mutex
);
break
;
}
/* Allocate a single contiguous block. If there are no
* options, we just need space for the AttrDesc structure.
* Otherwise, we need to tack on the full name length +
* options length.
*/
if
(
desc
.
ad_lang
.
bv_len
||
desc
.
ad_flags
!=
SLAP_DESC_NONE
)
{
dlen
=
desc
.
ad_type
->
sat_cname
.
bv_len
;
if
(
desc
.
ad_lang
.
bv_len
)
{
dlen
+=
1
+
desc
.
ad_lang
.
bv_len
;
}
if
(
slap_ad_is_binary
(
&
desc
)
)
{
dlen
+=
sizeof
(
";binary"
)
-
1
;
}
}
d2
=
ch_malloc
(
sizeof
(
AttributeDescription
)
+
dlen
+
1
);
d2
->
ad_type
=
desc
.
ad_type
;
d2
->
ad_flags
=
desc
.
ad_flags
;
d2
->
ad_cname
.
bv_len
=
desc
.
ad_type
->
sat_cname
.
bv_len
;
d2
->
ad_lang
.
bv_len
=
desc
.
ad_lang
.
bv_len
;
if
(
dlen
==
0
)
{
d2
->
ad_cname
.
bv_val
=
d2
->
ad_type
->
sat_cname
.
bv_val
;
d2
->
ad_lang
.
bv_val
=
NULL
;
}
else
{
d2
->
ad_cname
.
bv_val
=
(
char
*
)(
d2
+
1
);
strcpy
(
d2
->
ad_cname
.
bv_val
,
d2
->
ad_type
->
sat_cname
.
bv_val
);
if
(
slap_ad_is_binary
(
&
desc
)
)
{
strcpy
(
d2
->
ad_cname
.
bv_val
+
d2
->
ad_cname
.
bv_len
,
";binary"
);
d2
->
ad_cname
.
bv_len
+=
sizeof
(
";binary"
)
-
1
;
}
if
(
d2
->
ad_lang
.
bv_len
)
{
d2
->
ad_cname
.
bv_val
[
d2
->
ad_cname
.
bv_len
++
]
=
';'
;
d2
->
ad_lang
.
bv_val
=
d2
->
ad_cname
.
bv_val
+
d2
->
ad_cname
.
bv_len
;
strncpy
(
d2
->
ad_lang
.
bv_val
,
desc
.
ad_lang
.
bv_val
,
d2
->
ad_lang
.
bv_len
);
d2
->
ad_lang
.
bv_val
[
d2
->
ad_lang
.
bv_len
]
=
'\0'
;
ldap_pvt_str2lower
(
d2
->
ad_lang
.
bv_val
);
d2
->
ad_cname
.
bv_len
+=
d2
->
ad_lang
.
bv_len
;
}
}
/* Add new desc to list. We always want the bare Desc with
* no options to stay at the head of the list, assuming
* that one will be used most frequently.
*/
if
(
desc
.
ad_type
->
sat_ad
==
NULL
||
dlen
==
0
)
{