1 | /*
|
---|
2 | WMI Sample client
|
---|
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 "lib/cmdline/popt_common.h"
|
---|
23 | #include "librpc/rpc/dcerpc.h"
|
---|
24 | #include "librpc/gen_ndr/ndr_oxidresolver.h"
|
---|
25 | #include "librpc/gen_ndr/ndr_oxidresolver_c.h"
|
---|
26 | #include "librpc/gen_ndr/ndr_dcom.h"
|
---|
27 | #include "librpc/gen_ndr/ndr_dcom_c.h"
|
---|
28 | #include "librpc/gen_ndr/ndr_remact_c.h"
|
---|
29 | #include "librpc/gen_ndr/ndr_epmapper_c.h"
|
---|
30 | #include "librpc/gen_ndr/com_dcom.h"
|
---|
31 |
|
---|
32 | #include "lib/com/dcom/dcom.h"
|
---|
33 | #include "lib/com/com.h"
|
---|
34 |
|
---|
35 | #include "lib/wmi/wmi.h"
|
---|
36 |
|
---|
37 | struct program_args {
|
---|
38 | char *hostname;
|
---|
39 | char *query;
|
---|
40 | char *ns;
|
---|
41 | };
|
---|
42 |
|
---|
43 | static void parse_args(int argc, char *argv[], struct program_args *pmyargs)
|
---|
44 | {
|
---|
45 | poptContext pc;
|
---|
46 | int opt, i;
|
---|
47 |
|
---|
48 | int argc_new;
|
---|
49 | char **argv_new;
|
---|
50 |
|
---|
51 | struct poptOption long_options[] = {
|
---|
52 | POPT_AUTOHELP
|
---|
53 | POPT_COMMON_SAMBA
|
---|
54 | POPT_COMMON_CONNECTION
|
---|
55 | POPT_COMMON_CREDENTIALS
|
---|
56 | POPT_COMMON_VERSION
|
---|
57 | {"namespace", 0, POPT_ARG_STRING, &pmyargs->ns, 0,
|
---|
58 | "WMI namespace, default to root\\cimv2", 0},
|
---|
59 | POPT_TABLEEND
|
---|
60 | };
|
---|
61 |
|
---|
62 | pc = poptGetContext("wmi", argc, (const char **) argv,
|
---|
63 | long_options, POPT_CONTEXT_KEEP_FIRST);
|
---|
64 |
|
---|
65 | poptSetOtherOptionHelp(pc, "//host query\n\nExample: wmic -U [domain/]adminuser%password //host \"select * from Win32_ComputerSystem\"");
|
---|
66 |
|
---|
67 | while ((opt = poptGetNextOpt(pc)) != -1) {
|
---|
68 | poptPrintUsage(pc, stdout, 0);
|
---|
69 | poptFreeContext(pc);
|
---|
70 | exit(1);
|
---|
71 | }
|
---|
72 |
|
---|
73 | argv_new = discard_const_p(char *, poptGetArgs(pc));
|
---|
74 |
|
---|
75 | argc_new = argc;
|
---|
76 | for (i = 0; i < argc; i++) {
|
---|
77 | if (argv_new[i] == NULL) {
|
---|
78 | argc_new = i;
|
---|
79 | break;
|
---|
80 | }
|
---|
81 | }
|
---|
82 |
|
---|
83 | if (argc_new != 3 || argv_new[1][0] != '/'
|
---|
84 | || argv_new[1][1] != '/') {
|
---|
85 | poptPrintUsage(pc, stdout, 0);
|
---|
86 | poptFreeContext(pc);
|
---|
87 | exit(1);
|
---|
88 | }
|
---|
89 |
|
---|
90 | pmyargs->hostname = argv_new[1] + 2;
|
---|
91 | pmyargs->query = argv_new[2];
|
---|
92 | poptFreeContext(pc);
|
---|
93 | }
|
---|
94 |
|
---|
95 | static void escape_string(const char *src, char *dst, int len)
|
---|
96 | {
|
---|
97 | char *p = dst, *end = dst + len - 1;
|
---|
98 | const char *q = src;
|
---|
99 |
|
---|
100 | if ( q == NULL) {
|
---|
101 | strncpy( dst, "(null)", len);
|
---|
102 | return;
|
---|
103 | }
|
---|
104 |
|
---|
105 | while ( *q && p <= end ) {
|
---|
106 | if ( strchr( "|\\(),", *q)) {
|
---|
107 | *p++ = '\\';
|
---|
108 | *p++ = *q++;
|
---|
109 | } else if ( *q == '\n' ) {
|
---|
110 | *p++ = '\\';
|
---|
111 | *p++ = 'n';
|
---|
112 | q++;
|
---|
113 | } else if ( *q == '\r' ) {
|
---|
114 | *p++ = '\\';
|
---|
115 | *p++ = 'r';
|
---|
116 | q++;
|
---|
117 | } else {
|
---|
118 | *p++ = *q++;
|
---|
119 | }
|
---|
120 | }
|
---|
121 |
|
---|
122 | *p++ = 0;
|
---|
123 | }
|
---|
124 |
|
---|
125 | #define WERR_CHECK(msg) if (!W_ERROR_IS_OK(result)) { \
|
---|
126 | DEBUG(0, ("ERROR: %s\n", msg)); \
|
---|
127 | goto error; \
|
---|
128 | } else { \
|
---|
129 | DEBUG(1, ("OK : %s\n", msg)); \
|
---|
130 | }
|
---|
131 |
|
---|
132 | #define RETURN_CVAR_ARRAY_STR_START(arr) {\
|
---|
133 | uint32_t i;\
|
---|
134 | char *r;\
|
---|
135 | \
|
---|
136 | if (!arr) {\
|
---|
137 | return talloc_strdup(mem_ctx, "(null)");\
|
---|
138 | }\
|
---|
139 | r = talloc_strdup(mem_ctx, "(");\
|
---|
140 | for (i = 0; i < arr->count; ++i) {
|
---|
141 |
|
---|
142 |
|
---|
143 | #define RETURN_CVAR_ARRAY_STR_END(fmt, arr, item) \
|
---|
144 | r = talloc_asprintf_append(r, fmt "%s", item, (i+1 == arr->count)?"":",");\
|
---|
145 | }\
|
---|
146 | return talloc_asprintf_append(r, ")");\
|
---|
147 | }
|
---|
148 |
|
---|
149 | #define RETURN_CVAR_ARRAY_STR(fmt, arr) \
|
---|
150 | RETURN_CVAR_ARRAY_STR_START(arr) \
|
---|
151 | RETURN_CVAR_ARRAY_STR_END(fmt, arr, arr->item[i])
|
---|
152 |
|
---|
153 | #define RETURN_CVAR_ARRAY_ESCAPED(fmt, arr) \
|
---|
154 | RETURN_CVAR_ARRAY_STR_START(arr) \
|
---|
155 | char buf[2048]; \
|
---|
156 | escape_string( arr->item[i], buf, 2048); \
|
---|
157 | RETURN_CVAR_ARRAY_STR_END(fmt, arr, buf)
|
---|
158 |
|
---|
159 | char *string_CIMVAR(TALLOC_CTX *mem_ctx, union CIMVAR *v, enum CIMTYPE_ENUMERATION cimtype)
|
---|
160 | {
|
---|
161 | switch (cimtype) {
|
---|
162 | case CIM_SINT8: return talloc_asprintf(mem_ctx, "%d", v->v_sint8);
|
---|
163 | case CIM_UINT8: return talloc_asprintf(mem_ctx, "%u", v->v_uint8);
|
---|
164 | case CIM_SINT16: return talloc_asprintf(mem_ctx, "%d", v->v_sint16);
|
---|
165 | case CIM_UINT16: return talloc_asprintf(mem_ctx, "%u", v->v_uint16);
|
---|
166 | case CIM_SINT32: return talloc_asprintf(mem_ctx, "%d", v->v_sint32);
|
---|
167 | case CIM_UINT32: return talloc_asprintf(mem_ctx, "%u", v->v_uint32);
|
---|
168 | case CIM_SINT64: return talloc_asprintf(mem_ctx, "%lld", v->v_sint64);
|
---|
169 | case CIM_UINT64: return talloc_asprintf(mem_ctx, "%llu", v->v_sint64);
|
---|
170 | case CIM_REAL32: return talloc_asprintf(mem_ctx, "%f", (double)v->v_uint32);
|
---|
171 | case CIM_REAL64: return talloc_asprintf(mem_ctx, "%f", (double)v->v_uint64);
|
---|
172 | case CIM_BOOLEAN: return talloc_asprintf(mem_ctx, "%s", v->v_boolean?"True":"False");
|
---|
173 | case CIM_STRING:
|
---|
174 | case CIM_DATETIME:
|
---|
175 | case CIM_REFERENCE: {
|
---|
176 | char buf[2048];
|
---|
177 | escape_string((char*) v-> v_string, buf, 2048);
|
---|
178 | return talloc_asprintf(mem_ctx, "%s", buf);
|
---|
179 | }
|
---|
180 | case CIM_CHAR16: return talloc_asprintf(mem_ctx, "Unsupported");
|
---|
181 | case CIM_OBJECT: return talloc_asprintf(mem_ctx, "Unsupported");
|
---|
182 | case CIM_ARR_SINT8: RETURN_CVAR_ARRAY_STR("%d", v->a_sint8);
|
---|
183 | case CIM_ARR_UINT8: RETURN_CVAR_ARRAY_STR("%u", v->a_uint8);
|
---|
184 | case CIM_ARR_SINT16: RETURN_CVAR_ARRAY_STR("%d", v->a_sint16);
|
---|
185 | case CIM_ARR_UINT16: RETURN_CVAR_ARRAY_STR("%u", v->a_uint16);
|
---|
186 | case CIM_ARR_SINT32: RETURN_CVAR_ARRAY_STR("%d", v->a_sint32);
|
---|
187 | case CIM_ARR_UINT32: RETURN_CVAR_ARRAY_STR("%u", v->a_uint32);
|
---|
188 | case CIM_ARR_SINT64: RETURN_CVAR_ARRAY_STR("%lld", v->a_sint64);
|
---|
189 | case CIM_ARR_UINT64: RETURN_CVAR_ARRAY_STR("%llu", v->a_uint64);
|
---|
190 | case CIM_ARR_REAL32: RETURN_CVAR_ARRAY_STR("%f", v->a_real32);
|
---|
191 | case CIM_ARR_REAL64: RETURN_CVAR_ARRAY_STR("%f", v->a_real64);
|
---|
192 | case CIM_ARR_BOOLEAN: RETURN_CVAR_ARRAY_STR("%d", v->a_boolean);
|
---|
193 | case CIM_ARR_STRING: RETURN_CVAR_ARRAY_ESCAPED("%s", v->a_string);
|
---|
194 | case CIM_ARR_DATETIME: RETURN_CVAR_ARRAY_ESCAPED("%s", v->a_datetime);
|
---|
195 | case CIM_ARR_REFERENCE: RETURN_CVAR_ARRAY_ESCAPED("%s", v->a_reference);
|
---|
196 | default: return talloc_asprintf(mem_ctx, "Unsupported");
|
---|
197 | }
|
---|
198 | }
|
---|
199 |
|
---|
200 | #undef RETURN_CVAR_ARRAY_STR
|
---|
201 |
|
---|
202 | int main(int argc, char **argv)
|
---|
203 | {
|
---|
204 | struct program_args args = {};
|
---|
205 | uint32_t cnt = 5, ret;
|
---|
206 | char *class_name = NULL;
|
---|
207 | WERROR result;
|
---|
208 | NTSTATUS status;
|
---|
209 | struct IWbemServices *pWS = NULL;
|
---|
210 | struct BSTR queryLanguage, query;
|
---|
211 | struct IEnumWbemClassObject *pEnum = NULL;
|
---|
212 | struct com_context *ctx = NULL;
|
---|
213 |
|
---|
214 | parse_args(argc, argv, &args);
|
---|
215 |
|
---|
216 | wmi_init(&ctx, cmdline_credentials);
|
---|
217 |
|
---|
218 | if (!args.ns)
|
---|
219 | args.ns = "root\\cimv2";
|
---|
220 | result = WBEM_ConnectServer(ctx, args.hostname, args.ns, 0, 0, 0, 0, 0, 0, &pWS);
|
---|
221 | WERR_CHECK("Login to remote object.");
|
---|
222 |
|
---|
223 | queryLanguage.data = "WQL";
|
---|
224 | query.data = args.query;
|
---|
225 | result = IWbemServices_ExecQuery(pWS, ctx, queryLanguage, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_ENSURE_LOCATABLE, NULL, &pEnum);
|
---|
226 | WERR_CHECK("WMI query execute.");
|
---|
227 |
|
---|
228 | IEnumWbemClassObject_Reset(pEnum, ctx);
|
---|
229 | WERR_CHECK("Reset result of WMI query.");
|
---|
230 |
|
---|
231 | do {
|
---|
232 | uint32_t i, j;
|
---|
233 | struct WbemClassObject *co[cnt];
|
---|
234 |
|
---|
235 | result = IEnumWbemClassObject_SmartNext(pEnum, ctx, 0xFFFFFFFF, cnt, co, &ret);
|
---|
236 | /* WERR_BADFUNC is OK, it means only that there is less returned objects than requested */
|
---|
237 | if (!W_ERROR_EQUAL(result, WERR_BADFUNC)) {
|
---|
238 | WERR_CHECK("Retrieve result data.");
|
---|
239 | } else {
|
---|
240 | DEBUG(1, ("OK : Retrieved less objects than requested (it is normal).\n"));
|
---|
241 | }
|
---|
242 | if (!ret) break;
|
---|
243 |
|
---|
244 | for (i = 0; i < ret; ++i) {
|
---|
245 | if (!class_name || strcmp(co[i]->obj_class->__CLASS, class_name)) {
|
---|
246 | if (class_name) talloc_free(class_name);
|
---|
247 | class_name = talloc_strdup(ctx, co[i]->obj_class->__CLASS);
|
---|
248 | printf("CLASS: %s\n", class_name);
|
---|
249 | for (j = 0; j < co[i]->obj_class->__PROPERTY_COUNT; ++j)
|
---|
250 | printf("%s%s", j?"|":"", co[i]->obj_class->properties[j].property.name);
|
---|
251 | printf("\n");
|
---|
252 | }
|
---|
253 | for (j = 0; j < co[i]->obj_class->__PROPERTY_COUNT; ++j) {
|
---|
254 | char *s;
|
---|
255 | s = string_CIMVAR(ctx, &co[i]->instance->data[j], co[i]->obj_class->properties[j].property.desc->cimtype & CIM_TYPEMASK);
|
---|
256 | printf("%s%s", j?"|":"", s);
|
---|
257 | }
|
---|
258 | printf("\n");
|
---|
259 | }
|
---|
260 | } while (ret == cnt);
|
---|
261 | talloc_free(ctx);
|
---|
262 | return 0;
|
---|
263 | error:
|
---|
264 | status = werror_to_ntstatus(result);
|
---|
265 | fprintf(stderr, "NTSTATUS: %s - %s\n", nt_errstr(status), get_friendly_nt_error_msg(status));
|
---|
266 | talloc_free(ctx);
|
---|
267 | return 1;
|
---|
268 | }
|
---|