1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include <assert.h>
26 #include "wsman.h"
27 #include "wsmanbuffer.h"
28 #include "wsmanparser.h"
29 #include "http.h"
30 #include <base/time.h>
31 #include <xml/xml.h>
32 #include <base/log.h>
33 #include <base/result.h>
34 #include <base/strings.h>
35 #include <base/user.h>
36 #include <base/io.h>
37 #include <base/base.h>
38
39 #include "wstags.h"
40
41 #define T MI_T
42 #define CR MI_T("\n")
43 mike 1.1
44 /*
45 **==============================================================================
46 **
47 ** Local definitions:
48 **
49 **==============================================================================
50 */
51 /* Maximum wsman envelope size */
52 #define WSMAN_MAX_ENVELOPE_SIZE (128 * 1024)
53
54 /* aproximate repsonse header size */
55 #define WSMAN_APROX_ENUM_RESP_HEADER_SIZE 1024
56
57 static const MI_Uint32 _MAGIC = 0x1CF2BCB7;
58
59
60 /************************************************************************\
61 * Local definitions
62 \************************************************************************/
63
64 mike 1.1 typedef struct _WSMAN_ConnectionData WSMAN_ConnectionData;
65 typedef struct _WSMAN_EnumerateContext WSMAN_EnumerateContext;
66
67 /* These tags are used as magic numbers as well as to distinguish connection data strucutre from enumeration context */
68 #define DATA_TAG_CONNECTION_DATA 0x17CDDC11
69 #define DATA_TAG_ENUMERATION_CONTEXT 0xAB70900D
70
71 /* Maximum number of enumeration contexts stored at the same time
72 effectively limits number of concurent enumerations */
73 #define WSMAN_MAX_ENUM_CONTEXTS 64
74
75 struct _WSMAN
76 {
77 MI_Uint32 magic;
78 WSMANCallback callback;
79 void* callbackData;
80 Http* http;
81 Selector* selector;
82
83 /* configurable options */
84 WSMAN_Options options;
85 mike 1.1
86 /* Array of enumeration contexts:
87 each 'pull' will look for corresponding context
88 */
89 WSMAN_EnumerateContext* enumerateContexts[WSMAN_MAX_ENUM_CONTEXTS];
90
91 /* Cached xml parser with all namespaces registered */
92 XML xml;
93 };
94
95 /* Represents state of connection including buffers, unsent packets, states etc */
96 struct _WSMAN_ConnectionData
97 {
98 /* Since message's data can point to either ConnectionData or EnumerationContext,
99 both strucutres need some generic base property - tag;
100 in addition, tag used as magic number */
101 MI_Uint32 tag;
102
103 /* Link to http layer */
104 void* httpConnectionHandle;
105
106 mike 1.1 /* Requestor information */
107 uid_t uid;
108 gid_t gid;
109
110 /* Attributes of the request */
111 WSMAN_WSHeader wsheader;
112 union
113 {
114 /* Actual type is defined by wsheader.rqtAction field */
115 WSMAN_WSEnumeratePullBody wsenumpullbody;
116 }
117 u;
118
119 /* Request page (buffer for most pointers inside header/body structures) */
120 Page* page;
121
122 /* for single-instance repsonses, we keep mesage until result received to avoid
123 conflicts with keep-alive enabled */
124 PostInstanceMsg* single_message;
125
126 /* Number of consumers of this structure:
127 mike 1.1 connected client, outstanding request to the provider and timer */
128 MI_Uint32 refcounter;
129
130 /* response data */
131 /* only valid for enumerate/pull requests */
132 MI_Uint32 enumerateContextID;
133
134 /* flag indicates that response was not sent yet to the client */
135 MI_Boolean outstandingRequest;
136 };
137
138 /* Enumeration context:
139 'derived' from socket Handler, so it can subscribe for timeouts */
140
141 struct _WSMAN_EnumerateContext
142 {
143 /* Since message's data can point to either ConnectionData or EnumerationContext,
144 both strucutres need some generic base property - tag;
145 in addition, tag used as magic number */
146 MI_Uint32 tag;
147
148 mike 1.1 /* based member - can be added to 'selector' for timeout support */
149 Handler base;
150
151 /* response data */
152 /* Linked list of messages to send */
153 PostInstanceMsg* head;
154 PostInstanceMsg* tail;
155
156 /* Total size of all instances in response queue */
157 MI_Uint32 totalResponseSize;
158
159 /* NUmber of messages in repsonse queue */
160 MI_Uint32 totalResponses;
161
162 /* Number of consumers of this structure:
163 reference from enum-context-list in WSMAN, outstanding request to the provider and timer */
164 MI_Uint32 refcounter;
165
166 /* lower 16 bits is aninxed in self->enumerateContexts, upper 16 bits are random data (for validation) */
167 MI_Uint32 enumerationContextID;
168 MI_Result finalResult;
169 mike 1.1 /* indicates that 'Result' recevied form provider and stored in finalResult */
170 MI_Boolean enumerationCompleted;
171 /* Indicates that context has expired (either by timer or by Release request)
172 and all repsonses form the provider has to be ignored */
173 MI_Boolean expired;
174
175 /* pointer to current active connection - either Enumerate or Pull request */
176 WSMAN_ConnectionData* activeConnection;
177 };
178
179 /* forward declarations */
180 static void _CD_Release(
181 WSMAN_ConnectionData* selfConnectionData);
182
183 static void _SendEnumPullResponse(
184 WSMAN* self,
185 WSMAN_EnumerateContext* selfEC);
186
187 static MI_Boolean _ProcessEnumResponse(
188 WSMAN* self,
189 WSMAN_EnumerateContext* selfEC,
190 mike 1.1 MI_Boolean attachingPullRequest);
191
192 static void _WSMAN_ReleaseEnumerateContext(
193 WSMAN* self,
194 MI_Uint32 enumerationContextID);
195
196 /************************************************************************\
197 * Helper funcitons
198 \************************************************************************/
199 /* Converts Enumeration mode into "Message" struct flag */
200 MI_INLINE MI_Uint32 _convertWSMANtoMsgEnumerationMode(
201 MI_Uint32 enumerationMode )
202 {
203 if (WSMANTAG_ENUM_MODE_EPR == enumerationMode)
204 return WSMAN_EPRFlag;
205
206 if (WSMANTAG_ENUM_MODE_OBJECT_AND_EPR == enumerationMode)
207 return WSMAN_ObjectAndEPRFlag;
208
209 return WSMAN_ObjectFlag;
210 }
211 mike 1.1
212 /************************************************************************\
213 * Enumeration Context operations
214 \************************************************************************/
215 static void _EC_ReleaseAllMessages(
216 WSMAN_EnumerateContext* self)
217 {
218 /* Delete all queued messages*/
219 while (self->head)
220 {
221 PostInstanceMsg* msg = self->head;
222
223 List_Remove(
224 (ListElem**)&self->head,
225 (ListElem**)&self->tail,
226 (ListElem*)msg);
227 PostInstanceMsg_Release(msg);
228 }
229 self->totalResponses = 0;
230 self->totalResponseSize = 0;
231 }
232 mike 1.1
233 static void _EC_SetActiveConnection(
234 WSMAN_EnumerateContext* self,
235 WSMAN_ConnectionData* selfCD)
236 {
237 if (self->activeConnection)
238 _CD_Release(self->activeConnection);
239
240 self->activeConnection = selfCD;
241 if (self->activeConnection)
242 {
243 self->activeConnection->refcounter++;
244 self->activeConnection->enumerateContextID = self->enumerationContextID;
245 }
246 }
247
248 static void _EC_Release(
249 WSMAN_EnumerateContext* self,
250 MI_Boolean freeAllMessages)
251 {
252 if (--self->refcounter == 0)
253 mike 1.1 {
254 /* Delete all queued messages*/
255 _EC_ReleaseAllMessages(self);
256
257 /* release active connection (if exist) */
258 _EC_SetActiveConnection(self, 0);
259
260 #ifdef CONFIG_ENABLE_DEBUG
261 /* invalidate struct */
262 memset(self, 0xcd, sizeof(*self));
263 #endif
264 free(self);
265 }
266 else if (freeAllMessages)
267 {
268 /* Delete all queued messages*/
269 _EC_ReleaseAllMessages(self);
270 }
271 }
272
273 static MI_Boolean _EC_TimeoutCallback(
274 mike 1.1 Selector* sel,
275 Handler* handler,
276 MI_Uint32 mask,
277 MI_Uint64 currentTimeUsec)
278 {
279 /* since 'base' is not the first member in EC struct,
280 adjust pointer as appropriate */
281 WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)
282 (((char*)handler) - offsetof(WSMAN_EnumerateContext, base));
283
284 MI_UNUSED(sel);
285 MI_UNUSED(currentTimeUsec);
286
287 if (mask & SELECTOR_TIMEOUT)
288 {
289 /* remove context only from wsman list; selector will remove it automatically,
290 once 'false' returned */
291 _WSMAN_ReleaseEnumerateContext(
292 (WSMAN*)self->base.data, self->enumerationContextID);
293
294 /* once 'false' returned, selector will remove handler,
295 mike 1.1 so actual handling happens in next 'if' */
296 return MI_FALSE;
297 }
298
299 if (mask & (SELECTOR_REMOVE | SELECTOR_DESTROY))
300 {
301 _EC_Release(self, MI_TRUE);
302 }
303
304 return MI_TRUE;
305 }
306
307 /************************************************************************\
308 * WSman operations
309 \************************************************************************/
310 static WSMAN_EnumerateContext* _WSMAN_AllocateEnumContext(
311 WSMAN* self)
312 {
313 MI_Uint32 enumerationContextID;
314 WSMAN_EnumerateContext* enumContext;
315
316 mike 1.1 /* Find empty slot */
317 for (enumerationContextID = 0; enumerationContextID < MI_COUNT(self->enumerateContexts); enumerationContextID++)
318 {
319 if (!self->enumerateContexts[enumerationContextID])
320 break;
321 }
322
323 if (MI_COUNT(self->enumerateContexts) == enumerationContextID)
324 {
325 LOGW((T("Cannot allocate new enumerate context - too many concurrent enumerations") ));
326 return 0; /* no more slots available */
327 }
328
329 enumContext = (WSMAN_EnumerateContext*)calloc(1, sizeof(WSMAN_EnumerateContext));
330
331 if (!enumContext)
332 return 0;
333
334 /* Store reference to a new context */
335 self->enumerateContexts[enumerationContextID] = enumContext;
336
337 mike 1.1 /* set tag/magic */
338 enumContext->tag = DATA_TAG_ENUMERATION_CONTEXT;
339
340 /* Add random data to the context-id */
341 enumerationContextID |= (rand() & 0xFFFF) << 16;
342 enumContext->enumerationContextID = enumerationContextID;
343
344 /* set ref-counter to 1, since it's referred by enumerateContexts array now */
345 enumContext->refcounter = 1;
346 return enumContext;
347 }
348
349 static WSMAN_EnumerateContext* _WSMAN_FindEnumContext(
350 WSMAN* self,
351 MI_Uint32 enumerationContextID)
352 {
353 MI_Uint32 index = enumerationContextID & 0xFFFF;
354
355 /* ATTN: add logging here! */
356 /* verify that context exist and has the same id as required */
357 if (index < MI_COUNT(self->enumerateContexts) &&
358 mike 1.1 self->enumerateContexts[index] &&
359 self->enumerateContexts[index]->enumerationContextID == enumerationContextID)
360 return self->enumerateContexts[index];
361
362 return 0;
363 }
364
365
366 static void _WSMAN_ReleaseEnumerateContext(
367 WSMAN* self,
368 MI_Uint32 enumerationContextID)
369 {
370 MI_Uint32 index = enumerationContextID & 0xFFFF;
371
372 if (index < MI_COUNT(self->enumerateContexts) &&
373 self->enumerateContexts[index] &&
374 self->enumerateContexts[index]->enumerationContextID == enumerationContextID)
375 {
376 /* mark handler for removing:
377 we cannot remove it directly since we are inside selector's callback;
378 settign time to current will trigger timeout/context removal */
379 mike 1.1 MI_Uint64 currentTimeUsec = 0;
380
381 Time_Now(¤tTimeUsec);
382 self->enumerateContexts[index]->base.fireTimeoutAt = currentTimeUsec;
383 self->enumerateContexts[index]->expired = MI_TRUE;
384
385 /* dec-ref context: note: it can still be alive if porvider has outstanding request */
386 _EC_Release(self->enumerateContexts[index], MI_FALSE);
387 self->enumerateContexts[index] = 0;
388 }
389 }
390
391 static void _WSMAN_ReleaseAllEnumerateContexts(
392 WSMAN* self)
393 {
394 MI_Uint32 index;
395
396 for (index = 0; index < MI_COUNT(self->enumerateContexts); index++ )
397 {
398 if (self->enumerateContexts[index])
399 {
400 mike 1.1 /* delete timer if was set */
401 Selector_RemoveHandler(self->selector, &self->enumerateContexts[index]->base);
402
403 /* dec-ref context: note: it can still be alive if porvider has outstanding request */
404 _EC_Release(self->enumerateContexts[index], MI_FALSE);
405 self->enumerateContexts[index] = 0;
406 }
407 }
408 }
409
410 static void _WSMAN_SetUpdateTimer(
411 WSMAN* self,
412 WSMAN_EnumerateContext* selfEC)
413 {
414 /* check if timer was already added */
415 if (!selfEC->base.fireTimeoutAt)
416 {
417 /* add timer - first time called */
418 selfEC->base.sock = INVALID_SOCK;
419 selfEC->base.data = self;
420 selfEC->base.callback = _EC_TimeoutCallback;
421 mike 1.1
422 /* increment counter - will be decremented in callback/remove */
423 if (MI_RESULT_OK == Selector_AddHandler(self->selector, &selfEC->base))
424 selfEC->refcounter++;
425 }
426
427 /* extend time */
428 {
429 MI_Uint64 currentTimeUsec = 0;
430
431 if (MI_RESULT_OK == Time_Now(¤tTimeUsec))
432 {
433 selfEC->base.fireTimeoutAt =
434 currentTimeUsec + self->options.timeoutEnumContextUsec;
435 }
436 }
437 }
438
439 /************************************************************************\
440 * connection data operations
441 \************************************************************************/
442 mike 1.1 MI_INLINE void _CD_SetPage(
443 WSMAN_ConnectionData* selfConnectionData,
444 Page* page)
445 {
446 if (selfConnectionData->page)
447 free(selfConnectionData->page);
448
449 selfConnectionData->page = page;
450 }
451
452 MI_INLINE void _CD_SetSingleMessage(
453 WSMAN_ConnectionData* selfConnectionData,
454 PostInstanceMsg* single_message)
455 {
456 if (selfConnectionData->single_message)
457 PostInstanceMsg_Release(selfConnectionData->single_message);
458
459 selfConnectionData->single_message = single_message;
460
461 if (selfConnectionData->single_message)
462 Message_AddRef(&selfConnectionData->single_message->base);
463 mike 1.1 }
464
465 static void _CD_Cleanup(
466 WSMAN_ConnectionData* selfConnectionData)
467 {
468 _CD_SetPage(selfConnectionData, 0);
469 _CD_SetSingleMessage(selfConnectionData, 0);
470
471 /* free allocated instance/batch */
472 if (selfConnectionData->wsheader.instanceBatch)
473 {
474 /* destroying batch takes care of instance and instanceBatch members */
475 Batch_Destroy(selfConnectionData->wsheader.instanceBatch);
476 selfConnectionData->wsheader.instanceBatch = 0;
477 selfConnectionData->wsheader.instance = 0;
478 }
479 memset(&selfConnectionData->wsheader, 0, sizeof(selfConnectionData->wsheader));
480 }
481
482 static void _CD_Release(
483 WSMAN_ConnectionData* selfConnectionData)
484 mike 1.1 {
485 if (--selfConnectionData->refcounter == 0)
486 {
487 _CD_Cleanup(selfConnectionData);
488
489 free(selfConnectionData);
490 }
491 }
492
493
494 static void _SendFaultResponse(
495 Http* http,
496 WSMAN_ConnectionData* selfCD,
497 WSBUF_FAULT_CODE faultCode,
498 const MI_Char* descriptionText)
499 {
500 Page* responsePage = WSBuf_CreateFaultResponsePage(
501 faultCode,
502 selfCD->wsheader.unknownMandatoryTag,
503 selfCD->wsheader.rqtMessageID,
504 descriptionText);
505 mike 1.1
506 //printf("\n\n%s\n\n", (char*)(responsePage+1));
507
508 Http_SendResponse(http, selfCD->httpConnectionHandle,
509 HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR,
510 &responsePage);
511
512 selfCD->outstandingRequest = MI_FALSE;
513
514 if (responsePage)
515 free(responsePage);
516 }
517
518 static void _SendReleaseResponse(
519 WSMAN* self,
520 WSMAN_ConnectionData* selfCD)
521 {
522 Page* responsePage = WSBuf_CreateReleaseResponsePage(
523 selfCD->wsheader.rqtMessageID);
524
525 //printf("\n\n%s\n\n", (char*)(responsePage+1));
526 mike 1.1
527 Http_SendResponse(self->http, selfCD->httpConnectionHandle,
528 HTTP_ERROR_CODE_OK,
529 &responsePage);
530
531 selfCD->outstandingRequest = MI_FALSE;
532
533 if (responsePage)
534 free(responsePage);
535 }
536
537
538
539 static int _ValidateHeader(
540 Http* http,
541 WSMAN_ConnectionData* selfCD)
542 {
543 if (selfCD->wsheader.unknownMandatoryTag)
544 {
545 _SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_UNDERSTOOD, 0);
546 return -1;
547 mike 1.1 }
548
549 //DSP0226
550 //1756 R6.2-4: Services should reject any MaxEnvelopeSize value less than 8192 octets. This number
551 //1757 is the safe minimum in which faults can be reliably encoded for all character sets. If the requested
552 //1758 size is less than this, the service should return a wsman:EncodingLimit fault with the following
553 //1759 detail code:
554 //1760 http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/MinimumEnvelopeLimit
555
556 if (selfCD->wsheader.maxEnvelopeSize != 0 &&
557 selfCD->wsheader.maxEnvelopeSize < 8192)
558 {
559 LOGW_CHAR(("wsman: requested envelope size (%d) is too small; "
560 "expected at least 8K", (int)selfCD->wsheader.maxEnvelopeSize));
561
562 _SendFaultResponse(http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, 0);
563 return -1;
564 }
565
566 /* Limit envelope size to server's max */
567 if (selfCD->wsheader.maxEnvelopeSize == 0 ||
568 mike 1.1 selfCD->wsheader.maxEnvelopeSize > WSMAN_MAX_ENVELOPE_SIZE)
569 {
570 selfCD->wsheader.maxEnvelopeSize = WSMAN_MAX_ENVELOPE_SIZE;
571 }
572
573 /* verify action for invoke */
574 if (selfCD->wsheader.foundAction &&
575 0 == selfCD->wsheader.rqtAction &&
576 (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtMethod))
577 {
578 LOGW_CHAR(("wsman: unknown custom action"));
579
580 _SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_SUPPORTED,
581 T("unknown custom action"));
582 return -1;
583 }
584
585 return 0;
586 }
587
588 static int _ValidateEnumerateRequest(
589 mike 1.1 Http* http,
590 WSMAN_ConnectionData* selfCD)
591 {
592 /* If it has reference params, it must be an association request */
593 MI_Instance* referenceParameters =
594 selfCD->u.wsenumpullbody.associationFilter.referenceParameters;
595
596 if (referenceParameters)
597 {
598 selfCD->wsheader.rqtNamespace = referenceParameters->nameSpace;
599 selfCD->wsheader.rqtClassname = referenceParameters->classDecl->name;
600 }
601 else if (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtNamespace)
602 {
603 LOGW_CHAR(("wsman: mandatory parameters (className, namespace) "
604 "are missing for enumerate request"));
605
606 _SendFaultResponse(
607 http,
608 selfCD,
609 WSBUF_FAULT_INTERNAL_ERROR,
610 mike 1.1 T("mandatory parameters (className, namespace) "
611 "are missing for enumerate request"));
612 return -1;
613 }
614
615 //R8.2.3; DSP226
616 //wsmen:Enumerate/wsman:MaxElements
617 //(optional) indicates the maximum number of items the consumer is willing to accept in the
618 //EnumerateResponse
619 //It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
620 //implied value is 1.
621 if (!selfCD->u.wsenumpullbody.maxElements)
622 selfCD->u.wsenumpullbody.maxElements = 1;
623
624 // if enumeration mode is not specified, use 'Objects'
625 if (selfCD->u.wsenumpullbody.enumerationMode == 0)
626 selfCD->u.wsenumpullbody.enumerationMode = WSMANTAG_ENUM_MODE_OBJECT;
627
628 return 0;
629 }
630
631 mike 1.1 static int _ValidatePullRequest(
632 Http* http,
633 WSMAN_ConnectionData* selfCD)
634 {
635 MI_UNUSED(http);
636 //R8.2.3; DSP226
637 //wsmen:Enumerate/wsman:MaxElements
638 //(optional) indicates the maximum number of items the consumer is willing to accept in the
639 //EnumerateResponse
640 //It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
641 //implied value is 1.
642 if (!selfCD->u.wsenumpullbody.maxElements)
643 selfCD->u.wsenumpullbody.maxElements = 1;
644
645 return 0;
646 }
647
648 static void _ProcessEnumerateRequest(
649 Http* http,
650 void* httpConnectionHandle,
651 WSMAN* self,
652 mike 1.1 WSMAN_ConnectionData* selfCD)
653 {
654 EnumerateInstancesReq* msg;
655 WSMAN_EnumerateContext* enumContext;
656
657 /* create EnumerateContext */
658 enumContext = _WSMAN_AllocateEnumContext(self);
659
660 if (!enumContext)
661 {
662 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
663 selfCD->outstandingRequest = MI_FALSE;
664 return;
665 }
666
667 /* link new context to current EnumRequest */
668 _EC_SetActiveConnection(enumContext, selfCD);
669
670
671 // Create new request.
672 msg = EnumerateInstancesReq_New(/*_NextMsgID()*/ 1,
673 mike 1.1 WSMANFlag | _convertWSMANtoMsgEnumerationMode(selfCD->u.wsenumpullbody.enumerationMode));
674
675 if (!msg)
676 {
677 _WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
678 selfCD->enumerateContextID = 0;
679 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
680 selfCD->outstandingRequest = MI_FALSE;
681 return;
682 }
683
684 /* In case when client does not support optimized enumeration,
685 send empty Enum-response with correct enumerate context */
686 if (!selfCD->u.wsenumpullbody.allowOptimization)
687 {
688 _SendEnumPullResponse(self, enumContext);
689 _EC_SetActiveConnection(enumContext, 0);
690 _WSMAN_SetUpdateTimer(self, enumContext);
691 }
692
693 msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
694 mike 1.1 msg->className = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtClassname);
695 msg->deepInheritance = (selfCD->u.wsenumpullbody.polymorphismMode != WSMANTAG_ENUM_POLYMORPHISM_MODE_NONE);
696 msg->basePropertiesOnly = (selfCD->u.wsenumpullbody.polymorphismMode == WSMANTAG_ENUM_POLYMORPHISM_MODE_EXCLUDE_PROPS);
697
698 /* Set the query related fields */
699 {
700 if (selfCD->u.wsenumpullbody.dialect)
701 msg->queryLanguage = Batch_Strdup2(msg->base.batch, selfCD->u.wsenumpullbody.dialect);
702
703 if (selfCD->u.wsenumpullbody.filter)
704 msg->queryExpression = Batch_Strdup2(msg->base.batch, selfCD->u.wsenumpullbody.filter);
705 }
706
707 msg->base.uid = selfCD->uid;
708 msg->base.gid = selfCD->gid;
709
710 /* attach client id */
711 msg->base.clientID = PtrToUint64(enumContext);
712
713 /* increment counter to keep it alive until provider replies */
714 enumContext->refcounter++;
715 mike 1.1
716 (*self->callback)(self, &msg->base, self->callbackData);
717
718 EnumerateInstancesReq_Release(msg);
719 }
720
721 static void _ProcessAssociatorsRequest(
722 Http* http,
723 void* httpConnectionHandle,
724 WSMAN* self,
725 WSMAN_ConnectionData* selfCD)
726 {
727 AssociatorsOfReq* msg;
728 WSMAN_EnumerateContext* enumContext;
729 MI_Uint32 enumerationMode;
730
731
732 /* create EnumerateContext */
733 enumContext = _WSMAN_AllocateEnumContext(self);
734
735 if (!enumContext)
736 mike 1.1 {
737 Http_SendErrorResponse(
738 http,
739 httpConnectionHandle,
740 HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
741 selfCD->outstandingRequest = MI_FALSE;
742 return;
743 }
744
745 /* link new context to current EnumRequest */
746 _EC_SetActiveConnection(enumContext, selfCD);
747
748 /* Extract teh enumeration mode */
749 enumerationMode = _convertWSMANtoMsgEnumerationMode(
750 selfCD->u.wsenumpullbody.enumerationMode);
751
752 /* Create new request. */
753 msg = AssociatorsOfReq_New(
754 /*_NextMsgID()*/ 1,
755 WSMANFlag | enumerationMode);
756
757 mike 1.1 if (!msg)
758 {
759 _WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
760 selfCD->enumerateContextID = 0;
761 Http_SendErrorResponse(
762 http,
763 httpConnectionHandle,
764 HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
765 selfCD->outstandingRequest = MI_FALSE;
766 return;
767 }
768
769 /* In case when client does not support optimized enumeration,
770 * send empty Enum-response with correct enumerate context
771 */
772 if (!selfCD->u.wsenumpullbody.allowOptimization)
773 {
774 _SendEnumPullResponse(self, enumContext);
775 _EC_SetActiveConnection(enumContext, 0);
776 _WSMAN_SetUpdateTimer(self, enumContext);
777 }
778 mike 1.1
779 msg->nameSpace = Batch_Strdup2(
780 msg->base.batch,
781 selfCD->wsheader.rqtNamespace);
782
783 msg->className = Batch_Strdup2(
784 msg->base.batch,
785 selfCD->wsheader.rqtClassname);
786
787 msg->base.uid = selfCD->uid;
788 msg->base.gid = selfCD->gid;
789
790 /* Set messages fileds from association filter */
791 {
792 WSMAN_AssociationFilter* filter =
793 &selfCD->u.wsenumpullbody.associationFilter;
794
795 msg->instance = filter->referenceParameters;
796 msg->assocClass = filter->associationClassName;
797 msg->resultClass = filter->resultClassName;
798 msg->role = filter->role;
799 mike 1.1 msg->resultRole = filter->resultRole;
800 }
801
802 /* attach client id */
803 msg->base.clientID = PtrToUint64(enumContext);
804
805 /* increment counter to keep it alive until provider replies */
806 enumContext->refcounter++;
807
808 (*self->callback)(self, &msg->base, self->callbackData);
809
810 AssociatorsOfReq_Release(msg);
811 }
812
813 static void _ProcessPullRequest(
814 Http* http,
815 WSMAN* self,
816 WSMAN_ConnectionData* selfCD)
817 {
818 WSMAN_EnumerateContext* enumContext;
819
820 mike 1.1 /* find EnumerateContext */
821 enumContext = _WSMAN_FindEnumContext(self, selfCD->u.wsenumpullbody.enumerationContextID);
822
823 if (!enumContext)
824 {
825 _SendFaultResponse(http, selfCD, WSBUF_FAULT_DESTINATION_UNREACHABLE, T("Enumeration context not found"));
826 return;
827 }
828
829 /* link new context to the request */
830 _EC_SetActiveConnection(enumContext, selfCD);
831
832 _ProcessEnumResponse(self, enumContext, MI_TRUE);
833
834 }
835
836 static void _ProcessReleaseRequest(
837 Http* http,
838 WSMAN* self,
839 WSMAN_ConnectionData* selfCD)
840 {
841 mike 1.1 WSMAN_EnumerateContext* enumContext;
842
843 /* find EnumerateContext */
844 enumContext = _WSMAN_FindEnumContext(self, selfCD->u.wsenumpullbody.enumerationContextID);
845
846 if (!enumContext)
847 {
848 _SendFaultResponse(http, selfCD, WSBUF_FAULT_DESTINATION_UNREACHABLE, T("Enumeration context not found"));
849 return;
850 }
851
852 /* Remove context from the list */
853 _WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
854
855 _SendReleaseResponse(self, selfCD);
856 }
857
858 static void _ParseValidateProcessEnumerateRequest(
859 Http* http,
860 void* httpConnectionHandle,
861 WSMAN* self,
862 mike 1.1 WSMAN_ConnectionData* selfCD,
863 XML* xml)
864 {
865 /* ATTN: only used if enumeration contains an association filter. Find
866 * some way to prevent creation in that case.
867 */
868
869 if (!selfCD->wsheader.instanceBatch)
870 {
871 selfCD->wsheader.instanceBatch = Batch_New(BATCH_MAX_PAGES);
872 }
873
874 /* Parse enumerate request/body */
875 if (WS_ParseEnumerateBody(
876 xml,
877 &selfCD->wsheader.instanceBatch,
878 &selfCD->u.wsenumpullbody) != 0)
879 {
880 LOGW_CHAR(("wsman: unable to parse incoming xml/ enumerate request body"));
881 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
882 selfCD->outstandingRequest = MI_FALSE;
883 mike 1.1 return;
884 }
885
886 /* Validate enumerate request body */
887 if (_ValidateEnumerateRequest(http, selfCD) != 0)
888 {
889 /* appropriate error code was already sent to the client */
890 return;
891 }
892
893 /* Process reqest */
894
895 if (selfCD->u.wsenumpullbody.foundAssociationFilter)
896 {
897 _ProcessAssociatorsRequest(http,httpConnectionHandle,self,selfCD);
898 }
899 else
900 {
901 _ProcessEnumerateRequest(http,httpConnectionHandle,self,selfCD);
902 }
903 }
904 mike 1.1
905 static void _ParseValidateProcessInvokeRequest(
906 Http* http,
907 void* httpConnectionHandle,
908 WSMAN* self,
909 WSMAN_ConnectionData* selfCD,
910 XML* xml)
911 {
912 InvokeReq* msg = 0;
913
914 /* if instance was created from batch, re-use exisintg batch to allocate message */
915 if (selfCD->wsheader.instanceBatch)
916 {
917 /* Allocate heap space for message */
918 msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(InvokeReq));
919
920 if (!msg)
921 goto failed;
922
923 /* Set the tag */
924 msg->base.tag = InvokeReqTag;
925 mike 1.1
926 /* Set the message id and flags */
927 msg->base.msgID = 1;
928 msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
929
930 /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
931 msg->base.refCounter = 1;
932
933 /* Copy batch onto message (released by delete method) */
934 msg->base.batch = selfCD->wsheader.instanceBatch;
935
936 msg->instance = selfCD->wsheader.instance;
937 selfCD->wsheader.instanceBatch = 0;
938 selfCD->wsheader.instance = 0;
939 }
940 else
941 msg = InvokeReq_New(1, WSMANFlag | WSMAN_ObjectFlag);
942
943 if (!msg)
944 goto failed;
945
946 mike 1.1 /* Parse invoke request/body */
947 if (WS_ParseInvokeBody(xml, msg->base.batch, &msg->instanceParams) != 0)
948 goto failed;
949
950 /* Extract/set relevant parameters */
951 if (selfCD->wsheader.rqtNamespace)
952 msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
953
954 msg->className = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtClassname);
955 msg->function = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtMethod);
956
957 /* attach client id */
958 msg->base.clientID = PtrToUint64(selfCD);
959 msg->base.uid = selfCD->uid;
960 msg->base.gid = selfCD->gid;
961
962 /* increment counter to keep it alive until provider replies */
963 selfCD->refcounter++;
964
965 (*self->callback)(self, &msg->base, self->callbackData);
966
967 mike 1.1 InvokeReq_Release(msg);
968 return;
969
970 failed:
971 LOGW_CHAR(("wsman: unable to process invoke request"));
972 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
973 selfCD->outstandingRequest = MI_FALSE;
974
975 if (msg)
976 InvokeReq_Release(msg);
977 }
978
979 static void _ParseValidateProcessGetRequest(
980 Http* http,
981 void* httpConnectionHandle,
982 WSMAN* self,
983 WSMAN_ConnectionData* selfCD,
984 XML* xml)
985 {
986 GetInstanceReq* msg = 0;
987
988 mike 1.1 MI_UNUSED(xml);
989
990 /* Check if instance name parameter was specified */
991 if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
992 {
993 LOGW_CHAR(("wsman: get-instance: instance name parameter is missing"));
994 _SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("get-instance: instance name parameter is missing"));
995
996 selfCD->outstandingRequest = MI_FALSE;
997 return;
998 }
999
1000 /* if instance was created from batch, re-use exisintg batch to allocate message */
1001 /* Allocate heap space for message */
1002 msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(GetInstanceReq));
1003
1004 if (!msg)
1005 goto failed;
1006
1007 /* Set the tag */
1008 msg->base.tag = GetInstanceReqTag;
1009 mike 1.1
1010 /* Set the message id and flags */
1011 msg->base.msgID = 1;
1012 msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
1013
1014 /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
1015 msg->base.refCounter = 1;
1016
1017 /* Copy batch into message (released by delete method) */
1018 msg->base.batch = selfCD->wsheader.instanceBatch;
1019
1020 msg->instanceName = selfCD->wsheader.instance;
1021
1022 /* clear batch/instance fields in header structure */
1023 selfCD->wsheader.instanceBatch = 0;
1024 selfCD->wsheader.instance = 0;
1025
1026 /* Skip parsing get-request/body - assumed to be empty */
1027
1028 /* Extract/set relevant parameters */
1029 if (selfCD->wsheader.rqtNamespace)
1030 mike 1.1 msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
1031
1032 /* attach client id */
1033 msg->base.clientID = PtrToUint64(selfCD);
1034 msg->base.uid = selfCD->uid;
1035 msg->base.gid = selfCD->gid;
1036
1037 /* increment counter to keep it alive until provider replies */
1038 selfCD->refcounter++;
1039
1040 (*self->callback)(self, &msg->base, self->callbackData);
1041
1042 GetInstanceReq_Release(msg);
1043 return;
1044
1045 failed:
1046 LOGW_CHAR(("wsman: unable to process get-instance request"));
1047 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1048 selfCD->outstandingRequest = MI_FALSE;
1049
1050 if (msg)
1051 mike 1.1 GetInstanceReq_Release(msg);
1052 }
1053
1054 static void _ParseValidateProcessPutRequest(
1055 Http* http,
1056 void* httpConnectionHandle,
1057 WSMAN* self,
1058 WSMAN_ConnectionData* selfCD,
1059 XML* xml)
1060 {
1061 ModifyInstanceReq* msg = 0;
1062
1063 MI_UNUSED(xml);
1064
1065 /* Check if instance name parameter was specified */
1066 if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
1067 {
1068 LOGW_CHAR(("wsman: Put-instance: instance name parameter is missing"));
1069 _SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("Put-instance: instance name parameter is missing"));
1070
1071 selfCD->outstandingRequest = MI_FALSE;
1072 mike 1.1 return;
1073 }
1074
1075 /* if instance was created from batch, re-use exisintg batch to allocate message */
1076 /* Allocate heap space for message */
1077 msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(ModifyInstanceReq));
1078
1079 if (!msg)
1080 goto failed;
1081
1082 /* Set the tag */
1083 msg->base.tag = ModifyInstanceReqTag;
1084
1085 /* Set the message id and flags */
1086 msg->base.msgID = 1;
1087 msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
1088
1089 /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
1090 msg->base.refCounter = 1;
1091
1092 /* Copy batch into message (released by delete method) */
1093 mike 1.1 msg->base.batch = selfCD->wsheader.instanceBatch;
1094 msg->instance = selfCD->wsheader.instance;
1095
1096 /* clear batch/instance fields in header structure */
1097 selfCD->wsheader.instanceBatch = 0;
1098 selfCD->wsheader.instance = 0;
1099
1100 /* re-use 'create' parser to parse 'Modify' request/body */
1101 if (WS_ParseCreateBody(xml, msg->base.batch, &msg->instance) != 0)
1102 goto failed;
1103
1104 /* Extract/set relevant parameters */
1105 if (selfCD->wsheader.rqtNamespace)
1106 msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
1107
1108 /* attach client id */
1109 msg->base.clientID = PtrToUint64(selfCD);
1110 msg->base.uid = selfCD->uid;
1111 msg->base.gid = selfCD->gid;
1112
1113 /* increment counter to keep it alive until provider replies */
1114 mike 1.1 selfCD->refcounter++;
1115
1116 (*self->callback)(self, &msg->base, self->callbackData);
1117
1118 ModifyInstanceReq_Release(msg);
1119 return;
1120
1121 failed:
1122 LOGW_CHAR(("wsman: unable to process Put-instance request"));
1123 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1124 selfCD->outstandingRequest = MI_FALSE;
1125
1126 if (msg)
1127 ModifyInstanceReq_Release(msg);
1128 }
1129
1130 static void _ParseValidateProcessDeleteRequest(
1131 Http* http,
1132 void* httpConnectionHandle,
1133 WSMAN* self,
1134 WSMAN_ConnectionData* selfCD,
1135 mike 1.1 XML* xml)
1136 {
1137 DeleteInstanceReq* msg = 0;
1138
1139 MI_UNUSED(xml);
1140
1141 /* Check if instance name parameter was specified */
1142 if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
1143 {
1144 LOGW_CHAR(("wsman: delete-instance: instance name parameter is missing"));
1145 _SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("delete-instance: instance name parameter is missing"));
1146
1147 selfCD->outstandingRequest = MI_FALSE;
1148 return;
1149 }
1150
1151 /* if instance was created from batch, re-use exisintg batch to allocate message */
1152 /* Allocate heap space for message */
1153 msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(DeleteInstanceReq));
1154
1155 if (!msg)
1156 mike 1.1 goto failed;
1157
1158 /* Set the tag */
1159 msg->base.tag = DeleteInstanceReqTag;
1160
1161 /* Set the message id and flags */
1162 msg->base.msgID = 1;
1163 msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
1164
1165 /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
1166 msg->base.refCounter = 1;
1167
1168 /* Copy batch into message (released by delete method) */
1169 msg->base.batch = selfCD->wsheader.instanceBatch;
1170
1171 msg->instanceName = selfCD->wsheader.instance;
1172
1173 /* clear batch/instance fields in header structure */
1174 selfCD->wsheader.instanceBatch = 0;
1175 selfCD->wsheader.instance = 0;
1176
1177 mike 1.1 /* Skip parsing Delete-request/body - assumed to be empty */
1178
1179 /* Extract/set relevant parameters */
1180 if (selfCD->wsheader.rqtNamespace)
1181 msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
1182
1183 /* attach client id */
1184 msg->base.clientID = PtrToUint64(selfCD);
1185 msg->base.uid = selfCD->uid;
1186 msg->base.gid = selfCD->gid;
1187
1188 /* increment counter to keep it alive until provider replies */
1189 selfCD->refcounter++;
1190
1191 (*self->callback)(self, &msg->base, self->callbackData);
1192
1193 DeleteInstanceReq_Release(msg);
1194 return;
1195
1196 failed:
1197 LOGW_CHAR(("wsman: unable to process delete-instance request"));
1198 mike 1.1 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1199 selfCD->outstandingRequest = MI_FALSE;
1200
1201 if (msg)
1202 DeleteInstanceReq_Release(msg);
1203 }
1204
1205 static void _ParseValidateProcessCreateRequest(
1206 Http* http,
1207 void* httpConnectionHandle,
1208 WSMAN* self,
1209 WSMAN_ConnectionData* selfCD,
1210 XML* xml)
1211 {
1212 CreateInstanceReq* msg = 0;
1213
1214 msg = CreateInstanceReq_New(1, WSMANFlag | WSMAN_CreatedEPRFlag);
1215
1216 if (!msg)
1217 goto failed;
1218
1219 mike 1.1 /* Parse create request/body */
1220 if (WS_ParseCreateBody(xml, msg->base.batch, &msg->instance) != 0)
1221 goto failed;
1222
1223 /* Extract/set relevant parameters */
1224 if (selfCD->wsheader.rqtNamespace)
1225 msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
1226
1227 /* attach client id */
1228 msg->base.clientID = PtrToUint64(selfCD);
1229 msg->base.uid = selfCD->uid;
1230 msg->base.gid = selfCD->gid;
1231
1232 /* increment counter to keep it alive until provider replies */
1233 selfCD->refcounter++;
1234
1235 (*self->callback)(self, &msg->base, self->callbackData);
1236
1237 CreateInstanceReq_Release(msg);
1238 return;
1239
1240 mike 1.1 failed:
1241 LOGW_CHAR(("wsman: unable to process Create request"));
1242 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1243 selfCD->outstandingRequest = MI_FALSE;
1244
1245 if (msg)
1246 CreateInstanceReq_Release(msg);
1247 }
1248
1249 static void _ParseValidateProcessPullRequest(
1250 Http* http,
1251 void* httpConnectionHandle,
1252 WSMAN* self,
1253 WSMAN_ConnectionData* selfCD,
1254 XML* xml)
1255 {
1256 /* Parse pull request/body */
1257 if (WS_ParsePullBody(xml, &selfCD->u.wsenumpullbody) != 0)
1258 {
1259 LOGW_CHAR(("wsman: unable to parse incoming xml/ Pull request body"));
1260 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1261 mike 1.1 selfCD->outstandingRequest = MI_FALSE;
1262 return;
1263 }
1264
1265 /* Validate enumerate request body */
1266 if (_ValidatePullRequest(http, selfCD) != 0)
1267 {
1268 /* appropriate error code was already sent to the client */
1269 return;
1270 }
1271
1272 /* Process reqest */
1273 _ProcessPullRequest(http,self,selfCD);
1274 }
1275
1276 static void _ParseValidateProcessReleaseRequest(
1277 Http* http,
1278 void* httpConnectionHandle,
1279 WSMAN* self,
1280 WSMAN_ConnectionData* selfCD,
1281 XML* xml)
1282 mike 1.1 {
1283 /* Parse pull request/body */
1284 if (WS_ParseReleaseBody(xml, &selfCD->u.wsenumpullbody) != 0)
1285 {
1286 LOGW_CHAR(("wsman: unable to parse incoming xml/ Release request body"));
1287 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1288 selfCD->outstandingRequest = MI_FALSE;
1289 return;
1290 }
1291
1292 /* Validate enumerate request body */
1293 /* no validation needed */
1294
1295 /* Process reqest */
1296 _ProcessReleaseRequest(http,self,selfCD);
1297 }
1298
1299 static void _SendIdentifyResponse(
1300 WSMAN* self,
1301 WSMAN_ConnectionData* selfCD)
1302 {
1303 mike 1.1 WS_Buffer out;
1304 Page* responsePage = 0;
1305 # define MSG \
1306 "<soap:Envelope " \
1307 "xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" " \
1308 "xmlns:wsmid=\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\">" CR \
1309 "<soap:Header/>" CR \
1310 "<soap:Body>" CR \
1311 "<soap:IdentifyResponse>" CR \
1312 "<wsmid:ProtocolVersion>" \
1313 "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" \
1314 "</wsmid:ProtocolVersion>" CR \
1315 "<wsmid:ProductVendor>" \
1316 CONFIG_FULLPRODUCT \
1317 "</wsmid:ProductVendor>" CR \
1318 "<wsmid:ProductVersion>" \
1319 CONFIG_VERSION \
1320 "</wsmid:ProductVersion>" CR \
1321 "<wsmid:SecurityProfiles>" CR \
1322 "<wsmid:SecurityProfileName>" \
1323 "http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/https/basic" \
1324 mike 1.1 "</wsmid:SecurityProfileName>" CR \
1325 "</wsmid:SecurityProfiles>" CR \
1326 "</soap:IdentifyResponse>" CR \
1327 "</soap:Body>" CR \
1328 "</soap:Envelope>" CR
1329
1330 if (WSBuf_Init(&out, 1024) != MI_RESULT_OK)
1331 {
1332 goto failed;
1333 }
1334
1335 if (WSBuf_AddLit(&out, LIT(MSG)) != MI_RESULT_OK)
1336 {
1337 goto failed;
1338 }
1339
1340 responsePage = WSBuf_StealPage(&out);
1341
1342 if (!responsePage)
1343 goto failed;
1344
1345 mike 1.1 if (self->options.enableTracing)
1346 {
1347 printf("%s\n\n", (char*)(responsePage+1));
1348 }
1349
1350 Http_SendResponse(
1351 self->http,
1352 selfCD->httpConnectionHandle,
1353 HTTP_ERROR_CODE_OK,
1354 &responsePage);
1355
1356 selfCD->outstandingRequest = MI_FALSE;
1357
1358 if (responsePage)
1359 free(responsePage);
1360
1361 return;
1362
1363 failed:
1364 WSBuf_Destroy(&out);
1365 Http_SendErrorResponse(
1366 mike 1.1 self->http,
1367 selfCD->httpConnectionHandle,
1368 HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1369 selfCD->outstandingRequest = MI_FALSE;
1370 }
1371
1372 static void _HandleIdentifyRequest(
1373 Http* http,
1374 void* httpConnectionHandle,
1375 WSMAN* self,
1376 WSMAN_ConnectionData* selfCD,
1377 XML* xml)
1378 {
1379 /* Parse pull request/body */
1380 if (WS_ParseIdentifyBody(xml) != 0)
1381 {
1382 LOGW_CHAR(("wsman: found neither Action or Identify"));
1383 Http_SendErrorResponse(http, httpConnectionHandle,
1384 HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1385 selfCD->outstandingRequest = MI_FALSE;
1386 return;
1387 mike 1.1 }
1388
1389 _SendIdentifyResponse(self, selfCD);
1390 }
1391
1392 /************************************************************************\
1393 * Dispatcher calls processing
1394 \************************************************************************/
1395
1396 static void _EC_GetMessageSubset(
1397 WSMAN_EnumerateContext* selfEC,
1398 WSMAN_ConnectionData* selfCD,
1399 PostInstanceMsg** subsetEnd,
1400 MI_Uint32* totalSize)
1401 {
1402 MI_Uint32 count = 0;
1403 *totalSize = 0;
1404 *subsetEnd = selfEC->head;
1405
1406 while (*subsetEnd)
1407 {
1408 mike 1.1 if (count + 1 > selfCD->u.wsenumpullbody.maxElements ||
1409 (*totalSize) + (*subsetEnd)->packedInstanceSize + WSMAN_APROX_ENUM_RESP_HEADER_SIZE > selfCD->wsheader.maxEnvelopeSize)
1410 break;
1411
1412 (*totalSize) += (*subsetEnd)->packedInstanceSize;
1413 count++;
1414 (*subsetEnd) = (PostInstanceMsg*)(*subsetEnd)->base.next;
1415 }
1416 }
1417
1418 /* Sends as many instances as posisble (based on envelope-size and instance counter) */
1419 static void _SendEnumPullResponse(
1420 WSMAN* self,
1421 WSMAN_EnumerateContext* selfEC)
1422 {
1423 WS_Buffer outBufHeader, outBufTrailer;
1424 Page* responsePageCombined = 0;
1425 Page* responsePageHeader = 0;
1426 Page* responsePageTrailer = 0;
1427 MI_Uint32 totalSize, messagesSize = 0;
1428 WSMAN_ConnectionData* selfCD = selfEC->activeConnection;
1429 mike 1.1 PostInstanceMsg* subsetEnd = 0;
1430 MI_Boolean endOfSequence = selfEC->enumerationCompleted;
1431
1432
1433 /* Get message subset based on envelope size/ maxElements */
1434 _EC_GetMessageSubset(selfEC, selfCD, &subsetEnd, &messagesSize);
1435
1436 /* validate if all mesages can be sent */
1437 if (endOfSequence && subsetEnd)
1438 {
1439 endOfSequence = MI_FALSE;
1440 }
1441
1442 /* check if we can put at least one message in response */
1443 if (NULL != selfEC->head &&
1444 subsetEnd == selfEC->head)
1445 {
1446 LOGW_CHAR(("wsman: max-envelope is too small even for one message; message size %d",
1447 (int)subsetEnd->packedInstanceSize ));
1448 _SendFaultResponse(self->http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, T("insufficient envelope size for instance transferring"));
1449 /* Note: leaving context 'as is' so advanced client can increase packet size and re-try */
1450 mike 1.1 return;
1451 }
1452
1453 /* Create EnumResponse */
1454 if (WSBuf_Init(&outBufHeader, WSMAN_APROX_ENUM_RESP_HEADER_SIZE) != MI_RESULT_OK)
1455 {
1456 outBufTrailer.page = 0;
1457 goto failed;
1458 }
1459
1460 if (WSBuf_Init(&outBufTrailer, 256) != MI_RESULT_OK)
1461 goto failed;
1462
1463 /* prepare response header */
1464 if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
1465 {
1466 if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
1467 LIT(T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse")), selfCD->wsheader.rqtMessageID))
1468 goto failed;
1469 }
1470 else
1471 mike 1.1 {
1472 if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
1473 LIT(T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse")), selfCD->wsheader.rqtMessageID))
1474 goto failed;
1475 }
1476
1477 if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
1478 LIT(T("</SOAP-ENV:Header>")
1479 T("<SOAP-ENV:Body>"))))
1480 goto failed;
1481
1482 if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
1483 {
1484 if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
1485 LIT(T("<wsen:EnumerateResponse>"))))
1486 goto failed;
1487 }
1488 else
1489 {
1490 if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
1491 LIT(T("<wsen:PullResponse>"))))
1492 mike 1.1 goto failed;
1493 }
1494
1495 if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
1496 LIT(T("<wsen:EnumerationContext>"))))
1497 goto failed;
1498
1499 if (MI_RESULT_OK != WSBuf_AddUint32(&outBufHeader,selfEC->enumerationContextID))
1500 goto failed;
1501
1502 if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
1503 LIT(T("</wsen:EnumerationContext>"))))
1504 goto failed;
1505
1506 if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
1507 {
1508 if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
1509 LIT(T("<wsman:Items>"))))
1510 goto failed;
1511 }
1512 else
1513 mike 1.1 {
1514 if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
1515 LIT(T("<wsen:Items>"))))
1516 goto failed;
1517 }
1518
1519
1520
1521 /* trailer */
1522 if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
1523 {
1524 if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
1525 LIT(T("</wsman:Items>"))))
1526 goto failed;
1527 }
1528 else
1529 {
1530 if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
1531 LIT(T("</wsen:Items>"))))
1532 goto failed;
1533 }
1534 mike 1.1
1535 if (endOfSequence)
1536 {
1537 if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
1538 {
1539 if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
1540 LIT(T("<wsman:EndOfSequence/>"))))
1541 goto failed;
1542 }
1543 else
1544 {
1545 if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
1546 LIT(T("<wsen:EndOfSequence/>"))))
1547 goto failed;
1548 }
1549 }
1550
1551 if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
1552 {
1553 if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
1554 LIT(T("</wsen:EnumerateResponse>"))))
1555 mike 1.1 goto failed;
1556 }
1557 else
1558 {
1559 if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
1560 LIT(T("</wsen:PullResponse>"))))
1561 goto failed;
1562 }
1563 if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
1564 LIT(T("</SOAP-ENV:Body>")
1565 T("</SOAP-ENV:Envelope>"))))
1566 goto failed;
1567
1568 /* all together */
1569 responsePageHeader = WSBuf_StealPage(&outBufHeader);
1570 responsePageTrailer = WSBuf_StealPage(&outBufTrailer);
1571
1572 if (!responsePageTrailer || !responsePageHeader)
1573 goto failed;
1574
1575 /* calculate size */
1576 mike 1.1 totalSize = (MI_Uint32)(responsePageHeader->u.s.size + responsePageTrailer->u.s.size) + messagesSize;
1577
1578 responsePageCombined = (Page*)malloc(sizeof(Page) + totalSize + 1);
1579
1580 if (!responsePageCombined)
1581 goto failed;
1582
1583 {
1584 char* data = (char*) (responsePageCombined + 1);
1585 data[totalSize] = 0;
1586
1587 memcpy(data, responsePageHeader+1, responsePageHeader->u.s.size);
1588 data += responsePageHeader->u.s.size;
1589
1590 {
1591 PostInstanceMsg* msg = selfEC->head;
1592 while (msg != subsetEnd)
1593 {
1594 PostInstanceMsg* next = (PostInstanceMsg*)msg->base.next;
1595
1596 memcpy(data, msg->packedInstancePtr, msg->packedInstanceSize);
1597 mike 1.1 data += msg->packedInstanceSize;
1598
1599 /* remove message from the list */
1600 selfEC->totalResponses--;
1601 selfEC->totalResponseSize -= msg->packedInstanceSize;
1602 List_Remove(
1603 (ListElem**)&selfEC->head,
1604 (ListElem**)&selfEC->tail,
1605 (ListElem*)msg);
1606 PostInstanceMsg_Release(msg);
1607
1608 msg = next;
1609 }
1610 }
1611
1612 memcpy(data, responsePageTrailer+1, responsePageTrailer->u.s.size);
1613 data += responsePageTrailer->u.s.size;
1614
1615 responsePageCombined->u.s.size = totalSize;
1616 responsePageCombined->u.s.next = 0;
1617 }
1618 mike 1.1
1619 free(responsePageHeader); responsePageHeader = 0;
1620 free(responsePageTrailer); responsePageTrailer = 0;
1621
1622 /* Trace the response XML */
1623
1624 if (self->options.enableTracing)
1625 {
1626 printf("%s\n\n", (char*)(responsePageCombined+1));
1627 }
1628
1629 /*{
1630 FILE* f = Fopen("out_test.xml", "a");
1631 fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
1632 fclose(f);
1633 }*/
1634
1635 Http_SendResponse(
1636 self->http,
1637 selfCD->httpConnectionHandle,
1638 HTTP_ERROR_CODE_OK,
1639 mike 1.1 &responsePageCombined);
1640
1641 selfCD->outstandingRequest = MI_FALSE;
1642
1643 if (responsePageCombined)
1644 free(responsePageCombined);
1645
1646 return;
1647
1648 failed:
1649 WSBuf_Destroy(&outBufHeader);
1650 WSBuf_Destroy(&outBufTrailer);
1651 if (responsePageCombined) free(responsePageCombined);
1652 if (responsePageHeader) free(responsePageHeader);
1653 if (responsePageTrailer) free(responsePageTrailer);
1654
1655 _EC_ReleaseAllMessages(selfEC);
1656 Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1657 selfCD->outstandingRequest = MI_FALSE;
1658 }
1659
1660 mike 1.1 static void _SendInvokeResponse(
1661 WSMAN* self,
1662 WSMAN_ConnectionData* selfCD,
1663 PostInstanceMsg* message)
1664 {
1665 WS_Buffer outBuf;
1666 Page* responsePage = 0;
1667 MI_Char* action = 0;
1668 MI_Uint32 actionLen;
1669
1670 /* create action */
1671 actionLen = (MI_Uint32)(7 /* http:// */ +
1672 27 /* "/wbem/wscim/1/cim-schema/2/" */ +
1673 1 /* / between cn/meth */ +
1674 1 /* \0 at the end */ +
1675 strlen(selfCD->wsheader.rqtServer) +
1676 strlen(selfCD->wsheader.rqtClassname) +
1677 strlen(selfCD->wsheader.rqtMethod));
1678
1679 action = (MI_Char*)malloc(actionLen * sizeof(MI_Char));
1680
1681 mike 1.1 if (!action)
1682 goto failed;
1683
1684 #if (MI_CHAR_TYPE == 1)
1685 //Snprintf(action, actionLen, T("http://%s/wbem/wscim/1/cim-schema/2/%s/%s"),
1686 // selfCD->wsheader.rqtServer, selfCD->wsheader.rqtClassname, selfCD->wsheader.rqtMethod);
1687 {
1688 MI_Uint32 size;
1689 action[0] = 0;
1690 size = Strlcat(action, "http://", actionLen);
1691 size += Strlcat(action + size, selfCD->wsheader.rqtServer, actionLen - size);
1692 size += Strlcat(action + size, "/wbem/wscim/1/cim-schema/2/", actionLen - size);
1693 size += Strlcat(action + size, selfCD->wsheader.rqtClassname, actionLen - size);
1694 size += Strlcat(action + size, "/", actionLen - size);
1695 size += Strlcat(action + size, selfCD->wsheader.rqtMethod, actionLen - size);
1696
1697 assert(size == (actionLen-1));
1698 }
1699 #else
1700 Szprintf(action, actionLen, T("http://%S/wbem/wscim/1/cim-schema/2/%S/%S"),
1701 selfCD->wsheader.rqtServer, selfCD->wsheader.rqtClassname, selfCD->wsheader.rqtMethod);
1702 mike 1.1 #endif
1703
1704 actionLen--;
1705
1706 /* Create EnumResponse */
1707 if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE + message->packedInstanceSize) != MI_RESULT_OK)
1708 goto failed;
1709
1710 /* prepare response header */
1711 if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
1712 action, actionLen, selfCD->wsheader.rqtMessageID))
1713 goto failed;
1714
1715 if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
1716 LIT(T("</SOAP-ENV:Header>")
1717 T("<SOAP-ENV:Body>")
1718 T("<n1:ExecuteCommand_OUTPUT xmlns:n1=\"")
1719 )))
1720 goto failed;
1721
1722 if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
1723 mike 1.1 action, actionLen))
1724 goto failed;
1725
1726 if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
1727 LIT(T("\">"))))
1728 goto failed;
1729
1730
1731 if (MI_RESULT_OK != WSBuf_AddCharLit(&outBuf,
1732 message->packedInstancePtr, message->packedInstanceSize))
1733 goto failed;
1734
1735 /* trailer */
1736 if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
1737 LIT(
1738 T("</n1:ExecuteCommand_OUTPUT>")
1739 T("</SOAP-ENV:Body>")
1740 T("</SOAP-ENV:Envelope>"))))
1741 goto failed;
1742
1743 /* all together */
1744 mike 1.1 responsePage = WSBuf_StealPage(&outBuf);
1745
1746 if (!responsePage)
1747 goto failed;
1748
1749 /* Trace the response XML */
1750
1751 if (self->options.enableTracing)
1752 {
1753 printf("%s\n\n", (char*)(responsePage+1));
1754 }
1755
1756 /*{
1757 FILE* f = Fopen("out_test.xml", "a");
1758 fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
1759 fclose(f);
1760 }*/
1761
1762 Http_SendResponse(
1763 self->http,
1764 selfCD->httpConnectionHandle,
1765 mike 1.1 HTTP_ERROR_CODE_OK,
1766 &responsePage);
1767
1768 /* indicate that response was sent */
1769 selfCD->outstandingRequest = MI_FALSE;
1770
1771 if (responsePage)
1772 free(responsePage);
1773
1774 if (action)
1775 free(action);
1776
1777 return;
1778
1779 failed:
1780 WSBuf_Destroy(&outBuf);
1781 if (responsePage) free(responsePage);
1782 if (action) free(action);
1783
1784 Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1785
1786 mike 1.1 /* indicate that response was sent */
1787 selfCD->outstandingRequest = MI_FALSE;
1788 }
1789
1790 static void _SendSingleInstanceResponse(
1791 WSMAN* self,
1792 WSMAN_ConnectionData* selfCD,
1793 PostInstanceMsg* message,
1794 const MI_Char* action,
1795 MI_Uint32 actionSize)
1796 {
1797 WS_Buffer outBuf;
1798 Page* responsePage = 0;
1799
1800 if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE + message->packedInstanceSize) != MI_RESULT_OK)
1801 goto failed;
1802
1803 if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
1804 action, actionSize, selfCD->wsheader.rqtMessageID))
1805 goto failed;
1806
1807 mike 1.1 if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
1808 LIT(T("</SOAP-ENV:Header>")
1809 T("<SOAP-ENV:Body>")
1810 )))
1811 goto failed;
1812
1813
1814 if (MI_RESULT_OK != WSBuf_AddCharLit(&outBuf,
1815 message->packedInstancePtr, message->packedInstanceSize))
1816 goto failed;
1817
1818 /* trailer */
1819 if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
1820 LIT(
1821 T("</SOAP-ENV:Body>")
1822 T("</SOAP-ENV:Envelope>"))))
1823 goto failed;
1824
1825 /* all together */
1826 responsePage = WSBuf_StealPage(&outBuf);
1827
1828 mike 1.1 if (!responsePage)
1829 goto failed;
1830
1831 /* Trace the response XML */
1832
1833 if (self->options.enableTracing)
1834 {
1835 printf("%s\n\n", (char*)(responsePage+1));
1836 }
1837
1838 /* {
1839 FILE* f = Fopen("out_test.xml", "a");
1840 fwrite((char*)(responsePage+1), 1, (size_t)responsePage->u.s.size, f);
1841 fclose(f);
1842 } */
1843
1844 Http_SendResponse(
1845 self->http,
1846 selfCD->httpConnectionHandle,
1847 HTTP_ERROR_CODE_OK,
1848 &responsePage);
1849 mike 1.1
1850 /* indicate that response was sent */
1851 selfCD->outstandingRequest = MI_FALSE;
1852
1853 if (responsePage)
1854 free(responsePage);
1855
1856 return;
1857
1858 failed:
1859 WSBuf_Destroy(&outBuf);
1860 if (responsePage) free(responsePage);
1861
1862 Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1863
1864 /* indicate that response was sent */
1865 selfCD->outstandingRequest = MI_FALSE;
1866 }
1867
1868 static void _SendDeleteInstanceResponse(
1869 WSMAN* self,
1870 mike 1.1 WSMAN_ConnectionData* selfCD)
1871 {
1872 WS_Buffer outBuf;
1873 Page* responsePage = 0;
1874
1875 if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE) != MI_RESULT_OK)
1876 goto failed;
1877
1878 if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
1879 LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/DeleteResponse")), selfCD->wsheader.rqtMessageID))
1880 goto failed;
1881
1882 if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
1883 LIT(T("</SOAP-ENV:Header>")
1884 T("<SOAP-ENV:Body/>")
1885 T("</SOAP-ENV:Envelope>")
1886 )))
1887 goto failed;
1888
1889 /* all together */
1890 responsePage = WSBuf_StealPage(&outBuf);
1891 mike 1.1
1892 if (!responsePage)
1893 goto failed;
1894
1895 /* Trace the response XML */
1896
1897 if (self->options.enableTracing)
1898 {
1899 printf("%s\n\n", (char*)(responsePage+1));
1900 }
1901
1902 /*{
1903 FILE* f = Fopen("out_test.xml", "a");
1904 fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
1905 fclose(f);
1906 }*/
1907
1908 Http_SendResponse(
1909 self->http,
1910 selfCD->httpConnectionHandle,
1911 HTTP_ERROR_CODE_OK,
1912 mike 1.1 &responsePage);
1913
1914 /* indicate that response was sent */
1915 selfCD->outstandingRequest = MI_FALSE;
1916
1917 if (responsePage)
1918 free(responsePage);
1919
1920 return;
1921
1922 failed:
1923 WSBuf_Destroy(&outBuf);
1924 if (responsePage) free(responsePage);
1925
1926 Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
1927
1928 /* indicate that response was sent */
1929 selfCD->outstandingRequest = MI_FALSE;
1930 }
1931
1932 static void _SendErrorResponse(
1933 mike 1.1 WSMAN* self,
1934 WSMAN_ConnectionData* selfCD,
1935 MI_Result result)
1936 {
1937 WSBUF_FAULT_CODE faultCode;
1938 const MI_Char* description = 0;
1939
1940 faultCode = WSBuf_CIMErrorToWSFault(result, &description);
1941
1942 /* ATTN! consume text from cim_error if supplied */
1943 _SendFaultResponse(self->http, selfCD, faultCode, description);
1944 }
1945
1946
1947 /* Function processes backlog in enumeration context;
1948 returns true if message was sent to active connection;
1949 once last repsonse is sent, it deletes context */
1950 static MI_Boolean _ProcessEnumResponse(
1951 WSMAN* self,
1952 WSMAN_EnumerateContext* selfEC,
1953 MI_Boolean attachingPullRequest)
1954 mike 1.1 {
1955 /* do we have connected cleint to send response to? */
1956 if (!selfEC->activeConnection)
1957 return MI_FALSE;
1958
1959 if (selfEC->enumerationCompleted && selfEC->finalResult != MI_RESULT_OK)
1960 {
1961 _SendErrorResponse(self, selfEC->activeConnection, selfEC->finalResult);
1962
1963 /* release context */
1964 _EC_SetActiveConnection(selfEC, 0);
1965 _WSMAN_ReleaseEnumerateContext(self, selfEC->enumerationContextID);
1966 selfEC = 0;
1967 return MI_TRUE;
1968 }
1969
1970 /* Check if partial response has to be sent (or enumeration is completed) */
1971 /* Update: send anything that is available once client re-connects with pull */
1972 /* Send resposne now if:
1973 - enumeration is complete
1974 - queue has enough instances to fill entire packet (by size or number)
1975 mike 1.1 - pull request arrives. Normally, network is lsower than providers,
1976 so once client returns with next pull request, lets send all messages
1977 we have in queue
1978 - server is stressed (too many instances)
1979 */
1980 if (selfEC->enumerationCompleted ||
1981 WSMAN_APROX_ENUM_RESP_HEADER_SIZE + selfEC->totalResponseSize > selfEC->activeConnection->wsheader.maxEnvelopeSize ||
1982 selfEC->totalResponses >= selfEC->activeConnection->u.wsenumpullbody.maxElements ||
1983 (attachingPullRequest && selfEC->head) ||
1984 (Selector_IsStressed(self->selector) && selfEC->head)
1985 )
1986 //if (selfEC->enumerationCompleted || selfEC->head)
1987 {
1988 //LOGW_CHAR(("processing responses %d", selfEC->totalResponses));
1989
1990 _SendEnumPullResponse(self, selfEC);
1991 _EC_SetActiveConnection(selfEC, 0);
1992 }
1993
1994 /* release context if last message was sent */
1995 if (selfEC->enumerationCompleted && !selfEC->head)
1996 mike 1.1 {
1997 _EC_SetActiveConnection(selfEC, 0);
1998 _WSMAN_ReleaseEnumerateContext(self, selfEC->enumerationContextID);
1999 selfEC = 0;
2000 }
2001 else
2002 {
2003 /* set/update timer */
2004 _WSMAN_SetUpdateTimer(self, selfEC);
2005 }
2006
2007 return MI_TRUE;
2008 }
2009
2010 static void _ProcessResultEnumerationContext(
2011 WSMAN* self,
2012 WSMAN_EnumerateContext* selfEC,
2013 PostResultMsg* message )
2014 {
2015 /* mark context as 'completed' */
2016 selfEC->enumerationCompleted = MI_TRUE;
2017 mike 1.1 selfEC->finalResult = message->result;
2018 //ATTN!: process error text/messages
2019
2020 _ProcessEnumResponse(self, selfEC, MI_FALSE);
2021
2022 /* release context */
2023 _EC_Release(selfEC, MI_FALSE);
2024 }
2025
2026
2027 static void _ProcessInstanceResponse(
2028 WSMAN* self,
2029 WSMAN_ConnectionData* selfCD,
2030 PostInstanceMsg* message)
2031 {
2032 /* send appropriate response */
2033 switch (selfCD->wsheader.rqtAction)
2034 {
2035 case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
2036 _SendInvokeResponse(self, selfCD, message);
2037 break;
2038 mike 1.1
2039 case WSMANTAG_ACTION_GET:
2040 _SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse")));
2041 break;
2042
2043 case WSMANTAG_ACTION_PUT:
2044 _SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/PutResponse")));
2045 break;
2046
2047 case WSMANTAG_ACTION_CREATE:
2048 _SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse")));
2049 break;
2050
2051 default:
2052 /* unexpected */
2053 _SendFaultResponse(
2054 self->http,
2055 selfCD,
2056 WSBUF_FAULT_INTERNAL_ERROR,
2057 T("unexpected internal state"));
2058 break;
2059 mike 1.1 }
2060 selfCD->outstandingRequest = MI_FALSE;
2061 }
2062
2063 static void _ProcessResultConnectionData(
2064 WSMAN* self,
2065 WSMAN_ConnectionData* selfCD,
2066 PostResultMsg* message )
2067 {
2068 /* if response was not sent yet, send it now (error probably) */
2069 if (selfCD->outstandingRequest)
2070 {
2071 if (selfCD->single_message)
2072 {
2073 _ProcessInstanceResponse(self, selfCD, selfCD->single_message);
2074 }
2075 else if (MI_RESULT_OK == message->result &&
2076 WSMANTAG_ACTION_DELETE == selfCD->wsheader.rqtAction)
2077 {
2078 _SendDeleteInstanceResponse(self, selfCD);
2079 }
2080 mike 1.1 else
2081 {
2082 _SendErrorResponse(self, selfCD, message->result);
2083 }
2084
2085 selfCD->outstandingRequest = MI_FALSE;
2086 }
2087
2088 /* release connection data */
2089 _CD_Release(selfCD);
2090 }
2091
2092 static void _ProcessInstanceConnectionData(
2093 WSMAN* self,
2094 WSMAN_ConnectionData* selfCD,
2095 PostInstanceMsg* message)
2096 {
2097 MI_UNUSED(self);
2098
2099 /* Ignore expired contexts */
2100 if (!selfCD->outstandingRequest)
2101 mike 1.1 return;
2102
2103 _CD_SetSingleMessage(selfCD, message);
2104 }
2105
2106 static void _ProcessInstanceEnumerationContext(
2107 WSMAN* self,
2108 WSMAN_EnumerateContext* selfEC,
2109 PostInstanceMsg* message )
2110 {
2111 /* Ignore expired contexts */
2112 if (selfEC->expired)
2113 return;
2114
2115 /* add-ref message to keep it alive */
2116 Message_AddRef( &message->base);
2117
2118 /* Add it to the list to process when result is posted */
2119 List_Append(
2120 (ListElem**)&selfEC->head,
2121 (ListElem**)&selfEC->tail,
2122 mike 1.1 (ListElem*)message);
2123
2124 /* Increment total instance size */
2125 selfEC->totalResponseSize += message->packedInstanceSize;
2126
2127 /* Increment total number of responses */
2128 selfEC->totalResponses++;
2129
2130 /* Check if we need to send response to the client */
2131 _ProcessEnumResponse(self, selfEC, MI_FALSE);
2132 }
2133
2134 /* HTTP callbacks */
2135 static void _HttpCallbackOnNewConnection(
2136 Http* http,
2137 void* callbackData,
2138 void* httpConnectionHandle,
2139 void** connectionData)
2140 {
2141 WSMAN_ConnectionData* selfConnectionData;
2142 MI_UNUSED(http);
2143 mike 1.1 MI_UNUSED(callbackData);
2144
2145 selfConnectionData = (WSMAN_ConnectionData*)calloc(1, sizeof(WSMAN_ConnectionData));
2146
2147 if (!selfConnectionData)
2148 return /*MI_RESULT_FAILED*/;
2149
2150 selfConnectionData->httpConnectionHandle = httpConnectionHandle;
2151 selfConnectionData->refcounter = 1;
2152 selfConnectionData->tag = DATA_TAG_CONNECTION_DATA;
2153 *connectionData = selfConnectionData;
2154 }
2155
2156 static void _HttpCallbackOnCloseConnection(
2157 Http* http,
2158 void* callbackData,
2159 void* connectionData)
2160 {
2161 MI_UNUSED(http);
2162 MI_UNUSED(callbackData);
2163
2164 mike 1.1 if (connectionData)
2165 {
2166 WSMAN_ConnectionData* selfConnectionData = (WSMAN_ConnectionData*)connectionData;
2167 selfConnectionData->httpConnectionHandle = 0;
2168 selfConnectionData->outstandingRequest = MI_FALSE;
2169
2170 _CD_Release(selfConnectionData);
2171 }
2172 }
2173
2174 static void _HttpCallbackOnRequest(
2175 Http* http,
2176 void* callbackData,
2177 void* connectionData,
2178 void* httpConnectionHandle,
2179 const HttpHeaders* headers,
2180 Page** page)
2181 {
2182 WSMAN_ConnectionData* selfCD = (WSMAN_ConnectionData*)connectionData;
2183 WSMAN* self = (WSMAN*)callbackData;
2184 XML xml = self->xml;
2185 mike 1.1
2186 /* Trace the request XML */
2187
2188 if (self->options.enableTracing)
2189 {
2190 printf("%s\n\n", (const char*)((*page)+1));
2191 }
2192
2193 /* Cleanup connection data, since it may still store allocated pointers
2194 from previous operation */
2195 _CD_Cleanup(selfCD);
2196
2197 /* Verify content type */
2198 if ( !headers->contentType ||
2199 (Strcasecmp(headers->contentType,"application/soap+xml") != 0 &&
2200 Strcasecmp(headers->contentType,"text/xml") != 0))
2201 {
2202 LOGW_CHAR(("wsman: invalid/missing content type in request [%s]", (const char*)((*page)+1) ));
2203 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_BAD_REQUEST);
2204 return;
2205 }
2206 mike 1.1
2207 if (headers->charset &&
2208 Strcasecmp(headers->charset,"utf-8") != 0)
2209 {
2210 LOGW_CHAR(("wsman: charset is not supported [%s]", MI_GET_SAFE_PRINTF_STRING(headers->charset) ));
2211 _SendFaultResponse(http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, T("only utf 8 is supported"));
2212 return;
2213 }
2214
2215 if (!headers->username || !headers->password ||
2216 0 != AuthenticateUser(headers->username, headers->password))
2217 {
2218 LOGW_CHAR(("wsman: authentication failed for user [%s]", MI_GET_SAFE_PRINTF_STRING(headers->username) ));
2219 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_UNAUTHORIZED);
2220 return;
2221 }
2222
2223 if (0 != LookupUser(headers->username, &selfCD->uid, &selfCD->gid))
2224 {
2225 LOGW_CHAR(("wsman: get user [%s] uid/gid", MI_GET_SAFE_PRINTF_STRING(headers->username) ));
2226 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
2227 mike 1.1 return;
2228 }
2229
2230 XML_SetText(&xml, (char*)((*page)+1) );
2231
2232 /* Parse header */
2233 if (WS_ParseSoapEnvelope(&xml) != 0 ||
2234 WS_ParseWSHeader(&xml, &selfCD->wsheader) != 0 ||
2235 xml.status)
2236 {
2237 LOGW_CHAR(("wsman: unable to parse incoming xml [%s] ", (const char*)((*page)+1) ));
2238 Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
2239 return;
2240 }
2241
2242 /* Validate header */
2243 if (_ValidateHeader(http, selfCD) != 0)
2244 {
2245 return;
2246 }
2247
2248 mike 1.1 /* See if this is a Identify request */
2249
2250 if (!selfCD->wsheader.foundAction)
2251 {
2252 _HandleIdentifyRequest(
2253 http,
2254 httpConnectionHandle,
2255 self,
2256 selfCD,
2257 &xml);
2258 return;
2259 }
2260
2261 /* keep reference to the page to keep xml object/ cached strings like msgID valid */
2262 _CD_SetPage(selfCD, *page);
2263 *page = 0;
2264
2265 selfCD->outstandingRequest = MI_TRUE;
2266
2267 /* Parse body and send request to the dispatcher */
2268 switch (selfCD->wsheader.rqtAction)
2269 mike 1.1 {
2270 case WSMANTAG_ACTION_ENUMERATE:
2271 {
2272 _ParseValidateProcessEnumerateRequest(http, httpConnectionHandle, self, selfCD, &xml);
2273 break;
2274 }
2275 case WSMANTAG_ACTION_PULL:
2276 {
2277 _ParseValidateProcessPullRequest(http, httpConnectionHandle, self, selfCD, &xml);
2278 break;
2279 }
2280 case WSMANTAG_ACTION_RELEASE:
2281 {
2282 _ParseValidateProcessReleaseRequest(http, httpConnectionHandle, self, selfCD, &xml);
2283 break;
2284 }
2285 case WSMANTAG_ACTION_GET:
2286 {
2287 _ParseValidateProcessGetRequest(http, httpConnectionHandle, self, selfCD, &xml);
2288 break;
2289 }
2290 mike 1.1 case WSMANTAG_ACTION_PUT:
2291 {
2292 _ParseValidateProcessPutRequest(http, httpConnectionHandle, self, selfCD, &xml);
2293 break;
2294 }
2295 case WSMANTAG_ACTION_DELETE:
2296 {
2297 _ParseValidateProcessDeleteRequest(http, httpConnectionHandle, self, selfCD, &xml);
2298 break;
2299 }
2300 case WSMANTAG_ACTION_CREATE:
2301 {
2302 _ParseValidateProcessCreateRequest(http, httpConnectionHandle, self, selfCD, &xml);
2303 break;
2304 }
2305 case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
2306 {
2307 _ParseValidateProcessInvokeRequest(http, httpConnectionHandle, self, selfCD, &xml);
2308 break;
2309 }
2310 default:
2311 mike 1.1 {
2312 /* unsupported action */
2313 LOGW_CHAR(("wsman: unsupported action [%d] ", selfCD->wsheader.rqtAction ));
2314 _SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_SUPPORTED, 0);
2315 selfCD->outstandingRequest = MI_FALSE;
2316 break;
2317 }
2318 }
2319 }
2320
2321 /*
2322 **==============================================================================
2323 **
2324 ** Public definitions:
2325 **
2326 **==============================================================================
2327 */
2328 MI_Result WSMAN_New_Listener(
2329 WSMAN** selfOut,
2330 Selector* selector, /*optional, maybe NULL*/
2331 unsigned short http_port, /* 0 to disable */
2332 mike 1.1 unsigned short https_port, /* 0 to disable */
2333 WSMANCallback callback,
2334 void* callbackData)
2335 {
2336 WSMAN* self;
2337 MI_Result r;
2338
2339 /* Check parameters */
2340 if (!selfOut)
2341 return MI_RESULT_INVALID_PARAMETER;
2342
2343 /* Clear output parameter */
2344 *selfOut = NULL;
2345
2346 /* Allocate structure */
2347 {
2348 self = (WSMAN*)calloc(1, sizeof(WSMAN));
2349
2350 if (!self)
2351 return MI_RESULT_FAILED;
2352 }
2353 mike 1.1
2354 /* Save the callback and callbackData */
2355 self->callback = callback;
2356 self->callbackData = callbackData;
2357
2358 /*ATTN! slector can be null!*/
2359 self->selector = selector;
2360
2361 /* options */
2362 {
2363 WSMAN_Options options = DEFAULT_WSMAN_OPTIONS;
2364
2365 self->options = options;
2366 }
2367
2368 /* Set the magic number */
2369 self->magic = _MAGIC;
2370
2371 /* create a server */
2372 r = Http_New_Server(
2373 &self->http, selector, http_port, https_port,
2374 mike 1.1 _HttpCallbackOnNewConnection,
2375 _HttpCallbackOnCloseConnection,
2376 _HttpCallbackOnRequest, self);
2377
2378 if (MI_RESULT_OK != r)
2379 {
2380 WSMAN_Delete(self);
2381 return r;
2382 }
2383
2384 /* Initialize xml parser */
2385 XML_Init(&self->xml);
2386
2387 XML_RegisterNameSpace(&self->xml, 's',
2388 "http://www.w3.org/2003/05/soap-envelope");
2389
2390 XML_RegisterNameSpace(&self->xml, 'a',
2391 "http://schemas.xmlsoap.org/ws/2004/08/addressing");
2392
2393 XML_RegisterNameSpace(&self->xml, 'w',
2394 "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd");
2395 mike 1.1
2396 XML_RegisterNameSpace(&self->xml, 'n',
2397 "http://schemas.xmlsoap.org/ws/2004/09/enumeration");
2398
2399 XML_RegisterNameSpace(&self->xml, 'b',
2400 "http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd");
2401
2402 XML_RegisterNameSpace(&self->xml, 'p',
2403 "http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd");
2404
2405 XML_RegisterNameSpace(&self->xml, 'i',
2406 "http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd");
2407
2408 *selfOut = self;
2409
2410 return MI_RESULT_OK;
2411 }
2412
2413 MI_Result WSMAN_Delete(
2414 WSMAN* self)
2415 {
2416 mike 1.1 /* Check parameters */
2417 if (!self)
2418 return MI_RESULT_INVALID_PARAMETER;
2419
2420 /* Check magic number */
2421 if (self->magic != _MAGIC)
2422 return MI_RESULT_INVALID_PARAMETER;
2423
2424 Http_Delete(self->http);
2425
2426 /* clear all outstanding contexts */
2427 _WSMAN_ReleaseAllEnumerateContexts(self);
2428
2429 /* Clear magic number */
2430 self->magic = 0xDDDDDDDD;
2431
2432 /* Free self pointer */
2433 free(self);
2434
2435 return MI_RESULT_OK;
2436 }
2437 mike 1.1
2438 MI_Result WSMAN_Run(
2439 WSMAN* self,
2440 MI_Uint64 timeoutUsec)
2441 {
2442 /* Run the selector */
2443 return Http_Run(self->http, timeoutUsec);
2444 }
2445
2446 static MI_Result _SendIN_IO_thread(
2447 void* self_,
2448 Message* message)
2449 {
2450 WSMAN* self = (WSMAN*)self_;
2451 WSMAN_ConnectionData* selfCD = 0;
2452 WSMAN_EnumerateContext* selfEC = 0;
2453
2454 /* check params */
2455 if (!self || !message )
2456 return MI_RESULT_INVALID_PARAMETER;
2457
2458 mike 1.1 if (self->magic != _MAGIC)
2459 {
2460 LOGW((T("_SendIN_IO_thread: invalid magic!") ));
2461 return MI_RESULT_INVALID_PARAMETER;
2462 }
2463
2464 /* find where to send it */
2465 selfCD = (WSMAN_ConnectionData*)Uint64ToPtr(message->clientID);
2466 selfEC = (WSMAN_EnumerateContext*)Uint64ToPtr(message->clientID);
2467
2468 if (selfCD && selfCD->tag != DATA_TAG_CONNECTION_DATA)
2469 {
2470 selfCD = 0;
2471 }
2472 if (selfEC && selfEC->tag != DATA_TAG_ENUMERATION_CONTEXT)
2473 {
2474 selfEC = 0;
2475 }
2476 if (!selfCD && !selfEC)
2477 {
2478 LOGW((T("_SendIN_IO_thread: clientID!") ));
2479 mike 1.1 return MI_RESULT_INVALID_PARAMETER;
2480 }
2481
2482 /* ATTN! validate handler */
2483
2484 /* Process response message */
2485 switch (message->tag)
2486 {
2487 case PostResultMsgTag:
2488 if (selfCD)
2489 _ProcessResultConnectionData(self, selfCD, (PostResultMsg*)message );
2490 else
2491 _ProcessResultEnumerationContext(self, selfEC, (PostResultMsg*)message );
2492
2493 break;
2494
2495 case PostInstanceMsgTag:
2496 if (selfCD)
2497 _ProcessInstanceConnectionData(self, selfCD, (PostInstanceMsg*)message );
2498 else
2499 _ProcessInstanceEnumerationContext(self, selfEC, (PostInstanceMsg*)message );
2500 mike 1.1
2501 break;
2502
2503 default:
2504 LOGW((T("wsman: _SendIN_IO_thread: unexpected message tag %d"), message->tag ));
2505 return MI_RESULT_INVALID_PARAMETER;
2506 }
2507
2508 return MI_RESULT_OK;
2509 }
2510
2511 /* Signature must not have return type so we created this wrapper */
2512 static void _SendIN_IO_thread_wrapper(void* self, Message* message)
2513 {
2514 MI_Result r;
2515 r = _SendIN_IO_thread(self, message);
2516
2517 /* ATTN: log failed result? */
2518 }
2519
2520
2521 mike 1.1 MI_Result WSMAN_Send(
2522 WSMAN* self,
2523 Message* message)
2524 {
2525 return Selector_CallInIOThread(
2526 self->selector, _SendIN_IO_thread_wrapper, self, message );
2527 }
2528
2529 MI_Result WSMAN_SetOptions(
2530 WSMAN* self,
2531 const WSMAN_Options* options)
2532 {
2533 /* check params */
2534 if (!self || !options)
2535 return MI_RESULT_INVALID_PARAMETER;
2536
2537 /* Check magic number */
2538 if (self->magic != _MAGIC)
2539 {
2540 LOGW((T("invalid magic!") ));
2541 return MI_RESULT_INVALID_PARAMETER;
2542 mike 1.1 }
2543
2544 self->options = *options;
2545 return MI_RESULT_OK;
2546 }
|