xref: /onnv-gate/usr/src/lib/libldap4/common/disptmpl.c (revision 3857:21b9b714e4ab)
1 /*
2  * Portions Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 /*
8  * Copyright (c) 1993, 1994 Regents of the University of Michigan.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms are permitted
12  * provided that this notice is preserved and that due credit is given
13  * to the University of Michigan at Ann Arbor. The name of the University
14  * may not be used to endorse or promote products derived from this
15  * software without specific prior written permission. This software
16  * is provided ``as is'' without express or implied warranty.
17  *
18  * disptmpl.c:  display template library routines for LDAP clients
19  * 7 March 1994 by Mark C Smith
20  */
21 
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #ifdef MACOS
27 #include "macos.h"
28 #else /* MACOS */
29 #ifdef DOS
30 #include <malloc.h>
31 #include "msdos.h"
32 #else /* DOS */
33 #include <sys/types.h>
34 #include <sys/file.h>
35 #ifndef VMS
36 #include <unistd.h>
37 #endif /* VMS */
38 #endif /* DOS */
39 #endif /* MACOS */
40 
41 #include "lber.h"
42 #include "ldap.h"
43 #include "ldap-private.h"
44 #include "ldap-int.h"
45 
46 #ifndef NEEDPROTOS
47 static void free_disptmpl();
48 static int read_next_tmpl();
49 int next_line_tokens();
50 #else /* !NEEDPROTOS */
51 static void free_disptmpl( struct ldap_disptmpl *tmpl );
52 static int read_next_tmpl( char **bufp, ssize_t *blenp,
53 	struct ldap_disptmpl **tmplp, int dtversion );
54 int next_line_tokens( char **bufp, ssize_t *blenp, char ***toksp );
55 #endif /* !NEEDPROTOS */
56 
57 static char		*tmploptions[] = {
58     "addable", "modrdn",
59     "altview",
60     NULL
61 };
62 
63 
64 static unsigned int	tmploptvals[] = {
65     LDAP_DTMPL_OPT_ADDABLE, LDAP_DTMPL_OPT_ALLOWMODRDN,
66     LDAP_DTMPL_OPT_ALTVIEW,
67 };
68 
69 
70 static char		*itemtypes[] = {
71     "cis",			"mls",			"dn",
72     "bool",			"jpeg",			"jpegbtn",
73     "fax",			"faxbtn",		"audiobtn",
74     "time",			"date",			"url",
75     "searchact",		"linkact",		"adddnact",
76     "addact",			"verifyact",		"mail",
77 #ifdef SUN
78 	"protected",
79 #endif
80     NULL
81 };
82 
83 static unsigned int	itemsynids[] = {
84     LDAP_SYN_CASEIGNORESTR,	LDAP_SYN_MULTILINESTR,	LDAP_SYN_DN,
85     LDAP_SYN_BOOLEAN,		LDAP_SYN_JPEGIMAGE,	LDAP_SYN_JPEGBUTTON,
86     LDAP_SYN_FAXIMAGE,		LDAP_SYN_FAXBUTTON,	LDAP_SYN_AUDIOBUTTON,
87     LDAP_SYN_TIME,		LDAP_SYN_DATE,		LDAP_SYN_LABELEDURL,
88     LDAP_SYN_SEARCHACTION,	LDAP_SYN_LINKACTION,	LDAP_SYN_ADDDNACTION,
89     LDAP_SYN_ADDDNACTION,	LDAP_SYN_VERIFYDNACTION,LDAP_SYN_RFC822ADDR,
90 #ifdef SUN
91 	LDAP_SYN_PROTECTED,
92 #endif
93 };
94 
95 
96 static char		*itemoptions[] = {
97     "ro",		       		"sort",
98     "1val",				"hide",
99     "required",				"hideiffalse",
100     NULL
101 };
102 
103 
104 static unsigned int	itemoptvals[] = {
105     LDAP_DITEM_OPT_READONLY,		LDAP_DITEM_OPT_SORTVALUES,
106     LDAP_DITEM_OPT_SINGLEVALUED,	LDAP_DITEM_OPT_HIDEIFEMPTY,
107     LDAP_DITEM_OPT_VALUEREQUIRED,	LDAP_DITEM_OPT_HIDEIFFALSE,
108 };
109 
110 
111 #define ADDEF_CONSTANT	"constant"
112 #define ADDEF_ADDERSDN	"addersdn"
113 
114 #ifdef SUN
115 /* LP@Sun : right_trim */
right_trim(char * aStr)116 static void right_trim(char *aStr)
117 {
118 	char * theEnd = aStr + strlen(aStr);
119 	while ((theEnd >  aStr) && isspace(*(theEnd - 1)))
120 		theEnd--;
121 	theEnd;
122 	*theEnd= '\0';
123 }
124 #endif
125 
126 int
ldap_init_templates(char * file,struct ldap_disptmpl ** tmpllistp)127 ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp )
128 {
129     FILE	*fp;
130     char	*buf;
131     ssize_t	rlen, len;
132     int		rc, eof;
133 
134     *tmpllistp = NULLDISPTMPL;
135 
136     if (( fp = fopen( file, "r" )) == NULL ) {
137 	return( LDAP_TMPL_ERR_FILE );
138     }
139 
140     if ( fseek( fp, 0L, SEEK_END ) != 0 ) {	/* move to end to get len */
141 	fclose( fp );
142 	return( LDAP_TMPL_ERR_FILE );
143     }
144 
145     len = ftell( fp );
146 
147     if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {	/* back to start of file */
148 	fclose( fp );
149 	return( LDAP_TMPL_ERR_FILE );
150     }
151 
152     if (( buf = malloc( len )) == NULL ) {
153 	fclose( fp );
154 	return( LDAP_TMPL_ERR_MEM );
155     }
156 
157     rlen = fread( buf, (size_t) 1, len, fp );
158     eof = feof( fp );
159     fclose( fp );
160 
161     if ( rlen != len && !eof ) {	/* error:  didn't get the whole file */
162 	free( buf );
163 	return( LDAP_TMPL_ERR_FILE );
164     }
165 
166     rc = ldap_init_templates_buf( buf, rlen, tmpllistp );
167     free( buf );
168 
169     return( rc );
170 }
171 
172 
173 int
ldap_init_templates_buf(char * buf,ssize_t buflen,struct ldap_disptmpl ** tmpllistp)174 ldap_init_templates_buf( char *buf, ssize_t buflen,
175 	struct ldap_disptmpl **tmpllistp )
176 {
177     int				rc, version;
178     char			**toks;
179     struct ldap_disptmpl	*prevtmpl, *tmpl;
180 
181     *tmpllistp = prevtmpl = NULLDISPTMPL;
182 
183     if ( next_line_tokens( &buf, &buflen, &toks ) != 2 ||
184 	    strcasecmp( toks[ 0 ], "version" ) != 0 ) {
185 	free_strarray( toks );
186 	return( LDAP_TMPL_ERR_SYNTAX );
187     }
188     version = atoi( toks[ 1 ] );
189     free_strarray( toks );
190     if ( version != LDAP_TEMPLATE_VERSION ) {
191 	return( LDAP_TMPL_ERR_VERSION );
192     }
193 
194     while ( buflen > 0 && ( rc = read_next_tmpl( &buf, &buflen, &tmpl,
195 	    version )) == 0 && tmpl != NULLDISPTMPL ) {
196 	if ( prevtmpl == NULLDISPTMPL ) {
197 	    *tmpllistp = tmpl;
198 	} else {
199 	    prevtmpl->dt_next = tmpl;
200 	}
201 	prevtmpl = tmpl;
202     }
203 
204     if ( rc != 0 ) {
205 	ldap_free_templates( *tmpllistp );
206     }
207 
208     return( rc );
209 }
210 
211 
212 
213 void
ldap_free_templates(struct ldap_disptmpl * tmpllist)214 ldap_free_templates( struct ldap_disptmpl *tmpllist )
215 {
216     struct ldap_disptmpl	*tp, *nexttp;
217 
218     if ( tmpllist != NULL ) {
219 	for ( tp = tmpllist; tp != NULL; tp = nexttp ) {
220 	    nexttp = tp->dt_next;
221 	    free_disptmpl( tp );
222 	}
223     }
224 }
225 
226 
227 static void
free_disptmpl(struct ldap_disptmpl * tmpl)228 free_disptmpl( struct ldap_disptmpl *tmpl )
229 {
230     if ( tmpl != NULL ) {
231 	if ( tmpl->dt_name != NULL ) {
232 	    free(  tmpl->dt_name );
233 	}
234 
235 	if ( tmpl->dt_pluralname != NULL ) {
236 	    free( tmpl->dt_pluralname );
237 	}
238 
239 	if ( tmpl->dt_iconname != NULL ) {
240 	    free( tmpl->dt_iconname );
241 	}
242 
243 	if ( tmpl->dt_authattrname != NULL ) {
244 	    free( tmpl->dt_authattrname );
245 	}
246 
247 	if ( tmpl->dt_defrdnattrname != NULL ) {
248 	    free( tmpl->dt_defrdnattrname );
249 	}
250 
251 	if ( tmpl->dt_defaddlocation != NULL ) {
252 	    free( tmpl->dt_defaddlocation );
253 	}
254 
255 	if (  tmpl->dt_oclist != NULL ) {
256 	    struct ldap_oclist	*ocp, *nextocp;
257 
258 	    for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = nextocp ) {
259 		nextocp = ocp->oc_next;
260 		free_strarray( ocp->oc_objclasses );
261 		free( ocp );
262 	    }
263 	}
264 
265 	if (  tmpl->dt_adddeflist != NULL ) {
266 	    struct ldap_adddeflist	*adp, *nextadp;
267 
268 	    for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = nextadp ) {
269 		nextadp = adp->ad_next;
270 		if( adp->ad_attrname != NULL ) {
271 		    free( adp->ad_attrname );
272 		}
273 		if( adp->ad_value != NULL ) {
274 		    free( adp->ad_value );
275 		}
276 		free( adp );
277 	    }
278 	}
279 
280 	if (  tmpl->dt_items != NULL ) {
281 	    struct ldap_tmplitem	*rowp, *nextrowp, *colp, *nextcolp;
282 
283 	    for ( rowp = tmpl->dt_items; rowp != NULL; rowp = nextrowp ) {
284 		nextrowp = rowp->ti_next_in_col;
285 		for ( colp = rowp; colp != NULL; colp = nextcolp ) {
286 		    nextcolp = colp->ti_next_in_row;
287 		    if ( colp->ti_attrname != NULL ) {
288 			free( colp->ti_attrname );
289 		    }
290 		    if ( colp->ti_label != NULL ) {
291 			free( colp->ti_label );
292 		    }
293 		    if ( colp->ti_args != NULL ) {
294 			free_strarray( colp->ti_args );
295 		    }
296 		    free( colp );
297 		}
298 	    }
299 	}
300 
301 	free( tmpl );
302     }
303 }
304 
305 
306 struct ldap_disptmpl *
ldap_first_disptmpl(struct ldap_disptmpl * tmpllist)307 ldap_first_disptmpl( struct ldap_disptmpl *tmpllist )
308 {
309     return( tmpllist );
310 }
311 
312 
313 struct ldap_disptmpl *
ldap_next_disptmpl(struct ldap_disptmpl * tmpllist,struct ldap_disptmpl * tmpl)314 ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
315 	struct ldap_disptmpl *tmpl )
316 {
317     return( tmpl == NULLDISPTMPL ? tmpl : tmpl->dt_next );
318 }
319 
320 
321 struct ldap_disptmpl *
ldap_name2template(char * name,struct ldap_disptmpl * tmpllist)322 ldap_name2template( char *name, struct ldap_disptmpl *tmpllist )
323 {
324     struct ldap_disptmpl	*dtp;
325 
326     for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
327 	    dtp = ldap_next_disptmpl( tmpllist, dtp )) {
328 	if ( strcasecmp( name, dtp->dt_name ) == 0 ) {
329 	    return( dtp );
330 	}
331     }
332 
333     return( NULLDISPTMPL );
334 }
335 
336 
337 struct ldap_disptmpl *
ldap_oc2template(char ** oclist,struct ldap_disptmpl * tmpllist)338 ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist )
339 {
340     struct ldap_disptmpl	*dtp;
341     struct ldap_oclist		*oclp;
342     int				i, j, needcnt, matchcnt;
343 
344     if ( tmpllist == NULL || oclist == NULL || oclist[ 0 ] == NULL ) {
345 	return( NULLDISPTMPL );
346     }
347 
348     for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
349 		dtp = ldap_next_disptmpl( tmpllist, dtp )) {
350 	for ( oclp = dtp->dt_oclist; oclp != NULLOCLIST;
351 		oclp = oclp->oc_next ) {
352 	    needcnt = matchcnt = 0;
353 	    for ( i = 0; oclp->oc_objclasses[ i ] != NULL; ++i ) {
354 		for ( j = 0; oclist[ j ] != NULL; ++j ) {
355 #ifdef SUN
356 			/* LP@Sun : remove ending space from objectclass */
357 			right_trim(oclist[j]);
358 #endif
359 		    if ( strcasecmp( oclist[ j ], oclp->oc_objclasses[ i ] )
360 			    == 0 ) {
361 			++matchcnt;
362 		    }
363 		}
364 		++needcnt;
365 	    }
366 
367 	    if ( matchcnt == needcnt ) {
368 		return( dtp );
369 	    }
370 	}
371     }
372 
373     return( NULLDISPTMPL );
374 }
375 
376 
377 struct ldap_tmplitem *
ldap_first_tmplrow(struct ldap_disptmpl * tmpl)378 ldap_first_tmplrow( struct ldap_disptmpl *tmpl )
379 {
380     return( tmpl->dt_items );
381 }
382 
383 
384 struct ldap_tmplitem *
ldap_next_tmplrow(struct ldap_disptmpl * tmpl,struct ldap_tmplitem * row)385 ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
386 {
387     return( row == NULLTMPLITEM ? row : row->ti_next_in_col );
388 }
389 
390 
391 struct ldap_tmplitem *
ldap_first_tmplcol(struct ldap_disptmpl * tmpl,struct ldap_tmplitem * row)392 ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
393 {
394     return( row );
395 }
396 
397 
398 struct ldap_tmplitem *
ldap_next_tmplcol(struct ldap_disptmpl * tmpl,struct ldap_tmplitem * row,struct ldap_tmplitem * col)399 ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
400 	struct ldap_tmplitem *col )
401 {
402     return( col == NULLTMPLITEM ? col : col->ti_next_in_row );
403 }
404 
405 
406 char **
ldap_tmplattrs(struct ldap_disptmpl * tmpl,char ** includeattrs,int exclude,unsigned int syntaxmask)407 ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs,
408 	int exclude, unsigned int syntaxmask )
409 {
410 /*
411  * this routine should filter out duplicate attributes...
412  */
413     struct ldap_tmplitem	*tirowp, *ticolp;
414     int			i, attrcnt, memerr;
415     char		**attrs;
416 
417     attrcnt = 0;
418     memerr = 0;
419 
420     if (( attrs = (char **)malloc( sizeof( char * ))) == NULL ) {
421 	return( NULL );
422     }
423 
424     if ( includeattrs != NULL ) {
425 	for ( i = 0; !memerr && includeattrs[ i ] != NULL; ++i ) {
426 	    if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
427 		    sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
428 		    strdup( includeattrs[ i ] )) == NULL ) {
429 		memerr = 1;
430 	    } else {
431 		attrs[ attrcnt ] = NULL;
432 	    }
433 	}
434     }
435 
436     for ( tirowp = ldap_first_tmplrow( tmpl );
437 	    !memerr && tirowp != NULLTMPLITEM;
438 	    tirowp = ldap_next_tmplrow( tmpl, tirowp )) {
439 	for ( ticolp = ldap_first_tmplcol( tmpl, tirowp );
440 		ticolp != NULLTMPLITEM;
441 		ticolp = ldap_next_tmplcol( tmpl, tirowp, ticolp )) {
442 
443 	    if ( syntaxmask != 0 ) {
444 		if (( exclude &&
445 			( syntaxmask & ticolp->ti_syntaxid ) != 0 ) ||
446 			( !exclude &&
447 			( syntaxmask & ticolp->ti_syntaxid ) == 0 )) {
448 		    continue;
449 		}
450 	    }
451 
452 	    if ( ticolp->ti_attrname != NULL ) {
453 		if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
454 			sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
455 			strdup( ticolp->ti_attrname )) == NULL ) {
456 		    memerr = 1;
457 		} else {
458 		    attrs[ attrcnt ] = NULL;
459 		}
460 	    }
461 	}
462     }
463 
464     if ( memerr || attrcnt == 0 ) {
465 	for ( i = 0; i < attrcnt; ++i ) {
466 	    if ( attrs[ i ] != NULL ) {
467 		free( attrs[ i ] );
468 	    }
469 	}
470 
471 	free( (char *)attrs );
472 	return( NULL );
473     }
474 
475     return( attrs );
476 }
477 
478 
479 static int
read_next_tmpl(char ** bufp,ssize_t * blenp,struct ldap_disptmpl ** tmplp,int dtversion)480 read_next_tmpl( char **bufp, ssize_t *blenp, struct ldap_disptmpl **tmplp,
481 	int dtversion )
482 {
483     int				i, j, tokcnt, samerow, adsource;
484     char			**toks, *itemopts;
485     struct ldap_disptmpl	*tmpl;
486     struct ldap_oclist		*ocp, *prevocp;
487     struct ldap_adddeflist	*adp, *prevadp;
488     struct ldap_tmplitem	*rowp, *ip, *previp;
489 
490     *tmplp = NULL;
491 
492     /*
493      * template name comes first
494      */
495     if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
496 	free_strarray( toks );
497 	return( tokcnt == 0 ? 0 : LDAP_TMPL_ERR_SYNTAX );
498     }
499 
500     if (( tmpl = (struct ldap_disptmpl *)calloc( (size_t) 1,
501 	    sizeof( struct ldap_disptmpl ))) == NULL ) {
502 	free_strarray( toks );
503 	return(  LDAP_TMPL_ERR_MEM );
504     }
505     tmpl->dt_name = toks[ 0 ];
506     free( (char *)toks );
507 
508     /*
509      * template plural name comes next
510      */
511     if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
512 	free_strarray( toks );
513 	free_disptmpl( tmpl );
514 	return( LDAP_TMPL_ERR_SYNTAX );
515     }
516     tmpl->dt_pluralname = toks[ 0 ];
517     free( (char *)toks );
518 
519     /*
520      * template icon name is next
521      */
522     if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
523 	free_strarray( toks );
524 	free_disptmpl( tmpl );
525 	return( LDAP_TMPL_ERR_SYNTAX );
526     }
527     tmpl->dt_iconname = toks[ 0 ];
528     free( (char *)toks );
529 
530     /*
531      * template options come next
532      */
533     if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) < 1 ) {
534 	free_strarray( toks );
535 	free_disptmpl( tmpl );
536 	return( LDAP_TMPL_ERR_SYNTAX );
537     }
538     for ( i = 0; toks[ i ] != NULL; ++i ) {
539 	for ( j = 0; tmploptions[ j ] != NULL; ++j ) {
540 	    if ( strcasecmp( toks[ i ], tmploptions[ j ] ) == 0 ) {
541 		tmpl->dt_options |= tmploptvals[ j ];
542 	    }
543 	}
544     }
545     free_strarray( toks );
546 
547     /*
548      * object class list is next
549      */
550     while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
551 	if (( ocp = (struct ldap_oclist *)calloc( (size_t) 1,
552 		sizeof( struct ldap_oclist ))) == NULL ) {
553 	    free_strarray( toks );
554 	    free_disptmpl( tmpl );
555 	    return( LDAP_TMPL_ERR_MEM );
556 	}
557 	ocp->oc_objclasses = toks;
558 	if ( tmpl->dt_oclist == NULL ) {
559 	    tmpl->dt_oclist = ocp;
560 	} else {
561 	    prevocp->oc_next = ocp;
562 	}
563 	prevocp = ocp;
564     }
565     if ( tokcnt < 0 ) {
566 	free_disptmpl( tmpl );
567 	return( LDAP_TMPL_ERR_SYNTAX );
568     }
569 
570     /*
571      * read name of attribute to authenticate as
572      */
573     if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
574 	free_strarray( toks );
575 	free_disptmpl( tmpl );
576 	return( LDAP_TMPL_ERR_SYNTAX );
577     }
578     if ( toks[ 0 ][ 0 ] != '\0' ) {
579 	tmpl->dt_authattrname = toks[ 0 ];
580     } else {
581 	free( toks[ 0 ] );
582     }
583     free( (char *)toks );
584 
585     /*
586      * read default attribute to use for RDN
587      */
588     if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
589 	free_strarray( toks );
590 	free_disptmpl( tmpl );
591 	return( LDAP_TMPL_ERR_SYNTAX );
592     }
593     tmpl->dt_defrdnattrname = toks[ 0 ];
594     free( (char *)toks );
595 
596     /*
597      * read default location for new entries
598      */
599     if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
600 	free_strarray( toks );
601 	free_disptmpl( tmpl );
602 	return( LDAP_TMPL_ERR_SYNTAX );
603     }
604     if ( toks[ 0 ][ 0 ] != '\0' ) {
605 	tmpl->dt_defaddlocation = toks[ 0 ];
606     } else {
607 	free( toks[ 0 ] );
608     }
609     free( (char *)toks );
610 
611     /*
612      * read list of rules used to define default values for new entries
613      */
614     while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
615 	if ( strcasecmp( ADDEF_CONSTANT, toks[ 0 ] ) == 0 ) {
616 	    adsource = LDAP_ADSRC_CONSTANTVALUE;
617 	} else if ( strcasecmp( ADDEF_ADDERSDN, toks[ 0 ] ) == 0 ) {
618 	    adsource = LDAP_ADSRC_ADDERSDN;
619 	} else {
620 	    adsource = 0;
621 	}
622 	if ( adsource == 0 || tokcnt < 2 ||
623 		( adsource == LDAP_ADSRC_CONSTANTVALUE && tokcnt != 3 ) ||
624 		( adsource == LDAP_ADSRC_ADDERSDN && tokcnt != 2 )) {
625 	    free_strarray( toks );
626 	    free_disptmpl( tmpl );
627 	    return( LDAP_TMPL_ERR_SYNTAX );
628 	}
629 
630 	if (( adp = (struct ldap_adddeflist *)calloc( (size_t) 1,
631 		sizeof( struct ldap_adddeflist ))) == NULL ) {
632 	    free_strarray( toks );
633 	    free_disptmpl( tmpl );
634 	    return( LDAP_TMPL_ERR_MEM );
635 	}
636 	adp->ad_source = adsource;
637 	adp->ad_attrname = toks[ 1 ];
638 	if ( adsource == LDAP_ADSRC_CONSTANTVALUE ) {
639 	    adp->ad_value = toks[ 2 ];
640 	}
641 	free( toks[ 0 ] );
642 	free( (char *)toks );
643 
644 	if ( tmpl->dt_adddeflist == NULL ) {
645 	    tmpl->dt_adddeflist = adp;
646 	} else {
647 	    prevadp->ad_next = adp;
648 	}
649 	prevadp = adp;
650     }
651 
652     /*
653      * item list is next
654      */
655     samerow = 0;
656     while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
657 	if ( strcasecmp( toks[ 0 ], "item" ) == 0 ) {
658 	    if ( tokcnt < 4 ) {
659 		free_strarray( toks );
660 		free_disptmpl( tmpl );
661 		return( LDAP_TMPL_ERR_SYNTAX );
662 	    }
663 
664 	    if (( ip = (struct ldap_tmplitem *)calloc( (size_t) 1,
665 		    sizeof( struct ldap_tmplitem ))) == NULL ) {
666 		free_strarray( toks );
667 		free_disptmpl( tmpl );
668 		return( LDAP_TMPL_ERR_MEM );
669 	    }
670 
671 	    /*
672 	     * find syntaxid from config file string
673 	     */
674 	    while (( itemopts = strrchr( toks[ 1 ], ',' )) != NULL ) {
675 		*itemopts++ = '\0';
676 		for ( i = 0; itemoptions[ i ] != NULL; ++i ) {
677 		    if ( strcasecmp( itemopts, itemoptions[ i ] ) == 0 ) {
678 			break;
679 		    }
680 		}
681 		if ( itemoptions[ i ] == NULL ) {
682 		    free_strarray( toks );
683 		    free_disptmpl( tmpl );
684 		    return( LDAP_TMPL_ERR_SYNTAX );
685 		}
686 		ip->ti_options |= itemoptvals[ i ];
687 	    }
688 
689 	    for ( i = 0; itemtypes[ i ] != NULL; ++i ) {
690 		if ( strcasecmp( toks[ 1 ], itemtypes[ i ] ) == 0 ) {
691 		    break;
692 		}
693 	    }
694 	    if ( itemtypes[ i ] == NULL ) {
695 		free_strarray( toks );
696 		free_disptmpl( tmpl );
697 		return( LDAP_TMPL_ERR_SYNTAX );
698 	    }
699 
700 	    free( toks[ 0 ] );
701 	    free( toks[ 1 ] );
702 	    ip->ti_syntaxid = itemsynids[ i ];
703 	    ip->ti_label = toks[ 2 ];
704 	    if ( toks[ 3 ][ 0 ] == '\0' ) {
705 		ip->ti_attrname = NULL;
706 		free( toks[ 3 ] );
707 	    } else {
708 		ip->ti_attrname = toks[ 3 ];
709 	    }
710 	    if ( toks[ 4 ] != NULL ) {	/* extra args. */
711 		for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
712 		    ;
713 		}
714 		if (( ip->ti_args = (char **) calloc( (size_t) (i + 1), sizeof( char * )))
715 			== NULL ) {
716 		    free_disptmpl( tmpl );
717 		    return( LDAP_TMPL_ERR_MEM );
718 		}
719 		for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
720 		    ip->ti_args[ i ] = toks[ i + 4 ];
721 		}
722 	    }
723 	    free( (char *)toks );
724 
725 	    if ( tmpl->dt_items == NULL ) {
726 		tmpl->dt_items = rowp = ip;
727 	    } else if ( samerow ) {
728 		previp->ti_next_in_row = ip;
729 	    } else {
730 		rowp->ti_next_in_col = ip;
731 		rowp = ip;
732 	    }
733 	    previp = ip;
734 	    samerow = 0;
735 	} else if ( strcasecmp( toks[ 0 ], "samerow" ) == 0 ) {
736 	    free_strarray( toks );
737 	    samerow = 1;
738 	} else {
739 	    free_strarray( toks );
740 	    free_disptmpl( tmpl );
741 	    return( LDAP_TMPL_ERR_SYNTAX );
742 	}
743     }
744     if ( tokcnt < 0 ) {
745 	free_disptmpl( tmpl );
746 	return( LDAP_TMPL_ERR_SYNTAX );
747     }
748 
749     *tmplp = tmpl;
750     return( 0 );
751 }
752