/* XDSHLI_PROCESS.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% */ /* **++ ** FACILITY: XDSHLI - extension to X.500 XDS/OM interface ** ** The XDS High Level Interface (XDSHLI) helps build XDS/OM applications ** by providing a set of useful services. XDSHLI complements the XDS/OM API ** by hiding some of its complexities, but allowing access to these ** features if they are required. ** ** See XDSHLI.H for more information. ** ** MODULE DESCRIPTION: ** ** This module contains those XDSHLI routines which are associated ** with processing results or errors of Directory operations. ** They are ** dsX_count_result_entries()- determines if result is complete ** dsX_get_result_entry() - extracts Entry-Information from Result ** dsX_find_entry_name() - finds name of Entry ** dsX_find_attribute() - finds a specified attribute in Entry ** dsX_find_next_attribute()- finds an attribute by index ** get_attr_info() - returns info about an attribute ** dsX_process_error() - returns information about an error ** get_error_class() - gets class of error ** ** XDSHLI.H contains the functionality description of these routines, ** and other related information. ** ** AUTHORS: ** ** IRD ** ** CREATION DATE: 7-Aug-1993 ** ** ** MODIFICATION HISTORY: ** ** 000 7-Aug-1993 IRD Creation ** 001 24-Aug-1993 IRD Implement process error and minor interface changes ** 002 2-Sep-1993 IRD Implement other routines ** 003 13-Oct-1993 CMB Minor changes to comments ** 004 19-Oct-1993 xl Added OM_EXCLUDE_VALUES in the exclusions argument ** in the call to om_get(). ** 005 12-Nov-1993 IRD Change include statements ** 006 19-Nov-1993 IRD Fix to dsX_process_error() ** 007 02-Feb-1994 IRD Fix to referral handling in dsX_process_error() ** 008 28-Sep-1995 LG ICO 916 Minor fix to compilation warning **-- */ /* ** ** INCLUDE FILES ** */ #include #include "xdshli.h" #include "xdshli_private.h" /* **++ ** Prototypes of static routines **-- */ static enum dsX_Error_Class get_error_class( OM_object err_object); static void get_attr_info( OM_public_object attribute, /* IN - Attribute OM obj */ OM_object_identifier ** type, /* OUT- attribute type(opt)*/ unsigned int * count, /* OUT- count of values */ OM_descriptor ** value ); /* OUT- ptr to first value */ /* **++ ** This table contains the error messages which are returned by ** dsX_process_error(). ** The table is an array to pointers to the strings, and is indexed ** by the value of the DS_PROBLEM OM enumneration value. **-- */ static char* dsX_problem_table[] = { /* NULL record; there is no DS_PROBLEM OM enumeration of value zero */ NULL, /* X.500 Service Error - administrativeLimitExceeded */ "DSA error: Administrative limit exceeded before operation could be completed.", /* X.500 Update Error - affectsMultipleDSAs */ "DSA error: Modification not made, because it affects several DSAs.", /* X.500 Name Error - aliasDereferencingProblem */ "DSA error: Alias entry detected where alias entries are not permitted.", /* X.500 Name Error - aliasProblem */ "DSA error: Alias points to nonexistent entry.", /* X.500 Attribute Error - attributeOrValueAlreadyExists */ "DSA error: Attribute or value already exists.", /* XDS Library Error - Bad argument */ "XDS Library Error: Bad argument.", /* XDS Library Error - Bad class */ "XDS Library Error: Bad class.", /* XDS Library Error - Bad context */ "XDS Library Error: Bad context.", /* XDS Library Error - Bad name */ "XDS Library Error: Bad name.", /* XDS Library Error - Bad Session */ "XDS Library Error: Invalid session information.", /* XDS Library Error - Bad workspace */ "XDS Library Error: Bad workspace.", /* X.500 Service Error - busy */ "DSA error: Directory Service busy. Please try later.", /* X.500 Service Error - cannotAbandon */ "DSA error: Abandon Failed: Cannot abandon.", /* X.500 Service Error - ChainingRequired */ "DSA error: Operation requires chaining.", /* Communication Problem */ "Communications error: Unable to communicate with the DSA.", /* X.500 Attribute Error - constraintViolation */ "DSA error: Constraint violation in an attribute.", /* X.500 Service Error - ditError */ "DSA error: DIT consistency error. \nDirectory Service unable to perform operation.", /* X.500 Update Error - entryAlreadyExists */ "DSA error: Entry already exists.", /* X.500 Security Error - InappropriateAuthentication */ "DSA error: Credentials supplied do not \nauthorize a suitable level of authentication for this operation.", /* X.500 Attribute Error - InappropriateMatching */ "DSA error: Matching requested not appropriate for an attribute.", /* X.500 Security Error - InsufficientAccessRights */ "DSA error: You have insufficient access rights for this request.", /* X.500 Attribute Error - InvalidAttributeSyntax */ "DSA error: An attribute has invalid syntax.", /* X.500 Name Error - invalidAtttributeValue */ "DSA error: Attribute syntax error in entry name.", /* X.500 Security Error - InvalidCredentials */ "DSA error: Invalid username or password.", /* X.500 Service Error - invalidReference */ "DSA error: Directory Service is unable to perform this command. \nInvalid reference supplied.", /* X.500 Security Error - InvalidSignature */ "DSA error: Signature of request is invalid.", /* X.500 Service Error - loopDetected */ "DSA error: Internal loop detected. Directory Service operation failed.", /* XDS Library error - Miscellaneous*/ "XDS Library error: Miscellaneous.", /* XDS Library error - Missing type. */ "XDS Library error: Missing type.", /* XDS Library error - Mixed synchronous. */ "XDS Library error: Mixed synchronous.", /* X.500 Update Error - namingViolation */ "DSA error: Entry not created or modified because of naming violation. \nEntry type invalid at this point in DIT.", /* X.500 Security Error - noInformation */ "DSA error: Security error. Request not carried out.", /* X.500 Attribute Error - noSuchAttributeOrValue */ "DSA error: The attribute or value does not exist.", /* X.500 Name Error - noSuchObject */ "DSA error: No such entry exists.", /* X.500 Abandon Error - No such operation. */ "DSA error: Abandon Failed: No such operation.", /* X.500 Update Error - notAllowedOnNonLeaf, */ "DSA error: Modification not made. Request only valid for \nentries with no subordinate entries.", /* X.500 Update Error - notAllowedOnRDN */ "DSA error: Entry not modified. Modification would change entry name.", /* XDS Library Error - Not supported.*/ "XDS Library Error: Not supported.", /* X.500 Update Error - objectClassModificationProhibited */ "DSA error: Modification not made. Object class attribute may not be changed.", /* X.500 Update Error - objectClassViolation */ "DSA error: Entry not created or modified because of object class violation. \nResultant entry would be invalid for entry type.", /* X.500 Service Error - outOfScope */ "DSA error: No information available within requested scope.", /* X.500 Security Error - protectionRequired */ "DSA error: Requested operation requires signed argument.", /* X.500 Service Error - timeLimitExceeded */ "DSA error: Time limit exceeded before operation could be completed.", /* Abandon Error : Too late. */ "DSA error: Abandon Failed: Too late.", /* XDS Library Error: too many operations */ "XDS Library error: Too many operations.", /* XDS Library Error: too many sessions */ "XDS Library error: Too many sessions.", /* X.500 Service Error - unableToProceed */ "DSA error: DSA is unable to proceed. \nDSA does not have access to this information.", /* X.500 Service Error - unavailable */ "DSA error: Directory Service unavailable. Please try later.", /* X.500 Service Error - unavailableCriticalExtension */ "DSA error: Directory Service unable to perform this command. \nCritical extension unavailable.", /* X.500 Attribute Error - undefinedAttributeType */ "DSA error: The attribute type is undefined.", /* X.500 Service Error - unwillingToPerform */ "DSA error: Directory Service unwilling to perform requested operation.", /* Digital Extensions to Communication Errors */ "Communications error: Unable to transmit data to the DSA.", "Communications error: Unable to receive data from the DSA.", "Communications error: Association with the DSA has been aborted.", "Communications error: The DSA rejected association establishment.", "Communications error: Unexpected communications event.", "Communications error: Unable to decode the response from the DSA.", "Communications error: The DSA has returned a bad invoke id.", "Communications error: No memory.", "Communications error: ROSE reject.", "Communications error: ROSE invoke problem." } ; /* **++ ** This routine returns the number of results and a flag indicating ** whether the given search results are complete. ** ** See XDSHLI.H for more information. **-- */ extern void dsX_count_result_entries( OM_private_object result, /* IN - search result */ unsigned int * count, /* OUT - number of entries in result*/ unsigned int * is_complete /* OUT - if results are complete*/ ) { OM_public_object ds_search_info, ds_entries; OM_value_position ds_search_info_num, ds_entries_num ; OM_type ds_search_info_type[] = { DS_SEARCH_INFO, OM_NO_MORE_TYPES } ; OM_type ds_entries_type[] = { DS_ENTRIES, DS_PARTIAL_OUTCOME_QUAL, OM_NO_MORE_TYPES } ; *count = 0; *is_complete = TRUE ; /* * Extract the Search-Info OM object from the given Search-Result. * The exclusions specify that only the DS_SEARCH_INFO OM Attribute * is to be returned, and its sub-objects are to be private, not public. */ if ( OM_STATUS_OK(om_get(result, ( OM_EXCLUDE_SUBOBJECTS | OM_EXCLUDE_ALL_BUT_THESE_TYPES), ds_search_info_type, OM_TRUE, 0, 0, &ds_search_info, &ds_search_info_num)) ) { /* * This design assumes that the results are correlated, and that * there are no Uncorrelated Results. * * Extract the requested OM descriptors which are of type * DS_ENTRIES and DS_PARTIAL_OUTCOME_QUAL. * * Only the types are required for this operation, so exclude the * values. [004] */ if ( ds_search_info_num == 1 && OM_STATUS_OK(om_get(ds_search_info->value.object.object, OM_EXCLUDE_ALL_BUT_THESE_TYPES | OM_EXCLUDE_VALUES, ds_entries_type, OM_TRUE, 0, 0, &ds_entries, &ds_entries_num)) ) { /* * Count the number of DS_ENTRY descriptors. */ *count = omX_count_om_types( ds_entries, DS_ENTRIES ); /* * Ihe Search-Results are incomplete if they contain a * Partial-Outcome-Qualifier. */ if (omX_count_om_types(ds_entries, DS_PARTIAL_OUTCOME_QUAL) > 0) { *is_complete = FALSE ; } /* * Delete the ds_entries OM public object - no longer required. */ OM_STATUS_OK( om_delete(ds_entries) ); } /* * Delete the ds_search_info OM public object - no longer required. */ OM_STATUS_OK( om_delete(ds_search_info) ); } } /* dsX_get_result_entry() **++ ** ** This routine extracts the requested Entry-Information OM object ** from the given Search-Result OM private object and returns it. ** ** See XDSHLI.H for more information. **-- */ extern OM_public_object dsX_get_result_entry( OM_private_object result, /* IN - search result */ OM_value_position *pos /* IN/MOD - entry to read, incremented on exit */ ) { OM_public_object ds_search_info, ds_entries, entry_info = NULL ; OM_value_position ds_search_info_num, ds_entries_num, desc_num ; OM_type ds_search_info_type[] = { DS_SEARCH_INFO, OM_NO_MORE_TYPES } ; OM_type ds_entries_type[] = { DS_ENTRIES, OM_NO_MORE_TYPES } ; /* * Extract the Search-Info OM object from the given Search-Result. * The exclusions specify that only the DS_SEARCH_INFO OM attribute * is to be returned, and its sub-objects are to be private, not public. */ if ( OM_STATUS_OK(om_get(result, ( OM_EXCLUDE_SUBOBJECTS | OM_EXCLUDE_ALL_BUT_THESE_TYPES), ds_search_info_type, OM_TRUE, 0, 0, &ds_search_info, &ds_search_info_num)) ) /* * This design assumes that the results are correlated, and that * there are no Uncorrelated Results. * * Extract the requested Entry Information OM object from the * Search-Info. * The exclusions specify that only the DS_ENTRIES OM Attribute is * required (which references the Entry-Information), and that a * specific value is required. * If the given value exceeds the number of Entry-Information OM * objects available, none is returned, which is the required behavior. */ { if ( ds_search_info_num == 1 && OM_STATUS_OK(om_get(ds_search_info->value.object.object, (OM_EXCLUDE_ALL_BUT_THESE_TYPES | OM_EXCLUDE_ALL_BUT_THESE_VALUES | OM_EXCLUDE_SUBOBJECTS), ds_entries_type, OM_TRUE, *pos, *pos + 1, &ds_entries, &ds_entries_num)) ) { /* * Make the Entry-Information OM object public, by calling * om_get(), passing the OM private object retrieved in * the above call. */ if ( ds_entries_num == 1 && OM_STATUS_OK(om_get(ds_entries->value.object.object, OM_NO_EXCLUSIONS, NULL, OM_TRUE, 0, 0, &entry_info, &desc_num)) ) { /* * The required Entry-Information OM object has been extraced. * Increment 'pos'. */ (*pos)++ ; } /* * Delete ds_entries OM object since it is no longer required. */ OM_STATUS_OK( om_delete(ds_entries) ) ; } /* * Delete ds_search_info OM object since it is no longer required. */ OM_STATUS_OK( om_delete(ds_search_info) ) ; } return entry_info ; } /* dsX_find_entry_name() **++ ** This function finds and returns the name of the entry referred ** to by the given Entry-Information OM object. **-- */ extern OM_public_object dsX_find_entry_name( OM_public_object entry /* IN - entry-information */ ) { OM_descriptor *obj_name_desc ; /* * The name of the entry is indicated by the DS_OBJECT_NAME * OM Attribute, so find this in the Entry-Information OM object * and return the object it references, which is the name of the entry. */ obj_name_desc = omX_find_om_type( entry, DS_OBJECT_NAME ) ; return( obj_name_desc->value.object.object ) ; } /* dsX_find_attribute() **++ ** This routine finds the required attribute in the given Entry-Information ** OM object. **-- */ extern void dsX_find_attribute( OM_public_object entry, /* IN - in expanded entry */ OM_object_identifier * type, /* IN - attribute type */ unsigned int * count, /* OUT - count of values */ OM_descriptor ** value /* OUT - pointer to first value */ ) { OM_public_object attribute = NULL ; OM_descriptor * entry_info = entry, *attr_type ; *count = 0 ; *value = NULL ; /* * Search through the Entry-Information OM object for Attribute OM objects. * If the Attribute Type matches the requested type return the required * information, otherwise go to the next Attribute OM object. */ /* * Find the first occurance of DS_ATTRIBUTES (which references * the Attribute OM object). */ entry_info = omX_find_om_type( entry_info, DS_ATTRIBUTES ) ; if ( entry_info != NULL ) { /* * For each DS_ATTRIBUTES descriptor, determine whether its Attribute is * the one required. */ while ( attribute == NULL && entry_info->type == DS_ATTRIBUTES ) { /* * An Attibute OM object has been found. Find the OM Attribute * with type DS_ATTRIBUTE_TYPE. These are mandatory, so it * must exist. */ attr_type = omX_find_om_type(entry_info->value.object.object, DS_ATTRIBUTE_TYPE); /* * Compare the found attribute types with that which is required. */ if ( !omX_compare_om_strings(&(attr_type->value.string), type) ) { /* * This is not the attribute which is required. Increment * 'entry_info' to reference the next OM Attribute in the * Entry-Information object. This is the OM Attribute which * we continue the search from. */ entry_info++ ; } else { /* * This is the required attribute. */ attribute = entry_info->value.object.object ; } } if ( attribute != NULL ) { /* * We have the required attribute, return the required information. */ get_attr_info( attribute, NULL, count, value ) ; } } } /* **++ ** This routine finds and returns information about the attribute ** specified by the 'pos' parameter. ** ** See XDSHLI.H for more information. **-- */ extern void dsX_find_next_attribute( OM_public_object entry, /* IN - in expanded entry */ unsigned int * pos, /* IN/MOD - attribute pointer */ OM_object_identifier ** type, /* OUT - attribute type */ unsigned int * count, /* OUT - count of values */ OM_descriptor ** value /* OUT - pointer to first value */ ) { OM_descriptor * entry_info = entry; /* * Initialise the output parameters to NULL/zero. If the attribute * does not exist, these are the values that will be returned. */ *type = NULL ; *count = 0 ; *value = NULL ; /* * Find the first DS_ATTRIBUTES OM descriptor in the * Entry-Information OM object. */ entry_info = omX_find_om_type( entry, DS_ATTRIBUTES ) ; if ( entry_info != NULL ) { /* * Determine whether the value of 'pos' is valid, by comparing it with * the number of DS_ATTRIBUTES OM Attributes in the given OM object. */ if ( *pos < omX_count_om_types(entry_info, DS_ATTRIBUTES) ) { /* * Get the required information about the attribute, * increment 'pos', and return. */ get_attr_info( entry_info[*pos].value.object.object, type, count, value ) ; (*pos)++ ; } } } /* get_attr_info() **++ ** Given an Attribute OM public object, return the Attribute Type ** (if requested), the number of values, and the address of the first ** descriptor which is a value. **-- */ static void get_attr_info( OM_public_object attribute, /* IN - Attribute OM obj */ OM_object_identifier ** type, /* OUT- attribute type(opt)*/ unsigned int * count, /* OUT- count of values */ OM_descriptor ** value ) /* OUT- ptr to first value */ { OM_descriptor *attr_type; /* * Find the DS_ATTRIBUTE_TYPE if requested. */ if ( type != NULL ) { attr_type = omX_find_om_type( attribute, DS_ATTRIBUTE_TYPE ); *type = &(attr_type->value.string) ; } /* * Find the first Attribute Value in the Attribute OM object. * It is possible that there is no Attribute Value. Access Control in the * Directory can prevent values being returned. In this case * return the count parameter as zero, and value as an * address of a descriptor which does not have a 'type' field * of DS_ATTRIBUTE_VALUES. */ if ( (*value = omX_find_om_type(attribute, DS_ATTRIBUTE_VALUES))==NULL ) { *value = attribute ; } *count = omX_count_om_types( attribute, DS_ATTRIBUTE_VALUES) ; } /* dsX_process_error() **++ ** This routine processes information about a given error. ** ** See XDSHLI.H for a functional description. **-- */ extern void dsX_process_error( DS_status error, /* IN - error object */ enum dsX_Error_Class * error_class,/* OUT - class of error */ OM_enumeration * problem, /* OUT - problem code */ char ** text, /* OUT -text error message, if required */ char ** name /* OUT - text DN, if required,if available*/ ) { /* * The routine makes the Error OM object public, determines the class * of the Error OM Object and then extracts the problem code, and * uses this to lookup the error message. It also converts * name of the Diretory entry to text if appropriate. * Attribute-Error is a special case, because the Problem code * is contained in the Attribute-Problem sub-object. This is processed * separately, extracting the name, and the detecting the sub-object * which contains the problem code. * If the OM object is a Referral, control is returned to the * caller. */ OM_public_object error_object, public_error; OM_descriptor *name_desc, *problem_desc, *attr_problem_desc ; OM_value_position desc_no ; char * msg_text ; /* * If the optional output parameters are not NULL, initialize their * values to NULL. */ *problem = 0 ; if ( text != NULL ) { *text = NULL ; } if ( name != NULL ) { *name = NULL ; } /* * Determine the error class. */ *error_class = get_error_class( error ) ; /* * If the class of the OM Object is a Referral, return this status * back to the caller - no further information can be retreived. */ if ( *error_class == DSX_REFERRAL) { return ; } /* * Get a public copy of the private error object. */ if ( OM_STATUS_OK(om_get(error, OM_NO_EXCLUSIONS, NULL, OM_TRUE, 0, 0, &public_error, &desc_no)) ) { /* * Is the Error an Attribute-Error? */ if ( *error_class == DSX_ATTRIBUTE_ERROR ) { /* * The Error is an Attribute Error; get the name of the object * matched, and reference the Attribute-Problem OM Object to get * the Problem value. */ name_desc = omX_find_om_type( public_error, DS_OBJECT_NAME ) ; attr_problem_desc = omX_find_om_type( public_error, DS_PROBLEMS ); error_object = attr_problem_desc->value.object.object ; } else { /* * The top level OM Public Object contains the information required. */ error_object = public_error ; /* * Find the DS_MATCHED OM descriptor. This only exists in a * Name-Error. */ name_desc = omX_find_om_type( public_error, DS_MATCHED ) ; } /* * Find the DS_PROBLEM OM Attribute in the appropriate OM Public Object. */ problem_desc = omX_find_om_type( error_object, DS_PROBLEM ) ; *problem = problem_desc->value.enumeration ; if ( text != NULL ) { /* * If the caller requested an error message, lookup the message * in the table, and copy it to an allocated buffer. */ msg_text = dsX_problem_table[ problem_desc->value.enumeration ] ; *text = (char*)ALLOC_MEM( strlen(msg_text) + 1 ) ; if ( ALLOC_MEM_OK(*text) ) { strcpy( *text, msg_text ) ; } } /* * If the caller requested the name of the entry to be returned, * call dsX_dn_object_to_string() to convert the name to string format. */ if ( name != NULL ) { if ( name_desc != NULL ) { *name = dsX_dn_object_to_string( name_desc->value.object.object ) ; } } } return ; } /* get_error_class() **++ ** Given the Error Object, return the enumeration ** that indicates the class of the error. **-- */ static enum dsX_Error_Class get_error_class( OM_object err_object) { /* * Declare a local static table that maps Object Identifiers of types of * OM Error Classes to enumerations. The table is NULL terminated. * 'dsX_error_rec' defines the records of the table. */ typedef struct class_table { OM_object_identifier * om_class ; /* ptr to Obj-Ident of error */ enum dsX_Error_Class class ; /* enumeration of error */ } dsX_error_rec ; static dsX_error_rec dsX_class_table[] = { &(DS_C_ABANDON_FAILED), DSX_ABANDON_FAILED_ERROR, &(DS_C_ATTRIBUTE_ERROR), DSX_ATTRIBUTE_ERROR, &(DS_C_COMMUNICATIONS_ERROR), DSX_COMMUNICATIONS_ERROR, &(DS_C_LIBRARY_ERROR), DSX_LIBRARY_ERROR, &(DS_C_NAME_ERROR), DSX_NAME_ERROR, &(DS_C_REFERRAL), DSX_REFERRAL, &(DS_C_SECURITY_ERROR), DSX_SECURITY_ERROR, &(DS_C_SERVICE_ERROR), DSX_SERVICE_ERROR, &(DS_C_SYSTEM_ERROR), DSX_SYSTEM_ERROR, &(DS_C_UPDATE_ERROR), DSX_UPDATE_ERROR, NULL, 0 } ; unsigned int i = 0 ; OM_boolean matches ; /* * Step through each record in the table using om_instance() to * determine if the given object is equals the Object-Identifier in * the table. * The error can only be one these defined in the table, so the final * entry should never be reached. */ while ( dsX_class_table[i].om_class != NULL ) { OM_STATUS_OK( om_instance(err_object, *(dsX_class_table[i].om_class), &matches) ); if ( matches ) { return( dsX_class_table[i].class ) ; } i++ ; } }