source4 smbd process: pass the fatal flag to terminate
[bbaumbach/samba-autobuild/.git] / source3 / rpcclient / cmd_witness.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gregor Beck 2013-2014
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22 #include "rpcclient.h"
23 #include "librpc/gen_ndr/ndr_witness_c.h"
24 #include <popt.h>
25
26 /*
27  * We have to use the same connection for each subcommand
28  * for the context handles to be meaningful.
29  */
30 static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli);
31
32 static WERROR cmd_witness_GetInterfaceList(struct rpc_pipe_client *cli,
33                                            TALLOC_CTX *mem_ctx, int argc,
34                                            const char **argv)
35 {
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;
42
43         use_only_one_rpc_pipe_hack(cli);
44
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;
51         }
52         if (!W_ERROR_IS_OK(result)) {
53                 DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, error: %s\n", win_errstr(result)));
54                 goto done;
55         }
56
57         SMB_ASSERT(interface_list);
58         interfaces = interface_list->interfaces;
59         num_interfaces = interface_list->num_interfaces;
60
61         for (n=0; n < num_interfaces; n++) {
62                 char wif = (interfaces[n].flags & WITNESS_INFO_WITNESS_IF) ? '*' : ' ';
63                 char state = 'X';
64
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 = '?';
71                 }
72
73                 d_printf("%c%c %s", wif, state, interfaces[n].group_name);
74
75                 if (interfaces[n].flags & WITNESS_INFO_IPv4_VALID) {
76                         d_printf(" %s", interfaces[n].ipv4);
77                 }
78
79                 if (interfaces[n].flags & WITNESS_INFO_IPv6_VALID) {
80                         d_printf(" %s", interfaces[n].ipv6);
81                 }
82
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(" Unsuported Version (0x%08x)", interfaces[n].version);
92                 }
93
94                 d_printf("\n");
95         }
96
97 done:
98         talloc_free(frame);
99         return result;
100 }
101
102 static WERROR cmd_witness_Register(struct rpc_pipe_client *cli,
103                                    TALLOC_CTX *mem_ctx, int argc,
104                                    const char **argv)
105 {
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[] = {
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 }
125         };
126
127         use_only_one_rpc_pipe_hack(cli);
128
129         if (hostname[0] == '\0') {
130                 gethostname (hostname, sizeof(hostname));
131         }
132
133         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
134
135         while ((c = poptGetNextOpt(optCon)) >= 0) { }
136
137         if (c < -1) {
138              /* an error occurred during option processing */
139                 d_fprintf(stderr, "%s: %s\n",
140                           poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
141                           poptStrerror(c));
142              goto done;
143         }
144
145         if (argc < 2 || poptPeekArg(optCon) != NULL) {
146                 poptPrintHelp(optCon, stderr, 0);
147                 goto done;
148         }
149
150         status = dcerpc_witness_Register(cli->binding_handle, frame,
151                                          &hnd,
152                                          version,
153                                          net_name, ip_addr, client_name,
154                                          &result);
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);
158                 goto done;
159         }
160         if (!W_ERROR_IS_OK(result)) {
161                 DEBUG(0, ("dcerpc_witness_Register failed, error: %s\n", win_errstr(result)));
162                 goto done;
163         }
164
165         d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
166
167 done:
168         talloc_free(frame);
169         return result;
170 }
171
172 static WERROR cmd_witness_RegisterEx(struct rpc_pipe_client *cli,
173                                      TALLOC_CTX *mem_ctx, int argc,
174                                      const char **argv)
175 {
176         static char hostname[MAXHOSTNAMELEN] = {'\0'};
177         NTSTATUS status;
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;
186         long flags = 0;
187         long timeout = 0;
188         int c;
189         poptContext optCon;
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 }
201         };
202
203         use_only_one_rpc_pipe_hack(cli);
204
205         if (hostname[0] == '\0') {
206                 gethostname (hostname, sizeof(hostname));
207         }
208
209         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
210
211         while ((c = poptGetNextOpt(optCon)) >= 0) { }
212
213         if (c < -1) {
214              /* an error occurred during option processing */
215                 d_fprintf(stderr, "%s: %s\n",
216                           poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
217                           poptStrerror(c));
218              goto done;
219         }
220
221         if (argc < 2 || poptPeekArg(optCon) != NULL) {
222                 poptPrintHelp(optCon, stderr, 0);
223                 goto done;
224         }
225
226         status = dcerpc_witness_RegisterEx(cli->binding_handle, frame,
227                                            &hnd,
228                                            version,
229                                            net_name, share_name, ip_addr, client_name,
230                                            flags, timeout,
231                                            &result);
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);
235                 goto done;
236         }
237         if (!W_ERROR_IS_OK(result)) {
238                 DEBUG(0, ("dcerpc_witness_RegisterEx failed, error: %s\n", win_errstr(result)));
239                 goto done;
240         }
241
242         d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid));
243
244 done:
245         poptFreeContext(optCon);
246         talloc_free(frame);
247         return result;
248 }
249
250 static bool
251 read_context_handle(const char *str, struct policy_handle *hnd)
252 {
253         NTSTATUS status;
254         long type;
255         char *pos;
256         struct GUID guid;
257
258         type = strtol(str, &pos, 16);
259         if (*pos != ':') {
260                 DEBUG(0, ("read_context_handle: failed to parse type\n"));
261                 return false;
262         }
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)));
266                 return false;
267         }
268
269         hnd->handle_type = type;
270         hnd->uuid = guid;
271         return true;
272 }
273
274 static WERROR cmd_witness_UnRegister(struct rpc_pipe_client *cli,
275                                      TALLOC_CTX *mem_ctx, int argc,
276                                      const char **argv)
277 {
278         NTSTATUS status;
279         WERROR result = WERR_OK;
280         TALLOC_CTX *frame = talloc_stackframe();
281         struct policy_handle hnd;
282
283         use_only_one_rpc_pipe_hack(cli);
284
285         if (argc != 2) {
286                 d_printf("%s <context_handle>\n", argv[0]);
287                 goto done;
288         }
289
290         if (!read_context_handle(argv[1], &hnd)) {
291                 result = WERR_INVALID_PARAMETER;
292                 goto done;
293         }
294
295         status = dcerpc_witness_UnRegister(cli->binding_handle, frame,
296                                            hnd, &result);
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);
300                 goto done;
301         }
302         if (!W_ERROR_IS_OK(result)) {
303                 DEBUG(0, ("dcerpc_witness_UnRegister failed, error: %s\n", win_errstr(result)));
304                 goto done;
305         }
306
307 done:
308         talloc_free(frame);
309         return result;
310 }
311
312 static void print_notify_response_resource_change(struct witness_ResourceChange *r)
313 {
314         const char *type_str;
315
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";
322         } else {
323                 type_str = talloc_asprintf(r, "Invalid (%u)", r->type);
324         }
325         d_printf("%s -> %s\n", r->name, type_str);
326 }
327
328 static void print_notify_response_ip_addr_info_list(struct witness_IPaddrInfoList *r)
329 {
330         int i;
331
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;
336
337                 d_printf("Flags 0x%08x", flags);
338                 if (flags & WITNESS_IPADDR_V4) {
339                         d_printf(" %s", str4);
340                 }
341                 if (flags & WITNESS_IPADDR_V6) {
342                         d_printf(" %s", str6);
343                 }
344                 if (flags & WITNESS_IPADDR_ONLINE) {
345                         d_printf(" Online");
346                 }
347                 if (flags & WITNESS_IPADDR_ONLINE) {
348                         d_printf(" Offline");
349                 }
350                 d_printf("\n");
351         }
352 }
353
354 static void print_notify_response(union witness_notifyResponse_message *r,
355                                   uint32_t type)
356 {
357         switch (type) {
358         case WITNESS_NOTIFY_RESOURCE_CHANGE:
359                 print_notify_response_resource_change(&r->resource_change);
360                 break;
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);
365                 break;
366         default:
367                 break;
368         }
369 }
370
371 static WERROR cmd_witness_AsyncNotify(struct rpc_pipe_client *cli,
372                                       TALLOC_CTX *mem_ctx, int argc,
373                                       const char **argv)
374 {
375         NTSTATUS status;
376         WERROR result = WERR_OK;
377         TALLOC_CTX *frame = talloc_stackframe();
378         struct policy_handle hnd;
379         struct witness_notifyResponse *response = NULL;
380         uint32_t timeout;
381         int i;
382
383         use_only_one_rpc_pipe_hack(cli);
384
385         if (argc != 2) {
386                 d_printf("%s <context_handle>\n", argv[0]);
387                 goto done;
388         }
389
390         if (!read_context_handle(argv[1], &hnd)) {
391                 result = WERR_INVALID_PARAMETER;
392                 goto done;
393         }
394
395         timeout = dcerpc_binding_handle_set_timeout(cli->binding_handle, UINT32_MAX);
396         status = dcerpc_witness_AsyncNotify(cli->binding_handle, frame, hnd,
397                                             &response, &result);
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);
402                 goto done;
403         }
404         if (!W_ERROR_IS_OK(result)) {
405                 DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result)));
406                 goto done;
407         }
408
409         if (response == NULL) {
410                 d_printf("Got an empty response\n");
411                 goto done;
412         }
413
414         switch(response->type) {
415         case WITNESS_NOTIFY_RESOURCE_CHANGE:
416                 d_printf("Resource change");
417                 break;
418         case WITNESS_NOTIFY_CLIENT_MOVE:
419                 d_printf("Client move");
420                 break;
421         case WITNESS_NOTIFY_SHARE_MOVE:
422                 d_printf("Share move");
423                 break;
424         case WITNESS_NOTIFY_IP_CHANGE:
425                 d_printf("IP change");
426                 break;
427         default:
428                 d_printf("Unknown (0x%x)", (int)response->type);
429         }
430         d_printf(" with %d messages\n", response->num);
431
432         for (i=0; i < response->num; i++) {
433                 print_notify_response(&response->messages[i], response->type);
434         }
435 done:
436         talloc_free(frame);
437         return result;
438 }
439
440 struct cmd_set witness_commands[] = {
441         {"WITNESS"},
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, "", ""},
447         {NULL}
448 };
449
450 /*
451  * We have to use the same connection for each subcommand
452  * for the context handles to be meaningful.
453  */
454 static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli)
455 {
456         struct cmd_set *ptr;
457
458         for (ptr = &witness_commands[0]; ptr->name; ptr++) {
459                 ptr->rpc_pipe = cli;
460         }
461 }