2 Unix SMB/CIFS implementation.
5 Copyright (C) Gregor Beck 2013-2014
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.
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.
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/>.
22 #include "rpcclient.h"
23 #include "librpc/gen_ndr/ndr_witness_c.h"
27 * We have to use the same connection for each subcommand
28 * for the context handles to be meaningful.
30 static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli);
32 static WERROR cmd_witness_GetInterfaceList(struct rpc_pipe_client *cli,
33 TALLOC_CTX *mem_ctx, int argc,
38 TALLOC_CTX *frame = talloc_stackframe();
39 struct witness_interfaceList *interface_list = NULL;
40 uint32_t num_interfaces, n;
41 struct witness_interfaceInfo *interfaces;
43 use_only_one_rpc_pipe_hack(cli);
45 status = dcerpc_witness_GetInterfaceList(cli->binding_handle, frame,
46 &interface_list, &result);
47 if (!NT_STATUS_IS_OK(status)) {
48 DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, status: %s\n", nt_errstr(status)));
49 result = ntstatus_to_werror(status);
52 if (!W_ERROR_IS_OK(result)) {
53 DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, error: %s\n", win_errstr(result)));
57 SMB_ASSERT(interface_list);
58 interfaces = interface_list->interfaces;
59 num_interfaces = interface_list->num_interfaces;
61 for (n=0; n < num_interfaces; n++) {
62 char wif = (interfaces[n].flags & WITNESS_INFO_WITNESS_IF) ? '*' : ' ';
65 if (interfaces[n].state == WITNESS_STATE_AVAILABLE) {
67 } else if (interfaces[n].state == WITNESS_STATE_UNAVAILABLE) {
69 } else if (interfaces[n].state == WITNESS_STATE_UNKNOWN) {
73 d_printf("%c%c %s", wif, state, interfaces[n].group_name);
75 if (interfaces[n].flags & WITNESS_INFO_IPv4_VALID) {
76 d_printf(" %s", interfaces[n].ipv4);
79 if (interfaces[n].flags & WITNESS_INFO_IPv6_VALID) {
80 d_printf(" %s", interfaces[n].ipv6);
83 switch (interfaces[n].version) {
91 d_printf(" Unsupported Version (0x%08x)", interfaces[n].version);
102 static WERROR cmd_witness_Register(struct rpc_pipe_client *cli,
103 TALLOC_CTX *mem_ctx, int argc,
106 static char hostname[MAXHOSTNAMELEN] = {'\0'};
108 WERROR result = WERR_OK;
109 TALLOC_CTX *frame = talloc_stackframe();
110 struct policy_handle hnd;
111 const char *net_name = NULL;
112 const char *ip_addr = NULL;
113 const char *client_name = hostname;
114 long version = WITNESS_V1;
117 struct poptOption optionsTable[] = {
119 .longName = "version",
121 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
124 .descrip = "witness version",
125 .argDescrip = "version"
130 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
133 .descrip = "witness version 1",
139 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
142 .descrip = "witness version 2",
148 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
151 .descrip = "net name",
157 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
160 .descrip = "ip address",
164 .longName = "client",
166 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL,
169 .descrip = "client name",
175 use_only_one_rpc_pipe_hack(cli);
177 if (hostname[0] == '\0') {
178 gethostname (hostname, sizeof(hostname));
181 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
183 while ((c = poptGetNextOpt(optCon)) >= 0) { }
186 /* an error occurred during option processing */
187 d_fprintf(stderr, "%s: %s\n",
188 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
193 if (argc < 2 || poptPeekArg(optCon) != NULL) {
194 poptPrintHelp(optCon, stderr, 0);
198 status = dcerpc_witness_Register(cli->binding_handle, frame,
201 net_name, ip_addr, client_name,
203 if (!NT_STATUS_IS_OK(status)) {
204 DEBUG(0, ("dcerpc_witness_Register failed, status: %s\n", nt_errstr(status)));
205 result = ntstatus_to_werror(status);
208 if (!W_ERROR_IS_OK(result)) {
209 DEBUG(0, ("dcerpc_witness_Register failed, error: %s\n", win_errstr(result)));
213 d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
216 poptFreeContext(optCon);
221 static WERROR cmd_witness_RegisterEx(struct rpc_pipe_client *cli,
222 TALLOC_CTX *mem_ctx, int argc,
225 static char hostname[MAXHOSTNAMELEN] = {'\0'};
227 WERROR result = WERR_OK;
228 TALLOC_CTX *frame = talloc_stackframe();
229 struct policy_handle hnd;
230 const char *net_name = NULL;
231 const char *ip_addr = NULL;
232 const char *share_name = NULL;
233 const char *client_name = hostname;
234 long version = WITNESS_V2;
239 struct poptOption optionsTable[] = {
241 .longName = "version",
243 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
246 .descrip = "witness version",
247 .argDescrip = "version"
252 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
255 .descrip = "witness version 1",
260 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
263 .descrip = "witness version 2",
268 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
271 .descrip = "net name",
276 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
279 .descrip = "ip address",
284 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
287 .descrip = "share name",
290 .longName = "client",
292 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL,
295 .descrip = "client name",
300 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_OR|POPT_ARGFLAG_SHOW_DEFAULT,
306 .longName = "timeout",
308 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
311 .descrip = "timeout",
316 use_only_one_rpc_pipe_hack(cli);
318 if (hostname[0] == '\0') {
319 gethostname (hostname, sizeof(hostname));
322 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
324 while ((c = poptGetNextOpt(optCon)) >= 0) { }
327 /* an error occurred during option processing */
328 d_fprintf(stderr, "%s: %s\n",
329 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
334 if (argc < 2 || poptPeekArg(optCon) != NULL) {
335 poptPrintHelp(optCon, stderr, 0);
339 status = dcerpc_witness_RegisterEx(cli->binding_handle, frame,
342 net_name, share_name, ip_addr, client_name,
345 if (!NT_STATUS_IS_OK(status)) {
346 DEBUG(0, ("dcerpc_witness_RegisterEx failed, status: %s\n", nt_errstr(status)));
347 result = ntstatus_to_werror(status);
350 if (!W_ERROR_IS_OK(result)) {
351 DEBUG(0, ("dcerpc_witness_RegisterEx failed, error: %s\n", win_errstr(result)));
355 d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
358 poptFreeContext(optCon);
364 read_context_handle(const char *str, struct policy_handle *hnd)
371 type = strtol(str, &pos, 16);
373 DEBUG(0, ("read_context_handle: failed to parse type\n"));
376 status = GUID_from_string(pos+1, &guid);
377 if (!NT_STATUS_IS_OK(status)) {
378 DEBUG(0, ("read_context_handle: failed to parse guid %s\n", nt_errstr(status)));
382 hnd->handle_type = type;
387 static WERROR cmd_witness_UnRegister(struct rpc_pipe_client *cli,
388 TALLOC_CTX *mem_ctx, int argc,
392 WERROR result = WERR_OK;
393 TALLOC_CTX *frame = talloc_stackframe();
394 struct policy_handle hnd;
396 use_only_one_rpc_pipe_hack(cli);
399 d_printf("%s <context_handle>\n", argv[0]);
403 if (!read_context_handle(argv[1], &hnd)) {
404 result = WERR_INVALID_PARAMETER;
408 status = dcerpc_witness_UnRegister(cli->binding_handle, frame,
410 if (!NT_STATUS_IS_OK(status)) {
411 DEBUG(0, ("dcerpc_witness_UnRegister failed, status: %s\n", nt_errstr(status)));
412 result = ntstatus_to_werror(status);
415 if (!W_ERROR_IS_OK(result)) {
416 DEBUG(0, ("dcerpc_witness_UnRegister failed, error: %s\n", win_errstr(result)));
425 static void print_notify_response_resource_change(struct witness_ResourceChange *r)
427 const char *type_str;
429 if (r->type == WITNESS_RESOURCE_STATE_UNKNOWN) {
430 type_str = "Unknown";
431 } else if (r->type == WITNESS_RESOURCE_STATE_AVAILABLE) {
432 type_str = "Available\n";
433 } else if (r->type == WITNESS_RESOURCE_STATE_UNAVAILABLE) {
434 type_str = "Unavailable";
436 type_str = talloc_asprintf(r, "Invalid (%u)", r->type);
438 d_printf("%s -> %s\n", r->name, type_str);
441 static void print_notify_response_ip_addr_info_list(struct witness_IPaddrInfoList *r)
445 for (i=0; i < r->num; i++) {
446 uint32_t flags = r->addr[i].flags;
447 const char *str4 = r->addr[i].ipv4;
448 const char *str6 = r->addr[i].ipv6;
450 d_printf("Flags 0x%08x", flags);
451 if (flags & WITNESS_IPADDR_V4) {
452 d_printf(" %s", str4);
454 if (flags & WITNESS_IPADDR_V6) {
455 d_printf(" %s", str6);
457 if (flags & WITNESS_IPADDR_ONLINE) {
460 if (flags & WITNESS_IPADDR_ONLINE) {
461 d_printf(" Offline");
467 static void print_notify_response(union witness_notifyResponse_message *r,
471 case WITNESS_NOTIFY_RESOURCE_CHANGE:
472 print_notify_response_resource_change(&r->resource_change);
474 case WITNESS_NOTIFY_CLIENT_MOVE:
475 case WITNESS_NOTIFY_SHARE_MOVE:
476 case WITNESS_NOTIFY_IP_CHANGE:
477 print_notify_response_ip_addr_info_list(&r->client_move);
484 static WERROR cmd_witness_AsyncNotify(struct rpc_pipe_client *cli,
485 TALLOC_CTX *mem_ctx, int argc,
489 WERROR result = WERR_OK;
490 TALLOC_CTX *frame = talloc_stackframe();
491 struct policy_handle hnd;
492 struct witness_notifyResponse *response = NULL;
496 use_only_one_rpc_pipe_hack(cli);
499 d_printf("%s <context_handle>\n", argv[0]);
503 if (!read_context_handle(argv[1], &hnd)) {
504 result = WERR_INVALID_PARAMETER;
508 timeout = dcerpc_binding_handle_set_timeout(cli->binding_handle, UINT32_MAX);
509 status = dcerpc_witness_AsyncNotify(cli->binding_handle, frame, hnd,
511 dcerpc_binding_handle_set_timeout(cli->binding_handle, timeout);
512 if (!NT_STATUS_IS_OK(status)) {
513 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, status: %s\n", nt_errstr(status)));
514 result = ntstatus_to_werror(status);
517 if (!W_ERROR_IS_OK(result)) {
518 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result)));
522 if (response == NULL) {
523 d_printf("Got an empty response\n");
527 switch(response->type) {
528 case WITNESS_NOTIFY_RESOURCE_CHANGE:
529 d_printf("Resource change");
531 case WITNESS_NOTIFY_CLIENT_MOVE:
532 d_printf("Client move");
534 case WITNESS_NOTIFY_SHARE_MOVE:
535 d_printf("Share move");
537 case WITNESS_NOTIFY_IP_CHANGE:
538 d_printf("IP change");
541 d_printf("Unknown (0x%x)", (int)response->type);
543 d_printf(" with %d messages\n", response->num);
545 for (i=0; i < response->num; i++) {
546 print_notify_response(&response->messages[i], response->type);
553 struct cmd_set witness_commands[] = {
558 .name = "GetInterfaceList",
559 .returntype = RPC_RTYPE_WERROR,
561 .wfn = &cmd_witness_GetInterfaceList,
562 .table = &ndr_table_witness,
569 .returntype = RPC_RTYPE_WERROR,
571 .wfn = &cmd_witness_Register,
572 .table = &ndr_table_witness,
578 .name = "UnRegister",
579 .returntype = RPC_RTYPE_WERROR,
581 .wfn = &cmd_witness_UnRegister,
582 .table = &ndr_table_witness,
588 .name = "AsyncNotify",
589 .returntype = RPC_RTYPE_WERROR,
591 .wfn = &cmd_witness_AsyncNotify,
592 .table = &ndr_table_witness,
598 .name = "RegisterEx",
599 .returntype = RPC_RTYPE_WERROR,
601 .wfn = &cmd_witness_RegisterEx,
602 .table = &ndr_table_witness,
613 * We have to use the same connection for each subcommand
614 * for the context handles to be meaningful.
616 static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli)
620 for (ptr = &witness_commands[0]; ptr->name; ptr++) {