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
,
564 .description
= "List the interfaces to which witness client connections can be made",
569 .returntype
= RPC_RTYPE_WERROR
,
571 .wfn
= &cmd_witness_Register
,
572 .table
= &ndr_table_witness
,
574 .description
= "Register for resource state change notifications of a NetName and IPAddress",
578 .name
= "UnRegister",
579 .returntype
= RPC_RTYPE_WERROR
,
581 .wfn
= &cmd_witness_UnRegister
,
582 .table
= &ndr_table_witness
,
584 .description
= "Unregister for notifications from the server</para></listitem></varlistentry>",
588 .name
= "AsyncNotify",
589 .returntype
= RPC_RTYPE_WERROR
,
591 .wfn
= &cmd_witness_AsyncNotify
,
592 .table
= &ndr_table_witness
,
594 .description
= "Request notification of registered resource changes from the server",
598 .name
= "RegisterEx",
599 .returntype
= RPC_RTYPE_WERROR
,
601 .wfn
= &cmd_witness_RegisterEx
,
602 .table
= &ndr_table_witness
,
604 .description
= "Register for resource state change notifications of a NetName, ShareName and multiple IPAddresses",
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
++) {