2 * Samba Unix/Linux client library
3 * net witness commands to manage smb witness registrations
4 * Copyright (C) 2023 Stefan Metzmacher
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.
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.
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/>.
21 #include "utils/net.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"
38 #include "audit_logging.h" /* various JSON helpers */
39 #endif /* HAVE_JANSSON */
43 static struct db_context *net_witness_open_registration_db(void)
45 static struct db_context *db;
46 char *global_path = NULL;
52 global_path = lock_path(talloc_tos(), "rpcd_witness_registration.tdb");
53 if (global_path == NULL) {
62 TDB_INCOMPATIBLE_HASH,
67 TALLOC_FREE(global_path);
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);
82 struct net_witness_scan_registrations_regex {
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;
95 struct json_object filters_json;
96 struct json_object registrations_json;
98 const struct net_witness_scan_registrations_action_state *action;
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);
112 static bool net_witness_scan_registrations_match(
113 struct net_witness_scan_registrations_state *state,
114 const struct rpcd_witness_registration *rg)
116 if (state->net_name.valid) {
119 match = net_witness_scan_registrations_regex_match(
128 if (state->share_name.valid) {
131 match = net_witness_scan_registrations_regex_match(
140 if (state->ip_address.valid) {
143 match = net_witness_scan_registrations_regex_match(
152 if (state->client_computer.valid) {
155 match = net_witness_scan_registrations_regex_match(
156 &state->client_computer,
157 "client_computer_name",
158 rg->client_computer_name);
167 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)
173 struct net_context *c = state->c;
174 #endif /* HAVE_JANSSON */
183 ret = regcomp(&r->regex, value, REG_EXTENDED|REG_ICASE|REG_NOSUB);
186 regerror(ret, &r->regex, buf, sizeof(buf));
187 d_printf("regcomp(%s) failed for %s: "
188 "%d: %s\n", value, option, ret, buf);
194 ret = json_add_string(&state->filters_json,
201 #endif /* HAVE_JANSSON */
207 static bool net_witness_scan_registrations_regex_match(
208 struct net_witness_scan_registrations_regex *r,
209 const char *name, const char *value)
219 * without a share name,
220 * we match against an empty
226 ret = regexec(&r->regex, value, 0, NULL, 0);
227 if (ret == REG_NOMATCH) {
234 static void net_witness_scan_registrations_regex_free(
235 struct net_witness_scan_registrations_regex *r)
243 static bool net_witness_scan_registrations_init(
244 struct net_witness_scan_registrations_state *state)
246 struct net_context *c = state->c;
251 state->filters_json = json_new_object();
252 if (json_is_invalid(&state->filters_json)) {
256 if (c->opt_witness_registration != NULL) {
259 ret = json_add_string(&state->filters_json,
260 "--witness-registration",
261 c->opt_witness_registration);
267 if (c->opt_witness_apply_to_all != 0) {
270 ret = json_add_bool(&state->filters_json,
271 "--witness-apply-to-all",
272 c->opt_witness_apply_to_all != 0);
278 state->registrations_json = json_new_object();
279 if (json_is_invalid(&state->registrations_json)) {
282 #else /* not HAVE_JANSSON */
283 d_fprintf(stderr, _("JSON support not available\n"));
285 #endif /* not HAVE_JANSSON */
288 ok = net_witness_scan_registrations_regex_init(state,
290 "--witness-net-name",
291 c->opt_witness_net_name);
296 ok = net_witness_scan_registrations_regex_init(state,
298 "--witness-share-name",
299 c->opt_witness_share_name);
304 ok = net_witness_scan_registrations_regex_init(state,
306 "--witness-ip-address",
307 c->opt_witness_ip_address);
312 ok = net_witness_scan_registrations_regex_init(state,
313 &state->client_computer,
314 "--witness-client-computer-name",
315 c->opt_witness_client_computer_name);
320 ok = state->action->prepare_fn(state->action->private_data);
326 d_printf("%-36s %-20s %-15s %-20s %s\n",
327 "Registration-UUID:",
331 "ClientComputerName");
332 d_printf("%-36s-%-20s-%-15s-%-20s-%s\n",
333 "------------------------------------",
334 "--------------------",
335 "------------------",
336 "--------------------",
337 "------------------");
343 static bool net_witness_scan_registrations_finish(
344 struct net_witness_scan_registrations_state *state)
347 struct net_context *c = state->c;
348 struct json_object root_json = json_empty_object;
349 TALLOC_CTX *frame = NULL;
350 const char *json_str = NULL;
357 frame = talloc_stackframe();
359 root_json = json_new_object();
360 if (json_is_invalid(&root_json)) {
365 ret = json_add_object(&root_json,
367 &state->filters_json);
369 json_free(&root_json);
373 state->filters_json = json_empty_object;
375 if (state->message_json != NULL) {
376 ret = json_add_object(&root_json,
378 state->message_json);
380 json_free(&root_json);
384 *state->message_json = json_empty_object;
387 ret = json_add_object(&root_json,
389 &state->registrations_json);
391 json_free(&root_json);
395 state->registrations_json = json_empty_object;
397 json_str = json_to_string(frame, &root_json);
398 json_free(&root_json);
399 if (json_str == NULL) {
404 d_printf("%s\n", json_str);
407 #else /* not HAVE_JANSSON */
409 #endif /* not HAVE_JANSSON */
412 static void net_witness_scan_registrations_free(
413 struct net_witness_scan_registrations_state *state)
416 if (!json_is_invalid(&state->filters_json)) {
417 json_free(&state->filters_json);
419 if (!json_is_invalid(&state->registrations_json)) {
420 json_free(&state->registrations_json);
422 #endif /* HAVE_JANSSON */
424 net_witness_scan_registrations_regex_free(&state->net_name);
425 net_witness_scan_registrations_regex_free(&state->share_name);
426 net_witness_scan_registrations_regex_free(&state->ip_address);
427 net_witness_scan_registrations_regex_free(&state->client_computer);
431 static int dump_registration_json(struct json_object *registrations_json,
433 const struct rpcd_witness_registration *rg)
435 struct json_object jsobj = json_empty_object;
436 struct json_object flags_json = json_empty_object;
437 struct json_object context_json = json_empty_object;
438 struct json_object serverid_json = json_empty_object;
439 struct json_object auth_json = json_empty_object;
440 struct json_object connection_json = json_empty_object;
442 struct dom_sid_buf sid_buf;
445 jsobj = json_new_object();
446 if (json_is_invalid(&jsobj)) {
447 d_fprintf(stderr, _("error setting up JSON value\n"));
451 ret = json_add_flags32(&jsobj, "version", rg->version);
456 ret = json_add_string(&jsobj, "net_name", rg->net_name);
461 ret = json_add_string(&jsobj, "share_name", rg->share_name);
466 ret = json_add_string(&jsobj, "ip_address", rg->ip_address);
471 ret = json_add_string(&jsobj, "client_computer_name", rg->client_computer_name);
476 flags_json = json_new_object();
477 if (json_is_invalid(&flags_json)) {
481 ret = json_add_bool(&flags_json, "WITNESS_REGISTER_IP_NOTIFICATION",
482 (rg->flags & WITNESS_REGISTER_IP_NOTIFICATION) ?
488 ret = json_add_int(&flags_json, "int", rg->flags);
493 ret = json_add_flags32(&flags_json, "hex", rg->flags);
498 ret = json_add_object(&jsobj, "flags", &flags_json);
502 flags_json = json_empty_object;
504 ret = json_add_int(&jsobj, "timeout", rg->timeout);
509 context_json = json_new_object();
510 if (json_is_invalid(&context_json)) {
514 ret = json_add_int(&context_json, "handle_type", rg->context_handle.handle_type);
519 ret = json_add_guid(&context_json, "uuid", &rg->context_handle.uuid);
524 ret = json_add_object(&jsobj, "context_handle", &context_json);
528 context_json = json_empty_object;
530 serverid_json = json_new_object();
531 if (json_is_invalid(&serverid_json)) {
535 ret = json_add_int(&serverid_json, "pid", rg->server_id.pid);
540 ret = json_add_int(&serverid_json, "task_id", rg->server_id.task_id);
545 ret = json_add_int(&serverid_json, "vnn", rg->server_id.vnn);
550 ret = json_add_int(&serverid_json, "unique_id", rg->server_id.unique_id);
555 ret = json_add_object(&jsobj, "server_id", &serverid_json);
559 serverid_json = json_empty_object;
561 auth_json = json_new_object();
562 if (json_is_invalid(&auth_json)) {
566 ret = json_add_string(&auth_json, "account_name", rg->account_name);
571 ret = json_add_string(&auth_json, "domain_name", rg->domain_name);
576 ret = json_add_string(&auth_json,
578 dom_sid_str_buf(&rg->account_sid, &sid_buf));
583 ret = json_add_object(&jsobj, "auth", &auth_json);
587 auth_json = json_empty_object;
589 connection_json = json_new_object();
590 if (json_is_invalid(&connection_json)) {
594 ret = json_add_string(&connection_json, "local_address", rg->local_address);
599 ret = json_add_string(&connection_json, "remote_address", rg->remote_address);
604 ret = json_add_object(&jsobj, "connection", &connection_json);
608 connection_json = json_empty_object;
610 nttime_to_timeval(&tv, rg->registration_time);
611 ret = json_add_time(&jsobj, "registration_time", tv);
616 ret = json_add_object(registrations_json, key_str, &jsobj);
620 jsobj = json_empty_object;
623 if (!json_is_invalid(&connection_json)) {
624 json_free(&connection_json);
626 if (!json_is_invalid(&auth_json)) {
627 json_free(&auth_json);
629 if (!json_is_invalid(&serverid_json)) {
630 json_free(&serverid_json);
632 if (!json_is_invalid(&context_json)) {
633 json_free(&context_json);
635 if (!json_is_invalid(&flags_json)) {
636 json_free(&flags_json);
638 if (!json_is_invalid(&jsobj)) {
644 #endif /* HAVE_JANSSON */
646 static NTSTATUS net_witness_scan_registrations_dump_rg(
647 struct net_witness_scan_registrations_state *state,
648 const struct rpcd_witness_registration *rg)
650 struct net_context *c = state->c;
651 struct GUID_txt_buf key_buf;
652 const char *key_str = GUID_buf_string(&rg->context_handle.uuid, &key_buf);
658 ret = dump_registration_json(&state->registrations_json,
662 d_fprintf(stderr, "dump_registration_json(%s) failed\n",
664 return NT_STATUS_INTERNAL_ERROR;
666 #endif /* HAVE_JANSSON */
670 d_printf("%-36s %-20s %-15s %-20s %s\n",
673 rg->share_name ? rg->share_name : "''",
675 rg->client_computer_name);
680 static void net_witness_scan_registrations_parser(TDB_DATA key,
684 struct net_witness_scan_registrations_state *state =
685 (struct net_witness_scan_registrations_state *)private_data;
686 DATA_BLOB val_blob = data_blob_const(val.dptr, val.dsize);
687 struct rpcd_witness_registration rg;
688 enum ndr_err_code ndr_err;
689 TALLOC_CTX *frame = NULL;
692 if (val_blob.length == 0) {
696 frame = talloc_stackframe();
698 ndr_err = ndr_pull_struct_blob(&val_blob, frame, &rg,
699 (ndr_pull_flags_fn_t)ndr_pull_rpcd_witness_registration);
700 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
701 DBG_WARNING("Invalid record in rpcd_witness_registration.tdb:"
702 "key '%s' ndr_pull_struct_blob - %s\n",
704 ndr_errstr(ndr_err));
705 state->error = ndr_map_error2ntstatus(ndr_err);
710 if (!serverid_exists(&rg.server_id)) {
715 if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
716 NDR_PRINT_DEBUG(rpcd_witness_registration, &rg);
719 match = net_witness_scan_registrations_match(state, &rg);
720 if (!NT_STATUS_IS_OK(state->error)) {
729 match = state->action->match_fn(state->action->private_data, &rg);
735 state->error = state->action->process_fn(state->action->private_data, &rg);
736 if (NT_STATUS_IS_OK(state->error)) {
737 state->error = net_witness_scan_registrations_dump_rg(state,
743 static int net_witness_scan_registrations_traverse_cb(struct db_record *rec, void *private_data)
745 struct net_witness_scan_registrations_state *state =
746 (struct net_witness_scan_registrations_state *)private_data;
747 TDB_DATA key = dbwrap_record_get_key(rec);
748 TDB_DATA val = dbwrap_record_get_value(rec);
750 net_witness_scan_registrations_parser(key, val, private_data);
752 if (!NT_STATUS_IS_OK(state->error)) {
759 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)
763 struct net_witness_scan_registrations_state state = {
765 .message_json = message_json,
768 struct db_context *db = NULL;
772 db = net_witness_open_registration_db();
774 d_printf("net_witness_open_registration_db() failed\n");
778 ok = net_witness_scan_registrations_init(&state);
780 d_printf("net_witness_scan_registrations_init() failed\n");
784 if (c->opt_witness_registration != NULL) {
785 const char *key_str = c->opt_witness_registration;
786 DATA_BLOB key_blob = data_blob_string_const(key_str);
787 TDB_DATA key = make_tdb_data(key_blob.data, key_blob.length);
789 status = dbwrap_parse_record(db,
791 net_witness_scan_registrations_parser,
793 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
794 status = NT_STATUS_OK;
796 if (!NT_STATUS_IS_OK(status)) {
797 d_printf("dbwrap_parse_record(%s) failed: %s\n",
798 key_str, nt_errstr(status));
799 net_witness_scan_registrations_free(&state);
802 if (!NT_STATUS_IS_OK(state.error)) {
803 d_printf("net_witness_scan_registrations_parser(%s) failed: %s\n",
804 key_str, nt_errstr(state.error));
805 net_witness_scan_registrations_free(&state);
809 status = dbwrap_traverse_read(db,
810 net_witness_scan_registrations_traverse_cb,
813 if (!NT_STATUS_IS_OK(status)) {
814 d_printf("dbwrap_traverse_read() failed\n");
815 net_witness_scan_registrations_free(&state);
818 if (!NT_STATUS_IS_OK(state.error)) {
819 d_printf("net_witness_scan_registrations_traverse_cb() failed: %s\n",
820 nt_errstr(state.error));
821 net_witness_scan_registrations_free(&state);
826 ok = net_witness_scan_registrations_finish(&state);
828 d_printf("net_witness_scan_registrations_finish() failed\n");
832 net_witness_scan_registrations_free(&state);
836 struct net_witness_list_state {
837 struct net_context *c;
840 static bool net_witness_list_prepare_fn(void *private_data)
845 static bool net_witness_list_match_fn(void *private_data,
846 const struct rpcd_witness_registration *rg)
851 static NTSTATUS net_witness_list_process_fn(void *private_data,
852 const struct rpcd_witness_registration *rg)
857 static void net_witness_filter_usage(void)
859 d_printf(" Note: Only supported with clustering=yes!\n\n");
860 d_printf(" Machine readable output can be generated with "
861 "the following option:\n"
865 d_printf(" The selection of registrations can be limited by "
866 "the following options:\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"
872 " The following options all take a "
873 "POSIX Extended Regular Expression,\n"
874 " which can further filter the selection of "
876 " These options are applied as logical AND, "
878 " allows specifying multiple strings using "
881 " --witness-net-name=REGEX\n"
882 " This specifies the 'server name' the client\n"
883 " registered for monitoring.\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"
892 " --witness-ip-address=REGEX\n"
893 " This specifies the ip address the client\n"
894 " registered for monitoring.\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 "
904 static void net_witness_list_usage(void)
910 _("List witness registrations "
911 "from rpcd_witness_registration.tdb"));
912 net_witness_filter_usage();
915 static int net_witness_list(struct net_context *c, int argc, const char **argv)
917 TALLOC_CTX *frame = talloc_stackframe();
918 struct net_witness_list_state state = { .c = c, };
919 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,
927 if (c->display_usage) {
928 net_witness_list_usage();
933 net_witness_list_usage();
937 if (!lp_clustering()) {
938 d_printf("ERROR: Only supported with clustering=yes!\n\n");
942 ret = net_witness_scan_registrations(c, NULL, &action);
944 d_printf("net_witness_scan_registrations() failed\n");
954 struct net_witness_client_move_state {
955 struct net_context *c;
956 struct rpcd_witness_registration_updateB m;
960 static bool net_witness_client_move_prepare_fn(void *private_data)
962 struct net_witness_client_move_state *state =
963 (struct net_witness_client_move_state *)private_data;
965 if (state->headline != NULL) {
966 d_printf("%s\n", state->headline);
967 TALLOC_FREE(state->headline);
973 static bool net_witness_client_move_match_fn(void *private_data,
974 const struct rpcd_witness_registration *rg)
979 static NTSTATUS net_witness_client_move_process_fn(void *private_data,
980 const struct rpcd_witness_registration *rg)
982 struct net_witness_client_move_state *state =
983 (struct net_witness_client_move_state *)private_data;
984 struct net_context *c = state->c;
985 struct rpcd_witness_registration_updateB update = {
986 .context_handle = rg->context_handle,
987 .type = state->m.type,
988 .update = state->m.update,
990 DATA_BLOB blob = { .length = 0, };
991 enum ndr_err_code ndr_err;
994 if (state->headline != NULL) {
995 d_printf("%s\n", state->headline);
996 TALLOC_FREE(state->headline);
999 SMB_ASSERT(update.type != 0);
1001 if (DEBUGLVL(DBGLVL_DEBUG)) {
1002 NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
1005 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
1006 (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
1007 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1008 status = ndr_map_error2ntstatus(ndr_err);
1009 DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
1013 status = messaging_send(c->msg_ctx,
1015 MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
1017 if (!NT_STATUS_IS_OK(status)) {
1018 DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
1022 return NT_STATUS_OK;
1025 static void net_witness_update_usage(void)
1027 d_printf(" If the update should be applied to all registrations\n"
1028 " it needs to be explicitly specified:\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"
1037 static bool net_witness_verify_update_options(struct net_context *c)
1039 if (c->opt_witness_registration == NULL &&
1040 c->opt_witness_net_name == NULL &&
1041 c->opt_witness_share_name == NULL &&
1042 c->opt_witness_ip_address == NULL &&
1043 c->opt_witness_client_computer_name == NULL &&
1044 c->opt_witness_apply_to_all == 0)
1046 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");
1056 if (c->opt_witness_apply_to_all == 0) {
1060 if (c->opt_witness_registration != NULL ||
1061 c->opt_witness_net_name != NULL ||
1062 c->opt_witness_share_name != NULL ||
1063 c->opt_witness_ip_address != NULL ||
1064 c->opt_witness_client_computer_name != NULL)
1066 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");
1079 static void net_witness_move_usage(const char *name)
1081 d_printf(" The content of the %s notification contains ip addresses\n"
1082 " specified by (exactly one) of the following options:\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"
1091 " --witness-new-ip=IPADDRESS\n"
1092 " By specifying an IPADDRESS only the specified\n"
1093 " ip address is included in the response.\n"
1098 static bool net_witness_verify_move_options(struct net_context *c,
1105 *new_node = NONCLUSTER_VNN;
1109 ok = net_witness_verify_update_options(c);
1114 if (c->opt_witness_new_ip != NULL &&
1115 c->opt_witness_new_node != -2)
1117 d_printf("--witness-new-ip and "
1118 "--witness-new-node are not allowed together\n");
1122 if (c->opt_witness_new_ip == NULL &&
1123 c->opt_witness_new_node == -2)
1125 d_printf("--witness-new-ip or --witness-new-node required\n");
1129 if (c->opt_witness_new_node != -2) {
1130 *new_node = c->opt_witness_new_node;
1134 if (is_ipaddress_v4(c->opt_witness_new_ip)) {
1139 if (is_ipaddress_v6(c->opt_witness_new_ip)) {
1144 d_printf("Invalid ip address for --witness-new-ip=%s\n",
1145 c->opt_witness_new_ip);
1150 static bool net_witness_move_message_json(struct net_context *c,
1151 const char *msg_type,
1152 struct json_object *pmessage_json)
1154 struct json_object message_json = json_empty_object;
1157 message_json = json_new_object();
1158 if (json_is_invalid(&message_json)) {
1162 ret = json_add_string(&message_json,
1166 json_free(&message_json);
1170 if (c->opt_witness_new_ip != NULL) {
1171 ret = json_add_string(&message_json,
1173 c->opt_witness_new_ip);
1177 } else if (c->opt_witness_new_node != -1) {
1178 ret = json_add_int(&message_json,
1180 c->opt_witness_new_node);
1185 ret = json_add_bool(&message_json,
1193 *pmessage_json = message_json;
1196 #endif /* HAVE_JANSSON */
1198 static void net_witness_client_move_usage(void)
1201 "net witness client-move\n"
1204 _("Generate client move notifications for "
1205 "witness registrations to a new ip or node"));
1206 net_witness_filter_usage();
1207 net_witness_update_usage();
1208 net_witness_move_usage("CLIENT_MOVE");
1211 static int net_witness_client_move(struct net_context *c, int argc, const char **argv)
1213 TALLOC_CTX *frame = talloc_stackframe();
1214 struct net_witness_client_move_state state = { .c = c, };
1215 struct rpcd_witness_registration_updateB *m = &state.m;
1217 struct json_object _message_json = json_empty_object;
1218 #endif /* HAVE_JANSSON */
1219 struct json_object *message_json = NULL;
1220 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,
1227 const char *msg_type = NULL;
1228 uint32_t new_node = NONCLUSTER_VNN;
1229 bool is_ipv4 = false;
1230 bool is_ipv6 = false;
1233 if (c->display_usage) {
1234 net_witness_client_move_usage();
1239 net_witness_client_move_usage();
1243 if (!lp_clustering()) {
1244 d_printf("ERROR: Only supported with clustering=yes!\n\n");
1248 ok = net_witness_verify_move_options(c, &new_node, &is_ipv4, &is_ipv6);
1254 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_IPV4;
1255 m->update.client_move_to_ipv4.new_ipv4 = c->opt_witness_new_ip;
1256 msg_type = "CLIENT_MOVE_TO_IPV4";
1257 state.headline = talloc_asprintf(frame,
1258 "CLIENT_MOVE_TO_IPV4: %s",
1259 c->opt_witness_new_ip);
1260 if (state.headline == NULL) {
1263 } else if (is_ipv6) {
1264 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_IPV6;
1265 m->update.client_move_to_ipv6.new_ipv6 = c->opt_witness_new_ip;
1266 msg_type = "CLIENT_MOVE_TO_IPV6";
1267 state.headline = talloc_asprintf(frame,
1268 "CLIENT_MOVE_TO_IPV6: %s",
1269 c->opt_witness_new_ip);
1270 if (state.headline == NULL) {
1273 } else if (new_node != NONCLUSTER_VNN) {
1274 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_NODE;
1275 m->update.client_move_to_node.new_node = new_node;
1276 msg_type = "CLIENT_MOVE_TO_NODE";
1277 state.headline = talloc_asprintf(frame,
1278 "CLIENT_MOVE_TO_NODE: %u",
1280 if (state.headline == NULL) {
1284 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_CLIENT_MOVE_TO_NODE;
1285 m->update.client_move_to_node.new_node = NONCLUSTER_VNN;
1286 msg_type = "CLIENT_MOVE_TO_NODE";
1287 state.headline = talloc_asprintf(frame,
1288 "CLIENT_MOVE_TO_NODE: ALL");
1289 if (state.headline == NULL) {
1296 TALLOC_FREE(state.headline);
1298 ok = net_witness_move_message_json(c,
1302 d_printf("net_witness_move_message_json(%s) failed\n",
1307 message_json = &_message_json;
1309 #else /* not HAVE_JANSSON */
1311 #endif /* not HAVE_JANSSON */
1313 ret = net_witness_scan_registrations(c, message_json, &action);
1315 d_printf("net_witness_scan_registrations() failed\n");
1322 if (!json_is_invalid(&_message_json)) {
1323 json_free(&_message_json);
1325 #endif /* HAVE_JANSSON */
1330 struct net_witness_share_move_state {
1331 struct net_context *c;
1332 struct rpcd_witness_registration_updateB m;
1336 static bool net_witness_share_move_prepare_fn(void *private_data)
1338 struct net_witness_share_move_state *state =
1339 (struct net_witness_share_move_state *)private_data;
1341 if (state->headline != NULL) {
1342 d_printf("%s\n", state->headline);
1343 TALLOC_FREE(state->headline);
1349 static bool net_witness_share_move_match_fn(void *private_data,
1350 const struct rpcd_witness_registration *rg)
1352 if (rg->share_name == NULL) {
1359 static NTSTATUS net_witness_share_move_process_fn(void *private_data,
1360 const struct rpcd_witness_registration *rg)
1362 struct net_witness_share_move_state *state =
1363 (struct net_witness_share_move_state *)private_data;
1364 struct net_context *c = state->c;
1365 struct rpcd_witness_registration_updateB update = {
1366 .context_handle = rg->context_handle,
1367 .type = state->m.type,
1368 .update = state->m.update,
1370 DATA_BLOB blob = { .length = 0, };
1371 enum ndr_err_code ndr_err;
1374 SMB_ASSERT(update.type != 0);
1376 if (DEBUGLVL(DBGLVL_DEBUG)) {
1377 NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
1380 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
1381 (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
1382 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1383 status = ndr_map_error2ntstatus(ndr_err);
1384 DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
1388 status = messaging_send(c->msg_ctx,
1390 MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
1392 if (!NT_STATUS_IS_OK(status)) {
1393 DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
1397 return NT_STATUS_OK;
1400 static void net_witness_share_move_usage(void)
1403 "net witness share-move\n"
1406 _("Generate share move notifications for "
1407 "witness registrations to a new ip or node"));
1408 net_witness_filter_usage();
1409 net_witness_update_usage();
1410 d_printf(" Note: This only applies to registrations with "
1411 "a non empty share name!\n\n");
1412 net_witness_move_usage("SHARE_MOVE");
1415 static int net_witness_share_move(struct net_context *c, int argc, const char **argv)
1417 TALLOC_CTX *frame = talloc_stackframe();
1418 struct net_witness_share_move_state state = { .c = c, };
1419 struct rpcd_witness_registration_updateB *m = &state.m;
1421 struct json_object _message_json = json_empty_object;
1422 #endif /* HAVE_JANSSON */
1423 struct json_object *message_json = NULL;
1424 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,
1431 const char *msg_type = NULL;
1432 uint32_t new_node = NONCLUSTER_VNN;
1433 bool is_ipv4 = false;
1434 bool is_ipv6 = false;
1437 if (c->display_usage) {
1438 net_witness_share_move_usage();
1443 net_witness_share_move_usage();
1447 if (!lp_clustering()) {
1448 d_printf("ERROR: Only supported with clustering=yes!\n\n");
1452 ok = net_witness_verify_move_options(c, &new_node, &is_ipv4, &is_ipv6);
1458 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_IPV4;
1459 m->update.share_move_to_ipv4.new_ipv4 = c->opt_witness_new_ip;
1460 msg_type = "SHARE_MOVE_TO_IPV4";
1461 state.headline = talloc_asprintf(frame,
1462 "SHARE_MOVE_TO_IPV4: %s",
1463 c->opt_witness_new_ip);
1464 if (state.headline == NULL) {
1467 } else if (is_ipv6) {
1468 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_IPV6;
1469 m->update.share_move_to_ipv6.new_ipv6 = c->opt_witness_new_ip;
1470 msg_type = "SHARE_MOVE_TO_IPV6";
1471 state.headline = talloc_asprintf(frame,
1472 "SHARE_MOVE_TO_IPV6: %s",
1473 c->opt_witness_new_ip);
1474 if (state.headline == NULL) {
1477 } else if (new_node != NONCLUSTER_VNN) {
1478 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_NODE;
1479 m->update.share_move_to_node.new_node = new_node;
1480 msg_type = "SHARE_MOVE_TO_NODE";
1481 state.headline = talloc_asprintf(frame,
1482 "SHARE_MOVE_TO_NODE: %u",
1484 if (state.headline == NULL) {
1488 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_SHARE_MOVE_TO_NODE;
1489 m->update.share_move_to_node.new_node = NONCLUSTER_VNN;
1490 msg_type = "SHARE_MOVE_TO_NODE";
1491 state.headline = talloc_asprintf(frame,
1492 "SHARE_MOVE_TO_NODE: ALL");
1493 if (state.headline == NULL) {
1500 TALLOC_FREE(state.headline);
1502 ok = net_witness_move_message_json(c,
1506 d_printf("net_witness_move_message_json(%s) failed\n",
1511 message_json = &_message_json;
1513 #else /* not HAVE_JANSSON */
1515 #endif /* not HAVE_JANSSON */
1517 ret = net_witness_scan_registrations(c, message_json, &action);
1519 d_printf("net_witness_scan_registrations() failed\n");
1526 if (!json_is_invalid(&_message_json)) {
1527 json_free(&_message_json);
1529 #endif /* HAVE_JANSSON */
1534 struct net_witness_force_unregister_state {
1535 struct net_context *c;
1536 struct rpcd_witness_registration_updateB m;
1540 static bool net_witness_force_unregister_prepare_fn(void *private_data)
1542 struct net_witness_force_unregister_state *state =
1543 (struct net_witness_force_unregister_state *)private_data;
1545 if (state->headline != NULL) {
1546 d_printf("%s\n", state->headline);
1547 TALLOC_FREE(state->headline);
1553 static bool net_witness_force_unregister_match_fn(void *private_data,
1554 const struct rpcd_witness_registration *rg)
1559 static NTSTATUS net_witness_force_unregister_process_fn(void *private_data,
1560 const struct rpcd_witness_registration *rg)
1562 struct net_witness_force_unregister_state *state =
1563 (struct net_witness_force_unregister_state *)private_data;
1564 struct net_context *c = state->c;
1565 struct rpcd_witness_registration_updateB update = {
1566 .context_handle = rg->context_handle,
1567 .type = state->m.type,
1568 .update = state->m.update,
1570 DATA_BLOB blob = { .length = 0, };
1571 enum ndr_err_code ndr_err;
1574 SMB_ASSERT(update.type != 0);
1576 if (DEBUGLVL(DBGLVL_DEBUG)) {
1577 NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
1580 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
1581 (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
1582 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1583 status = ndr_map_error2ntstatus(ndr_err);
1584 DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
1588 status = messaging_send(c->msg_ctx,
1590 MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
1592 if (!NT_STATUS_IS_OK(status)) {
1593 DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
1597 return NT_STATUS_OK;
1600 static void net_witness_force_unregister_usage(void)
1603 "net witness force-unregister\n"
1606 _("Force unregistrations for witness registrations"));
1607 net_witness_filter_usage();
1608 net_witness_update_usage();
1609 d_printf(" The selected registrations are removed on "
1611 " any pending AsyncNotify request will get "
1612 "a NOT_FOUND error.\n"
1614 " Typically this triggers a clean re-registration "
1619 static int net_witness_force_unregister(struct net_context *c, int argc, const char **argv)
1621 TALLOC_CTX *frame = talloc_stackframe();
1622 struct net_witness_force_unregister_state state = { .c = c, };
1623 struct rpcd_witness_registration_updateB *m = &state.m;
1625 struct json_object _message_json = json_empty_object;
1626 #endif /* HAVE_JANSSON */
1627 struct json_object *message_json = NULL;
1628 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,
1637 if (c->display_usage) {
1638 net_witness_force_unregister_usage();
1643 net_witness_force_unregister_usage();
1647 if (!lp_clustering()) {
1648 d_printf("ERROR: Only supported with clustering=yes!\n\n");
1652 ok = net_witness_verify_update_options(c);
1657 m->type = RPCD_WITNESS_REGISTRATION_UPDATE_FORCE_UNREGISTER;
1659 state.headline = talloc_asprintf(frame, "FORCE_UNREGISTER:");
1660 if (state.headline == NULL) {
1666 TALLOC_FREE(state.headline);
1668 _message_json = json_new_object();
1669 if (json_is_invalid(&_message_json)) {
1673 ret = json_add_string(&_message_json,
1675 "FORCE_UNREGISTER");
1680 message_json = &_message_json;
1682 #endif /* HAVE_JANSSON */
1684 ret = net_witness_scan_registrations(c, message_json, &action);
1686 d_printf("net_witness_scan_registrations() failed\n");
1693 if (!json_is_invalid(&_message_json)) {
1694 json_free(&_message_json);
1696 #endif /* HAVE_JANSSON */
1701 struct net_witness_force_response_state {
1702 struct net_context *c;
1703 struct rpcd_witness_registration_updateB m;
1705 struct json_object json_root;
1706 #endif /* HAVE_JANSSON */
1711 static NTSTATUS net_witness_force_response_parse_rc(
1712 struct net_witness_force_response_state *state,
1714 TALLOC_CTX *mem_ctx,
1716 union witness_notifyResponse_message *message)
1718 struct witness_ResourceChange *rc = &message->resource_change;
1719 json_t *jsctype = NULL;
1721 json_t *jscname = NULL;
1722 const char *cname = NULL;
1724 if (!json_is_object(jsmsg)) {
1725 DBG_ERR("'message[%zu]' needs to be an object\n", mi);
1726 return NT_STATUS_INVALID_PARAMETER;
1729 jsctype = json_object_get(jsmsg, "type");
1730 if (jsctype == NULL) {
1731 DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1732 return NT_STATUS_INVALID_PARAMETER;
1734 if (!json_is_integer(jsctype)) {
1735 DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1736 return NT_STATUS_INVALID_PARAMETER;
1738 ctype = json_integer_value(jsctype);
1740 jscname = json_object_get(jsmsg, "name");
1741 if (jscname == NULL) {
1742 DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1743 return NT_STATUS_INVALID_PARAMETER;
1745 if (!json_is_string(jscname)) {
1746 DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1747 return NT_STATUS_INVALID_PARAMETER;
1749 cname = json_string_value(jscname);
1752 rc->name = talloc_strdup(mem_ctx, cname);
1753 if (rc->name == NULL) {
1754 return NT_STATUS_NO_MEMORY;
1757 return NT_STATUS_OK;
1760 static NTSTATUS net_witness_force_response_parse_ipl(
1761 struct net_witness_force_response_state *state,
1763 TALLOC_CTX *mem_ctx,
1765 union witness_notifyResponse_message *message)
1767 struct witness_IPaddrInfoList *ipl =
1768 &message->client_move;
1769 size_t ai, num_addrs = 0;
1770 struct witness_IPaddrInfo *addrs = NULL;
1772 if (!json_is_array(jsmsg)) {
1773 DBG_ERR("'messages[%zu]' needs to be an array\n", mi);
1774 return NT_STATUS_INVALID_PARAMETER;
1777 num_addrs = json_array_size(jsmsg);
1778 if (num_addrs > UINT32_MAX) {
1779 DBG_ERR("Too many elements in 'messages[%zu]': %zu\n",
1781 return NT_STATUS_INVALID_PARAMETER;
1784 addrs = talloc_zero_array(mem_ctx,
1785 struct witness_IPaddrInfo,
1787 if (addrs == NULL) {
1788 return NT_STATUS_NO_MEMORY;
1791 for (ai = 0; ai < num_addrs; ai++) {
1792 struct witness_IPaddrInfo *info =
1794 json_t *jsaddr = json_array_get(jsmsg, ai);
1795 json_t *jsflags = NULL;
1797 json_t *jsipv4 = NULL;
1798 const char *ipv4 = NULL;
1799 json_t *jsipv6 = NULL;
1800 const char *ipv6 = NULL;
1802 if (!json_is_object(jsaddr)) {
1803 DBG_ERR("'messages[%zu][%zu]' needs to be an object\n",
1805 return NT_STATUS_INVALID_PARAMETER;
1808 jsflags = json_object_get(jsaddr, "flags");
1809 if (jsflags == NULL) {
1810 DBG_ERR("'messages[%zu][%zu]['flags']' missing\n",
1812 return NT_STATUS_INVALID_PARAMETER;
1814 if (!json_is_integer(jsflags)) {
1815 DBG_ERR("'messages[%zu][%zu]['flags']' "
1816 "needs to be an integer\n",
1818 return NT_STATUS_INVALID_PARAMETER;
1820 flags = json_integer_value(jsflags);
1822 jsipv4 = json_object_get(jsaddr, "ipv4");
1823 if (jsipv4 != NULL) {
1824 if (!json_is_string(jsipv4)) {
1825 DBG_ERR("'messages[%zu][%zu]['ipv4']' "
1826 "needs to be a string\n",
1828 return NT_STATUS_INVALID_PARAMETER;
1830 ipv4 = json_string_value(jsipv4);
1831 if (!is_ipaddress_v4(ipv4)) {
1832 DBG_ERR("'messages[%zu][%zu]['ipv4']' "
1833 "needs to be a valid ipv4 address\n",
1835 return NT_STATUS_INVALID_PARAMETER;
1841 jsipv6 = json_object_get(jsaddr, "ipv6");
1842 if (jsipv6 != NULL) {
1843 if (!json_is_string(jsipv6)) {
1844 DBG_ERR("'messages[%zu][%zu]['ipv6']' "
1845 "needs to be a string\n",
1847 DBG_ERR("%s: INVALID_PARAMETER\n", __location__);
1848 return NT_STATUS_INVALID_PARAMETER;
1850 ipv6 = json_string_value(jsipv6);
1851 if (!is_ipaddress_v6(ipv6)) {
1852 DBG_ERR("'messages[%zu][%zu]['ipv4']' "
1853 "needs to be a valid ipv6 address\n",
1855 return NT_STATUS_INVALID_PARAMETER;
1861 info->flags = flags;
1862 info->ipv4 = talloc_strdup(addrs, ipv4);
1863 if (info->ipv4 == NULL) {
1864 return NT_STATUS_NO_MEMORY;
1866 info->ipv6 = talloc_strdup(addrs, ipv6);
1867 if (info->ipv6 == NULL) {
1868 return NT_STATUS_NO_MEMORY;
1872 ipl->num = num_addrs;
1875 return NT_STATUS_OK;
1877 #endif /* HAVE_JANSSON */
1879 static NTSTATUS net_witness_force_response_parse(struct net_witness_force_response_state *state)
1882 struct net_context *c = state->c;
1883 struct rpcd_witness_registration_update_force_response *force = NULL;
1884 struct witness_notifyResponse *response = NULL;
1885 size_t mi, num_messages = 0;
1886 union witness_notifyResponse_message *messages = NULL;
1887 json_t *jsroot = NULL;
1888 json_t *jsresult = NULL;
1889 json_t *jsresponse = NULL;
1890 json_t *jstype = NULL;
1891 json_t *jsmessages = NULL;
1893 if (c->opt_witness_forced_response != NULL) {
1894 const char *str = c->opt_witness_forced_response;
1895 size_t flags = JSON_REJECT_DUPLICATES;
1896 json_error_t jserror;
1898 jsroot = json_loads(str, flags, &jserror);
1899 if (jsroot == NULL) {
1900 DBG_ERR("Invalid JSON in "
1901 "--witness-forced-response='%s'\n",
1903 return NT_STATUS_INVALID_PARAMETER;
1905 state->json_root = (struct json_object) {
1911 state->m.type = RPCD_WITNESS_REGISTRATION_UPDATE_FORCE_RESPONSE;
1912 force = &state->m.update.force_response;
1913 force->response = NULL;
1914 force->result = WERR_OK;
1916 if (jsroot == NULL) {
1917 return NT_STATUS_OK;
1920 jsresult = json_object_get(jsroot, "result");
1921 if (jsresult != NULL) {
1922 int val_type = json_typeof(jsresult);
1925 case JSON_INTEGER: {
1926 json_int_t val = json_integer_value(jsresult);
1928 if (val > UINT32_MAX) {
1929 DBG_ERR("Invalid 'result' value: %d\n",
1931 return NT_STATUS_INVALID_PARAMETER;
1934 DBG_ERR("invalid 'result' value: %d\n",
1936 return NT_STATUS_INVALID_PARAMETER;
1939 force->result = W_ERROR(val);
1942 DBG_ERR("Invalid json type for 'result' - needs integer\n");
1943 return NT_STATUS_INVALID_PARAMETER;
1947 jsresponse = json_object_get(jsroot, "response");
1948 if (jsresponse == NULL) {
1949 return NT_STATUS_OK;
1952 if (!json_is_object(jsresponse)) {
1953 DBG_ERR("Invalid json type 'response' needs object\n");
1954 return NT_STATUS_INVALID_PARAMETER;
1957 response = talloc_zero(talloc_tos(), struct witness_notifyResponse);
1958 if (response == NULL) {
1959 return NT_STATUS_NO_MEMORY;
1962 jstype = json_object_get(jsresponse, "type");
1963 if (jstype == NULL) {
1964 DBG_ERR("Missing 'type' element in 'response'\n");
1965 return NT_STATUS_INVALID_PARAMETER;
1968 int val_type = json_typeof(jstype);
1971 case JSON_INTEGER: {
1972 json_int_t val = json_integer_value(jstype);
1974 if (val > WITNESS_NOTIFY_IP_CHANGE) {
1975 DBG_ERR("invalid 'type' value in 'response': "
1977 return NT_STATUS_INVALID_PARAMETER;
1979 if (val < WITNESS_NOTIFY_RESOURCE_CHANGE) {
1980 DBG_ERR("invalid 'type' value in 'response': "
1982 return NT_STATUS_INVALID_PARAMETER;
1985 response->type = val;
1988 DBG_ERR("Invalid json type for 'type' in 'response' "
1989 "- needs integer\n");
1990 return NT_STATUS_INVALID_PARAMETER;
1994 force->response = response;
1996 jsmessages = json_object_get(jsresponse, "messages");
1997 if (jsmessages == NULL) {
1998 return NT_STATUS_OK;
2001 if (!json_is_array(jsmessages)) {
2002 DBG_ERR("'messages' in 'response' needs to be an array\n");
2003 return NT_STATUS_INVALID_PARAMETER;
2006 num_messages = json_array_size(jsmessages);
2007 if (num_messages > UINT32_MAX) {
2008 DBG_ERR("Too many elements in 'messages': %zu\n",
2010 return NT_STATUS_INVALID_PARAMETER;
2013 messages = talloc_zero_array(response,
2014 union witness_notifyResponse_message,
2016 if (messages == NULL) {
2017 return NT_STATUS_NO_MEMORY;
2020 for (mi = 0; mi < num_messages; mi++) {
2021 json_t *jsmsg = json_array_get(jsmessages, mi);
2022 union witness_notifyResponse_message *message = &messages[mi];
2025 switch (response->type) {
2026 case WITNESS_NOTIFY_RESOURCE_CHANGE:
2027 status = net_witness_force_response_parse_rc(state,
2032 if (!NT_STATUS_IS_OK(status)) {
2034 "net_witness_force_response_parse_rc";
2035 DBG_ERR("%s failed: %s\n",
2036 fn, nt_errstr(status));
2041 case WITNESS_NOTIFY_CLIENT_MOVE:
2042 case WITNESS_NOTIFY_SHARE_MOVE:
2043 case WITNESS_NOTIFY_IP_CHANGE:
2044 status = net_witness_force_response_parse_ipl(state,
2049 if (!NT_STATUS_IS_OK(status)) {
2051 "net_witness_force_response_parse_ipl";
2052 DBG_ERR("%s failed: %s\n",
2053 fn, nt_errstr(status));
2061 response->num = num_messages;
2062 response->messages = messages;
2064 return NT_STATUS_OK;
2065 #else /* not HAVE_JANSSON */
2066 d_fprintf(stderr, _("JSON support not available\n"));
2067 return NT_STATUS_NOT_IMPLEMENTED;
2068 #endif /* not HAVE_JANSSON */
2071 static bool net_witness_force_response_prepare_fn(void *private_data)
2073 struct net_witness_force_response_state *state =
2074 (struct net_witness_force_response_state *)private_data;
2076 if (state->headline != NULL) {
2077 d_printf("%s\n", state->headline);
2078 TALLOC_FREE(state->headline);
2084 static bool net_witness_force_response_match_fn(void *private_data,
2085 const struct rpcd_witness_registration *rg)
2090 static NTSTATUS net_witness_force_response_process_fn(void *private_data,
2091 const struct rpcd_witness_registration *rg)
2093 struct net_witness_force_response_state *state =
2094 (struct net_witness_force_response_state *)private_data;
2095 struct net_context *c = state->c;
2096 struct rpcd_witness_registration_updateB update = {
2097 .context_handle = rg->context_handle,
2098 .type = state->m.type,
2099 .update = state->m.update,
2101 DATA_BLOB blob = { .length = 0, };
2102 enum ndr_err_code ndr_err;
2105 SMB_ASSERT(update.type != 0);
2107 if (DEBUGLVL(DBGLVL_DEBUG)) {
2108 NDR_PRINT_DEBUG(rpcd_witness_registration_updateB, &update);
2111 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &update,
2112 (ndr_push_flags_fn_t)ndr_push_rpcd_witness_registration_updateB);
2113 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2114 status = ndr_map_error2ntstatus(ndr_err);
2115 DBG_ERR("ndr_push_struct_blob - %s\n", nt_errstr(status));
2119 status = messaging_send(c->msg_ctx,
2121 MSG_RPCD_WITNESS_REGISTRATION_UPDATE,
2123 if (!NT_STATUS_IS_OK(status)) {
2124 DBG_ERR("messaging_send() - %s\n", nt_errstr(status));
2128 return NT_STATUS_OK;
2131 static void net_witness_force_response_usage(void)
2134 "net witness force-response\n"
2137 _("Force an AsyncNotify response based on "
2138 "json input (mostly for testing)"));
2139 net_witness_filter_usage();
2140 net_witness_update_usage();
2141 d_printf(" Note this is designed for testing and debugging!\n"
2143 " In short it is not designed to be used by "
2145 " but developers and automated tests.\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"
2151 " --witness-forced-response=JSON\n"
2152 " This allows the generation of very complex\n"
2153 " witness_notifyResponse structures.\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"
2159 " Simple examples are:\n"
2161 "# Resource Change:\n%s\n"
2163 "# Client Move:\n%s\n"
2165 "# Share Move:\n%s\n"
2167 "# IP Change:\n%s\n"
2169 "'{ \"result\": 0, \"response\": { \"type\": 1, "
2170 "\"messages\": [ { "
2172 "\"name\": \"some-resource-name\" "
2175 "'{ \"result\": 0, \"response\": { \"type\": 2, "
2179 "\"ipv4\": \"10.0.10.1\" "
2183 "'{ \"result\": 0, \"response\": { \"type\": 3, "
2187 "\"ipv4\": \"10.0.10.1\" "
2191 "'{ \"result\": 0, \"response\": { \"type\": 4, "
2195 "\"ipv4\": \"10.0.10.1\" "
2201 static int net_witness_force_response(struct net_context *c, int argc, const char **argv)
2203 TALLOC_CTX *frame = talloc_stackframe();
2204 struct net_witness_force_response_state state = { .c = c, };
2206 struct json_object _message_json = json_empty_object;
2207 #endif /* HAVE_JANSSON */
2208 struct json_object *message_json = NULL;
2209 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,
2219 if (c->display_usage) {
2220 net_witness_force_response_usage();
2225 net_witness_force_response_usage();
2229 if (!lp_clustering()) {
2230 d_printf("ERROR: Only supported with clustering=yes!\n\n");
2234 ok = net_witness_verify_update_options(c);
2239 status = net_witness_force_response_parse(&state);
2240 if (!NT_STATUS_IS_OK(status)) {
2241 d_printf("net_witness_force_response_parse failed: %s\n",
2246 state.headline = talloc_asprintf(frame, "FORCE_RESPONSE:%s%s",
2247 c->opt_witness_forced_response != NULL ?
2249 c->opt_witness_forced_response != NULL ?
2250 c->opt_witness_forced_response : "");
2252 if (state.headline == NULL) {
2258 TALLOC_FREE(state.headline);
2260 _message_json = json_new_object();
2261 if (json_is_invalid(&_message_json)) {
2265 ret = json_add_string(&_message_json,
2272 if (!json_is_invalid(&state.json_root)) {
2273 ret = json_add_object(&_message_json,
2279 state.json_root = json_empty_object;
2281 message_json = &_message_json;
2283 #endif /* HAVE_JANSSON */
2285 ret = net_witness_scan_registrations(c, message_json, &action);
2287 d_printf("net_witness_scan_registrations() failed\n");
2294 if (!json_is_invalid(&_message_json)) {
2295 json_free(&_message_json);
2297 if (!json_is_invalid(&state.json_root)) {
2298 json_free(&state.json_root);
2300 #endif /* HAVE_JANSSON */
2305 int net_witness(struct net_context *c, int argc, const char **argv)
2307 struct functable func[] = {
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"),
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"),
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"),
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"),
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)"),
2357 {NULL, NULL, 0, NULL, NULL}
2360 return net_run_function(c, argc, argv, "net witness", func);