xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/ldapcompare.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: ldapcompare.c,v 1.1.1.4 2014/05/28 09:58:20 tron Exp $	*/
2 
3 /* ldapcompare.c -- LDAP compare tool */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2014 The OpenLDAP Foundation.
8  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
9  * Portions Copyright 1998-2001 Net Boolean Incorporated.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms are permitted
24  * provided that this notice is preserved and that due credit is given
25  * to the University of Michigan at Ann Arbor.  The name of the
26  * University may not be used to endorse or promote products derived
27  * from this software without specific prior written permission.  This
28  * software is provided ``as is'' without express or implied warranty.
29  */
30 /* Portions Copyright 2002, F5 Networks, Inc, All rights reserved.
31  * This software is not subject to any license of F5 Networks.
32  * This is free software; you can redistribute and use it
33  * under the same terms as OpenLDAP itself.
34  */
35 /* ACKNOWLEDGEMENTS:
36  * This work was originally developed by Jeff Costlow (F5 Networks)
37  * based, in part, on existing LDAP tools and adapted for inclusion
38  * into OpenLDAP Software by Kurt D. Zeilenga.
39  */
40 
41 #include "portable.h"
42 
43 #include <stdio.h>
44 
45 #include <ac/stdlib.h>
46 
47 #include <ac/ctype.h>
48 #include <ac/string.h>
49 #include <ac/unistd.h>
50 #include <ac/errno.h>
51 #include <ac/socket.h>
52 #include <ac/time.h>
53 #include <sys/stat.h>
54 
55 #ifdef HAVE_FCNTL_H
56 #include <fcntl.h>
57 #endif
58 #ifdef HAVE_SYS_TYPES_H
59 #include <sys/types.h>
60 #endif
61 #ifdef HAVE_IO_H
62 #include <io.h>
63 #endif
64 
65 #include <ldap.h>
66 
67 #include "lutil.h"
68 #include "lutil_ldap.h"
69 #include "ldap_defaults.h"
70 
71 #include "common.h"
72 
73 
74 static int quiet = 0;
75 
76 
77 void
78 usage( void )
79 {
80 	fprintf( stderr, _("usage: %s [options] DN <attr:value|attr::b64value>\n"), prog);
81 	fprintf( stderr, _("where:\n"));
82 	fprintf( stderr, _("  DN\tDistinguished Name\n"));
83 	fprintf( stderr, _("  attr\tassertion attribute\n"));
84 	fprintf( stderr, _("  value\tassertion value\n"));
85 	fprintf( stderr, _("  b64value\tbase64 encoding of assertion value\n"));
86 
87 	fprintf( stderr, _("Compare options:\n"));
88 	fprintf( stderr, _("  -E [!]<ext>[=<extparam>] compare extensions (! indicates criticality)\n"));
89 	fprintf( stderr, _("             !dontUseCopy                (Don't Use Copy)\n"));
90 	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
91 	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
92 	fprintf( stderr, _("  -z         Quiet mode,"
93 		" don't print anything, use return values\n"));
94 	tool_common_usage();
95 	exit( EXIT_FAILURE );
96 }
97 
98 static int docompare LDAP_P((
99 	LDAP *ld,
100 	char *dn,
101 	char *attr,
102 	struct berval *bvalue,
103 	int quiet,
104 	LDAPControl **sctrls,
105 	LDAPControl **cctrls));
106 
107 
108 const char options[] = "z"
109 	"Cd:D:e:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:Z";
110 
111 #ifdef LDAP_CONTROL_DONTUSECOPY
112 int dontUseCopy = 0;
113 #endif
114 
115 int
116 handle_private_option( int i )
117 {
118 	char	*control, *cvalue;
119 	int		crit;
120 
121 	switch ( i ) {
122 	case 'E': /* compare extensions */
123 		if( protocol == LDAP_VERSION2 ) {
124 			fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
125 				prog, protocol );
126 			exit( EXIT_FAILURE );
127 		}
128 
129 		/* should be extended to support comma separated list of
130 		 *	[!]key[=value] parameters, e.g.  -E !foo,bar=567
131 		 */
132 
133 		crit = 0;
134 		cvalue = NULL;
135 		if( optarg[0] == '!' ) {
136 			crit = 1;
137 			optarg++;
138 		}
139 
140 		control = ber_strdup( optarg );
141 		if ( (cvalue = strchr( control, '=' )) != NULL ) {
142 			*cvalue++ = '\0';
143 		}
144 
145 #ifdef LDAP_CONTROL_DONTUSECOPY
146 		if ( strcasecmp( control, "dontUseCopy" ) == 0 ) {
147 			if( dontUseCopy ) {
148 				fprintf( stderr,
149 					_("dontUseCopy control previously specified\n"));
150 				exit( EXIT_FAILURE );
151 			}
152 			if( cvalue != NULL ) {
153 				fprintf( stderr,
154 					_("dontUseCopy: no control value expected\n") );
155 				usage();
156 			}
157 			if( !crit ) {
158 				fprintf( stderr,
159 					_("dontUseCopy: critical flag required\n") );
160 				usage();
161 			}
162 
163 			dontUseCopy = 1 + crit;
164 		} else
165 #endif
166 		{
167 			fprintf( stderr,
168 				_("Invalid compare extension name: %s\n"), control );
169 			usage();
170 		}
171 		break;
172 
173 	case 'z':
174 		quiet = 1;
175 		break;
176 
177 	default:
178 		return 0;
179 	}
180 	return 1;
181 }
182 
183 
184 int
185 main( int argc, char **argv )
186 {
187 	char		*compdn = NULL, *attrs = NULL;
188 	char		*sep;
189 	int		rc;
190 	LDAP		*ld = NULL;
191 	struct berval	bvalue = { 0, NULL };
192 	int		i = 0;
193 	LDAPControl	c[1];
194 
195 
196 	tool_init( TOOL_COMPARE );
197 	prog = lutil_progname( "ldapcompare", argc, argv );
198 
199 	tool_args( argc, argv );
200 
201 	if ( argc - optind != 2 ) {
202 		usage();
203 	}
204 
205 	compdn = argv[optind++];
206 	attrs = argv[optind++];
207 
208 	/* user passed in only 2 args, the last one better be in
209 	 * the form attr:value or attr::b64value
210 	 */
211 	sep = strchr(attrs, ':');
212 	if (!sep) {
213 		usage();
214 	}
215 
216 	*sep++='\0';
217 	if ( *sep != ':' ) {
218 		bvalue.bv_val = strdup( sep );
219 		bvalue.bv_len = strlen( bvalue.bv_val );
220 
221 	} else {
222 		/* it's base64 encoded. */
223 		bvalue.bv_val = malloc( strlen( &sep[1] ));
224 		bvalue.bv_len = lutil_b64_pton( &sep[1],
225 			(unsigned char *) bvalue.bv_val, strlen( &sep[1] ));
226 
227 		if (bvalue.bv_len == (ber_len_t)-1) {
228 			fprintf(stderr, _("base64 decode error\n"));
229 			exit(-1);
230 		}
231 	}
232 
233 	ld = tool_conn_setup( 0, 0 );
234 
235 	tool_bind( ld );
236 
237 	if ( 0
238 #ifdef LDAP_CONTROL_DONTUSECOPY
239 		|| dontUseCopy
240 #endif
241 		)
242 	{
243 #ifdef LDAP_CONTROL_DONTUSECOPY
244 		if ( dontUseCopy ) {
245 			c[i].ldctl_oid = LDAP_CONTROL_DONTUSECOPY;
246 			c[i].ldctl_value.bv_val = NULL;
247 			c[i].ldctl_value.bv_len = 0;
248 			c[i].ldctl_iscritical = dontUseCopy > 1;
249 			i++;
250 		}
251 #endif
252 	}
253 
254 	tool_server_controls( ld, c, i );
255 
256 	if ( verbose ) {
257 		fprintf( stderr, _("DN:%s, attr:%s, value:%s\n"),
258 			compdn, attrs, sep );
259 	}
260 
261 	rc = docompare( ld, compdn, attrs, &bvalue, quiet, NULL, NULL );
262 
263 	free( bvalue.bv_val );
264 
265 	tool_exit( ld, rc );
266 }
267 
268 
269 static int docompare(
270 	LDAP *ld,
271 	char *dn,
272 	char *attr,
273 	struct berval *bvalue,
274 	int quiet,
275 	LDAPControl **sctrls,
276 	LDAPControl **cctrls )
277 {
278 	int		rc, msgid, code;
279 	LDAPMessage	*res;
280 	char		*matcheddn;
281 	char		*text;
282 	char		**refs;
283 	LDAPControl **ctrls = NULL;
284 
285 	if ( dont ) {
286 		return LDAP_SUCCESS;
287 	}
288 
289 	rc = ldap_compare_ext( ld, dn, attr, bvalue,
290 		sctrls, cctrls, &msgid );
291 	if ( rc == -1 ) {
292 		return( rc );
293 	}
294 
295 	for ( ; ; ) {
296 		struct timeval	tv;
297 
298 		tv.tv_sec = 0;
299 		tv.tv_usec = 100000;
300 
301 		if ( tool_check_abandon( ld, msgid ) ) {
302 			return LDAP_CANCELLED;
303 		}
304 
305 		rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
306 		if ( rc < 0 ) {
307 			tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
308 			return rc;
309 		}
310 
311 		if ( rc != 0 ) {
312 			break;
313 		}
314 	}
315 
316 	rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 );
317 
318 	if( rc != LDAP_SUCCESS ) {
319 		fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
320 			prog, ldap_err2string( rc ), rc );
321 		return rc;
322 	}
323 
324 	if ( !quiet && ( verbose || ( code != LDAP_SUCCESS && code != LDAP_COMPARE_TRUE && code != LDAP_COMPARE_FALSE )||
325 		(matcheddn && *matcheddn) || (text && *text) || (refs && *refs) ) )
326 	{
327 		printf( _("Compare Result: %s (%d)\n"),
328 			ldap_err2string( code ), code );
329 
330 		if( text && *text ) {
331 			printf( _("Additional info: %s\n"), text );
332 		}
333 
334 		if( matcheddn && *matcheddn ) {
335 			printf( _("Matched DN: %s\n"), matcheddn );
336 		}
337 
338 		if( refs ) {
339 			int i;
340 			for( i=0; refs[i]; i++ ) {
341 				printf(_("Referral: %s\n"), refs[i] );
342 			}
343 		}
344 	}
345 
346 	/* if we were told to be quiet, use the return value. */
347 	if ( !quiet ) {
348 		if ( code == LDAP_COMPARE_TRUE ) {
349 			printf(_("TRUE\n"));
350 		} else if ( code == LDAP_COMPARE_FALSE ) {
351 			printf(_("FALSE\n"));
352 		} else {
353 			printf(_("UNDEFINED\n"));
354 		}
355 	}
356 
357 	if ( ctrls ) {
358 		tool_print_ctrls( ld, ctrls );
359 		ldap_controls_free( ctrls );
360 	}
361 
362 	ber_memfree( text );
363 	ber_memfree( matcheddn );
364 	ber_memvfree( (void **) refs );
365 
366 	return( code );
367 }
368 
369