Line data Source code
1 : /*
2 : * Samba Unix/Linux client library
3 : * net witness commands to manage smb witness registrations
4 : * Copyright (C) 2023 Stefan Metzmacher
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "utils/net.h"
22 : #include "messages.h"
23 : #include "serverid.h"
24 : #include "lib/util/util_tdb.h"
25 : #include "source3/include/util_tdb.h"
26 : #include "libcli/security/dom_sid.h"
27 : #include "lib/dbwrap/dbwrap.h"
28 : #include "lib/dbwrap/dbwrap_rbt.h"
29 : #include "lib/dbwrap/dbwrap_open.h"
30 : #include "lib/param/param.h"
31 : #include "librpc/gen_ndr/ndr_rpcd_witness.h"
32 : #include <regex.h>
33 :
34 : struct json_object;
35 :
36 : #ifdef HAVE_JANSSON
37 : #include <jansson.h>
38 : #include "audit_logging.h" /* various JSON helpers */
39 : #endif /* HAVE_JANSSON */
40 :
41 : #undef strcasecmp
42 :
43 0 : static struct db_context *net_witness_open_registration_db(void)
44 : {
45 0 : static struct db_context *db;
46 0 : char *global_path = NULL;
47 :
48 0 : if (db != NULL) {
49 0 : return db;
50 : }
51 :
52 0 : global_path = lock_path(talloc_tos(), "rpcd_witness_registration.tdb");
53 0 : if (global_path == NULL) {
54 0 : return NULL;
55 : }
56 :
57 0 : db = db_open(NULL,
58 : global_path,
59 : 0, /* hash_size */
60 : TDB_DEFAULT |
61 : TDB_CLEAR_IF_FIRST |
62 : TDB_INCOMPATIBLE_HASH,
63 : O_RDONLY,
64 : 0600,
65 : DBWRAP_LOCK_ORDER_1,
66 : DBWRAP_FLAG_NONE);
67 0 : TALLOC_FREE(global_path);
68 0 : if (db == NULL) {
69 0 : return NULL;
70 : }
71 :
72 0 : return db;
73 : }
74 :
75 : struct net_witness_scan_registrations_action_state {
76 : bool (*prepare_fn)(void *private_data);
77 : bool (*match_fn)(void *private_data, const struct rpcd_witness_registration *rg);
78 : NTSTATUS (*process_fn)(void *private_data, const struct rpcd_witness_registration *rg);
79 : void *private_data;
80 : };
81 :
82 : struct net_witness_scan_registrations_regex {
83 : regex_t regex;
84 : bool valid;
85 : };
86 :
87 : struct net_witness_scan_registrations_state {
88 : struct net_context *c;
89 : struct net_witness_scan_registrations_regex net_name;
90 : struct net_witness_scan_registrations_regex share_name;
91 : struct net_witness_scan_registrations_regex ip_address;
92 : struct net_witness_scan_registrations_regex client_computer;
93 : struct json_object *message_json;
94 : #ifdef HAVE_JANSSON
95 : struct json_object filters_json;
96 : struct json_object registrations_json;
97 : #endif
98 : const struct net_witness_scan_registrations_action_state *action;
99 : NTSTATUS error;
100 : };
101 :
102 : static bool net_witness_scan_registrations_regex_init(
103 : struct net_witness_scan_registrations_state *state,
104 : struct net_witness_scan_registrations_regex *r,
105 : const char *option, const char *value);
106 : static bool net_witness_scan_registrations_regex_match(
107 : struct net_witness_scan_registrations_regex *r,
108 : const char *name, const char *value);
109 : static void net_witness_scan_registrations_regex_free(
110 : struct net_witness_scan_registrations_regex *r);
111 :
112 0 : static bool net_witness_scan_registrations_match(
113 : struct net_witness_scan_registrations_state *state,
114 : const struct rpcd_witness_registration *rg)
115 : {
116 0 : if (state->net_name.valid) {
117 0 : bool match;
118 :
119 0 : match = net_witness_scan_registrations_regex_match(
120 : &state->net_name,
121 : "net_name",
122 0 : rg->net_name);
123 0 : if (!match) {
124 0 : return false;
125 : }
126 : }
127 :
128 0 : if (state->share_name.valid) {
129 0 : bool match;
130 :
131 0 : match = net_witness_scan_registrations_regex_match(
132 : &state->share_name,
133 : "share_name",
134 0 : rg->share_name);
135 0 : if (!match) {
136 0 : return false;
137 : }
138 : }
139 :
140 0 : if (state->ip_address.valid) {
141 0 : bool match;
142 :
143 0 : match = net_witness_scan_registrations_regex_match(
144 : &state->ip_address,
145 : "ip_address",
146 0 : rg->ip_address);
147 0 : if (!match) {
148 0 : return false;
149 : }
150 : }
151 :
152 0 : if (state->client_computer.valid) {
153 0 : bool match;
154 :
155 0 : match = net_witness_scan_registrations_regex_match(
156 : &state->client_computer,
157 : "client_computer_name",
158 0 : rg->client_computer_name);
159 0 : if (!match) {
160 0 : return false;
161 : }
162 : }
163 :
164 0 : return true;
165 : }
166 :
167 0 : static bool net_witness_scan_registrations_regex_init(
168 : struct net_witness_scan_registrations_state *state,
169 : struct net_witness_scan_registrations_regex *r,
170 : const char *option, const char *value)
171 : {
172 : #ifdef HAVE_JANSSON
173 0 : struct net_context *c = state->c;
174 : #endif /* HAVE_JANSSON */
175 0 : int ret;
176 :
177 0 : r->valid = false;
178 :
179 0 : if (value == NULL) {
180 0 : return true;
181 : }
182 :
183 0 : ret = regcomp(&r->regex, value, REG_EXTENDED|REG_ICASE|REG_NOSUB);
184 0 : if (ret != 0) {
185 0 : fstring buf = { 0,};
186 0 : regerror(ret, &r->regex, buf, sizeof(buf));
187 0 : d_printf("regcomp(%s) failed for %s: "
188 : "%d: %s\n", value, option, ret, buf);
189 0 : return false;
190 : }
191 :
192 : #ifdef HAVE_JANSSON
193 0 : if (c->opt_json) {
194 0 : ret = json_add_string(&state->filters_json,
195 : option,
196 : value);
197 0 : if (ret != 0) {
198 0 : return false;
199 : }
200 : }
201 : #endif /* HAVE_JANSSON */
202 :
203 0 : r->valid = true;
204 0 : return true;
205 : }
206 :
207 0 : static bool net_witness_scan_registrations_regex_match(
208 : struct net_witness_scan_registrations_regex *r,
209 : const char *name, const char *value)
210 : {
211 0 : int ret;
212 :
213 0 : if (!r->valid) {
214 0 : return false;
215 : }
216 :
217 0 : if (value == NULL) {
218 : /*
219 : * without a share name,
220 : * we match against an empty
221 : * string.
222 : */
223 0 : value = "";
224 : }
225 :
226 0 : ret = regexec(&r->regex, value, 0, NULL, 0);
227 0 : if (ret == REG_NOMATCH) {
228 0 : return false;
229 : }
230 :
231 0 : return true;
232 : }
233 :
234 0 : static void net_witness_scan_registrations_regex_free(
235 : struct net_witness_scan_registrations_regex *r)
236 : {
237 0 : if (r->valid) {
238 0 : regfree(&r->regex);
239 0 : r->valid = false;
240 : }
241 0 : }
242 :
243 0 : static bool net_witness_scan_registrations_init(
244 : struct net_witness_scan_registrations_state *state)
245 : {
246 0 : struct net_context *c = state->c;
247 0 : bool ok;
248 :
249 0 : if (c->opt_json) {
250 : #ifdef HAVE_JANSSON
251 0 : state->filters_json = json_new_object();
252 0 : if (json_is_invalid(&state->filters_json)) {
253 0 : return false;
254 : }
255 :
256 0 : if (c->opt_witness_registration != NULL) {
257 0 : int ret;
258 :
259 0 : ret = json_add_string(&state->filters_json,
260 : "--witness-registration",
261 : c->opt_witness_registration);
262 0 : if (ret != 0) {
263 0 : return false;
264 : }
265 : }
266 :
267 0 : if (c->opt_witness_apply_to_all != 0) {
268 0 : int ret;
269 :
270 0 : ret = json_add_bool(&state->filters_json,
271 : "--witness-apply-to-all",
272 0 : c->opt_witness_apply_to_all != 0);
273 0 : if (ret != 0) {
274 0 : return false;
275 : }
276 : }
277 :
278 0 : state->registrations_json = json_new_object();
279 0 : if (json_is_invalid(&state->registrations_json)) {
280 0 : return false;
281 : }
282 : #else /* not HAVE_JANSSON */
283 0 : d_fprintf(stderr, _("JSON support not available\n"));
284 0 : return false;
285 : #endif /* not HAVE_JANSSON */
286 : }
287 :
288 0 : ok = net_witness_scan_registrations_regex_init(state,
289 : &state->net_name,
290 : "--witness-net-name",
291 : c->opt_witness_net_name);
292 0 : if (!ok) {
293 0 : return false;
294 : }
295 :
296 0 : ok = net_witness_scan_registrations_regex_init(state,
297 : &state->share_name,
298 : "--witness-share-name",
299 : c->opt_witness_share_name);
300 0 : if (!ok) {
301 0 : return false;
302 : }
303 :
304 0 : ok = net_witness_scan_registrations_regex_init(state,
305 : &state->ip_address,
306 : "--witness-ip-address",
307 : c->opt_witness_ip_address);
308 0 : if (!ok) {
309 0 : return false;
310 : }
311 :
312 0 : ok = net_witness_scan_registrations_regex_init(state,
313 : &state->client_computer,
314 : "--witness-client-computer-name",
315 : c->opt_witness_client_computer_name);
316 0 : if (!ok) {
317 0 : return false;
318 : }
319 :
320 0 : ok = state->action->prepare_fn(state->action->private_data);
321 0 : if (!ok) {
322 0 : return false;
323 : }
324 :
325 0 : if (!c->opt_json) {
326 0 : d_printf("%-36s %-20s %-15s %-20s %s\n",
327 : "Registration-UUID:",
328 : "NetName",
329 : "ShareName",
330 : "IpAddress",
331 : "ClientComputerName");
332 0 : d_printf("%-36s-%-20s-%-15s-%-20s-%s\n",
333 : "------------------------------------",
334 : "--------------------",
335 : "------------------",
336 : "--------------------",
337 : "------------------");
338 : }
339 :
340 0 : return true;
341 : }
342 :
343 0 : static bool net_witness_scan_registrations_finish(
344 : struct net_witness_scan_registrations_state *state)
345 : {
346 : #ifdef HAVE_JANSSON
347 0 : struct net_context *c = state->c;
348 0 : struct json_object root_json = json_empty_object;
349 0 : TALLOC_CTX *frame = NULL;
350 0 : const char *json_str = NULL;
351 0 : int ret;
352 :
353 0 : if (!c->opt_json) {
354 0 : return true;
355 : }
356 :
357 0 : frame = talloc_stackframe();
358 :
359 0 : root_json = json_new_object();
360 0 : if (json_is_invalid(&root_json)) {
361 0 : TALLOC_FREE(frame);
362 0 : return false;
363 : }
364 :
365 0 : ret = json_add_object(&root_json,
366 : "filters",
367 : &state->filters_json);
368 0 : if (ret != 0) {
369 0 : json_free(&root_json);
370 0 : TALLOC_FREE(frame);
371 0 : return false;
372 : }
373 0 : state->filters_json = json_empty_object;
374 :
375 0 : if (state->message_json != NULL) {
376 0 : ret = json_add_object(&root_json,
377 : "message",
378 : state->message_json);
379 0 : if (ret != 0) {
380 0 : json_free(&root_json);
381 0 : TALLOC_FREE(frame);
382 0 : return false;
383 : }
384 0 : *state->message_json = json_empty_object;
385 : }
386 :
387 0 : ret = json_add_object(&root_json,
388 : "registrations",
389 : &state->registrations_json);
390 0 : if (ret != 0) {
391 0 : json_free(&root_json);
392 0 : TALLOC_FREE(frame);
393 0 : return false;
394 : }
395 0 : state->registrations_json = json_empty_object;
396 :
397 0 : json_str = json_to_string(frame, &root_json);
398 0 : json_free(&root_json);
399 0 : if (json_str == NULL) {
400 0 : TALLOC_FREE(frame);
401 0 : return false;
402 : }
403 :
404 0 : d_printf("%s\n", json_str);
405 0 : TALLOC_FREE(frame);
406 0 : return true;
407 : #else /* not HAVE_JANSSON */
408 0 : return true;
409 : #endif /* not HAVE_JANSSON */
410 : }
411 :
412 0 : static void net_witness_scan_registrations_free(
413 : struct net_witness_scan_registrations_state *state)
414 : {
415 : #ifdef HAVE_JANSSON
416 0 : if (!json_is_invalid(&state->filters_json)) {
417 0 : json_free(&state->filters_json);
418 : }
419 0 : if (!json_is_invalid(&state->registrations_json)) {
420 0 : json_free(&state->registrations_json);
421 : }
422 : #endif /* HAVE_JANSSON */
423 :
424 0 : net_witness_scan_registrations_regex_free(&state->net_name);
425 0 : net_witness_scan_registrations_regex_free(&state->share_name);
426 0 : net_witness_scan_registrations_regex_free(&state->ip_address);
427 0 : net_witness_scan_registrations_regex_free(&state->client_computer);
428 0 : }
429 :
430 : #ifdef HAVE_JANSSON
431 0 : static int dump_registration_json(struct json_object *registrations_json,
432 : const char *key_str,
433 : const struct rpcd_witness_registration *rg)
434 : {
435 0 : struct json_object jsobj = json_empty_object;
436 0 : struct json_object flags_json = json_empty_object;
437 0 : struct json_object context_json = json_empty_object;
438 0 : struct json_object serverid_json = json_empty_object;
439 0 : struct json_object auth_json = json_empty_object;
440 0 : struct json_object connection_json = json_empty_object;
441 0 : struct timeval tv;
442 0 : struct dom_sid_buf sid_buf;
443 0 : int ret = 0;
444 :
445 0 : jsobj = json_new_object();
446 0 : if (json_is_invalid(&jsobj)) {
447 0 : d_fprintf(stderr, _("error setting up JSON value\n"));
448 0 : goto failure;
449 : }
450 :
451 0 : ret = json_add_flags32(&jsobj, "version", rg->version);
452 0 : if (ret != 0) {
453 0 : goto failure;
454 : }
455 :
456 0 : ret = json_add_string(&jsobj, "net_name", rg->net_name);
457 0 : if (ret != 0) {
458 0 : goto failure;
459 : }
460 :
461 0 : ret = json_add_string(&jsobj, "share_name", rg->share_name);
462 0 : if (ret != 0) {
463 0 : goto failure;
464 : }
465 :
466 0 : ret = json_add_string(&jsobj, "ip_address", rg->ip_address);
467 0 : if (ret != 0) {
468 0 : goto failure;
469 : }
470 :
471 0 : ret = json_add_string(&jsobj, "client_computer_name", rg->client_computer_name);
472 0 : if (ret != 0) {
473 0 : goto failure;
474 : }
475 :
476 0 : flags_json = json_new_object();
477 0 : if (json_is_invalid(&flags_json)) {
478 0 : goto failure;
479 : }
480 :
481 0 : ret = json_add_bool(&flags_json, "WITNESS_REGISTER_IP_NOTIFICATION",
482 0 : (rg->flags & WITNESS_REGISTER_IP_NOTIFICATION) ?
483 0 : true : false);
484 0 : if (ret != 0) {
485 0 : goto failure;
486 : }
487 :
488 0 : ret = json_add_int(&flags_json, "int", rg->flags);
489 0 : if (ret != 0) {
490 0 : goto failure;
491 : }
492 :
493 0 : ret = json_add_flags32(&flags_json, "hex", rg->flags);
494 0 : if (ret != 0) {
495 0 : goto failure;
496 : }
497 :
498 0 : ret = json_add_object(&jsobj, "flags", &flags_json);
499 0 : if (ret != 0) {
500 0 : goto failure;
501 : }
502 0 : flags_json = json_empty_object;
503 :
504 0 : ret = json_add_int(&jsobj, "timeout", rg->timeout);
505 0 : if (ret != 0) {
506 0 : goto failure;
507 : }
508 :
509 0 : context_json = json_new_object();
510 0 : if (json_is_invalid(&context_json)) {
511 0 : goto failure;
512 : }
513 :
514 0 : ret = json_add_int(&context_json, "handle_type", rg->context_handle.handle_type);
515 0 : if (ret != 0) {
516 0 : goto failure;
517 : }
518 :
519 0 : ret = json_add_guid(&context_json, "uuid", &rg->context_handle.uuid);
520 0 : if (ret != 0) {
521 0 : goto failure;
522 : }
523 :
524 0 : ret = json_add_object(&jsobj, "context_handle", &context_json);
525 0 : if (ret != 0) {
526 0 : goto failure;
527 : }
528 0 : context_json = json_empty_object;
529 :
530 0 : serverid_json = json_new_object();
531 0 : if (json_is_invalid(&serverid_json)) {
532 0 : goto failure;
533 : }
534 :
535 0 : ret = json_add_int(&serverid_json, "pid", rg->server_id.pid);
536 0 : if (ret != 0) {
537 0 : goto failure;
538 : }
539 :
540 0 : ret = json_add_int(&serverid_json, "task_id", rg->server_id.task_id);
541 0 : if (ret != 0) {
542 0 : goto failure;
543 : }
544 :
545 0 : ret = json_add_int(&serverid_json, "vnn", rg->server_id.vnn);
546 0 : if (ret != 0) {
547 0 : goto failure;
548 : }
549 :
550 0 : ret = json_add_int(&serverid_json, "unique_id", rg->server_id.unique_id);
551 0 : if (ret != 0) {
552 0 : goto failure;
553 : }
554 :
555 0 : ret = json_add_object(&jsobj, "server_id", &serverid_json);
556 0 : if (ret != 0) {
557 0 : goto failure;
558 : }
559 0 : serverid_json = json_empty_object;
560 :
561 0 : auth_json = json_new_object();
562 0 : if (json_is_invalid(&auth_json)) {
563 0 : goto failure;
564 : }
565 :
566 0 : ret = json_add_string(&auth_json, "account_name", rg->account_name);
567 0 : if (ret != 0) {
568 0 : goto failure;
569 : }
570 :
571 0 : ret = json_add_string(&auth_json, "domain_name", rg->domain_name);
572 0 : if (ret != 0) {
573 0 : goto failure;
574 : }
575 :
576 0 : ret = json_add_string(&auth_json,
577 : "account_sid",
578 0 : dom_sid_str_buf(&rg->account_sid, &sid_buf));
579 0 : if (ret != 0) {
580 0 : goto failure;
581 : }
582 :
583 0 : ret = json_add_object(&jsobj, "auth", &auth_json);
584 0 : if (ret != 0) {
585 0 : goto failure;
586 : }
587 0 : auth_json = json_empty_object;
588 :
589 0 : connection_json = json_new_object();
590 0 : if (json_is_invalid(&connection_json)) {
591 0 : goto failure;
592 : }
593 :
594 0 : ret = json_add_string(&connection_json, "local_address", rg->local_address);
595 0 : if (ret != 0) {
596 0 : goto failure;
597 : }
598 :
599 0 : ret = json_add_string(&connection_json, "remote_address", rg->remote_address);
600 0 : if (ret != 0) {
601 0 : goto failure;
602 : }
603 :
604 0 : ret = json_add_object(&jsobj, "connection", &connection_json);
605 0 : if (ret != 0) {
606 0 : goto failure;
607 : }
608 0 : connection_json = json_empty_object;
609 :
610 0 : nttime_to_timeval(&tv, rg->registration_time);
611 0 : ret = json_add_time(&jsobj, "registration_time", tv);
612 0 : if (ret != 0) {
613 0 : goto failure;
614 : }
615 :
616 0 : ret = json_add_object(registrations_json, key_str, &jsobj);
617 0 : if (ret != 0) {
618 0 : goto failure;
619 : }
620 0 : jsobj = json_empty_object;
621 :
622 0 : failure:
623 0 : if (!json_is_invalid(&connection_json)) {
624 0 : json_free(&connection_json);
625 : }
626 0 : if (!json_is_invalid(&auth_json)) {
627 0 : json_free(&auth_json);
628 : }
629 0 : if (!json_is_invalid(&serverid_json)) {
630 0 : json_free(&serverid_json);
631 : }
632 0 : if (!json_is_invalid(&context_json)) {
633 0 : json_free(&context_json);
634 : }
635 0 : if (!json_is_invalid(&flags_json)) {
636 0 : json_free(&flags_json);
637 : }
638 0 : if (!json_is_invalid(&jsobj)) {
639 0 : json_free(&jsobj);
640 : }
641 :
642 0 : return ret;
643 : }
644 : #endif /* HAVE_JANSSON */
645 :
646 0 : static NTSTATUS net_witness_scan_registrations_dump_rg(
647 : struct net_witness_scan_registrations_state *state,
648 : const struct rpcd_witness_registration *rg)
649 : {
650 0 : struct net_context *c = state->c;
651 0 : struct GUID_txt_buf key_buf;
652 0 : const char *key_str = GUID_buf_string(&rg->context_handle.uuid, &key_buf);
653 :
654 0 : if (c->opt_json) {
655 : #ifdef HAVE_JANSSON
656 0 : int ret;
657 :
658 0 : ret = dump_registration_json(&state->registrations_json,
659 : key_str,
660 : rg);
661 0 : if (ret != 0) {
662 0 : d_fprintf(stderr, "dump_registration_json(%s) failed\n",
663 : key_str);
664 0 : return NT_STATUS_INTERNAL_ERROR;
665 : }
666 : #endif /* HAVE_JANSSON */
667 0 : return NT_STATUS_OK;
668 : }
669 :
670 0 : d_printf("%-36s %-20s %-15s %-20s %s\n",
671 : key_str,
672 0 : rg->net_name,
673 0 : rg->share_name ? rg->share_name : "''",
674 0 : rg->ip_address,
675 0 : rg->client_computer_name);
676 :
677 0 : return NT_STATUS_OK;
678 : }
679 :
680 0 : static void net_witness_scan_registrations_parser(TDB_DATA key,
681 : TDB_DATA val,
682 : void *private_data)
683 : {
684 0 : struct net_witness_scan_registrations_state *state =
685 : (struct net_witness_scan_registrations_state *)private_data;
686 0 : DATA_BLOB val_blob = data_blob_const(val.dptr, val.dsize);
687 0 : struct rpcd_witness_registration rg;
688 0 : enum ndr_err_code ndr_err;
689 0 : TALLOC_CTX *frame = NULL;
690 0 : bool match = false;
691 :
692 0 : if (val_blob.length == 0) {
693 0 : return;
694 : }
695 :
696 0 : frame = talloc_stackframe();
697 :
698 0 : ndr_err = ndr_pull_struct_blob(&val_blob, frame, &rg,
699 : (ndr_pull_flags_fn_t)ndr_pull_rpcd_witness_registration);
700 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
701 0 : DBG_WARNING("Invalid record in rpcd_witness_registration.tdb:"
702 : "key '%s' ndr_pull_struct_blob - %s\n",
703 : tdb_data_dbg(key),
704 : ndr_errstr(ndr_err));
705 0 : state->error = ndr_map_error2ntstatus(ndr_err);
706 0 : TALLOC_FREE(frame);
707 0 : return;
708 : }
709 :
710 0 : if (!serverid_exists(&rg.server_id)) {
711 0 : TALLOC_FREE(frame);
712 0 : return;
713 : }
714 :
715 0 : if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
716 0 : NDR_PRINT_DEBUG(rpcd_witness_registration, &rg);
717 : }
718 :
719 0 : match = net_witness_scan_registrations_match(state, &rg);
720 0 : if (!NT_STATUS_IS_OK(state->error)) {
721 0 : TALLOC_FREE(frame);
722 0 : return;
723 : }
724 0 : if (!match) {
725 0 : TALLOC_FREE(frame);
726 0 : return;
727 : }
728 :
729 0 : match = state->action->match_fn(state->action->private_data, &rg);
730 0 : if (!match) {
731 0 : TALLOC_FREE(frame);
732 0 : return;
733 : }
734 :
735 0 : state->error = state->action->process_fn(state->action->private_data, &rg);
736 0 : if (NT_STATUS_IS_OK(state->error)) {
737 0 : state->error = net_witness_scan_registrations_dump_rg(state,
738 : &rg);
739 : }
740 0 : TALLOC_FREE(frame);
741 : }
742 :
743 0 : static int net_witness_scan_registrations_traverse_cb(struct db_record *rec, void *private_data)
744 : {
745 0 : struct net_witness_scan_registrations_state *state =
746 : (struct net_witness_scan_registrations_state *)private_data;
747 0 : TDB_DATA key = dbwrap_record_get_key(rec);
748 0 : TDB_DATA val = dbwrap_record_get_value(rec);
749 :
750 0 : net_witness_scan_registrations_parser(key, val, private_data);
751 :
752 0 : if (!NT_STATUS_IS_OK(state->error)) {
753 0 : return -1;
754 : }
755 :
756 0 : return 0;
757 : }
758 :
759 0 : static int net_witness_scan_registrations(struct net_context *c,
760 : struct json_object *message_json,
761 : const struct net_witness_scan_registrations_action_state *action)
762 : {
763 0 : struct net_witness_scan_registrations_state state = {
764 : .c = c,
765 : .message_json = message_json,
766 : .action = action,
767 : };
768 0 : struct db_context *db = NULL;
769 0 : NTSTATUS status;
770 0 : bool ok;
771 :
772 0 : db = net_witness_open_registration_db();
773 0 : if (db == NULL) {
774 0 : d_printf("net_witness_open_registration_db() failed\n");
775 0 : return -1;
776 : }
777 :
778 0 : ok = net_witness_scan_registrations_init(&state);
779 0 : if (!ok) {
780 0 : d_printf("net_witness_scan_registrations_init() failed\n");
781 0 : return -1;
782 : }
783 :
784 0 : if (c->opt_witness_registration != NULL) {
785 0 : const char *key_str = c->opt_witness_registration;
786 0 : DATA_BLOB key_blob = data_blob_string_const(key_str);
787 0 : TDB_DATA key = make_tdb_data(key_blob.data, key_blob.length);
788 :
789 0 : status = dbwrap_parse_record(db,
790 : key,
791 : net_witness_scan_registrations_parser,
792 : &state);
793 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
794 0 : status = NT_STATUS_OK;
795 : }
796 0 : if (!NT_STATUS_IS_OK(status)) {
797 0 : d_printf("dbwrap_parse_record(%s) failed: %s\n",
798 : key_str, nt_errstr(status));
799 0 : net_witness_scan_registrations_free(&state);
800 0 : return -1;
801 : }
802 0 : if (!NT_STATUS_IS_OK(state.error)) {
803 0 : d_printf("net_witness_scan_registrations_parser(%s) failed: %s\n",
804 : key_str, nt_errstr(state.error));
805 0 : net_witness_scan_registrations_free(&state);
806 0 : return -1;
807 : }
808 : } else {
809 0 : status = dbwrap_traverse_read(db,
810 : net_witness_scan_registrations_traverse_cb,
811 : &state,
812 : NULL); /* count */
813 0 : if (!NT_STATUS_IS_OK(status)) {
814 0 : d_printf("dbwrap_traverse_read() failed\n");
815 0 : net_witness_scan_registrations_free(&state);
816 0 : return -1;
817 : }
818 0 : if (!NT_STATUS_IS_OK(state.error)) {
819 0 : d_printf("net_witness_scan_registrations_traverse_cb() failed: %s\n",
820 : nt_errstr(state.error));
821 0 : net_witness_scan_registrations_free(&state);
822 0 : return -1;
823 : }
824 : }
825 :
826 0 : ok = net_witness_scan_registrations_finish(&state);
827 0 : if (!ok) {
828 0 : d_printf("net_witness_scan_registrations_finish() failed\n");
829 0 : return -1;
830 : }
831 :
832 0 : net_witness_scan_registrations_free(&state);
833 0 : return 0;
834 : }
835 :
836 : struct net_witness_list_state {
837 : struct net_context *c;
838 : };
839 :
840 0 : static bool net_witness_list_prepare_fn(void *private_data)
841 : {
842 0 : return true;
843 : }
844 :
845 0 : static bool net_witness_list_match_fn(void *private_data,
846 : const struct rpcd_witness_registration *rg)
847 : {
848 0 : return true;
849 : }
850 :
851 0 : static NTSTATUS net_witness_list_process_fn(void *private_data,
852 : const struct rpcd_witness_registration *rg)
853 : {
854 0 : return NT_STATUS_OK;
855 : }
856 :
857 0 : static void net_witness_filter_usage(void)
858 : {
859 0 : d_printf(" Note: Only supported with clustering=yes!\n\n");
860 0 : d_printf(" Machine readable output can be generated with "
861 : "the following option:\n"
862 : "\n"
863 : " --json\n"
864 : "\n");
865 0 : d_printf(" The selection of registrations can be limited by "
866 : "the following options:\n"
867 : "\n"
868 : " --witness-registration=REGISTRATION_UUID\n"
869 : " This does a direct lookup for REGISTRATION_UUID\n"
870 : " instead of doing a database traversal.\n"
871 : "\n"
872 : " The following options all take a "
873 : "POSIX Extended Regular Expression,\n"
874 : " which can further filter the selection of "
875 : "registrations.\n"
876 : " These options are applied as logical AND, "
877 : "but each REGEX \n"
878 : " allows specifying multiple strings using "
879 : "the pipe symbol.\n"
880 : "\n"
881 : " --witness-net-name=REGEX\n"
882 : " This specifies the 'server name' the client\n"
883 : " registered for monitoring.\n"
884 : "\n"
885 : " --witness-share-name=REGEX\n"
886 : " This specifies the 'share name' the client\n"
887 : " registered for monitoring.\n"
888 : " Note that the share name is optional in the\n"
889 : " registration, otherwise an empty string is \n"
890 : " matched.\n"
891 : "\n"
892 : " --witness-ip-address=REGEX\n"
893 : " This specifies the ip address the client\n"
894 : " registered for monitoring.\n"
895 : "\n"
896 : " --witness-client-computer-name=REGEX\n"
897 : " This specifies the client computer name the client\n"
898 : " specified in the registration.\n"
899 : " Note it is just a string chosen by the "
900 : "client itself.\n"
901 : "\n");
902 0 : }
903 :
904 0 : static void net_witness_list_usage(void)
905 : {
906 0 : d_printf("%s\n"
907 : "net witness list\n"
908 : " %s\n\n",
909 : _("Usage:"),
910 : _("List witness registrations "
911 : "from rpcd_witness_registration.tdb"));
912 0 : net_witness_filter_usage();
913 0 : }
914 :
915 0 : static int net_witness_list(struct net_context *c, int argc, const char **argv)
916 : {
917 0 : TALLOC_CTX *frame = talloc_stackframe();
918 0 : struct net_witness_list_state state = { .c = c, };
919 0 : struct net_witness_scan_registrations_action_state action = {
920 : .prepare_fn = net_witness_list_prepare_fn,
921 : .match_fn = net_witness_list_match_fn,
922 : .process_fn = net_witness_list_process_fn,
923 : .private_data = &state,
924 : };
925 0 : int ret = -1;
926 :
927 0 : if (c->display_usage) {
928 0 : net_witness_list_usage();
929 0 : goto out;
930 : }
931 :
932 0 : if (argc != 0) {
933 0 : net_witness_list_usage();
934 0 : goto out;
935 : }
936 :
937 0 : if (!lp_clustering()) {
938 0 : d_printf("ERROR: Only supported with clustering=yes!\n\n");
939 0 : goto out;
940 : }
941 :
942 0 : ret = net_witness_scan_registrations(c, NULL, &action);
943 0 : if (ret != 0) {
944 0 : d_printf("net_witness_scan_registrations() failed\n");
945 0 : goto out;
946 : }
947 :
948 0 : ret = 0;
949 0 : out:
950 0 : TALLOC_FREE(frame);
951 0 : return ret;
952 : }
953 :
954 : struct net_witness_client_move_state {
955 : struct net_context *c;
956 : struct rpcd_witness_registration_updateB m;
957 : char *headline;
958 : };
959 :
960 0 : static bool net_witness_client_move_prepare_fn(void *private_data)
961 : {
962 0 : struct net_witness_client_move_state *state =
963 : (struct net_witness_client_move_state *)private_data;
964 :
965 0 : if (state->headline != NULL) {
966 0 : d_printf("%s\n", state->headline);
967 0 : TALLOC_FREE(state->headline);
968 : }
969 :
970 0 : return true;
971 : }
972 :
973 0 : static bool net_witness_client_move_match_fn(void *private_data,
974 : const struct rpcd_witness_registration *rg)
975 : {
976 0 : return true;
977 : }
978 :
979 0 : static NTSTATUS net_witness_client_move_process_fn(void *private_data,
980 : const struct rpcd_witness_registration *rg)
981 : {
982 0 : struct net_witness_client_move_state *state =
983 : (struct net_witness_client_move_state *)private_data;
984 0 : struct net_context *c = state->c;
985 0 : struct rpcd_witness_registration_updateB update = {
986 : .context_handle = rg->context_handle,
987 0 : .type = state->m.type,
988 : .update = state->m.update,
989 : };
990 0 : DATA_BLOB blob = { .length = 0, };
991 0 : enum ndr_err_code ndr_err;
992 0 : NTSTATUS status;
993 :
994 0 : if (state->headline != NULL) {
995 0 : d_printf("%s\n", state->headline);
996 0 : TALLOC_FREE(state->headline);
997 : }
998 :
999 0 : SMB_ASSERT(update.type != 0);
1000 :
1001 0 : if (DEBUGLVL(DBGLVL_DEBUG)) {
1002 0 : NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
1003 : }
1004 :
1005 0 : ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
1006 : (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
1007 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1008 0 : status = ndr_map_error2ntstatus(ndr_err);
1009 0 : DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
1010 0 : return status;
1011 : }
1012 :
1013 0 : status = messaging_send(c->msg_ctx,
1014 : rg->server_id,
1015 : MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
1016 : &blob);
1017 0 : if (!NT_STATUS_IS_OK(status)) {
1018 0 : DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
1019 0 : return status;
1020 : }
1021 :
1022 0 : return NT_STATUS_OK;
1023 : }
1024 :
1025 0 : static void net_witness_update_usage(void)
1026 : {
1027 0 : d_printf(" If the update should be applied to all registrations\n"
1028 : " it needs to be explicitly specified:\n"
1029 : "\n"
1030 : " --witness-apply-to-all\n"
1031 : " This selects all registrations.\n"
1032 : " Note: This is mutual exclusive to "
1033 : "the above options.\n"
1034 : "\n");
1035 0 : }
1036 :
1037 0 : static bool net_witness_verify_update_options(struct net_context *c)
1038 : {
1039 0 : if (c->opt_witness_registration == NULL &&
1040 0 : c->opt_witness_net_name == NULL &&
1041 0 : c->opt_witness_share_name == NULL &&
1042 0 : c->opt_witness_ip_address == NULL &&
1043 0 : c->opt_witness_client_computer_name == NULL &&
1044 0 : c->opt_witness_apply_to_all == 0)
1045 : {
1046 0 : d_printf("--witness-apply-to-all or "
1047 : "at least one of following requires:\n"
1048 : "--witness-registration\n"
1049 : "--witness-net-name\n"
1050 : "--witness-share-name\n"
1051 : "--witness-ip-address\n"
1052 : "--witness-client-computer-name\n");
1053 0 : return false;
1054 : }
1055 :
1056 0 : if (c->opt_witness_apply_to_all == 0) {
1057 0 : return true;
1058 : }
1059 :
1060 0 : if (c->opt_witness_registration != NULL ||
1061 0 : c->opt_witness_net_name != NULL ||
1062 0 : c->opt_witness_share_name != NULL ||
1063 0 : c->opt_witness_ip_address != NULL ||
1064 0 : c->opt_witness_client_computer_name != NULL)
1065 : {
1066 0 : d_printf("--witness-apply-to-all not allowed "
1067 : "together with the following options:\n"
1068 : "--witness-registration\n"
1069 : "--witness-net-name\n"
1070 : "--witness-share-name\n"
1071 : "--witness-ip-address\n"
1072 : "--witness-client-computer-name\n");
1073 0 : return false;
1074 : }
1075 :
1076 0 : return true;
1077 : }
1078 :
1079 0 : static void net_witness_move_usage(const char *name)
1080 : {
1081 0 : d_printf(" The content of the %s notification contains ip addresses\n"
1082 : " specified by (exactly one) of the following options:\n"
1083 : "\n"
1084 : " --witness-new-node=NODEID\n"
1085 : " By specifying a NODEID all ip addresses\n"
1086 : " currently available on the given node are\n"
1087 : " included in the response.\n"
1088 : " By specifying '-1' as NODEID all ip addresses\n"
1089 : " of the cluster are included in the response.\n"
1090 : "\n"
1091 : " --witness-new-ip=IPADDRESS\n"
1092 : " By specifying an IPADDRESS only the specified\n"
1093 : " ip address is included in the response.\n"
1094 : "\n",
1095 : name);
1096 0 : }
1097 :
1098 0 : static bool net_witness_verify_move_options(struct net_context *c,
1099 : uint32_t *new_node,
1100 : bool *is_ipv4,
1101 : bool *is_ipv6)
1102 : {
1103 0 : bool ok;
1104 :
1105 0 : *new_node = NONCLUSTER_VNN;
1106 0 : *is_ipv4 = false;
1107 0 : *is_ipv6 = false;
1108 :
1109 0 : ok = net_witness_verify_update_options(c);
1110 0 : if (!ok) {
1111 0 : return false;
1112 : }
1113 :
1114 0 : if (c->opt_witness_new_ip != NULL &&
1115 0 : c->opt_witness_new_node != -2)
1116 : {
1117 0 : d_printf("--witness-new-ip and "
1118 : "--witness-new-node are not allowed together\n");
1119 0 : return false;
1120 : }
1121 :
1122 0 : if (c->opt_witness_new_ip == NULL &&
1123 0 : c->opt_witness_new_node == -2)
1124 : {
1125 0 : d_printf("--witness-new-ip or --witness-new-node required\n");
1126 0 : return false;
1127 : }
1128 :
1129 0 : if (c->opt_witness_new_node != -2) {
1130 0 : *new_node = c->opt_witness_new_node;
1131 0 : return true;
1132 : }
1133 :
1134 0 : if (is_ipaddress_v4(c->opt_witness_new_ip)) {
1135 0 : *is_ipv4 = true;
1136 0 : return true;
1137 : }
1138 :
1139 0 : if (is_ipaddress_v6(c->opt_witness_new_ip)) {
1140 0 : *is_ipv6 = true;
1141 0 : return true;
1142 : }
1143 :
1144 0 : d_printf("Invalid ip address for --witness-new-ip=%s\n",
1145 : c->opt_witness_new_ip);
1146 0 : return false;
1147 : }
1148 :
1149 : #ifdef HAVE_JANSSON
1150 0 : static bool net_witness_move_message_json(struct net_context *c,
1151 : const char *msg_type,
1152 : struct json_object *pmessage_json)
1153 : {
1154 0 : struct json_object message_json = json_empty_object;
1155 0 : int ret;
1156 :
1157 0 : message_json = json_new_object();
1158 0 : if (json_is_invalid(&message_json)) {
1159 0 : return false;
1160 : }
1161 :
1162 0 : ret = json_add_string(&message_json,
1163 : "type",
1164 : msg_type);
1165 0 : if (ret != 0) {
1166 0 : json_free(&message_json);
1167 0 : return false;
1168 : }
1169 :
1170 0 : if (c->opt_witness_new_ip != NULL) {
1171 0 : ret = json_add_string(&message_json,
1172 : "new_ip",
1173 : c->opt_witness_new_ip);
1174 0 : if (ret != 0) {
1175 0 : return false;
1176 : }
1177 0 : } else if (c->opt_witness_new_node != -1) {
1178 0 : ret = json_add_int(&message_json,
1179 : "new_node",
1180 0 : c->opt_witness_new_node);
1181 0 : if (ret != 0) {
1182 0 : return false;
1183 : }
1184 : } else {
1185 0 : ret = json_add_bool(&message_json,
1186 : "all_nodes",
1187 : true);
1188 0 : if (ret != 0) {
1189 0 : return false;
1190 : }
1191 : }
1192 :
1193 0 : *pmessage_json = message_json;
1194 0 : return true;
1195 : }
1196 : #endif /* HAVE_JANSSON */
1197 :
1198 0 : static void net_witness_client_move_usage(void)
1199 : {
1200 0 : d_printf("%s\n"
1201 : "net witness client-move\n"
1202 : " %s\n\n",
1203 : _("Usage:"),
1204 : _("Generate client move notifications for "
1205 : "witness registrations to a new ip or node"));
1206 0 : net_witness_filter_usage();
1207 0 : net_witness_update_usage();
1208 0 : net_witness_move_usage("CLIENT_MOVE");
1209 0 : }
1210 :
1211 0 : static int net_witness_client_move(struct net_context *c, int argc, const char **argv)
1212 : {
1213 0 : TALLOC_CTX *frame = talloc_stackframe();
1214 0 : struct net_witness_client_move_state state = { .c = c, };
1215 0 : struct rpcd_witness_registration_updateB *m = &state.m;
1216 : #ifdef HAVE_JANSSON
1217 0 : struct json_object _message_json = json_empty_object;
1218 : #endif /* HAVE_JANSSON */
1219 0 : struct json_object *message_json = NULL;
1220 0 : struct net_witness_scan_registrations_action_state action = {
1221 : .prepare_fn = net_witness_client_move_prepare_fn,
1222 : .match_fn = net_witness_client_move_match_fn,
1223 : .process_fn = net_witness_client_move_process_fn,
1224 : .private_data = &state,
1225 : };
1226 0 : int ret = -1;
1227 0 : const char *msg_type = NULL;
1228 0 : uint32_t new_node = NONCLUSTER_VNN;
1229 0 : bool is_ipv4 = false;
1230 0 : bool is_ipv6 = false;
1231 0 : bool ok;
1232 :
1233 0 : if (c->display_usage) {
1234 0 : net_witness_client_move_usage();
1235 0 : goto out;
1236 : }
1237 :
1238 0 : if (argc != 0) {
1239 0 : net_witness_client_move_usage();
1240 0 : goto out;
1241 : }
1242 :
1243 0 : if (!lp_clustering()) {
1244 0 : d_printf("ERROR: Only supported with clustering=yes!\n\n");
1245 0 : goto out;
1246 : }
1247 :
1248 0 : ok = net_witness_verify_move_options(c, &new_node, &is_ipv4, &is_ipv6);
1249 0 : if (!ok) {
1250 0 : goto out;
1251 : }
1252 :
1253 0 : if (is_ipv4) {
1254 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_IPV4;
1255 0 : m->update.client_move_to_ipv4.new_ipv4 = c->opt_witness_new_ip;
1256 0 : msg_type = "CLIENT_MOVE_TO_IPV4";
1257 0 : state.headline = talloc_asprintf(frame,
1258 : "CLIENT_MOVE_TO_IPV4: %s",
1259 : c->opt_witness_new_ip);
1260 0 : if (state.headline == NULL) {
1261 0 : goto out;
1262 : }
1263 0 : } else if (is_ipv6) {
1264 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_IPV6;
1265 0 : m->update.client_move_to_ipv6.new_ipv6 = c->opt_witness_new_ip;
1266 0 : msg_type = "CLIENT_MOVE_TO_IPV6";
1267 0 : state.headline = talloc_asprintf(frame,
1268 : "CLIENT_MOVE_TO_IPV6: %s",
1269 : c->opt_witness_new_ip);
1270 0 : if (state.headline == NULL) {
1271 0 : goto out;
1272 : }
1273 0 : } else if (new_node != NONCLUSTER_VNN) {
1274 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_NODE;
1275 0 : m->update.client_move_to_node.new_node = new_node;
1276 0 : msg_type = "CLIENT_MOVE_TO_NODE";
1277 0 : state.headline = talloc_asprintf(frame,
1278 : "CLIENT_MOVE_TO_NODE: %u",
1279 : new_node);
1280 0 : if (state.headline == NULL) {
1281 0 : goto out;
1282 : }
1283 : } else {
1284 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_NODE;
1285 0 : m->update.client_move_to_node.new_node = NONCLUSTER_VNN;
1286 0 : msg_type = "CLIENT_MOVE_TO_NODE";
1287 0 : state.headline = talloc_asprintf(frame,
1288 : "CLIENT_MOVE_TO_NODE: ALL");
1289 0 : if (state.headline == NULL) {
1290 0 : goto out;
1291 : }
1292 : }
1293 :
1294 : #ifdef HAVE_JANSSON
1295 0 : if (c->opt_json) {
1296 0 : TALLOC_FREE(state.headline);
1297 :
1298 0 : ok = net_witness_move_message_json(c,
1299 : msg_type,
1300 : &_message_json);
1301 0 : if (!ok) {
1302 0 : d_printf("net_witness_move_message_json(%s) failed\n",
1303 : msg_type);
1304 0 : goto out;
1305 : }
1306 :
1307 0 : message_json = &_message_json;
1308 : }
1309 : #else /* not HAVE_JANSSON */
1310 : (void)msg_type;
1311 : #endif /* not HAVE_JANSSON */
1312 :
1313 0 : ret = net_witness_scan_registrations(c, message_json, &action);
1314 0 : if (ret != 0) {
1315 0 : d_printf("net_witness_scan_registrations() failed\n");
1316 0 : goto out;
1317 : }
1318 :
1319 0 : ret = 0;
1320 0 : out:
1321 : #ifdef HAVE_JANSSON
1322 0 : if (!json_is_invalid(&_message_json)) {
1323 0 : json_free(&_message_json);
1324 : }
1325 : #endif /* HAVE_JANSSON */
1326 0 : TALLOC_FREE(frame);
1327 0 : return ret;
1328 : }
1329 :
1330 : struct net_witness_share_move_state {
1331 : struct net_context *c;
1332 : struct rpcd_witness_registration_updateB m;
1333 : char *headline;
1334 : };
1335 :
1336 0 : static bool net_witness_share_move_prepare_fn(void *private_data)
1337 : {
1338 0 : struct net_witness_share_move_state *state =
1339 : (struct net_witness_share_move_state *)private_data;
1340 :
1341 0 : if (state->headline != NULL) {
1342 0 : d_printf("%s\n", state->headline);
1343 0 : TALLOC_FREE(state->headline);
1344 : }
1345 :
1346 0 : return true;
1347 : }
1348 :
1349 0 : static bool net_witness_share_move_match_fn(void *private_data,
1350 : const struct rpcd_witness_registration *rg)
1351 : {
1352 0 : if (rg->share_name == NULL) {
1353 0 : return false;
1354 : }
1355 :
1356 0 : return true;
1357 : }
1358 :
1359 0 : static NTSTATUS net_witness_share_move_process_fn(void *private_data,
1360 : const struct rpcd_witness_registration *rg)
1361 : {
1362 0 : struct net_witness_share_move_state *state =
1363 : (struct net_witness_share_move_state *)private_data;
1364 0 : struct net_context *c = state->c;
1365 0 : struct rpcd_witness_registration_updateB update = {
1366 : .context_handle = rg->context_handle,
1367 0 : .type = state->m.type,
1368 : .update = state->m.update,
1369 : };
1370 0 : DATA_BLOB blob = { .length = 0, };
1371 0 : enum ndr_err_code ndr_err;
1372 0 : NTSTATUS status;
1373 :
1374 0 : SMB_ASSERT(update.type != 0);
1375 :
1376 0 : if (DEBUGLVL(DBGLVL_DEBUG)) {
1377 0 : NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
1378 : }
1379 :
1380 0 : ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
1381 : (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
1382 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1383 0 : status = ndr_map_error2ntstatus(ndr_err);
1384 0 : DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
1385 0 : return status;
1386 : }
1387 :
1388 0 : status = messaging_send(c->msg_ctx,
1389 : rg->server_id,
1390 : MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
1391 : &blob);
1392 0 : if (!NT_STATUS_IS_OK(status)) {
1393 0 : DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
1394 0 : return status;
1395 : }
1396 :
1397 0 : return NT_STATUS_OK;
1398 : }
1399 :
1400 0 : static void net_witness_share_move_usage(void)
1401 : {
1402 0 : d_printf("%s\n"
1403 : "net witness share-move\n"
1404 : " %s\n\n",
1405 : _("Usage:"),
1406 : _("Generate share move notifications for "
1407 : "witness registrations to a new ip or node"));
1408 0 : net_witness_filter_usage();
1409 0 : net_witness_update_usage();
1410 0 : d_printf(" Note: This only applies to registrations with "
1411 : "a non empty share name!\n\n");
1412 0 : net_witness_move_usage("SHARE_MOVE");
1413 0 : }
1414 :
1415 0 : static int net_witness_share_move(struct net_context *c, int argc, const char **argv)
1416 : {
1417 0 : TALLOC_CTX *frame = talloc_stackframe();
1418 0 : struct net_witness_share_move_state state = { .c = c, };
1419 0 : struct rpcd_witness_registration_updateB *m = &state.m;
1420 : #ifdef HAVE_JANSSON
1421 0 : struct json_object _message_json = json_empty_object;
1422 : #endif /* HAVE_JANSSON */
1423 0 : struct json_object *message_json = NULL;
1424 0 : struct net_witness_scan_registrations_action_state action = {
1425 : .prepare_fn = net_witness_share_move_prepare_fn,
1426 : .match_fn = net_witness_share_move_match_fn,
1427 : .process_fn = net_witness_share_move_process_fn,
1428 : .private_data = &state,
1429 : };
1430 0 : int ret = -1;
1431 0 : const char *msg_type = NULL;
1432 0 : uint32_t new_node = NONCLUSTER_VNN;
1433 0 : bool is_ipv4 = false;
1434 0 : bool is_ipv6 = false;
1435 0 : bool ok;
1436 :
1437 0 : if (c->display_usage) {
1438 0 : net_witness_share_move_usage();
1439 0 : goto out;
1440 : }
1441 :
1442 0 : if (argc != 0) {
1443 0 : net_witness_share_move_usage();
1444 0 : goto out;
1445 : }
1446 :
1447 0 : if (!lp_clustering()) {
1448 0 : d_printf("ERROR: Only supported with clustering=yes!\n\n");
1449 0 : goto out;
1450 : }
1451 :
1452 0 : ok = net_witness_verify_move_options(c, &new_node, &is_ipv4, &is_ipv6);
1453 0 : if (!ok) {
1454 0 : goto out;
1455 : }
1456 :
1457 0 : if (is_ipv4) {
1458 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_IPV4;
1459 0 : m->update.share_move_to_ipv4.new_ipv4 = c->opt_witness_new_ip;
1460 0 : msg_type = "SHARE_MOVE_TO_IPV4";
1461 0 : state.headline = talloc_asprintf(frame,
1462 : "SHARE_MOVE_TO_IPV4: %s",
1463 : c->opt_witness_new_ip);
1464 0 : if (state.headline == NULL) {
1465 0 : goto out;
1466 : }
1467 0 : } else if (is_ipv6) {
1468 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_IPV6;
1469 0 : m->update.share_move_to_ipv6.new_ipv6 = c->opt_witness_new_ip;
1470 0 : msg_type = "SHARE_MOVE_TO_IPV6";
1471 0 : state.headline = talloc_asprintf(frame,
1472 : "SHARE_MOVE_TO_IPV6: %s",
1473 : c->opt_witness_new_ip);
1474 0 : if (state.headline == NULL) {
1475 0 : goto out;
1476 : }
1477 0 : } else if (new_node != NONCLUSTER_VNN) {
1478 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_NODE;
1479 0 : m->update.share_move_to_node.new_node = new_node;
1480 0 : msg_type = "SHARE_MOVE_TO_NODE";
1481 0 : state.headline = talloc_asprintf(frame,
1482 : "SHARE_MOVE_TO_NODE: %u",
1483 : new_node);
1484 0 : if (state.headline == NULL) {
1485 0 : goto out;
1486 : }
1487 : } else {
1488 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_NODE;
1489 0 : m->update.share_move_to_node.new_node = NONCLUSTER_VNN;
1490 0 : msg_type = "SHARE_MOVE_TO_NODE";
1491 0 : state.headline = talloc_asprintf(frame,
1492 : "SHARE_MOVE_TO_NODE: ALL");
1493 0 : if (state.headline == NULL) {
1494 0 : goto out;
1495 : }
1496 : }
1497 :
1498 : #ifdef HAVE_JANSSON
1499 0 : if (c->opt_json) {
1500 0 : TALLOC_FREE(state.headline);
1501 :
1502 0 : ok = net_witness_move_message_json(c,
1503 : msg_type,
1504 : &_message_json);
1505 0 : if (!ok) {
1506 0 : d_printf("net_witness_move_message_json(%s) failed\n",
1507 : msg_type);
1508 0 : goto out;
1509 : }
1510 :
1511 0 : message_json = &_message_json;
1512 : }
1513 : #else /* not HAVE_JANSSON */
1514 : (void)msg_type;
1515 : #endif /* not HAVE_JANSSON */
1516 :
1517 0 : ret = net_witness_scan_registrations(c, message_json, &action);
1518 0 : if (ret != 0) {
1519 0 : d_printf("net_witness_scan_registrations() failed\n");
1520 0 : goto out;
1521 : }
1522 :
1523 0 : ret = 0;
1524 0 : out:
1525 : #ifdef HAVE_JANSSON
1526 0 : if (!json_is_invalid(&_message_json)) {
1527 0 : json_free(&_message_json);
1528 : }
1529 : #endif /* HAVE_JANSSON */
1530 0 : TALLOC_FREE(frame);
1531 0 : return ret;
1532 : }
1533 :
1534 : struct net_witness_force_unregister_state {
1535 : struct net_context *c;
1536 : struct rpcd_witness_registration_updateB m;
1537 : char *headline;
1538 : };
1539 :
1540 0 : static bool net_witness_force_unregister_prepare_fn(void *private_data)
1541 : {
1542 0 : struct net_witness_force_unregister_state *state =
1543 : (struct net_witness_force_unregister_state *)private_data;
1544 :
1545 0 : if (state->headline != NULL) {
1546 0 : d_printf("%s\n", state->headline);
1547 0 : TALLOC_FREE(state->headline);
1548 : }
1549 :
1550 0 : return true;
1551 : }
1552 :
1553 0 : static bool net_witness_force_unregister_match_fn(void *private_data,
1554 : const struct rpcd_witness_registration *rg)
1555 : {
1556 0 : return true;
1557 : }
1558 :
1559 0 : static NTSTATUS net_witness_force_unregister_process_fn(void *private_data,
1560 : const struct rpcd_witness_registration *rg)
1561 : {
1562 0 : struct net_witness_force_unregister_state *state =
1563 : (struct net_witness_force_unregister_state *)private_data;
1564 0 : struct net_context *c = state->c;
1565 0 : struct rpcd_witness_registration_updateB update = {
1566 : .context_handle = rg->context_handle,
1567 0 : .type = state->m.type,
1568 : .update = state->m.update,
1569 : };
1570 0 : DATA_BLOB blob = { .length = 0, };
1571 0 : enum ndr_err_code ndr_err;
1572 0 : NTSTATUS status;
1573 :
1574 0 : SMB_ASSERT(update.type != 0);
1575 :
1576 0 : if (DEBUGLVL(DBGLVL_DEBUG)) {
1577 0 : NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
1578 : }
1579 :
1580 0 : ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
1581 : (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
1582 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1583 0 : status = ndr_map_error2ntstatus(ndr_err);
1584 0 : DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
1585 0 : return status;
1586 : }
1587 :
1588 0 : status = messaging_send(c->msg_ctx,
1589 : rg->server_id,
1590 : MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
1591 : &blob);
1592 0 : if (!NT_STATUS_IS_OK(status)) {
1593 0 : DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
1594 0 : return status;
1595 : }
1596 :
1597 0 : return NT_STATUS_OK;
1598 : }
1599 :
1600 0 : static void net_witness_force_unregister_usage(void)
1601 : {
1602 0 : d_printf("%s\n"
1603 : "net witness force-unregister\n"
1604 : " %s\n\n",
1605 : _("Usage:"),
1606 : _("Force unregistrations for witness registrations"));
1607 0 : net_witness_filter_usage();
1608 0 : net_witness_update_usage();
1609 0 : d_printf(" The selected registrations are removed on "
1610 : "the server and\n"
1611 : " any pending AsyncNotify request will get "
1612 : "a NOT_FOUND error.\n"
1613 : "\n"
1614 : " Typically this triggers a clean re-registration "
1615 : "on the client.\n"
1616 : "\n");
1617 0 : }
1618 :
1619 0 : static int net_witness_force_unregister(struct net_context *c, int argc, const char **argv)
1620 : {
1621 0 : TALLOC_CTX *frame = talloc_stackframe();
1622 0 : struct net_witness_force_unregister_state state = { .c = c, };
1623 0 : struct rpcd_witness_registration_updateB *m = &state.m;
1624 : #ifdef HAVE_JANSSON
1625 0 : struct json_object _message_json = json_empty_object;
1626 : #endif /* HAVE_JANSSON */
1627 0 : struct json_object *message_json = NULL;
1628 0 : struct net_witness_scan_registrations_action_state action = {
1629 : .prepare_fn = net_witness_force_unregister_prepare_fn,
1630 : .match_fn = net_witness_force_unregister_match_fn,
1631 : .process_fn = net_witness_force_unregister_process_fn,
1632 : .private_data = &state,
1633 : };
1634 0 : int ret = -1;
1635 0 : bool ok;
1636 :
1637 0 : if (c->display_usage) {
1638 0 : net_witness_force_unregister_usage();
1639 0 : goto out;
1640 : }
1641 :
1642 0 : if (argc != 0) {
1643 0 : net_witness_force_unregister_usage();
1644 0 : goto out;
1645 : }
1646 :
1647 0 : if (!lp_clustering()) {
1648 0 : d_printf("ERROR: Only supported with clustering=yes!\n\n");
1649 0 : goto out;
1650 : }
1651 :
1652 0 : ok = net_witness_verify_update_options(c);
1653 0 : if (!ok) {
1654 0 : goto out;
1655 : }
1656 :
1657 0 : m->type = RPCD_WITNESS_REGISTRATION_UPDATE_FORCE_UNREGISTER;
1658 :
1659 0 : state.headline = talloc_asprintf(frame, "FORCE_UNREGISTER:");
1660 0 : if (state.headline == NULL) {
1661 0 : goto out;
1662 : }
1663 :
1664 : #ifdef HAVE_JANSSON
1665 0 : if (c->opt_json) {
1666 0 : TALLOC_FREE(state.headline);
1667 :
1668 0 : _message_json = json_new_object();
1669 0 : if (json_is_invalid(&_message_json)) {
1670 0 : goto out;
1671 : }
1672 :
1673 0 : ret = json_add_string(&_message_json,
1674 : "type",
1675 : "FORCE_UNREGISTER");
1676 0 : if (ret != 0) {
1677 0 : goto out;
1678 : }
1679 :
1680 0 : message_json = &_message_json;
1681 : }
1682 : #endif /* HAVE_JANSSON */
1683 :
1684 0 : ret = net_witness_scan_registrations(c, message_json, &action);
1685 0 : if (ret != 0) {
1686 0 : d_printf("net_witness_scan_registrations() failed\n");
1687 0 : goto out;
1688 : }
1689 :
1690 0 : ret = 0;
1691 0 : out:
1692 : #ifdef HAVE_JANSSON
1693 0 : if (!json_is_invalid(&_message_json)) {
1694 0 : json_free(&_message_json);
1695 : }
1696 : #endif /* HAVE_JANSSON */
1697 0 : TALLOC_FREE(frame);
1698 0 : return ret;
1699 : }
1700 :
1701 : struct net_witness_force_response_state {
1702 : struct net_context *c;
1703 : struct rpcd_witness_registration_updateB m;
1704 : #ifdef HAVE_JANSSON
1705 : struct json_object json_root;
1706 : #endif /* HAVE_JANSSON */
1707 : char *headline;
1708 : };
1709 :
1710 : #ifdef HAVE_JANSSON
1711 0 : static NTSTATUS net_witness_force_response_parse_rc(
1712 : struct net_witness_force_response_state *state,
1713 : json_t *jsmsg,
1714 : TALLOC_CTX *mem_ctx,
1715 : size_t mi,
1716 : union witness_notifyResponse_message *message)
1717 : {
1718 0 : struct witness_ResourceChange *rc = &message->resource_change;
1719 0 : json_t *jsctype = NULL;
1720 0 : json_int_t ctype;
1721 0 : json_t *jscname = NULL;
1722 0 : const char *cname = NULL;
1723 :
1724 0 : if (!json_is_object(jsmsg)) {
1725 0 : DBG_ERR("'message[%zu]' needs to be an object\n", mi);
1726 0 : return NT_STATUS_INVALID_PARAMETER;
1727 : }
1728 :
1729 0 : jsctype = json_object_get(jsmsg, "type");
1730 0 : if (jsctype == NULL) {
1731 0 : DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1732 0 : return NT_STATUS_INVALID_PARAMETER;
1733 : }
1734 0 : if (!json_is_integer(jsctype)) {
1735 0 : DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1736 0 : return NT_STATUS_INVALID_PARAMETER;
1737 : }
1738 0 : ctype = json_integer_value(jsctype);
1739 :
1740 0 : jscname = json_object_get(jsmsg, "name");
1741 0 : if (jscname == NULL) {
1742 0 : DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1743 0 : return NT_STATUS_INVALID_PARAMETER;
1744 : }
1745 0 : if (!json_is_string(jscname)) {
1746 0 : DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1747 0 : return NT_STATUS_INVALID_PARAMETER;
1748 : }
1749 0 : cname = json_string_value(jscname);
1750 :
1751 0 : rc->type = ctype;
1752 0 : rc->name = talloc_strdup(mem_ctx, cname);
1753 0 : if (rc->name == NULL) {
1754 0 : return NT_STATUS_NO_MEMORY;
1755 : }
1756 :
1757 0 : return NT_STATUS_OK;
1758 : }
1759 :
1760 0 : static NTSTATUS net_witness_force_response_parse_ipl(
1761 : struct net_witness_force_response_state *state,
1762 : json_t *jsmsg,
1763 : TALLOC_CTX *mem_ctx,
1764 : size_t mi,
1765 : union witness_notifyResponse_message *message)
1766 : {
1767 0 : struct witness_IPaddrInfoList *ipl =
1768 : &message->client_move;
1769 0 : size_t ai, num_addrs = 0;
1770 0 : struct witness_IPaddrInfo *addrs = NULL;
1771 :
1772 0 : if (!json_is_array(jsmsg)) {
1773 0 : DBG_ERR("'messages[%zu]' needs to be an array\n", mi);
1774 0 : return NT_STATUS_INVALID_PARAMETER;
1775 : }
1776 :
1777 0 : num_addrs = json_array_size(jsmsg);
1778 0 : if (num_addrs > UINT32_MAX) {
1779 0 : DBG_ERR("Too many elements in 'messages[%zu]': %zu\n",
1780 : mi, num_addrs);
1781 0 : return NT_STATUS_INVALID_PARAMETER;
1782 : }
1783 :
1784 0 : addrs = talloc_zero_array(mem_ctx,
1785 : struct witness_IPaddrInfo,
1786 : num_addrs);
1787 0 : if (addrs == NULL) {
1788 0 : return NT_STATUS_NO_MEMORY;
1789 : }
1790 :
1791 0 : for (ai = 0; ai < num_addrs; ai++) {
1792 0 : struct witness_IPaddrInfo *info =
1793 0 : &addrs[ai];
1794 0 : json_t *jsaddr = json_array_get(jsmsg, ai);
1795 0 : json_t *jsflags = NULL;
1796 0 : json_int_t flags;
1797 0 : json_t *jsipv4 = NULL;
1798 0 : const char *ipv4 = NULL;
1799 0 : json_t *jsipv6 = NULL;
1800 0 : const char *ipv6 = NULL;
1801 :
1802 0 : if (!json_is_object(jsaddr)) {
1803 0 : DBG_ERR("'messages[%zu][%zu]' needs to be an object\n",
1804 : mi, ai);
1805 0 : return NT_STATUS_INVALID_PARAMETER;
1806 : }
1807 :
1808 0 : jsflags = json_object_get(jsaddr, "flags");
1809 0 : if (jsflags == NULL) {
1810 0 : DBG_ERR("'messages[%zu][%zu]['flags']' missing\n",
1811 : mi, ai);
1812 0 : return NT_STATUS_INVALID_PARAMETER;
1813 : }
1814 0 : if (!json_is_integer(jsflags)) {
1815 0 : DBG_ERR("'messages[%zu][%zu]['flags']' "
1816 : "needs to be an integer\n",
1817 : mi, ai);
1818 0 : return NT_STATUS_INVALID_PARAMETER;
1819 : }
1820 0 : flags = json_integer_value(jsflags);
1821 :
1822 0 : jsipv4 = json_object_get(jsaddr, "ipv4");
1823 0 : if (jsipv4 != NULL) {
1824 0 : if (!json_is_string(jsipv4)) {
1825 0 : DBG_ERR("'messages[%zu][%zu]['ipv4']' "
1826 : "needs to be a string\n",
1827 : mi, ai);
1828 0 : return NT_STATUS_INVALID_PARAMETER;
1829 : }
1830 0 : ipv4 = json_string_value(jsipv4);
1831 0 : if (!is_ipaddress_v4(ipv4)) {
1832 0 : DBG_ERR("'messages[%zu][%zu]['ipv4']' "
1833 : "needs to be a valid ipv4 address\n",
1834 : mi, ai);
1835 0 : return NT_STATUS_INVALID_PARAMETER;
1836 : }
1837 : } else {
1838 0 : ipv4 = "0.0.0.0";
1839 : }
1840 :
1841 0 : jsipv6 = json_object_get(jsaddr, "ipv6");
1842 0 : if (jsipv6 != NULL) {
1843 0 : if (!json_is_string(jsipv6)) {
1844 0 : DBG_ERR("'messages[%zu][%zu]['ipv6']' "
1845 : "needs to be a string\n",
1846 : mi, ai);
1847 0 : DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1848 0 : return NT_STATUS_INVALID_PARAMETER;
1849 : }
1850 0 : ipv6 = json_string_value(jsipv6);
1851 0 : if (!is_ipaddress_v6(ipv6)) {
1852 0 : DBG_ERR("'messages[%zu][%zu]['ipv4']' "
1853 : "needs to be a valid ipv6 address\n",
1854 : mi, ai);
1855 0 : return NT_STATUS_INVALID_PARAMETER;
1856 : }
1857 : } else {
1858 0 : ipv6 = "::";
1859 : }
1860 :
1861 0 : info->flags = flags;
1862 0 : info->ipv4 = talloc_strdup(addrs, ipv4);
1863 0 : if (info->ipv4 == NULL) {
1864 0 : return NT_STATUS_NO_MEMORY;
1865 : }
1866 0 : info->ipv6 = talloc_strdup(addrs, ipv6);
1867 0 : if (info->ipv6 == NULL) {
1868 0 : return NT_STATUS_NO_MEMORY;
1869 : }
1870 : }
1871 :
1872 0 : ipl->num = num_addrs;
1873 0 : ipl->addr = addrs;
1874 :
1875 0 : return NT_STATUS_OK;
1876 : }
1877 : #endif /* HAVE_JANSSON */
1878 :
1879 0 : static NTSTATUS net_witness_force_response_parse(struct net_witness_force_response_state *state)
1880 : {
1881 : #ifdef HAVE_JANSSON
1882 0 : struct net_context *c = state->c;
1883 0 : struct rpcd_witness_registration_update_force_response *force = NULL;
1884 0 : struct witness_notifyResponse *response = NULL;
1885 0 : size_t mi, num_messages = 0;
1886 0 : union witness_notifyResponse_message *messages = NULL;
1887 0 : json_t *jsroot = NULL;
1888 0 : json_t *jsresult = NULL;
1889 0 : json_t *jsresponse = NULL;
1890 0 : json_t *jstype = NULL;
1891 0 : json_t *jsmessages = NULL;
1892 :
1893 0 : if (c->opt_witness_forced_response != NULL) {
1894 0 : const char *str = c->opt_witness_forced_response;
1895 0 : size_t flags = JSON_REJECT_DUPLICATES;
1896 0 : json_error_t jserror;
1897 :
1898 0 : jsroot = json_loads(str, flags, &jserror);
1899 0 : if (jsroot == NULL) {
1900 0 : DBG_ERR("Invalid JSON in "
1901 : "--witness-forced-response='%s'\n",
1902 : str);
1903 0 : return NT_STATUS_INVALID_PARAMETER;
1904 : }
1905 0 : state->json_root = (struct json_object) {
1906 : .root = jsroot,
1907 : .valid = true,
1908 : };
1909 : }
1910 :
1911 0 : state->m.type = RPCD_WITNESS_REGISTRATION_UPDATE_FORCE_RESPONSE;
1912 0 : force = &state->m.update.force_response;
1913 0 : force->response = NULL;
1914 0 : force->result = WERR_OK;
1915 :
1916 0 : if (jsroot == NULL) {
1917 0 : return NT_STATUS_OK;
1918 : }
1919 :
1920 0 : jsresult = json_object_get(jsroot, "result");
1921 0 : if (jsresult != NULL) {
1922 0 : int val_type = json_typeof(jsresult);
1923 :
1924 0 : switch (val_type) {
1925 0 : case JSON_INTEGER: {
1926 0 : json_int_t val = json_integer_value(jsresult);
1927 :
1928 0 : if (val > UINT32_MAX) {
1929 0 : DBG_ERR("Invalid 'result' value: %d\n",
1930 : (int) val);
1931 0 : return NT_STATUS_INVALID_PARAMETER;
1932 : }
1933 0 : if (val < 0) {
1934 0 : DBG_ERR("invalid 'result' value: %d\n",
1935 : (int) val);
1936 0 : return NT_STATUS_INVALID_PARAMETER;
1937 : }
1938 :
1939 0 : force->result = W_ERROR(val);
1940 0 : }; break;
1941 0 : default:
1942 0 : DBG_ERR("Invalid json type for 'result' - needs integer\n");
1943 0 : return NT_STATUS_INVALID_PARAMETER;
1944 : }
1945 : }
1946 :
1947 0 : jsresponse = json_object_get(jsroot, "response");
1948 0 : if (jsresponse == NULL) {
1949 0 : return NT_STATUS_OK;
1950 : }
1951 :
1952 0 : if (!json_is_object(jsresponse)) {
1953 0 : DBG_ERR("Invalid json type 'response' needs object\n");
1954 0 : return NT_STATUS_INVALID_PARAMETER;
1955 : }
1956 :
1957 0 : response = talloc_zero(talloc_tos(), struct witness_notifyResponse);
1958 0 : if (response == NULL) {
1959 0 : return NT_STATUS_NO_MEMORY;
1960 : }
1961 :
1962 0 : jstype = json_object_get(jsresponse, "type");
1963 0 : if (jstype == NULL) {
1964 0 : DBG_ERR("Missing 'type' element in 'response'\n");
1965 0 : return NT_STATUS_INVALID_PARAMETER;
1966 : }
1967 : {
1968 0 : int val_type = json_typeof(jstype);
1969 :
1970 0 : switch (val_type) {
1971 0 : case JSON_INTEGER: {
1972 0 : json_int_t val = json_integer_value(jstype);
1973 :
1974 0 : if (val > WITNESS_NOTIFY_IP_CHANGE) {
1975 0 : DBG_ERR("invalid 'type' value in 'response': "
1976 : "%d\n", (int) val);
1977 0 : return NT_STATUS_INVALID_PARAMETER;
1978 : }
1979 0 : if (val < WITNESS_NOTIFY_RESOURCE_CHANGE) {
1980 0 : DBG_ERR("invalid 'type' value in 'response': "
1981 : "%d\n", (int) val);
1982 0 : return NT_STATUS_INVALID_PARAMETER;
1983 : }
1984 :
1985 0 : response->type = val;
1986 0 : }; break;
1987 0 : default:
1988 0 : DBG_ERR("Invalid json type for 'type' in 'response' "
1989 : "- needs integer\n");
1990 0 : return NT_STATUS_INVALID_PARAMETER;
1991 : }
1992 : }
1993 :
1994 0 : force->response = response;
1995 :
1996 0 : jsmessages = json_object_get(jsresponse, "messages");
1997 0 : if (jsmessages == NULL) {
1998 0 : return NT_STATUS_OK;
1999 : }
2000 :
2001 0 : if (!json_is_array(jsmessages)) {
2002 0 : DBG_ERR("'messages' in 'response' needs to be an array\n");
2003 0 : return NT_STATUS_INVALID_PARAMETER;
2004 : }
2005 :
2006 0 : num_messages = json_array_size(jsmessages);
2007 0 : if (num_messages > UINT32_MAX) {
2008 0 : DBG_ERR("Too many elements in 'messages': %zu\n",
2009 : num_messages);
2010 0 : return NT_STATUS_INVALID_PARAMETER;
2011 : }
2012 :
2013 0 : messages = talloc_zero_array(response,
2014 : union witness_notifyResponse_message,
2015 : num_messages);
2016 0 : if (messages == NULL) {
2017 0 : return NT_STATUS_NO_MEMORY;
2018 : }
2019 :
2020 0 : for (mi = 0; mi < num_messages; mi++) {
2021 0 : json_t *jsmsg = json_array_get(jsmessages, mi);
2022 0 : union witness_notifyResponse_message *message = &messages[mi];
2023 0 : NTSTATUS status;
2024 :
2025 0 : switch (response->type) {
2026 0 : case WITNESS_NOTIFY_RESOURCE_CHANGE:
2027 0 : status = net_witness_force_response_parse_rc(state,
2028 : jsmsg,
2029 : messages,
2030 : mi,
2031 : message);
2032 0 : if (!NT_STATUS_IS_OK(status)) {
2033 0 : const char *fn =
2034 : "net_witness_force_response_parse_rc";
2035 0 : DBG_ERR("%s failed: %s\n",
2036 : fn, nt_errstr(status));
2037 0 : return status;
2038 : }
2039 :
2040 0 : break;
2041 0 : case WITNESS_NOTIFY_CLIENT_MOVE:
2042 : case WITNESS_NOTIFY_SHARE_MOVE:
2043 : case WITNESS_NOTIFY_IP_CHANGE:
2044 0 : status = net_witness_force_response_parse_ipl(state,
2045 : jsmsg,
2046 : messages,
2047 : mi,
2048 : message);
2049 0 : if (!NT_STATUS_IS_OK(status)) {
2050 0 : const char *fn =
2051 : "net_witness_force_response_parse_ipl";
2052 0 : DBG_ERR("%s failed: %s\n",
2053 : fn, nt_errstr(status));
2054 0 : return status;
2055 : }
2056 :
2057 0 : break;
2058 : }
2059 : }
2060 :
2061 0 : response->num = num_messages;
2062 0 : response->messages = messages;
2063 :
2064 0 : return NT_STATUS_OK;
2065 : #else /* not HAVE_JANSSON */
2066 0 : d_fprintf(stderr, _("JSON support not available\n"));
2067 0 : return NT_STATUS_NOT_IMPLEMENTED;
2068 : #endif /* not HAVE_JANSSON */
2069 : }
2070 :
2071 0 : static bool net_witness_force_response_prepare_fn(void *private_data)
2072 : {
2073 0 : struct net_witness_force_response_state *state =
2074 : (struct net_witness_force_response_state *)private_data;
2075 :
2076 0 : if (state->headline != NULL) {
2077 0 : d_printf("%s\n", state->headline);
2078 0 : TALLOC_FREE(state->headline);
2079 : }
2080 :
2081 0 : return true;
2082 : }
2083 :
2084 0 : static bool net_witness_force_response_match_fn(void *private_data,
2085 : const struct rpcd_witness_registration *rg)
2086 : {
2087 0 : return true;
2088 : }
2089 :
2090 0 : static NTSTATUS net_witness_force_response_process_fn(void *private_data,
2091 : const struct rpcd_witness_registration *rg)
2092 : {
2093 0 : struct net_witness_force_response_state *state =
2094 : (struct net_witness_force_response_state *)private_data;
2095 0 : struct net_context *c = state->c;
2096 0 : struct rpcd_witness_registration_updateB update = {
2097 : .context_handle = rg->context_handle,
2098 0 : .type = state->m.type,
2099 : .update = state->m.update,
2100 : };
2101 0 : DATA_BLOB blob = { .length = 0, };
2102 0 : enum ndr_err_code ndr_err;
2103 0 : NTSTATUS status;
2104 :
2105 0 : SMB_ASSERT(update.type != 0);
2106 :
2107 0 : if (DEBUGLVL(DBGLVL_DEBUG)) {
2108 0 : NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
2109 : }
2110 :
2111 0 : ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
2112 : (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
2113 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2114 0 : status = ndr_map_error2ntstatus(ndr_err);
2115 0 : DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
2116 0 : return status;
2117 : }
2118 :
2119 0 : status = messaging_send(c->msg_ctx,
2120 : rg->server_id,
2121 : MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
2122 : &blob);
2123 0 : if (!NT_STATUS_IS_OK(status)) {
2124 0 : DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
2125 0 : return status;
2126 : }
2127 :
2128 0 : return NT_STATUS_OK;
2129 : }
2130 :
2131 0 : static void net_witness_force_response_usage(void)
2132 : {
2133 0 : d_printf("%s\n"
2134 : "net witness force-response\n"
2135 : " %s\n\n",
2136 : _("Usage:"),
2137 : _("Force an AsyncNotify response based on "
2138 : "json input (mostly for testing)"));
2139 0 : net_witness_filter_usage();
2140 0 : net_witness_update_usage();
2141 0 : d_printf(" Note this is designed for testing and debugging!\n"
2142 : "\n"
2143 : " In short it is not designed to be used by "
2144 : "administrators,\n"
2145 : " but developers and automated tests.\n"
2146 : "\n"
2147 : " By default an empty response with WERR_OK is generated,\n"
2148 : " but basically any valid response can be specified by a\n"
2149 : " specifying a JSON string:\n"
2150 : "\n"
2151 : " --witness-forced-response=JSON\n"
2152 : " This allows the generation of very complex\n"
2153 : " witness_notifyResponse structures.\n"
2154 : "\n"
2155 : " As this is for developers, please read the code\n"
2156 : " in order to understand all possible values\n"
2157 : " of the JSON string format...\n"
2158 : "\n"
2159 : " Simple examples are:\n"
2160 : "\n"
2161 : "# Resource Change:\n%s\n"
2162 : "\n"
2163 : "# Client Move:\n%s\n"
2164 : "\n"
2165 : "# Share Move:\n%s\n"
2166 : "\n"
2167 : "# IP Change:\n%s\n"
2168 : "\n",
2169 : "'{ \"result\": 0, \"response\": { \"type\": 1, "
2170 : "\"messages\": [ { "
2171 : "\"type\": 255 , "
2172 : "\"name\": \"some-resource-name\" "
2173 : "} ]"
2174 : "}}'",
2175 : "'{ \"result\": 0, \"response\": { \"type\": 2, "
2176 : "\"messages\": ["
2177 : "[{ "
2178 : "\"flags\": 9, "
2179 : "\"ipv4\": \"10.0.10.1\" "
2180 : "}]"
2181 : "]"
2182 : "}}'",
2183 : "'{ \"result\": 0, \"response\": { \"type\": 3, "
2184 : "\"messages\": ["
2185 : "[{ "
2186 : "\"flags\": 9, "
2187 : "\"ipv4\": \"10.0.10.1\" "
2188 : "}]"
2189 : "]"
2190 : "}}'",
2191 : "'{ \"result\": 0, \"response\": { \"type\": 4, "
2192 : "\"messages\": ["
2193 : "[{ "
2194 : "\"flags\": 9, "
2195 : "\"ipv4\": \"10.0.10.1\" "
2196 : "}]"
2197 : "]"
2198 : "}}'");
2199 0 : }
2200 :
2201 0 : static int net_witness_force_response(struct net_context *c, int argc, const char **argv)
2202 : {
2203 0 : TALLOC_CTX *frame = talloc_stackframe();
2204 0 : struct net_witness_force_response_state state = { .c = c, };
2205 : #ifdef HAVE_JANSSON
2206 0 : struct json_object _message_json = json_empty_object;
2207 : #endif /* HAVE_JANSSON */
2208 0 : struct json_object *message_json = NULL;
2209 0 : struct net_witness_scan_registrations_action_state action = {
2210 : .prepare_fn = net_witness_force_response_prepare_fn,
2211 : .match_fn = net_witness_force_response_match_fn,
2212 : .process_fn = net_witness_force_response_process_fn,
2213 : .private_data = &state,
2214 : };
2215 0 : NTSTATUS status;
2216 0 : int ret = -1;
2217 0 : bool ok;
2218 :
2219 0 : if (c->display_usage) {
2220 0 : net_witness_force_response_usage();
2221 0 : goto out;
2222 : }
2223 :
2224 0 : if (argc != 0) {
2225 0 : net_witness_force_response_usage();
2226 0 : goto out;
2227 : }
2228 :
2229 0 : if (!lp_clustering()) {
2230 0 : d_printf("ERROR: Only supported with clustering=yes!\n\n");
2231 0 : goto out;
2232 : }
2233 :
2234 0 : ok = net_witness_verify_update_options(c);
2235 0 : if (!ok) {
2236 0 : goto out;
2237 : }
2238 :
2239 0 : status = net_witness_force_response_parse(&state);
2240 0 : if (!NT_STATUS_IS_OK(status)) {
2241 0 : d_printf("net_witness_force_response_parse failed: %s\n",
2242 : nt_errstr(status));
2243 0 : goto out;
2244 : }
2245 :
2246 0 : state.headline = talloc_asprintf(frame, "FORCE_RESPONSE:%s%s",
2247 0 : c->opt_witness_forced_response != NULL ?
2248 : " " : "",
2249 0 : c->opt_witness_forced_response != NULL ?
2250 : c->opt_witness_forced_response : "");
2251 :
2252 0 : if (state.headline == NULL) {
2253 0 : goto out;
2254 : }
2255 :
2256 : #ifdef HAVE_JANSSON
2257 0 : if (c->opt_json) {
2258 0 : TALLOC_FREE(state.headline);
2259 :
2260 0 : _message_json = json_new_object();
2261 0 : if (json_is_invalid(&_message_json)) {
2262 0 : goto out;
2263 : }
2264 :
2265 0 : ret = json_add_string(&_message_json,
2266 : "type",
2267 : "FORCE_RESPONSE");
2268 0 : if (ret != 0) {
2269 0 : goto out;
2270 : }
2271 :
2272 0 : if (!json_is_invalid(&state.json_root)) {
2273 0 : ret = json_add_object(&_message_json,
2274 : "json",
2275 : &state.json_root);
2276 0 : if (ret != 0) {
2277 0 : goto out;
2278 : }
2279 0 : state.json_root = json_empty_object;
2280 : }
2281 0 : message_json = &_message_json;
2282 : }
2283 : #endif /* HAVE_JANSSON */
2284 :
2285 0 : ret = net_witness_scan_registrations(c, message_json, &action);
2286 0 : if (ret != 0) {
2287 0 : d_printf("net_witness_scan_registrations() failed\n");
2288 0 : goto out;
2289 : }
2290 :
2291 0 : ret = 0;
2292 0 : out:
2293 : #ifdef HAVE_JANSSON
2294 0 : if (!json_is_invalid(&_message_json)) {
2295 0 : json_free(&_message_json);
2296 : }
2297 0 : if (!json_is_invalid(&state.json_root)) {
2298 0 : json_free(&state.json_root);
2299 : }
2300 : #endif /* HAVE_JANSSON */
2301 0 : TALLOC_FREE(frame);
2302 0 : return ret;
2303 : }
2304 :
2305 0 : int net_witness(struct net_context *c, int argc, const char **argv)
2306 : {
2307 0 : struct functable func[] = {
2308 : {
2309 : "list",
2310 : net_witness_list,
2311 : NET_TRANSPORT_LOCAL,
2312 : N_("List witness registrations "
2313 : "from rpcd_witness_registration.tdb"),
2314 : N_("net witness list\n"
2315 : " List witness registrations "
2316 : "from rpcd_witness_registration.tdb"),
2317 : },
2318 : {
2319 : "client-move",
2320 : net_witness_client_move,
2321 : NET_TRANSPORT_LOCAL,
2322 : N_("Generate client move notifications for "
2323 : "witness registrations to a new ip or node"),
2324 : N_("net witness client-move\n"
2325 : " Generate client move notifications for "
2326 : "witness registrations to a new ip or node"),
2327 : },
2328 : {
2329 : "share-move",
2330 : net_witness_share_move,
2331 : NET_TRANSPORT_LOCAL,
2332 : N_("Generate share move notifications for "
2333 : "witness registrations to a new ip or node"),
2334 : N_("net witness share-move\n"
2335 : " Generate share move notifications for "
2336 : "witness registrations to a new ip or node"),
2337 : },
2338 : {
2339 : "force-unregister",
2340 : net_witness_force_unregister,
2341 : NET_TRANSPORT_LOCAL,
2342 : N_("Force unregistrations for witness registrations"),
2343 : N_("net witness force-unregister\n"
2344 : " Force unregistrations for "
2345 : "witness registrations"),
2346 : },
2347 : {
2348 : "force-response",
2349 : net_witness_force_response,
2350 : NET_TRANSPORT_LOCAL,
2351 : N_("Force an AsyncNotify response based on "
2352 : "json input (mostly for testing)"),
2353 : N_("net witness force-response\n"
2354 : " Force an AsyncNotify response based on "
2355 : "json input (mostly for testing)"),
2356 : },
2357 : {NULL, NULL, 0, NULL, NULL}
2358 : };
2359 :
2360 0 : return net_run_function(c, argc, argv, "net witness", func);
2361 : }
|