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
[] = {
118 {"version", 'v', POPT_ARG_LONG
|POPT_ARGFLAG_SHOW_DEFAULT
, &version
, WITNESS_V2
, "witness version", "version"},
119 {"V1", '1', POPT_ARG_LONG
|POPT_ARG_VAL
, &version
, WITNESS_V1
, "witness version 1", NULL
},
120 {"V2", '2', POPT_ARG_LONG
|POPT_ARG_VAL
, &version
, WITNESS_V2
, "witness version 2", NULL
},
121 {"net", 'n', POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
, &net_name
, 0, "net name", NULL
},
122 {"ip", 'i', POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
, &ip_addr
, 0, "ip address", NULL
},
123 {"client", 'c', POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
|POPT_ARGFLAG_OPTIONAL
, &client_name
, 0, "client name", NULL
},
124 { NULL
, 0, 0, NULL
, 0 }
127 use_only_one_rpc_pipe_hack(cli
);
129 if (hostname
[0] == '\0') {
130 gethostname (hostname
, sizeof(hostname
));
133 optCon
= poptGetContext(NULL
, argc
, argv
, optionsTable
, 0);
135 while ((c
= poptGetNextOpt(optCon
)) >= 0) { }
138 /* an error occurred during option processing */
139 d_fprintf(stderr
, "%s: %s\n",
140 poptBadOption(optCon
, POPT_BADOPTION_NOALIAS
),
145 if (argc
< 2 || poptPeekArg(optCon
) != NULL
) {
146 poptPrintHelp(optCon
, stderr
, 0);
150 status
= dcerpc_witness_Register(cli
->binding_handle
, frame
,
153 net_name
, ip_addr
, client_name
,
155 if (!NT_STATUS_IS_OK(status
)) {
156 DEBUG(0, ("dcerpc_witness_Register failed, status: %s\n", nt_errstr(status
)));
157 result
= ntstatus_to_werror(status
);
160 if (!W_ERROR_IS_OK(result
)) {
161 DEBUG(0, ("dcerpc_witness_Register failed, error: %s\n", win_errstr(result
)));
165 d_printf("%x:%s\n", hnd
.handle_type
, GUID_string(frame
, &hnd
.uuid
));
172 static WERROR
cmd_witness_RegisterEx(struct rpc_pipe_client
*cli
,
173 TALLOC_CTX
*mem_ctx
, int argc
,
176 static char hostname
[MAXHOSTNAMELEN
] = {'\0'};
178 WERROR result
= WERR_OK
;
179 TALLOC_CTX
*frame
= talloc_stackframe();
180 struct policy_handle hnd
;
181 const char *net_name
= NULL
;
182 const char *ip_addr
= NULL
;
183 const char *share_name
= NULL
;
184 const char *client_name
= hostname
;
185 long version
= WITNESS_V2
;
190 struct poptOption optionsTable
[] = {
191 {"version", 'v', POPT_ARG_LONG
|POPT_ARGFLAG_SHOW_DEFAULT
, &version
, WITNESS_V2
, "witness version", "version"},
192 {"V1", '1', POPT_ARG_LONG
|POPT_ARG_VAL
, &version
, WITNESS_V1
, "witness version 1", NULL
},
193 {"V2", '2', POPT_ARG_LONG
|POPT_ARG_VAL
, &version
, WITNESS_V2
, "witness version 2", NULL
},
194 {"net", 'n', POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
, &net_name
, 0, "net name", NULL
},
195 {"ip", 'i', POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
, &ip_addr
, 0, "ip address", NULL
},
196 {"share", 's', POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
, &share_name
, 0, "share name", NULL
},
197 {"client", 'c', POPT_ARG_STRING
|POPT_ARGFLAG_SHOW_DEFAULT
|POPT_ARGFLAG_OPTIONAL
, &client_name
, 0, "client name", NULL
},
198 {"flags", 'f', POPT_ARG_LONG
|POPT_ARGFLAG_OR
|POPT_ARGFLAG_SHOW_DEFAULT
, &flags
, 0, "flags", NULL
},
199 {"timeout", 't', POPT_ARG_LONG
|POPT_ARGFLAG_SHOW_DEFAULT
, &timeout
, 0, "timeout", NULL
},
200 { NULL
, 0, 0, NULL
, 0 }
203 use_only_one_rpc_pipe_hack(cli
);
205 if (hostname
[0] == '\0') {
206 gethostname (hostname
, sizeof(hostname
));
209 optCon
= poptGetContext(NULL
, argc
, argv
, optionsTable
, 0);
211 while ((c
= poptGetNextOpt(optCon
)) >= 0) { }
214 /* an error occurred during option processing */
215 d_fprintf(stderr
, "%s: %s\n",
216 poptBadOption(optCon
, POPT_BADOPTION_NOALIAS
),
221 if (argc
< 2 || poptPeekArg(optCon
) != NULL
) {
222 poptPrintHelp(optCon
, stderr
, 0);
226 status
= dcerpc_witness_RegisterEx(cli
->binding_handle
, frame
,
229 net_name
, share_name
, ip_addr
, client_name
,
232 if (!NT_STATUS_IS_OK(status
)) {
233 DEBUG(0, ("dcerpc_witness_RegisterEx failed, status: %s\n", nt_errstr(status
)));
234 result
= ntstatus_to_werror(status
);
237 if (!W_ERROR_IS_OK(result
)) {
238 DEBUG(0, ("dcerpc_witness_RegisterEx failed, error: %s\n", win_errstr(result
)));
242 d_printf("%x:%s\n", hnd
.handle_type
, GUID_string(frame
, &hnd
.uuid
));
245 poptFreeContext(optCon
);
251 read_context_handle(const char *str
, struct policy_handle
*hnd
)
258 type
= strtol(str
, &pos
, 16);
260 DEBUG(0, ("read_context_handle: failed to parse type\n"));
263 status
= GUID_from_string(pos
+1, &guid
);
264 if (!NT_STATUS_IS_OK(status
)) {
265 DEBUG(0, ("read_context_handle: failed to parse guid %s\n", nt_errstr(status
)));
269 hnd
->handle_type
= type
;
274 static WERROR
cmd_witness_UnRegister(struct rpc_pipe_client
*cli
,
275 TALLOC_CTX
*mem_ctx
, int argc
,
279 WERROR result
= WERR_OK
;
280 TALLOC_CTX
*frame
= talloc_stackframe();
281 struct policy_handle hnd
;
283 use_only_one_rpc_pipe_hack(cli
);
286 d_printf("%s <context_handle>\n", argv
[0]);
290 if (!read_context_handle(argv
[1], &hnd
)) {
291 result
= WERR_INVALID_PARAMETER
;
295 status
= dcerpc_witness_UnRegister(cli
->binding_handle
, frame
,
297 if (!NT_STATUS_IS_OK(status
)) {
298 DEBUG(0, ("dcerpc_witness_UnRegister failed, status: %s\n", nt_errstr(status
)));
299 result
= ntstatus_to_werror(status
);
302 if (!W_ERROR_IS_OK(result
)) {
303 DEBUG(0, ("dcerpc_witness_UnRegister failed, error: %s\n", win_errstr(result
)));
312 static void print_notify_response_resource_change(struct witness_ResourceChange
*r
)
314 const char *type_str
;
316 if (r
->type
== WITNESS_RESOURCE_STATE_UNKNOWN
) {
317 type_str
= "Unknown";
318 } else if (r
->type
== WITNESS_RESOURCE_STATE_AVAILABLE
) {
319 type_str
= "Available\n";
320 } else if (r
->type
== WITNESS_RESOURCE_STATE_UNAVAILABLE
) {
321 type_str
= "Unavailable";
323 type_str
= talloc_asprintf(r
, "Invalid (%u)", r
->type
);
325 d_printf("%s -> %s\n", r
->name
, type_str
);
328 static void print_notify_response_ip_addr_info_list(struct witness_IPaddrInfoList
*r
)
332 for (i
=0; i
< r
->num
; i
++) {
333 uint32_t flags
= r
->addr
[i
].flags
;
334 const char *str4
= r
->addr
[i
].ipv4
;
335 const char *str6
= r
->addr
[i
].ipv6
;
337 d_printf("Flags 0x%08x", flags
);
338 if (flags
& WITNESS_IPADDR_V4
) {
339 d_printf(" %s", str4
);
341 if (flags
& WITNESS_IPADDR_V6
) {
342 d_printf(" %s", str6
);
344 if (flags
& WITNESS_IPADDR_ONLINE
) {
347 if (flags
& WITNESS_IPADDR_ONLINE
) {
348 d_printf(" Offline");
354 static void print_notify_response(union witness_notifyResponse_message
*r
,
358 case WITNESS_NOTIFY_RESOURCE_CHANGE
:
359 print_notify_response_resource_change(&r
->resource_change
);
361 case WITNESS_NOTIFY_CLIENT_MOVE
:
362 case WITNESS_NOTIFY_SHARE_MOVE
:
363 case WITNESS_NOTIFY_IP_CHANGE
:
364 print_notify_response_ip_addr_info_list(&r
->client_move
);
371 static WERROR
cmd_witness_AsyncNotify(struct rpc_pipe_client
*cli
,
372 TALLOC_CTX
*mem_ctx
, int argc
,
376 WERROR result
= WERR_OK
;
377 TALLOC_CTX
*frame
= talloc_stackframe();
378 struct policy_handle hnd
;
379 struct witness_notifyResponse
*response
= NULL
;
383 use_only_one_rpc_pipe_hack(cli
);
386 d_printf("%s <context_handle>\n", argv
[0]);
390 if (!read_context_handle(argv
[1], &hnd
)) {
391 result
= WERR_INVALID_PARAMETER
;
395 timeout
= dcerpc_binding_handle_set_timeout(cli
->binding_handle
, UINT32_MAX
);
396 status
= dcerpc_witness_AsyncNotify(cli
->binding_handle
, frame
, hnd
,
398 dcerpc_binding_handle_set_timeout(cli
->binding_handle
, timeout
);
399 if (!NT_STATUS_IS_OK(status
)) {
400 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, status: %s\n", nt_errstr(status
)));
401 result
= ntstatus_to_werror(status
);
404 if (!W_ERROR_IS_OK(result
)) {
405 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result
)));
409 if (response
== NULL
) {
410 d_printf("Got an empty response\n");
414 switch(response
->type
) {
415 case WITNESS_NOTIFY_RESOURCE_CHANGE
:
416 d_printf("Resource change");
418 case WITNESS_NOTIFY_CLIENT_MOVE
:
419 d_printf("Client move");
421 case WITNESS_NOTIFY_SHARE_MOVE
:
422 d_printf("Share move");
424 case WITNESS_NOTIFY_IP_CHANGE
:
425 d_printf("IP change");
428 d_printf("Unknown (0x%x)", (int)response
->type
);
430 d_printf(" with %d messages\n", response
->num
);
432 for (i
=0; i
< response
->num
; i
++) {
433 print_notify_response(&response
->messages
[i
], response
->type
);
440 struct cmd_set witness_commands
[] = {
442 {"GetInterfaceList", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_GetInterfaceList
, &ndr_table_witness
, NULL
, "", ""},
443 {"Register", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_Register
, &ndr_table_witness
, NULL
, "", ""},
444 {"UnRegister", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_UnRegister
, &ndr_table_witness
, NULL
, "", ""},
445 {"AsyncNotify", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_AsyncNotify
, &ndr_table_witness
, NULL
, "", ""},
446 {"RegisterEx", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_RegisterEx
, &ndr_table_witness
, NULL
, "", ""},
451 * We have to use the same connection for each subcommand
452 * for the context handles to be meaningful.
454 static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client
*cli
)
458 for (ptr
= &witness_commands
[0]; ptr
->name
; ptr
++) {