Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : RPC pipe client
4 :
5 : Copyright (C) Gregor Beck 2013-2014
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "rpcclient.h"
23 : #include "librpc/gen_ndr/ndr_witness_c.h"
24 : #include <popt.h>
25 :
26 : /*
27 : * We have to use the same connection for each subcommand
28 : * for the context handles to be meaningful.
29 : */
30 : static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli);
31 :
32 0 : static WERROR cmd_witness_GetInterfaceList(struct rpc_pipe_client *cli,
33 : TALLOC_CTX *mem_ctx, int argc,
34 : const char **argv)
35 : {
36 : NTSTATUS status;
37 : WERROR result;
38 0 : TALLOC_CTX *frame = talloc_stackframe();
39 0 : struct witness_interfaceList *interface_list = NULL;
40 : uint32_t num_interfaces, n;
41 : struct witness_interfaceInfo *interfaces;
42 :
43 0 : use_only_one_rpc_pipe_hack(cli);
44 :
45 0 : status = dcerpc_witness_GetInterfaceList(cli->binding_handle, frame,
46 : &interface_list, &result);
47 0 : if (!NT_STATUS_IS_OK(status)) {
48 0 : DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, status: %s\n", nt_errstr(status)));
49 0 : result = ntstatus_to_werror(status);
50 0 : goto done;
51 : }
52 0 : if (!W_ERROR_IS_OK(result)) {
53 0 : DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, error: %s\n", win_errstr(result)));
54 0 : goto done;
55 : }
56 :
57 0 : SMB_ASSERT(interface_list);
58 0 : interfaces = interface_list->interfaces;
59 0 : num_interfaces = interface_list->num_interfaces;
60 :
61 0 : for (n=0; n < num_interfaces; n++) {
62 0 : char wif = (interfaces[n].flags & WITNESS_INFO_WITNESS_IF) ? '*' : ' ';
63 0 : char state = 'X';
64 :
65 0 : if (interfaces[n].state == WITNESS_STATE_AVAILABLE) {
66 0 : state = '+';
67 0 : } else if (interfaces[n].state == WITNESS_STATE_UNAVAILABLE) {
68 0 : state = '-';
69 0 : } else if (interfaces[n].state == WITNESS_STATE_UNKNOWN) {
70 0 : state = '?';
71 : }
72 :
73 0 : d_printf("%c%c %s", wif, state, interfaces[n].group_name);
74 :
75 0 : if (interfaces[n].flags & WITNESS_INFO_IPv4_VALID) {
76 0 : d_printf(" %s", interfaces[n].ipv4);
77 : }
78 :
79 0 : if (interfaces[n].flags & WITNESS_INFO_IPv6_VALID) {
80 0 : d_printf(" %s", interfaces[n].ipv6);
81 : }
82 :
83 0 : switch (interfaces[n].version) {
84 0 : case WITNESS_V1:
85 0 : d_printf(" V1");
86 0 : break;
87 0 : case WITNESS_V2:
88 0 : d_printf(" V2");
89 0 : break;
90 0 : default:
91 0 : d_printf(" Unsupported Version (0x%08x)", interfaces[n].version);
92 : }
93 :
94 0 : d_printf("\n");
95 : }
96 :
97 0 : done:
98 0 : talloc_free(frame);
99 0 : return result;
100 : }
101 :
102 0 : static WERROR cmd_witness_Register(struct rpc_pipe_client *cli,
103 : TALLOC_CTX *mem_ctx, int argc,
104 : const char **argv)
105 : {
106 : static char hostname[MAXHOSTNAMELEN] = {'\0'};
107 : NTSTATUS status;
108 0 : WERROR result = WERR_OK;
109 0 : TALLOC_CTX *frame = talloc_stackframe();
110 : struct policy_handle hnd;
111 0 : const char *net_name = NULL;
112 0 : const char *ip_addr = NULL;
113 0 : const char *client_name = hostname;
114 0 : long version = WITNESS_V1;
115 : int c;
116 : poptContext optCon;
117 0 : struct poptOption optionsTable[] = {
118 : {
119 : .longName = "version",
120 : .shortName = 'v',
121 : .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
122 : .arg = &version,
123 : .val = WITNESS_V2,
124 : .descrip = "witness version",
125 : .argDescrip = "version"
126 : },
127 : {
128 : .longName = "V1",
129 : .shortName = '1',
130 : .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
131 : .arg = &version,
132 : .val = WITNESS_V1,
133 : .descrip = "witness version 1",
134 : .argDescrip = NULL
135 : },
136 : {
137 : .longName = "V2",
138 : .shortName = '2',
139 : .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
140 : .arg = &version,
141 : .val = WITNESS_V2,
142 : .descrip = "witness version 2",
143 : .argDescrip = NULL
144 : },
145 : {
146 : .longName = "net",
147 : .shortName = 'n',
148 : .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
149 : .arg = &net_name,
150 : .val = 0,
151 : .descrip = "net name",
152 : .argDescrip = NULL
153 : },
154 : {
155 : .longName = "ip",
156 : .shortName = 'i',
157 : .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
158 : .arg = &ip_addr,
159 : .val = 0,
160 : .descrip = "ip address",
161 : .argDescrip = NULL
162 : },
163 : {
164 : .longName = "client",
165 : .shortName = 'c',
166 : .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL,
167 : .arg = &client_name,
168 : .val = 0,
169 : .descrip = "client name",
170 : .argDescrip = NULL
171 : },
172 : POPT_TABLEEND
173 : };
174 :
175 0 : use_only_one_rpc_pipe_hack(cli);
176 :
177 0 : if (hostname[0] == '\0') {
178 0 : gethostname (hostname, sizeof(hostname));
179 : }
180 :
181 0 : optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
182 :
183 0 : while ((c = poptGetNextOpt(optCon)) >= 0) { }
184 :
185 0 : if (c < -1) {
186 : /* an error occurred during option processing */
187 0 : d_fprintf(stderr, "%s: %s\n",
188 : poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
189 : poptStrerror(c));
190 0 : goto done;
191 : }
192 :
193 0 : if (argc < 2 || poptPeekArg(optCon) != NULL) {
194 0 : poptPrintHelp(optCon, stderr, 0);
195 0 : goto done;
196 : }
197 :
198 0 : status = dcerpc_witness_Register(cli->binding_handle, frame,
199 : &hnd,
200 : version,
201 : net_name, ip_addr, client_name,
202 : &result);
203 0 : if (!NT_STATUS_IS_OK(status)) {
204 0 : DEBUG(0, ("dcerpc_witness_Register failed, status: %s\n", nt_errstr(status)));
205 0 : result = ntstatus_to_werror(status);
206 0 : goto done;
207 : }
208 0 : if (!W_ERROR_IS_OK(result)) {
209 0 : DEBUG(0, ("dcerpc_witness_Register failed, error: %s\n", win_errstr(result)));
210 0 : goto done;
211 : }
212 :
213 0 : d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
214 :
215 0 : done:
216 0 : poptFreeContext(optCon);
217 0 : talloc_free(frame);
218 0 : return result;
219 : }
220 :
221 0 : static WERROR cmd_witness_RegisterEx(struct rpc_pipe_client *cli,
222 : TALLOC_CTX *mem_ctx, int argc,
223 : const char **argv)
224 : {
225 : static char hostname[MAXHOSTNAMELEN] = {'\0'};
226 : NTSTATUS status;
227 0 : WERROR result = WERR_OK;
228 0 : TALLOC_CTX *frame = talloc_stackframe();
229 : struct policy_handle hnd;
230 0 : const char *net_name = NULL;
231 0 : const char *ip_addr = NULL;
232 0 : const char *share_name = NULL;
233 0 : const char *client_name = hostname;
234 0 : long version = WITNESS_V2;
235 0 : long flags = 0;
236 0 : long timeout = 0;
237 : int c;
238 : poptContext optCon;
239 0 : struct poptOption optionsTable[] = {
240 : {
241 : .longName = "version",
242 : .shortName = 'v',
243 : .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
244 : .arg = &version,
245 : .val = WITNESS_V2,
246 : .descrip = "witness version",
247 : .argDescrip = "version"
248 : },
249 : {
250 : .longName = "V1",
251 : .shortName = '1',
252 : .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
253 : .arg = &version,
254 : .val = WITNESS_V1,
255 : .descrip = "witness version 1",
256 : },
257 : {
258 : .longName = "V2",
259 : .shortName = '2',
260 : .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
261 : .arg = &version,
262 : .val = WITNESS_V2,
263 : .descrip = "witness version 2",
264 : },
265 : {
266 : .longName = "net",
267 : .shortName = 'n',
268 : .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
269 : .arg = &net_name,
270 : .val = 0,
271 : .descrip = "net name",
272 : },
273 : {
274 : .longName = "ip",
275 : .shortName = 'i',
276 : .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
277 : .arg = &ip_addr,
278 : .val = 0,
279 : .descrip = "ip address",
280 : },
281 : {
282 : .longName = "share",
283 : .shortName = 's',
284 : .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
285 : .arg = &share_name,
286 : .val = 0,
287 : .descrip = "share name",
288 : },
289 : {
290 : .longName = "client",
291 : .shortName = 'c',
292 : .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL,
293 : .arg = &client_name,
294 : .val = 0,
295 : .descrip = "client name",
296 : },
297 : {
298 : .longName = "flags",
299 : .shortName = 'f',
300 : .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_OR|POPT_ARGFLAG_SHOW_DEFAULT,
301 : .arg = &flags,
302 : .val = 0,
303 : .descrip = "flags",
304 : },
305 : {
306 : .longName = "timeout",
307 : .shortName = 't',
308 : .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
309 : .arg = &timeout,
310 : .val = 0,
311 : .descrip = "timeout",
312 : },
313 : POPT_TABLEEND
314 : };
315 :
316 0 : use_only_one_rpc_pipe_hack(cli);
317 :
318 0 : if (hostname[0] == '\0') {
319 0 : gethostname (hostname, sizeof(hostname));
320 : }
321 :
322 0 : optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
323 :
324 0 : while ((c = poptGetNextOpt(optCon)) >= 0) { }
325 :
326 0 : if (c < -1) {
327 : /* an error occurred during option processing */
328 0 : d_fprintf(stderr, "%s: %s\n",
329 : poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
330 : poptStrerror(c));
331 0 : goto done;
332 : }
333 :
334 0 : if (argc < 2 || poptPeekArg(optCon) != NULL) {
335 0 : poptPrintHelp(optCon, stderr, 0);
336 0 : goto done;
337 : }
338 :
339 0 : status = dcerpc_witness_RegisterEx(cli->binding_handle, frame,
340 : &hnd,
341 : version,
342 : net_name, share_name, ip_addr, client_name,
343 : flags, timeout,
344 : &result);
345 0 : if (!NT_STATUS_IS_OK(status)) {
346 0 : DEBUG(0, ("dcerpc_witness_RegisterEx failed, status: %s\n", nt_errstr(status)));
347 0 : result = ntstatus_to_werror(status);
348 0 : goto done;
349 : }
350 0 : if (!W_ERROR_IS_OK(result)) {
351 0 : DEBUG(0, ("dcerpc_witness_RegisterEx failed, error: %s\n", win_errstr(result)));
352 0 : goto done;
353 : }
354 :
355 0 : d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
356 :
357 0 : done:
358 0 : poptFreeContext(optCon);
359 0 : talloc_free(frame);
360 0 : return result;
361 : }
362 :
363 : static bool
364 0 : read_context_handle(const char *str, struct policy_handle *hnd)
365 : {
366 : NTSTATUS status;
367 : long type;
368 : char *pos;
369 : struct GUID guid;
370 :
371 0 : type = strtol(str, &pos, 16);
372 0 : if (*pos != ':') {
373 0 : DEBUG(0, ("read_context_handle: failed to parse type\n"));
374 0 : return false;
375 : }
376 0 : status = GUID_from_string(pos+1, &guid);
377 0 : if (!NT_STATUS_IS_OK(status)) {
378 0 : DEBUG(0, ("read_context_handle: failed to parse guid %s\n", nt_errstr(status)));
379 0 : return false;
380 : }
381 :
382 0 : hnd->handle_type = type;
383 0 : hnd->uuid = guid;
384 0 : return true;
385 : }
386 :
387 0 : static WERROR cmd_witness_UnRegister(struct rpc_pipe_client *cli,
388 : TALLOC_CTX *mem_ctx, int argc,
389 : const char **argv)
390 : {
391 : NTSTATUS status;
392 0 : WERROR result = WERR_OK;
393 0 : TALLOC_CTX *frame = talloc_stackframe();
394 : struct policy_handle hnd;
395 :
396 0 : use_only_one_rpc_pipe_hack(cli);
397 :
398 0 : if (argc != 2) {
399 0 : d_printf("%s <context_handle>\n", argv[0]);
400 0 : goto done;
401 : }
402 :
403 0 : if (!read_context_handle(argv[1], &hnd)) {
404 0 : result = WERR_INVALID_PARAMETER;
405 0 : goto done;
406 : }
407 :
408 0 : status = dcerpc_witness_UnRegister(cli->binding_handle, frame,
409 : hnd, &result);
410 0 : if (!NT_STATUS_IS_OK(status)) {
411 0 : DEBUG(0, ("dcerpc_witness_UnRegister failed, status: %s\n", nt_errstr(status)));
412 0 : result = ntstatus_to_werror(status);
413 0 : goto done;
414 : }
415 0 : if (!W_ERROR_IS_OK(result)) {
416 0 : DEBUG(0, ("dcerpc_witness_UnRegister failed, error: %s\n", win_errstr(result)));
417 0 : goto done;
418 : }
419 :
420 0 : done:
421 0 : talloc_free(frame);
422 0 : return result;
423 : }
424 :
425 0 : static void print_notify_response_resource_change(struct witness_ResourceChange *r)
426 : {
427 : const char *type_str;
428 :
429 0 : if (r->type == WITNESS_RESOURCE_STATE_UNKNOWN) {
430 0 : type_str = "Unknown";
431 0 : } else if (r->type == WITNESS_RESOURCE_STATE_AVAILABLE) {
432 0 : type_str = "Available\n";
433 0 : } else if (r->type == WITNESS_RESOURCE_STATE_UNAVAILABLE) {
434 0 : type_str = "Unavailable";
435 : } else {
436 0 : type_str = talloc_asprintf(r, "Invalid (%u)", r->type);
437 : }
438 0 : d_printf("%s -> %s\n", r->name, type_str);
439 0 : }
440 :
441 0 : static void print_notify_response_ip_addr_info_list(struct witness_IPaddrInfoList *r)
442 : {
443 : int i;
444 :
445 0 : for (i=0; i < r->num; i++) {
446 0 : uint32_t flags = r->addr[i].flags;
447 0 : const char *str4 = r->addr[i].ipv4;
448 0 : const char *str6 = r->addr[i].ipv6;
449 :
450 0 : d_printf("Flags 0x%08x", flags);
451 0 : if (flags & WITNESS_IPADDR_V4) {
452 0 : d_printf(" %s", str4);
453 : }
454 0 : if (flags & WITNESS_IPADDR_V6) {
455 0 : d_printf(" %s", str6);
456 : }
457 0 : if (flags & WITNESS_IPADDR_ONLINE) {
458 0 : d_printf(" Online");
459 : }
460 0 : if (flags & WITNESS_IPADDR_ONLINE) {
461 0 : d_printf(" Offline");
462 : }
463 0 : d_printf("\n");
464 : }
465 0 : }
466 :
467 0 : static void print_notify_response(union witness_notifyResponse_message *r,
468 : uint32_t type)
469 : {
470 0 : switch (type) {
471 0 : case WITNESS_NOTIFY_RESOURCE_CHANGE:
472 0 : print_notify_response_resource_change(&r->resource_change);
473 0 : break;
474 0 : case WITNESS_NOTIFY_CLIENT_MOVE:
475 : case WITNESS_NOTIFY_SHARE_MOVE:
476 : case WITNESS_NOTIFY_IP_CHANGE:
477 0 : print_notify_response_ip_addr_info_list(&r->client_move);
478 0 : break;
479 0 : default:
480 0 : break;
481 : }
482 0 : }
483 :
484 0 : static WERROR cmd_witness_AsyncNotify(struct rpc_pipe_client *cli,
485 : TALLOC_CTX *mem_ctx, int argc,
486 : const char **argv)
487 : {
488 : NTSTATUS status;
489 0 : WERROR result = WERR_OK;
490 0 : TALLOC_CTX *frame = talloc_stackframe();
491 : struct policy_handle hnd;
492 0 : struct witness_notifyResponse *response = NULL;
493 : uint32_t timeout;
494 : int i;
495 :
496 0 : use_only_one_rpc_pipe_hack(cli);
497 :
498 0 : if (argc != 2) {
499 0 : d_printf("%s <context_handle>\n", argv[0]);
500 0 : goto done;
501 : }
502 :
503 0 : if (!read_context_handle(argv[1], &hnd)) {
504 0 : result = WERR_INVALID_PARAMETER;
505 0 : goto done;
506 : }
507 :
508 0 : timeout = dcerpc_binding_handle_set_timeout(cli->binding_handle, UINT32_MAX);
509 0 : status = dcerpc_witness_AsyncNotify(cli->binding_handle, frame, hnd,
510 : &response, &result);
511 0 : dcerpc_binding_handle_set_timeout(cli->binding_handle, timeout);
512 0 : if (!NT_STATUS_IS_OK(status)) {
513 0 : DEBUG(0, ("dcerpc_witness_AsyncNotify failed, status: %s\n", nt_errstr(status)));
514 0 : result = ntstatus_to_werror(status);
515 0 : goto done;
516 : }
517 0 : if (!W_ERROR_IS_OK(result)) {
518 0 : DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result)));
519 0 : goto done;
520 : }
521 :
522 0 : if (response == NULL) {
523 0 : d_printf("Got an empty response\n");
524 0 : goto done;
525 : }
526 :
527 0 : switch(response->type) {
528 0 : case WITNESS_NOTIFY_RESOURCE_CHANGE:
529 0 : d_printf("Resource change");
530 0 : break;
531 0 : case WITNESS_NOTIFY_CLIENT_MOVE:
532 0 : d_printf("Client move");
533 0 : break;
534 0 : case WITNESS_NOTIFY_SHARE_MOVE:
535 0 : d_printf("Share move");
536 0 : break;
537 0 : case WITNESS_NOTIFY_IP_CHANGE:
538 0 : d_printf("IP change");
539 0 : break;
540 0 : default:
541 0 : d_printf("Unknown (0x%x)", (int)response->type);
542 : }
543 0 : d_printf(" with %d messages\n", response->num);
544 :
545 0 : for (i=0; i < response->num; i++) {
546 0 : print_notify_response(&response->messages[i], response->type);
547 : }
548 0 : done:
549 0 : talloc_free(frame);
550 0 : return result;
551 : }
552 :
553 : struct cmd_set witness_commands[] = {
554 : {
555 : .name = "WITNESS",
556 : },
557 : {
558 : .name = "GetInterfaceList",
559 : .returntype = RPC_RTYPE_WERROR,
560 : .ntfn = NULL,
561 : .wfn = &cmd_witness_GetInterfaceList,
562 : .table = &ndr_table_witness,
563 : .rpc_pipe = NULL,
564 : .description = "List the interfaces to which witness client connections can be made",
565 : .usage = "",
566 : },
567 : {
568 : .name = "Register",
569 : .returntype = RPC_RTYPE_WERROR,
570 : .ntfn = NULL,
571 : .wfn = &cmd_witness_Register,
572 : .table = &ndr_table_witness,
573 : .rpc_pipe = NULL,
574 : .description = "Register for resource state change notifications of a NetName and IPAddress",
575 : .usage = "",
576 : },
577 : {
578 : .name = "UnRegister",
579 : .returntype = RPC_RTYPE_WERROR,
580 : .ntfn = NULL,
581 : .wfn = &cmd_witness_UnRegister,
582 : .table = &ndr_table_witness,
583 : .rpc_pipe = NULL,
584 : .description = "Unregister for notifications from the server</para></listitem></varlistentry>",
585 : .usage = "",
586 : },
587 : {
588 : .name = "AsyncNotify",
589 : .returntype = RPC_RTYPE_WERROR,
590 : .ntfn = NULL,
591 : .wfn = &cmd_witness_AsyncNotify,
592 : .table = &ndr_table_witness,
593 : .rpc_pipe = NULL,
594 : .description = "Request notification of registered resource changes from the server",
595 : .usage = "",
596 : },
597 : {
598 : .name = "RegisterEx",
599 : .returntype = RPC_RTYPE_WERROR,
600 : .ntfn = NULL,
601 : .wfn = &cmd_witness_RegisterEx,
602 : .table = &ndr_table_witness,
603 : .rpc_pipe = NULL,
604 : .description = "Register for resource state change notifications of a NetName, ShareName and multiple IPAddresses",
605 : .usage = "",
606 : },
607 : {
608 : .name = NULL,
609 : }
610 : };
611 :
612 : /*
613 : * We have to use the same connection for each subcommand
614 : * for the context handles to be meaningful.
615 : */
616 0 : static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli)
617 : {
618 : struct cmd_set *ptr;
619 :
620 0 : for (ptr = &witness_commands[0]; ptr->name; ptr++) {
621 0 : ptr->rpc_pipe = cli;
622 : }
623 0 : }
|