xref: /titanic_52/usr/src/lib/libldap5/sources/ldap/common/getvalues.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
2*7c478bd9Sstevel@tonic-gate 
3*7c478bd9Sstevel@tonic-gate /*
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
5*7c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
6*7c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
7*7c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
10*7c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11*7c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
12*7c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
15*7c478bd9Sstevel@tonic-gate  * March 31, 1998.
16*7c478bd9Sstevel@tonic-gate  *
17*7c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
18*7c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
19*7c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
20*7c478bd9Sstevel@tonic-gate  * Rights Reserved.
21*7c478bd9Sstevel@tonic-gate  *
22*7c478bd9Sstevel@tonic-gate  * Contributor(s):
23*7c478bd9Sstevel@tonic-gate  */
24*7c478bd9Sstevel@tonic-gate /*
25*7c478bd9Sstevel@tonic-gate  *  Copyright (c) 1990 Regents of the University of Michigan.
26*7c478bd9Sstevel@tonic-gate  *  All rights reserved.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  *  getvalues.c
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #if 0
33*7c478bd9Sstevel@tonic-gate #ifndef lint
34*7c478bd9Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
35*7c478bd9Sstevel@tonic-gate #endif
36*7c478bd9Sstevel@tonic-gate #endif
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include "ldap-int.h"
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate static void **
42*7c478bd9Sstevel@tonic-gate internal_ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target,
43*7c478bd9Sstevel@tonic-gate 	int lencall )
44*7c478bd9Sstevel@tonic-gate {
45*7c478bd9Sstevel@tonic-gate 	struct berelement	ber;
46*7c478bd9Sstevel@tonic-gate 	char		        *attr;
47*7c478bd9Sstevel@tonic-gate 	int			        rc;
48*7c478bd9Sstevel@tonic-gate 	void			    **vals;
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
53*7c478bd9Sstevel@tonic-gate 		return( NULL );	/* punt */
54*7c478bd9Sstevel@tonic-gate 	}
55*7c478bd9Sstevel@tonic-gate 	if ( target == NULL ||
56*7c478bd9Sstevel@tonic-gate 	    !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
57*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
58*7c478bd9Sstevel@tonic-gate 		return( NULL );
59*7c478bd9Sstevel@tonic-gate 	}
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	ber = *entry->lm_ber;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate 	/* skip sequence, dn, sequence of, and snag the first attr */
64*7c478bd9Sstevel@tonic-gate 	if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
65*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
66*7c478bd9Sstevel@tonic-gate 		return( NULL );
67*7c478bd9Sstevel@tonic-gate 	}
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	rc = strcasecmp( (char *)target, attr );
70*7c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE( attr );
71*7c478bd9Sstevel@tonic-gate 	if ( rc != 0 ) {
72*7c478bd9Sstevel@tonic-gate 		while ( 1 ) {
73*7c478bd9Sstevel@tonic-gate 			if ( ber_scanf( &ber, "x}{a", &attr ) == LBER_ERROR ) {
74*7c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR,
75*7c478bd9Sstevel@tonic-gate 				    NULL, NULL );
76*7c478bd9Sstevel@tonic-gate 				return( NULL );
77*7c478bd9Sstevel@tonic-gate 			}
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 			rc = strcasecmp( (char *)target, attr );
80*7c478bd9Sstevel@tonic-gate 			if ( rc == 0 ) {
81*7c478bd9Sstevel@tonic-gate 				NSLDAPI_FREE( attr );
82*7c478bd9Sstevel@tonic-gate 				break;
83*7c478bd9Sstevel@tonic-gate 			}
84*7c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( attr );
85*7c478bd9Sstevel@tonic-gate 		}
86*7c478bd9Sstevel@tonic-gate 	}
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	/*
89*7c478bd9Sstevel@tonic-gate 	 * if we get this far, we've found the attribute and are sitting
90*7c478bd9Sstevel@tonic-gate 	 * just before the set of values.
91*7c478bd9Sstevel@tonic-gate 	 */
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	if ( lencall ) {
94*7c478bd9Sstevel@tonic-gate 		rc = ber_scanf( &ber, "[V]", &vals );
95*7c478bd9Sstevel@tonic-gate 	} else {
96*7c478bd9Sstevel@tonic-gate 		rc = ber_scanf( &ber, "[v]", &vals );
97*7c478bd9Sstevel@tonic-gate 	}
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	if ( rc == LBER_ERROR ) {
100*7c478bd9Sstevel@tonic-gate 		rc = LDAP_DECODING_ERROR;
101*7c478bd9Sstevel@tonic-gate 	} else {
102*7c478bd9Sstevel@tonic-gate 		rc = LDAP_SUCCESS;
103*7c478bd9Sstevel@tonic-gate 	}
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	return(( rc == LDAP_SUCCESS ) ? vals : NULL );
108*7c478bd9Sstevel@tonic-gate }
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /* For language-sensitive attribute matching, we are looking for a
112*7c478bd9Sstevel@tonic-gate    language tag that looks like one of the following:
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate    cn
115*7c478bd9Sstevel@tonic-gate    cn;lang-en
116*7c478bd9Sstevel@tonic-gate    cn;lang-en-us
117*7c478bd9Sstevel@tonic-gate    cn;lang-ja
118*7c478bd9Sstevel@tonic-gate    cn;lang-ja-JP-kanji
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate    The base language specification consists of two letters following
121*7c478bd9Sstevel@tonic-gate    "lang-". After that, there may be additional language-specific
122*7c478bd9Sstevel@tonic-gate    narrowings preceded by a "-". In our processing we go from the
123*7c478bd9Sstevel@tonic-gate    specific to the general, preferring a complete subtype match, but
124*7c478bd9Sstevel@tonic-gate    accepting a partial one. For example:
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate    For a request for "cn;lang-en-us", we would return cn;lang-en-us
127*7c478bd9Sstevel@tonic-gate    if present, otherwise cn;lang-en if present, otherwise cn.
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate    Besides the language subtype, there may be other subtypes:
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate    cn;lang-ja;binary         (Unlikely!)
132*7c478bd9Sstevel@tonic-gate    cn;lang-ja;phonetic
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate    If not in the target, they are ignored. If they are in the target,
135*7c478bd9Sstevel@tonic-gate    they must be in the attribute to match.
136*7c478bd9Sstevel@tonic-gate */
137*7c478bd9Sstevel@tonic-gate #define LANG_SUBTYPE_INDEX_NONE      -1
138*7c478bd9Sstevel@tonic-gate #define LANG_SUBTYPE_INDEX_DUPLICATE -2
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate typedef struct {
141*7c478bd9Sstevel@tonic-gate 	int    start;
142*7c478bd9Sstevel@tonic-gate 	int    length;
143*7c478bd9Sstevel@tonic-gate } _SubStringIndex;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate static int
146*7c478bd9Sstevel@tonic-gate parse_subtypes( const char *target, int *baseLenp, char **langp,
147*7c478bd9Sstevel@tonic-gate 				_SubStringIndex **subs, int *nsubtypes )
148*7c478bd9Sstevel@tonic-gate {
149*7c478bd9Sstevel@tonic-gate 	int nSubtypes = 0;
150*7c478bd9Sstevel@tonic-gate 	int ind = 0;
151*7c478bd9Sstevel@tonic-gate 	char *nextToken;
152*7c478bd9Sstevel@tonic-gate  	_SubStringIndex *result = NULL;
153*7c478bd9Sstevel@tonic-gate 	int langIndex;
154*7c478bd9Sstevel@tonic-gate 	int targetLen;
155*7c478bd9Sstevel@tonic-gate 	int subtypeStart;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	langIndex = LANG_SUBTYPE_INDEX_NONE;
158*7c478bd9Sstevel@tonic-gate 	*subs = NULL;
159*7c478bd9Sstevel@tonic-gate 	*langp = NULL;
160*7c478bd9Sstevel@tonic-gate 	*baseLenp = 0;
161*7c478bd9Sstevel@tonic-gate 	*nsubtypes = 0;
162*7c478bd9Sstevel@tonic-gate 	targetLen = strlen( target );
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	/* Parse past base attribute */
165*7c478bd9Sstevel@tonic-gate 	nextToken = strchr( target, ';' );
166*7c478bd9Sstevel@tonic-gate 	if ( NULL != nextToken ) {
167*7c478bd9Sstevel@tonic-gate 		subtypeStart = nextToken - target + 1;
168*7c478bd9Sstevel@tonic-gate 		*baseLenp = subtypeStart - 1;
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 	else {
171*7c478bd9Sstevel@tonic-gate 		subtypeStart = targetLen;
172*7c478bd9Sstevel@tonic-gate 		*baseLenp = subtypeStart;
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate 	ind = subtypeStart;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	/* How many subtypes? */
177*7c478bd9Sstevel@tonic-gate 	nextToken = (char *)target + subtypeStart;
178*7c478bd9Sstevel@tonic-gate 	while ( nextToken && *nextToken ) {
179*7c478bd9Sstevel@tonic-gate 		char *thisToken = nextToken;
180*7c478bd9Sstevel@tonic-gate 		nextToken = strchr( thisToken, ';' );
181*7c478bd9Sstevel@tonic-gate 		if ( NULL != nextToken )
182*7c478bd9Sstevel@tonic-gate 			nextToken++;
183*7c478bd9Sstevel@tonic-gate 		if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
184*7c478bd9Sstevel@tonic-gate 			/* If there was a previous lang tag, this is illegal! */
185*7c478bd9Sstevel@tonic-gate 			if ( langIndex != LANG_SUBTYPE_INDEX_NONE ) {
186*7c478bd9Sstevel@tonic-gate 				langIndex = LANG_SUBTYPE_INDEX_DUPLICATE;
187*7c478bd9Sstevel@tonic-gate 				return langIndex;
188*7c478bd9Sstevel@tonic-gate 			}
189*7c478bd9Sstevel@tonic-gate 			else {
190*7c478bd9Sstevel@tonic-gate 				langIndex = nSubtypes;
191*7c478bd9Sstevel@tonic-gate 			}
192*7c478bd9Sstevel@tonic-gate 		} else {
193*7c478bd9Sstevel@tonic-gate 			nSubtypes++;
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate 	/* No language subtype? */
197*7c478bd9Sstevel@tonic-gate 	if ( langIndex < 0 )
198*7c478bd9Sstevel@tonic-gate 		return langIndex;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/* Allocate array of non-language subtypes */
201*7c478bd9Sstevel@tonic-gate 	if ( nSubtypes > 0 ) {
202*7c478bd9Sstevel@tonic-gate 		result = (_SubStringIndex *)NSLDAPI_MALLOC( sizeof(*result)
203*7c478bd9Sstevel@tonic-gate 		    * nSubtypes );
204*7c478bd9Sstevel@tonic-gate 		if (result == NULL) {
205*7c478bd9Sstevel@tonic-gate 			return LANG_SUBTYPE_INDEX_NONE;	/* Error */
206*7c478bd9Sstevel@tonic-gate 		}
207*7c478bd9Sstevel@tonic-gate 		memset( result, 0, sizeof(*result) * nSubtypes );
208*7c478bd9Sstevel@tonic-gate 	}
209*7c478bd9Sstevel@tonic-gate 	ind = 0;
210*7c478bd9Sstevel@tonic-gate 	nSubtypes = 0;
211*7c478bd9Sstevel@tonic-gate 	ind = subtypeStart;
212*7c478bd9Sstevel@tonic-gate 	nextToken = (char *)target + subtypeStart;
213*7c478bd9Sstevel@tonic-gate 	while ( nextToken && *nextToken ) {
214*7c478bd9Sstevel@tonic-gate 		char *thisToken = nextToken;
215*7c478bd9Sstevel@tonic-gate 		int len;
216*7c478bd9Sstevel@tonic-gate 		nextToken = strchr( thisToken, ';' );
217*7c478bd9Sstevel@tonic-gate 		if ( NULL != nextToken ) {
218*7c478bd9Sstevel@tonic-gate 			len = nextToken - thisToken;
219*7c478bd9Sstevel@tonic-gate 			nextToken++;
220*7c478bd9Sstevel@tonic-gate 		}
221*7c478bd9Sstevel@tonic-gate 		else {
222*7c478bd9Sstevel@tonic-gate 			nextToken = (char *)target + targetLen;
223*7c478bd9Sstevel@tonic-gate 			len = nextToken - thisToken;
224*7c478bd9Sstevel@tonic-gate 		}
225*7c478bd9Sstevel@tonic-gate 		if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
226*7c478bd9Sstevel@tonic-gate 			int i;
227*7c478bd9Sstevel@tonic-gate 			*langp = (char *)NSLDAPI_MALLOC( len + 1 );
228*7c478bd9Sstevel@tonic-gate 			if (*langp == NULL) {
229*7c478bd9Sstevel@tonic-gate 				if (result != NULL)
230*7c478bd9Sstevel@tonic-gate 					NSLDAPI_FREE(result);
231*7c478bd9Sstevel@tonic-gate 				return LANG_SUBTYPE_INDEX_NONE;	/* Error */
232*7c478bd9Sstevel@tonic-gate 			}
233*7c478bd9Sstevel@tonic-gate 			for( i = 0; i < len; i++ )
234*7c478bd9Sstevel@tonic-gate 				(*langp)[i] = toupper( target[ind+i] );
235*7c478bd9Sstevel@tonic-gate 			(*langp)[len] = 0;
236*7c478bd9Sstevel@tonic-gate 		}
237*7c478bd9Sstevel@tonic-gate 		else {
238*7c478bd9Sstevel@tonic-gate 			result[nSubtypes].start = thisToken - target;
239*7c478bd9Sstevel@tonic-gate 			result[nSubtypes].length = len;
240*7c478bd9Sstevel@tonic-gate 			nSubtypes++;
241*7c478bd9Sstevel@tonic-gate 		}
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 	*subs = result;
244*7c478bd9Sstevel@tonic-gate 	*nsubtypes = nSubtypes;
245*7c478bd9Sstevel@tonic-gate 	return langIndex;
246*7c478bd9Sstevel@tonic-gate }
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate static int
250*7c478bd9Sstevel@tonic-gate check_lang_match( const char *target, const char *baseTarget,
251*7c478bd9Sstevel@tonic-gate 				  _SubStringIndex *targetTypes,
252*7c478bd9Sstevel@tonic-gate 				  int ntargetTypes, char *targetLang, char *attr )
253*7c478bd9Sstevel@tonic-gate {
254*7c478bd9Sstevel@tonic-gate 	int langIndex;
255*7c478bd9Sstevel@tonic-gate  	_SubStringIndex *subtypes;
256*7c478bd9Sstevel@tonic-gate 	int baseLen;
257*7c478bd9Sstevel@tonic-gate 	char *lang;
258*7c478bd9Sstevel@tonic-gate 	int nsubtypes;
259*7c478bd9Sstevel@tonic-gate 	int mismatch = 0;
260*7c478bd9Sstevel@tonic-gate 	int match = -1;
261*7c478bd9Sstevel@tonic-gate 	int i;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	/* Get all subtypes in the attribute name */
264*7c478bd9Sstevel@tonic-gate  	langIndex = parse_subtypes( attr, &baseLen, &lang, &subtypes, &nsubtypes );
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	/* Check if there any required non-language subtypes which are
267*7c478bd9Sstevel@tonic-gate 	   not in this attribute */
268*7c478bd9Sstevel@tonic-gate 	for( i = 0; i < ntargetTypes; i++ ) {
269*7c478bd9Sstevel@tonic-gate 		char *t = (char *)target+targetTypes[i].start;
270*7c478bd9Sstevel@tonic-gate 		int tlen = targetTypes[i].length;
271*7c478bd9Sstevel@tonic-gate 		int j;
272*7c478bd9Sstevel@tonic-gate 		for( j = 0; j < nsubtypes; j++ ) {
273*7c478bd9Sstevel@tonic-gate 			char *a = attr + subtypes[j].start;
274*7c478bd9Sstevel@tonic-gate 			int alen = subtypes[j].length;
275*7c478bd9Sstevel@tonic-gate 			if ( (tlen == alen) && !strncasecmp( t, a, tlen ) )
276*7c478bd9Sstevel@tonic-gate 				break;
277*7c478bd9Sstevel@tonic-gate 		}
278*7c478bd9Sstevel@tonic-gate 		if ( j >= nsubtypes ) {
279*7c478bd9Sstevel@tonic-gate 			mismatch = 1;
280*7c478bd9Sstevel@tonic-gate 			break;
281*7c478bd9Sstevel@tonic-gate 		}
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 	if ( mismatch ) {
284*7c478bd9Sstevel@tonic-gate 	    if ( NULL != subtypes )
285*7c478bd9Sstevel@tonic-gate 		    NSLDAPI_FREE( subtypes );
286*7c478bd9Sstevel@tonic-gate 		if ( NULL != lang )
287*7c478bd9Sstevel@tonic-gate 		    NSLDAPI_FREE( lang );
288*7c478bd9Sstevel@tonic-gate 		return -1;
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	/* If there was no language subtype... */
292*7c478bd9Sstevel@tonic-gate 	if ( langIndex < 0 ) {
293*7c478bd9Sstevel@tonic-gate 	    if ( NULL != subtypes )
294*7c478bd9Sstevel@tonic-gate 		    NSLDAPI_FREE( subtypes );
295*7c478bd9Sstevel@tonic-gate 		if ( NULL != lang )
296*7c478bd9Sstevel@tonic-gate 		    NSLDAPI_FREE( lang );
297*7c478bd9Sstevel@tonic-gate 		if ( LANG_SUBTYPE_INDEX_NONE == langIndex )
298*7c478bd9Sstevel@tonic-gate 			return 0;
299*7c478bd9Sstevel@tonic-gate 		else
300*7c478bd9Sstevel@tonic-gate 			return -1;
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	/* Okay, now check the language subtag */
304*7c478bd9Sstevel@tonic-gate 	i = 0;
305*7c478bd9Sstevel@tonic-gate 	while( targetLang[i] && lang[i] &&
306*7c478bd9Sstevel@tonic-gate 			(toupper(targetLang[i]) == toupper(lang[i])) )
307*7c478bd9Sstevel@tonic-gate 		i++;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	/* The total length can't be longer than the requested subtype */
310*7c478bd9Sstevel@tonic-gate 	if ( !lang[i] || (lang[i] == ';') ) {
311*7c478bd9Sstevel@tonic-gate 		/* If the found subtype is shorter than the requested one, the next
312*7c478bd9Sstevel@tonic-gate 		   character in the requested one should be "-" */
313*7c478bd9Sstevel@tonic-gate 		if ( !targetLang[i] || (targetLang[i] == '-') )
314*7c478bd9Sstevel@tonic-gate 			match = i;
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 	return match;
317*7c478bd9Sstevel@tonic-gate }
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate static int check_base_match( const char *target, char *attr )
320*7c478bd9Sstevel@tonic-gate {
321*7c478bd9Sstevel@tonic-gate     int i = 0;
322*7c478bd9Sstevel@tonic-gate 	int rc;
323*7c478bd9Sstevel@tonic-gate 	while( target[i] && attr[i] && (toupper(target[i]) == toupper(attr[i])) )
324*7c478bd9Sstevel@tonic-gate 	    i++;
325*7c478bd9Sstevel@tonic-gate 	rc = ( !target[i] && (!attr[i] || (';' == attr[i])) );
326*7c478bd9Sstevel@tonic-gate 	return rc;
327*7c478bd9Sstevel@tonic-gate }
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate static void **
330*7c478bd9Sstevel@tonic-gate internal_ldap_get_lang_values( LDAP *ld, LDAPMessage *entry,
331*7c478bd9Sstevel@tonic-gate 							const char *target, char **type, int lencall )
332*7c478bd9Sstevel@tonic-gate {
333*7c478bd9Sstevel@tonic-gate 	struct berelement	ber;
334*7c478bd9Sstevel@tonic-gate 	char		        *attr = NULL;
335*7c478bd9Sstevel@tonic-gate 	int			        rc;
336*7c478bd9Sstevel@tonic-gate 	void			    **vals = NULL;
337*7c478bd9Sstevel@tonic-gate 	int                 langIndex;
338*7c478bd9Sstevel@tonic-gate  	_SubStringIndex     *subtypes;
339*7c478bd9Sstevel@tonic-gate 	int                 nsubtypes;
340*7c478bd9Sstevel@tonic-gate 	char                *baseTarget = NULL;
341*7c478bd9Sstevel@tonic-gate 	int                 bestMatch = 0;
342*7c478bd9Sstevel@tonic-gate 	char                *lang = NULL;
343*7c478bd9Sstevel@tonic-gate 	int                 len;
344*7c478bd9Sstevel@tonic-gate 	int					firstAttr = 1;
345*7c478bd9Sstevel@tonic-gate 	char				*bestType = NULL;
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
350*7c478bd9Sstevel@tonic-gate 		return( NULL );
351*7c478bd9Sstevel@tonic-gate 	}
352*7c478bd9Sstevel@tonic-gate 	if ( (target == NULL) ||
353*7c478bd9Sstevel@tonic-gate 	    !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
354*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
355*7c478bd9Sstevel@tonic-gate 		return( NULL );
356*7c478bd9Sstevel@tonic-gate 	}
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	/* A language check was requested, so see if there really is a
359*7c478bd9Sstevel@tonic-gate 	   language subtype in the attribute spec */
360*7c478bd9Sstevel@tonic-gate 	langIndex = parse_subtypes( target, &len, &lang,
361*7c478bd9Sstevel@tonic-gate 							   &subtypes, &nsubtypes );
362*7c478bd9Sstevel@tonic-gate 	if ( langIndex < 0 ) {
363*7c478bd9Sstevel@tonic-gate 		if ( NULL != subtypes ) {
364*7c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( subtypes );
365*7c478bd9Sstevel@tonic-gate 			subtypes = NULL;
366*7c478bd9Sstevel@tonic-gate 		}
367*7c478bd9Sstevel@tonic-gate 		vals = internal_ldap_get_values( ld, entry, target, lencall );
368*7c478bd9Sstevel@tonic-gate 		if ( NULL != type )
369*7c478bd9Sstevel@tonic-gate 			*type = nsldapi_strdup( target );
370*7c478bd9Sstevel@tonic-gate 		return vals;
371*7c478bd9Sstevel@tonic-gate 	} else {
372*7c478bd9Sstevel@tonic-gate 		/* Get just the base attribute name */
373*7c478bd9Sstevel@tonic-gate 		baseTarget = (char *)NSLDAPI_MALLOC( len + 1 );
374*7c478bd9Sstevel@tonic-gate 		if (baseTarget == NULL) {
375*7c478bd9Sstevel@tonic-gate 			return( NULL );
376*7c478bd9Sstevel@tonic-gate 		}
377*7c478bd9Sstevel@tonic-gate 		memcpy( baseTarget, target, len );
378*7c478bd9Sstevel@tonic-gate 		baseTarget[len] = 0;
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	ber = *entry->lm_ber;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	/* Process all attributes in the entry */
384*7c478bd9Sstevel@tonic-gate 	while ( 1 ) {
385*7c478bd9Sstevel@tonic-gate 		int foundMatch = 0;
386*7c478bd9Sstevel@tonic-gate 		if ( NULL != attr )
387*7c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( attr );
388*7c478bd9Sstevel@tonic-gate 		if ( firstAttr ) {
389*7c478bd9Sstevel@tonic-gate 			firstAttr = 0;
390*7c478bd9Sstevel@tonic-gate 			/* skip sequence, dn, sequence of, and snag the first attr */
391*7c478bd9Sstevel@tonic-gate 			if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
392*7c478bd9Sstevel@tonic-gate 				break;
393*7c478bd9Sstevel@tonic-gate 			}
394*7c478bd9Sstevel@tonic-gate 		} else {
395*7c478bd9Sstevel@tonic-gate 			if ( ber_scanf( &ber, "{a", &attr ) == LBER_ERROR ) {
396*7c478bd9Sstevel@tonic-gate 				break;
397*7c478bd9Sstevel@tonic-gate 			}
398*7c478bd9Sstevel@tonic-gate 		}
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 		if ( check_base_match( (const char *)baseTarget, attr ) ) {
401*7c478bd9Sstevel@tonic-gate 			int thisMatch = check_lang_match( target, baseTarget,
402*7c478bd9Sstevel@tonic-gate 											  subtypes, nsubtypes, lang, attr );
403*7c478bd9Sstevel@tonic-gate 			if ( thisMatch > bestMatch ) {
404*7c478bd9Sstevel@tonic-gate 				if ( vals )
405*7c478bd9Sstevel@tonic-gate 					NSLDAPI_FREE( vals );
406*7c478bd9Sstevel@tonic-gate 				foundMatch = 1;
407*7c478bd9Sstevel@tonic-gate 				bestMatch = thisMatch;
408*7c478bd9Sstevel@tonic-gate 				if ( NULL != bestType )
409*7c478bd9Sstevel@tonic-gate 					NSLDAPI_FREE( bestType );
410*7c478bd9Sstevel@tonic-gate 				bestType = attr;
411*7c478bd9Sstevel@tonic-gate 				attr = NULL;
412*7c478bd9Sstevel@tonic-gate 			}
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 		if ( foundMatch ) {
415*7c478bd9Sstevel@tonic-gate 			if ( lencall ) {
416*7c478bd9Sstevel@tonic-gate 				rc = ber_scanf( &ber, "[V]}", &vals );
417*7c478bd9Sstevel@tonic-gate 			} else {
418*7c478bd9Sstevel@tonic-gate 				rc = ber_scanf( &ber, "[v]}", &vals );
419*7c478bd9Sstevel@tonic-gate 			}
420*7c478bd9Sstevel@tonic-gate 		} else {
421*7c478bd9Sstevel@tonic-gate 			ber_scanf( &ber, "x}" );
422*7c478bd9Sstevel@tonic-gate 		}
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE( lang );
426*7c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE( baseTarget );
427*7c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE( subtypes );
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	if ( NULL != type )
430*7c478bd9Sstevel@tonic-gate 		*type = bestType;
431*7c478bd9Sstevel@tonic-gate 	else if ( NULL != bestType )
432*7c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( bestType );
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	if ( NULL == vals ) {
435*7c478bd9Sstevel@tonic-gate 		rc = LDAP_DECODING_ERROR;
436*7c478bd9Sstevel@tonic-gate 	} else {
437*7c478bd9Sstevel@tonic-gate 		rc = LDAP_SUCCESS;
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	return( vals );
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate char **
447*7c478bd9Sstevel@tonic-gate LDAP_CALL
448*7c478bd9Sstevel@tonic-gate ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target )
449*7c478bd9Sstevel@tonic-gate {
450*7c478bd9Sstevel@tonic-gate 	return( (char **) internal_ldap_get_values( ld, entry, target, 0 ) );
451*7c478bd9Sstevel@tonic-gate }
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate struct berval **
454*7c478bd9Sstevel@tonic-gate LDAP_CALL
455*7c478bd9Sstevel@tonic-gate ldap_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target )
456*7c478bd9Sstevel@tonic-gate {
457*7c478bd9Sstevel@tonic-gate 	return( (struct berval **) internal_ldap_get_values( ld, entry, target,
458*7c478bd9Sstevel@tonic-gate 	    1 ) );
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate char **
462*7c478bd9Sstevel@tonic-gate LDAP_CALL
463*7c478bd9Sstevel@tonic-gate ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, const char *target,
464*7c478bd9Sstevel@tonic-gate 						char **type )
465*7c478bd9Sstevel@tonic-gate {
466*7c478bd9Sstevel@tonic-gate 	return( (char **) internal_ldap_get_lang_values( ld, entry,
467*7c478bd9Sstevel@tonic-gate 											target, type, 0 ) );
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate struct berval **
471*7c478bd9Sstevel@tonic-gate LDAP_CALL
472*7c478bd9Sstevel@tonic-gate ldap_get_lang_values_len( LDAP *ld, LDAPMessage *entry, const char *target,
473*7c478bd9Sstevel@tonic-gate 						char **type )
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	return( (struct berval **) internal_ldap_get_lang_values( ld, entry,
476*7c478bd9Sstevel@tonic-gate 										   target, type, 1 ) );
477*7c478bd9Sstevel@tonic-gate }
478*7c478bd9Sstevel@tonic-gate 
479