/* **============================================================================== ** ** 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 "wsmanbuffer.h" #include #include #include #include #include #include #include #include #include #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; typedef struct _Char_Encoding { const MI_Char* str; MI_Uint32 size; } Char_Encoding; /* **============================================================================== ** ** Forward declarations: ** **============================================================================== */ static MI_Result _PackInstance( WS_Buffer* 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( WS_Buffer* 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 }; // Defines encodings of special characters. Just use a 7-bit ASCII character // as an index into this array to retrieve its string encoding and encoding // length in bytes. static const Char_Encoding s_encodedChars127[128] = { {LIT(MI_T("�"))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(" "))}, {LIT(MI_T(" "))}, {LIT(MI_T(" "))}, {LIT(MI_T(" "))}, {LIT(MI_T(" "))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(""))}, {LIT(MI_T(" "))}, {LIT(MI_T("!"))}, {LIT(MI_T("""))}, {LIT(MI_T("#"))}, {LIT(MI_T("$"))}, {LIT(MI_T("%"))}, {LIT(MI_T("&"))}, {LIT(MI_T("'"))}, {LIT(MI_T("("))}, {LIT(MI_T(")"))}, {LIT(MI_T("*"))}, {LIT(MI_T("+"))}, {LIT(MI_T(","))}, {LIT(MI_T("-"))}, {LIT(MI_T("."))}, {LIT(MI_T("/"))}, {LIT(MI_T("0"))}, {LIT(MI_T("1"))}, {LIT(MI_T("2"))}, {LIT(MI_T("3"))}, {LIT(MI_T("4"))}, {LIT(MI_T("5"))}, {LIT(MI_T("6"))}, {LIT(MI_T("7"))}, {LIT(MI_T("8"))}, {LIT(MI_T("9"))}, {LIT(MI_T(":"))}, {LIT(MI_T(";"))}, {LIT(MI_T("<"))}, {LIT(MI_T("="))}, {LIT(MI_T(">"))}, {LIT(MI_T("?"))}, {LIT(MI_T("@"))}, {LIT(MI_T("A"))}, {LIT(MI_T("B"))}, {LIT(MI_T("C"))}, {LIT(MI_T("D"))}, {LIT(MI_T("E"))}, {LIT(MI_T("F"))}, {LIT(MI_T("G"))}, {LIT(MI_T("H"))}, {LIT(MI_T("I"))}, {LIT(MI_T("J"))}, {LIT(MI_T("K"))}, {LIT(MI_T("L"))}, {LIT(MI_T("M"))}, {LIT(MI_T("N"))}, {LIT(MI_T("O"))}, {LIT(MI_T("P"))}, {LIT(MI_T("Q"))}, {LIT(MI_T("R"))}, {LIT(MI_T("S"))}, {LIT(MI_T("T"))}, {LIT(MI_T("U"))}, {LIT(MI_T("V"))}, {LIT(MI_T("W"))}, {LIT(MI_T("X"))}, {LIT(MI_T("Y"))}, {LIT(MI_T("Z"))}, {LIT(MI_T("["))}, {LIT(MI_T("\\"))}, {LIT(MI_T("]"))}, {LIT(MI_T("^"))}, {LIT(MI_T("_"))}, {LIT(MI_T("`"))}, {LIT(MI_T("a"))}, {LIT(MI_T("b"))}, {LIT(MI_T("c"))}, {LIT(MI_T("d"))}, {LIT(MI_T("e"))}, {LIT(MI_T("f"))}, {LIT(MI_T("g"))}, {LIT(MI_T("h"))}, {LIT(MI_T("i"))}, {LIT(MI_T("j"))}, {LIT(MI_T("k"))}, {LIT(MI_T("l"))}, {LIT(MI_T("m"))}, {LIT(MI_T("n"))}, {LIT(MI_T("o"))}, {LIT(MI_T("p"))}, {LIT(MI_T("q"))}, {LIT(MI_T("r"))}, {LIT(MI_T("s"))}, {LIT(MI_T("t"))}, {LIT(MI_T("u"))}, {LIT(MI_T("v"))}, {LIT(MI_T("w"))}, {LIT(MI_T("x"))}, {LIT(MI_T("y"))}, {LIT(MI_T("z"))}, {LIT(MI_T("{"))}, {LIT(MI_T("|"))}, {LIT(MI_T("}"))}, {LIT(MI_T("~"))}, {LIT(MI_T(""))} }; /* Table used to identify special 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* buf) { if (buf->page) free(buf->page); return MI_RESULT_OK; } #if (MI_CHAR_TYPE == 1) Page* WSBuf_StealPage( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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) { item = s_encodedChars127[c].str; size_chars = s_encodedChars127[c].size; } 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( WS_Buffer* buf, const char* str) { return WSBuf_AddCharLit(buf, str, (MI_Uint32)strlen(str)); } MI_Result WSBuf_AddCharLit( WS_Buffer* 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)( WS_Buffer* buf, const MI_Char* name, MI_Boolean start); INLINE MI_Result PropertyTagWriter_PropStart( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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 MI_Result _PackFieldString( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* 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( WS_Buffer* buf, PropertyTagWriter writer, const MI_Char* name, const void* field, MI_Type type) { /* 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) { 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 (MI_RESULT_OK != _PackValue(buf,writer,name,currentValue,stype)) return MI_RESULT_FAILED; currentValue += Type_SizeOf(stype); } return MI_RESULT_OK; } return _PackValue(buf,writer,name,field,type); } static MI_Result _PackEPR( WS_Buffer* 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 (MI_RESULT_OK != _PackValue(buf, PropertyTagWriter_EPR, pd->name, value, (MI_Type)pd->type)) 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_Result _PackInstance( WS_Buffer* 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; if (filterProperty && (*filterProperty)(pd->name, filterPropertyData)) continue; if (MI_RESULT_OK != _PackField(buf, PropertyTagWriter_Prop, pd->name, value, (MI_Type)pd->type)) 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) { WS_Buffer 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( WS_Buffer *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) { WS_Buffer 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) { WS_Buffer 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; }