/* XDSHLI_NAME.C V5.6-3 *%COPYRIGHT_START% * * Copyright Digital Equipment Corporation 1993. 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 handling Distinguished Names. ** They are ** dsX_dn_string_to_object() - creates an OM object from a string ** parse_dn() - parses a Distinguished Name ** parse_rdn() - parses a Relative-Distinguished-Name ** parse_ava() - parses an Attr-Value-Assertion ** parse_type() - parses an Attribute-Type ** parse_value() - parses an Attribute-Value ** parse_spaced_separator() - parses spaced separator ** parse_optional_spaces() - parses an optional-space ** trim_trailing_spaces() - trims trailing spaces from a token ** get_attribute_oid() - get Obj-Id for given Attribute Keyword ** char_member_of() - checks if char is member of current set ** compare_strings() - case-insensitive string comparison ** dsX_dn_object_to_string() - creates DN string from an OM object ** dn_object_to_string() - converts DS-DN OM public object to string ** process_rdn() - converts RDN OM object to string ** process_ava() - converts AVA OM object to string ** buf_create() - create buffer ** buf_append() - appends to buffer ** buf_delete() - deletes buffer ** buf_trim() - trims buffer ** get_attribute_name() - gets attribute type name for OID ** ** XDSHLI.H contains the functionality description of the external ** 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 Implemented dsX_dn_string_to_object(). ** 002 1-Sep-1993 IRD Implement dsX_dn_object_to_string(), & other changes ** 003 13-Oct-1993 CMB Minor changes to comments ** 004 12-Nov-1993 IRD Change include statements **-- */ /* **++ ** INCLUDE FILES **-- */ #include #include #include "xdshli.h" #include "xdshli_private.h" /* **++ ** Error messages **-- */ #define EXPECTED_EQUALS_ERROR \ "Equals expected after Attribute Type but not found." #define EXPECTED_TYPE_ERROR "Attribute Type expected but not found." #define EXPECTED_VALUE_ERROR "Attribute Value expected but not found." #define EXPECTED_SEPARATOR_ERROR "Separator expected but not found." #define UNKNOWN_TYPE_ERROR "Attribute Type is unknown." #define PROCESSING_ERROR "Error processing Distinguished Name." /* **++ ** Characters and sets of characters which are significant in the name ** syntax described in XDSHLI.H, used in parsing the string format. **-- */ #define EQUALS '=' #define PLUS '+' typedef struct { char* characters ; /* Sequence of characters */ unsigned int char_count ; /* No. of characters */ } char_list_t ; #define OPTIONAL_SPACES_SET " \n" /* space, */ #define SEPARATORS_SET ",;" /* comma, semi-colon */ #define SPECIAL_CHARS_SET ",=\"\n+<>#;" /* comma, equals, double-quotes, , +, open and closed angled brackets, hash, semi-colon */ static char_list_t optional_spaces = { OPTIONAL_SPACES_SET, sizeof( OPTIONAL_SPACES_SET ) -1 } ; #define OPTIONAL_SPACES &optional_spaces static char_list_t special_chars = { SPECIAL_CHARS_SET, sizeof( SPECIAL_CHARS_SET ) -1 } ; #define SPECIAL_CHARS &special_chars static char_list_t separators = { SEPARATORS_SET, sizeof( SEPARATORS_SET ) -1 } ; #define SEPARATORS &separators /* **++ ** Strings which are significant in the name ** syntax described in XDSHLI.H, used in generating the string format. **-- */ #define BUF_LEN 256 #define RDN_SEPARATOR ", " #define RDN_SEPARATOR_LEN strlen(RDN_SEPARATOR) #define AVA_SEPARATOR " + " #define AVA_SEPARATOR_LEN strlen(AVA_SEPARATOR) #define EQUALITY "=" #define EQUALITY_LEN strlen(EQUALITY) #define DEFAULT_ATTRIBUTE_NAME "Unknown Attribute" /* **++ ** Prototypes of static routines **-- */ static unsigned int parse_dn( OM_workspace workspace, /* IN - Workspace */ OM_private_object dn_object, /* IN/MOD - dist. name */ char ** cur_pos, /* IN/MOD - addr of dn element */ char ** message ); /* OUT - message if error */ static unsigned int parse_rdn( OM_workspace workspace, /* IN - workspace */ OM_private_object dn_object, /* IN/MOD - DS-DN OM Object */ char ** cur_pos, /* IN/MOD - ptr to rdn start */ char ** message ); /* OUT - message if error */ static unsigned int parse_ava( OM_private_object rdn_object, /* IN/MOD - RDN OM object */ char ** cur_pos, /* IN/MOD - current pos in string*/ char ** message ); /* OUT - message if error */ static unsigned int parse_type( char ** cur_pos, /* IN/MOD - postion in string */ char ** type, /* OUT - start of type token */ unsigned int * length, /* OUT - length of type token */ char ** message ); /* OUT - message if error */ static unsigned int parse_value( char ** cur_pos, /* IN/MOD - position in string */ char ** value, /* OUT - start of value */ unsigned int * length, /* OUT - length of value */ char ** message ); /* OUT - message if error */ static unsigned int parse_spaced_separator( char ** cur_pos, /* IN/MOD - position in string */ char ** message); /* OUT - message if error */ static void parse_optional_spaces( char ** cur_pos ); static unsigned int trim_trailing_spaces( char * token_start, /* IN - start of token */ unsigned int length ); /* IN - current token length */ static OM_object_identifier *get_attribute_oid( char * type_keyword, /* IN - keyword string */ unsigned int keyword_len, /* IN - keyword length */ OM_enumeration * value_syntax);/* OUT- syntax of value */ static unsigned int char_member_of( char * cur_pos, /* IN - character to match*/ char_list_t * char_list ); /* IN - set of char to matched */ static unsigned int compare_strings( char * string1, /* IN - keyword string */ char * string2, /* IN - keyword length */ unsigned int count ); /* OUT- syntax of value*/ static char* dn_object_to_string( OM_public_object name ); /* IN - public name object */ static unsigned int process_rdn( OM_public_object rdn_object, /* IN - DS-RDN public object*/ char ** buffer, /* IN/MOD - working buffer */ unsigned int * buf_len ); /* IN/MOD - buffer length */ static unsigned int process_ava( OM_public_object ava_object, /* IN - AVA OM public object*/ char ** buffer, /* IN/MOD - working buffer */ unsigned int * buf_len ); /* IN/MOD - buffer length */ static unsigned int buf_create( char ** buffer, /* IN/MOD - buffer to create */ unsigned int initial_length);/*IN - length of buffer */ static unsigned int buf_append( char ** buffer, /* IN/MOD - buffer*/ unsigned int * buf_len, /* IN/MOD - ptr to buffer length*/ char * string, /* IN - string to be appended */ unsigned int string_len); /* IN - length of string */ static void buf_delete( char ** buffer); /* IN/MOD- buffer to deallocate */ static unsigned int buf_trim( char ** buffer, /* IN/MOD - buffer */ unsigned int * buf_len); /* IN/MOD - buffer len */ static char* get_attribute_name( OM_object_identifier *attr_type_oid);/* IN - attr type oid */ /* **++ ** This table maps between Attribute Type keywords and Object Identifiers. ** The final record is NULLs to indicate the end of the table. ** The syntax field indicates the encoded syntax of the Attribute Value. **-- */ static struct { char * keyword ; OM_object_identifier * oid ; OM_enumeration value_syntax ; } attr_type_table[] = { /* CountryName */ "C" , &(DS_A_COUNTRY_NAME), OM_S_PRINTABLE_STRING, /* CommonName */ "CN", &(DS_A_COMMON_NAME), OM_S_TELETEX_STRING, /* OrganizationName */ "O" , &(DS_A_ORG_NAME), OM_S_TELETEX_STRING, /* OrganizationalUnitName */ "OU", &(DS_A_ORG_UNIT_NAME),OM_S_TELETEX_STRING, /* LocalityName */ "L" , &(DS_A_LOCALITY_NAME),OM_S_TELETEX_STRING, /* StateOrProvinceName */ "ST", &(DS_A_STATE_OR_PROV_NAME), OM_S_TELETEX_STRING, /* End of table */ NULL, NULL, OM_S_NO_MORE_SYNTAXES } ; /* dsX_dn_string_to_object() **++ ** This routine converts a Distinguished Name in a string ** to an DS-DN OM Private Object. See XDSHLI.H for more information. **-- */ extern OM_private_object dsX_dn_string_to_object( OM_workspace workspace, /* IN - workspace */ char * name, /* IN - null-terminated string */ char ** error_text, /* OUT - pointer to error text */ unsigned int * pos) /* OUT - index to error position */ { OM_private_object dn_object = NULL ; char* cur_pos, *message = NULL ; /* * Create the DN object. */ if (OM_STATUS_OK( om_create(DS_C_DS_DN, OM_FALSE, workspace, &dn_object )) ) { /* * If the string is NULL, or just contains a NULL byte, it is assumed to * be the root entry */ if ( name != NULL && !CHAR_MATCH(*name, EOS) ) { /* * The name contains characters to be processed */ cur_pos = name ; if ( !parse_dn(workspace, dn_object, &cur_pos, &message) ) { /* * An error was detected. Delete the DN OM Object, and return * the message in an allocated buffer, and the address in the * string where the error was detected, if requested by the * caller. */ OM_STATUS_OK( om_delete(dn_object) ) ; dn_object = NULL ; if ( pos != NULL ) { /* * Calculate the position of the error in the string */ *pos = cur_pos - name ; } if ( error_text != NULL ) { if ( message == NULL ) { /* * If an error was detected by no message returned, * return a catch-all */ message = PROCESSING_ERROR ; } /* * Allocate a return buffer, and copy the message into it */ *error_text = (char*)ALLOC_MEM( strlen(message)+1 ) ; if ( ALLOC_MEM_OK(*error_text) ) { strcpy( *error_text, message ) ; } } } } } return dn_object ; } /* parse_dn() **++ ** This function the converts a Distinguished Name in the given string ** to a DS-DN OM Private Object. ** The format of the Distinguished Name must conform to the ** grammar defined in XDSHLI.H. ** This routine parses the components of the null-terminated string ** indicated by 'cur_pos'. If the string is valid, the status TRUE is ** returned with the generated DS-DN OM Private Object. ** If the string cannot be converted a OM Private Object, ** FALSE is returned, with a message describing the problem, and ** 'cur_pos' is modified to point to the character in the string where ** the problem was detected. **-- */ static unsigned int parse_dn( OM_workspace workspace, /* IN - Workspace */ OM_private_object dn_object, /* IN/MOD - dist. name */ char ** cur_pos, /* IN/MOD - addr of dn element */ char ** message ) /* OUT - message if error */ { /* * Skip any optional spaces at the start of the string. */ parse_optional_spaces(cur_pos) ; /* * cur_pos should now point to the start of the first RDN. * Process each RDN and their separators. */ do { if ( parse_rdn(workspace, dn_object, cur_pos, message) ) { /* * RDN successfully parsed. If this is end of string, then * return, otherwise parse the . */ if ( !CHAR_MATCH(**cur_pos ,EOS) ) /* EOS is permitted */ { if ( !parse_spaced_separator(cur_pos, message) ) { return FALSE ; } } } else { return FALSE; } } while( !CHAR_MATCH(**cur_pos, EOS) ) ; return TRUE ; } /* parse_rdn() **++ ** This function parses an RDN, and inserts the RDN into the DS-DN OM ** Object. ** The RDN component starts at the input value of 'cur_pos'. ** If the RDN component is parsed successfully, TRUE is returned, ** with 'cur_pos' modified to point to the first character which ** terminates the RDN. ** If an error is detected parsing the string, FALSE is returned, ** with a message describing the error, and 'cur_pos' modified ** to the position in the string where the error was detected. **-- */ static unsigned int parse_rdn( OM_workspace workspace, /* IN - workspace */ OM_private_object dn_object, /* IN/MOD - DS-DN OM Object */ char ** cur_pos, /* IN/MOD - ptr to rdn start */ char ** message ) /* OUT - message if error */ { OM_private_object rdn_object ; unsigned int ok = FALSE ; OM_descriptor rdn_desc[2] ; /* * Create DS-RDN OM Private Object */ if ( OM_STATUS_OK(om_create(DS_C_DS_RDN, OM_FALSE, workspace, &rdn_object)) ) { if ( ok = parse_ava(rdn_object, cur_pos, message) ) { while( CHAR_MATCH(**cur_pos, PLUS) && ok ) { /* * This RDN contains multiple AVAs. Point to the next character, * process any optional spaces, and parse the AVA. */ CHAR_NEXT(*cur_pos) ; parse_optional_spaces(cur_pos) ; ok = parse_ava( rdn_object, cur_pos, message ) ; } } if ( ok ) { /* * If no error, insert this RDN into the DN. * Initialise an OM_public_object to contain the DS_RDNS OM attribute * referencing the rdn_object. * * The order of the RDNs in the DS-DN OM Object is significant. The * most significant RDN must be occur first in the sequence of RDNs. * The RDNs are ordered least-significant to most-significant in the * string, so as each RDN is parsed, it is inserted at the beginning * of the DS-DN OM Object. */ OMX_OBJECT_DESC(rdn_desc[0], DS_RDNS, rdn_object) ; OMX_OM_NULL_DESC(rdn_desc[1]) ; if ( !OM_STATUS_OK(om_put(dn_object, OM_INSERT_AT_BEGINNING, rdn_desc, NULL, 0, 0)) ) { ok = FALSE ; } } /* * Delete the RDN object which was created at the top of the routine */ OM_STATUS_OK(om_delete(rdn_object)) ; } return( ok ) ; } /* parse_ava() **++ ** This function parses an AVA and returns the RDN OM Object modified ** with the value of the AVA. ** 'cur_pos' indicates the start of the component in the grammar ** defined in XDSHLI. ** If the string is parsed successfully, TRUE is returned, with the ** modified RDN OM Object, and 'cur_pos' pointing to an AVA terminator. ** If the RDN OM Object cannot be parsed then FALSE is returned, ** with an message explaining the error, and 'cur_pos' modified to ** point to the problem in the string. ** **-- */ static unsigned int parse_ava( OM_private_object rdn_object, /* IN/MOD - RDN OM object */ char ** cur_pos, /* IN/MOD - current pos in string*/ char ** message ) /* OUT - message if error */ { char *type, *value ; unsigned int type_len, value_len ; OM_descriptor AVA[4] ; OM_descriptor RDN_desc[2] ; OM_object_identifier *type_oid ; OM_enumeration value_syntax ; /* * The first character should be the start of the type token. * Parse this, and then the value token. */ if ( parse_type(cur_pos, &type, &type_len, message) ) { if ( CHAR_MATCH(**cur_pos, EQUALS) ) { /* * Type has been parsed. Determine its Object-Identifier value, * or return an error if the type is unknown */ if ( (type_oid = get_attribute_oid(type, type_len, &value_syntax)) == NULL) { *message = UNKNOWN_TYPE_ERROR ; } else { /* * The type is known. Now parse the value. */ CHAR_NEXT( *cur_pos ) ; parse_optional_spaces( cur_pos ) ; if ( parse_value(cur_pos, &value, &value_len, message) ) { /* * The type and value have been extracted. Insert the * AVA into the RDN OM Object. Set up a RDN OM Public * object, which references the AVA OM Public Object * that contains the type and value. */ OMX_CLASS_DESC( AVA[0], DS_C_AVA ) ; OMX_ATTR_TYPE_DESC( AVA[1], DS_ATTRIBUTE_TYPE, *type_oid ) ; OMX_STRING_DESC( AVA[2], (OM_S_LOCAL_STRING | value_syntax) , DS_ATTRIBUTE_VALUES, value, value_len ); OMX_OM_NULL_DESC( AVA[3] ) ; OMX_OBJECT_DESC( RDN_desc[0], DS_AVAS, AVA ) ; OMX_OM_NULL_DESC( RDN_desc[1] ) ; if ( OM_STATUS_OK(om_put(rdn_object, OM_INSERT_AT_END, RDN_desc, NULL, 0, 0)) ) { return TRUE ; } } } } else { *message = EXPECTED_EQUALS_ERROR ; } } return FALSE ; } /* parse_type() **++ ** This function returns an attribute type keyword token from ** the given string. ** 'cur_pos' indicates the start of the component in the ** grammar defined in XDSHLI.H. This is the type of the attribute. ** If the type is parsed successfully, TRUE is returned, with the address ** of start of the type token, and its length, stripped of any trailing ** spaces, and 'cur_pos' modified to point to the terminator of the ** type. ** If there was an error, FALSE is returned, with a message ** explaining the error, and 'cur_pos' modified to indicate ** where in the string the error was detected. ** **-- */ static unsigned int parse_type( char ** cur_pos, /* IN/MOD - postion in string */ char ** type, /* IN/MOD - start of type token */ unsigned int * length, /* IN/MOD - length of type token */ char ** message ) /* OUT - message if error */ { /* * First character should be start of type. If not report an error, * otherwise return the type. */ *type = *cur_pos ; while ( !char_member_of(*cur_pos, SPECIAL_CHARS) && !CHAR_MATCH(**cur_pos, EOS) ) { /* * Character is not a terminator of the 'type' token, nor the * end of the string, so move to the next character in the string. */ CHAR_NEXT( *cur_pos ) ; } if ( *type < *cur_pos ) { /* * At least one valid character of a 'type' token was found. * Calculate the length of the token, and then trim off any trailing * spaces. */ *length = *cur_pos - *type ; *length = trim_trailing_spaces( *type, *length ) ; return TRUE ; } else { /* * First character was not valid; return an error. */ *message = EXPECTED_TYPE_ERROR ; return FALSE; } } /* parse_value() **++ ** This function returns the value element from the string. ** 'cur_pos' indicates the start of the value in the string. ** If the value is successfully parsed, TRUE is returned, with the address ** of the start of the value, and the length of the value (trimmed of ** any trailing spaces), and 'cur_pos' modified to point to the ** separator. ** If the value is not detected, FALSE is returned, with a message ** indicating the error, and 'cur_pos' modified to point to where ** the error was detected in the string. ** **-- */ static unsigned int parse_value( char ** cur_pos, /* IN/MOD - position in string */ char ** value, /* IN/MOD - start or value */ unsigned int * length, /* IN/MOD - length of value */ char ** message ) /* OUT - message if error */ { *value = *cur_pos ; /* * If the first character is not a terminator, then it is the * start of a valid value. Proceed along the string until a terminator * is detected. */ while ( !char_member_of(*cur_pos, SPECIAL_CHARS) && !CHAR_MATCH(**cur_pos, EOS) ) { /* * This character is not a 'value' token terminator, so check the * next character. */ CHAR_NEXT(*cur_pos) ; } if ( *value < *cur_pos ) { /* * There is at least one valid character in the 'value' token. * Calculate its length and trim of any trailing spaces. */ *length = *cur_pos - *value ; *length = trim_trailing_spaces( *value, *length ) ; return TRUE ; } else { /* * First character was not valid ; return an error */ *message = EXPECTED_VALUE_ERROR ; return FALSE; } } /* parse_spaced_separator() **++ ** This function parses a element as defined in the ** grammar defined in XDSHLI.H. ** This function return TRUE if the separator is processed correctly, ** with 'cur_pos' modified to point to the start of the next element. ** If the separator cannot be parsed, FALSE is returned, with a message ** describing the error, and 'cur_pos' modified to point to the ** error in the string. **-- */ static unsigned int parse_spaced_separator( char ** cur_pos, char ** message) { /* * Process the optional spaces, the separator, and any further optional * spaces. */ parse_optional_spaces( cur_pos ) ; if ( char_member_of(*cur_pos, SEPARATORS) ) { /* * Separator found - move to the next character. */ CHAR_NEXT(*cur_pos); parse_optional_spaces( cur_pos ) ; return TRUE ; } else { *message = EXPECTED_SEPARATOR_ERROR ; return FALSE ; } } /* parse_optional_spaces() **++ ** This function parses optional spaces, and returns when a non-space ** is detected, with 'cur_pos' referencing it. ** **-- */ static void parse_optional_spaces( char ** cur_pos ) { while ( char_member_of( *cur_pos, OPTIONAL_SPACES ) ) { CHAR_NEXT(*cur_pos) ; } } /* trim_trailing_spaces() **++ ** Given a token, this routine trims any trailing spaces, and return ** the shortened length. **-- */ static unsigned int trim_trailing_spaces( char * token_start, /* IN - start of token */ unsigned int length ) /* IN - current token length */ { /* * Setup 'pos' to point to last character in the string */ char * pos = token_start + length - 1 ; /* * Step back through the string until a non-space is found */ while ( char_member_of( pos, OPTIONAL_SPACES ) && pos >= token_start ) { CHAR_PREV(pos) ; } /* * Return the length of the trimmed string */ return( pos - token_start + 1 ) ; } /* char_member_of() **++ ** This function determines whether the given character matches ** a member of the given set of characters. ** If a match is found, TRUE is returned, otherwise FALSE is returned. **-- */ static unsigned int char_member_of( char * cur_pos, /* IN - address of character to match */ char_list_t *char_set ) /* IN - list of characters to be matched */ { unsigned int i ; /* * See if the character matches any of the characters in the given set. */ for ( i = 0 ; i < char_set->char_count ; i++ ) { if ( CHAR_MATCH( *cur_pos, char_set->characters[i] ) ) { return TRUE ; } } return FALSE ; } /* get_attribute_oid() **++ ** This function takes a keyword representing an attribute type, ** and returns the address of that type's Object Identifer and its ** syntax, or NULL if it cannot be matched. **-- */ static OM_object_identifier *get_attribute_oid( char * type_keyword, /* IN - keyword string */ unsigned int keyword_len, /* IN - keyword length */ OM_enumeration * value_syntax ) /* OUT- syntax of value*/ { /* * Given the keyword, step through the table attempting a case-insensitive * match. If the end of the table is reached without a successful match, * return NULL. */ unsigned int i = 0 ; while ( attr_type_table[i].keyword != NULL ) { /* * If the size of the given type is the same as this entry in the * table, and they have the same values, return the address of the * corresponding object identifier. */ if ( (strlen(attr_type_table[i].keyword) == keyword_len) && compare_strings(attr_type_table[i].keyword, type_keyword, keyword_len) ) { *value_syntax = attr_type_table[i].value_syntax ; return( attr_type_table[i].oid ) ; } i++ ; } return NULL ; } /* compare_strings() **++ ** This function returns TRUE if the strings are equivalent ignoring ** case, otherwise FALSE. **-- */ static unsigned int compare_strings( char * string1,/* IN - keyword string */ char * string2,/* IN - keyword length */ unsigned int count ) /* OUT- syntax of value*/ { unsigned int i = 0, matching = TRUE ; /* * Compare the upper case value of each character until all checked * or a non-equivalent character is detected. */ while ( i < count && matching ) { if ( toupper(string1[i]) != toupper(string2[i]) ) { matching = FALSE ; } i++ ; } return matching ; } /* dsX_dn_object_to_string() **++ ** This routine converts a Distinguished Name as a DS-DN OM Object to a ** string format. ** ** See XDSHLI.H for more information. **-- */ extern char * dsX_dn_object_to_string( OM_object name) /* IN - name object */ { char * name_string ; OM_value_position desc_no ; OM_public_object pub_name ; /* * Make the DS-DN OM object public if it is private. */ if ( name->syntax & OM_S_PRIVATE ) { if ( OM_STATUS_OK(om_get(name, OM_NO_EXCLUSIONS, NULL, OM_TRUE, 0, 0, &pub_name, &desc_no )) ) { /* * Convert the name to its string format, and then delete * the created OM public object. */ name_string = dn_object_to_string( pub_name ) ; OM_STATUS_OK( om_delete(pub_name) ) ; return( name_string ) ; } } else { /* * Name is an OM public object. Convert it to a string. */ return( dn_object_to_string(name) ) ; } } /* dn_object_to_string() **++ ** This function converts a DS-DN OM public object to a string ** representation. If the conversion succeeds, the string is returned ** in an allocated buffer, otherwise NULL is returned. If ** the Distinguished Name is the root entry, a buffer containing ** a single NULL byte is returned. **-- */ static char* dn_object_to_string( OM_public_object name ) /* IN - public name object */ { OM_descriptor *rdn_desc = name, *desc ; char * buffer = NULL ; unsigned int buf_len = BUF_LEN, rdn_count; /* * Create the working buffer. This is an allocated buffer with NULL * as the first character. */ if ( buf_create(&buffer, buf_len) ) { /* * Find the first RDN OM Attribute. If there are none, the DN is * the root entry. The string representation of the root entry * is a string containing just a NULL byte, which is what is in the * buffer, so there is no further processing to perform. */ if ( (rdn_desc = omX_find_om_type(rdn_desc, DS_RDNS)) != NULL ) { /* * There is at least one RDN in the Distinguished Name. * Process each of the RDNs in the Distinguished Name. * The order of the RDNs in the DS-DN OM object is most significant * to least significant. The string syntax of the Distinguished * Name requires the least significant RDN first. * So, find the last RDN descriptor and work backwards. */ /* * Find the last RDN descriptor */ rdn_count = omX_count_om_types( rdn_desc, DS_RDNS ) ; desc = rdn_desc + rdn_count -1 ; /* * All RDNs, except the last are to be terminated with a * RDN_SEPARATOR. So process the non-terminal RDNs first, backwards. */ while ( desc != rdn_desc ) { if (!process_rdn( desc->value.object.object, &buffer, &buf_len )) { /* * There was an error processing the DN. Delete the * buffer and return NULL */ buf_delete( &buffer ) ; return NULL ; } else { /* * The RDN has been processed, now add the RDN Separator. */ if ( !buf_append(&buffer, &buf_len, RDN_SEPARATOR, RDN_SEPARATOR_LEN) ) { /* * Error adding the RDN separator. */ buf_delete( &buffer ) ; return NULL ; } else { /* * Move back to the next RDN to be processed. */ desc-- ; } } } /* * Now add the final RDN. */ if (!process_rdn( desc->value.object.object, &buffer, &buf_len )) { /* * There was an error processing the DN. Delete the * buffer and return NULL. */ buf_delete( &buffer ) ; return NULL ; } } /* * The DN has been processed. Trim the length of the buffer * to the length of the string it contains. */ buf_trim( &buffer, &buf_len ) ; } return buffer ; } /* process_rdn() **++ ** This function appends the given RDN to the given buffer. If the ** RDN is processed successfully, TRUE is returned, with the ** buffer modified with the data, and possibly 'buf_len' modified ** if the buffer had to be extended. ** If there was an error, FALSE is returned, and the contents of ** the buffer are undefined. **-- */ static unsigned int process_rdn( OM_public_object rdn_object, /* IN - DS-RDN public object*/ char ** buffer, /* IN/MOD - working buffer */ unsigned int * buf_len ) /* IN/MOD - buffer length */ { OM_descriptor *ava_desc ; unsigned int ava_num, i ; /* * Find the AVA OM Attribute, and count the number of AVAs in the * RDN. */ ava_desc = omX_find_om_type(rdn_object, DS_AVAS) ; ava_num = omX_count_om_types(ava_desc, DS_AVAS ) ; /* * If there are two or more AVAs, they have to be separated by a * separator (for example ' + '). The final AVA is not terminated * with this separator, so add the intermediate AVAs and their separators. */ for ( i = 0 ; i < (ava_num - 1) ; i++ ) { if (process_ava( ava_desc->value.object.object, buffer, buf_len )) { /* * Added the AVA, now add the separator. */ if ( buf_append( buffer, buf_len, AVA_SEPARATOR, AVA_SEPARATOR_LEN) ) { /* * Move to the next separator. */ ava_desc++ ; } else { /* * Error adding separator. */ return FALSE ; } } else { /* * Error processing AVA, return FALSE. */ return FALSE ; } } /* * Add the final AVA without a separator. */ return( process_ava( ava_desc->value.object.object, buffer, buf_len ) ) ; } /* process_ava() **++ ** This function processes an AVA OM public object, appending the ** attribute type name and value to an existing string in the given ** buffer. ** If the AVA is processed successfully, TRUE is returned, with ** the buffer modified, and 'buf_len' modified if required. ** Otherwise FALSE is returned, with the contents of the buffer ** undefined. **-- */ static unsigned int process_ava( OM_public_object ava_object, /* IN - AVA OM public object*/ char ** buffer, /* IN/MOD - working buffer */ unsigned int * buf_len ) /* IN/MOD - buffer length */ { OM_descriptor *attr_type_desc, *attr_value_desc ; char * attr_type_name ; /* * Find the attribute type and append its descriptive name to the buffer. */ attr_type_desc = omX_find_om_type( ava_object, DS_ATTRIBUTE_TYPE ) ; /* * Get a descriptive name for the attribute type. */ attr_type_name = get_attribute_name( &attr_type_desc->value.string ) ; /* * The attribute value is the next descriptor in the OM public object. * This assumes that a value descriptor exists, which is a reasonable * assumption. */ attr_value_desc = attr_type_desc + 1 ; /* * Append the attribute name, the equality symbol, and the attribute * value (assumed to be a string) to the buffer. */ if ( buf_append(buffer, buf_len, attr_type_name, strlen(attr_type_name)) ) { if ( buf_append(buffer, buf_len, EQUALITY, EQUALITY_LEN) ) { if ( buf_append(buffer, buf_len, attr_value_desc->value.string.elements, attr_value_desc->value.string.length ) ) { return TRUE ; } } } /* * If control reaches here, there was a processing error. * Return FALSE. */ return FALSE ; } /* buf_create() **++ ** This function allocates a buffer of the requested size, ** and sets the first byte to NULL, and returns TRUE. If there ** is an error, then FALSE is returned. **-- */ static unsigned int buf_create( char ** buffer, unsigned int initial_length) { *buffer = (char*)ALLOC_MEM( initial_length ) ; if ( ALLOC_MEM_OK(*buffer) ) { /* * Buffer allocated OK. Set the first byte to NULL and return TRUE. */ **buffer = EOS ; return TRUE ; } else { /* * Unable to allocate buffer. */ return FALSE ; } } /* buf_append() **++ ** This function, appends the given string to the null-terminated ** string in the given buffer. ** If the length of the string is greater than the unused space in ** the buffer, the buffer is extended, and the value of 'buf_len' ** modified accordingly. If the function completes successfully TRUE is ** returned. Otherwise FALSE is returned. ** **-- */ static unsigned int buf_append( char ** buffer, /* IN/MOD - addr of ptr to buffer */ unsigned int * buf_len, /* IN/MOD - ptr to buffer length */ char * string, /* IN - string to be appended */ unsigned int string_len)/* IN - length of string */ { /* * Check if the buffer has to be reallocated. */ if ( string_len > (*buf_len - strlen(*buffer) -1) ) { /* * Double the size of the existing buffer. */ *buffer = (char*)REALLOC_MEM( *buffer, *buf_len * 2 ) ; if ( !ALLOC_MEM_OK(*buffer) ) { /* * Buffer reallocation failed. Return FALSE. */ return FALSE; } } /* * Append the given string to the string in the buffer. */ strncat( *buffer, string, string_len ) ; return TRUE ; } /* buf_delete() **++ ** This function deallocates the given buffer, and returns its address ** as NULL. ** **-- */ static void buf_delete( char ** buffer) /* IN/MOD - buffer to deallocate */ { DEALLOC_MEM( *buffer ) ; *buffer = NULL ; } /* buf_trim() **++ ** This function trims the length of the given buffer to just contain ** the null-terminated string. If this operation completes ** successfully TRUE is returned, with the modified buf_len parameter. ** Otherwise FALSE is returned. **-- */ static unsigned int buf_trim( char ** buffer, /* IN/MOD - buffer */ unsigned int * buf_len) /* IN/MOD - buffer len */ { /* * Calculate length required (including NULL terminator). */ *buf_len = strlen(*buffer) + 1 ; *buffer = (char*)REALLOC_MEM( *buffer, *buf_len ) ; if ( ALLOC_MEM_OK(*buffer) ) { return TRUE ; } else { return FALSE; } } /* get_attribute_name() **++ ** This function returns the address of a static string which ** contains the name of the attribute identified by the given ** OM_object_identifier value. If the value is not identified, ** the address of a static default string is returned. **-- */ static char* get_attribute_name( OM_object_identifier *attr_type_oid) /* IN - attr type oid */ { /* * Given the object-identifier of the attribute type, step through the table * attempting to match it. * If the end of the table is reached without a successful match, * return a pointer to default string. */ unsigned int i = 0 ; while ( attr_type_table[i].keyword != NULL ) { /* * Compare the given object identitifier against that in the table. */ if ( omX_compare_om_strings(attr_type_oid, attr_type_table[i].oid) ) { /* * They match; return the address of the descriptive name. */ return( attr_type_table[i].keyword ) ; } i++ ; } return DEFAULT_ATTRIBUTE_NAME ; }