s3:client: Fix old-style function definition
[Samba.git] / source3 / rpcclient / cmd_witness.c
blob987c79736b60bfe058eff14442f64cb0972587cc
1 /*
2 Unix SMB/CIFS implementation.
3 RPC pipe client
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/>.
21 #include "includes.h"
22 #include "rpcclient.h"
23 #include "librpc/gen_ndr/ndr_witness_c.h"
24 #include <popt.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,
34 const char **argv)
36 NTSTATUS status;
37 WERROR result;
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);
50 goto done;
52 if (!W_ERROR_IS_OK(result)) {
53 DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, error: %s\n", win_errstr(result)));
54 goto done;
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) ? '*' : ' ';
63 char state = 'X';
65 if (interfaces[n].state == WITNESS_STATE_AVAILABLE) {
66 state = '+';
67 } else if (interfaces[n].state == WITNESS_STATE_UNAVAILABLE) {
68 state = '-';
69 } else if (interfaces[n].state == WITNESS_STATE_UNKNOWN) {
70 state = '?';
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) {
84 case WITNESS_V1:
85 d_printf(" V1");
86 break;
87 case WITNESS_V2:
88 d_printf(" V2");
89 break;
90 default:
91 d_printf(" Unsupported Version (0x%08x)", interfaces[n].version);
94 d_printf("\n");
97 done:
98 talloc_free(frame);
99 return result;
102 static WERROR cmd_witness_Register(struct rpc_pipe_client *cli,
103 TALLOC_CTX *mem_ctx, int argc,
104 const char **argv)
106 static char hostname[MAXHOSTNAMELEN] = {'\0'};
107 NTSTATUS status;
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;
115 int c;
116 poptContext optCon;
117 struct poptOption optionsTable[] = {
119 .longName = "version",
120 .shortName = 'v',
121 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
122 .arg = &version,
123 .val = WITNESS_V2,
124 .descrip = "witness version",
125 .argDescrip = "version"
128 .longName = "V1",
129 .shortName = '1',
130 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
131 .arg = &version,
132 .val = WITNESS_V1,
133 .descrip = "witness version 1",
134 .argDescrip = NULL
137 .longName = "V2",
138 .shortName = '2',
139 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
140 .arg = &version,
141 .val = WITNESS_V2,
142 .descrip = "witness version 2",
143 .argDescrip = NULL
146 .longName = "net",
147 .shortName = 'n',
148 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
149 .arg = &net_name,
150 .val = 0,
151 .descrip = "net name",
152 .argDescrip = NULL
155 .longName = "ip",
156 .shortName = 'i',
157 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
158 .arg = &ip_addr,
159 .val = 0,
160 .descrip = "ip address",
161 .argDescrip = NULL
164 .longName = "client",
165 .shortName = 'c',
166 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL,
167 .arg = &client_name,
168 .val = 0,
169 .descrip = "client name",
170 .argDescrip = NULL
172 POPT_TABLEEND
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) { }
185 if (c < -1) {
186 /* an error occurred during option processing */
187 d_fprintf(stderr, "%s: %s\n",
188 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
189 poptStrerror(c));
190 goto done;
193 if (argc < 2 || poptPeekArg(optCon) != NULL) {
194 poptPrintHelp(optCon, stderr, 0);
195 goto done;
198 status = dcerpc_witness_Register(cli->binding_handle, frame,
199 &hnd,
200 version,
201 net_name, ip_addr, client_name,
202 &result);
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);
206 goto done;
208 if (!W_ERROR_IS_OK(result)) {
209 DEBUG(0, ("dcerpc_witness_Register failed, error: %s\n", win_errstr(result)));
210 goto done;
213 d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
215 done:
216 poptFreeContext(optCon);
217 talloc_free(frame);
218 return result;
221 static WERROR cmd_witness_RegisterEx(struct rpc_pipe_client *cli,
222 TALLOC_CTX *mem_ctx, int argc,
223 const char **argv)
225 static char hostname[MAXHOSTNAMELEN] = {'\0'};
226 NTSTATUS status;
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;
235 long flags = 0;
236 long timeout = 0;
237 int c;
238 poptContext optCon;
239 struct poptOption optionsTable[] = {
241 .longName = "version",
242 .shortName = 'v',
243 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
244 .arg = &version,
245 .val = WITNESS_V2,
246 .descrip = "witness version",
247 .argDescrip = "version"
250 .longName = "V1",
251 .shortName = '1',
252 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
253 .arg = &version,
254 .val = WITNESS_V1,
255 .descrip = "witness version 1",
258 .longName = "V2",
259 .shortName = '2',
260 .argInfo = POPT_ARG_LONG|POPT_ARG_VAL,
261 .arg = &version,
262 .val = WITNESS_V2,
263 .descrip = "witness version 2",
266 .longName = "net",
267 .shortName = 'n',
268 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
269 .arg = &net_name,
270 .val = 0,
271 .descrip = "net name",
274 .longName = "ip",
275 .shortName = 'i',
276 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
277 .arg = &ip_addr,
278 .val = 0,
279 .descrip = "ip address",
282 .longName = "share",
283 .shortName = 's',
284 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
285 .arg = &share_name,
286 .val = 0,
287 .descrip = "share name",
290 .longName = "client",
291 .shortName = 'c',
292 .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL,
293 .arg = &client_name,
294 .val = 0,
295 .descrip = "client name",
298 .longName = "flags",
299 .shortName = 'f',
300 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_OR|POPT_ARGFLAG_SHOW_DEFAULT,
301 .arg = &flags,
302 .val = 0,
303 .descrip = "flags",
306 .longName = "timeout",
307 .shortName = 't',
308 .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT,
309 .arg = &timeout,
310 .val = 0,
311 .descrip = "timeout",
313 POPT_TABLEEND
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) { }
326 if (c < -1) {
327 /* an error occurred during option processing */
328 d_fprintf(stderr, "%s: %s\n",
329 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
330 poptStrerror(c));
331 goto done;
334 if (argc < 2 || poptPeekArg(optCon) != NULL) {
335 poptPrintHelp(optCon, stderr, 0);
336 goto done;
339 status = dcerpc_witness_RegisterEx(cli->binding_handle, frame,
340 &hnd,
341 version,
342 net_name, share_name, ip_addr, client_name,
343 flags, timeout,
344 &result);
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);
348 goto done;
350 if (!W_ERROR_IS_OK(result)) {
351 DEBUG(0, ("dcerpc_witness_RegisterEx failed, error: %s\n", win_errstr(result)));
352 goto done;
355 d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
357 done:
358 poptFreeContext(optCon);
359 talloc_free(frame);
360 return result;
363 static bool
364 read_context_handle(const char *str, struct policy_handle *hnd)
366 NTSTATUS status;
367 long type;
368 char *pos;
369 struct GUID guid;
371 type = strtol(str, &pos, 16);
372 if (*pos != ':') {
373 DEBUG(0, ("read_context_handle: failed to parse type\n"));
374 return false;
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)));
379 return false;
382 hnd->handle_type = type;
383 hnd->uuid = guid;
384 return true;
387 static WERROR cmd_witness_UnRegister(struct rpc_pipe_client *cli,
388 TALLOC_CTX *mem_ctx, int argc,
389 const char **argv)
391 NTSTATUS status;
392 WERROR result = WERR_OK;
393 TALLOC_CTX *frame = talloc_stackframe();
394 struct policy_handle hnd;
396 use_only_one_rpc_pipe_hack(cli);
398 if (argc != 2) {
399 d_printf("%s <context_handle>\n", argv[0]);
400 goto done;
403 if (!read_context_handle(argv[1], &hnd)) {
404 result = WERR_INVALID_PARAMETER;
405 goto done;
408 status = dcerpc_witness_UnRegister(cli->binding_handle, frame,
409 hnd, &result);
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);
413 goto done;
415 if (!W_ERROR_IS_OK(result)) {
416 DEBUG(0, ("dcerpc_witness_UnRegister failed, error: %s\n", win_errstr(result)));
417 goto done;
420 done:
421 talloc_free(frame);
422 return 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";
435 } else {
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)
443 int i;
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) {
458 d_printf(" Online");
460 if (flags & WITNESS_IPADDR_ONLINE) {
461 d_printf(" Offline");
463 d_printf("\n");
467 static void print_notify_response(union witness_notifyResponse_message *r,
468 uint32_t type)
470 switch (type) {
471 case WITNESS_NOTIFY_RESOURCE_CHANGE:
472 print_notify_response_resource_change(&r->resource_change);
473 break;
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);
478 break;
479 default:
480 break;
484 static WERROR cmd_witness_AsyncNotify(struct rpc_pipe_client *cli,
485 TALLOC_CTX *mem_ctx, int argc,
486 const char **argv)
488 NTSTATUS status;
489 WERROR result = WERR_OK;
490 TALLOC_CTX *frame = talloc_stackframe();
491 struct policy_handle hnd;
492 struct witness_notifyResponse *response = NULL;
493 uint32_t timeout;
494 int i;
496 use_only_one_rpc_pipe_hack(cli);
498 if (argc != 2) {
499 d_printf("%s <context_handle>\n", argv[0]);
500 goto done;
503 if (!read_context_handle(argv[1], &hnd)) {
504 result = WERR_INVALID_PARAMETER;
505 goto done;
508 timeout = dcerpc_binding_handle_set_timeout(cli->binding_handle, UINT32_MAX);
509 status = dcerpc_witness_AsyncNotify(cli->binding_handle, frame, hnd,
510 &response, &result);
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);
515 goto done;
517 if (!W_ERROR_IS_OK(result)) {
518 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result)));
519 goto done;
522 if (response == NULL) {
523 d_printf("Got an empty response\n");
524 goto done;
527 switch(response->type) {
528 case WITNESS_NOTIFY_RESOURCE_CHANGE:
529 d_printf("Resource change");
530 break;
531 case WITNESS_NOTIFY_CLIENT_MOVE:
532 d_printf("Client move");
533 break;
534 case WITNESS_NOTIFY_SHARE_MOVE:
535 d_printf("Share move");
536 break;
537 case WITNESS_NOTIFY_IP_CHANGE:
538 d_printf("IP change");
539 break;
540 default:
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);
548 done:
549 talloc_free(frame);
550 return result;
553 struct cmd_set witness_commands[] = {
555 .name = "WITNESS",
558 .name = "GetInterfaceList",
559 .returntype = RPC_RTYPE_WERROR,
560 .ntfn = NULL,
561 .wfn = &cmd_witness_GetInterfaceList,
562 .table = &ndr_table_witness,
563 .rpc_pipe = NULL,
564 .description = "List the interfaces to which witness client connections can be made",
565 .usage = "",
568 .name = "Register",
569 .returntype = RPC_RTYPE_WERROR,
570 .ntfn = NULL,
571 .wfn = &cmd_witness_Register,
572 .table = &ndr_table_witness,
573 .rpc_pipe = NULL,
574 .description = "Register for resource state change notifications of a NetName and IPAddress",
575 .usage = "",
578 .name = "UnRegister",
579 .returntype = RPC_RTYPE_WERROR,
580 .ntfn = NULL,
581 .wfn = &cmd_witness_UnRegister,
582 .table = &ndr_table_witness,
583 .rpc_pipe = NULL,
584 .description = "Unregister for notifications from the server</para></listitem></varlistentry>",
585 .usage = "",
588 .name = "AsyncNotify",
589 .returntype = RPC_RTYPE_WERROR,
590 .ntfn = NULL,
591 .wfn = &cmd_witness_AsyncNotify,
592 .table = &ndr_table_witness,
593 .rpc_pipe = NULL,
594 .description = "Request notification of registered resource changes from the server",
595 .usage = "",
598 .name = "RegisterEx",
599 .returntype = RPC_RTYPE_WERROR,
600 .ntfn = NULL,
601 .wfn = &cmd_witness_RegisterEx,
602 .table = &ndr_table_witness,
603 .rpc_pipe = NULL,
604 .description = "Register for resource state change notifications of a NetName, ShareName and multiple IPAddresses",
605 .usage = "",
608 .name = NULL,
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)
618 struct cmd_set *ptr;
620 for (ptr = &witness_commands[0]; ptr->name; ptr++) {
621 ptr->rpc_pipe = cli;