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