More improvements.
[samba.git] / source4 / lib / wmi / tools / wmic.c
1 /*
2    WMI Sample client
3    Copyright (C) 2006 Andrzej Hajda <andrzej.hajda@wp.pl>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "includes.h"
21 #include "lib/cmdline/popt_common.h"
22 #include "librpc/rpc/dcerpc.h"
23 #include "librpc/gen_ndr/ndr_oxidresolver.h"
24 #include "librpc/gen_ndr/ndr_oxidresolver_c.h"
25 #include "librpc/gen_ndr/ndr_dcom.h"
26 #include "librpc/gen_ndr/ndr_dcom_c.h"
27 #include "librpc/gen_ndr/ndr_remact_c.h"
28 #include "librpc/gen_ndr/ndr_epmapper_c.h"
29 #include "librpc/gen_ndr/com_dcom.h"
30 #include "librpc/rpc/dcerpc_table.h"
31
32 #include "lib/com/dcom/dcom.h"
33 #include "lib/com/proto.h"
34 #include "lib/com/dcom/proto.h"
35
36 struct WBEMCLASS;
37 struct WBEMOBJECT;
38
39 #include "wmi/wmi.h"
40
41 struct program_args {
42     char *hostname;
43     char *query;
44     char *ns;
45 };
46
47 static void parse_args(int argc, char *argv[], struct program_args *pmyargs)
48 {
49     poptContext pc;
50     int opt, i;
51
52     int argc_new;
53     char **argv_new;
54
55     struct poptOption long_options[] = {
56         POPT_AUTOHELP
57         POPT_COMMON_SAMBA
58         POPT_COMMON_CONNECTION
59         POPT_COMMON_CREDENTIALS
60         POPT_COMMON_VERSION
61         {"namespace", 0, POPT_ARG_STRING, &pmyargs->ns, 0,
62          "WMI namespace, default to root\\cimv2", 0},
63         POPT_TABLEEND
64     };
65
66     pc = poptGetContext("wmi", argc, (const char **) argv,
67                 long_options, POPT_CONTEXT_KEEP_FIRST);
68
69     poptSetOtherOptionHelp(pc, "//host query\n\nExample: wmic -U [domain/]adminuser%password //host \"select * from Win32_ComputerSystem\"");
70
71     while ((opt = poptGetNextOpt(pc)) != -1) {
72         poptPrintUsage(pc, stdout, 0);
73         poptFreeContext(pc);
74         exit(1);
75     }
76
77     argv_new = discard_const_p(char *, poptGetArgs(pc));
78
79     argc_new = argc;
80     for (i = 0; i < argc; i++) {
81         if (argv_new[i] == NULL) {
82             argc_new = i;
83             break;
84         }
85     }
86
87     if (argc_new != 3 || argv_new[1][0] != '/'
88         || argv_new[1][1] != '/') {
89         poptPrintUsage(pc, stdout, 0);
90         poptFreeContext(pc);
91         exit(1);
92     }
93
94     pmyargs->hostname = argv_new[1] + 2;
95     pmyargs->query = argv_new[2];
96     poptFreeContext(pc);
97 }
98
99 #define WERR_CHECK(msg) if (!W_ERROR_IS_OK(result)) { \
100                             DEBUG(0, ("ERROR: %s\n", msg)); \
101                             goto error; \
102                         } else { \
103                             DEBUG(1, ("OK   : %s\n", msg)); \
104                         }
105
106 #define RETURN_CVAR_ARRAY_STR(fmt, arr) {\
107         uint32_t i;\
108         char *r;\
109 \
110         if (!arr) {\
111                 return talloc_strdup(mem_ctx, "NULL");\
112         }\
113         r = talloc_strdup(mem_ctx, "(");\
114         for (i = 0; i < arr->count; ++i) {\
115                 r = talloc_asprintf_append(r, fmt "%s", arr->item[i], (i+1 == arr->count)?"":",");\
116         }\
117         return talloc_asprintf_append(r, ")");\
118 }
119
120 char *string_CIMVAR(TALLOC_CTX *mem_ctx, union CIMVAR *v, enum CIMTYPE_ENUMERATION cimtype)
121 {
122         switch (cimtype) {
123         case CIM_SINT8: return talloc_asprintf(mem_ctx, "%d", v->v_sint8);
124         case CIM_UINT8: return talloc_asprintf(mem_ctx, "%u", v->v_uint8);
125         case CIM_SINT16: return talloc_asprintf(mem_ctx, "%d", v->v_sint16);
126         case CIM_UINT16: return talloc_asprintf(mem_ctx, "%u", v->v_uint16);
127         case CIM_SINT32: return talloc_asprintf(mem_ctx, "%d", v->v_sint32);
128         case CIM_UINT32: return talloc_asprintf(mem_ctx, "%u", v->v_uint32);
129         case CIM_SINT64: return talloc_asprintf(mem_ctx, "%lld", v->v_sint64);
130         case CIM_UINT64: return talloc_asprintf(mem_ctx, "%llu", v->v_sint64);
131         case CIM_REAL32: return talloc_asprintf(mem_ctx, "%f", (double)v->v_uint32);
132         case CIM_REAL64: return talloc_asprintf(mem_ctx, "%f", (double)v->v_uint64);
133         case CIM_BOOLEAN: return talloc_asprintf(mem_ctx, "%s", v->v_boolean?"True":"False");
134         case CIM_STRING:
135         case CIM_DATETIME:
136         case CIM_REFERENCE: return talloc_asprintf(mem_ctx, "%s", v->v_string);
137         case CIM_CHAR16: return talloc_asprintf(mem_ctx, "Unsupported");
138         case CIM_OBJECT: return talloc_asprintf(mem_ctx, "Unsupported");
139         case CIM_ARR_SINT8: RETURN_CVAR_ARRAY_STR("%d", v->a_sint8);
140         case CIM_ARR_UINT8: RETURN_CVAR_ARRAY_STR("%u", v->a_uint8);
141         case CIM_ARR_SINT16: RETURN_CVAR_ARRAY_STR("%d", v->a_sint16);
142         case CIM_ARR_UINT16: RETURN_CVAR_ARRAY_STR("%u", v->a_uint16);
143         case CIM_ARR_SINT32: RETURN_CVAR_ARRAY_STR("%d", v->a_sint32);
144         case CIM_ARR_UINT32: RETURN_CVAR_ARRAY_STR("%u", v->a_uint32);
145         case CIM_ARR_SINT64: RETURN_CVAR_ARRAY_STR("%lld", v->a_sint64);
146         case CIM_ARR_UINT64: RETURN_CVAR_ARRAY_STR("%llu", v->a_uint64);
147         case CIM_ARR_REAL32: RETURN_CVAR_ARRAY_STR("%f", v->a_real32);
148         case CIM_ARR_REAL64: RETURN_CVAR_ARRAY_STR("%f", v->a_real64);
149         case CIM_ARR_BOOLEAN: RETURN_CVAR_ARRAY_STR("%d", v->a_boolean);
150         case CIM_ARR_STRING: RETURN_CVAR_ARRAY_STR("%s", v->a_string);
151         case CIM_ARR_DATETIME: RETURN_CVAR_ARRAY_STR("%s", v->a_datetime);
152         case CIM_ARR_REFERENCE: RETURN_CVAR_ARRAY_STR("%s", v->a_reference);
153         default: return talloc_asprintf(mem_ctx, "Unsupported");
154         }
155 }
156
157 #undef RETURN_CVAR_ARRAY_STR
158
159 int main(int argc, char **argv)
160 {
161         struct program_args args = {};
162         uint32_t cnt = 5, ret;
163         char *class_name = NULL;
164         WERROR result;
165         NTSTATUS status;
166         struct IWbemServices *pWS = NULL;
167
168         parse_args(argc, argv, &args);
169
170         dcerpc_init();
171         dcerpc_table_init();
172
173         dcom_proxy_IUnknown_init();
174         dcom_proxy_IWbemLevel1Login_init();
175         dcom_proxy_IWbemServices_init();
176         dcom_proxy_IEnumWbemClassObject_init();
177         dcom_proxy_IRemUnknown_init();
178         dcom_proxy_IWbemFetchSmartEnum_init();
179         dcom_proxy_IWbemWCOSmartEnum_init();
180
181         struct com_context *ctx = NULL;
182         com_init_ctx(&ctx, NULL);
183         dcom_client_init(ctx, cmdline_credentials);
184
185         if (!args.ns)
186                 args.ns = "root\\cimv2";
187         result = WBEM_ConnectServer(ctx, args.hostname, args.ns, 0, 0, 0, 0, 0, 0, &pWS);
188         WERR_CHECK("Login to remote object.");
189
190         struct IEnumWbemClassObject *pEnum = NULL;
191         result = IWbemServices_ExecQuery(pWS, ctx, "WQL", args.query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_ENSURE_LOCATABLE, NULL, &pEnum);
192         WERR_CHECK("WMI query execute.");
193
194         IEnumWbemClassObject_Reset(pEnum, ctx);
195         WERR_CHECK("Reset result of WMI query.");
196
197         do {
198                 uint32_t i, j;
199                 struct WbemClassObject *co[cnt];
200
201                 result = IEnumWbemClassObject_SmartNext(pEnum, ctx, 0xFFFFFFFF, cnt, co, &ret);
202                 /* WERR_BADFUNC is OK, it means only that there is less returned objects than requested */
203                 if (!W_ERROR_EQUAL(result, WERR_BADFUNC)) {
204                         WERR_CHECK("Retrieve result data.");
205                 } else {
206                         DEBUG(1, ("OK   : Retrieved less objects than requested (it is normal).\n"));
207                 }
208                 if (!ret) break;
209
210                 for (i = 0; i < ret; ++i) {
211                         if (!class_name || strcmp(co[i]->obj_class->__CLASS, class_name)) {
212                                 if (class_name) talloc_free(class_name);
213                                 class_name = talloc_strdup(ctx, co[i]->obj_class->__CLASS);
214                                 printf("CLASS: %s\n", class_name);
215                                 for (j = 0; j < co[i]->obj_class->__PROPERTY_COUNT; ++j)
216                                         printf("%s%s", j?"|":"", co[i]->obj_class->properties[j].name);
217                                 printf("\n");
218                         }
219                         for (j = 0; j < co[i]->obj_class->__PROPERTY_COUNT; ++j) {
220                                 char *s;
221                                 s = string_CIMVAR(ctx, &co[i]->instance->data[j], co[i]->obj_class->properties[j].desc->cimtype & CIM_TYPEMASK);
222                                 printf("%s%s", j?"|":"", s);
223                         }
224                         printf("\n");
225                 }
226         } while (ret == cnt);
227         talloc_free(ctx);
228         return 0;
229 error:
230         status = werror_to_ntstatus(result);
231         fprintf(stderr, "NTSTATUS: %s - %s\n", nt_errstr(status), get_friendly_nt_error_msg(status));
232         talloc_free(ctx);
233         return 1;
234 }