xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/ldapcompare.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: ldapcompare.c,v 1.3 2021/08/14 16:14:49 christos 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-2021 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 <sys/cdefs.h>
42 __RCSID("$NetBSD: ldapcompare.c,v 1.3 2021/08/14 16:14:49 christos Exp $");
43 
44 #include "portable.h"
45 
46 #include <stdio.h>
47 
48 #include <ac/stdlib.h>
49 
50 #include <ac/ctype.h>
51 #include <ac/string.h>
52 #include <ac/unistd.h>
53 #include <ac/errno.h>
54 #include <ac/socket.h>
55 #include <ac/time.h>
56 #include <sys/stat.h>
57 
58 #ifdef HAVE_FCNTL_H
59 #include <fcntl.h>
60 #endif
61 #ifdef HAVE_SYS_TYPES_H
62 #include <sys/types.h>
63 #endif
64 #ifdef HAVE_IO_H
65 #include <io.h>
66 #endif
67 
68 #include <ldap.h>
69 
70 #include "lutil.h"
71 #include "lutil_ldap.h"
72 #include "ldap_defaults.h"
73 
74 #include "common.h"
75 
76 
77 static int quiet = 0;
78 
79 
80 void
usage(void)81 usage( void )
82 {
83 	fprintf( stderr, _("usage: %s [options] DN <attr:value|attr::b64value>\n"), prog);
84 	fprintf( stderr, _("where:\n"));
85 	fprintf( stderr, _("  DN\tDistinguished Name\n"));
86 	fprintf( stderr, _("  attr\tassertion attribute\n"));
87 	fprintf( stderr, _("  value\tassertion value\n"));
88 	fprintf( stderr, _("  b64value\tbase64 encoding of assertion value\n"));
89 
90 	fprintf( stderr, _("Compare options:\n"));
91 	fprintf( stderr, _("  -E [!]<ext>[=<extparam>] compare extensions (! indicates criticality)\n"));
92 	fprintf( stderr, _("             !dontUseCopy                (Don't Use Copy)\n"));
93 	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
94 	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
95 	fprintf( stderr, _("  -z         Quiet mode,"
96 		" don't print anything, use return values\n"));
97 	tool_common_usage();
98 	exit( EXIT_FAILURE );
99 }
100 
101 static int docompare LDAP_P((
102 	LDAP *ld,
103 	char *dn,
104 	char *attr,
105 	struct berval *bvalue,
106 	int quiet,
107 	LDAPControl **sctrls,
108 	LDAPControl **cctrls));
109 
110 
111 const char options[] = "z"
112 	"Cd:D:e:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:Z";
113 
114 #ifdef LDAP_CONTROL_DONTUSECOPY
115 int dontUseCopy = 0;
116 #endif
117 
118 int
handle_private_option(int i)119 handle_private_option( int i )
120 {
121 	char	*control, *cvalue;
122 	int		crit;
123 
124 	switch ( i ) {
125 	case 'E': /* compare extensions */
126 		if( protocol == LDAP_VERSION2 ) {
127 			fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
128 				prog, protocol );
129 			exit( EXIT_FAILURE );
130 		}
131 
132 		/* should be extended to support comma separated list of
133 		 *	[!]key[=value] parameters, e.g.  -E !foo,bar=567
134 		 */
135 
136 		crit = 0;
137 		cvalue = NULL;
138 		if( optarg[0] == '!' ) {
139 			crit = 1;
140 			optarg++;
141 		}
142 
143 		control = optarg;
144 		if ( (cvalue = strchr( control, '=' )) != NULL ) {
145 			*cvalue++ = '\0';
146 		}
147 
148 #ifdef LDAP_CONTROL_DONTUSECOPY
149 		if ( strcasecmp( control, "dontUseCopy" ) == 0 ) {
150 			if( dontUseCopy ) {
151 				fprintf( stderr,
152 					_("dontUseCopy control previously specified\n"));
153 				exit( EXIT_FAILURE );
154 			}
155 			if( cvalue != NULL ) {
156 				fprintf( stderr,
157 					_("dontUseCopy: no control value expected\n") );
158 				usage();
159 			}
160 			if( !crit ) {
161 				fprintf( stderr,
162 					_("dontUseCopy: critical flag required\n") );
163 				usage();
164 			}
165 
166 			dontUseCopy = 1 + crit;
167 		} else
168 #endif
169 		{
170 			fprintf( stderr,
171 				_("Invalid compare extension name: %s\n"), control );
172 			usage();
173 		}
174 		break;
175 
176 	case 'z':
177 		quiet = 1;
178 		break;
179 
180 	default:
181 		return 0;
182 	}
183 	return 1;
184 }
185 
186 
187 int
main(int argc,char ** argv)188 main( int argc, char **argv )
189 {
190 	char		*compdn = NULL, *attrs = NULL;
191 	char		*sep;
192 	int		rc;
193 	LDAP		*ld = NULL;
194 	struct berval	bvalue = { 0, NULL };
195 	int		i = 0;
196 	LDAPControl	c[1];
197 
198 
199 	tool_init( TOOL_COMPARE );
200 	prog = lutil_progname( "ldapcompare", argc, argv );
201 
202 	tool_args( argc, argv );
203 
204 	if ( argc - optind != 2 ) {
205 		usage();
206 	}
207 
208 	compdn = argv[optind++];
209 	attrs = argv[optind++];
210 
211 	/* user passed in only 2 args, the last one better be in
212 	 * the form attr:value or attr::b64value
213 	 */
214 	sep = strchr(attrs, ':');
215 	if (!sep) {
216 		usage();
217 	}
218 
219 	*sep++='\0';
220 	if ( *sep != ':' ) {
221 		bvalue.bv_val = strdup( sep );
222 		bvalue.bv_len = strlen( bvalue.bv_val );
223 
224 	} else {
225 		/* it's base64 encoded. */
226 		bvalue.bv_val = malloc( strlen( &sep[1] ));
227 		bvalue.bv_len = lutil_b64_pton( &sep[1],
228 			(unsigned char *) bvalue.bv_val, strlen( &sep[1] ));
229 
230 		if (bvalue.bv_len == (ber_len_t)-1) {
231 			fprintf(stderr, _("base64 decode error\n"));
232 			exit(-1);
233 		}
234 	}
235 
236 	ld = tool_conn_setup( 0, 0 );
237 
238 	tool_bind( ld );
239 
240 	if ( 0
241 #ifdef LDAP_CONTROL_DONTUSECOPY
242 		|| dontUseCopy
243 #endif
244 		)
245 	{
246 #ifdef LDAP_CONTROL_DONTUSECOPY
247 		if ( dontUseCopy ) {
248 			c[i].ldctl_oid = LDAP_CONTROL_DONTUSECOPY;
249 			c[i].ldctl_value.bv_val = NULL;
250 			c[i].ldctl_value.bv_len = 0;
251 			c[i].ldctl_iscritical = dontUseCopy > 1;
252 			i++;
253 		}
254 #endif
255 	}
256 
257 	tool_server_controls( ld, c, i );
258 
259 	if ( verbose ) {
260 		fprintf( stderr, _("DN:%s, attr:%s, value:%s\n"),
261 			compdn, attrs, sep );
262 	}
263 
264 	rc = docompare( ld, compdn, attrs, &bvalue, quiet, NULL, NULL );
265 
266 	free( bvalue.bv_val );
267 
268 	tool_exit( ld, rc );
269 }
270 
271 
docompare(LDAP * ld,char * dn,char * attr,struct berval * bvalue,int quiet,LDAPControl ** sctrls,LDAPControl ** cctrls)272 static int docompare(
273 	LDAP *ld,
274 	char *dn,
275 	char *attr,
276 	struct berval *bvalue,
277 	int quiet,
278 	LDAPControl **sctrls,
279 	LDAPControl **cctrls )
280 {
281 	int		rc, msgid, code;
282 	LDAPMessage	*res;
283 	char		*matcheddn;
284 	char		*text;
285 	char		**refs;
286 	LDAPControl **ctrls = NULL;
287 
288 	if ( dont ) {
289 		return LDAP_SUCCESS;
290 	}
291 
292 	rc = ldap_compare_ext( ld, dn, attr, bvalue,
293 		sctrls, cctrls, &msgid );
294 	if ( rc == -1 ) {
295 		return( rc );
296 	}
297 
298 	for ( ; ; ) {
299 		struct timeval	tv;
300 
301 		tv.tv_sec = 0;
302 		tv.tv_usec = 100000;
303 
304 		if ( tool_check_abandon( ld, msgid ) ) {
305 			return LDAP_CANCELLED;
306 		}
307 
308 		rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
309 		if ( rc < 0 ) {
310 			tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
311 			return rc;
312 		}
313 
314 		if ( rc != 0 ) {
315 			break;
316 		}
317 	}
318 
319 	rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 );
320 
321 	if( rc != LDAP_SUCCESS ) {
322 		fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
323 			prog, ldap_err2string( rc ), rc );
324 		return rc;
325 	}
326 
327 	if ( !quiet && ( verbose || ( code != LDAP_SUCCESS && code != LDAP_COMPARE_TRUE && code != LDAP_COMPARE_FALSE )||
328 		(matcheddn && *matcheddn) || (text && *text) || (refs && *refs) ) )
329 	{
330 		printf( _("Compare Result: %s (%d)\n"),
331 			ldap_err2string( code ), code );
332 
333 		if( text && *text ) {
334 			printf( _("Additional info: %s\n"), text );
335 		}
336 
337 		if( matcheddn && *matcheddn ) {
338 			printf( _("Matched DN: %s\n"), matcheddn );
339 		}
340 
341 		if( refs ) {
342 			int i;
343 			for( i=0; refs[i]; i++ ) {
344 				printf(_("Referral: %s\n"), refs[i] );
345 			}
346 		}
347 	}
348 
349 	/* if we were told to be quiet, use the return value. */
350 	if ( !quiet ) {
351 		if ( code == LDAP_COMPARE_TRUE ) {
352 			printf(_("TRUE\n"));
353 		} else if ( code == LDAP_COMPARE_FALSE ) {
354 			printf(_("FALSE\n"));
355 		} else {
356 			printf(_("UNDEFINED\n"));
357 		}
358 	}
359 
360 	if ( ctrls ) {
361 		tool_print_ctrls( ld, ctrls );
362 		ldap_controls_free( ctrls );
363 	}
364 
365 	ber_memfree( text );
366 	ber_memfree( matcheddn );
367 	ber_memvfree( (void **) refs );
368 
369 	return( code );
370 }
371 
372