1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15
16#include "portable.h"
17
18#include <stdio.h>
19
20#include <ac/stdlib.h>
21
22#include <ac/ctype.h>
23#include <ac/socket.h>
24#include <ac/string.h>
25#include <ac/time.h>
26#include <ac/unistd.h>
27
28#include <sys/stat.h>
29
30#ifdef HAVE_SYS_FILE_H
31#include <sys/file.h>
32#endif
33#ifdef HAVE_IO_H
34#include <io.h>
35#endif
36
37#include <fcntl.h>
38
39/* including the "internal" defs is legit and nec. since this test routine has
40 * a-priori knowledge of libldap internal workings.
41 * hodges@stanford.edu 5-Feb-96
42 */
43#include "ldap-int.h"
44
45/* local functions */
46static char *get_line LDAP_P(( char *line, int len, FILE *fp, const char *prompt ));
47static char **get_list LDAP_P(( const char *prompt ));
48static int file_read LDAP_P(( const char *path, struct berval *bv ));
49static LDAPMod **get_modlist LDAP_P(( const char *prompt1,
50	const char *prompt2, const char *prompt3 ));
51static void handle_result LDAP_P(( LDAP *ld, LDAPMessage *lm ));
52static void print_ldap_result LDAP_P(( LDAP *ld, LDAPMessage *lm,
53	const char *s ));
54static void print_search_entry LDAP_P(( LDAP *ld, LDAPMessage *res ));
55static void free_list LDAP_P(( char **list ));
56
57static char *dnsuffix;
58
59static char *
60get_line( char *line, int len, FILE *fp, const char *prompt )
61{
62	fputs(prompt, stdout);
63
64	if ( fgets( line, len, fp ) == NULL )
65		return( NULL );
66
67	line[ strlen( line ) - 1 ] = '\0';
68
69	return( line );
70}
71
72static char **
73get_list( const char *prompt )
74{
75	static char	buf[256];
76	int		num;
77	char		**result;
78
79	num = 0;
80	result = (char **) 0;
81	while ( 1 ) {
82		get_line( buf, sizeof(buf), stdin, prompt );
83
84		if ( *buf == '\0' )
85			break;
86
87		if ( result == (char **) 0 )
88			result = (char **) malloc( sizeof(char *) );
89		else
90			result = (char **) realloc( result,
91			    sizeof(char *) * (num + 1) );
92
93		result[num++] = (char *) strdup( buf );
94	}
95	if ( result == (char **) 0 )
96		return( NULL );
97	result = (char **) realloc( result, sizeof(char *) * (num + 1) );
98	result[num] = NULL;
99
100	return( result );
101}
102
103
104static void
105free_list( char **list )
106{
107	int	i;
108
109	if ( list != NULL ) {
110		for ( i = 0; list[ i ] != NULL; ++i ) {
111			free( list[ i ] );
112		}
113		free( (char *)list );
114	}
115}
116
117
118static int
119file_read( const char *path, struct berval *bv )
120{
121	FILE		*fp;
122	ber_slen_t	rlen;
123	int		eof;
124
125	if (( fp = fopen( path, "r" )) == NULL ) {
126	    	perror( path );
127		return( -1 );
128	}
129
130	if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
131		perror( path );
132		fclose( fp );
133		return( -1 );
134	}
135
136	bv->bv_len = ftell( fp );
137
138	if (( bv->bv_val = (char *)malloc( bv->bv_len )) == NULL ) {
139		perror( "malloc" );
140		fclose( fp );
141		return( -1 );
142	}
143
144	if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
145		perror( path );
146		fclose( fp );
147		return( -1 );
148	}
149
150	rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
151	eof = feof( fp );
152	fclose( fp );
153
154	if ( (ber_len_t) rlen != bv->bv_len ) {
155		perror( path );
156		free( bv->bv_val );
157		return( -1 );
158	}
159
160	return( bv->bv_len );
161}
162
163
164static LDAPMod **
165get_modlist(
166	const char *prompt1,
167	const char *prompt2,
168	const char *prompt3 )
169{
170	static char	buf[256];
171	int		num;
172	LDAPMod		tmp = { 0 };
173	LDAPMod		**result;
174	struct berval	**bvals;
175
176	num = 0;
177	result = NULL;
178	while ( 1 ) {
179		if ( prompt1 ) {
180			get_line( buf, sizeof(buf), stdin, prompt1 );
181			tmp.mod_op = atoi( buf );
182
183			if ( tmp.mod_op == -1 || buf[0] == '\0' )
184				break;
185		}
186
187		get_line( buf, sizeof(buf), stdin, prompt2 );
188		if ( buf[0] == '\0' )
189			break;
190		tmp.mod_type = strdup( buf );
191
192		tmp.mod_values = get_list( prompt3 );
193
194		if ( tmp.mod_values != NULL ) {
195			int	i;
196
197			for ( i = 0; tmp.mod_values[i] != NULL; ++i )
198				;
199			bvals = (struct berval **)calloc( i + 1,
200			    sizeof( struct berval *));
201			for ( i = 0; tmp.mod_values[i] != NULL; ++i ) {
202				bvals[i] = (struct berval *)malloc(
203				    sizeof( struct berval ));
204				if ( strncmp( tmp.mod_values[i], "{FILE}",
205				    6 ) == 0 ) {
206					if ( file_read( tmp.mod_values[i] + 6,
207					    bvals[i] ) < 0 ) {
208						free( bvals );
209						for ( i = 0; i<num; i++ )
210							free( result[ i ] );
211						free( result );
212						return( NULL );
213					}
214				} else {
215					bvals[i]->bv_val = tmp.mod_values[i];
216					bvals[i]->bv_len =
217					    strlen( tmp.mod_values[i] );
218				}
219			}
220			tmp.mod_bvalues = bvals;
221			tmp.mod_op |= LDAP_MOD_BVALUES;
222		}
223
224		if ( result == NULL )
225			result = (LDAPMod **) malloc( sizeof(LDAPMod *) );
226		else
227			result = (LDAPMod **) realloc( result,
228			    sizeof(LDAPMod *) * (num + 1) );
229
230		result[num] = (LDAPMod *) malloc( sizeof(LDAPMod) );
231		*(result[num]) = tmp;	/* struct copy */
232		num++;
233	}
234	if ( result == NULL )
235		return( NULL );
236	result = (LDAPMod **) realloc( result, sizeof(LDAPMod *) * (num + 1) );
237	result[num] = NULL;
238
239	return( result );
240}
241
242
243static int
244bind_prompt( LDAP *ld,
245	LDAP_CONST char *url,
246	ber_tag_t request, ber_int_t msgid,
247	void *params )
248{
249	static char	dn[256], passwd[256];
250	int	authmethod;
251
252	printf("rebind for request=%ld msgid=%ld url=%s\n",
253		request, (long) msgid, url );
254
255	authmethod = LDAP_AUTH_SIMPLE;
256
257		get_line( dn, sizeof(dn), stdin, "re-bind dn? " );
258		strcat( dn, dnsuffix );
259
260	if ( authmethod == LDAP_AUTH_SIMPLE && dn[0] != '\0' ) {
261			get_line( passwd, sizeof(passwd), stdin,
262			    "re-bind password? " );
263		} else {
264			passwd[0] = '\0';
265		}
266
267	return ldap_bind_s( ld, dn, passwd, authmethod);
268}
269
270
271int
272main( int argc, char **argv )
273{
274	LDAP		*ld = NULL;
275	int		i, c, port, errflg, method, id, msgtype;
276	char		line[256], command1, command2, command3;
277	char		passwd[64], dn[256], rdn[64], attr[64], value[256];
278	char		filter[256], *host, **types;
279	char		**exdn;
280	static const char usage[] =
281		"usage: %s [-u] [-h host] [-d level] [-s dnsuffix] [-p port] [-t file] [-T file]\n";
282	int		bound, all, scope, attrsonly;
283	LDAPMessage	*res;
284	LDAPMod		**mods, **attrs;
285	struct timeval	timeout;
286	char		*copyfname = NULL;
287	int		copyoptions = 0;
288	LDAPURLDesc	*ludp;
289
290	host = NULL;
291	port = LDAP_PORT;
292	dnsuffix = "";
293	errflg = 0;
294
295	while (( c = getopt( argc, argv, "h:d:s:p:t:T:" )) != -1 ) {
296		switch( c ) {
297		case 'd':
298#ifdef LDAP_DEBUG
299			ldap_debug = atoi( optarg );
300#ifdef LBER_DEBUG
301			if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
302				ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ldap_debug );
303			}
304#endif
305#else
306			printf( "Compile with -DLDAP_DEBUG for debugging\n" );
307#endif
308			break;
309
310		case 'h':
311			host = optarg;
312			break;
313
314		case 's':
315			dnsuffix = optarg;
316			break;
317
318		case 'p':
319			port = atoi( optarg );
320			break;
321
322		case 't':	/* copy ber's to given file */
323			copyfname = strdup( optarg );
324/*			copyoptions = LBER_TO_FILE; */
325			break;
326
327		case 'T':	/* only output ber's to given file */
328			copyfname = strdup( optarg );
329/*			copyoptions = (LBER_TO_FILE | LBER_TO_FILE_ONLY); */
330			break;
331
332		default:
333		    ++errflg;
334		}
335	}
336
337	if ( host == NULL && optind == argc - 1 ) {
338		host = argv[ optind ];
339		++optind;
340	}
341
342	if ( errflg || optind < argc - 1 ) {
343		fprintf( stderr, usage, argv[ 0 ] );
344		exit( EXIT_FAILURE );
345	}
346
347	printf( "ldap_init( %s, %d )\n",
348		host == NULL ? "(null)" : host, port );
349
350	ld = ldap_init( host, port );
351
352	if ( ld == NULL ) {
353		perror( "ldap_init" );
354		exit( EXIT_FAILURE );
355	}
356
357	if ( copyfname != NULL ) {
358		if ( ( ld->ld_sb->sb_fd = open( copyfname, O_WRONLY|O_CREAT|O_EXCL,
359		    0600 ))  == -1 ) {
360			perror( copyfname );
361			exit ( EXIT_FAILURE );
362		}
363		ld->ld_sb->sb_options = copyoptions;
364	}
365
366	bound = 0;
367	timeout.tv_sec = 0;
368	timeout.tv_usec = 0;
369
370	(void) memset( line, '\0', sizeof(line) );
371	while ( get_line( line, sizeof(line), stdin, "\ncommand? " ) != NULL ) {
372		command1 = line[0];
373		command2 = line[1];
374		command3 = line[2];
375
376		switch ( command1 ) {
377		case 'a':	/* add or abandon */
378			switch ( command2 ) {
379			case 'd':	/* add */
380				get_line( dn, sizeof(dn), stdin, "dn? " );
381				strcat( dn, dnsuffix );
382				if ( (attrs = get_modlist( NULL, "attr? ",
383				    "value? " )) == NULL )
384					break;
385				if ( (id = ldap_add( ld, dn, attrs )) == -1 )
386					ldap_perror( ld, "ldap_add" );
387				else
388					printf( "Add initiated with id %d\n",
389					    id );
390				break;
391
392			case 'b':	/* abandon */
393				get_line( line, sizeof(line), stdin, "msgid? " );
394				id = atoi( line );
395				if ( ldap_abandon( ld, id ) != 0 )
396					ldap_perror( ld, "ldap_abandon" );
397				else
398					printf( "Abandon successful\n" );
399				break;
400			default:
401				printf( "Possibilities: [ad]d, [ab]ort\n" );
402			}
403			break;
404
405		case 'b':	/* asynch bind */
406			method = LDAP_AUTH_SIMPLE;
407			get_line( dn, sizeof(dn), stdin, "dn? " );
408			strcat( dn, dnsuffix );
409
410			if ( method == LDAP_AUTH_SIMPLE && dn[0] != '\0' )
411				get_line( passwd, sizeof(passwd), stdin,
412				    "password? " );
413			else
414				passwd[0] = '\0';
415
416			if ( ldap_bind( ld, dn, passwd, method ) == -1 ) {
417				fprintf( stderr, "ldap_bind failed\n" );
418				ldap_perror( ld, "ldap_bind" );
419			} else {
420				printf( "Bind initiated\n" );
421				bound = 1;
422			}
423			break;
424
425		case 'B':	/* synch bind */
426			method = LDAP_AUTH_SIMPLE;
427			get_line( dn, sizeof(dn), stdin, "dn? " );
428			strcat( dn, dnsuffix );
429
430			if ( dn[0] != '\0' )
431				get_line( passwd, sizeof(passwd), stdin,
432				    "password? " );
433			else
434				passwd[0] = '\0';
435
436			if ( ldap_bind_s( ld, dn, passwd, method ) !=
437			    LDAP_SUCCESS ) {
438				fprintf( stderr, "ldap_bind_s failed\n" );
439				ldap_perror( ld, "ldap_bind_s" );
440			} else {
441				printf( "Bind successful\n" );
442				bound = 1;
443			}
444			break;
445
446		case 'c':	/* compare */
447			get_line( dn, sizeof(dn), stdin, "dn? " );
448			strcat( dn, dnsuffix );
449			get_line( attr, sizeof(attr), stdin, "attr? " );
450			get_line( value, sizeof(value), stdin, "value? " );
451
452			if ( (id = ldap_compare( ld, dn, attr, value )) == -1 )
453				ldap_perror( ld, "ldap_compare" );
454			else
455				printf( "Compare initiated with id %d\n", id );
456			break;
457
458		case 'd':	/* turn on debugging */
459#ifdef LDAP_DEBUG
460			get_line( line, sizeof(line), stdin, "debug level? " );
461			ldap_debug = atoi( line );
462#ifdef LBER_DEBUG
463			if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
464				ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ldap_debug );
465			}
466#endif
467#else
468			printf( "Compile with -DLDAP_DEBUG for debugging\n" );
469#endif
470			break;
471
472		case 'E':	/* explode a dn */
473			get_line( line, sizeof(line), stdin, "dn? " );
474			exdn = ldap_explode_dn( line, 0 );
475			for ( i = 0; exdn != NULL && exdn[i] != NULL; i++ ) {
476				printf( "\t%s\n", exdn[i] );
477			}
478			break;
479
480		case 'g':	/* set next msgid */
481			get_line( line, sizeof(line), stdin, "msgid? " );
482			ld->ld_msgid = atoi( line );
483			break;
484
485		case 'v':	/* set version number */
486			get_line( line, sizeof(line), stdin, "version? " );
487			ld->ld_version = atoi( line );
488			break;
489
490		case 'm':	/* modify or modifyrdn */
491			if ( strncmp( line, "modify", 4 ) == 0 ) {
492				get_line( dn, sizeof(dn), stdin, "dn? " );
493				strcat( dn, dnsuffix );
494				if ( (mods = get_modlist(
495				    "mod (0=>add, 1=>delete, 2=>replace -1=>done)? ",
496				    "attribute type? ", "attribute value? " ))
497				    == NULL )
498					break;
499				if ( (id = ldap_modify( ld, dn, mods )) == -1 )
500					ldap_perror( ld, "ldap_modify" );
501				else
502					printf( "Modify initiated with id %d\n",
503					    id );
504			} else if ( strncmp( line, "modrdn", 4 ) == 0 ) {
505				get_line( dn, sizeof(dn), stdin, "dn? " );
506				strcat( dn, dnsuffix );
507				get_line( rdn, sizeof(rdn), stdin, "newrdn? " );
508				if ( (id = ldap_modrdn( ld, dn, rdn )) == -1 )
509					ldap_perror( ld, "ldap_modrdn" );
510				else
511					printf( "Modrdn initiated with id %d\n",
512					    id );
513			} else {
514				printf( "Possibilities: [modi]fy, [modr]dn\n" );
515			}
516			break;
517
518		case 'q':	/* quit */
519			ldap_unbind( ld );
520			exit( EXIT_SUCCESS );
521			break;
522
523		case 'r':	/* result or remove */
524			switch ( command3 ) {
525			case 's':	/* result */
526				get_line( line, sizeof(line), stdin,
527				    "msgid (-1=>any)? " );
528				if ( line[0] == '\0' )
529					id = -1;
530				else
531					id = atoi( line );
532				get_line( line, sizeof(line), stdin,
533				    "all (0=>any, 1=>all)? " );
534				if ( line[0] == '\0' )
535					all = 1;
536				else
537					all = atoi( line );
538				if (( msgtype = ldap_result( ld, id, all,
539				    &timeout, &res )) < 1 ) {
540					ldap_perror( ld, "ldap_result" );
541					break;
542				}
543				printf( "\nresult: msgtype %d msgid %d\n",
544				    msgtype, res->lm_msgid );
545				handle_result( ld, res );
546				res = NULL;
547				break;
548
549			case 'm':	/* remove */
550				get_line( dn, sizeof(dn), stdin, "dn? " );
551				strcat( dn, dnsuffix );
552				if ( (id = ldap_delete( ld, dn )) == -1 )
553					ldap_perror( ld, "ldap_delete" );
554				else
555					printf( "Remove initiated with id %d\n",
556					    id );
557				break;
558
559			default:
560				printf( "Possibilities: [rem]ove, [res]ult\n" );
561				break;
562			}
563			break;
564
565		case 's':	/* search */
566			get_line( dn, sizeof(dn), stdin, "searchbase? " );
567			strcat( dn, dnsuffix );
568			get_line( line, sizeof(line), stdin,
569			    "scope (0=baseObject, 1=oneLevel, 2=subtree, 3=children)? " );
570			scope = atoi( line );
571			get_line( filter, sizeof(filter), stdin,
572			    "search filter (e.g. sn=jones)? " );
573			types = get_list( "attrs to return? " );
574			get_line( line, sizeof(line), stdin,
575			    "attrsonly (0=attrs&values, 1=attrs only)? " );
576			attrsonly = atoi( line );
577
578			    if (( id = ldap_search( ld, dn, scope, filter,
579				    types, attrsonly  )) == -1 ) {
580				ldap_perror( ld, "ldap_search" );
581			    } else {
582				printf( "Search initiated with id %d\n", id );
583			    }
584			free_list( types );
585			break;
586
587		case 't':	/* set timeout value */
588			get_line( line, sizeof(line), stdin, "timeout? " );
589			timeout.tv_sec = atoi( line );
590			break;
591
592		case 'p':	/* parse LDAP URL */
593			get_line( line, sizeof(line), stdin, "LDAP URL? " );
594			if (( i = ldap_url_parse( line, &ludp )) != 0 ) {
595			    fprintf( stderr, "ldap_url_parse: error %d\n", i );
596			} else {
597			    printf( "\t  host: " );
598			    if ( ludp->lud_host == NULL ) {
599				printf( "DEFAULT\n" );
600			    } else {
601				printf( "<%s>\n", ludp->lud_host );
602			    }
603			    printf( "\t  port: " );
604			    if ( ludp->lud_port == 0 ) {
605				printf( "DEFAULT\n" );
606			    } else {
607				printf( "%d\n", ludp->lud_port );
608			    }
609			    printf( "\t    dn: <%s>\n", ludp->lud_dn );
610			    printf( "\t attrs:" );
611			    if ( ludp->lud_attrs == NULL ) {
612				printf( " ALL" );
613			    } else {
614				for ( i = 0; ludp->lud_attrs[ i ] != NULL; ++i ) {
615				    printf( " <%s>", ludp->lud_attrs[ i ] );
616				}
617			    }
618			    printf( "\n\t scope: %s\n",
619					ludp->lud_scope == LDAP_SCOPE_BASE ? "baseObject"
620					: ludp->lud_scope == LDAP_SCOPE_ONELEVEL ? "oneLevel"
621					: ludp->lud_scope == LDAP_SCOPE_SUBTREE ? "subtree"
622#ifdef LDAP_SCOPE_SUBORDINATE
623					: ludp->lud_scope == LDAP_SCOPE_SUBORDINATE ? "children"
624#endif
625					: "**invalid**" );
626			    printf( "\tfilter: <%s>\n", ludp->lud_filter );
627			    ldap_free_urldesc( ludp );
628			}
629			    break;
630
631		case 'n':	/* set dn suffix, for convenience */
632			get_line( line, sizeof(line), stdin, "DN suffix? " );
633			strcpy( dnsuffix, line );
634			break;
635
636		case 'o':	/* set ldap options */
637			get_line( line, sizeof(line), stdin, "alias deref (0=never, 1=searching, 2=finding, 3=always)?" );
638			ld->ld_deref = atoi( line );
639			get_line( line, sizeof(line), stdin, "timelimit?" );
640			ld->ld_timelimit = atoi( line );
641			get_line( line, sizeof(line), stdin, "sizelimit?" );
642			ld->ld_sizelimit = atoi( line );
643
644			LDAP_BOOL_ZERO(&ld->ld_options);
645
646			get_line( line, sizeof(line), stdin,
647				"Recognize and chase referrals (0=no, 1=yes)?" );
648			if ( atoi( line ) != 0 ) {
649				LDAP_BOOL_SET(&ld->ld_options, LDAP_BOOL_REFERRALS);
650				get_line( line, sizeof(line), stdin,
651					"Prompt for bind credentials when chasing referrals (0=no, 1=yes)?" );
652				if ( atoi( line ) != 0 ) {
653					ldap_set_rebind_proc( ld, bind_prompt, NULL );
654				}
655			}
656			break;
657
658		case '?':	/* help */
659			printf(
660"Commands: [ad]d         [ab]andon         [b]ind\n"
661"          [B]ind async  [c]ompare\n"
662"          [modi]fy      [modr]dn          [rem]ove\n"
663"          [res]ult      [s]earch          [q]uit/unbind\n\n"
664"          [d]ebug       set ms[g]id\n"
665"          d[n]suffix    [t]imeout         [v]ersion\n"
666"          [?]help       [o]ptions"
667"          [E]xplode dn  [p]arse LDAP URL\n" );
668			break;
669
670		default:
671			printf( "Invalid command.  Type ? for help.\n" );
672			break;
673		}
674
675		(void) memset( line, '\0', sizeof(line) );
676	}
677
678	return( 0 );
679}
680
681static void
682handle_result( LDAP *ld, LDAPMessage *lm )
683{
684	switch ( lm->lm_msgtype ) {
685	case LDAP_RES_COMPARE:
686		printf( "Compare result\n" );
687		print_ldap_result( ld, lm, "compare" );
688		break;
689
690	case LDAP_RES_SEARCH_RESULT:
691		printf( "Search result\n" );
692		print_ldap_result( ld, lm, "search" );
693		break;
694
695	case LDAP_RES_SEARCH_ENTRY:
696		printf( "Search entry\n" );
697		print_search_entry( ld, lm );
698		break;
699
700	case LDAP_RES_ADD:
701		printf( "Add result\n" );
702		print_ldap_result( ld, lm, "add" );
703		break;
704
705	case LDAP_RES_DELETE:
706		printf( "Delete result\n" );
707		print_ldap_result( ld, lm, "delete" );
708		break;
709
710	case LDAP_RES_MODRDN:
711		printf( "ModRDN result\n" );
712		print_ldap_result( ld, lm, "modrdn" );
713		break;
714
715	case LDAP_RES_BIND:
716		printf( "Bind result\n" );
717		print_ldap_result( ld, lm, "bind" );
718		break;
719
720	default:
721		printf( "Unknown result type 0x%lx\n",
722		        (unsigned long) lm->lm_msgtype );
723		print_ldap_result( ld, lm, "unknown" );
724	}
725}
726
727static void
728print_ldap_result( LDAP *ld, LDAPMessage *lm, const char *s )
729{
730	ldap_result2error( ld, lm, 1 );
731	ldap_perror( ld, s );
732/*
733	if ( ld->ld_error != NULL && *ld->ld_error != '\0' )
734		fprintf( stderr, "Additional info: %s\n", ld->ld_error );
735	if ( LDAP_NAME_ERROR( ld->ld_errno ) && ld->ld_matched != NULL )
736		fprintf( stderr, "Matched DN: %s\n", ld->ld_matched );
737*/
738}
739
740static void
741print_search_entry( LDAP *ld, LDAPMessage *res )
742{
743	LDAPMessage	*e;
744
745	for ( e = ldap_first_entry( ld, res ); e != NULL;
746	    e = ldap_next_entry( ld, e ) )
747	{
748		BerElement	*ber = NULL;
749		char *a, *dn, *ufn;
750
751		if ( e->lm_msgtype == LDAP_RES_SEARCH_RESULT )
752			break;
753
754		dn = ldap_get_dn( ld, e );
755		printf( "\tDN: %s\n", dn );
756
757		ufn = ldap_dn2ufn( dn );
758		printf( "\tUFN: %s\n", ufn );
759
760		free( dn );
761		free( ufn );
762
763		for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL;
764		    a = ldap_next_attribute( ld, e, ber ) )
765		{
766			struct berval	**vals;
767
768			printf( "\t\tATTR: %s\n", a );
769			if ( (vals = ldap_get_values_len( ld, e, a ))
770			    == NULL ) {
771				printf( "\t\t\t(no values)\n" );
772			} else {
773				int i;
774				for ( i = 0; vals[i] != NULL; i++ ) {
775					int	j, nonascii;
776
777					nonascii = 0;
778					for ( j = 0; (ber_len_t) j < vals[i]->bv_len; j++ )
779						if ( !isascii( vals[i]->bv_val[j] ) ) {
780							nonascii = 1;
781							break;
782						}
783
784					if ( nonascii ) {
785						printf( "\t\t\tlength (%ld) (not ascii)\n", vals[i]->bv_len );
786#ifdef BPRINT_NONASCII
787						ber_bprint( vals[i]->bv_val,
788						    vals[i]->bv_len );
789#endif /* BPRINT_NONASCII */
790						continue;
791					}
792					printf( "\t\t\tlength (%ld) %s\n",
793					    vals[i]->bv_len, vals[i]->bv_val );
794				}
795				ber_bvecfree( vals );
796			}
797		}
798
799		if(ber != NULL) {
800			ber_free( ber, 0 );
801		}
802	}
803
804	if ( res->lm_msgtype == LDAP_RES_SEARCH_RESULT
805	    || res->lm_chain != NULL )
806		print_ldap_result( ld, res, "search" );
807}
808