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