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 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 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 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 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