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