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(" Unsuported 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
));
220 static WERROR
cmd_witness_RegisterEx(struct rpc_pipe_client
*cli
,
221 TALLOC_CTX
*mem_ctx
, int argc
,
224 static char hostname
[MAXHOSTNAMELEN
] = {'\0'};
226 WERROR result
= WERR_OK
;
227 TALLOC_CTX
*frame
= talloc_stackframe();
228 struct policy_handle hnd
;
229 const char *net_name
= NULL
;
230 const char *ip_addr
= NULL
;
231 const char *share_name
= NULL
;
232 const char *client_name
= hostname
;
233 long version
= WITNESS_V2
;
238 struct poptOption optionsTable
[] = {
240 .longName
= "version",
242 .argInfo
= POPT_ARG_LONG
|POPT_ARGFLAG_SHOW_DEFAULT
,
245 .descrip
= "witness version",
246 .argDescrip
= "version"
251 .argInfo
= POPT_ARG_LONG
|POPT_ARG_VAL
,
254 .descrip
= "witness version 1",
259 .argInfo
= POPT_ARG_LONG
|POPT_ARG_VAL
,
262 .descrip
= "witness version 2",
267 .argInfo
= POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
,
270 .descrip
= "net name",
275 .argInfo
= POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
,
278 .descrip
= "ip address",
283 .argInfo
= POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
,
286 .descrip
= "share name",
289 .longName
= "client",
291 .argInfo
= POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
|POPT_ARGFLAG_OPTIONAL
,
294 .descrip
= "client name",
299 .argInfo
= POPT_ARG_LONG
|POPT_ARGFLAG_OR
|POPT_ARGFLAG_SHOW_DEFAULT
,
305 .longName
= "timeout",
307 .argInfo
= POPT_ARG_LONG
|POPT_ARGFLAG_SHOW_DEFAULT
,
310 .descrip
= "timeout",
315 use_only_one_rpc_pipe_hack(cli
);
317 if (hostname
[0] == '\0') {
318 gethostname (hostname
, sizeof(hostname
));
321 optCon
= poptGetContext(NULL
, argc
, argv
, optionsTable
, 0);
323 while ((c
= poptGetNextOpt(optCon
)) >= 0) { }
326 /* an error occurred during option processing */
327 d_fprintf(stderr
, "%s: %s\n",
328 poptBadOption(optCon
, POPT_BADOPTION_NOALIAS
),
333 if (argc
< 2 || poptPeekArg(optCon
) != NULL
) {
334 poptPrintHelp(optCon
, stderr
, 0);
338 status
= dcerpc_witness_RegisterEx(cli
->binding_handle
, frame
,
341 net_name
, share_name
, ip_addr
, client_name
,
344 if (!NT_STATUS_IS_OK(status
)) {
345 DEBUG(0, ("dcerpc_witness_RegisterEx failed, status: %s\n", nt_errstr(status
)));
346 result
= ntstatus_to_werror(status
);
349 if (!W_ERROR_IS_OK(result
)) {
350 DEBUG(0, ("dcerpc_witness_RegisterEx failed, error: %s\n", win_errstr(result
)));
354 d_printf("%x:%s\n", hnd
.handle_type
, GUID_string(frame
, &hnd
.uuid
));
357 poptFreeContext(optCon
);
363 read_context_handle(const char *str
, struct policy_handle
*hnd
)
370 type
= strtol(str
, &pos
, 16);
372 DEBUG(0, ("read_context_handle: failed to parse type\n"));
375 status
= GUID_from_string(pos
+1, &guid
);
376 if (!NT_STATUS_IS_OK(status
)) {
377 DEBUG(0, ("read_context_handle: failed to parse guid %s\n", nt_errstr(status
)));
381 hnd
->handle_type
= type
;
386 static WERROR
cmd_witness_UnRegister(struct rpc_pipe_client
*cli
,
387 TALLOC_CTX
*mem_ctx
, int argc
,
391 WERROR result
= WERR_OK
;
392 TALLOC_CTX
*frame
= talloc_stackframe();
393 struct policy_handle hnd
;
395 use_only_one_rpc_pipe_hack(cli
);
398 d_printf("%s <context_handle>\n", argv
[0]);
402 if (!read_context_handle(argv
[1], &hnd
)) {
403 result
= WERR_INVALID_PARAMETER
;
407 status
= dcerpc_witness_UnRegister(cli
->binding_handle
, frame
,
409 if (!NT_STATUS_IS_OK(status
)) {
410 DEBUG(0, ("dcerpc_witness_UnRegister failed, status: %s\n", nt_errstr(status
)));
411 result
= ntstatus_to_werror(status
);
414 if (!W_ERROR_IS_OK(result
)) {
415 DEBUG(0, ("dcerpc_witness_UnRegister failed, error: %s\n", win_errstr(result
)));
424 static void print_notify_response_resource_change(struct witness_ResourceChange
*r
)
426 const char *type_str
;
428 if (r
->type
== WITNESS_RESOURCE_STATE_UNKNOWN
) {
429 type_str
= "Unknown";
430 } else if (r
->type
== WITNESS_RESOURCE_STATE_AVAILABLE
) {
431 type_str
= "Available\n";
432 } else if (r
->type
== WITNESS_RESOURCE_STATE_UNAVAILABLE
) {
433 type_str
= "Unavailable";
435 type_str
= talloc_asprintf(r
, "Invalid (%u)", r
->type
);
437 d_printf("%s -> %s\n", r
->name
, type_str
);
440 static void print_notify_response_ip_addr_info_list(struct witness_IPaddrInfoList
*r
)
444 for (i
=0; i
< r
->num
; i
++) {
445 uint32_t flags
= r
->addr
[i
].flags
;
446 const char *str4
= r
->addr
[i
].ipv4
;
447 const char *str6
= r
->addr
[i
].ipv6
;
449 d_printf("Flags 0x%08x", flags
);
450 if (flags
& WITNESS_IPADDR_V4
) {
451 d_printf(" %s", str4
);
453 if (flags
& WITNESS_IPADDR_V6
) {
454 d_printf(" %s", str6
);
456 if (flags
& WITNESS_IPADDR_ONLINE
) {
459 if (flags
& WITNESS_IPADDR_ONLINE
) {
460 d_printf(" Offline");
466 static void print_notify_response(union witness_notifyResponse_message
*r
,
470 case WITNESS_NOTIFY_RESOURCE_CHANGE
:
471 print_notify_response_resource_change(&r
->resource_change
);
473 case WITNESS_NOTIFY_CLIENT_MOVE
:
474 case WITNESS_NOTIFY_SHARE_MOVE
:
475 case WITNESS_NOTIFY_IP_CHANGE
:
476 print_notify_response_ip_addr_info_list(&r
->client_move
);
483 static WERROR
cmd_witness_AsyncNotify(struct rpc_pipe_client
*cli
,
484 TALLOC_CTX
*mem_ctx
, int argc
,
488 WERROR result
= WERR_OK
;
489 TALLOC_CTX
*frame
= talloc_stackframe();
490 struct policy_handle hnd
;
491 struct witness_notifyResponse
*response
= NULL
;
495 use_only_one_rpc_pipe_hack(cli
);
498 d_printf("%s <context_handle>\n", argv
[0]);
502 if (!read_context_handle(argv
[1], &hnd
)) {
503 result
= WERR_INVALID_PARAMETER
;
507 timeout
= dcerpc_binding_handle_set_timeout(cli
->binding_handle
, UINT32_MAX
);
508 status
= dcerpc_witness_AsyncNotify(cli
->binding_handle
, frame
, hnd
,
510 dcerpc_binding_handle_set_timeout(cli
->binding_handle
, timeout
);
511 if (!NT_STATUS_IS_OK(status
)) {
512 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, status: %s\n", nt_errstr(status
)));
513 result
= ntstatus_to_werror(status
);
516 if (!W_ERROR_IS_OK(result
)) {
517 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result
)));
521 if (response
== NULL
) {
522 d_printf("Got an empty response\n");
526 switch(response
->type
) {
527 case WITNESS_NOTIFY_RESOURCE_CHANGE
:
528 d_printf("Resource change");
530 case WITNESS_NOTIFY_CLIENT_MOVE
:
531 d_printf("Client move");
533 case WITNESS_NOTIFY_SHARE_MOVE
:
534 d_printf("Share move");
536 case WITNESS_NOTIFY_IP_CHANGE
:
537 d_printf("IP change");
540 d_printf("Unknown (0x%x)", (int)response
->type
);
542 d_printf(" with %d messages\n", response
->num
);
544 for (i
=0; i
< response
->num
; i
++) {
545 print_notify_response(&response
->messages
[i
], response
->type
);
552 struct cmd_set witness_commands
[] = {
557 .name
= "GetInterfaceList",
558 .returntype
= RPC_RTYPE_WERROR
,
560 .wfn
= &cmd_witness_GetInterfaceList
,
561 .table
= &ndr_table_witness
,
568 .returntype
= RPC_RTYPE_WERROR
,
570 .wfn
= &cmd_witness_Register
,
571 .table
= &ndr_table_witness
,
577 .name
= "UnRegister",
578 .returntype
= RPC_RTYPE_WERROR
,
580 .wfn
= &cmd_witness_UnRegister
,
581 .table
= &ndr_table_witness
,
587 .name
= "AsyncNotify",
588 .returntype
= RPC_RTYPE_WERROR
,
590 .wfn
= &cmd_witness_AsyncNotify
,
591 .table
= &ndr_table_witness
,
597 .name
= "RegisterEx",
598 .returntype
= RPC_RTYPE_WERROR
,
600 .wfn
= &cmd_witness_RegisterEx
,
601 .table
= &ndr_table_witness
,
612 * We have to use the same connection for each subcommand
613 * for the context handles to be meaningful.
615 static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client
*cli
)
619 for (ptr
= &witness_commands
[0]; ptr
->name
; ptr
++) {