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