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