1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * The contents of this file are subject to the Netscape Public
8  * License Version 1.1 (the "License"); you may not use this file
9  * except in compliance with the License. You may obtain a copy of
10  * the License at http://www.mozilla.org/NPL/
11  *
12  * Software distributed under the License is distributed on an "AS
13  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14  * implied. See the License for the specific language governing
15  * rights and limitations under the License.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
20  * The Initial Developer of the Original Code is Netscape
21  * Communications Corporation. Portions created by Netscape are
22  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
23  * Rights Reserved.
24  *
25  * Contributor(s):
26  */
27 /*
28  * Copyright (c) 1993, 1994 Regents of the University of Michigan.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms are permitted
32  * provided that this notice is preserved and that due credit is given
33  * to the University of Michigan at Ann Arbor. The name of the University
34  * may not be used to endorse or promote products derived from this
35  * software without specific prior written permission. This software
36  * is provided ``as is'' without express or implied warranty.
37  *
38  */
39 /*
40  * searchpref.c:  search preferences library routines for LDAP clients
41  */
42 
43 #include "ldap-int.h"
44 #include "srchpref.h"
45 
46 static void free_searchobj( struct ldap_searchobj *so );
47 static int read_next_searchobj( char **bufp, long *blenp,
48 	struct ldap_searchobj **sop, int soversion );
49 
50 
51 static char		*sobjoptions[] = {
52     "internal",
53     NULL
54 };
55 
56 
57 static unsigned long	sobjoptvals[] = {
58     LDAP_SEARCHOBJ_OPT_INTERNAL,
59 };
60 
61 
62 int
63 LDAP_CALL
ldap_init_searchprefs(char * file,struct ldap_searchobj ** solistp)64 ldap_init_searchprefs( char *file, struct ldap_searchobj **solistp )
65 {
66     FILE	*fp;
67     char	*buf;
68     long	rlen, len;
69     int		rc, eof;
70 
71     if (( fp = fopen( file, "rF" )) == NULL ) {
72 	return( LDAP_SEARCHPREF_ERR_FILE );
73     }
74 
75     if ( fseek( fp, 0L, SEEK_END ) != 0 ) {	/* move to end to get len */
76 	fclose( fp );
77 	return( LDAP_SEARCHPREF_ERR_FILE );
78     }
79 
80     len = ftell( fp );
81 
82     if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {	/* back to start of file */
83 	fclose( fp );
84 	return( LDAP_SEARCHPREF_ERR_FILE );
85     }
86 
87     if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
88 	fclose( fp );
89 	return( LDAP_SEARCHPREF_ERR_MEM );
90     }
91 
92     rlen = fread( buf, 1, (size_t)len, fp );
93     eof = feof( fp );
94     fclose( fp );
95 
96     if ( rlen != len && !eof ) {	/* error:  didn't get the whole file */
97 	NSLDAPI_FREE( buf );
98 	return( LDAP_SEARCHPREF_ERR_FILE );
99     }
100 
101     rc = ldap_init_searchprefs_buf( buf, rlen, solistp );
102     NSLDAPI_FREE( buf );
103 
104     return( rc );
105 }
106 
107 
108 int
109 LDAP_CALL
ldap_init_searchprefs_buf(char * buf,long buflen,struct ldap_searchobj ** solistp)110 ldap_init_searchprefs_buf( char *buf, long buflen,
111 	struct ldap_searchobj **solistp )
112 {
113     int				rc = 0, version;
114     char			**toks;
115     struct ldap_searchobj	*prevso, *so;
116 
117     *solistp = prevso = NULLSEARCHOBJ;
118 
119     if ( ldap_next_line_tokens( &buf, &buflen, &toks ) != 2 ||
120 	    strcasecmp( toks[ 0 ], "version" ) != 0 ) {
121 	ldap_free_strarray( toks );
122 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
123     }
124     version = atoi( toks[ 1 ] );
125     ldap_free_strarray( toks );
126     if ( version != LDAP_SEARCHPREF_VERSION &&
127 	    version != LDAP_SEARCHPREF_VERSION_ZERO ) {
128 	return( LDAP_SEARCHPREF_ERR_VERSION );
129     }
130 
131     while ( buflen > 0 && ( rc = read_next_searchobj( &buf, &buflen, &so,
132 	    version )) == 0 && so != NULLSEARCHOBJ ) {
133 	if ( prevso == NULLSEARCHOBJ ) {
134 	    *solistp = so;
135 	} else {
136 	    prevso->so_next = so;
137 	}
138 	prevso = so;
139     }
140 
141     if ( rc != 0 ) {
142 	ldap_free_searchprefs( *solistp );
143     }
144 
145     return( rc );
146 }
147 
148 
149 
150 void
151 LDAP_CALL
ldap_free_searchprefs(struct ldap_searchobj * solist)152 ldap_free_searchprefs( struct ldap_searchobj *solist )
153 {
154     struct ldap_searchobj	*so, *nextso;
155 
156     if ( solist != NULL ) {
157 	for ( so = solist; so != NULL; so = nextso ) {
158 	    nextso = so->so_next;
159 	    free_searchobj( so );
160 	}
161     }
162     /* XXX XXX need to do some work here */
163 }
164 
165 
166 static void
free_searchobj(struct ldap_searchobj * so)167 free_searchobj( struct ldap_searchobj *so )
168 {
169     if ( so != NULL ) {
170 	if ( so->so_objtypeprompt != NULL ) {
171 	    NSLDAPI_FREE(  so->so_objtypeprompt );
172 	}
173 	if ( so->so_prompt != NULL ) {
174 	    NSLDAPI_FREE(  so->so_prompt );
175 	}
176 	if ( so->so_filterprefix != NULL ) {
177 	    NSLDAPI_FREE(  so->so_filterprefix );
178 	}
179 	if ( so->so_filtertag != NULL ) {
180 	    NSLDAPI_FREE(  so->so_filtertag );
181 	}
182 	if ( so->so_defaultselectattr != NULL ) {
183 	    NSLDAPI_FREE(  so->so_defaultselectattr );
184 	}
185 	if ( so->so_defaultselecttext != NULL ) {
186 	    NSLDAPI_FREE(  so->so_defaultselecttext );
187 	}
188 	if ( so->so_salist != NULL ) {
189 	    struct ldap_searchattr *sa, *nextsa;
190 	    for ( sa = so->so_salist; sa != NULL; sa = nextsa ) {
191 		nextsa = sa->sa_next;
192 		if ( sa->sa_attrlabel != NULL ) {
193 		    NSLDAPI_FREE( sa->sa_attrlabel );
194 		}
195 		if ( sa->sa_attr != NULL ) {
196 		    NSLDAPI_FREE( sa->sa_attr );
197 		}
198 		if ( sa->sa_selectattr != NULL ) {
199 		    NSLDAPI_FREE( sa->sa_selectattr );
200 		}
201 		if ( sa->sa_selecttext != NULL ) {
202 		    NSLDAPI_FREE( sa->sa_selecttext );
203 		}
204 		NSLDAPI_FREE( sa );
205 	    }
206 	}
207 	if ( so->so_smlist != NULL ) {
208 	    struct ldap_searchmatch *sm, *nextsm;
209 	    for ( sm = so->so_smlist; sm != NULL; sm = nextsm ) {
210 		nextsm = sm->sm_next;
211 		if ( sm->sm_matchprompt != NULL ) {
212 		    NSLDAPI_FREE( sm->sm_matchprompt );
213 		}
214 		if ( sm->sm_filter != NULL ) {
215 		    NSLDAPI_FREE( sm->sm_filter );
216 		}
217 		NSLDAPI_FREE( sm );
218 	    }
219 	}
220 	NSLDAPI_FREE( so );
221     }
222 }
223 
224 
225 
226 struct ldap_searchobj *
227 LDAP_CALL
ldap_first_searchobj(struct ldap_searchobj * solist)228 ldap_first_searchobj( struct ldap_searchobj *solist )
229 {
230     return( solist );
231 }
232 
233 
234 struct ldap_searchobj *
235 LDAP_CALL
ldap_next_searchobj(struct ldap_searchobj * solist,struct ldap_searchobj * so)236 ldap_next_searchobj( struct ldap_searchobj *solist, struct ldap_searchobj *so )
237 {
238     return( so == NULLSEARCHOBJ ? so : so->so_next );
239 }
240 
241 
242 
243 static int
read_next_searchobj(char ** bufp,long * blenp,struct ldap_searchobj ** sop,int soversion)244 read_next_searchobj( char **bufp, long *blenp, struct ldap_searchobj **sop,
245 	int soversion )
246 {
247     int				i, j, tokcnt;
248     char			**toks;
249     struct ldap_searchobj	*so;
250     struct ldap_searchattr	**sa;
251     struct ldap_searchmatch	**sm;
252 
253     *sop = NULL;
254 
255     /*
256      * Object type prompt comes first
257      */
258     if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
259 	ldap_free_strarray( toks );
260 	return( tokcnt == 0 ? 0 : LDAP_SEARCHPREF_ERR_SYNTAX );
261     }
262 
263     if (( so = (struct ldap_searchobj *)NSLDAPI_CALLOC( 1,
264 	    sizeof( struct ldap_searchobj ))) == NULL ) {
265 	ldap_free_strarray( toks );
266 	return(  LDAP_SEARCHPREF_ERR_MEM );
267     }
268     so->so_objtypeprompt = toks[ 0 ];
269     NSLDAPI_FREE( (char *)toks );
270 
271     /*
272      * if this is post-version zero, options come next
273      */
274     if ( soversion > LDAP_SEARCHPREF_VERSION_ZERO ) {
275 	if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) < 1 ) {
276 	    ldap_free_strarray( toks );
277 	    ldap_free_searchprefs( so );
278 	    return( LDAP_SEARCHPREF_ERR_SYNTAX );
279 	}
280 	for ( i = 0; toks[ i ] != NULL; ++i ) {
281 	    for ( j = 0; sobjoptions[ j ] != NULL; ++j ) {
282 		if ( strcasecmp( toks[ i ], sobjoptions[ j ] ) == 0 ) {
283 		    so->so_options |= sobjoptvals[ j ];
284 		}
285 	    }
286 	}
287 	ldap_free_strarray( toks );
288     }
289 
290     /*
291      * "Fewer choices" prompt is next
292      */
293     if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
294 	ldap_free_strarray( toks );
295 	ldap_free_searchprefs( so );
296 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
297     }
298     so->so_prompt = toks[ 0 ];
299     NSLDAPI_FREE( (char *)toks );
300 
301     /*
302      * Filter prefix for "More Choices" searching is next
303      */
304     if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
305 	ldap_free_strarray( toks );
306 	ldap_free_searchprefs( so );
307 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
308     }
309     so->so_filterprefix = toks[ 0 ];
310     NSLDAPI_FREE( (char *)toks );
311 
312     /*
313      * "Fewer Choices" filter tag comes next
314      */
315     if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
316 	ldap_free_strarray( toks );
317 	ldap_free_searchprefs( so );
318 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
319     }
320     so->so_filtertag = toks[ 0 ];
321     NSLDAPI_FREE( (char *)toks );
322 
323     /*
324      * Selection (disambiguation) attribute comes next
325      */
326     if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
327 	ldap_free_strarray( toks );
328 	ldap_free_searchprefs( so );
329 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
330     }
331     so->so_defaultselectattr = toks[ 0 ];
332     NSLDAPI_FREE( (char *)toks );
333 
334     /*
335      * Label for selection (disambiguation) attribute
336      */
337     if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
338 	ldap_free_strarray( toks );
339 	ldap_free_searchprefs( so );
340 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
341     }
342     so->so_defaultselecttext = toks[ 0 ];
343     NSLDAPI_FREE( (char *)toks );
344 
345     /*
346      * Search scope is next
347      */
348     if (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
349 	ldap_free_strarray( toks );
350 	ldap_free_searchprefs( so );
351 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
352     }
353     if ( !strcasecmp(toks[ 0 ], "subtree" )) {
354 	so->so_defaultscope = LDAP_SCOPE_SUBTREE;
355     } else if ( !strcasecmp(toks[ 0 ], "onelevel" )) {
356 	so->so_defaultscope = LDAP_SCOPE_ONELEVEL;
357     } else if ( !strcasecmp(toks[ 0 ], "base" )) {
358 	so->so_defaultscope = LDAP_SCOPE_BASE;
359     } else {
360 	ldap_free_searchprefs( so );
361 	return( LDAP_SEARCHPREF_ERR_SYNTAX );
362     }
363     ldap_free_strarray( toks );
364 
365 
366     /*
367      * "More Choices" search option list comes next
368      */
369     sa = &( so->so_salist );
370     while (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
371 	if ( tokcnt < 5 ) {
372 	    ldap_free_strarray( toks );
373 	    ldap_free_searchprefs( so );
374 	    return( LDAP_SEARCHPREF_ERR_SYNTAX );
375 	}
376 	if (( *sa = ( struct ldap_searchattr * )NSLDAPI_CALLOC( 1,
377 		sizeof( struct ldap_searchattr ))) == NULL ) {
378 	    ldap_free_strarray( toks );
379 	    ldap_free_searchprefs( so );
380 	    return(  LDAP_SEARCHPREF_ERR_MEM );
381 	}
382 	( *sa )->sa_attrlabel = toks[ 0 ];
383 	( *sa )->sa_attr = toks[ 1 ];
384 	( *sa )->sa_selectattr = toks[ 3 ];
385 	( *sa )->sa_selecttext = toks[ 4 ];
386 	/* Deal with bitmap */
387 	( *sa )->sa_matchtypebitmap = 0;
388 	for ( i = strlen( toks[ 2 ] ) - 1, j = 0; i >= 0; i--, j++ ) {
389 	    if ( toks[ 2 ][ i ] == '1' ) {
390 		( *sa )->sa_matchtypebitmap |= (1 << j);
391 	    }
392 	}
393 	NSLDAPI_FREE( toks[ 2 ] );
394 	NSLDAPI_FREE( ( char * ) toks );
395 	sa = &(( *sa )->sa_next);
396     }
397     *sa = NULL;
398 
399     /*
400      * Match types are last
401      */
402     sm = &( so->so_smlist );
403     while (( tokcnt = ldap_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
404 	if ( tokcnt < 2 ) {
405 	    ldap_free_strarray( toks );
406 	    ldap_free_searchprefs( so );
407 	    return( LDAP_SEARCHPREF_ERR_SYNTAX );
408 	}
409 	if (( *sm = ( struct ldap_searchmatch * )NSLDAPI_CALLOC( 1,
410 		sizeof( struct ldap_searchmatch ))) == NULL ) {
411 	    ldap_free_strarray( toks );
412 	    ldap_free_searchprefs( so );
413 	    return(  LDAP_SEARCHPREF_ERR_MEM );
414 	}
415 	( *sm )->sm_matchprompt = toks[ 0 ];
416 	( *sm )->sm_filter = toks[ 1 ];
417 	NSLDAPI_FREE( ( char * ) toks );
418 	sm = &(( *sm )->sm_next );
419     }
420     *sm = NULL;
421 
422     *sop = so;
423     return( 0 );
424 }
425