Line data Source code
1 : /*
2 : * Samba Unix/Linux SMB client library
3 : * Json output
4 : * Copyright (C) Jule Anger 2022
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 "smbprofile.h"
22 : #include "lib/util/time_basic.h"
23 : #include "conn_tdb.h"
24 : #include "session.h"
25 : #include "librpc/gen_ndr/smbXsrv.h"
26 : #include "librpc/gen_ndr/open_files.h"
27 : #include "status_json.h"
28 : #include "../libcli/security/security.h"
29 : #include "status.h"
30 : #include "lib/util/server_id.h"
31 : #include "lib/util/string_wrappers.h"
32 :
33 : #include <jansson.h>
34 : #include "audit_logging.h" /* various JSON helpers */
35 : #include "auth/common_auth.h"
36 :
37 18 : int add_general_information_to_json(struct traverse_state *state)
38 : {
39 : int result;
40 :
41 18 : result = json_add_timestamp(&state->root_json);
42 18 : if (result < 0) {
43 0 : return -1;
44 : }
45 :
46 18 : result = json_add_string(&state->root_json, "version", samba_version_string());
47 18 : if (result < 0) {
48 0 : return -1;
49 : }
50 :
51 18 : result = json_add_string(&state->root_json, "smb_conf", get_dyn_CONFIGFILE());
52 18 : if (result < 0) {
53 0 : return -1;
54 : }
55 :
56 18 : return 0;
57 : }
58 :
59 12 : static int add_server_id_to_json(struct json_object *parent_json,
60 : const struct server_id server_id)
61 : {
62 : struct json_object sub_json;
63 12 : char *pid_str = NULL;
64 12 : char *task_id_str = NULL;
65 12 : char *vnn_str = NULL;
66 12 : char *unique_id_str = NULL;
67 : int result;
68 :
69 12 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
70 12 : if (tmp_ctx == NULL) {
71 0 : return -1;
72 : }
73 :
74 12 : sub_json = json_new_object();
75 12 : if (json_is_invalid(&sub_json)) {
76 0 : goto failure;
77 : }
78 :
79 12 : pid_str = talloc_asprintf(
80 12 : tmp_ctx, "%lu", (unsigned long)server_id.pid);
81 12 : result = json_add_string(&sub_json, "pid", pid_str);
82 12 : if (result < 0) {
83 0 : goto failure;
84 : }
85 12 : task_id_str = talloc_asprintf(tmp_ctx, "%u", server_id.task_id);
86 12 : result = json_add_string(&sub_json, "task_id", task_id_str);
87 12 : if (result < 0) {
88 0 : goto failure;
89 : }
90 12 : vnn_str = talloc_asprintf(tmp_ctx, "%u", server_id.vnn);
91 12 : result = json_add_string(&sub_json, "vnn", vnn_str);
92 12 : if (result < 0) {
93 0 : goto failure;
94 : }
95 12 : unique_id_str = talloc_asprintf(
96 12 : tmp_ctx, "%"PRIu64, server_id.unique_id);
97 12 : result = json_add_string(&sub_json, "unique_id", unique_id_str);
98 12 : if (result < 0) {
99 0 : goto failure;
100 : }
101 :
102 12 : result = json_add_object(parent_json, "server_id", &sub_json);
103 12 : if (result < 0) {
104 0 : goto failure;
105 : }
106 :
107 12 : TALLOC_FREE(tmp_ctx);
108 12 : return 0;
109 0 : failure:
110 0 : json_free(&sub_json);
111 0 : TALLOC_FREE(tmp_ctx);
112 0 : return -1;
113 : }
114 :
115 : struct mask2txt {
116 : uint32_t mask;
117 : const char *string_desc;
118 : };
119 :
120 : /*
121 : * Convert a mask of some sort (access, oplock, leases),
122 : * to key/value pairs in a JSON object.
123 : */
124 12 : static int map_mask_to_json(struct json_object *root_json,
125 : uint32_t tomap,
126 : const struct mask2txt *table)
127 : {
128 12 : const struct mask2txt *a = NULL;
129 12 : int result = 0;
130 :
131 92 : for (a = table; a->string_desc != 0; a++) {
132 80 : result = json_add_bool(root_json, a->string_desc,
133 80 : (tomap & a->mask) ? true : false);
134 :
135 80 : if (result < 0) {
136 0 : return result;
137 : }
138 80 : tomap &= ~a->mask;
139 : }
140 :
141 : /* Assert we know about all requested "tomap" values */
142 12 : SMB_ASSERT(tomap == 0);
143 :
144 12 : return 0;
145 : }
146 :
147 : static const struct mask2txt access_mask[] = {
148 : {FILE_READ_DATA, "READ_DATA"},
149 : {FILE_WRITE_DATA, "WRITE_DATA"},
150 : {FILE_APPEND_DATA, "APPEND_DATA"},
151 : {FILE_READ_EA, "READ_EA"},
152 : {FILE_WRITE_EA, "WRITE_EA"},
153 : {FILE_EXECUTE, "EXECUTE"},
154 : {FILE_READ_ATTRIBUTES, "READ_ATTRIBUTES"},
155 : {FILE_WRITE_ATTRIBUTES, "WRITE_ATTRIBUTES"},
156 : {FILE_DELETE_CHILD, "DELETE_CHILD"},
157 : {SEC_STD_DELETE, "DELETE"},
158 : {SEC_STD_READ_CONTROL, "READ_CONTROL"},
159 : {SEC_STD_WRITE_DAC, "WRITE_DAC"},
160 : {SEC_STD_SYNCHRONIZE, "SYNCHRONIZE"},
161 : {SEC_FLAG_SYSTEM_SECURITY, "ACCESS_SYSTEM_SECURITY"},
162 : {0, NULL}
163 : };
164 :
165 : static const struct mask2txt oplock_mask[] = {
166 : {EXCLUSIVE_OPLOCK, "EXCLUSIVE"},
167 : {BATCH_OPLOCK, "BATCH"},
168 : {LEVEL_II_OPLOCK, "LEVEL_II"},
169 : {LEASE_OPLOCK, "LEASE"},
170 : {0, NULL}
171 : };
172 :
173 : static const struct mask2txt sharemode_mask[] = {
174 : {FILE_SHARE_READ, "READ"},
175 : {FILE_SHARE_WRITE, "WRITE"},
176 : {FILE_SHARE_DELETE, "DELETE"},
177 : {0, NULL}
178 : };
179 :
180 : static const struct mask2txt lease_mask[] = {
181 : {SMB2_LEASE_READ, "READ"},
182 : {SMB2_LEASE_WRITE, "WRITE"},
183 : {SMB2_LEASE_HANDLE, "HANDLE"},
184 : {0, NULL}
185 : };
186 :
187 878 : int add_profile_item_to_json(struct traverse_state *state,
188 : const char *section,
189 : const char *subsection,
190 : const char *key,
191 : uintmax_t value)
192 : {
193 878 : struct json_object section_json = {
194 : .valid = false,
195 : };
196 878 : struct json_object subsection_json = {
197 : .valid = false,
198 : };
199 878 : int result = 0;
200 :
201 878 : section_json = json_get_object(&state->root_json, section);
202 878 : if (json_is_invalid(§ion_json)) {
203 0 : goto failure;
204 : }
205 878 : subsection_json = json_get_object(§ion_json, subsection);
206 878 : if (json_is_invalid(&subsection_json)) {
207 0 : goto failure;
208 : }
209 :
210 878 : result = json_add_int(&subsection_json, key, value);
211 878 : if (result < 0) {
212 0 : goto failure;
213 : }
214 :
215 878 : result = json_update_object(§ion_json, subsection, &subsection_json);
216 878 : if (result < 0) {
217 0 : goto failure;
218 : }
219 878 : result = json_update_object(&state->root_json, section, §ion_json);
220 878 : if (result < 0) {
221 0 : goto failure;
222 : }
223 :
224 878 : return 0;
225 0 : failure:
226 0 : json_free(§ion_json);
227 0 : json_free(&subsection_json);
228 0 : return -1;
229 : }
230 :
231 16 : int add_section_to_json(struct traverse_state *state,
232 : const char *key)
233 : {
234 : struct json_object empty_json;
235 : int result;
236 :
237 16 : empty_json = json_new_object();
238 16 : if (json_is_invalid(&empty_json)) {
239 0 : return -1;
240 : }
241 :
242 16 : result = json_add_object(&state->root_json, key, &empty_json);
243 16 : if (result < 0) {
244 0 : return -1;
245 : }
246 :
247 16 : return result;
248 : }
249 :
250 16 : static int add_crypto_to_json(struct json_object *parent_json,
251 : const char *key,
252 : const char *cipher,
253 : enum crypto_degree degree)
254 : {
255 : struct json_object sub_json;
256 : const char *degree_str;
257 : int result;
258 :
259 16 : if (degree == CRYPTO_DEGREE_NONE) {
260 12 : degree_str = "none";
261 4 : } else if (degree == CRYPTO_DEGREE_PARTIAL) {
262 4 : degree_str = "partial";
263 : } else {
264 0 : degree_str = "full";
265 : }
266 :
267 16 : sub_json = json_new_object();
268 16 : if (json_is_invalid(&sub_json)) {
269 0 : goto failure;
270 : }
271 :
272 16 : result = json_add_string(&sub_json, "cipher", cipher);
273 16 : if (result < 0) {
274 0 : goto failure;
275 : }
276 16 : result = json_add_string(&sub_json, "degree", degree_str);
277 16 : if (result < 0) {
278 0 : goto failure;
279 : }
280 16 : result = json_add_object(parent_json, key, &sub_json);
281 16 : if (result < 0) {
282 0 : goto failure;
283 : }
284 :
285 16 : return 0;
286 0 : failure:
287 0 : json_free(&sub_json);
288 0 : return -1;
289 : }
290 :
291 4 : static int add_channel_to_json(struct json_object *parent_json,
292 : const struct smbXsrv_channel_global0 *channel)
293 : {
294 4 : TALLOC_CTX *frame = talloc_stackframe();
295 : struct json_object sub_json;
296 4 : char *id_str = NULL;
297 : struct timeval tv;
298 : struct timeval_buf tv_buf;
299 4 : char *time_str = NULL;
300 : int result;
301 :
302 4 : sub_json = json_new_object();
303 4 : if (json_is_invalid(&sub_json)) {
304 0 : goto failure;
305 : }
306 :
307 4 : id_str = talloc_asprintf(frame, "%"PRIu64"", channel->channel_id);
308 4 : if (id_str == NULL) {
309 0 : goto failure;
310 : }
311 4 : result = json_add_string(&sub_json, "channel_id", id_str);
312 4 : if (result < 0) {
313 0 : goto failure;
314 : }
315 4 : nttime_to_timeval(&tv, channel->creation_time);
316 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
317 4 : if (time_str == NULL) {
318 0 : goto failure;
319 : }
320 4 : result = json_add_string(&sub_json, "creation_time", time_str);
321 4 : if (result < 0) {
322 0 : goto failure;
323 : }
324 4 : result = json_add_string(&sub_json, "local_address", channel->local_address);
325 4 : if (result < 0) {
326 0 : goto failure;
327 : }
328 4 : result = json_add_string(&sub_json, "remote_address", channel->remote_address);
329 4 : if (result < 0) {
330 0 : goto failure;
331 : }
332 :
333 4 : result = json_add_object(parent_json, id_str, &sub_json);
334 4 : if (result < 0) {
335 0 : goto failure;
336 : }
337 :
338 4 : TALLOC_FREE(frame);
339 4 : return 0;
340 0 : failure:
341 0 : json_free(&sub_json);
342 0 : TALLOC_FREE(frame);
343 0 : return -1;
344 : }
345 :
346 4 : static int add_channels_to_json(struct json_object *parent_json,
347 : const struct smbXsrv_session_global0 *global)
348 : {
349 : struct json_object sub_json;
350 : uint32_t i;
351 : int result;
352 :
353 4 : sub_json = json_new_object();
354 4 : if (json_is_invalid(&sub_json)) {
355 0 : goto failure;
356 : }
357 :
358 8 : for (i = 0; i < global->num_channels; i++) {
359 4 : const struct smbXsrv_channel_global0 *c = &global->channels[i];
360 :
361 4 : result = add_channel_to_json(&sub_json, c);
362 4 : if (result < 0) {
363 0 : goto failure;
364 : }
365 : }
366 :
367 4 : result = json_add_object(parent_json, "channels", &sub_json);
368 4 : if (result < 0) {
369 0 : goto failure;
370 : }
371 :
372 4 : return 0;
373 0 : failure:
374 0 : json_free(&sub_json);
375 0 : return -1;
376 : }
377 :
378 4 : int traverse_connections_json(struct traverse_state *state,
379 : const struct connections_data *crec,
380 : const char *encryption_cipher,
381 : enum crypto_degree encryption_degree,
382 : const char *signing_cipher,
383 : enum crypto_degree signing_degree)
384 : {
385 : struct json_object sub_json;
386 : struct json_object connections_json;
387 : struct timeval tv;
388 : struct timeval_buf tv_buf;
389 4 : char *time = NULL;
390 4 : int result = 0;
391 4 : char *sess_id_str = NULL;
392 4 : char *tcon_id_str = NULL;
393 :
394 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
395 4 : if (tmp_ctx == NULL) {
396 0 : return -1;
397 : }
398 :
399 4 : sub_json = json_new_object();
400 4 : if (json_is_invalid(&sub_json)) {
401 0 : goto failure;
402 : }
403 4 : connections_json = json_get_object(&state->root_json, "tcons");
404 4 : if (json_is_invalid(&connections_json)) {
405 0 : goto failure;
406 : }
407 :
408 4 : result = json_add_string(&sub_json, "service", crec->servicename);
409 4 : if (result < 0) {
410 0 : goto failure;
411 : }
412 4 : result = add_server_id_to_json(&sub_json, crec->pid);
413 4 : if (result < 0) {
414 0 : goto failure;
415 : }
416 4 : tcon_id_str = talloc_asprintf(tmp_ctx, "%u", crec->cnum);
417 4 : if (tcon_id_str == NULL) {
418 0 : goto failure;
419 : }
420 4 : result = json_add_string(&sub_json, "tcon_id", tcon_id_str);
421 4 : if (result < 0) {
422 0 : goto failure;
423 : }
424 4 : sess_id_str = talloc_asprintf(tmp_ctx, "%u", crec->sess_id);
425 4 : if (sess_id_str == NULL) {
426 0 : goto failure;
427 : }
428 4 : result = json_add_string(&sub_json, "session_id", sess_id_str);
429 4 : if (result < 0) {
430 0 : goto failure;
431 : }
432 4 : result = json_add_string(&sub_json, "machine", crec->machine);
433 4 : if (result < 0) {
434 0 : goto failure;
435 : }
436 4 : nttime_to_timeval(&tv, crec->start);
437 4 : time = timeval_str_buf(&tv, true, true, &tv_buf);
438 4 : if (time == NULL) {
439 0 : goto failure;
440 : }
441 4 : result = json_add_string(&sub_json, "connected_at", time);
442 4 : if (result < 0) {
443 0 : goto failure;
444 : }
445 4 : result = add_crypto_to_json(&sub_json, "encryption",
446 : encryption_cipher, encryption_degree);
447 4 : if (result < 0) {
448 0 : goto failure;
449 : }
450 4 : result = add_crypto_to_json(&sub_json, "signing",
451 : signing_cipher, signing_degree);
452 4 : if (result < 0) {
453 0 : goto failure;
454 : }
455 :
456 4 : result = json_add_object(&connections_json, tcon_id_str, &sub_json);
457 4 : if (result < 0) {
458 0 : goto failure;
459 : }
460 :
461 4 : result = json_update_object(&state->root_json, "tcons", &connections_json);
462 4 : if (result < 0) {
463 0 : goto failure;
464 : }
465 :
466 4 : TALLOC_FREE(tmp_ctx);
467 4 : return 0;
468 0 : failure:
469 0 : json_free(&sub_json);
470 0 : TALLOC_FREE(tmp_ctx);
471 0 : return -1;
472 : }
473 :
474 4 : int traverse_sessionid_json(struct traverse_state *state,
475 : struct sessionid *session,
476 : char *uid_str,
477 : char *gid_str,
478 : const char *encryption_cipher,
479 : enum crypto_degree encryption_degree,
480 : const char *signing_cipher,
481 : enum crypto_degree signing_degree,
482 : const char *connection_dialect)
483 : {
484 : struct json_object sub_json;
485 : struct json_object session_json;
486 4 : int result = 0;
487 4 : char *id_str = NULL;
488 : struct timeval tv;
489 : struct timeval_buf tv_buf;
490 4 : char *time_str = NULL;
491 :
492 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
493 4 : if (tmp_ctx == NULL) {
494 0 : return -1;
495 : }
496 :
497 4 : sub_json = json_new_object();
498 4 : if (json_is_invalid(&sub_json)) {
499 0 : goto failure;
500 : }
501 :
502 4 : session_json = json_get_object(&state->root_json, "sessions");
503 4 : if (json_is_invalid(&session_json)) {
504 0 : goto failure;
505 : }
506 :
507 4 : id_str = talloc_asprintf(tmp_ctx, "%u", session->id_num);
508 4 : result = json_add_string(&sub_json, "session_id", id_str);
509 4 : if (result < 0) {
510 0 : goto failure;
511 : }
512 4 : result = add_server_id_to_json(&sub_json, session->pid);
513 4 : if (result < 0) {
514 0 : goto failure;
515 : }
516 4 : result = json_add_int(&sub_json, "uid", session->uid);
517 4 : if (result < 0) {
518 0 : goto failure;
519 : }
520 4 : result = json_add_int(&sub_json, "gid", session->gid);
521 4 : if (result < 0) {
522 0 : goto failure;
523 : }
524 4 : result = json_add_string(&sub_json, "username", uid_str);
525 4 : if (result < 0) {
526 0 : goto failure;
527 : }
528 4 : result = json_add_string(&sub_json, "groupname", gid_str);
529 4 : if (result < 0) {
530 0 : goto failure;
531 : }
532 :
533 4 : nttime_to_timeval(&tv, session->global->creation_time);
534 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
535 4 : if (time_str == NULL) {
536 0 : goto failure;
537 : }
538 4 : result = json_add_string(&sub_json, "creation_time", time_str);
539 4 : if (result < 0) {
540 0 : goto failure;
541 : }
542 :
543 4 : nttime_to_timeval(&tv, session->global->expiration_time);
544 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
545 4 : if (time_str == NULL) {
546 0 : goto failure;
547 : }
548 4 : result = json_add_string(&sub_json, "expiration_time", time_str);
549 4 : if (result < 0) {
550 0 : goto failure;
551 : }
552 :
553 4 : nttime_to_timeval(&tv, session->global->auth_time);
554 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
555 4 : if (time_str == NULL) {
556 0 : goto failure;
557 : }
558 4 : result = json_add_string(&sub_json, "auth_time", time_str);
559 4 : if (result < 0) {
560 0 : goto failure;
561 : }
562 :
563 4 : result = json_add_string(&sub_json, "remote_machine", session->remote_machine);
564 4 : if (result < 0) {
565 0 : goto failure;
566 : }
567 4 : result = json_add_string(&sub_json, "hostname", session->hostname);
568 4 : if (result < 0) {
569 0 : goto failure;
570 : }
571 4 : result = json_add_string(&sub_json, "session_dialect", connection_dialect);
572 4 : if (result < 0) {
573 0 : goto failure;
574 : }
575 4 : result = json_add_guid(&sub_json,
576 : "client_guid",
577 4 : &session->global->client_guid);
578 4 : if (result < 0) {
579 0 : goto failure;
580 : }
581 4 : result = add_crypto_to_json(&sub_json, "encryption",
582 : encryption_cipher, encryption_degree);
583 4 : if (result < 0) {
584 0 : goto failure;
585 : }
586 4 : result = add_crypto_to_json(&sub_json, "signing",
587 : signing_cipher, signing_degree);
588 4 : if (result < 0) {
589 0 : goto failure;
590 : }
591 :
592 4 : result = add_channels_to_json(&sub_json, session->global);
593 4 : if (result < 0) {
594 0 : goto failure;
595 : }
596 :
597 4 : result = json_add_object(&session_json, id_str, &sub_json);
598 4 : if (result < 0) {
599 0 : goto failure;
600 : }
601 :
602 4 : result = json_update_object(&state->root_json, "sessions", &session_json);
603 4 : if (result < 0) {
604 0 : goto failure;
605 : }
606 :
607 4 : TALLOC_FREE(tmp_ctx);
608 4 : return 0;
609 0 : failure:
610 0 : json_free(&sub_json);
611 0 : TALLOC_FREE(tmp_ctx);
612 0 : return -1;
613 : }
614 :
615 4 : static int add_access_mode_to_json(struct json_object *parent_json,
616 : int access_int)
617 : {
618 : struct json_object access_json;
619 4 : char *access_hex = NULL;
620 4 : const char *access_str = NULL;
621 : int result;
622 :
623 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
624 4 : if (tmp_ctx == NULL) {
625 0 : return -1;
626 : }
627 :
628 4 : access_json = json_new_object();
629 4 : if (json_is_invalid(&access_json)) {
630 0 : goto failure;
631 : }
632 :
633 4 : access_hex = talloc_asprintf(tmp_ctx, "0x%08x", access_int);
634 4 : result = json_add_string(&access_json, "hex", access_hex);
635 4 : if (result < 0) {
636 0 : goto failure;
637 : }
638 4 : result = map_mask_to_json(&access_json, access_int, access_mask);
639 4 : if (result < 0) {
640 0 : goto failure;
641 : }
642 :
643 8 : access_str = talloc_asprintf(tmp_ctx, "%s%s",
644 4 : (access_int & FILE_READ_DATA)?"R":"",
645 4 : (access_int & (FILE_WRITE_DATA|FILE_APPEND_DATA))?"W":"");
646 4 : result = json_add_string(&access_json, "text", access_str);
647 4 : if (result < 0) {
648 0 : goto failure;
649 : }
650 :
651 4 : result = json_add_object(parent_json, "access_mask", &access_json);
652 4 : if (result < 0) {
653 0 : goto failure;
654 : }
655 :
656 4 : TALLOC_FREE(tmp_ctx);
657 4 : return 0;
658 0 : failure:
659 0 : json_free(&access_json);
660 0 : TALLOC_FREE(tmp_ctx);
661 0 : return -1;
662 : }
663 :
664 4 : static int add_caching_to_json(struct json_object *parent_json,
665 : int op_type,
666 : int lease_type)
667 : {
668 : struct json_object caching_json;
669 4 : char *hex = NULL;
670 4 : char *caching_text = NULL;
671 4 : int caching_type = 0;
672 : int result;
673 :
674 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
675 4 : if (tmp_ctx == NULL) {
676 0 : return -1;
677 : }
678 :
679 4 : caching_json = json_new_object();
680 4 : if (json_is_invalid(&caching_json)) {
681 0 : goto failure;
682 : }
683 :
684 4 : if (op_type & LEASE_OPLOCK) {
685 0 : caching_type = lease_type;
686 : } else {
687 4 : if (op_type & LEVEL_II_OPLOCK) {
688 0 : caching_type = SMB2_LEASE_READ;
689 4 : } else if (op_type & EXCLUSIVE_OPLOCK) {
690 0 : caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE;
691 4 : } else if (op_type & BATCH_OPLOCK) {
692 0 : caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE;
693 : }
694 : }
695 4 : result = map_mask_to_json(&caching_json, caching_type, lease_mask);
696 4 : if (result < 0) {
697 0 : goto failure;
698 : }
699 :
700 4 : hex = talloc_asprintf(tmp_ctx, "0x%08x", caching_type);
701 4 : if (hex == NULL) {
702 0 : goto failure;
703 : }
704 4 : result = json_add_string(&caching_json, "hex", hex);
705 4 : if (result < 0) {
706 0 : goto failure;
707 : }
708 :
709 12 : caching_text = talloc_asprintf(tmp_ctx, "%s%s%s",
710 4 : (caching_type & SMB2_LEASE_READ)?"R":"",
711 4 : (caching_type & SMB2_LEASE_WRITE)?"W":"",
712 4 : (caching_type & SMB2_LEASE_HANDLE)?"H":"");
713 4 : if (caching_text == NULL) {
714 0 : return -1;
715 : }
716 :
717 4 : result = json_add_string(&caching_json, "text", caching_text);
718 4 : if (result < 0) {
719 0 : goto failure;
720 : }
721 :
722 4 : result = json_add_object(parent_json, "caching", &caching_json);
723 4 : if (result < 0) {
724 0 : goto failure;
725 : }
726 :
727 4 : TALLOC_FREE(tmp_ctx);
728 4 : return 0;
729 0 : failure:
730 0 : json_free(&caching_json);
731 0 : TALLOC_FREE(tmp_ctx);
732 0 : return -1;
733 : }
734 :
735 4 : static int add_oplock_to_json(struct json_object *parent_json,
736 : uint16_t op_type,
737 : const char *op_str)
738 : {
739 : struct json_object oplock_json;
740 : int result;
741 :
742 4 : oplock_json = json_new_object();
743 4 : if (json_is_invalid(&oplock_json)) {
744 0 : goto failure;
745 : }
746 :
747 4 : if (op_type != 0) {
748 0 : result = map_mask_to_json(&oplock_json, op_type, oplock_mask);
749 0 : if (result < 0) {
750 0 : goto failure;
751 : }
752 0 : result = json_add_string(&oplock_json, "text", op_str);
753 0 : if (result < 0) {
754 0 : goto failure;
755 : }
756 : }
757 :
758 4 : result = json_add_object(parent_json, "oplock", &oplock_json);
759 4 : if (result < 0) {
760 0 : goto failure;
761 : }
762 :
763 4 : return 0;
764 0 : failure:
765 0 : json_free(&oplock_json);
766 0 : return -1;
767 : }
768 :
769 0 : static int lease_key_to_str(struct smb2_lease_key lease_key,
770 : char *lease_str)
771 : {
772 0 : uint8_t _buf[16] = {0};
773 0 : DATA_BLOB blob = data_blob_const(_buf, sizeof(_buf));
774 : struct GUID guid;
775 : NTSTATUS status;
776 0 : char *tmp = NULL;
777 :
778 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
779 0 : if (tmp_ctx == NULL) {
780 0 : return -1;
781 : }
782 :
783 0 : PUSH_LE_U64(_buf, 0, lease_key.data[0]);
784 0 : PUSH_LE_U64(_buf, 8, lease_key.data[1]);
785 :
786 0 : status = GUID_from_ndr_blob(&blob, &guid);
787 0 : if (!NT_STATUS_IS_OK(status)) {
788 0 : goto failure;
789 : }
790 0 : tmp = GUID_string(tmp_ctx, &guid);
791 0 : if (tmp == NULL) {
792 0 : goto failure;
793 : }
794 0 : fstrcpy(lease_str, tmp);
795 :
796 0 : TALLOC_FREE(tmp_ctx);
797 0 : return 0;
798 0 : failure:
799 0 : TALLOC_FREE(tmp_ctx);
800 0 : return -1;
801 : }
802 :
803 4 : static int add_lease_to_json(struct json_object *parent_json,
804 : int lease_type,
805 : struct smb2_lease_key lease_key,
806 : bool add_lease)
807 : {
808 : struct json_object lease_json;
809 4 : char *lease_hex = NULL;
810 4 : char *lease_text = NULL;
811 : fstring lease_key_str;
812 : int result;
813 :
814 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
815 4 : if (tmp_ctx == NULL) {
816 0 : return -1;
817 : }
818 :
819 4 : lease_json = json_new_object();
820 4 : if (json_is_invalid(&lease_json)) {
821 0 : goto failure;
822 : }
823 :
824 :
825 4 : if (add_lease) {
826 0 : result = lease_key_to_str(lease_key, lease_key_str);
827 0 : if (result < 0) {
828 0 : goto failure;
829 : }
830 0 : result = json_add_string(&lease_json, "lease_key", lease_key_str);
831 0 : if (result < 0) {
832 0 : goto failure;
833 : }
834 0 : lease_hex = talloc_asprintf(tmp_ctx, "0x%08x", lease_type);
835 0 : result = json_add_string(&lease_json, "hex", lease_hex);
836 0 : if (result < 0) {
837 0 : goto failure;
838 : }
839 0 : if (lease_type > (SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE + SMB2_LEASE_READ)) {
840 0 : result = json_add_bool(&lease_json, "UNKNOWN", true);
841 0 : if (result < 0) {
842 0 : goto failure;
843 : }
844 : } else {
845 0 : result = map_mask_to_json(&lease_json, lease_type, lease_mask);
846 0 : if (result < 0) {
847 0 : goto failure;
848 : }
849 : }
850 0 : lease_text = talloc_asprintf(tmp_ctx, "%s%s%s",
851 0 : (lease_type & SMB2_LEASE_READ)?"R":"",
852 0 : (lease_type & SMB2_LEASE_WRITE)?"W":"",
853 0 : (lease_type & SMB2_LEASE_HANDLE)?"H":"");
854 :
855 0 : result = json_add_string(&lease_json, "text", lease_text);
856 0 : if (result < 0) {
857 0 : goto failure;
858 : }
859 : }
860 :
861 4 : result = json_add_object(parent_json, "lease", &lease_json);
862 4 : if (result < 0) {
863 0 : goto failure;
864 : }
865 :
866 4 : TALLOC_FREE(tmp_ctx);
867 4 : return 0;
868 0 : failure:
869 0 : json_free(&lease_json);
870 0 : TALLOC_FREE(tmp_ctx);
871 0 : return -1;
872 : }
873 :
874 4 : static int add_sharemode_to_json(struct json_object *parent_json,
875 : int sharemode)
876 : {
877 : struct json_object sharemode_json;
878 4 : char *hex = NULL;
879 4 : char *text = NULL;
880 : int result;
881 :
882 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
883 4 : if (tmp_ctx == NULL) {
884 0 : return -1;
885 : }
886 :
887 4 : sharemode_json = json_new_object();
888 4 : if (json_is_invalid(&sharemode_json)) {
889 0 : goto failure;
890 : }
891 :
892 4 : hex = talloc_asprintf(tmp_ctx, "0x%08x", sharemode);
893 4 : if (hex == NULL) {
894 0 : goto failure;
895 : }
896 4 : result = json_add_string(&sharemode_json, "hex", hex);
897 4 : if (result < 0) {
898 0 : goto failure;
899 : }
900 4 : result = map_mask_to_json(&sharemode_json, sharemode, sharemode_mask);
901 4 : if (result < 0) {
902 0 : goto failure;
903 : }
904 :
905 12 : text = talloc_asprintf(tmp_ctx, "%s%s%s",
906 4 : (sharemode & FILE_SHARE_READ)?"R":"",
907 4 : (sharemode & FILE_SHARE_WRITE)?"W":"",
908 4 : (sharemode & FILE_SHARE_DELETE)?"D":"");
909 4 : if (text == NULL) {
910 0 : goto failure;
911 : }
912 4 : result = json_add_string(&sharemode_json, "text", text);
913 4 : if (result < 0) {
914 0 : goto failure;
915 : }
916 :
917 4 : result = json_add_object(parent_json, "sharemode", &sharemode_json);
918 4 : if (result < 0) {
919 0 : goto failure;
920 : }
921 :
922 4 : TALLOC_FREE(tmp_ctx);
923 4 : return 0;
924 0 : failure:
925 0 : json_free(&sharemode_json);
926 0 : TALLOC_FREE(tmp_ctx);
927 0 : return -1;
928 : }
929 :
930 4 : static int add_open_to_json(struct json_object *parent_json,
931 : const struct share_mode_entry *e,
932 : bool resolve_uids,
933 : const char *op_str,
934 : uint32_t lease_type,
935 : const char *uid_str)
936 : {
937 4 : struct json_object sub_json = {
938 : .valid = false,
939 : };
940 4 : struct json_object opens_json = {
941 : .valid = false,
942 : };
943 : struct timeval_buf tv_buf;
944 4 : int result = 0;
945 : char *timestr;
946 4 : bool add_lease = false;
947 4 : char *key = NULL;
948 4 : char *share_file_id = NULL;
949 4 : char *pid = NULL;
950 : struct server_id_buf tmp;
951 :
952 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
953 4 : if (tmp_ctx == NULL) {
954 0 : return -1;
955 : }
956 :
957 4 : opens_json = json_get_object(parent_json, "opens");
958 4 : if (json_is_invalid(&opens_json)) {
959 0 : goto failure;
960 : }
961 4 : sub_json = json_new_object();
962 4 : if (json_is_invalid(&sub_json)) {
963 0 : goto failure;
964 : }
965 :
966 :
967 4 : result = add_server_id_to_json(&sub_json, e->pid);
968 4 : if (result < 0) {
969 0 : goto failure;
970 : }
971 4 : if (resolve_uids) {
972 0 : result = json_add_string(&sub_json, "username", uid_str);
973 0 : if (result < 0) {
974 0 : goto failure;
975 : }
976 : }
977 4 : result = json_add_int(&sub_json, "uid", e->uid);
978 4 : if (result < 0) {
979 0 : goto failure;
980 : }
981 4 : share_file_id = talloc_asprintf(tmp_ctx, "%"PRIu64, e->share_file_id);
982 4 : result = json_add_string(&sub_json, "share_file_id", share_file_id);
983 4 : if (result < 0) {
984 0 : goto failure;
985 : }
986 4 : result = add_sharemode_to_json(&sub_json, e->share_access);
987 4 : if (result < 0) {
988 0 : goto failure;
989 : }
990 4 : result = add_access_mode_to_json(&sub_json, e->access_mask);
991 4 : if (result < 0) {
992 0 : goto failure;
993 : }
994 4 : result = add_caching_to_json(&sub_json, e->op_type, lease_type);
995 4 : if (result < 0) {
996 0 : goto failure;
997 : }
998 4 : result = add_oplock_to_json(&sub_json, e->op_type, op_str);
999 4 : if (result < 0) {
1000 0 : goto failure;
1001 : }
1002 4 : add_lease = e->op_type & LEASE_OPLOCK;
1003 4 : result = add_lease_to_json(&sub_json, lease_type, e->lease_key, add_lease);
1004 4 : if (result < 0) {
1005 0 : goto failure;
1006 : }
1007 :
1008 4 : timestr = timeval_str_buf(&e->time, true, true, &tv_buf);
1009 4 : if (timestr == NULL) {
1010 0 : goto failure;
1011 : }
1012 4 : result = json_add_string(&sub_json, "opened_at", timestr);
1013 4 : if (result < 0) {
1014 0 : goto failure;
1015 : }
1016 :
1017 4 : pid = server_id_str_buf(e->pid, &tmp);
1018 4 : key = talloc_asprintf(tmp_ctx, "%s/%"PRIu64, pid, e->share_file_id);
1019 4 : result = json_add_object(&opens_json, key, &sub_json);
1020 4 : if (result < 0) {
1021 0 : goto failure;
1022 : }
1023 4 : result = json_update_object(parent_json, "opens", &opens_json);
1024 4 : if (result < 0) {
1025 0 : goto failure;
1026 : }
1027 :
1028 4 : TALLOC_FREE(tmp_ctx);
1029 4 : return 0;
1030 0 : failure:
1031 0 : json_free(&opens_json);
1032 0 : json_free(&sub_json);
1033 0 : TALLOC_FREE(tmp_ctx);
1034 0 : return -1;
1035 : }
1036 :
1037 4 : static int add_fileid_to_json(struct json_object *parent_json,
1038 : struct file_id fid)
1039 : {
1040 : struct json_object fid_json;
1041 : int result;
1042 :
1043 4 : fid_json = json_new_object();
1044 4 : if (json_is_invalid(&fid_json)) {
1045 0 : goto failure;
1046 : }
1047 :
1048 4 : result = json_add_int(&fid_json, "devid", fid.devid);
1049 4 : if (result < 0) {
1050 0 : goto failure;
1051 : }
1052 4 : result = json_add_int(&fid_json, "inode", fid.inode);
1053 4 : if (result < 0) {
1054 0 : goto failure;
1055 : }
1056 4 : result = json_add_int(&fid_json, "extid", fid.extid);
1057 4 : if (result < 0) {
1058 0 : goto failure;
1059 : }
1060 :
1061 4 : result = json_add_object(parent_json, "fileid", &fid_json);
1062 4 : if (result < 0) {
1063 0 : goto failure;
1064 : }
1065 :
1066 4 : return 0;
1067 0 : failure:
1068 0 : json_free(&fid_json);
1069 0 : return -1;
1070 : }
1071 :
1072 4 : int print_share_mode_json(struct traverse_state *state,
1073 : const struct share_mode_data *d,
1074 : const struct share_mode_entry *e,
1075 : struct file_id fid,
1076 : const char *uid_str,
1077 : const char *op_str,
1078 : uint32_t lease_type,
1079 : const char *filename)
1080 : {
1081 4 : struct json_object locks_json = {
1082 : .valid = false,
1083 : };
1084 4 : struct json_object file_json = {
1085 : .valid = false,
1086 : };
1087 4 : char *key = NULL;
1088 4 : int result = 0;
1089 :
1090 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1091 4 : if (tmp_ctx == NULL) {
1092 0 : return -1;
1093 : }
1094 :
1095 4 : if (d->servicepath[strlen(d->servicepath)-1] == '/') {
1096 0 : key = talloc_asprintf(tmp_ctx, "%s%s", d->servicepath, filename);
1097 : } else {
1098 4 : key = talloc_asprintf(tmp_ctx, "%s/%s", d->servicepath, filename);
1099 : }
1100 :
1101 4 : locks_json = json_get_object(&state->root_json, "open_files");
1102 4 : if (json_is_invalid(&locks_json)) {
1103 0 : goto failure;
1104 : }
1105 4 : file_json = json_get_object(&locks_json, key);
1106 4 : if (json_is_invalid(&file_json)) {
1107 0 : goto failure;
1108 : }
1109 :
1110 4 : result = json_add_string(&file_json, "service_path", d->servicepath);
1111 4 : if (result < 0) {
1112 0 : goto failure;
1113 : }
1114 4 : result = json_add_string(&file_json, "filename", filename);
1115 4 : if (result < 0) {
1116 0 : goto failure;
1117 : }
1118 4 : result = add_fileid_to_json(&file_json, fid);
1119 4 : if (result < 0) {
1120 0 : goto failure;
1121 : }
1122 4 : result = json_add_int(&file_json, "num_pending_deletes", d->num_delete_tokens);
1123 4 : if (result < 0) {
1124 0 : goto failure;
1125 : }
1126 :
1127 4 : result = add_open_to_json(&file_json,
1128 : e,
1129 4 : state->resolve_uids,
1130 : op_str,
1131 : lease_type,
1132 : uid_str);
1133 4 : if (result < 0) {
1134 0 : goto failure;
1135 : }
1136 :
1137 4 : result = json_update_object(&locks_json, key, &file_json);
1138 4 : if (result < 0) {
1139 0 : goto failure;
1140 : }
1141 4 : result = json_update_object(&state->root_json, "open_files", &locks_json);
1142 4 : if (result < 0) {
1143 0 : goto failure;
1144 : }
1145 :
1146 4 : TALLOC_FREE(tmp_ctx);
1147 4 : return 0;
1148 0 : failure:
1149 0 : json_free(&file_json);
1150 0 : json_free(&locks_json);
1151 0 : TALLOC_FREE(tmp_ctx);
1152 0 : return -1;
1153 : }
1154 :
1155 0 : static int add_lock_to_json(struct json_object *parent_json,
1156 : struct server_id server_id,
1157 : const char *type,
1158 : enum brl_flavour flavour,
1159 : intmax_t start,
1160 : intmax_t size)
1161 : {
1162 0 : struct json_object sub_json = {
1163 : .valid = false,
1164 : };
1165 0 : struct json_object locks_json = {
1166 : .valid = false,
1167 : };
1168 : const char *flavour_str;
1169 0 : int result = 0;
1170 :
1171 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1172 0 : if (tmp_ctx == NULL) {
1173 0 : return -1;
1174 : }
1175 :
1176 0 : locks_json = json_get_array(parent_json, "locks");
1177 0 : if (json_is_invalid(&locks_json)) {
1178 0 : goto failure;
1179 : }
1180 0 : sub_json = json_new_object();
1181 0 : if (json_is_invalid(&sub_json)) {
1182 0 : goto failure;
1183 : }
1184 :
1185 0 : result = add_server_id_to_json(&sub_json, server_id);
1186 0 : if (result < 0) {
1187 0 : goto failure;
1188 : }
1189 0 : result = json_add_string(&sub_json, "type", type);
1190 0 : if (result < 0) {
1191 0 : goto failure;
1192 : }
1193 0 : flavour_str = talloc_asprintf(tmp_ctx, "%s%s",
1194 : (flavour == WINDOWS_LOCK)?"Windows":"",
1195 : (flavour == POSIX_LOCK)?"Posix":"");
1196 0 : result = json_add_string(&sub_json, "flavour", flavour_str);
1197 0 : if (result < 0) {
1198 0 : goto failure;
1199 : }
1200 0 : result = json_add_int(&sub_json, "start", start);
1201 0 : if (result < 0) {
1202 0 : goto failure;
1203 : }
1204 0 : result = json_add_int(&sub_json, "size", size);
1205 0 : if (result < 0) {
1206 0 : goto failure;
1207 : }
1208 :
1209 0 : result = json_add_object(&locks_json, NULL, &sub_json);
1210 0 : if (result < 0) {
1211 0 : goto failure;
1212 : }
1213 0 : result = json_update_object(parent_json, "locks", &locks_json);
1214 0 : if (result < 0) {
1215 0 : goto failure;
1216 : }
1217 :
1218 0 : TALLOC_FREE(tmp_ctx);
1219 0 : return 0;
1220 0 : failure:
1221 0 : json_free(&locks_json);
1222 0 : json_free(&sub_json);
1223 0 : TALLOC_FREE(tmp_ctx);
1224 0 : return -1;
1225 : }
1226 :
1227 0 : int print_brl_json(struct traverse_state *state,
1228 : const struct server_id server_id,
1229 : struct file_id fid,
1230 : const char *type,
1231 : enum brl_flavour flavour,
1232 : intmax_t start,
1233 : intmax_t size,
1234 : const char *sharepath,
1235 : const char *filename)
1236 : {
1237 0 : struct json_object file_json = {
1238 : .valid = false,
1239 : };
1240 0 : struct json_object brl_json = {
1241 : .valid = false,
1242 : };
1243 0 : int result = 0;
1244 : char *key;
1245 :
1246 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1247 0 : if (tmp_ctx == NULL) {
1248 0 : return -1;
1249 : }
1250 :
1251 0 : if (sharepath[strlen(sharepath)-1] == '/') {
1252 0 : key = talloc_asprintf(tmp_ctx, "%s%s", sharepath, filename);
1253 : } else {
1254 0 : key = talloc_asprintf(tmp_ctx, "%s/%s", sharepath, filename);
1255 : }
1256 0 : if (key == NULL) {
1257 0 : goto failure;
1258 : }
1259 :
1260 0 : brl_json = json_get_object(&state->root_json, "byte_range_locks");
1261 0 : if (json_is_invalid(&brl_json)) {
1262 0 : goto failure;
1263 : }
1264 0 : file_json = json_get_object(&brl_json, key);
1265 0 : if (json_is_invalid(&file_json)) {
1266 0 : goto failure;
1267 : }
1268 :
1269 0 : result = add_fileid_to_json(&file_json, fid);
1270 0 : if (result < 0) {
1271 0 : goto failure;
1272 : }
1273 0 : result = json_add_string(&file_json, "file_name", filename);
1274 0 : if (result < 0) {
1275 0 : goto failure;
1276 : }
1277 0 : result = json_add_string(&file_json, "share_path", sharepath);
1278 0 : if (result < 0) {
1279 0 : goto failure;
1280 : }
1281 0 : result = add_server_id_to_json(&file_json, server_id);
1282 0 : if (result < 0) {
1283 0 : goto failure;
1284 : }
1285 0 : result = add_lock_to_json(&file_json, server_id, type, flavour, start, size);
1286 0 : if (result < 0) {
1287 0 : goto failure;
1288 : }
1289 :
1290 0 : result = json_add_object(&brl_json, key, &file_json);
1291 0 : if (result < 0) {
1292 0 : goto failure;
1293 : }
1294 0 : result = json_update_object(&state->root_json, "byte_range_locks", &brl_json);
1295 0 : if (result < 0) {
1296 0 : goto failure;
1297 : }
1298 :
1299 0 : TALLOC_FREE(tmp_ctx);
1300 0 : return 0;
1301 0 : failure:
1302 0 : json_free(&file_json);
1303 0 : json_free(&brl_json);
1304 0 : TALLOC_FREE(tmp_ctx);
1305 0 : return -1;
1306 : }
1307 :
1308 0 : bool print_notify_rec_json(struct traverse_state *state,
1309 : const struct notify_instance *instance,
1310 : const struct server_id server_id,
1311 : const char *path)
1312 : {
1313 : struct json_object sub_json;
1314 : struct json_object notify_json;
1315 0 : char *filter = NULL;
1316 0 : char *subdir_filter = NULL;
1317 : struct timeval_buf tv_buf;
1318 : struct timeval val;
1319 0 : char *time = NULL;
1320 0 : char *pid = NULL;
1321 : struct server_id_buf tmp;
1322 0 : int result = 0;
1323 :
1324 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1325 0 : if (tmp_ctx == NULL) {
1326 0 : return -1;
1327 : }
1328 :
1329 0 : sub_json = json_new_object();
1330 0 : if (json_is_invalid(&sub_json)) {
1331 0 : return false;
1332 : }
1333 0 : notify_json = json_get_object(&state->root_json, "notifies");
1334 0 : if (json_is_invalid(¬ify_json)) {
1335 0 : goto failure;
1336 : }
1337 :
1338 0 : result = add_server_id_to_json(&sub_json, server_id);
1339 0 : if (result < 0) {
1340 0 : goto failure;
1341 : }
1342 0 : result = json_add_string(&sub_json, "path", path);
1343 0 : if (result < 0) {
1344 0 : goto failure;
1345 : }
1346 0 : filter = talloc_asprintf(tmp_ctx, "%u", instance->filter);
1347 0 : if (filter == NULL) {
1348 0 : goto failure;
1349 : }
1350 0 : result = json_add_string(&sub_json, "filter", filter);
1351 0 : if (result < 0) {
1352 0 : goto failure;
1353 : }
1354 0 : subdir_filter = talloc_asprintf(tmp_ctx, "%u", instance->subdir_filter);
1355 0 : if (subdir_filter == NULL) {
1356 0 : goto failure;
1357 : }
1358 0 : result = json_add_string(&sub_json, "subdir_filter", subdir_filter);
1359 0 : if (result < 0) {
1360 0 : goto failure;
1361 : }
1362 0 : val = convert_timespec_to_timeval(instance->creation_time);
1363 0 : time = timeval_str_buf(&val, true, true, &tv_buf);
1364 0 : result = json_add_string(&sub_json, "creation_time", time);
1365 0 : if (result < 0) {
1366 0 : goto failure;
1367 : }
1368 :
1369 0 : pid = server_id_str_buf(server_id, &tmp);
1370 0 : result = json_add_object(¬ify_json, pid, &sub_json);
1371 0 : if (result < 0) {
1372 0 : goto failure;
1373 : }
1374 :
1375 0 : result = json_update_object(&state->root_json, "notifies", ¬ify_json);
1376 0 : if (result < 0) {
1377 0 : goto failure;
1378 : }
1379 :
1380 0 : TALLOC_FREE(tmp_ctx);
1381 0 : return true;
1382 0 : failure:
1383 0 : json_free(&sub_json);
1384 0 : TALLOC_FREE(tmp_ctx);
1385 0 : return false;
1386 : }
|