/* **============================================================================== ** ** Open Management Infrastructure (OMI) ** ** Copyright (c) Microsoft Corporation ** ** Licensed under the Apache License, Version 2.0 (the "License"); you may not ** use this file except in compliance with the License. You may obtain a copy ** of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABLITY OR NON-INFRINGEMENT. ** ** See the Apache 2 License for the specific language governing permissions ** and limitations under the License. ** **============================================================================== */ #include #include "wsbuf.h" #include #include #include #include #include #include #include #include #include #include #if defined(WSBUF_DISABLE_INLINING) # include "wsbufinline.h" #endif #define T MI_T #if 0 #define ENABLE_TRACING #endif #ifdef ENABLE_TRACING #define PRINTF(a) printf a #else #define PRINTF(a) #endif #define XML_CR MI_T("\n") /* **============================================================================== ** ** Local datatypes: ** **============================================================================== */ typedef struct _BUF_FaultItem { const MI_Char* action; MI_Uint32 actionSize; const char* code; /* sender/receiver */ const char* subCode; /* wsa:XXX */ const char* defaultTest; } BUF_FaultItem; typedef struct _BUF_CIMErrorItem { WSBUF_FAULT_CODE faultCode; const MI_Char* description; } BUF_CIMErrorItem; /* **============================================================================== ** ** Forward declarations: ** **============================================================================== */ static MI_Result _PackInstance( WSBuf* buf, const MI_Instance* instance, MI_Boolean (*filterProperty)(const MI_Char* name, void* data), void* filterPropertyData, const MI_ClassDecl* castToClassDecl, MI_Uint32 flags, MI_Boolean embedded); static MI_Result _PackEPR( WSBuf* buf, const MI_Instance* instance); /* **============================================================================== ** ** Static data: ** **============================================================================== */ static const BUF_FaultItem s_faults[] = { /* WSBUF_FAULT_INTERNAL_ERROR */ { LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")), "SOAP-ENV:Receiver", "wsman:InternalError", "The service cannot comply with the request due to internal processing errors." }, /* WSBUF_FAULT_NOT_SUPPORTED */ { LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")), "SOAP-ENV:Sender", "wsman:UnsupportedFeature", "not supported" }, /* WSBUF_FAULT_NOT_UNDERSTOOD */ { LIT(MI_T("http://schemas.xmlsoap.org/ws/2004/08/addressing/fault")), "SOAP-ENV:MustUnderstand", 0, "Header not understood" }, /* WSBUF_FAULT_DESTINATION_UNREACHABLE */ { LIT(MI_T("http://schemas.xmlsoap.org/ws/2004/08/addressing/fault")), "SOAP-ENV:Sender", "wsa:DestinationUnreachable", "No route can be determined to reach the destination role defined by the Addressing To header." }, /* WSBUF_FAULT_ACCESS_DENIED */ { LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")), "SOAP-ENV:Sender", "wsman:AccessDenied", "The sender was not authorized to access the resource." }, /* WSBUF_FAULT_ENCODING_LIMIT */ { LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")), "SOAP-ENV:Sender", "wsman:EncodingLimit", "An internal encoding limit was exceeded in a request or would be violated if the message were processed." } }; static const BUF_CIMErrorItem s_cimerrors[] = { /* MI_RESULT_OK = 0, */ { 0, 0 }, /* MI_RESULT_FAILED = 1, */ { WSBUF_FAULT_INTERNAL_ERROR, MI_T("CIM ERROR:FAILED: A general error occurred, not covered by a more specific error code.") }, /* MI_RESULT_ACCESS_DENIED = 2, */ { WSBUF_FAULT_ACCESS_DENIED, MI_T("CIM ERROR:ACCESS_DENIED: Access to a CIM resource is not available to the client.") }, /* MI_RESULT_INVALID_NAMESPACE = 3, */ { WSBUF_FAULT_DESTINATION_UNREACHABLE, MI_T("CIM ERROR:INVALID_NAMESPACE: The target namespace does not exist.") }, /* MI_RESULT_INVALID_PARAMETER = 4,*/ { WSBUF_FAULT_INTERNAL_ERROR, MI_T("CIM ERROR:INVALID_PARAMETER: One or more parameter values passed to the method are not valid.") }, /* MI_RESULT_INVALID_CLASS = 5, */ { WSBUF_FAULT_DESTINATION_UNREACHABLE, MI_T("CIM ERROR:INVALID_CLASS: The specified class does not exist.") }, /* MI_RESULT_NOT_FOUND = 6,*/ { WSBUF_FAULT_DESTINATION_UNREACHABLE, MI_T("CIM ERROR:NOT_FOUND: The requested object cannot be found.") }, /* MI_RESULT_NOT_SUPPORTED = 7, */ { WSBUF_FAULT_NOT_SUPPORTED, MI_T("CIM ERROR:NOT_SUPPORTED: The requested operation is not supported.") } #if 0 /* The operation cannot be invoked because the class has subclasses. */ MI_RESULT_CLASS_HAS_CHILDREN = 8, /* The operation cannot be invoked because the class has instances. */ MI_RESULT_CLASS_HAS_INSTANCES = 9, /* The operation cannot be invoked because the superclass does not exist. */ MI_RESULT_INVALID_SUPERCLASS = 10, /* The operation cannot be invoked because an object already exists. */ MI_RESULT_ALREADY_EXISTS = 11, /* The specified property does not exist. */ MI_RESULT_NO_SUCH_PROPERTY = 12, /* The value supplied is not compatible with the type. */ MI_RESULT_TYPE_MISMATCH = 13, /* The query language is not recognized or supported. */ MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED = 14, /* The query is not valid for the specified query language. */ MI_RESULT_INVALID_QUERY = 15, /* The extrinsic method cannot be invoked. */ MI_RESULT_METHOD_NOT_AVAILABLE = 16, /* The specified extrinsic method does not exist. */ MI_RESULT_METHOD_NOT_FOUND = 17, /* The specified namespace is not empty. */ MI_RESULT_NAMESPACE_NOT_EMPTY = 20, /* The enumeration identified by the specified context is invalid. */ MI_RESULT_INVALID_ENUMERATION_CONTEXT = 21, /* The specified operation timeout is not supported by the CIM Server. */ MI_RESULT_INVALID_OPERATION_TIMEOUT = 22, /* The Pull operation has been abandoned. */ MI_RESULT_PULL_HAS_BEEN_ABANDONED = 23, /* The attempt to abandon a concurrent Pull operation failed. */ MI_RESULT_PULL_CANNOT_BE_ABANDONED = 24, /* Using a filter in the enumeration is not supported by the CIM server. */ MI_RESULT_FILTERED_ENUMERATION_NOT_SUPPORTED = 25, /* The CIM server does not support continuation on error. */ MI_RESULT_CONTINUATION_ON_ERROR_NOT_SUPPORTED = 26, /* The operation failed because server limits were exceeded. */ MI_RESULT_SERVER_LIMITS_EXCEEDED = 27, /* The CIM server is shutting down and cannot process the operation. */ MI_RESULT_SERVER_IS_SHUTTING_DOWN = 28 #endif }; /* Encodings for special XML characters */ static const char* s_specialCharEncodings[128] = { "\004�", "\004", "\004", "\004", "\004", "\004", "\004", "\004", "\004", "\004 ", "\005 ", "\005 ", "\005 ", "\005 ", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\005", "\001 ", "\001!", "\006"", "\001#", "\001$", "\001%", "\005&", "\006'", "\001(", "\001)", "\001*", "\001+", "\001,", "\001-", "\001.", "\001/", "\0010", "\0011", "\0012", "\0013", "\0014", "\0015", "\0016", "\0017", "\0018", "\0019", "\001:", "\001;", "\004<", "\001=", "\004>", "\001?", "\001@", "\001A", "\001B", "\001C", "\001D", "\001E", "\001F", "\001G", "\001H", "\001I", "\001J", "\001K", "\001L", "\001M", "\001N", "\001O", "\001P", "\001Q", "\001R", "\001S", "\001T", "\001U", "\001V", "\001W", "\001X", "\001Y", "\001Z", "\001[", "\001\\", "\001]", "\001^", "\001_", "\001`", "\001a", "\001b", "\001c", "\001d", "\001e", "\001f", "\001g", "\001h", "\001i", "\001j", "\001k", "\001l", "\001m", "\001n", "\001o", "\001p", "\001q", "\001r", "\001s", "\001t", "\001u", "\001v", "\001w", "\001x", "\001y", "\001z", "\001{", "\001|", "\001}", "\001~", "\006", }; /* This table idnetifies special XML characters. */ static const char s_specialChars[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, }; /* **============================================================================== ** ** Local definitions: ** **============================================================================== */ MI_INLINE MI_Boolean _Field_GetExists( const void* field, MI_Type type) { return Field_GetExists((const Field*)field, type); } static MI_Result _ReallocPage( WSBuf* buf, MI_Uint32 newSize) { Page* new_page; /* round up to next 1k */ #define WSMAN_BUF_CAPACITY 1024 newSize = ((newSize + WSMAN_BUF_CAPACITY) / WSMAN_BUF_CAPACITY) * WSMAN_BUF_CAPACITY; new_page = (Page*)realloc(buf->page, sizeof(Page) + newSize); if (!new_page) return MI_RESULT_FAILED; buf->page = new_page; buf->page->u.s.size = newSize; return MI_RESULT_OK; } #if 0 #if (MI_CHAR_TYPE == 1) #define FIRST_HIGH_SURROGATE 0xD800 #define LAST_HIGH_SURROGATE 0xDBFF static void _UTF16toUTF8( MI_Char16 c, char* s) { static const MI_Uint8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; MI_Uint8* tgt = (MI_Uint8*)s; MI_Uint32 numberOfBytes; /* not a valid single char */ if (c >= FIRST_HIGH_SURROGATE && c <= LAST_HIGH_SURROGATE) { s[0] = '?'; s[1] = 0; return; } if (c < 0x80) { numberOfBytes = 1; } else if (c < 0x800) { numberOfBytes = 2; } else { numberOfBytes = 3; } tgt += numberOfBytes; switch (numberOfBytes) { case 3: *--tgt = (MI_Uint8)((c | 0x80) & 0xBF); c >>= 6; case 2: *--tgt = (MI_Uint8)((c | 0x80) & 0xBF); c >>= 6; case 1: *--tgt = (MI_Uint8)(c | firstByteMark[numberOfBytes]); } } #endif #endif /* **============================================================================== ** ** Public API: ** **============================================================================== */ MI_Result WSBuf_Init( WSBuf* buf, MI_Uint32 initialSize) { buf->page = (Page*)malloc(sizeof(Page) + initialSize); buf->position = 0; if (!buf->page) { return MI_RESULT_FAILED; } buf->page->u.s.size = initialSize; buf->page->u.s.next = 0; /* Put empty string inside */ ((MI_Char*)(buf->page +1))[0] = 0; return MI_RESULT_OK; } MI_Result WSBuf_Destroy( WSBuf* buf) { if (buf->page) free(buf->page); return MI_RESULT_OK; } #if (MI_CHAR_TYPE == 1) Page* WSBuf_StealPage( WSBuf* buf) { Page* res = buf->page; if (!res) return 0; buf->page = 0; res->u.s.size = buf->position; buf->position = 0; return res; } #else Page* WSBuf_StealPage( WSBuf* buf) { if (!buf->page) return 0; /* convert wchar_t to utf-8 unfortunately, Windows does not support wchat -> utf8 conversion in crt */ { Page* res; const MI_Char* text = ((MI_Char*)(buf->page +1)); int size = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, 0, NULL); if (size == 0) goto failed; res = (Page*)malloc(sizeof(Page) + size); if (!res) goto failed; if (WideCharToMultiByte(CP_UTF8, 0, text, -1, (char*)(res + 1), size, 0, NULL) == 0) { free(res); goto failed; } res->u.s.size = size - 1; res->u.s.next = 0; free(buf->page); buf->page = 0; buf->position = 0; return res; } failed: free(buf->page); buf->page = 0; return 0; } #endif MI_Result WSBuf_AddUint32( WSBuf* buf, MI_Uint32 x) { MI_Char tmp[12]; size_t size; const MI_Char* s = Uint32ToZStr(tmp, x, &size); return WSBuf_AddLit(buf, s, (MI_Uint32)size); } MI_Result __WSBuf_AddLit( WSBuf* buf, const MI_Char* str, MI_Uint32 size) { MI_Uint32 n = (size + 1) * sizeof(MI_Char); /* Extend buffer (WSBuf_AddLit determined it was too small) */ if (_ReallocPage(buf, n + buf->position) != MI_RESULT_OK) return MI_RESULT_FAILED; /* Add string */ { char* data = ((char*)(buf->page+1)) + buf->position; memcpy( data, str, n - sizeof(MI_Char)); ((MI_Char*)data)[size] = 0; buf->position += n - sizeof(MI_Char); } return MI_RESULT_OK; } /* Add string with proper xml encoding */ MI_Result WSBuf_AddString( WSBuf* buf, const MI_Char* str) { #if (MI_CHAR_TYPE == 1) /* Process leading non-special characters in the hope that little will * be left over to be encoded the expensive way below this block. */ { const unsigned char* start = (const unsigned char*)str; const unsigned char* p = start; while (!s_specialChars[*p]) p++; if (p != start) { if (WSBuf_AddLit(buf, (const char*)start, (MI_Uint32)(p - start))) return MI_RESULT_FAILED; str = (const char*)p; } if (!*str) return MI_RESULT_OK; } #endif /* Now encode what remains (starting with first special char hit above) */ { /*MI_Uint32 size = (MI_Uint32)((MI_Strlen(str) + 1)*sizeof(MI_Char));*/ MI_Char* pos = (MI_Char*)(((char*)(buf->page +1)) + buf->position); MI_Char* end = (MI_Char*)(((char*)(buf->page +1)) + buf->page->u.s.size); /* Add reamingin characters (next character is special) */ while (*str) { const MI_Char* item; size_t size_chars; MI_Uint32 c = (MI_Uint32)(MI_Sint16)*str; /* if c is ascii ?*/ if (c < 128) { /* First byte is the length */ item = s_specialCharEncodings[c] + 1; size_chars = s_specialCharEncodings[c][0]; } else { item = str; size_chars = 1; } /* Extend buffer if needed */ if ( (size_t)(end - pos) <= (size_chars + 1)) { size_t current_pos = (pos - ((MI_Char*)(buf->page +1))) * sizeof(MI_Char); if (_ReallocPage(buf, (MI_Uint32)(buf->page->u.s.size + size_chars * sizeof(MI_Char))) != MI_RESULT_OK) return MI_RESULT_FAILED; pos = (MI_Char*)(((char*)(buf->page +1)) + current_pos); end = (MI_Char*)(((char*)(buf->page +1)) + buf->page->u.s.size); } if (1 == size_chars) *pos = *item; else memcpy( pos, item, size_chars * sizeof(MI_Char)); pos += size_chars; str++; } buf->position = (MI_Uint32)((pos - ((MI_Char*)(buf->page +1))) * sizeof(MI_Char)); /* put \0 at the end */ ((MI_Char*)(((char*)(buf->page +1)) + buf->position))[0] = 0; return MI_RESULT_OK; } } #if (MI_CHAR_TYPE != 1) MI_Result WSBuf_AddCharStringNoEncoding( WSBuf* buf, const char* str) { return WSBuf_AddCharLit(buf, str, (MI_Uint32)strlen(str)); } MI_Result WSBuf_AddCharLit( WSBuf* buf, const char* str, MI_Uint32 size_) { MI_Uint32 size = (MI_Uint32)((size_ + 1)*sizeof(MI_Char)); /* Extend buffer if needed */ if (size + buf->position > buf->page->u.s.size && _ReallocPage(buf, size + buf->position) != MI_RESULT_OK) return MI_RESULT_FAILED; { MI_Char* data = (MI_Char*)(((char*)(buf->page +1)) + buf->position); MI_Uint32 i; for (i = 0; i < size_; i++) { *data++ = *str++; } buf->position += size - sizeof(MI_Char); } return MI_RESULT_OK; } #endif /* Callback to tag writer: allows to write properties for both values/EPRs with the same routine */ typedef MI_Result (*PropertyTagWriter)( WSBuf* buf, const MI_Char* name, MI_Boolean start); INLINE MI_Result PropertyTagWriter_PropStart( WSBuf* buf, const MI_Char* name) { MI_Uint32 n = (MI_Uint32)Zlen(name); if (MI_RESULT_OK != WSBuf_AddLit3(buf, '<', 'p', ':') || MI_RESULT_OK != WSBuf_AddLit(buf, name, n) || MI_RESULT_OK != WSBuf_AddLit1(buf,'>')) { return MI_RESULT_FAILED; } return MI_RESULT_OK; } INLINE MI_Result PropertyTagWriter_PropEnd( WSBuf* buf, const MI_Char* name) { MI_Uint32 n = (MI_Uint32)Zlen(name); if (MI_RESULT_OK != WSBuf_AddLit4(buf, '<', '/', 'p', ':') || MI_RESULT_OK != WSBuf_AddLit(buf, name, n) || MI_RESULT_OK != WSBuf_AddLit2(buf, '>', '\n')) { return MI_RESULT_FAILED; } return MI_RESULT_OK; } static MI_Result PropertyTagWriter_Prop( WSBuf* buf, const MI_Char* name, MI_Boolean start) { if (start) return PropertyTagWriter_PropStart(buf, name); else return PropertyTagWriter_PropEnd(buf, name); } static MI_Result PropertyTagWriter_EPR( WSBuf* buf, const MI_Char* name, MI_Boolean start) { if (start) { if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("') ) return MI_RESULT_FAILED; } else { if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR)) ) return MI_RESULT_FAILED; } return MI_RESULT_OK; } static MI_Result _PackFieldNil( WSBuf* buf, const MI_Char* name) { if ( MI_RESULT_OK != WSBuf_AddLit3(buf, '<', 'p', ':') || MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,name) || MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T(" xsi:nil=\"true\"/>") XML_CR)) ) return MI_RESULT_FAILED; return MI_RESULT_OK; } static int _Base64Callback( const char* data, size_t size, void* callbackData) { WSBuf* buf = callbackData; return WSBuf_AddLit(buf, data, size) == MI_RESULT_OK ? 0 : -1; } static MI_Result _PackFieldOctetString( WSBuf* buf, const MI_Char* name, const MI_Uint8* data, size_t size) { /* Validate first 4 bytes which contain the length then remove them */ { size_t length = 0; if (size < 4) return MI_RESULT_FAILED; length |= data[0] << 24; length |= data[1] << 16; length |= data[2] << 8; length |= data[3]; if (length != size) return MI_RESULT_FAILED; data += 4; size -= 4; } if (WSBuf_AddLit3(buf, '<', 'p', ':') != MI_RESULT_OK) return MI_RESULT_FAILED; if (WSBuf_AddStringNoEncoding(buf, name) != MI_RESULT_OK) return MI_RESULT_FAILED; if (WSBuf_AddLit(buf, LIT(MI_T(" xsi:type=\"cim:cimBase64Binary\">"))) != MI_RESULT_OK) { return MI_RESULT_FAILED; } if (Base64Enc(data, size, _Base64Callback, buf) != 0) return MI_RESULT_FAILED; if (PropertyTagWriter_PropEnd(buf, name) != MI_RESULT_OK) return MI_RESULT_FAILED; return MI_RESULT_OK; } static MI_Result _PackFieldString( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, const MI_Char* value) { if ( MI_RESULT_OK != writer(buf,name,MI_TRUE) || MI_RESULT_OK != WSBuf_AddString(buf,value) || MI_RESULT_OK != writer(buf,name,MI_FALSE) ) return MI_RESULT_FAILED; return MI_RESULT_OK; } static MI_Result _PackFieldStringLit( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, const MI_Char* value, MI_Uint32 valueSize) { if ( MI_RESULT_OK != writer(buf,name,MI_TRUE) || MI_RESULT_OK != WSBuf_AddLit(buf,value,valueSize) || MI_RESULT_OK != writer(buf,name,MI_FALSE) ) return MI_RESULT_FAILED; return MI_RESULT_OK; } static MI_Result _PackFieldEmbeddedInstance( WSBuf* buf, const MI_Char* name, const MI_Instance* value) { if ( MI_RESULT_OK != PropertyTagWriter_PropStart(buf,name) || MI_RESULT_OK != _PackInstance(buf,value,NULL,NULL,0,WSMAN_ObjectFlag,MI_TRUE) || MI_RESULT_OK != PropertyTagWriter_PropEnd(buf,name) ) return MI_RESULT_FAILED; return MI_RESULT_OK; } static MI_Result _PackFieldRef( WSBuf* buf, const MI_Char* name, const MI_Instance* value) { if ( MI_RESULT_OK != PropertyTagWriter_PropStart(buf,name) || MI_RESULT_OK != _PackEPR(buf,value) || MI_RESULT_OK != PropertyTagWriter_PropEnd(buf,name) ) return MI_RESULT_FAILED; return MI_RESULT_OK; } static MI_Result _PackFieldUint32( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, MI_Uint32 value) { MI_Char tmp[11]; size_t size; const MI_Char* str = Uint32ToZStr(tmp, value, &size); return _PackFieldStringLit(buf,writer, name, str, (MI_Uint32)size); } static MI_Result _PackFieldUint64( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, MI_Uint64 value) { MI_Char tmp[21]; size_t size; const MI_Char* str = Uint64ToZStr(tmp, value, &size); return _PackFieldStringLit(buf, writer, name, str, (MI_Uint32)size); } static MI_Result _PackFieldSint32( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, MI_Sint32 value) { MI_Char s[24]; MI_Sint32 size = Szprintf(s, MI_COUNT(s), MI_T("%d"), value); return _PackFieldStringLit(buf,writer,name,s,size); } static MI_Result _PackFieldSint64( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, MI_Sint64 value) { MI_Char s[24]; MI_Sint32 size = Szprintf(s, MI_COUNT(s), SINT64_FMT_T, value); return _PackFieldStringLit(buf,writer,name,s,size); } static MI_Result _PackFieldReal64( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, MI_Real64 value) { MI_Char s[24]; MI_Sint32 size = Szprintf(s, MI_COUNT(s), MI_T("%g"), value); return _PackFieldStringLit(buf,writer,name,s,size); } static MI_Result _PackFieldDatetime( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, const MI_Datetime* p) { MI_Char tmp[64]; FormatWSManDatetime(p, tmp); return _PackFieldStringLit(buf, writer, name, tmp, (MI_Uint32)Zlen(tmp)); } static MI_Result _PackValue( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, const void* field, MI_Type type) { switch(type) { case MI_BOOLEAN: { MI_Boolean* f = (MI_Boolean*)field; if (*f) return _PackFieldStringLit(buf,writer,name,LIT(MI_T("TRUE"))); else return _PackFieldStringLit(buf,writer,name,LIT(MI_T("FALSE"))); } case MI_UINT8: { MI_Uint8* f = (MI_Uint8*)field; return _PackFieldUint32(buf,writer,name,*f); } case MI_UINT16: { MI_Uint16* f = (MI_Uint16*)field; return _PackFieldUint32(buf,writer,name,*f); } case MI_UINT32: { MI_Uint32* f = (MI_Uint32*)field; return _PackFieldUint32(buf,writer,name,*f); } case MI_UINT64: { MI_Uint64* f = (MI_Uint64*)field; return _PackFieldUint64(buf,writer,name,*f); } case MI_SINT8: { MI_Sint8* f = (MI_Sint8*)field; return _PackFieldSint32(buf,writer,name,*f); } case MI_SINT16: { MI_Sint16* f = (MI_Sint16*)field; return _PackFieldSint32(buf,writer,name,*f); } case MI_SINT32: { MI_Sint32* f = (MI_Sint32*)field; return _PackFieldSint32(buf,writer,name,*f); } case MI_SINT64: { MI_Sint64* f = (MI_Sint64*)field; return _PackFieldSint64(buf,writer,name,*f); } case MI_REAL32: { MI_Real32* f = (MI_Real32*)field; return _PackFieldReal64(buf,writer,name,*f); } case MI_REAL64: { MI_Real64* f = (MI_Real64*)field; return _PackFieldReal64(buf,writer,name,*f); } case MI_DATETIME: { MI_Datetime* f = (MI_Datetime*)field; return _PackFieldDatetime(buf,writer,name,&*f); } case MI_CHAR16: { MI_Char16* f = (MI_Char16*)field; #if 0 #if (MI_CHAR_TYPE == 1) char s[6]; memset(s,0,sizeof(s)); _UTF16toUTF8(*f,s); #else /* whcar_t - steal page will translate it */ wchar_t s[2] = {0, 0}; s[0] = *f; #endif /* ATTN: convert it to utf8 and encode as a string */ return _PackFieldString(buf,writer,name,s); #else return _PackFieldUint32(buf,writer,name,(MI_Uint32)*f); #endif } case MI_INSTANCE: { MI_Instance** f = (MI_Instance**)field; return _PackFieldEmbeddedInstance(buf,name,*f); } case MI_REFERENCE: { MI_Instance** f = (MI_Instance**)field; return _PackFieldRef(buf,name,*f); } case MI_STRING: { MI_String* f = (MI_String*)field; return _PackFieldString(buf,writer,name,*f); } default: break; } return MI_RESULT_OK; } static MI_Result _PackField( WSBuf* buf, PropertyTagWriter writer, const MI_Char* name, const void* field, MI_Type type, MI_Boolean isOctetString) { /* Check if value is null */ if (!_Field_GetExists(field, type)) return _PackFieldNil(buf, name); /* Check if type is array: Arrays are encoded the same way regular instances are with repeating instance as many times as many elements are in array */ if (type & MI_ARRAY_BIT) { if (isOctetString && type == MI_UINT8A) { MI_Uint8AField* f = (MI_Uint8AField*)field; return _PackFieldOctetString(buf, name, f->value.data, f->value.size); } /* ATTN: STRING OctetString not handled! */ { MI_ArrayField* f = (MI_ArrayField*)field; MI_Uint32 i; MI_Type stype = type & ~MI_ARRAY_BIT; char* currentValue = (char*)f->value.data; for (i = 0; i < f->value.size; i++) { if (_PackValue( buf, writer, name, currentValue, stype) != MI_RESULT_OK) { return MI_RESULT_FAILED; } currentValue += Type_SizeOf(stype); } return MI_RESULT_OK; } } return _PackValue(buf, writer, name, field, type); } static MI_Result _PackEPR( WSBuf* buf, const MI_Instance* instance) { Instance* self = (Instance*)instance; const MI_ClassDecl* cd = self->classDecl; MI_Uint32 i; /* Put EPR header */ if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous") XML_CR MI_T("") XML_CR MI_T("http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/") )) || MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) || MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR MI_T("") XML_CR )) ) return MI_RESULT_FAILED; /* namespace (if present)*/ if (self->nameSpace) { } /* Put properties */ for ( i = 0; i < cd->numProperties; i++ ) { const MI_PropertyDecl* pd = cd->properties[i]; const void* value = (char*)self + pd->offset; if ((pd->flags & MI_FLAG_KEY) == 0) continue; /* skip null values */ if (!_Field_GetExists(value,(MI_Type)pd->type)) continue; if (_PackValue( buf, PropertyTagWriter_EPR, pd->name, value, (MI_Type)pd->type) != MI_RESULT_OK) { return MI_RESULT_FAILED; } } /* close EPR */ if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR MI_T("") XML_CR )) ) return MI_RESULT_FAILED; return MI_RESULT_OK; } static MI_Boolean TestOctetStringQualifier( const MI_PropertyDecl* pd) { size_t i; for (i = 0; i < pd->numQualifiers; i++) { const MI_Qualifier* q = pd->qualifiers[i]; if (Zcasecmp(q->name, T("OctetString")) == 0 && q->type == MI_BOOLEAN && q->value) { return *((const MI_Boolean*)q->value); } } return MI_FALSE; } static MI_Result _PackInstance( WSBuf* buf, const MI_Instance* instance, MI_Boolean (*filterProperty)(const MI_Char* name, void* data), void* filterPropertyData, const MI_ClassDecl* castToClassDecl, MI_Uint32 flags, MI_Boolean embedded) { Instance* self = (Instance*)instance; const MI_ClassDecl* cd = castToClassDecl ? castToClassDecl : self->classDecl; MI_Uint32 i; /* Check for null arguments */ if (!self || !buf) MI_RETURN(MI_RESULT_INVALID_PARAMETER); /* For Object & EPR, add tag */ if ((flags & WSMAN_ObjectAndEPRFlag) == WSMAN_ObjectAndEPRFlag) { if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR))) return MI_RESULT_FAILED; } /* If object was requested */ if ((flags & WSMAN_ObjectFlag) == WSMAN_ObjectFlag) { /* Put classname */ if ( MI_RESULT_OK != WSBuf_AddLit3(buf, '<', 'p', ':') || MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) || MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T(" xmlns:p=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/"))) || MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) || MI_RESULT_OK != WSBuf_AddLit2(buf, '"', '\n')) return MI_RESULT_FAILED; if (embedded) { if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T(" xsi:type=\""))) || MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) || MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("_Type\"") XML_CR))) return MI_RESULT_FAILED; } if ( MI_RESULT_OK != WSBuf_AddLit2(buf, '>', '\n')) return MI_RESULT_FAILED; /* Put properties */ for ( i = 0; i < cd->numProperties; i++ ) { const MI_PropertyDecl* pd = cd->properties[i]; const void* value = (char*)self + pd->offset; MI_Boolean isOctetString = MI_FALSE; if (filterProperty && (*filterProperty)(pd->name, filterPropertyData)) { continue; } /* Search for OctetString qualifier */ if (pd->type == MI_UINT8A || pd->type == MI_STRINGA) isOctetString = TestOctetStringQualifier(pd); /* Pack the field */ if (_PackField( buf, PropertyTagWriter_Prop, pd->name, value, (MI_Type)pd->type, isOctetString) != MI_RESULT_OK) { return MI_RESULT_FAILED; } } /* close class */ if ( MI_RESULT_OK != WSBuf_AddLit4(buf, '<', '/', 'p', ':') || MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) || MI_RESULT_OK != WSBuf_AddLit2(buf, '>', '\n')) return MI_RESULT_FAILED; } /* If EPR was requested */ if ((flags & WSMAN_EPRFlag) == WSMAN_EPRFlag) { if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR)) || MI_RESULT_OK != _PackEPR(buf,instance) || MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR))) return MI_RESULT_FAILED; } /* If EPR was requested */ if ((flags & WSMAN_CreatedEPRFlag) == WSMAN_CreatedEPRFlag) { if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR)) || MI_RESULT_OK != _PackEPR(buf,instance) || MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR))) return MI_RESULT_FAILED; } /* For Object & EPR, add tag */ if ((flags & WSMAN_ObjectAndEPRFlag) == WSMAN_ObjectAndEPRFlag) { if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("") XML_CR))) return MI_RESULT_FAILED; } return MI_RESULT_OK; } MI_Result WSBuf_InstanceToBuf( const MI_Instance* instance, MI_Boolean (*filterProperty)(const MI_Char* name, void* data), void* filterPropertyData, const MI_ClassDecl* castToClassDecl, Batch* batch, MI_Uint32 flags, void** ptrOut, MI_Uint32* sizeOut) { WSBuf buf; MI_Result r; Page* page; r = WSBuf_Init(&buf,1024); if (MI_RESULT_OK != r) return r; r = _PackInstance(&buf, instance, filterProperty, filterPropertyData, castToClassDecl, flags,MI_FALSE); if (MI_RESULT_OK != r) { WSBuf_Destroy(&buf); return r; } page = WSBuf_StealPage(&buf); Batch_AttachPage(batch, page); *ptrOut = page + 1; *sizeOut = (MI_Uint32)page->u.s.size; return MI_RESULT_OK; } void WSBuf_GenerateMessageID( MI_Char msgID[WS_MSG_ID_SIZE]) { //WS-Management qualifies the use of wsa:MessageID and wsa:RelatesTo as follows: //R5.4.6.4-1: The MessageID and RelatesTo URIs may be of any format, as long as they are valid //URIs according to RFC 3986. Two URIs are considered different even if the characters in the //URIs differ only by case. //The following two formats are endorsed by this specification. The first is considered a best //practice because it is backed by RFC 4122: //urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx //or //uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx //In these formats, each x is an uppercase or lowercase hexadecimal digit (lowercase is required //by RFC 4122); there are no spaces or other tokens. The value may be a DCE-style universally //unique identifier (UUID) with provable uniqueness properties in this format, however, it is not //necessary to have provable uniqueness properties in the URIs used in the wsa:MessageID and //wsa:RelatesTo headers. //Regardless of format, the URI should not exceed the maximum defined in R13.1-6. //UUIDs have a numeric meaning as well as a string meaning, and this can lead to confusion. A UUID //in lowercase is a different URI from the same UUID in uppercase. This is because URIs are case1619 //tive. If a UUID is converted to its decimal equivalent the case of the original characters is lost. //WS-Management works with the URI value itself, not the underlying decimal equivalent //representation. Services are free to interpret the URI in any way, but are not allowed to alter the case //usage when repeating the message or any of the MessageID values in subsequent messages. //The RFC 4122 requires the digits to be lowercase, which is the responsibility of the client. The service //simply processes the values as URI values and is not required to analyze the URI for correctness or //compliance. The service replicates the client usage in the wsa:RelatesTo reply header and is not //allowed to alter the case usage. //R5.4.6.4-2: The MessageID should be generated according to any algorithm that ensures that no //two MessageIDs are repeated. Because the value is treated as case-sensitive (R5.4.6.4-1), //confusion can arise if the same value is reused differing only in case. As a result, the service shall //not create or employ MessageID values that differ only in case. For any message transmitted by //the service, the MessageID shall not be reused. static MI_Uint64 s1, s2; if (!s1) Time_Now(&s1); s2++; /* ADC */ if (!s2) s1++; Szprintf(msgID, WS_MSG_ID_SIZE, MI_T("uuid:%08X-%04X-%04X-%04X-%08X%04X"), (MI_Uint32)(s1 & 0xFFFFFFFF), (MI_Uint32)((s1 >> 32) & 0xFFFF), (MI_Uint32)((s1 >> 48) & 0xFFFF), (MI_Uint32)((s2 >> 48) & 0xFFFF), (MI_Uint32)(s2 & 0xFFFFFFFF), (MI_Uint32)((s2 >> 32) & 0xFFFF) ); } MI_Result WSBuf_CreateSoapResponseHeader( WSBuf *buf, const MI_Char* action, MI_Uint32 actionSize, const char* relatesTo) { MI_Char msgID[WS_MSG_ID_SIZE]; /* Response header */ if (MI_RESULT_OK != WSBuf_AddLit(buf, LIT( MI_T("") XML_CR MI_T("") XML_CR MI_T("http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous") XML_CR MI_T(""))) ) { goto failed; } if (MI_RESULT_OK != WSBuf_AddLit(buf, action, actionSize)) goto failed; if (MI_RESULT_OK != WSBuf_AddLit(buf, LIT(MI_T("") XML_CR MI_T("" )))) goto failed; /* Generate new uniqueue msg id */ WSBuf_GenerateMessageID(msgID); if (MI_RESULT_OK != WSBuf_AddLit(buf, msgID, WS_MSG_ID_SIZE - 1)) goto failed; if (MI_RESULT_OK != WSBuf_AddLit(buf, LIT(MI_T("") XML_CR))) goto failed; if (relatesTo) { if (MI_RESULT_OK != WSBuf_AddLit(buf, LIT(MI_T("")))) goto failed; if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(buf, relatesTo)) goto failed; if (MI_RESULT_OK != WSBuf_AddLit(buf, LIT(MI_T("") XML_CR))) goto failed; } return MI_RESULT_OK; failed: return MI_RESULT_FAILED; } Page* WSBuf_CreateFaultResponsePage( WSBUF_FAULT_CODE faultCode, const char* notUnderstoodTag, const char* requestMessageID, const MI_Char* descriptionText) { WSBuf outBuf; const BUF_FaultItem* fault; if ( ((MI_Uint32)faultCode) >= MI_COUNT(s_faults)) { fault = s_faults + 0; /* internal error */ } else { fault = s_faults + (MI_Uint32)faultCode; } /* prepare soap response with error */ if (WSBuf_Init(&outBuf, 1024) != MI_RESULT_OK) return 0; /* fault header */ if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf, fault->action, fault->actionSize, requestMessageID)) goto failed; if (notUnderstoodTag) { if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT(MI_T("')) goto failed; } if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT( MI_T("") XML_CR XML_CR MI_T("") XML_CR MI_T("") XML_CR MI_T("") XML_CR MI_T(""))) ) goto failed; if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(&outBuf, fault->code)) goto failed; //SOAP-ENV:Sender if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT(MI_T("") XML_CR))) goto failed; if (fault->subCode) { if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT(MI_T("") XML_CR MI_T("")))) goto failed; if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(&outBuf, fault->subCode)) goto failed; if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT(MI_T("") XML_CR MI_T("") XML_CR))) goto failed; } if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT(MI_T("") XML_CR MI_T("") XML_CR MI_T("")))) goto failed; if ( descriptionText ) { if (MI_RESULT_OK != WSBuf_AddString(&outBuf, descriptionText)) goto failed; } else { if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(&outBuf, fault->defaultTest)) goto failed; } if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT( MI_T("") XML_CR MI_T("") XML_CR MI_T("") XML_CR MI_T("") XML_CR MI_T("") XML_CR)) ) goto failed; return WSBuf_StealPage(&outBuf); failed: WSBuf_Destroy(&outBuf); return 0; } Page* WSBuf_CreateReleaseResponsePage( const char* requestMessageID) { WSBuf outBuf; /* prepare soap response with error */ if (WSBuf_Init(&outBuf, 1024) != MI_RESULT_OK) return 0; /* fault header */ if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf, LIT(MI_T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/ReleaseResponse")), requestMessageID)) goto failed; if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, LIT( MI_T("") XML_CR XML_CR MI_T("") XML_CR MI_T("") XML_CR)) ) goto failed; return WSBuf_StealPage(&outBuf); failed: WSBuf_Destroy(&outBuf); return 0; } WSBUF_FAULT_CODE WSBuf_CIMErrorToWSFault( MI_Uint32 cimErrorCode, const MI_Char** description ) { MI_Uint32 index = cimErrorCode < MI_COUNT(s_cimerrors) ? cimErrorCode : MI_RESULT_FAILED; if ( description ) *description = s_cimerrors[index].description; return s_cimerrors[index].faultCode; }