Back to index

lightning-sunbird  0.9+nobinonly
ldapcmp.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* tool to compare the contents of two LDAP directory subtrees */
00039 
00040 #include "ldaptool.h"
00041 
00042 typedef struct attr {
00043     char *name;
00044     char **vals;
00045     struct attr *next;
00046 } ATTR;                     /* used for comparing two entries */
00047 
00048 static void options_callback( int option, char *optarg );
00049 static int docompare( LDAP *ld1, LDAP *ld2, char *base );
00050 static int cmp2(LDAP *ld1, LDAP *ld2, LDAPMessage *e1, int findonly );
00051 static void notfound(char *base, int dbaseno);
00052 ATTR* get_attrs( LDAP *ld, LDAPMessage *e );
00053 char* cmp_attrs( ATTR *a1, ATTR *a2 );
00054 static void attr_free(ATTR *at);
00055 #if 0 /* these functions are not used */
00056 static void print_entry( LDAP *ld, LDAPMessage *entry, int attrsonly );
00057 static void print_dn( LDAP *ld, LDAPMessage *entry );
00058 static int write_ldif_value( char *type, char *value, unsigned long vallen );
00059 #endif /* 0 */
00060 
00061 static void
00062 usage( void )
00063 {
00064     fprintf( stderr,
00065            "usage: %s -b basedn [options] [attributes...]\nwhere:\n",
00066            ldaptool_progname );
00067     fprintf( stderr, "    basedn\tbase dn for search\n" );
00068     fprintf( stderr, "\t\t(if the environment variable LDAP_BASEDN is set,\n" );
00069     fprintf( stderr, "\t\tthen the -b flag is not required)\n" );
00070     fprintf( stderr, "options:\n" );
00071     fprintf( stderr, "    -s scope\tone of base, one, or sub (default is sub)\n" );
00072     ldaptool_common_usage( 1 );
00073     exit( LDAP_PARAM_ERROR );
00074 }
00075 
00076 static char   *base = NULL;
00077 static int     allow_binary, vals2tmp, ldif, scope, deref, differ=0;
00078 static int    attrsonly, timelimit, sizelimit;
00079 #if 0 /* these statics are referenced only by unused functions */
00080 static char   *sep = LDAPTOOL_DEFSEP;
00081 static char   **sortattr = NULL;
00082 static int    *skipsortattr = NULL;
00083 static int    includeufn;
00084 #endif /* 0 */
00085 
00086 
00087 int
00088 main( int argc, char **argv )
00089 {
00090     int                     rc, optind;
00091     LDAP             *ld1, *ld2;
00092 
00093 #ifdef notdef
00094 #ifdef HPUX11
00095 #ifndef __LP64__
00096        _main( argc, argv);
00097 #endif /* __LP64_ */
00098 #endif /* HPUX11 */
00099 #endif
00100 
00101     deref = LDAP_DEREF_NEVER;
00102     allow_binary = vals2tmp = attrsonly = 0;
00103     ldif = 1;
00104     sizelimit = timelimit = 0;
00105     scope = LDAP_SCOPE_SUBTREE;
00106 
00107     optind = ldaptool_process_args( argc, argv, "Bb:l:s:z:", 0,
00108            options_callback );
00109 
00110     if ( optind == -1 ) {
00111        usage();
00112     }
00113 
00114     if ( base == NULL ) {
00115        if (( base = getenv( "LDAP_BASEDN" )) == NULL ) {
00116            usage();
00117        }
00118     }
00119 
00120     ld1 = ldaptool_ldap_init( 0 );
00121 
00122     ldap_set_option( ld1, LDAP_OPT_DEREF, &deref );
00123     ldap_set_option( ld1, LDAP_OPT_TIMELIMIT, &timelimit );
00124     ldap_set_option( ld1, LDAP_OPT_SIZELIMIT, &sizelimit );
00125 
00126     ldaptool_bind( ld1 );
00127 
00128     ld2 = ldaptool_ldap_init( 1 );
00129 
00130     ldap_set_option( ld2, LDAP_OPT_DEREF, &deref );
00131     ldap_set_option( ld2, LDAP_OPT_TIMELIMIT, &timelimit );
00132     ldap_set_option( ld2, LDAP_OPT_SIZELIMIT, &sizelimit );
00133 
00134     ldaptool_bind( ld2 );
00135     if ( ldaptool_verbose ) {
00136        printf( "Connections to servers established.  Beginning comparison.\n" );
00137     }
00138 
00139     rc = docompare( ld1, ld2, base );
00140 
00141     ldaptool_cleanup( ld1 );
00142     ldaptool_cleanup( ld2 );
00143     if ( ldaptool_verbose && !rc ) {
00144        if ( !differ ) {
00145            printf( "compare completed: no differences found\n" );
00146        } else {
00147            printf( "compare completed: ****differences were found****\n" );
00148        }
00149     }
00150     return( rc );
00151 }
00152 
00153 
00154 static void
00155 options_callback( int option, char *optarg )
00156 {
00157     switch( option ) {
00158     case 'B': /* allow binary values to be printed, even if -o used */
00159        ++allow_binary;
00160        break;
00161     case 's': /* search scope */
00162        if ( strncasecmp( optarg, "base", 4 ) == 0 ) {
00163            scope = LDAP_SCOPE_BASE;
00164        } else if ( strncasecmp( optarg, "one", 3 ) == 0 ) {
00165            scope = LDAP_SCOPE_ONELEVEL;
00166        } else if ( strncasecmp( optarg, "sub", 3 ) == 0 ) {
00167            scope = LDAP_SCOPE_SUBTREE;
00168        } else {
00169            fprintf( stderr, "scope should be base, one, or sub\n" );
00170            usage();
00171        }
00172        break;
00173     case 'b': /* searchbase */
00174        base = strdup( optarg );
00175        break;
00176     case 'l': /* time limit */
00177        timelimit = atoi( optarg );
00178        break;
00179     case 'z': /* size limit */
00180        sizelimit = atoi( optarg );
00181        break;
00182     default:
00183        usage();
00184        break;
00185     }
00186 }
00187 
00188 
00189 /*
00190  * Returns an LDAP error code.
00191  */
00192 static int
00193 docompare( LDAP *ld1, LDAP *ld2, char *base )
00194 {
00195     int                     rc, msgid;
00196     LDAPMessage             *res, *e;
00197     LDAPControl             *ctrls[2], **serverctrls;
00198 
00199     if ( ldaptool_verbose ) {
00200         printf( "Base: %s\n\n", base );
00201     }
00202     if ( ldaptool_not ) {
00203        return( LDAP_SUCCESS );
00204     }
00205 
00206     if (( ctrls[0] = ldaptool_create_manage_dsait_control()) != NULL ) {
00207        ctrls[1] = NULL;
00208        serverctrls = ctrls;
00209     } else {
00210        serverctrls = NULL;
00211     }
00212 
00213     if ( ldap_search_ext( ld1, base, scope, "objectClass=*", NULL,
00214            0, serverctrls, NULL, NULL, -1, &msgid ) != LDAP_SUCCESS ) {
00215        return( ldaptool_print_lderror( ld1, "ldap_search",
00216            LDAPTOOL_CHECK4SSL_IF_APPROP ));
00217     }
00218 /* XXXmcs: this code should be modified to display referrals and references */
00219     while ( (rc = ldap_result( ld1, LDAP_RES_ANY, 0, NULL, &res )) == 
00220         LDAP_RES_SEARCH_ENTRY ) {
00221         e = ldap_first_entry( ld1, res );
00222         rc = cmp2( ld1, ld2, e , 0);
00223         ldap_msgfree( res );
00224     }
00225     if ( rc == -1 ) {
00226        return( ldaptool_print_lderror( ld1, "ldap_result",
00227               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00228     }
00229     if (( rc = ldap_result2error( ld1, res, 0 )) != LDAP_SUCCESS ) {
00230         ldaptool_print_lderror( ld1, "ldap_search",
00231               LDAPTOOL_CHECK4SSL_IF_APPROP );
00232     }
00233     ldap_msgfree( res );
00234 
00235     if ( ldap_search_ext( ld2, base, scope, "objectClass=*", NULL,
00236            0, serverctrls, NULL, NULL, -1, &msgid  ) == -1 ) {
00237        return( ldaptool_print_lderror( ld2, "ldap_search",
00238               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00239     }
00240 /* XXXmcs: this code should be modified to display referrals and references */
00241     while ( (rc = ldap_result( ld2, LDAP_RES_ANY, 0, NULL, &res )) == 
00242            LDAP_RES_SEARCH_ENTRY ) {
00243        e = ldap_first_entry( ld2, res );
00244         rc = cmp2( ld2, ld1, e , 1);
00245         ldap_msgfree( res );
00246     }
00247     if ( rc == -1 ) {
00248        return( ldaptool_print_lderror( ld2, "ldap_result",
00249               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00250     }
00251     if (( rc = ldap_result2error( ld1, res, 0 )) != LDAP_SUCCESS ) {
00252         ldaptool_print_lderror( ld1, "ldap_search",
00253               LDAPTOOL_CHECK4SSL_IF_APPROP );
00254     }
00255     ldap_msgfree( res );
00256 
00257     return( rc );
00258 }
00259 
00260 
00261 /*
00262  * Returns an LDAP error code.
00263  */
00264 static int
00265 cmp2( LDAP *ld1, LDAP *ld2, LDAPMessage *e1, int findonly)
00266 {
00267     LDAPMessage             *e2, *res;
00268     char             *dn, *attrcmp;
00269     int                     found=0, rc, msgid;
00270     ATTR             *a1, *a2;
00271 
00272     dn = ldap_get_dn( ld1, e1 );
00273 
00274     if ( ldaptool_verbose ) {
00275        if ( findonly ) {
00276            printf( "Checking that %s exists on both servers\n", dn );
00277        } else {
00278            printf("Comparing entry %s on both servers\n", dn );
00279        }
00280     }
00281 
00282     if ( ldap_search( ld2, dn, LDAP_SCOPE_BASE, "objectClass=*", NULL, 0 ) == -1 ) {
00283         return( ldaptool_print_lderror( ld2, "ldap_search",
00284               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00285     }
00286 /* XXXmcs: this code should be modified to display referrals and references */
00287     while ( (rc = ldap_result( ld2, LDAP_RES_ANY, 0, NULL, &res )) == 
00288         LDAP_RES_SEARCH_ENTRY ) {
00289         e2 = ldap_first_entry( ld1, res );
00290        found = 1;
00291        if ( !findonly ) {
00292            a1 = get_attrs( ld1, e1 );
00293            a2 = get_attrs( ld2, e2 );
00294            attrcmp = cmp_attrs( a1, a2 );
00295            if ( strcmp( attrcmp, "") != 0 ) {
00296                printf("\n%s%s\n", dn, attrcmp);
00297            }
00298        }
00299         ldap_msgfree( res );
00300     }
00301     if ( !found ) {
00302        notfound( dn, findonly );
00303        differ = 1;
00304     }
00305     if ( rc == -1 ) {
00306         return( ldaptool_print_lderror( ld2, "ldap_result",
00307               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00308     }
00309     ldap_msgfree( res );
00310     ldap_memfree( dn );
00311     return(rc);
00312 }
00313 
00314 
00315 ATTR*
00316 get_attrs( LDAP *ld, LDAPMessage *e )
00317 {
00318     char             *a;
00319     ATTR             *head, *tail, *tmp;
00320     BerElement              *ber;
00321 
00322     head=tail=tmp=NULL;
00323     for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL; 
00324          a = ldap_next_attribute( ld, e, ber ) ) {
00325         tmp = (ATTR*)malloc(sizeof(ATTR));
00326        if(head == NULL)
00327            head = tail = tmp;
00328        else {
00329            tail->next = tmp;
00330            tail = tmp;
00331        }
00332        tmp->name = a;
00333        tmp->vals = ldap_get_values( ld, e, a );
00334        tmp->next = NULL;
00335     }
00336    if ( ber != NULL ) {
00337       ber_free( ber, 0 );
00338    }
00339    /*   used for debugging
00340    tmp=head;
00341    while(tmp!= NULL) {
00342        printf("\n%s :", tmp->name);
00343        for(i=0; tmp->vals[i] != NULL; i++)
00344           printf("\n\t%d  %s", i, tmp->vals[i]);
00345        tmp = tmp->next;
00346        }
00347    */
00348    return(head);
00349 }
00350 
00351 
00352 char*
00353 cmp_attrs( ATTR *a1, ATTR *a2 )
00354 {
00355     static char result[5000];
00356     char res[1000], partial[1000], *name = "";
00357     ATTR *head1, *head2, *tmp, *prev, *start;
00358     int i, j, found;
00359 
00360     head1 = a1;
00361     head2 = a2;
00362     tmp = a2;
00363     prev = NULL;
00364     strcpy(result, "");
00365     while(head1 != NULL) {
00366         name = head1->name;
00367        if(head2 == NULL) {
00368            while(head1 != NULL) {
00369                sprintf(partial, "\ndifferent: %s(*)", head1->name);
00370               strcat(result, partial);
00371               for(i=0; head1->vals[i] != NULL; i++) {
00372                   sprintf(partial,"\n\t1: %s", head1->vals[i]);
00373                   strcat(result, partial);
00374               }
00375               tmp = head1;
00376               head1 = head1->next;
00377               attr_free(tmp);
00378            }
00379            differ = 1;
00380            break;
00381        }
00382         name = head1->name;
00383        start = tmp;
00384        while(tmp != NULL) {
00385            if(!strcmp(name, tmp->name)) { /* attr found  */
00386                strcpy(res, "");
00387                for(i=0; (head1->vals[i]) != NULL; i++) {
00388                   found = 0;
00389                   for(j=0; (tmp->vals[j]) != NULL; j++)
00390                       if(!strcmp(head1->vals[i], tmp->vals[j])) {
00391                          found = 1;
00392                          tmp->vals[j][0] = 7;
00393                          break;
00394                      }
00395                   if(!found) {
00396                       sprintf(partial, "\n\t1: %s", head1->vals[i]);
00397                      strcat(res, partial);
00398                   }
00399               }
00400                for(j=0; tmp->vals[j] != NULL; j++)
00401                 if(tmp->vals[j][0] != 7){
00402                       sprintf(partial, "\n\t2: %s", tmp->vals[j]);
00403                      strcat(res, partial);
00404                   }
00405 
00406               if(strcmp(res, "")) {
00407                   sprintf(partial, "\ndifferent: %s%s", name, res);
00408                   differ = 1;
00409                   strcat(result, partial);
00410               }
00411               if(prev == NULL) {          /* tmp = head2 */
00412                   head2 = head2->next;
00413                   attr_free(tmp);
00414                   tmp = head2;
00415               }
00416                else {
00417                   prev->next = tmp->next;
00418                   attr_free(tmp);
00419                   tmp = prev->next;
00420                   if(tmp == NULL) {
00421                       tmp = head2;
00422                      prev = NULL;
00423                   }
00424               }
00425               break;
00426            }
00427            else {                   /* attr not found */
00428                if(prev == NULL)
00429                   prev = head2;
00430               else
00431                   prev = tmp;
00432               tmp = tmp->next;
00433                if(tmp == NULL)     {      /* end of list */
00434                   tmp = head2;
00435                   prev = NULL;
00436               }
00437               if(tmp == start) {   /* attr !exist in 2 */
00438                   sprintf(partial, "\ndifferent: %s(*)", name);
00439                   differ = 1;
00440                   strcat(result, partial);
00441                   for(i=0; head1->vals[i] != NULL; i++) {
00442                       sprintf(partial, "\n\t1: %s", head1->vals[i]);
00443                      strcat(result, partial);
00444                   }
00445                   break;
00446               }    
00447            }
00448        }
00449        start = head1;
00450        head1 = head1->next;
00451        attr_free(start);
00452     }
00453     while(head2 != NULL) {
00454         sprintf(partial, "\ndifferent: %s(*)", head2->name);
00455        differ = 1;
00456               strcat(result, partial);
00457               for(i=0; head2->vals[i] != NULL; i++) {
00458                   sprintf(partial, "\n\t2: %s", head2->vals[i]);
00459                   strcat(result, partial);
00460               }
00461        tmp = head2;
00462               head2 = head2->next;
00463               attr_free(tmp);
00464     }
00465     return(result);
00466 }
00467 
00468 
00469 static void
00470 attr_free(ATTR *at)
00471 {
00472     ldap_memfree(at->name);
00473     ldap_value_free(at->vals);
00474     free(at);
00475 }
00476 
00477 
00478 static void
00479 notfound(char *base, int dbaseno)
00480 {
00481     printf("%donly: %s\n", dbaseno+1, base);
00482 }
00483 
00484 
00485 #if 0  /* these function is not used */
00486 /* used for debugging */
00487 static void
00488 print_dn( LDAP *ld, LDAPMessage *entry )
00489 {
00490     char             *dn, *ufn;
00491 
00492     dn = ldap_get_dn( ld, entry );
00493     if ( ldif ) {
00494        write_ldif_value( "dn", dn, strlen( dn ));
00495     } else {
00496        printf( "%s\n", dn );
00497     }
00498     if ( includeufn ) {
00499        ufn = ldap_dn2ufn( dn );
00500        if ( ldif ) {
00501            write_ldif_value( "ufn", ufn, strlen( ufn ));
00502        } else {
00503            printf( "%s\n", ufn );
00504        }
00505        free( ufn );
00506     }
00507     ldap_memfree( dn );
00508 }
00509 
00510 
00511 static void
00512 print_entry( ld, entry, attrsonly )
00513     LDAP      *ld;
00514     LDAPMessage      *entry;
00515     int              attrsonly;
00516 {
00517     char             *a, *dn, *ufn, tmpfname[ 256 ];
00518     int                     i, notascii;
00519     BerElement              *ber;
00520     struct berval    **bvals;
00521     FILE             *tmpfp;
00522 #if defined( XP_WIN32 )
00523        char   mode[20] = "w+b";
00524 #else
00525        char   mode[20] = "w";
00526 #endif
00527 
00528     dn = ldap_get_dn( ld, entry );
00529     if ( ldif ) {
00530        write_ldif_value( "dn", dn, strlen( dn ));
00531     } else {
00532        printf( "%s\n", dn );
00533     }
00534     if ( includeufn ) {
00535        ufn = ldap_dn2ufn( dn );
00536        if ( ldif ) {
00537            write_ldif_value( "ufn", ufn, strlen( ufn ));
00538        } else {
00539            printf( "%s\n", ufn );
00540        }
00541        free( ufn );
00542     }
00543     ldap_memfree( dn );
00544 
00545     for ( a = ldap_first_attribute( ld, entry, &ber ); a != NULL;
00546            a = ldap_next_attribute( ld, entry, ber ) ) {
00547        if ( ldap_charray_inlist(sortattr, a) &&            /* in the list*/
00548            skipsortattr[ldap_charray_position(sortattr, a)] ) {/* and skip it*/
00549            continue;                                       /* so skip it! */
00550        }
00551        if ( attrsonly ) {
00552            if ( ldif ) {
00553               write_ldif_value( a, "", 0 );
00554            } else {
00555               printf( "%s\n", a );
00556            }
00557        } else if (( bvals = ldap_get_values_len( ld, entry, a )) != NULL ) {
00558            for ( i = 0; bvals[i] != NULL; i++ ) {
00559               if ( vals2tmp ) {
00560                   sprintf( tmpfname, "%s/ldapcmp-%s-XXXXXX",
00561                          ldaptool_get_tmp_dir(), a );
00562                   tmpfp = NULL;
00563 
00564                   if ( mktemp( tmpfname ) == NULL ) {
00565                      perror( tmpfname );
00566                   } else if (( tmpfp = fopen( tmpfname, mode)) == NULL ) {
00567                      perror( tmpfname );
00568                   } else if ( fwrite( bvals[ i ]->bv_val,
00569                          bvals[ i ]->bv_len, 1, tmpfp ) == 0 ) {
00570                      perror( tmpfname );
00571                   } else if ( ldif ) {
00572                      write_ldif_value( a, tmpfname, strlen( tmpfname ));
00573                   } else {
00574                      printf( "%s%s%s\n", a, sep, tmpfname );
00575                   }
00576 
00577                   if ( tmpfp != NULL ) {
00578                      fclose( tmpfp );
00579                   }
00580               } else {
00581                   notascii = 0;
00582                   if ( !ldif && !allow_binary ) {
00583                      notascii = !ldaptool_berval_is_ascii( bvals[ i ] );
00584                   }
00585 
00586                   if ( ldif ) {
00587                      write_ldif_value( a, bvals[ i ]->bv_val,
00588                             bvals[ i ]->bv_len );
00589                   } else {
00590                      printf( "%s%s%s\n", a, sep,
00591                             notascii ? "NOT ASCII" : bvals[ i ]->bv_val );
00592                   }
00593               }
00594            }
00595            ber_bvecfree( bvals );
00596        }
00597     }
00598     if ( ber != NULL ) {
00599        ber_free( ber, 0 );
00600     }
00601 }
00602 
00603 
00604 static int
00605 write_ldif_value( char *type, char *value, unsigned long vallen )
00606 {
00607     char      *ldif;
00608 
00609     if (( ldif = ldif_type_and_value( type, value, (int)vallen )) == NULL ) {
00610        return( -1 );
00611     }
00612 
00613     fputs( ldif, stdout );
00614     free( ldif );
00615 
00616     return( 0 );
00617 }
00618 #endif /* 0 */