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
);