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_PARAM
;
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
)));
313 RESOURCE_STATE_UNKNOWN
= 0x00,
314 RESOURCE_STATE_AVAILABLE
= 0x01,
315 RESOURCE_STATE_UNAVAILABLE
= 0xff
318 static bool AsyncNotify_Change(TALLOC_CTX
*mem_ctx
, const uint8_t **ptr
)
320 const uint8_t *pos
= *ptr
;
321 uint32_t length
= IVAL(pos
,0);
322 uint32_t type
= IVAL(pos
,4);
324 const char *type_str
;
326 ok
= convert_string_talloc(mem_ctx
, CH_UTF16LE
, CH_UNIX
, pos
+ 8,
327 length
- 8, &name
, NULL
);
332 if (type
== RESOURCE_STATE_UNKNOWN
) {
333 type_str
= "Unknown";
334 } else if(type
== RESOURCE_STATE_AVAILABLE
) {
335 type_str
= "Available\n";
336 } else if(type
== RESOURCE_STATE_UNAVAILABLE
) {
337 type_str
= "Unavailable";
339 type_str
= talloc_asprintf(name
, "Invalid (%u)", type
);
341 d_printf("%s -> %s\n", name
, type_str
);
351 IPADDR_ONLINE
= 0x08,
352 IPADDR_OFFLINE
= 0x10,
355 /* IPADDR_INFO_LIST */
356 static bool AsyncNotify_Move(TALLOC_CTX
*mem_ctx
, const uint8_t **ptr
)
358 const uint8_t *pos
= *ptr
;
359 uint32_t length
= IVAL(pos
,0);
360 /* uint32_t reserved = IVAL(pos,4); */
361 uint32_t num
= IVAL(pos
,8);
366 for (n
=0; n
<num
; n
++) {
367 uint32_t flags
= IVAL(pos
,0);
369 struct sockaddr_storage sas4
;
373 ipv4
.s_addr
= *((const in_addr_t
*)pos
);
374 in_addr_to_sockaddr_storage(&sas4
, ipv4
);
375 str4
= print_canonical_sockaddr(mem_ctx
, &sas4
);
380 struct in6_addr ipv6
;
381 struct sockaddr_storage sas6
;
383 memcpy(&ipv6
.s6_addr
, pos
, 16);
384 in6_addr_to_sockaddr_storage(&sas6
, ipv6
);
385 str6
= print_canonical_sockaddr(mem_ctx
, &sas6
);
387 DATA_BLOB ipv6
= data_blob(pos
, 16);
388 str6
= data_blob_hex_string_upper(mem_ctx
, &ipv6
);
393 d_printf("Flags 0x%08x", flags
);
394 if (flags
& IPADDR_V4
) {
395 d_printf(" %s", str4
);
397 if (flags
& IPADDR_V6
) {
398 d_printf(" %s", str6
);
400 if (flags
& IPADDR_ONLINE
) {
403 if (flags
& IPADDR_ONLINE
) {
404 d_printf(" Offline");
411 if (pos
- *ptr
== length
) {
418 static WERROR
cmd_witness_AsyncNotify(struct rpc_pipe_client
*cli
,
419 TALLOC_CTX
*mem_ctx
, int argc
,
423 WERROR result
= WERR_OK
;
424 TALLOC_CTX
*frame
= talloc_stackframe();
425 struct policy_handle hnd
;
426 struct witness_notifyResponse
*response
= NULL
;
428 bool (*read_response
)(TALLOC_CTX
*, const uint8_t**) = NULL
;
430 use_only_one_rpc_pipe_hack(cli
);
433 d_printf("%s <context_handle>\n", argv
[0]);
437 if (!read_context_handle(argv
[1], &hnd
)) {
438 result
= WERR_INVALID_PARAM
;
442 timeout
= dcerpc_binding_handle_set_timeout(cli
->binding_handle
, UINT32_MAX
);
443 status
= dcerpc_witness_AsyncNotify(cli
->binding_handle
, frame
, hnd
,
445 dcerpc_binding_handle_set_timeout(cli
->binding_handle
, timeout
);
446 if (!NT_STATUS_IS_OK(status
)) {
447 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, status: %s\n", nt_errstr(status
)));
448 result
= ntstatus_to_werror(status
);
451 if (!W_ERROR_IS_OK(result
)) {
452 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result
)));
456 switch(response
->message_type
) {
457 case WITNESS_NOTIFY_RESOURCE_CHANGE
:
458 d_printf("Resource change");
459 read_response
= AsyncNotify_Change
;
461 case WITNESS_NOTIFY_CLIENT_MOVE
:
462 d_printf("Client move");
463 read_response
= AsyncNotify_Move
;
465 case WITNESS_NOTIFY_SHARE_MOVE
:
466 d_printf("Share move");
467 read_response
= AsyncNotify_Move
;
469 case WITNESS_NOTIFY_IP_CHANGE
:
470 d_printf("IP change");
471 read_response
= AsyncNotify_Move
;
474 d_printf("Unknown (0x%x)", (int)response
->message_type
);
476 d_printf(" with %d messages\n", response
->num_messages
);
480 const uint8_t *pos
= response
->message_buffer
;
482 for (n
=0; n
<response
->num_messages
; n
++) {
483 read_response(frame
, &pos
);
492 struct cmd_set witness_commands
[] = {
494 {"GetInterfaceList", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_GetInterfaceList
, &ndr_table_witness
, NULL
, "", ""},
495 {"Register", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_Register
, &ndr_table_witness
, NULL
, "", ""},
496 {"UnRegister", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_UnRegister
, &ndr_table_witness
, NULL
, "", ""},
497 {"AsyncNotify", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_AsyncNotify
, &ndr_table_witness
, NULL
, "", ""},
498 {"RegisterEx", RPC_RTYPE_WERROR
, NULL
, &cmd_witness_RegisterEx
, &ndr_table_witness
, NULL
, "", ""},
503 * We have to use the same connection for each subcommand
504 * for the context handles to be meaningful.
506 static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client
*cli
)
510 for (ptr
= &witness_commands
[0]; ptr
->name
; ptr
++) {