1/* shellutil.c - common routines useful when building shell-based backends */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 1998-2011 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16/* Portions Copyright (c) 1995 Regents of the University of Michigan.
17 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms are permitted
20 * provided that this notice is preserved and that due credit is given
21 * to the University of Michigan at Ann Arbor. The name of the University
22 * may not be used to endorse or promote products derived from this
23 * software without specific prior written permission. This software
24 * is provided ``as is'' without express or implied warranty.
25 */
26/* ACKNOWLEDGEMENTS:
27 * This work was originally developed by the University of Michigan
28 * (as part of U-MICH LDAP).
29 */
30
31
32#include "portable.h"
33
34#include <stdio.h>
35
36#include <ac/stdlib.h>
37#include <ac/stdarg.h>
38
39#include <pwd.h>
40
41#include <ac/ctype.h>
42#include <ac/string.h>
43
44#include <lber.h>
45#include <ldap.h>
46#include "shellutil.h"
47
48
49int	debugflg;
50char	*progname;
51
52static struct inputparams	ips[] = {
53    IP_TYPE_SUFFIX,	"suffix",
54    IP_TYPE_BASE,	"base",
55    IP_TYPE_SCOPE,	"scope",
56    IP_TYPE_ALIASDEREF,	"deref",
57    IP_TYPE_SIZELIMIT,	"sizelimit",
58    IP_TYPE_TIMELIMIT,	"timelimit",
59    IP_TYPE_FILTER,	"filter",
60    IP_TYPE_ATTRS,	"attrs",
61    IP_TYPE_ATTRSONLY,	"attrsonly",
62    0,			NULL
63};
64
65
66void
67write_result( FILE *fp, int code, char *matched, char *info )
68{
69    fprintf( fp, "RESULT\ncode: %d\n", code );
70    debug_printf( ">> RESULT\n" );
71    debug_printf( ">> code: %d\n", code );
72
73    if ( matched != NULL ) {
74	fprintf( fp, "matched: %s\n", matched );
75	debug_printf( ">> matched: %s\n", matched );
76    }
77
78    if ( info != NULL ) {
79	fprintf( fp, "info: %s\n", info );
80	debug_printf( ">> info: %s\n", info );
81    }
82}
83
84
85void
86write_entry( struct ldop *op, struct ldentry *entry, FILE *ofp )
87{
88    struct ldattr	**app;
89    char		**valp;
90
91    fprintf( ofp, "dn: %s\n", entry->lde_dn );
92    for ( app = entry->lde_attrs; *app != NULL; ++app ) {
93	if ( attr_requested( (*app)->lda_name, op )) {
94	    for ( valp = (*app)->lda_values; *valp != NULL; ++valp ) {
95		fprintf( ofp, "%s: %s\n", (*app)->lda_name, *valp );
96	    }
97	}
98    }
99    fputc( '\n', ofp );
100}
101
102
103int
104test_filter( struct ldop *op, struct ldentry *entry )
105{
106    return ((random() & 0x07 ) == 0x07) /* XXX random for now */
107		? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
108}
109
110
111int
112attr_requested( char *name, struct ldop *op )
113{
114    char	**ap;
115
116    if ( op->ldop_srch.ldsp_attrs == NULL ) {	/* special case */
117	return( 1 );
118    }
119
120    for ( ap = op->ldop_srch.ldsp_attrs; *ap != NULL; ++ap ) {
121	if ( strcasecmp( name, *ap ) == 0 ) {
122	    return( 1 );
123	}
124    }
125
126    return( 0 );
127}
128
129
130void
131free_entry( struct ldentry *entry )
132{
133    struct ldattr	**app;
134    char		**valp;
135
136    free( entry->lde_dn );
137
138    for ( app = entry->lde_attrs; *app != NULL; ++app ) {
139	for ( valp = (*app)->lda_values; *valp != NULL; ++valp ) {
140	    free( *valp );
141	}
142	free( (*app)->lda_values );
143	free( (*app)->lda_name );
144    }
145
146    free( entry->lde_attrs );
147    free( entry );
148}
149
150
151int
152parse_input( FILE *ifp, FILE *ofp, struct ldop *op )
153{
154    char		*p, *args, line[ MAXLINELEN + 1 ];
155    struct inputparams	*ip;
156
157    if ( fgets( line, MAXLINELEN, ifp ) == NULL ) {
158	write_result( ofp, LDAP_OTHER, NULL, "Empty Input" );
159    }
160    line[ strlen( line ) - 1 ] = '\0';
161    if ( strncasecmp( line, STR_OP_SEARCH, sizeof( STR_OP_SEARCH ) - 1 )
162	    != 0 ) {
163	write_result( ofp, LDAP_UNWILLING_TO_PERFORM, NULL,
164		"Operation Not Supported" );
165	return( -1 );
166    }
167
168    op->ldop_op = LDOP_SEARCH;
169
170    while ( fgets( line, MAXLINELEN, ifp ) != NULL ) {
171	line[ strlen( line ) - 1 ] = '\0';
172	debug_printf( "<< %s\n", line );
173
174	args = line;
175	if (( ip = find_input_tag( &args )) == NULL ) {
176	    debug_printf( "ignoring %s\n", line );
177	    continue;
178	}
179
180	switch( ip->ip_type ) {
181	case IP_TYPE_SUFFIX:
182	    add_strval( &op->ldop_suffixes, args );
183	    break;
184	case IP_TYPE_BASE:
185	    op->ldop_dn = estrdup( args );
186	    break;
187	case IP_TYPE_SCOPE:
188	    if ( lutil_atoi( &op->ldop_srch.ldsp_scope, args ) != 0 ||
189		( op->ldop_srch.ldsp_scope != LDAP_SCOPE_BASE &&
190		    op->ldop_srch.ldsp_scope != LDAP_SCOPE_ONELEVEL &&
191		    op->ldop_srch.ldsp_scope != LDAP_SCOPE_SUBTREE ) )
192	    {
193		write_result( ofp, LDAP_OTHER, NULL, "Bad scope" );
194		return( -1 );
195	    }
196	    break;
197	case IP_TYPE_ALIASDEREF:
198	    if ( lutil_atoi( &op->ldop_srch.ldsp_aliasderef, args ) != 0 ) {
199		write_result( ofp, LDAP_OTHER, NULL, "Bad alias deref" );
200		return( -1 );
201	    }
202	    break;
203	case IP_TYPE_SIZELIMIT:
204	    if ( lutil_atoi( &op->ldop_srch.ldsp_sizelimit, args ) != 0 ) {
205		write_result( ofp, LDAP_OTHER, NULL, "Bad size limit" );
206		return( -1 );
207	    }
208	    break;
209	case IP_TYPE_TIMELIMIT:
210	    if ( lutil_atoi( &op->ldop_srch.ldsp_timelimit, args ) != 0 ) {
211		write_result( ofp, LDAP_OTHER, NULL, "Bad time limit" );
212		return( -1 );
213	    }
214	    break;
215	case IP_TYPE_FILTER:
216	    op->ldop_srch.ldsp_filter = estrdup( args );
217	    break;
218	case IP_TYPE_ATTRSONLY:
219	    op->ldop_srch.ldsp_attrsonly = ( *args != '0' );
220	    break;
221	case IP_TYPE_ATTRS:
222	    if ( strcmp( args, "all" ) == 0 ) {
223		op->ldop_srch.ldsp_attrs = NULL;
224	    } else {
225		while ( args != NULL ) {
226		    if (( p = strchr( args, ' ' )) != NULL ) {
227			*p++ = '\0';
228			while ( isspace( (unsigned char) *p )) {
229			    ++p;
230			}
231		    }
232		    add_strval( &op->ldop_srch.ldsp_attrs, args );
233		    args = p;
234		}
235	    }
236	    break;
237	}
238    }
239
240    if ( op->ldop_suffixes == NULL || op->ldop_dn == NULL ||
241		op->ldop_srch.ldsp_filter == NULL ) {
242	write_result( ofp, LDAP_OTHER, NULL,
243		"Required suffix:, base:, or filter: missing" );
244	return( -1 );
245    }
246
247    return( 0 );
248}
249
250
251struct inputparams *
252find_input_tag( char **linep )	/* linep is set to start of args */
253{
254    int		i;
255    char	*p;
256
257    if (( p = strchr( *linep, ':' )) == NULL || p == *linep ) {
258	return( NULL );
259    }
260
261    for ( i = 0; ips[ i ].ip_type != 0; ++i ) {
262	if ( strncasecmp( *linep, ips[ i ].ip_tag, p - *linep ) == 0 ) {
263	    while ( isspace( (unsigned char) *(++p) )) {
264		;
265	    }
266	    *linep = p;
267	    return( &ips[ i ] );
268	}
269    }
270
271    return( NULL );
272}
273
274
275void
276add_strval( char ***sp, char *val )
277{
278    int		i;
279    char	**vallist;
280
281    vallist = *sp;
282
283    if ( vallist == NULL ) {
284	i = 0;
285    } else {
286	for ( i = 0; vallist[ i ] != NULL; ++i ) {
287	    ;
288	}
289    }
290
291    vallist = (char **)erealloc( vallist, ( i + 2 ) * sizeof( char * ));
292    vallist[ i ] = estrdup( val );
293    vallist[ ++i ] = NULL;
294    *sp = vallist;
295}
296
297
298char *
299estrdup( char *s )
300{
301    char	*p;
302
303    if (( p = strdup( s )) == NULL ) {
304	debug_printf( "strdup failed\n" );
305	exit( EXIT_FAILURE );
306    }
307
308    return( p );
309}
310
311
312void *
313erealloc( void *s, unsigned size )
314{
315    char	*p;
316
317    if ( s == NULL ) {
318	p = malloc( size );
319    } else {
320	p = realloc( s, size );
321    }
322
323    if ( p == NULL ) {
324	debug_printf( "realloc( p, %d ) failed\n", size );
325	exit( EXIT_FAILURE );
326    }
327
328    return( p );
329}
330
331
332char *
333ecalloc( unsigned nelem, unsigned elsize )
334{
335    char	*p;
336
337    if (( p = calloc( nelem, elsize )) == NULL ) {
338	debug_printf( "calloc( %d, %d ) failed\n", nelem, elsize );
339	exit( EXIT_FAILURE );
340    }
341
342    return( p );
343}
344
345
346#ifdef LDAP_DEBUG
347
348/* VARARGS */
349void
350debug_printf( const char *fmt, ... )
351{
352    va_list	ap;
353
354	if ( debugflg ) {
355		va_start( ap, fmt );
356		fprintf( stderr, "%s: ", progname );
357		vfprintf( stderr, fmt, ap );
358		va_end( ap );
359	}
360}
361
362
363void
364dump_ldop( struct ldop *op )
365{
366    if ( !debugflg ) {
367	return;
368    }
369
370    debug_printf( "SEARCH operation\n" );
371    if ( op->ldop_suffixes == NULL ) {
372	debug_printf( "    suffix: NONE\n" );
373    } else {
374	int	i;
375	for ( i = 0; op->ldop_suffixes[ i ] != NULL; ++i ) {
376	    debug_printf( "    suffix: <%s>\n", op->ldop_suffixes[ i ] );
377	}
378    }
379    debug_printf( "        dn: <%s>\n", op->ldop_dn );
380    debug_printf( "     scope: <%d>\n", op->ldop_srch.ldsp_scope );
381    debug_printf( "    filter: <%s>\n", op->ldop_srch.ldsp_filter );
382    debug_printf( "aliasderef: <%d>\n", op->ldop_srch.ldsp_aliasderef );
383    debug_printf( " sizelimit: <%d>\n", op->ldop_srch.ldsp_sizelimit );
384    debug_printf( " timelimit: <%d>\n", op->ldop_srch.ldsp_timelimit );
385    debug_printf( " attrsonly: <%d>\n", op->ldop_srch.ldsp_attrsonly );
386    if ( op->ldop_srch.ldsp_attrs == NULL ) {
387	debug_printf( "     attrs: ALL\n" );
388    } else {
389	int	i;
390
391	for ( i = 0; op->ldop_srch.ldsp_attrs[ i ] != NULL; ++i ) {
392	    debug_printf( "  attrs: <%s>\n", op->ldop_srch.ldsp_attrs[ i ] );
393	}
394    }
395}
396#endif /* LDAP_DEBUG */
397