/* XDS_READ_EXAMPLE_1.C V5.6-3 *%COPYRIGHT_START% * * Copyright Digital Equipment Corporation 1993, 1995. All rights reserved * * Restricted Rights: Use, duplication, or disclosure by the U.S Government is * subject to restrictions as set forth in subparagraph (C) (1) (ii) of DFARS * 252.227-7013, or in FAR 52.227-19, or in FAR 52.227-14 Alt, III, as * applicable. Unpublished rights reserved under applicable copyright laws. * * This software is proprietary to and embodies the confidential technology of * Digital Equipment Corporation. Possession, use, or copying of this software * and media is authorized only pursuant to a valid written license from * Digital or an authorized sublicensor. * *%COPYRIGHT_END% */ /****************************************************************** * The following are trademarks of Digital Equipment Corporation: * DEC, OpenVMS, ULTRIX. * ******************************************************************/ /****************************************************************************** * * * FACILITY: X.500 XDS * * * ABSTRACT: * This example program demonstrates how to use the Digital X.500 * Directory Service API. The program demonstrates how to connect to * the Directory, read an entry, and use the services to extract * information from the entry. * * * ENVIRONMENT: * OpenVMS, ULTRIX, Digital UNIX (formerly DEC OSF/1) * * * FUNCTIONAL DESCRIPTION * This program reads a directory entry and displays its Distinguished * Name and the Telephone Number attribute value. * The program calls XDS to bind to the directory, and read a directory * entry. The OM functions are called to extract the Distinguished Name * and Telephone Number from the content of the entry read from the * Directory. * The error handling in this program is simple, to make it easier to * read. * * The DXIM equivalent command is: * dxim> show entry /c=US/o=Abacus/ou=Sales/cn="Francis Black" - * attribute telephonenumber * * * INSTRUCTIONS * Install the Digital X.500 Directory API component on the system where * the program is to be built and run. On ULTRIX and Digital UNIX (formerly * DEC OSF/1) systems you will also need to install the BASE component because it * is a prerequisite of the API component. Perform any documented * post-installation tasks. The Installation Card can be referred to * regarding any post-installation tasks. * * To build the program: * ULTRIX: * c89 /usr/examples/dxd/xds_read_example_1.c \ * -o xds_read_example_1 -lxds * #(note:cc may not compile the program) * Digital UNIX: * cc /usr/examples/dxd/xds_read_example_1.c \ * -o xds_read_example_1 -lxds * OpenVMS: * Copy program from [DXD] subdirectory of SYS$EXAMPLES to * the default directory, and * $ cc xds_read_example_1.c * $ link xds_read_example_1, sys$input/opt * sys$share:dxd$xds_shr.exe/share * sys$share:vaxcrtl.exe/share (if VAX C compiler used) * sys$share:decc$shr.exe/share (if DEC C compiler used) * * * To execute the program successfully, the following are required: * - An operational DSA to bind to, containing an entry * /c=US/o=Abacus/ou=Sales/cn="Francis Black" which has a telephone * number attribute. * - The application defaults must be configured on the system where * the program is to run. See the Digital X.500 Directory Service Management * guide for details of how to do this. * * To understand the logic and the calls to XDS, * refer to Digital X.500 Directory Service Programming * documentation. * * To configure the program to read a Directory entry of a different name, * change the Distinguished Name OM Public Object referred to by * the variable entry_to_read. This OM Object is initialized at the * start of main(). * * * AUTHOR: X.500 Development * * * CREATION DATE: May 1993 * * * MODIFICATION HISTORY: * * Version Date Reviser Reason * -------- ----------- ------------- ---------------------------- * 1.0 May 93 NK/IRD creation * June 93 CMB minor edits in comments * July 93 kjo Enhancements to the comments * October 93 djb Change OSF/1 linking instructions * November 93 IRD Change build instructions *****************************************************************************/ #include #include #include /* * Include XDS and OM definitions used in the program */ #include #include #include /************************************************************************ * Define the Object Identifiers representing OM Classes and Directory * Attributes used in the program. * The OM_EXPORT macro declares these as variables and initializes them * Look in the file XOM.H for a definition of the macro. ************************************************************************/ /* * Define the Object Identifiers for the AVA, DS-DN and DS-RDN classes. * These will be used when setting the Class Description attribute for the * AVA, DS_DN and the DS_RDN objects. */ OM_EXPORT(DS_C_AVA) OM_EXPORT(DS_C_DS_DN) OM_EXPORT(DS_C_DS_RDN) /* * Define the Object Identifiers for the country (COUNTRY_NAME), * organization (ORG_NAME), organizationalUnit (ORG_UNIT_NAME), * commonName (COMMON_NAME) and telephoneNumber (PHONE_NBR) attributes. * These are Object ID's that represent X.500 Directory Attributes. */ OM_EXPORT(DS_A_COUNTRY_NAME) OM_EXPORT(DS_A_ORG_NAME) OM_EXPORT(DS_A_ORG_UNIT_NAME) OM_EXPORT(DS_A_COMMON_NAME) OM_EXPORT(DS_A_PHONE_NBR) #define TRUE 1 #define FALSE 0 /* * Function Prototypes */ static void Display_Data(OM_private_object); static void find_attr_name(OM_string *attr_type, char *attr_name ); static int ObjectIdsMatch( OM_string *objid1, OM_string *objid2 ); /*************************************************************************** * * OM Public Objects * ================= * * The basic data structure used to pass data into XDS and to extract * data from XDS is the OM Public Object. * OM Public Objects are arrays of OM Descriptors which contain values * that describe the object. * * The OM Descriptor has a structure which is equivalent to * * typedef struct OM_descriptor_struct { * OM_type type; * OM_syntax syntax; * union OM_value_union value; * } OM_descriptor; * * In this example, where appropriate, OM Object will be represented as * +---------------------------------------------------------------------------+ | Type | Syntax of value | Value | +---------------------------------------------------------------------------+ | . | | . | | . | +---------------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUE | +---------------------------------------------------------------------------+ * * Note that the end of an OM Public Object is indicated by OM_NO_MORE_TYPES * in the final OM Descriptor. * * They are described in the Digital X.500 Directory Service * Programming and OSI-Data-Manipulation user documentation. *****************************************************************************/ main() { /************************************************************************* * This routine initializes the Distinguished Name, creates an OM Workspace, * establishes a connection to the Directory, reads the entry, * calls a routine to process the results, and tidies up. *************************************************************************/ /* * Declare local variables */ OM_return_code om_delete_status; DS_status bind_status, read_status, unbind_status, shutdown_status; OM_private_object session, read_result; OM_workspace workspace; OM_sint invoke_id; OM_descriptor AVA_country_US[4], /* For the Name of the entry */ AVA_org_Abacus[4], AVA_ou_Sales[4], AVA_cn_FrancisBlack[4], RDN_country_US[3], RDN_org_Abacus[3], RDN_ou_Sales[3], RDN_cn_FrancisBlack[3], entry_to_read[6]; /***************************************************************************** * * Defining a Distinguished Name OM Public Object * ============================================== * * This program reads a pre-defined entry in the Directory. The Distinguished * Name of this entry is required by ds_read() to read the entry. The * following declarations and initializations set up the Distinguished Name * as a public object. * * The Distinguished Name is /c=US/o=Abacus/ou=Sales/cn="Francis Black" * * The structure of an OM Public Object which represents a DN is complex. * In this example there are * - four AVA OM Public Objects, each containing an attribute type * and value used in the Distinguished Name. * - four DS-RDN OM Public Objects, each of which point to an AVA * OM Public Object. * - one DS-DN OM Public Object, which points to the four DS-RDN OM * Public Objects which constitute the full Distinguished Name. * ****************************************************************************/ /* * The following descriptor initializations use the OMX macros to * make the program compilable on all supported operating systems. * The VAX C compiler does not permit the initialization of unions. * All the OMX macros are declared in the file xom.h * * The normal method is to declare the OM_descriptors as static and * initialize them at the same time * eg static OM_descriptor AVA_country_US[] = * { * OM_OID_DESC(OM_CLASS, DS_C_AVA), * OM_OID_DESC(DS_ATTRIBUTE_TYPE, DS_A_COUNTRY_NAME), * { DS_ATTRIBUTE_VALUES,OM_S_PRINTABLE_STRING,OM_STRING("US") }, * OM_NULL_DESCRIPTOR * }; */ /* * Initialize the OM Public Object AVA_country_US by using the OMX macros. * The initialized object will look like +-----------------------------------------------------------------------+ | OM_CLASS | OM_S_OBJECT_ID.. | ref to DS_C_AVA | +-----------------------------------------------------------------------+ | DS_ATTRIBUTE_TYPE | OM_S_OBJECT_ID.. | ref to DS_A_COUNTRY_NAME | +-----------------------------------------------------------------------+ | DS_ATTRIBUTE_VALUES | OM_S_PRINTABLE_STR..| ref to string "US" | +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUE | +-----------------------------------------------------------------------+ * NOTE: The term 'ref' (reference) has been used in the third column * because this field actually contains a structure which itself * contains a pointer to the required value. */ OMX_CLASS_DESC( AVA_country_US[0], DS_C_AVA ); OMX_ATTR_TYPE_DESC( AVA_country_US[1], DS_ATTRIBUTE_TYPE, DS_A_COUNTRY_NAME); OMX_ZSTRING_DESC( AVA_country_US[2], OM_S_PRINTABLE_STRING, DS_ATTRIBUTE_VALUES, "US"); OMX_OM_NULL_DESC(AVA_country_US[3]); /* * Initialize the other AVA OM Public Objects to the values that * appear in the Distinguished Name using the OMX macros. * These OM Public Objects will look similar to AVA_country_US. */ OMX_CLASS_DESC( AVA_org_Abacus[0], DS_C_AVA ); OMX_ATTR_TYPE_DESC( AVA_org_Abacus[1], DS_ATTRIBUTE_TYPE, DS_A_ORG_NAME); OMX_ZSTRING_DESC( AVA_org_Abacus[2], OM_S_PRINTABLE_STRING, DS_ATTRIBUTE_VALUES, "Abacus"); OMX_OM_NULL_DESC(AVA_org_Abacus[3]); OMX_CLASS_DESC( AVA_ou_Sales[0], DS_C_AVA ); OMX_ATTR_TYPE_DESC( AVA_ou_Sales[1], DS_ATTRIBUTE_TYPE, DS_A_ORG_UNIT_NAME); OMX_ZSTRING_DESC( AVA_ou_Sales[2], OM_S_PRINTABLE_STRING, DS_ATTRIBUTE_VALUES, "Sales"); OMX_OM_NULL_DESC(AVA_ou_Sales[3]); OMX_CLASS_DESC( AVA_cn_FrancisBlack[0], DS_C_AVA ); OMX_ATTR_TYPE_DESC( AVA_cn_FrancisBlack[1], DS_ATTRIBUTE_TYPE, DS_A_COMMON_NAME); OMX_ZSTRING_DESC( AVA_cn_FrancisBlack[2], OM_S_PRINTABLE_STRING, DS_ATTRIBUTE_VALUES, "Francis Black"); OMX_OM_NULL_DESC(AVA_cn_FrancisBlack[3]); /* * Initialize the OM Public Object RDN_country_US by using the OMX macros. * This object refers to the appropriate AVA OM Public Object. * The initialized object will look like +-----------------------------------------------------------------------+ | OM_CLASS | OM_S_OBJECT_ID.. | ref to DS_C_DS_RDN | +-----------------------------------------------------------------------+ | DS_AVAS | OM_S_OBJECT | ref to AVA_country_US obj| +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUE | +-----------------------------------------------------------------------+ */ OMX_CLASS_DESC( RDN_country_US[0], DS_C_DS_RDN ); OMX_OBJECT_DESC( RDN_country_US[1], DS_AVAS, AVA_country_US); OMX_OM_NULL_DESC( RDN_country_US[2]); /* * Initialize the other RDN OM Public Objects to the values that * appear in the Distinguished Name using the OMX macros. * The initialized object will look similar to the RDN_country_US OM * Public Object. */ OMX_CLASS_DESC( RDN_org_Abacus[0], DS_C_DS_RDN ); OMX_OBJECT_DESC( RDN_org_Abacus[1], DS_AVAS, AVA_org_Abacus); OMX_OM_NULL_DESC( RDN_org_Abacus[2]); OMX_CLASS_DESC( RDN_ou_Sales[0], DS_C_DS_RDN ); OMX_OBJECT_DESC( RDN_ou_Sales[1], DS_AVAS, AVA_ou_Sales); OMX_OM_NULL_DESC( RDN_ou_Sales[2]); OMX_CLASS_DESC( RDN_cn_FrancisBlack[0], DS_C_DS_RDN ); OMX_OBJECT_DESC( RDN_cn_FrancisBlack[1], DS_AVAS, AVA_cn_FrancisBlack); OMX_OM_NULL_DESC( RDN_cn_FrancisBlack[2]); /* * Initialize the OM Public Object entry_to_read by using the OMX macros. * This object refers to each of the Relative Distinguished Names * which are in the Distinguished Name. * The object will look like +-----------------------------------------------------------------------+ | OM_CLASS | OM_S_OBJECT_ID.. | ref to DS_C_DS_DN | +-----------------------------------------------------------------------+ | DS_RDNS | OM_S_OBJECT | ref to RDN_country_US obj| +-----------------------------------------------------------------------+ | DS_RDNS | OM_S_OBJECT | ref to RDN_org_Abacus obj| +-----------------------------------------------------------------------+ | DS_RDNS | OM_S_OBJECT | ref to RDN_ou_Sales obj | +-----------------------------------------------------------------------+ | DS_RDNS | OM_S_OBJECT | ref to RDN_cn_FrancisBlac| +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUE | +-----------------------------------------------------------------------+ */ OMX_CLASS_DESC( entry_to_read[0], DS_C_DS_DN ); OMX_OBJECT_DESC( entry_to_read[1], DS_RDNS, RDN_country_US); OMX_OBJECT_DESC( entry_to_read[2], DS_RDNS, RDN_org_Abacus); OMX_OBJECT_DESC( entry_to_read[3], DS_RDNS, RDN_ou_Sales); OMX_OBJECT_DESC( entry_to_read[4], DS_RDNS, RDN_cn_FrancisBlack); OMX_OM_NULL_DESC( entry_to_read[5]); /***************************************************************************** * Proceed with the program, connecting to the Directory, reading the * entry, processing the results and tidying up after. *****************************************************************************/ /* * Obtain a workspace with the ds_initialize() function. The workspace is * used by the XDS/OM Interface to create and manage OM Objects. */ if ((workspace = ds_initialize()) == NULL) { printf("Failed to open Workspace.\n"); return(EXIT_FAILURE); } else printf("Valid Workspace obtained.\n"); /* * Open a session with the Directory by calling ds_bind(). * The input parameters are the details of the session requested * by the application, and the workspace. * The literal DS_DEFAULT_SESSION indicates that default values * are to be used when connecting to the Directory. In the Digital * implementation of XDS, the DSA's Presentation Address is stored in * the DUA defaults file. See Digital X.500 Directory Service * Programming. * The output parameter session identifies the specific * connection to the Directory. It is an input parameter to other * XDS calls to the Directory Sevice. */ bind_status = ds_bind(DS_DEFAULT_SESSION, workspace, &session); if (bind_status == DS_SUCCESS) printf("Bind was succesful.\n"); else { printf("Bind failed.\n"); return(EXIT_FAILURE); } /* * Read the entry in the Directory using ds_read(). * Input parameters are the session, the context, the name * of the entry to be read, and what information is to be returned in * the result. * The default values for the context OM Object are used if the * DS_DEFAULT_CONTEXT literal is passed as the context parameter. * All information in the entry is returned when * DS_SELECT_ALL_TYPES_AND_VALUES as the selection parameter. * The output parameters are the address of the Read-Result OM Private * Object, and the invoke_id. The invoke_id is only used on asynchronous * operations, so can be ignored in this case. */ read_status = ds_read(session, DS_DEFAULT_CONTEXT, entry_to_read, DS_SELECT_ALL_TYPES_AND_VALUES, &read_result, &invoke_id); if (read_status == DS_SUCCESS) { printf("Read was succesful.\n\n"); /* * Extract the information from the read-result and display it. */ Display_Data(read_result); } else { printf("Read failed.\n"); return(EXIT_FAILURE); } /* * Close the Directory session with the function ds_unbind(). * No further Directory operations can be performed unless * ds_bind() is called again. */ unbind_status = ds_unbind(session); if (unbind_status == DS_SUCCESS) printf("\nUnbind was succesful.\n"); else { printf("Unbind failed.\n"); return(EXIT_FAILURE); } /* * Delete the Service Generated OM Objects which are no longer required. * Service Generated OM Objects are those which are created and returned * to the application by XDS. * The Read-Result OM Object has been processed, and is no longer needed. * The Session OM Object is also no longer required because the program * has unbound from the Directory. */ om_delete_status=om_delete(session); if (om_delete_status != OM_SUCCESS) { printf("om_delete failed.\n"); return(EXIT_FAILURE); } om_delete_status=om_delete(read_result); if (om_delete_status != OM_SUCCESS) { printf("om_delete failed.\n"); return(EXIT_FAILURE); } /* * Release the workspace by calling ds_shutdown(). * No further XDS/OM functions can now be called. */ shutdown_status = ds_shutdown(workspace); if (shutdown_status == DS_SUCCESS) printf("Shutdown was succesful.\n"); else { printf("Shutdown failed.\n"); return(EXIT_FAILURE); } /* * Use exit() to return to operating system. This overcomes the problem of * displaying the VMS message "%NONAME-W-NOMSG, Message number 00000000". */ exit(EXIT_SUCCESS); } static void Display_Data(OM_private_object read_result) { /************************************************************************* * This routine extracts the appropriate information from a Read Result * OM Private Object, and displays the entry's Distinguished Name and * telephone number. * * There are two methods an application can use to extract information * from an OM Private Object. * - The results can be expanded out into a tree-structure of OM Public * Objects, and the structure traversed to find the information required. * - The information can be found by stepping through the object and * extracting the appropriate information at each level. * * This program demonstrates the latter method. * The merits of each approach are described in Digital X.500 Directory Service * Programming. ************************************************************************* /* * Declare variables */ OM_value_position total_number; OM_return_code om_get_status, om_delete_status; OM_public_object entry_object, object_name_object, rdns_object, rdns_ptr, avas_object, saved_avas_object, current_object, attributes_object, saved_attributes_object; OM_type entry_type[2], name_type[2], rdns_type[2], attributes_type[2]; char the_attr_name[128]; int required_attribute; /*********************************************************************** * The Read-Result OM Object contains information about the reading of * the entry. The Entry-Information OM Object (a sub-object of the * Read-Result OM Object) contains the information that is required. * We use om_get() to extract the Entry-Information OM Private Object * from the Read-Result OM Private Object. ************************************************************************/ /* * Define the OM types of the OM Attributes that om_get() is to extract * from the Read-Result OM Private Object. In this case, it's the DS_ENTRY * OM Attribute which references the Entry-Information OM object required. */ entry_type[0] = DS_ENTRY; entry_type[1] = OM_NO_MORE_TYPES; /* * Call om_get() to extract the required information from the Read-Result * OM Private Object. * Arguments: * read_result : Read-Result OM Private Object. * OM_EXCLUDE_ALL_BUT_THESE_TYPES|OM_EXCLUDE_SUBOBJECTS : * extract only the OM types in 'entry_type', * and don't expand any sub-objects. * entry_type : OM types to be extracted from Read-Result * OM_TRUE : convert any string value to ISO-Latin-1 * 0 : only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * 0 : only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * entry_object : the OM Object returned by om_get() * total_number : The number of attribute descriptors in the returned * OM Object (excluding the final descriptor). */ om_get_status = om_get(read_result, OM_EXCLUDE_ALL_BUT_THESE_TYPES|OM_EXCLUDE_SUBOBJECTS, entry_type, OM_TRUE, 0, 0, &entry_object, &total_number); if (om_get_status != OM_SUCCESS) { printf("om_get failed.\n"); return; } /***************************************************************************** * Display the Distinguished Name of the Entry which was read. * Firstly extract the DS-DN OM Object from the Entry-Information OM * Private Object. *****************************************************************************/ /* * Define the OM types of the OM Attributes that om_get() is to extract * from the Entry-Information OM Private Object. In this case, it's the * DS_OBJECT_NAME OM Attribute. */ name_type[0] = DS_OBJECT_NAME; name_type[1] = OM_NO_MORE_TYPES; /* * Call om_get() to extract the required information from the * Entry-Information OM Private Object. * Arguments: * entry_object->value.object.object : The Entry-Information OM * Private Object. 'entry_object' contains +-----------------------------------------------------------------------+ | DS_ENTRY | OM_S_OBJECT | ref to Entry-Info Pr.Obj.| +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUE | +-----------------------------------------------------------------------+ * * The Entry-Information OM Private Object is the value of the * DS_ENTRY attribute. The OM_value structure is defined in * XOM.H as * * typedef struct OM_descriptor_struct { * OM_type type; * OM_syntax syntax; * union OM_value_union value; * } OM_descriptor; * * typedef union OM_value_union { * OM_string string; * OM_boolean boolean; * OM_enumeration enumeration; * OM_integer integer; * OM_padded_object object; * } OM_value; * * typedef struct { * OM_uint32 padding; * OM_object object; * } OM_padded_object; * * So * entry_object->value.object.object * ^ ^ * ___| |____ * from OM_value from OM_padded_object * which is the actual * pointer to the object. * * OM_EXCLUDE_ALL_BUT_THESE_TYPES|OM_EXCLUDE_SUBOBJECTS : * extract only the OM types in name_type, * and don't expand any sub-objects. * name_type : OM types to be extracted from Entry-Information * OM_TRUE : convert any OM_string value to ISO-Latin-1 * 0 : only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * 0 : only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * object_name_object : the OM Object returned by om_get() * total_number : The number of attribute descriptors in the returned * OM Object (excluding the final descriptor). */ om_get_status = om_get(entry_object->value.object.object, OM_EXCLUDE_ALL_BUT_THESE_TYPES|OM_EXCLUDE_SUBOBJECTS, name_type, OM_TRUE, 0, 0, &object_name_object, &total_number); if (om_get_status != OM_SUCCESS) { printf("om_get failed.\n"); return; } /****************************************************************************** * Extract the RDNs from the Distinguished Name. om_get() is called * to extract the DS-RDN OM Objects from the DS-DN OM Private Object. ****************************************************************************/ /* * Define the OM types of the OM Attributes that om_get() is to extract * from the DS-DN OM Private Object. In this case, it's the DS_RDNS * OM Attribute. */ rdns_type[0] = DS_RDNS; rdns_type[1] = OM_NO_MORE_TYPES; /* * Call om_get() to extract the required information from the * DS-DN OM Private Object. * Arguments: * object_name_object->value.object.object : The DS-DN OM Private Object. * object_name_object contains +-----------------------------------------------------------------------+ | DS_OBJECT_NAME | OM_S_OBJECT | ref to DS-DN Private Obj.| +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUE | +-----------------------------------------------------------------------+ * * The DS-DN OM Private Object is the value of the DS_OBJECT_NAME OM * attribute. This value is accessed the same way as * entry_object is accessed above. * OM_EXCLUDE_ALL_BUT_THESE_TYPES|OM_EXCLUDE_SUBOBJECTS : * extract only the OM types in rdns_type, and don't expand any * sub-objects. * name_type : OM types to be extracted from Entry-Information * OM_TRUE : convert any string value to ISO-Latin-1 * 0 : only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * 0 : only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * rdns_object : the OM Object returned by om_get() * total_number : The number of attribute descriptors in the returned * OM Object (excluding the final descriptor). */ om_get_status=om_get(object_name_object->value.object.object, OM_EXCLUDE_ALL_BUT_THESE_TYPES | OM_EXCLUDE_SUBOBJECTS, rdns_type, OM_TRUE, 0, 0, &rdns_object, &total_number); if (om_get_status != OM_SUCCESS) { printf("om_get failed.\n"); return; } /* * Delete the object_name_object, which is no longer required. */ om_delete_status=om_delete(object_name_object); if (om_delete_status != OM_SUCCESS) { printf("om_delete failed.\n"); return; } printf("Distinguished Name:\n"); printf("------------------\n"); /* * The contents of rdns_object will be something like: * +-----------------------------------------------------------------------+ | DS_RDNS | OM_S_OBJECT | ref to DS-RDN Private Obj| +-----------------------------------------------------------------------+ | DS_RDNS | OM_S_OBJECT | ref to DS-RDN Private Obj| +-----------------------------------------------------------------------+ | . | | . | | . | +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUES | +-----------------------------------------------------------------------+ * * Step through the rdns_object, extracting the information * from the RDN object and display it. Use a pointer to step * through the object, and preserve the rdns_object value so * it can be deleted when no longer required. */ rdns_ptr = rdns_object ; while (rdns_ptr->type != OM_NO_MORE_TYPES) { /* * Call om_get() to extract the required information from the * DS-RDN OM Private Object. * Arguments: * rdns_ptr->value.object.object : The DS-RDN OM Public Object. * OM_NO_EXCLUSIONS : No exclusions. * 0 : Get all all types and values, including * sub-objects. * OM_TRUE :convert any string value to ISO-Latin-1 * 0 :only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * 0 :only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * avas_object:the OM Object returned by om_get() * total_number: The number of attribute descriptors in the returned * OM Object (excluding the final descriptor). */ om_get_status =om_get(rdns_ptr->value.object.object, OM_NO_EXCLUSIONS, 0, OM_TRUE, 0, 0, &avas_object, &total_number); if (om_get_status != OM_SUCCESS) { printf("om_get failed.\n"); return; } /* * The structure of avas_object will be * +-----------------------------------------------------------------------+ | OM_CLASS | OM_S_OBJECT_IDENT.. | ref to DS_C_RDN | +-----------------------------------------------------------------------+ | DS_AVAS | OM_S_OBJECT | ref to AVA Public Object | +-----------------------------------------------------------------------+ | . | +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUES | +-----------------------------------------------------------------------+ * * Get to the DS_AVAS OM Attribute in avas_object, and then * traverse the DS_AVA. * NOTE: This example only supports RDNs containing one AVA. * The X.500 Recommendations permit RDNs to contain * multiple AVAs. */ /* * Get the first AVA in the array if avas_object. It is the * second OM Attribute. Save the value of the object; it needs * to be deleted later on. */ saved_avas_object = avas_object; avas_object++ ; current_object=avas_object->value.object.object; /* * The structure of current_object is +-----------------------------------------------------------------------+ | OM_CLASS | OM_S_OBJECT_IDENT.. | ref to DS_C_ATTRIBUTE | +-----------------------------------------------------------------------+ | DS_ATTRIBUTE_TYPE | OM_S_OBJECT_IDENT.. | ref to a Attr. Type OID | +-----------------------------------------------------------------------+ | DS_ATTRIBUTE_VALUES |eg. OM_S_LOCAL_STRING| ref to Attr value;eg "US"| +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUES | +-----------------------------------------------------------------------+ * * Step through the Attribute OM Public Object, handling the * Attribute Type and Attribute Value. */ while (current_object->type != OM_NO_MORE_TYPES) { /* * Note we always have just one attribute value for an AVA. * It is just a special case of an Attribute OM Object. * Get a name for the attribute type. Call find_attr_name() * passing in the OM_string value for the Attribute Type's * Object Identifier. */ if (current_object->type == DS_ATTRIBUTE_TYPE) { find_attr_name(&(current_object->value.string), the_attr_name); } /* * Print the attributes value. * NOTE: This example only supports values of string syntax */ if (current_object->type == DS_ATTRIBUTE_VALUES) printf("/%s=%s", the_attr_name, current_object->value.string.elements); current_object++; } rdns_ptr++; } /* End of while loop */ /* * The Distinguished Name has now been processed. * Delete the rdns_object, which is no longer required. * */ om_delete_status=om_delete(rdns_object); if (om_delete_status != OM_SUCCESS) { printf("om_delete failed.\n"); return; } /* * Delete the object_name_object, which is no longer required. */ om_delete_status=om_delete(saved_avas_object); if (om_delete_status != OM_SUCCESS) { printf("om_delete failed.\n"); return; } /***************************************************************************** * Display the Telephone Number Attribute in the Entry. Call om_get() * to extract the Attribute OM Public Objects from the Entry-Information * Private Object. *****************************************************************************/ /* * Define the OM types of the OM Attributes that om_get() is to extract * from the Entry-Information OM Private Object. In this case, its the * DS_ATTRIBUTES OM Attribute. */ attributes_type[0] = DS_ATTRIBUTES; attributes_type[1] = OM_NO_MORE_TYPES; /* * Call om_get() to extract the required information. * Arguments: * entry_object->value.object.object : The Entry-Information OM * Private Object. * OM_EXCLUDE_ALL_BUT_THESE_TYPES : Only return the requested types * Note that all sub-objects will be expanded into OM Public Objects * as well. * attributes_type : Requested types of OM Attributes. * OM_TRUE :convert any string value to ISO-Latin-1 * 0 :only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * 0 :only present if we choose EXCLUDE_ALL_BUT_THESE_VALUES * attributes_object:the OM Object returned by om_get() * total_number: The number of attribute descriptors in the returned * OM Object (excluding the final descriptor). */ om_get_status = om_get(entry_object->value.object.object, OM_EXCLUDE_ALL_BUT_THESE_TYPES, attributes_type, OM_TRUE, 0, 0, &attributes_object, &total_number); if (om_get_status != OM_SUCCESS) { printf("om_get failed.\n"); return; } /* * Delete the entry_object, which is no longer required. */ om_delete_status=om_delete(entry_object); if (om_delete_status != OM_SUCCESS) { printf("om_delete failed.\n"); return; } printf("\n"); printf("ATTRIBUTES:\n"); printf("----------\n"); /* * The attributes_object contains * +-----------------------------------------------------------------------+ | DS_ATTRIBUTES | OM_S_OBJECT |ref to Attribute Public Obj| +-----------------------------------------------------------------------+ | DS_ATTRIBUTES | OM_S_OBJECT |ref to Attribute Public Obj| +-----------------------------------------------------------------------+ | . | +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES|OM_NO_MORE_VALUES | +-----------------------------------------------------------------------+ * * Each DS_ATTRIBUTES OM Descriptor represents an attribute * stored in the entry which was read from the Directory. * To find the Telephone Number Attribute, step through this object, * examine each Attribute OM Public Object, and determine whether it's * the Telephone Number attribtue. * Save the value of the attributes_object so that it can be * deleted when it's no longer required. */ saved_attributes_object = attributes_object; while ( attributes_object->type != OM_NO_MORE_TYPES) { current_object=attributes_object->value.object.object; /* * current_object points to a Attribute OM Public Object. * The contents of this Public Object is something like +-----------------------------------------------------------------------+ | OM_CLASS | OM_S_OBJECT_IDENT.. | ref to DS_C_ATTRIBUTE | +-----------------------------------------------------------------------+ | DS_ATTRIBUTE_TYPE | OM_S_OBJECT_IDENT.. | ref to a Attr. Type OID | +-----------------------------------------------------------------------+ | DS_ATTRIBUTE_VALUES |eg. OM_S_LOCAL_STRING| first attribute value | +-----------------------------------------------------------------------+ | DS_ATTRIBUTE_VALUES |eg. OM_S_LOCAL_STRING| further attribute values | +-----------------------------------------------------------------------+ | OM_NO_MORE_TYPES | OM_NO_MORE_SYNTAXES | OM_NO_MORE_VALUES | +-----------------------------------------------------------------------+ * If the Attribute Type is Telephone Number, print out the attribute * values. */ /* * The first descriptor is of type OM_CLASS which is not required. * Move to the next descriptor which is of type DS_ATTRIBUTE_TYPE. */ current_object++; /* * Is this one of the attributes we are intrested in? */ required_attribute = FALSE ; if (current_object->type == DS_ATTRIBUTE_TYPE) { if ( ObjectIdsMatch( &(current_object->value.string), &DS_A_PHONE_NBR ) ) { required_attribute = TRUE ; current_object++; } } /* * If the attribute is one that we are interested in then * print its value(s). */ if ( (current_object->type == DS_ATTRIBUTE_VALUES) && (required_attribute == TRUE) ) { printf("%s = %.*s\n", "Telephone Number", current_object->value.string.length, current_object->value.string.elements); current_object++; /* * If the attribute has multiple values then * print out those values as well. * NOTE: Only string values can be displayed. This program * does not support other attribute value syntaxes. */ while (current_object->type == DS_ATTRIBUTE_VALUES) { printf("%*c = %.*s\n", 16, ' ', current_object->value.string.length, current_object->value.string.elements); current_object++; } /* End of while loop */ } attributes_object++; } /* End of while loop */ /* * Delete the attributes_object, which is no longer required. */ om_delete_status=om_delete(saved_attributes_object); if (om_delete_status != OM_SUCCESS) { printf("om_delete failed.\n"); return; } printf("\n"); } static void find_attr_name(OM_string *attr_type, char *attr_name ) { /**************************************************************************** * This function takes an attribute type Object Identifier, and returns * a descriptive name for the Attribute Type. If the Attribute Type * is not known, it returns a default value. The caller passes in * a buffer, which is assumed to be long enough to contain the returned * length. ****************************************************************************/ if ( ObjectIdsMatch( attr_type, &DS_A_COUNTRY_NAME ) ) { strcpy(attr_name, "C"); } else if ( ObjectIdsMatch( attr_type, &DS_A_ORG_NAME ) ) { strcpy(attr_name, "O"); } else if ( ObjectIdsMatch( attr_type, &DS_A_ORG_UNIT_NAME ) ) { strcpy(attr_name, "OU"); } else if ( ObjectIdsMatch( attr_type, &DS_A_COMMON_NAME ) ) { strcpy(attr_name, "CN"); } else { strcpy(attr_name, "Unknown Attribute"); } return ; } static int ObjectIdsMatch( OM_string *objid1, OM_string *objid2 ) { /***************************************************************************** * This function compares two object identifiers, and returns TRUE if * they match, and FALSE if they do not. * The comparison consists of comparing the lengths of the Object Identifier. * If the lengths are identical, the values are compared to determine * whether they are the same. *****************************************************************************/ if ( objid1->length == objid2->length ) { if (memcmp(objid1->elements,objid2->elements,objid1->length) == 0) { return TRUE; } } return FALSE ; }