/* -*- C -*- * * * © 2010 Hewlett-Packard Development Company, L.P. * * Confidential computer software. Valid license from HP and/or its * subsidiaries required for possession, use, or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * Computer Software Documentation, and Technical Data for Commercial Items * are licensed to the U.S. Government under vendor's standard commercial * license. * * Neither HP nor any of its subsidiaries shall be liable for technical or * editorial errors or omissions contained herein. The information in this * document is provided "as is" without warranty of any kind and is subject to * change without notice. The warranties for HP products are set forth in the * express limited warranty statements accompanying such products. Nothing * herein should be construed as constituting an additional warranty. * * */ /* * Compaq revision history * * Rev Author Date Comments * --- ------ ---- -------- * 001 Nick Hudson 08-Sep-2000 Initial version * * 002 Rupesh S 19-Mar-2010 Added more configurable parameters that can be passed. * - port * - bind_dn * - bind_password * - port_security * - ca_file * - base_dn * * 003 Venkatakrishna T 11-Jun-2015 Modified to honor "startTLS" as an option in port_security. */ /* * This program demonstrates the use of the OpenVMS LDAP API from a client * application. * * The program may be compiled using either C or C++. * * The program may be compiled with either 32 or 64 bit pointers (providing * that the compiler supports it). * * To build this program use: * $ cc ldap_example * $ link ldap_example * * The program expects to run as a foreign command. To define the foreign * command use the following syntax: * * $ ldap_example := $disk1:[mydir]ldap_example.exe ! define foreign command * * The program expects the following arguments: * * server The node which is providing LDAP access to a directory * * port The LDAP directory server port to connect to. * A default port of 389 is used if not provided. * * bind_dn The bind dn, enclose in double quotes. Use a blank string * if LDAP directory server supports anonymous bind. * * bind_password The bind password. Use a blank string if LDAP directory * server supports anonymous bind. * * port_security The port security "SSL" or "TLS". Use a blank string * if no port security is required. * * cafile The location of the ca file. Use a blank string if no * CA file is required. * * base_dn The base object in the directory for the search operation. * This is a required field. * * filter The search filter to be used * * attributes An optional list of one or more attributes to be returned * for each matching record. If no attributes are specified, * then all user attributes will be returned. * * Given the parameters above, the program will attempt to make contact * with an LDAP server on node "server", and request a search for all * records below the object "o=acme, c=us" that match the filter "sn=s*". * For each matching record, the attributes "cn" and "sn" will be displayed. */ #include #include #include #include int setup_tls (LDAP *ldapContext, int port_security,char *ca_file); /* * Generic routine to display an error message and return any * supplementary information from the LDAP handle */ void report_error(const char *operation, int result, LDAP *ld) { int stat; char *errmsgp = NULL; printf("%s returned error %d (\"%s\")\n",operation, result, ldap_err2string(result)); stat = ldap_get_option(ld,LDAP_OPT_ERROR_STRING,&errmsgp); if ((stat == -1) || (strlen(errmsgp) == 0)) { printf("No supplementary error text available\n"); } else { printf("Error text : \"%s\"\n",errmsgp); } if (errmsgp != NULL) { ldap_memfree(errmsgp); errmsgp = NULL; } } void main(int argc, char *argv[]) { int stat; int i; int num_entries; char **attrs_array = NULL; int attribute_count; int port_num, ssl_sec=0; /* * For servers which don't support version 3 of the protocol, edit * the line below to use LDAP_VERSION2. Both of these constants * are defined inside LDAP.H */ int protocol = LDAP_VERSION3; /* * The following pointers may be allocated by the LDAP API, and * should be free'd using an appropriate mechanism */ LDAP *ld = NULL; LDAPMessage *result = NULL; LDAPMessage *one_entry = NULL; char *dn = NULL; char *attr_name = NULL; char **values = NULL; BerElement *ber = NULL; if (argc < 9) { printf("Usage:ldap_example server port bind_dn bind_password port_security cafile base_dn filter [attributes]\n\n"); printf("Mandatory arguments : For specifying NULL values use \"\"\n"); printf("server --> The node which is providing LDAP access to a directory\n"); printf("port --> The port through which to search\n"); printf("bind_dn --> The bind dn, enclose in double quotes. Specify a \"\" if\n"); printf(" anonymous bind is supported by LDAP directory server.\n"); printf("bind_password --> The bind password. Specify a \"\" if anonymous bind\n"); printf(" is supported by LDAP directory server.\n"); printf("port_security --> The port security \"SSL\" or \"TLS\". Specify a \"\" if\n"); printf(" you are not using any port security.\n"); printf("cafile --> The location of the ca file. Specify a \"\" if ca file is\n"); printf(" not present.\n"); printf("base_dn --> The base object in the directory for the search operation.\n"); printf(" This is a required argument.\n"); printf("filter --> The search filter to be used. Specify a \"\" if the LDAP\n"); printf(" search needs to be done without filters.\n"); printf("\nOptional arguments : \n"); printf("attributes --> An optional list of one or more attributes to be returned\n"); printf(" for each matching record. If no attributes are specified,\n"); printf(" then all user attributes will be returned.\n"); printf("Example : \n"); printf ("\n $ ldap_example server1 389 \"\" \"\" \"\" \"\" \"ou=vms,o=testcom\" \"\""); printf ("\n $ ldap_example server1 389 \"cn=admin,ou=vms,o=testcom\" \"WELCOME123\" \"\" \"\" -"); printf ("\n \"ou=vms,o=testcom\" \"\""); printf ("\n $ ldap_example server1 389 \"cn=admin,ou=vms,o=testcom\" \"WELCOME123\" \"\" \"\" -"); printf ("\n \"ou=vms,o=testcom\" \"\" \"DN\""); printf ("\n $ ldap_example server1 389 \"cn=admin,ou=vms,o=testcom\" \"WELCOME123\" \"\" \"\" -"); printf ("\n \"ou=vms,o=testcom\" \"\" \"DN\" \"SN\""); printf ("\n $ ldap_example server2 389 -"); printf ("\n \"CN=query_account,CN=Users,DC=testdomain,DC=testcom,DC=com\" -"); printf ("\n \"welcome@123\" \"\" \"\" \"CN=Users,DC=testdomain,DC=testcom,DC=com\" -"); printf ("\n \"\" \"samaccountname\""); printf ("\n $ ldap_example server2 636 -"); printf ("\n \"CN=query_account,CN=Users,DC=testdomain,DC=testcom,DC=com\" -"); printf ("\n \"welcome@123\" \"SSL\" \"\" \"CN=Users,DC=testdomain,DC=testcom,DC=com\" -"); printf ("\n \"\" \"samaccountname\""); printf ("\n $ ldap_example server2 389 \"CN=query_account,CN=Users,DC=testdomain,DC=testcom,DC=com\" -"); printf ("\n \"welcome@123\" \"starttls\" \"\" \"CN=Users,DC=testdomain,DC=testcom,DC=com\" -"); printf ("\n \"\" \"samaccountname\""); printf ("\n $ ldap_example server2 636 \"CN=query_account,CN=Users,DC=testdomain,DC=testcom,DC=com\" -"); printf ("\n \"welcome@123\" \"SSL\" \"SYS$SYSROOT:[SYSMGR]server2.CER\" -"); printf ("\n \"CN=Users,DC=testdomain,DC=testcom,DC=com\" \"\" \"samaccountname\"\n"); goto finished; } /* * If the user requested any particular attributes, then build up * an array to pass to the search routine. If no attributes are * specified, then "attrs_array" will be NULL, and the server should * return all user attributes for each matching entry */ attribute_count = (argc - 9); if (attribute_count != 0) { i = 0; /* * Allocate enough room for a pointer to each attribute, plus * a NULL terminating pointer. */ attrs_array = (char **)calloc((attribute_count + 1),sizeof(char *)); while (i < attribute_count) { attrs_array[i] = strdup(argv[i+9]); i++; } } /* * Establish a context with the library specifying an LDAP server name * and using the port provided , if no port is provided use default LDAP port number. * No connection is made with the server at this stage, so a failure here * would indicate a problem with the library, rather than a network or * server related issue. */ if ((argv[2]== NULL) || (strcmp(argv[2], "") == 0)) port_num=LDAP_PORT; else port_num=atoi(argv[2]); ld = ldap_init(argv[1],port_num ); if (ld == NULL) { printf("ldap_init failed\n"); goto finished; } /* * Having been provided with a LDAP context, it is possible now to * specify options for this session */ stat = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol); if (stat != LDAP_SUCCESS) { report_error("ldap_set_option",stat,ld); goto finished; } /* * Secure the communication channel unless the user has explicitly disabled security. */ if ((argv[5] != NULL) && (strcmp(argv[5], "") != 0)) { /* * Setup port security to SSL or TLS */ if ( (strcmp("SSL",argv[5])== 0) || (strcmp("ssl",argv[5])== 0) ) ssl_sec = 1; stat = setup_tls( ld,ssl_sec,argv[6]); if (stat != LDAP_SUCCESS) { report_error("setup_tls",stat,ld); goto finished; } } /* * Execute a simple bind, with the base dn and password. */ stat = ldap_simple_bind_s(ld,argv[3],argv[4]); if (stat != LDAP_SUCCESS) { report_error("simple_bind",stat,ld); goto finished; } /* * Issue a synchronous search request; this call will not return * until the server has responded. */ stat = ldap_search_s(ld, /* ld */ argv[7], /* base */ LDAP_SCOPE_SUBTREE, /* scope */ argv[8], /* filter */ attrs_array, /* attrs */ 0, /* attrsonly */ &result); /* res */ if (stat != LDAP_SUCCESS) { report_error("ldap_search_s",stat,ld); goto finished; } num_entries = ldap_count_entries(ld,result); if (num_entries == 0) { printf("No matching entries found\n"); goto finished; } printf("Number of entries returned : %d\n",num_entries); /* * Now look at the results that came back */ one_entry = ldap_first_entry(ld,result); while (one_entry != NULL) { /* * The distinguished name of this entry */ dn = ldap_get_dn(ld,one_entry); if (dn != NULL) { printf("\ndn = %s\n",ldap_get_dn(ld,one_entry)); ldap_memfree(dn); dn = NULL; /* * Step through each attribute */ attr_name = ldap_first_attribute(ld,one_entry,&ber); if (attr_name == NULL) { printf("\n"); } /* * Extract the values for each attribute returned. This program * assumes that such values will be "printable" value strings. For * non-printable (binary) data, ldap_get_values_len() should * be used. */ while (attr_name != NULL) { values = ldap_get_values(ld,one_entry,attr_name); if (values == NULL) { printf("\n"); } else { i = 0; while (values[i] != NULL) { printf("%s : %s\n",attr_name,values[i]); i++; } } ldap_memfree(attr_name); attr_name = NULL; ldap_value_free(values); values = NULL; attr_name = ldap_next_attribute(ld,one_entry,ber); } /* * The BerElement pointer is no longer needed and so can be * released. Since this pointer was just being used as an * iterator and doesn't point to any memory that the program * has allocated itself, use zero as the second parameter to * ber_free(). */ if (ber != NULL) { ber_free(ber, 0); ber = NULL; } } else { report_error("ldap_get_dn",0,ld); } one_entry = ldap_next_entry(ld,one_entry); } /* * All exit paths should come through here, where free up any data * structures that the library has allocated using the appropriate * functions. * It is a good habit to set pointers to NULL after releasing them, * although in the cases below it isn't strictly necessary. */ finished: /* * "dn" may have been allocated by ldap_get_dn() */ if (dn != NULL) { ldap_memfree(dn); dn = NULL; } /* * "attr_name" may have been allocated by ldap_first_attribute() or * ldap_next_attribute() */ if (attr_name != NULL) { ldap_memfree(attr_name); attr_name = NULL; } /* * "values" may have been allocated by ldap_get_values() */ if (values != NULL) { ldap_value_free(values); values = NULL; } /* * "ber" may have been allocated by ldap_first_attribute() or * ldap_next_attribute() * Since this pointer was just being used as an iterator and * doesn't point to any memory that the program has allocated * itself, use zero as the second parameter to ber_free() */ if (ber != NULL) { ber_free(ber, 0); ber = NULL; } /* * "one_entry" may have been allocated by ldap_first_entry() or * ldap_next_entry() */ if (one_entry != NULL) { ldap_msgfree(one_entry); one_entry = NULL; } /* * "result" may have been allocated by ldap_search_s() */ if (result != NULL) { ldap_msgfree(result); result = NULL; } /* * "ld" was returned from ldap_init() */ if (ld != NULL) { ldap_unbind(ld); ld = NULL; } /* * "attrs_array" was allocated by this program */ if (attrs_array != NULL) { i = 0; while (attrs_array[i] != NULL) { free(attrs_array[i]); attrs_array[i] = NULL; i++; } free(attrs_array); attrs_array = NULL; } printf("\nProgram terminating\n"); } /* ** */ int setup_tls(LDAP *ldapContext, int port_security, char *ca_file) { int status,ldap_status; void *ldapTLSOption_on = LDAP_OPT_ON; int StartTLS; int ssl_version; /* * Determine StartTLS method: SSL socket (0) or StartTLS negotiation over * standard socket (1). */ if (port_security == 1) { ssl_version = 30; /* Use SSLV3 Protocol */ StartTLS = 0; } else { ssl_version = 23; /* Negotiate the SSL Protocol */ StartTLS = 1; } /* * If the user specified a CA certificate file, then use it to * verify the server's certificate. We need to do this every time we connect * because the server could change beneath us at any time -- so be paranoid. */ if (strcmp(ca_file,"")!=0) { if (ldap_set_option(ldapContext, LDAP_OPT_TLS_VERIFY_REQUIRED, &ldapTLSOption_on) != LDAP_SUCCESS) return -1; if (ldap_set_option(ldapContext, LDAP_OPT_TLS_CA_FILE, ca_file) != LDAP_SUCCESS) return -1; } ldap_status = ldap_set_option(ldapContext, LDAP_OPT_TLS_VERSION, &ssl_version); if (ldap_status != LDAP_SUCCESS) return ldap_status; status = ldap_tls_start(ldapContext, StartTLS); if (status != LDAP_SUCCESS) return -1; return LDAP_SUCCESS; }