LCOV - code coverage report
Current view: top level - source3/utils - net_witness.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 0 1108 0.0 %
Date: 2024-04-21 15:09:00 Functions: 0 48 0.0 %

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

Generated by: LCOV version 1.14