1/* 2 WMI Implementation 3 Copyright (C) 2006 Andrzej Hajda <andrzej.hajda@wp.pl> 4 Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22#include "librpc/gen_ndr/dcom.h" 23#include "librpc/gen_ndr/com_dcom.h" 24#include "librpc/ndr/libndr.h" 25#include "librpc/ndr/libndr_proto.h" 26#include "lib/com/com.h" 27#include "lib/com/dcom/dcom.h" 28#include "lib/util/dlinklist.h" 29#include "librpc/ndr/libndr.h" 30#include "librpc/gen_ndr/ndr_dcom.h" 31#include "librpc/rpc/dcerpc.h" 32#include "librpc/gen_ndr/ndr_misc.h" 33#include "lib/talloc/talloc.h" 34#include "libcli/composite/composite.h" 35#include "lib/wmi/wmi.h" 36#include "librpc/gen_ndr/ndr_wmi.h" 37 38enum { 39 DATATYPE_CLASSOBJECT = 2, 40 DATATYPE_OBJECT = 3, 41 COFLAG_IS_CLASS = 4, 42}; 43 44static enum ndr_err_code marshal(TALLOC_CTX *mem_ctx, struct IUnknown *pv, struct OBJREF *o) 45{ 46 struct ndr_push *ndr; 47 struct IWbemClassObject *wco; 48 struct MInterfacePointer *mp; 49 50 mp = (struct MInterfacePointer *)((char *)o - offsetof(struct MInterfacePointer, obj)); /* FIXME:high remove this Mumbo Jumbo */ 51 wco = pv->object_data; 52 ndr = talloc_zero(mem_ctx, struct ndr_push); 53 ndr->flags = 0; 54 ndr->alloc_size = 1024; 55 ndr->data = talloc_array(mp, uint8_t, ndr->alloc_size); 56 57 if (wco) { 58 uint32_t ofs; 59 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0x12345678)); 60 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); 61 NDR_CHECK(ndr_push_IWbemClassObject(ndr, NDR_SCALARS | NDR_BUFFERS, wco)); 62 ofs = ndr->offset; 63 ndr->offset = 4; 64 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ofs - 8)); 65 ndr->offset = ofs; 66 } else { 67 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); 68 } 69 o->u_objref.u_custom.pData = talloc_realloc(mp, ndr->data, uint8_t, ndr->offset); 70 o->u_objref.u_custom.size = ndr->offset; 71 mp->size = sizeof(struct OBJREF) - sizeof(union OBJREF_Types) + sizeof(struct u_custom) + o->u_objref.u_custom.size - 4; 72 if (DEBUGLVL(9)) { 73 NDR_PRINT_DEBUG(IWbemClassObject, wco); 74 } 75 return NDR_ERR_SUCCESS; 76} 77 78static enum ndr_err_code unmarshal(TALLOC_CTX *mem_ctx, struct OBJREF *o, struct IUnknown **pv) 79{ 80 struct ndr_pull *ndr; 81 struct IWbemClassObject *wco; 82 enum ndr_err_code ndr_err; 83 uint32_t u; 84 85 mem_ctx = talloc_new(0); 86 ndr = talloc_zero(mem_ctx, struct ndr_pull); 87 ndr->current_mem_ctx = mem_ctx; 88 ndr->data = o->u_objref.u_custom.pData; 89 ndr->data_size = o->u_objref.u_custom.size; 90 91 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 92 if (!u) { 93 talloc_free(*pv); 94 *pv = NULL; 95 return NDR_ERR_SUCCESS; 96 } 97 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 98 if (u + 8 > ndr->data_size) { 99 DEBUG(1, ("unmarshall_IWbemClassObject: Incorrect data_size")); 100 return NDR_ERR_BUFSIZE; 101 } 102 wco = talloc_zero(*pv, struct IWbemClassObject); 103 ndr->current_mem_ctx = wco; 104 ndr_err = ndr_pull_IWbemClassObject(ndr, NDR_SCALARS | NDR_BUFFERS, wco); 105 106 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLVL(9))) { 107 NDR_PRINT_DEBUG(IWbemClassObject, wco); 108 } 109 110 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 111 (*pv)->object_data = wco; 112 } else { 113 talloc_free(wco); 114 } 115 return NDR_ERR_SUCCESS; 116} 117 118WERROR dcom_IWbemClassObject_from_WbemClassObject(struct com_context *ctx, struct IWbemClassObject **_p, struct IWbemClassObject *wco) 119{ 120 struct IWbemClassObject *p; 121 122 p = talloc_zero(ctx, struct IWbemClassObject); 123 p->ctx = ctx; 124 p->obj.signature = 0x574f454d; 125 p->obj.flags = OBJREF_CUSTOM; 126 GUID_from_string("dc12a681-737f-11cf-884d-00aa004b2e24", &p->obj.iid); 127 GUID_from_string("4590f812-1d3a-11d0-891f-00aa004b2e24", &p->obj.u_objref.u_custom.clsid); 128 p->object_data = (void *)wco; 129 talloc_steal(p, p->object_data); 130 *_p = p; 131 return WERR_OK; 132} 133 134WERROR IWbemClassObject_GetMethod(struct IWbemClassObject *d, TALLOC_CTX *mem_ctx, const char *name, uint32_t flags, struct IWbemClassObject **in, struct IWbemClassObject **out) 135{ 136 uint32_t i; 137 struct IWbemClassObject *wco; 138 139 wco = (struct IWbemClassObject *)d->object_data; 140 for (i = 0; i < wco->obj_methods->count; ++i) 141 if (!strcmp(wco->obj_methods->method[i].name, name)) { 142 if (in) dcom_IWbemClassObject_from_WbemClassObject(d->ctx, in, wco->obj_methods->method[i].in); 143 if (out) dcom_IWbemClassObject_from_WbemClassObject(d->ctx, out, wco->obj_methods->method[i].out); 144 return WERR_OK; 145 } 146 return WERR_NOT_FOUND; 147} 148 149void IWbemClassObject_CreateInstance(struct IWbemClassObject *wco) 150{ 151 uint32_t i; 152 153 wco->instance = talloc_zero(wco, struct WbemInstance); 154 wco->instance->default_flags = talloc_array(wco->instance, uint8_t, wco->obj_class->__PROPERTY_COUNT); 155 wco->instance->data = talloc_array(wco->instance, union CIMVAR, wco->obj_class->__PROPERTY_COUNT); 156 memset(wco->instance->data, 0, sizeof(union CIMVAR) * wco->obj_class->__PROPERTY_COUNT); 157 for (i = 0; i < wco->obj_class->__PROPERTY_COUNT; ++i) { 158 wco->instance->default_flags[i] = 1; /* FIXME:high resolve this magic */ 159 } 160 wco->instance->__CLASS = wco->obj_class->__CLASS; 161 wco->instance->u2_4 = 4; 162 wco->instance->u3_1 = 1; 163} 164 165WERROR IWbemClassObject_Clone(struct IWbemClassObject *d, TALLOC_CTX *mem_ctx, struct IWbemClassObject **copy) 166{ 167 return WERR_NOT_SUPPORTED; 168} 169 170WERROR IWbemClassObject_SpawnInstance(struct IWbemClassObject *d, TALLOC_CTX *mem_ctx, uint32_t flags, struct IWbemClassObject **instance) 171{ 172 struct IWbemClassObject *wco, *nwco; 173 174 wco = (struct IWbemClassObject *)d->object_data; 175 nwco = talloc_zero(mem_ctx, struct IWbemClassObject); 176 nwco->flags = WCF_INSTANCE; 177 nwco->obj_class = wco->obj_class; 178 IWbemClassObject_CreateInstance(nwco); 179 dcom_IWbemClassObject_from_WbemClassObject(d->ctx, instance, nwco); 180 return WERR_OK; 181} 182 183WERROR IWbemClassObject_Get(struct IWbemClassObject *d, TALLOC_CTX *mem_ctx, const char *name, uint32_t flags, union CIMVAR *val, enum CIMTYPE_ENUMERATION *cimtype, uint32_t *flavor) 184{ 185 uint32_t i; 186 for (i = 0; i < d->obj_class->__PROPERTY_COUNT; ++i) { 187 if (!strcmp(d->obj_class->properties[i].property.name, name)) { 188 duplicate_CIMVAR(mem_ctx, &d->instance->data[i], val, d->obj_class->properties[i].property.desc->cimtype); 189 if (cimtype != NULL) 190 *cimtype = d->obj_class->properties[i].property.desc->cimtype; 191 if (flavor != NULL) 192 *flavor = 0; /* FIXME:avg implement flavor */ 193 return WERR_OK; 194 } 195 } 196 return WERR_NOT_FOUND; 197} 198 199WERROR IWbemClassObject_Put(struct IWbemClassObject *d, TALLOC_CTX *mem_ctx, const char *name, uint32_t flags, union CIMVAR *val, enum CIMTYPE_ENUMERATION cimtype) 200{ 201 struct IWbemClassObject *wco; 202 uint32_t i; 203 204 wco = (struct IWbemClassObject *)d->object_data; 205 for (i = 0; i < wco->obj_class->__PROPERTY_COUNT; ++i) { 206 if (!strcmp(wco->obj_class->properties[i].property.name, name)) { 207 if (cimtype && cimtype != wco->obj_class->properties[i].property.desc->cimtype) return WERR_INVALID_PARAM; 208 wco->instance->default_flags[i] = 0; 209 duplicate_CIMVAR(wco->instance, val, &wco->instance->data[i], wco->obj_class->properties[i].property.desc->cimtype); 210 return WERR_OK; 211 } 212 } 213 return WERR_NOT_FOUND; 214} 215 216#define WERR_CHECK(msg) if (!W_ERROR_IS_OK(result)) { \ 217 DEBUG(1, ("ERROR: %s - %s\n", msg, wmi_errstr(result))); \ 218 return result; \ 219 } else { \ 220 DEBUG(1, ("OK : %s\n", msg)); \ 221 } 222 223struct pair_guid_ptr { 224 struct GUID guid; 225 void *ptr; 226 struct pair_guid_ptr *next, *prev; 227}; 228 229static void *get_ptr_by_guid(struct pair_guid_ptr *list, struct GUID *uuid) 230{ 231 for (; list; list = list->next) { 232 if (GUID_equal(&list->guid, uuid)) 233 return list->ptr; 234 } 235 return NULL; 236} 237 238static void add_pair_guid_ptr(TALLOC_CTX *mem_ctx, struct pair_guid_ptr **list, struct GUID *uuid, void *ptr) 239{ 240 struct pair_guid_ptr *e; 241 242 e = talloc(mem_ctx, struct pair_guid_ptr); 243 e->guid = *uuid; 244 e->ptr = ptr; 245 talloc_steal(e, ptr); 246 DLIST_ADD(*list, e); 247} 248 249struct IEnumWbemClassObject_data { 250 struct GUID guid; 251 struct IWbemFetchSmartEnum *pFSE; 252 struct IWbemWCOSmartEnum *pSE; 253 struct pair_guid_ptr *cache; 254}; 255#define NDR_CHECK_EXPR(expr) do { if (!(expr)) {\ 256 DEBUG(0, ("%s(%d): WBEMDATA_ERR(0x%08X): Error parsing(%s)\n", __FILE__, __LINE__, ndr->offset, #expr)); \ 257 return NDR_ERR_VALIDATE; \ 258 } \ 259 } while(0) 260 261#define NDR_CHECK_CONST(val, exp) NDR_CHECK_EXPR((val) == (exp)) 262 263 264static enum ndr_err_code WBEMDATA_Parse(TALLOC_CTX *mem_ctx, uint8_t *data, uint32_t size, struct IEnumWbemClassObject *d, uint32_t uCount, struct IWbemClassObject **apObjects) 265{ 266 struct ndr_pull *ndr; 267 uint32_t u, i, ofs_next; 268 uint8_t u8, datatype; 269 struct GUID guid; 270 struct IEnumWbemClassObject_data *ecod; 271 272 if (!uCount) 273 return NDR_ERR_BAD_SWITCH; 274 275 ecod = d->object_data; 276 277 ndr = talloc_zero(mem_ctx, struct ndr_pull); 278 ndr->current_mem_ctx = d->ctx; 279 ndr->data = data; 280 ndr->data_size = size; 281 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); 282 283 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 284 NDR_CHECK_CONST(u, 0x0); 285 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 286 NDR_CHECK_CONST(u, *(const uint32_t *)"WBEM"); 287 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 288 NDR_CHECK_CONST(u, *(const uint32_t *)"DATA"); 289 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 290 NDR_CHECK_CONST(u, 0x1A); /* Length of header */ 291 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 292 NDR_PULL_NEED_BYTES(ndr, u + 6); 293 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 294 NDR_CHECK_CONST(u, 0x0); 295 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &u8)); 296 NDR_CHECK_CONST(u8, 0x01); /* Major Version */ 297 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &u8)); 298 NDR_CHECK_EXPR(u8 <= 1); /* Minor Version 0 - Win2000, 1 - XP/2003 */ 299 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 300 NDR_CHECK_CONST(u, 0x8); /* Length of header */ 301 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 302 NDR_PULL_NEED_BYTES(ndr, u); 303 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 304 NDR_CHECK_CONST(u, 0xC); /* Length of header */ 305 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 306 NDR_PULL_NEED_BYTES(ndr, u + 4); 307 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 308 NDR_CHECK_CONST(u, uCount); 309 for (i = 0; i < uCount; ++i) { 310 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 311 NDR_CHECK_CONST(u, 0x9); /* Length of header */ 312 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 313 NDR_PULL_NEED_BYTES(ndr, u + 1); 314 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &datatype)); 315 ofs_next = ndr->offset + u; 316 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 317 NDR_CHECK_CONST(u, 0x18); /* Length of header */ 318 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &u)); 319 NDR_PULL_NEED_BYTES(ndr, u + 16); 320 NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &guid)); 321 switch (datatype) { 322 case DATATYPE_CLASSOBJECT: 323 apObjects[i] = talloc_zero(d->ctx, struct IWbemClassObject); 324 ndr->current_mem_ctx = apObjects[i]; 325 NDR_CHECK(ndr_pull_WbemClassObject(ndr, NDR_SCALARS|NDR_BUFFERS, apObjects[i])); 326 ndr->current_mem_ctx = d->ctx; 327 add_pair_guid_ptr(ecod, &ecod->cache, &guid, apObjects[i]->obj_class); 328 break; 329 case DATATYPE_OBJECT: 330 apObjects[i] = talloc_zero(d->ctx, struct IWbemClassObject); 331 apObjects[i]->obj_class = get_ptr_by_guid(ecod->cache, &guid); 332 (void)talloc_reference(apObjects[i], apObjects[i]->obj_class); 333 ndr->current_mem_ctx = apObjects[i]; 334 NDR_CHECK(ndr_pull_WbemClassObject_Object(ndr, NDR_SCALARS|NDR_BUFFERS, apObjects[i])); 335 ndr->current_mem_ctx = d->ctx; 336 break; 337 default: 338 DEBUG(0, ("WBEMDATA_Parse: Data type %d not supported\n", datatype)); 339 return NDR_ERR_BAD_SWITCH; 340 } 341 ndr->offset = ofs_next; 342 if (DEBUGLVL(9)) { 343 NDR_PRINT_DEBUG(IWbemClassObject, apObjects[i]); 344 } 345 } 346 return NDR_ERR_SUCCESS; 347} 348 349WERROR IEnumWbemClassObject_SmartNext(struct IEnumWbemClassObject *d, TALLOC_CTX *mem_ctx, int32_t lTimeout, uint32_t uCount, struct IWbemClassObject **apObjects, uint32_t *puReturned) 350{ 351 WERROR result; 352 NTSTATUS status; 353 struct IEnumWbemClassObject_data *ecod; 354 TALLOC_CTX *loc_ctx; 355 uint32_t size; 356 uint8_t *data; 357 358 loc_ctx = talloc_new(0); 359 ecod = d->object_data; 360 if (!ecod) { 361 struct GUID iid; 362 WERROR coresult; 363 364 d->object_data = ecod = talloc_zero(d, struct IEnumWbemClassObject_data); 365 GUID_from_string(COM_IWBEMFETCHSMARTENUM_UUID, &iid); 366 result = dcom_query_interface((struct IUnknown *)d, 5, 1, &iid, (struct IUnknown **)&ecod->pFSE, &coresult); 367 WERR_CHECK("dcom_query_interface."); 368 result = coresult; 369 WERR_CHECK("Retrieve enumerator of result(IWbemFetchSmartEnum)."); 370 371 result = IWbemFetchSmartEnum_Fetch(ecod->pFSE, mem_ctx, &ecod->pSE); 372 WERR_CHECK("Retrieve enumerator of result(IWbemWCOSmartEnum)."); 373 374 ecod->guid = GUID_random(); 375 d->vtable->Release_send = dcom_proxy_IEnumWbemClassObject_Release_send; 376 } 377 378 result = IWbemWCOSmartEnum_Next(ecod->pSE, loc_ctx, &ecod->guid, lTimeout, uCount, puReturned, &size, &data); 379 if (!W_ERROR_EQUAL(result, WERR_BADFUNC)) { 380 WERR_CHECK("IWbemWCOSmartEnum_Next."); 381 } 382 383 if (data) { 384 NDR_CHECK(WBEMDATA_Parse(mem_ctx, data, size, d, *puReturned, apObjects)); 385 } 386 if (!W_ERROR_IS_OK(result)) { 387 status = werror_to_ntstatus(result); 388 DEBUG(9, ("dcom_proxy_IEnumWbemClassObject_Next: %s - %s\n", nt_errstr(status), get_friendly_nt_error_msg(status))); 389 } 390 talloc_free(loc_ctx); 391 return result; 392} 393 394struct composite_context *dcom_proxy_IEnumWbemClassObject_Release_send(struct IUnknown *d, TALLOC_CTX *mem_ctx) 395{ 396 struct composite_context *c, *cr; 397 struct REMINTERFACEREF iref[3]; 398 struct dcom_object_exporter *ox; 399 struct IEnumWbemClassObject_data *ecod; 400 int n; 401 402 c = composite_create(d->ctx, d->ctx->event_ctx); 403 if (c == NULL) return NULL; 404 c->private_data = d; 405 406 ox = object_exporter_by_ip(d->ctx, d); 407 iref[0].ipid = IUnknown_ipid(d); 408 iref[0].cPublicRefs = 5; 409 iref[0].cPrivateRefs = 0; 410 n = 1; 411 412 ecod = d->object_data; 413 if (ecod) { 414 if (ecod->pFSE) { 415 talloc_steal(d, ecod->pFSE); 416 iref[n].ipid = IUnknown_ipid(ecod->pFSE); 417 iref[n].cPublicRefs = 5; 418 iref[n].cPrivateRefs = 0; 419 ++n; 420 } 421 if (ecod->pSE) { 422 talloc_steal(d, ecod->pSE); 423 iref[n].ipid = IUnknown_ipid(ecod->pSE); 424 iref[n].cPublicRefs = 5; 425 iref[n].cPrivateRefs = 0; 426 ++n; 427 } 428 } 429 cr = IRemUnknown_RemRelease_send(ox->rem_unknown, mem_ctx, n, iref); 430 431 composite_continue(c, cr, dcom_release_continue, c); 432 return c; 433} 434 435NTSTATUS dcom_proxy_IWbemClassObject_init(void) 436{ 437 struct GUID clsid; 438 GUID_from_string("4590f812-1d3a-11d0-891f-00aa004b2e24", &clsid); 439 dcom_register_marshal(&clsid, marshal, unmarshal); 440 441#if 0 442 struct IEnumWbemClassObject_vtable *proxy_vtable; 443 proxy_vtable = (struct IEnumWbemClassObject_vtable *)dcom_proxy_vtable_by_iid((struct GUID *)&dcerpc_table_IEnumWbemClassObject.syntax_id.uuid); 444 if (proxy_vtable) 445 proxy_vtable->Release_send = dcom_proxy_IEnumWbemClassObject_Release_send; 446 else 447 DEBUG(0, ("WARNING: IEnumWbemClassObject should be initialized before IWbemClassObject.")); 448#endif 449 450 return NT_STATUS_OK; 451} 452