/* $Novell: extmatch.c,v 1.10 2003/05/12 12:19:53 $ */ /************************************************************************** * Novell Software Developer Kit * * Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved. * * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. * USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT * ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK. * PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A * ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS * PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET, * DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S * PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S * CUSTOMERS WITH RESPECT TO THIS CODE. * *************************************************************************** extMatch.c *************************************************************************** Description: The extMatch.c sample constructs the extensible match filter with the given inputs, searches the directory and prints the results. Extensible match requires eDirectory version 8.7 or higher. The LDAP v3 Core protocol specification requires LDAP servers to recognize a search element called an extensible match. Extensible match provides additional features which can be expressed in the search filter. Feature 1. Allow matching to components of the object's Distinguished Name as well as attributes of the object. Feature 2. Allow a specific matching rule to be used for an attribute-value comparison, such as a sounds-alike match. Feature 3. Allow a match to any attribute of an object supporting a particular matching rule. For example, one could search for objects with any string attribute containing "Dino". These features may be used independently or in combination. All the supported matching rules are advertised through LDAP subschema subentry object using the standard matchingRules and matchingRuleUse schema attributes. It is mandatory that either dnAttribute or matching rule be present as part of extensible match filter. NOTE: In eDirectory 8.7, only the DN feature of extensible match is supported (feature 1). The following examples illustrate the use of extensible match filters and correspond to the features listed above. Example #1: (ou:dn:=Sales) Same as filter "(ou=Sales)" except that DN components should be considered part of the entry when doing the match. Any object with "ou=Sales" as part of its DN will match. Example #2: (cn:2.4.6.8:=Barney Rubble) Specifies matching rule "2.4.6.8" to be used when making comparisons for (cn="Barney Rubble"). Example #2a: (cn:dn:2.4.6.8:=Barney Rubble) Combines examples #1 and #2. Specifies the matching rule to use and indicates that components of entry's DN should be considered attributes of the entry when evaluating the match. Example #3: (:2.4.6.8:=Dino) Indicates this filter should be applied to all attributes supporting this matching rule. Example #3a: (:dn:2.4.6.8:=Dino) Same as example #3, but also includes components of the DN in the match. For further details, refer to IETF RFC 2251 and RFC 2254. ***************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ldap.h> #if defined(N_PLAT_NLM) && defined(LIBC) #include <screen.h> #endif static char usage[] = "\nextMatch [-d] <host name> <port number> <login dn> <password>" "\n <search base> <attribute name> <matching rule> <match value>" "\n where:" "\n -d means consider DN components as attributes of the object" "\n <search base> is the starting container for a subtree search" "\n <attribute name> is the attribute to match against, or \"\" for all attrs" "\n <matching rule> is an OID specifying the matching rule to use, or \"\"" "\n <match value> is the value to compare against in the search filter\n" "\nExamples:" "\n #1. extMatch -d Acme.com 389 cn=admin,o=Acme secret o=Acme ou \"\" Sales" "\n #2. extMatch Acme.com 389 cn=admin,o=Acme secret" "\n ou=Sales,o=Acme cn 2.4.6.8 \"Barney Rubble\"" "\n #3. extMatch Acme.com 389 cn=admin,o=Acme secret o=Acme \"\" 2.4.6.8 Dino" "\n NOTE: Only example 1 is supported by eDirectory 8.7\n"; int main( int argc, char **argv ) { int version, ldapPort, rc; size_t len; char *ldapHost, *loginDN, *password, *searchBase, *dn; char *matchAttribute, *matchingRule, *matchValue, *extMatchFilter; LDAP *ld; LDAPMessage *searchResult, *entry; char *attrs[] = { LDAP_NO_ATTRS, NULL }; /* Return DN names only */ struct timeval timeOut = {10,0}; /* 10 second connection/search timeout */ int useDN = 0; /* 1 if to use dnAttribute */ int useRule = 0; /* 1 if matching rule is given */ int useAttribute = 0; /* 1 if attribute value is given */ #if defined(N_PLAT_NLM) && defined(LIBC) setscreenmode(SCR_NO_MODE); /* Don't clear screen on exit */ #endif /* Determine which options are set */ if (argc > 1) { /* Interrogate options until we get something else */ for( ;; ) { /* -d option inserts ":dn" in the filter */ if( strcmp( argv[1],"-d") == 0 ) { useDN = 1; argc--; argv++; continue; } /* An option, but not -d option */ if( argv[1][0] == '-') { printf("%s", usage); return -1; } break; } } /* Validate number of arguments against options chosen. */ if (argc == 9) { ldapHost = argv[1]; ldapPort = atoi(argv[2]); loginDN = argv[3]; password = argv[4]; searchBase = argv[5]; matchAttribute = argv[6]; matchingRule = argv[7]; matchValue = argv[8]; } else { printf("%s", usage); return -1; } if (*matchAttribute) useAttribute = 1; if (*matchingRule) useRule = 1; /* Must have dn option or matching rule. */ if (useDN==0 && useRule==0) { printf("\n Error: Either <attribute name> or <matching rule> must be\n" " present as part of an extensible match filter.\n\n"); printf("%s", usage); return -1; } /* Allocate enough memory for "(attr:dn:rule:=value)" */ len = 8 + strlen(matchValue); /* "(:dn:=value)<null>" */ if (useAttribute) len += strlen(matchAttribute); if (useRule) len += strlen(matchingRule); extMatchFilter = (char*)malloc(len); if (extMatchFilter == NULL) { printf("Memory allocation error\n"); return -1; } /* Construct extensible matching filter*/ strcpy(extMatchFilter, "("); if (useAttribute) strcat(extMatchFilter, matchAttribute); if (useDN) strcat(extMatchFilter, ":dn"); if (useRule) { strcat(extMatchFilter, ":"); strcat(extMatchFilter, matchingRule); } strcat(extMatchFilter, ":="); strcat(extMatchFilter, matchValue); strcat(extMatchFilter, ")"); printf("\n Extensible match filter: %s\n", extMatchFilter); /* Set LDAP version to 3 and set connection timeout. */ version = LDAP_VERSION3; ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version); ldap_set_option( NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeOut); /* Initialize the LDAP session */ if (( ld = ldap_init( ldapHost, ldapPort )) == NULL) { printf ( "\n LDAP session initialization failed\n"); goto cleanup; } printf("\n LDAP session initialized\n"); /* Bind to the server */ rc = ldap_simple_bind_s( ld, loginDN, password ); if (rc != LDAP_SUCCESS ) { printf("ldap_simple_bind_s: %s\n", ldap_err2string( rc )); goto cleanup; } printf("\n Bind successful\n"); /* Search the directory */ rc = ldap_search_ext_s( ld, /* LDAP session handle */ searchBase, /* container to search */ LDAP_SCOPE_SUBTREE, /* search scope */ extMatchFilter, /* extensible match search filter */ attrs, /* attributes to return */ 0, /* return attributes and values */ NULL, /* server controls */ NULL, /* client controls */ &timeOut, /* search timeout */ LDAP_NO_LIMIT, /* no size limit */ &searchResult ); /* returned results */ if ( rc != LDAP_SUCCESS ) { printf("ldap_search_ext_s: %s\n", ldap_err2string( rc )); ldap_msgfree( searchResult ); goto cleanup; } /* Read and print matched entry names. */ for ( entry = ldap_first_entry( ld, searchResult ); entry != NULL; entry = ldap_next_entry( ld, entry ) ) { if (( dn = ldap_get_dn( ld, entry )) != NULL ) { printf("\n dn: %s\n", dn ); ldap_memfree( dn ); } } printf("\n Extensible match search completed successfully.\n"); ldap_msgfree( searchResult ); cleanup: free( extMatchFilter ); ldap_unbind_s( ld ); return rc; }