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_ANONYMOUS) {
262 0 : degree_str = "anonymous";
263 4 : } else if (degree == CRYPTO_DEGREE_PARTIAL) {
264 4 : degree_str = "partial";
265 : } else {
266 0 : degree_str = "full";
267 : }
268 :
269 16 : sub_json = json_new_object();
270 16 : if (json_is_invalid(&sub_json)) {
271 0 : goto failure;
272 : }
273 :
274 16 : result = json_add_string(&sub_json, "cipher", cipher);
275 16 : if (result < 0) {
276 0 : goto failure;
277 : }
278 16 : result = json_add_string(&sub_json, "degree", degree_str);
279 16 : if (result < 0) {
280 0 : goto failure;
281 : }
282 16 : result = json_add_object(parent_json, key, &sub_json);
283 16 : if (result < 0) {
284 0 : goto failure;
285 : }
286 :
287 16 : return 0;
288 0 : failure:
289 0 : json_free(&sub_json);
290 0 : return -1;
291 : }
292 :
293 4 : static int add_channel_to_json(struct json_object *parent_json,
294 : const struct smbXsrv_channel_global0 *channel)
295 : {
296 4 : TALLOC_CTX *frame = talloc_stackframe();
297 : struct json_object sub_json;
298 4 : char *id_str = NULL;
299 : struct timeval tv;
300 : struct timeval_buf tv_buf;
301 4 : char *time_str = NULL;
302 : int result;
303 :
304 4 : sub_json = json_new_object();
305 4 : if (json_is_invalid(&sub_json)) {
306 0 : goto failure;
307 : }
308 :
309 4 : id_str = talloc_asprintf(frame, "%"PRIu64"", channel->channel_id);
310 4 : if (id_str == NULL) {
311 0 : goto failure;
312 : }
313 4 : result = json_add_string(&sub_json, "channel_id", id_str);
314 4 : if (result < 0) {
315 0 : goto failure;
316 : }
317 4 : nttime_to_timeval(&tv, channel->creation_time);
318 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
319 4 : if (time_str == NULL) {
320 0 : goto failure;
321 : }
322 4 : result = json_add_string(&sub_json, "creation_time", time_str);
323 4 : if (result < 0) {
324 0 : goto failure;
325 : }
326 4 : result = json_add_string(&sub_json, "local_address", channel->local_address);
327 4 : if (result < 0) {
328 0 : goto failure;
329 : }
330 4 : result = json_add_string(&sub_json, "remote_address", channel->remote_address);
331 4 : if (result < 0) {
332 0 : goto failure;
333 : }
334 :
335 4 : result = json_add_object(parent_json, id_str, &sub_json);
336 4 : if (result < 0) {
337 0 : goto failure;
338 : }
339 :
340 4 : TALLOC_FREE(frame);
341 4 : return 0;
342 0 : failure:
343 0 : json_free(&sub_json);
344 0 : TALLOC_FREE(frame);
345 0 : return -1;
346 : }
347 :
348 4 : static int add_channels_to_json(struct json_object *parent_json,
349 : const struct smbXsrv_session_global0 *global)
350 : {
351 : struct json_object sub_json;
352 : uint32_t i;
353 : int result;
354 :
355 4 : sub_json = json_new_object();
356 4 : if (json_is_invalid(&sub_json)) {
357 0 : goto failure;
358 : }
359 :
360 8 : for (i = 0; i < global->num_channels; i++) {
361 4 : const struct smbXsrv_channel_global0 *c = &global->channels[i];
362 :
363 4 : result = add_channel_to_json(&sub_json, c);
364 4 : if (result < 0) {
365 0 : goto failure;
366 : }
367 : }
368 :
369 4 : result = json_add_object(parent_json, "channels", &sub_json);
370 4 : if (result < 0) {
371 0 : goto failure;
372 : }
373 :
374 4 : return 0;
375 0 : failure:
376 0 : json_free(&sub_json);
377 0 : return -1;
378 : }
379 :
380 4 : int traverse_connections_json(struct traverse_state *state,
381 : const struct connections_data *crec,
382 : const char *encryption_cipher,
383 : enum crypto_degree encryption_degree,
384 : const char *signing_cipher,
385 : enum crypto_degree signing_degree)
386 : {
387 : struct json_object sub_json;
388 : struct json_object connections_json;
389 : struct timeval tv;
390 : struct timeval_buf tv_buf;
391 4 : char *time = NULL;
392 4 : int result = 0;
393 4 : char *sess_id_str = NULL;
394 4 : char *tcon_id_str = NULL;
395 :
396 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
397 4 : if (tmp_ctx == NULL) {
398 0 : return -1;
399 : }
400 :
401 4 : sub_json = json_new_object();
402 4 : if (json_is_invalid(&sub_json)) {
403 0 : goto failure;
404 : }
405 4 : connections_json = json_get_object(&state->root_json, "tcons");
406 4 : if (json_is_invalid(&connections_json)) {
407 0 : goto failure;
408 : }
409 :
410 4 : result = json_add_string(&sub_json, "service", crec->servicename);
411 4 : if (result < 0) {
412 0 : goto failure;
413 : }
414 4 : result = add_server_id_to_json(&sub_json, crec->pid);
415 4 : if (result < 0) {
416 0 : goto failure;
417 : }
418 4 : tcon_id_str = talloc_asprintf(tmp_ctx, "%u", crec->cnum);
419 4 : if (tcon_id_str == NULL) {
420 0 : goto failure;
421 : }
422 4 : result = json_add_string(&sub_json, "tcon_id", tcon_id_str);
423 4 : if (result < 0) {
424 0 : goto failure;
425 : }
426 4 : sess_id_str = talloc_asprintf(tmp_ctx, "%u", crec->sess_id);
427 4 : if (sess_id_str == NULL) {
428 0 : goto failure;
429 : }
430 4 : result = json_add_string(&sub_json, "session_id", sess_id_str);
431 4 : if (result < 0) {
432 0 : goto failure;
433 : }
434 4 : result = json_add_string(&sub_json, "machine", crec->machine);
435 4 : if (result < 0) {
436 0 : goto failure;
437 : }
438 4 : nttime_to_timeval(&tv, crec->start);
439 4 : time = timeval_str_buf(&tv, true, true, &tv_buf);
440 4 : if (time == NULL) {
441 0 : goto failure;
442 : }
443 4 : result = json_add_string(&sub_json, "connected_at", time);
444 4 : if (result < 0) {
445 0 : goto failure;
446 : }
447 4 : result = add_crypto_to_json(&sub_json, "encryption",
448 : encryption_cipher, encryption_degree);
449 4 : if (result < 0) {
450 0 : goto failure;
451 : }
452 4 : result = add_crypto_to_json(&sub_json, "signing",
453 : signing_cipher, signing_degree);
454 4 : if (result < 0) {
455 0 : goto failure;
456 : }
457 :
458 4 : result = json_add_object(&connections_json, tcon_id_str, &sub_json);
459 4 : if (result < 0) {
460 0 : goto failure;
461 : }
462 :
463 4 : result = json_update_object(&state->root_json, "tcons", &connections_json);
464 4 : if (result < 0) {
465 0 : goto failure;
466 : }
467 :
468 4 : TALLOC_FREE(tmp_ctx);
469 4 : return 0;
470 0 : failure:
471 0 : json_free(&sub_json);
472 0 : TALLOC_FREE(tmp_ctx);
473 0 : return -1;
474 : }
475 :
476 4 : int traverse_sessionid_json(struct traverse_state *state,
477 : struct sessionid *session,
478 : char *uid_str,
479 : char *gid_str,
480 : const char *encryption_cipher,
481 : enum crypto_degree encryption_degree,
482 : const char *signing_cipher,
483 : enum crypto_degree signing_degree,
484 : const char *connection_dialect)
485 : {
486 : struct json_object sub_json;
487 : struct json_object session_json;
488 4 : int result = 0;
489 4 : char *id_str = NULL;
490 : struct timeval tv;
491 : struct timeval_buf tv_buf;
492 4 : char *time_str = NULL;
493 :
494 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
495 4 : if (tmp_ctx == NULL) {
496 0 : return -1;
497 : }
498 :
499 4 : sub_json = json_new_object();
500 4 : if (json_is_invalid(&sub_json)) {
501 0 : goto failure;
502 : }
503 :
504 4 : session_json = json_get_object(&state->root_json, "sessions");
505 4 : if (json_is_invalid(&session_json)) {
506 0 : goto failure;
507 : }
508 :
509 4 : id_str = talloc_asprintf(tmp_ctx, "%u", session->id_num);
510 4 : result = json_add_string(&sub_json, "session_id", id_str);
511 4 : if (result < 0) {
512 0 : goto failure;
513 : }
514 4 : result = add_server_id_to_json(&sub_json, session->pid);
515 4 : if (result < 0) {
516 0 : goto failure;
517 : }
518 4 : result = json_add_int(&sub_json, "uid", session->uid);
519 4 : if (result < 0) {
520 0 : goto failure;
521 : }
522 4 : result = json_add_int(&sub_json, "gid", session->gid);
523 4 : if (result < 0) {
524 0 : goto failure;
525 : }
526 4 : result = json_add_string(&sub_json, "username", uid_str);
527 4 : if (result < 0) {
528 0 : goto failure;
529 : }
530 4 : result = json_add_string(&sub_json, "groupname", gid_str);
531 4 : if (result < 0) {
532 0 : goto failure;
533 : }
534 :
535 4 : nttime_to_timeval(&tv, session->global->creation_time);
536 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
537 4 : if (time_str == NULL) {
538 0 : goto failure;
539 : }
540 4 : result = json_add_string(&sub_json, "creation_time", time_str);
541 4 : if (result < 0) {
542 0 : goto failure;
543 : }
544 :
545 4 : nttime_to_timeval(&tv, session->global->expiration_time);
546 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
547 4 : if (time_str == NULL) {
548 0 : goto failure;
549 : }
550 4 : result = json_add_string(&sub_json, "expiration_time", time_str);
551 4 : if (result < 0) {
552 0 : goto failure;
553 : }
554 :
555 4 : nttime_to_timeval(&tv, session->global->auth_time);
556 4 : time_str = timeval_str_buf(&tv, true, true, &tv_buf);
557 4 : if (time_str == NULL) {
558 0 : goto failure;
559 : }
560 4 : result = json_add_string(&sub_json, "auth_time", time_str);
561 4 : if (result < 0) {
562 0 : goto failure;
563 : }
564 :
565 4 : result = json_add_string(&sub_json, "remote_machine", session->remote_machine);
566 4 : if (result < 0) {
567 0 : goto failure;
568 : }
569 4 : result = json_add_string(&sub_json, "hostname", session->hostname);
570 4 : if (result < 0) {
571 0 : goto failure;
572 : }
573 4 : result = json_add_string(&sub_json, "session_dialect", connection_dialect);
574 4 : if (result < 0) {
575 0 : goto failure;
576 : }
577 4 : result = json_add_guid(&sub_json,
578 : "client_guid",
579 4 : &session->global->client_guid);
580 4 : if (result < 0) {
581 0 : goto failure;
582 : }
583 4 : result = add_crypto_to_json(&sub_json, "encryption",
584 : encryption_cipher, encryption_degree);
585 4 : if (result < 0) {
586 0 : goto failure;
587 : }
588 4 : result = add_crypto_to_json(&sub_json, "signing",
589 : signing_cipher, signing_degree);
590 4 : if (result < 0) {
591 0 : goto failure;
592 : }
593 :
594 4 : result = add_channels_to_json(&sub_json, session->global);
595 4 : if (result < 0) {
596 0 : goto failure;
597 : }
598 :
599 4 : result = json_add_object(&session_json, id_str, &sub_json);
600 4 : if (result < 0) {
601 0 : goto failure;
602 : }
603 :
604 4 : result = json_update_object(&state->root_json, "sessions", &session_json);
605 4 : if (result < 0) {
606 0 : goto failure;
607 : }
608 :
609 4 : TALLOC_FREE(tmp_ctx);
610 4 : return 0;
611 0 : failure:
612 0 : json_free(&sub_json);
613 0 : TALLOC_FREE(tmp_ctx);
614 0 : return -1;
615 : }
616 :
617 4 : static int add_access_mode_to_json(struct json_object *parent_json,
618 : int access_int)
619 : {
620 : struct json_object access_json;
621 4 : char *access_hex = NULL;
622 4 : const char *access_str = NULL;
623 : int result;
624 :
625 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
626 4 : if (tmp_ctx == NULL) {
627 0 : return -1;
628 : }
629 :
630 4 : access_json = json_new_object();
631 4 : if (json_is_invalid(&access_json)) {
632 0 : goto failure;
633 : }
634 :
635 4 : access_hex = talloc_asprintf(tmp_ctx, "0x%08x", access_int);
636 4 : result = json_add_string(&access_json, "hex", access_hex);
637 4 : if (result < 0) {
638 0 : goto failure;
639 : }
640 4 : result = map_mask_to_json(&access_json, access_int, access_mask);
641 4 : if (result < 0) {
642 0 : goto failure;
643 : }
644 :
645 8 : access_str = talloc_asprintf(tmp_ctx, "%s%s",
646 4 : (access_int & FILE_READ_DATA)?"R":"",
647 4 : (access_int & (FILE_WRITE_DATA|FILE_APPEND_DATA))?"W":"");
648 4 : result = json_add_string(&access_json, "text", access_str);
649 4 : if (result < 0) {
650 0 : goto failure;
651 : }
652 :
653 4 : result = json_add_object(parent_json, "access_mask", &access_json);
654 4 : if (result < 0) {
655 0 : goto failure;
656 : }
657 :
658 4 : TALLOC_FREE(tmp_ctx);
659 4 : return 0;
660 0 : failure:
661 0 : json_free(&access_json);
662 0 : TALLOC_FREE(tmp_ctx);
663 0 : return -1;
664 : }
665 :
666 4 : static int add_caching_to_json(struct json_object *parent_json,
667 : int op_type,
668 : int lease_type)
669 : {
670 : struct json_object caching_json;
671 4 : char *hex = NULL;
672 4 : char *caching_text = NULL;
673 4 : int caching_type = 0;
674 : int result;
675 :
676 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
677 4 : if (tmp_ctx == NULL) {
678 0 : return -1;
679 : }
680 :
681 4 : caching_json = json_new_object();
682 4 : if (json_is_invalid(&caching_json)) {
683 0 : goto failure;
684 : }
685 :
686 4 : if (op_type & LEASE_OPLOCK) {
687 0 : caching_type = lease_type;
688 : } else {
689 4 : if (op_type & LEVEL_II_OPLOCK) {
690 0 : caching_type = SMB2_LEASE_READ;
691 4 : } else if (op_type & EXCLUSIVE_OPLOCK) {
692 0 : caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE;
693 4 : } else if (op_type & BATCH_OPLOCK) {
694 0 : caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE;
695 : }
696 : }
697 4 : result = map_mask_to_json(&caching_json, caching_type, lease_mask);
698 4 : if (result < 0) {
699 0 : goto failure;
700 : }
701 :
702 4 : hex = talloc_asprintf(tmp_ctx, "0x%08x", caching_type);
703 4 : if (hex == NULL) {
704 0 : goto failure;
705 : }
706 4 : result = json_add_string(&caching_json, "hex", hex);
707 4 : if (result < 0) {
708 0 : goto failure;
709 : }
710 :
711 12 : caching_text = talloc_asprintf(tmp_ctx, "%s%s%s",
712 4 : (caching_type & SMB2_LEASE_READ)?"R":"",
713 4 : (caching_type & SMB2_LEASE_WRITE)?"W":"",
714 4 : (caching_type & SMB2_LEASE_HANDLE)?"H":"");
715 4 : if (caching_text == NULL) {
716 0 : return -1;
717 : }
718 :
719 4 : result = json_add_string(&caching_json, "text", caching_text);
720 4 : if (result < 0) {
721 0 : goto failure;
722 : }
723 :
724 4 : result = json_add_object(parent_json, "caching", &caching_json);
725 4 : if (result < 0) {
726 0 : goto failure;
727 : }
728 :
729 4 : TALLOC_FREE(tmp_ctx);
730 4 : return 0;
731 0 : failure:
732 0 : json_free(&caching_json);
733 0 : TALLOC_FREE(tmp_ctx);
734 0 : return -1;
735 : }
736 :
737 4 : static int add_oplock_to_json(struct json_object *parent_json,
738 : uint16_t op_type,
739 : const char *op_str)
740 : {
741 : struct json_object oplock_json;
742 : int result;
743 :
744 4 : oplock_json = json_new_object();
745 4 : if (json_is_invalid(&oplock_json)) {
746 0 : goto failure;
747 : }
748 :
749 4 : if (op_type != 0) {
750 0 : result = map_mask_to_json(&oplock_json, op_type, oplock_mask);
751 0 : if (result < 0) {
752 0 : goto failure;
753 : }
754 0 : result = json_add_string(&oplock_json, "text", op_str);
755 0 : if (result < 0) {
756 0 : goto failure;
757 : }
758 : }
759 :
760 4 : result = json_add_object(parent_json, "oplock", &oplock_json);
761 4 : if (result < 0) {
762 0 : goto failure;
763 : }
764 :
765 4 : return 0;
766 0 : failure:
767 0 : json_free(&oplock_json);
768 0 : return -1;
769 : }
770 :
771 0 : static int lease_key_to_str(struct smb2_lease_key lease_key,
772 : char *lease_str)
773 : {
774 0 : uint8_t _buf[16] = {0};
775 0 : DATA_BLOB blob = data_blob_const(_buf, sizeof(_buf));
776 : struct GUID guid;
777 : NTSTATUS status;
778 0 : char *tmp = NULL;
779 :
780 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
781 0 : if (tmp_ctx == NULL) {
782 0 : return -1;
783 : }
784 :
785 0 : PUSH_LE_U64(_buf, 0, lease_key.data[0]);
786 0 : PUSH_LE_U64(_buf, 8, lease_key.data[1]);
787 :
788 0 : status = GUID_from_ndr_blob(&blob, &guid);
789 0 : if (!NT_STATUS_IS_OK(status)) {
790 0 : goto failure;
791 : }
792 0 : tmp = GUID_string(tmp_ctx, &guid);
793 0 : if (tmp == NULL) {
794 0 : goto failure;
795 : }
796 0 : fstrcpy(lease_str, tmp);
797 :
798 0 : TALLOC_FREE(tmp_ctx);
799 0 : return 0;
800 0 : failure:
801 0 : TALLOC_FREE(tmp_ctx);
802 0 : return -1;
803 : }
804 :
805 4 : static int add_lease_to_json(struct json_object *parent_json,
806 : int lease_type,
807 : struct smb2_lease_key lease_key,
808 : bool add_lease)
809 : {
810 : struct json_object lease_json;
811 4 : char *lease_hex = NULL;
812 4 : char *lease_text = NULL;
813 : fstring lease_key_str;
814 : int result;
815 :
816 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
817 4 : if (tmp_ctx == NULL) {
818 0 : return -1;
819 : }
820 :
821 4 : lease_json = json_new_object();
822 4 : if (json_is_invalid(&lease_json)) {
823 0 : goto failure;
824 : }
825 :
826 :
827 4 : if (add_lease) {
828 0 : result = lease_key_to_str(lease_key, lease_key_str);
829 0 : if (result < 0) {
830 0 : goto failure;
831 : }
832 0 : result = json_add_string(&lease_json, "lease_key", lease_key_str);
833 0 : if (result < 0) {
834 0 : goto failure;
835 : }
836 0 : lease_hex = talloc_asprintf(tmp_ctx, "0x%08x", lease_type);
837 0 : result = json_add_string(&lease_json, "hex", lease_hex);
838 0 : if (result < 0) {
839 0 : goto failure;
840 : }
841 0 : if (lease_type > (SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE + SMB2_LEASE_READ)) {
842 0 : result = json_add_bool(&lease_json, "UNKNOWN", true);
843 0 : if (result < 0) {
844 0 : goto failure;
845 : }
846 : } else {
847 0 : result = map_mask_to_json(&lease_json, lease_type, lease_mask);
848 0 : if (result < 0) {
849 0 : goto failure;
850 : }
851 : }
852 0 : lease_text = talloc_asprintf(tmp_ctx, "%s%s%s",
853 0 : (lease_type & SMB2_LEASE_READ)?"R":"",
854 0 : (lease_type & SMB2_LEASE_WRITE)?"W":"",
855 0 : (lease_type & SMB2_LEASE_HANDLE)?"H":"");
856 :
857 0 : result = json_add_string(&lease_json, "text", lease_text);
858 0 : if (result < 0) {
859 0 : goto failure;
860 : }
861 : }
862 :
863 4 : result = json_add_object(parent_json, "lease", &lease_json);
864 4 : if (result < 0) {
865 0 : goto failure;
866 : }
867 :
868 4 : TALLOC_FREE(tmp_ctx);
869 4 : return 0;
870 0 : failure:
871 0 : json_free(&lease_json);
872 0 : TALLOC_FREE(tmp_ctx);
873 0 : return -1;
874 : }
875 :
876 4 : static int add_sharemode_to_json(struct json_object *parent_json,
877 : int sharemode)
878 : {
879 : struct json_object sharemode_json;
880 4 : char *hex = NULL;
881 4 : char *text = NULL;
882 : int result;
883 :
884 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
885 4 : if (tmp_ctx == NULL) {
886 0 : return -1;
887 : }
888 :
889 4 : sharemode_json = json_new_object();
890 4 : if (json_is_invalid(&sharemode_json)) {
891 0 : goto failure;
892 : }
893 :
894 4 : hex = talloc_asprintf(tmp_ctx, "0x%08x", sharemode);
895 4 : if (hex == NULL) {
896 0 : goto failure;
897 : }
898 4 : result = json_add_string(&sharemode_json, "hex", hex);
899 4 : if (result < 0) {
900 0 : goto failure;
901 : }
902 4 : result = map_mask_to_json(&sharemode_json, sharemode, sharemode_mask);
903 4 : if (result < 0) {
904 0 : goto failure;
905 : }
906 :
907 12 : text = talloc_asprintf(tmp_ctx, "%s%s%s",
908 4 : (sharemode & FILE_SHARE_READ)?"R":"",
909 4 : (sharemode & FILE_SHARE_WRITE)?"W":"",
910 4 : (sharemode & FILE_SHARE_DELETE)?"D":"");
911 4 : if (text == NULL) {
912 0 : goto failure;
913 : }
914 4 : result = json_add_string(&sharemode_json, "text", text);
915 4 : if (result < 0) {
916 0 : goto failure;
917 : }
918 :
919 4 : result = json_add_object(parent_json, "sharemode", &sharemode_json);
920 4 : if (result < 0) {
921 0 : goto failure;
922 : }
923 :
924 4 : TALLOC_FREE(tmp_ctx);
925 4 : return 0;
926 0 : failure:
927 0 : json_free(&sharemode_json);
928 0 : TALLOC_FREE(tmp_ctx);
929 0 : return -1;
930 : }
931 :
932 4 : static int add_open_to_json(struct json_object *parent_json,
933 : const struct share_mode_entry *e,
934 : bool resolve_uids,
935 : const char *op_str,
936 : uint32_t lease_type,
937 : const char *uid_str)
938 : {
939 4 : struct json_object sub_json = {
940 : .valid = false,
941 : };
942 4 : struct json_object opens_json = {
943 : .valid = false,
944 : };
945 : struct timeval_buf tv_buf;
946 4 : int result = 0;
947 : char *timestr;
948 4 : bool add_lease = false;
949 4 : char *key = NULL;
950 4 : char *share_file_id = NULL;
951 4 : char *pid = NULL;
952 : struct server_id_buf tmp;
953 :
954 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
955 4 : if (tmp_ctx == NULL) {
956 0 : return -1;
957 : }
958 :
959 4 : opens_json = json_get_object(parent_json, "opens");
960 4 : if (json_is_invalid(&opens_json)) {
961 0 : goto failure;
962 : }
963 4 : sub_json = json_new_object();
964 4 : if (json_is_invalid(&sub_json)) {
965 0 : goto failure;
966 : }
967 :
968 :
969 4 : result = add_server_id_to_json(&sub_json, e->pid);
970 4 : if (result < 0) {
971 0 : goto failure;
972 : }
973 4 : if (resolve_uids) {
974 0 : result = json_add_string(&sub_json, "username", uid_str);
975 0 : if (result < 0) {
976 0 : goto failure;
977 : }
978 : }
979 4 : result = json_add_int(&sub_json, "uid", e->uid);
980 4 : if (result < 0) {
981 0 : goto failure;
982 : }
983 4 : share_file_id = talloc_asprintf(tmp_ctx, "%"PRIu64, e->share_file_id);
984 4 : result = json_add_string(&sub_json, "share_file_id", share_file_id);
985 4 : if (result < 0) {
986 0 : goto failure;
987 : }
988 4 : result = add_sharemode_to_json(&sub_json, e->share_access);
989 4 : if (result < 0) {
990 0 : goto failure;
991 : }
992 4 : result = add_access_mode_to_json(&sub_json, e->access_mask);
993 4 : if (result < 0) {
994 0 : goto failure;
995 : }
996 4 : result = add_caching_to_json(&sub_json, e->op_type, lease_type);
997 4 : if (result < 0) {
998 0 : goto failure;
999 : }
1000 4 : result = add_oplock_to_json(&sub_json, e->op_type, op_str);
1001 4 : if (result < 0) {
1002 0 : goto failure;
1003 : }
1004 4 : add_lease = e->op_type & LEASE_OPLOCK;
1005 4 : result = add_lease_to_json(&sub_json, lease_type, e->lease_key, add_lease);
1006 4 : if (result < 0) {
1007 0 : goto failure;
1008 : }
1009 :
1010 4 : timestr = timeval_str_buf(&e->time, true, true, &tv_buf);
1011 4 : if (timestr == NULL) {
1012 0 : goto failure;
1013 : }
1014 4 : result = json_add_string(&sub_json, "opened_at", timestr);
1015 4 : if (result < 0) {
1016 0 : goto failure;
1017 : }
1018 :
1019 4 : pid = server_id_str_buf(e->pid, &tmp);
1020 4 : key = talloc_asprintf(tmp_ctx, "%s/%"PRIu64, pid, e->share_file_id);
1021 4 : result = json_add_object(&opens_json, key, &sub_json);
1022 4 : if (result < 0) {
1023 0 : goto failure;
1024 : }
1025 4 : result = json_update_object(parent_json, "opens", &opens_json);
1026 4 : if (result < 0) {
1027 0 : goto failure;
1028 : }
1029 :
1030 4 : TALLOC_FREE(tmp_ctx);
1031 4 : return 0;
1032 0 : failure:
1033 0 : json_free(&opens_json);
1034 0 : json_free(&sub_json);
1035 0 : TALLOC_FREE(tmp_ctx);
1036 0 : return -1;
1037 : }
1038 :
1039 4 : static int add_fileid_to_json(struct json_object *parent_json,
1040 : struct file_id fid)
1041 : {
1042 : struct json_object fid_json;
1043 : int result;
1044 :
1045 4 : fid_json = json_new_object();
1046 4 : if (json_is_invalid(&fid_json)) {
1047 0 : goto failure;
1048 : }
1049 :
1050 4 : result = json_add_int(&fid_json, "devid", fid.devid);
1051 4 : if (result < 0) {
1052 0 : goto failure;
1053 : }
1054 4 : result = json_add_int(&fid_json, "inode", fid.inode);
1055 4 : if (result < 0) {
1056 0 : goto failure;
1057 : }
1058 4 : result = json_add_int(&fid_json, "extid", fid.extid);
1059 4 : if (result < 0) {
1060 0 : goto failure;
1061 : }
1062 :
1063 4 : result = json_add_object(parent_json, "fileid", &fid_json);
1064 4 : if (result < 0) {
1065 0 : goto failure;
1066 : }
1067 :
1068 4 : return 0;
1069 0 : failure:
1070 0 : json_free(&fid_json);
1071 0 : return -1;
1072 : }
1073 :
1074 4 : int print_share_mode_json(struct traverse_state *state,
1075 : const struct share_mode_data *d,
1076 : const struct share_mode_entry *e,
1077 : struct file_id fid,
1078 : const char *uid_str,
1079 : const char *op_str,
1080 : uint32_t lease_type,
1081 : const char *filename)
1082 : {
1083 4 : struct json_object locks_json = {
1084 : .valid = false,
1085 : };
1086 4 : struct json_object file_json = {
1087 : .valid = false,
1088 : };
1089 4 : char *key = NULL;
1090 4 : int result = 0;
1091 :
1092 4 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1093 4 : if (tmp_ctx == NULL) {
1094 0 : return -1;
1095 : }
1096 :
1097 4 : if (d->servicepath[strlen(d->servicepath)-1] == '/') {
1098 0 : key = talloc_asprintf(tmp_ctx, "%s%s", d->servicepath, filename);
1099 : } else {
1100 4 : key = talloc_asprintf(tmp_ctx, "%s/%s", d->servicepath, filename);
1101 : }
1102 :
1103 4 : locks_json = json_get_object(&state->root_json, "open_files");
1104 4 : if (json_is_invalid(&locks_json)) {
1105 0 : goto failure;
1106 : }
1107 4 : file_json = json_get_object(&locks_json, key);
1108 4 : if (json_is_invalid(&file_json)) {
1109 0 : goto failure;
1110 : }
1111 :
1112 4 : result = json_add_string(&file_json, "service_path", d->servicepath);
1113 4 : if (result < 0) {
1114 0 : goto failure;
1115 : }
1116 4 : result = json_add_string(&file_json, "filename", filename);
1117 4 : if (result < 0) {
1118 0 : goto failure;
1119 : }
1120 4 : result = add_fileid_to_json(&file_json, fid);
1121 4 : if (result < 0) {
1122 0 : goto failure;
1123 : }
1124 4 : result = json_add_int(&file_json, "num_pending_deletes", d->num_delete_tokens);
1125 4 : if (result < 0) {
1126 0 : goto failure;
1127 : }
1128 :
1129 4 : result = add_open_to_json(&file_json,
1130 : e,
1131 4 : state->resolve_uids,
1132 : op_str,
1133 : lease_type,
1134 : uid_str);
1135 4 : if (result < 0) {
1136 0 : goto failure;
1137 : }
1138 :
1139 4 : result = json_update_object(&locks_json, key, &file_json);
1140 4 : if (result < 0) {
1141 0 : goto failure;
1142 : }
1143 4 : result = json_update_object(&state->root_json, "open_files", &locks_json);
1144 4 : if (result < 0) {
1145 0 : goto failure;
1146 : }
1147 :
1148 4 : TALLOC_FREE(tmp_ctx);
1149 4 : return 0;
1150 0 : failure:
1151 0 : json_free(&file_json);
1152 0 : json_free(&locks_json);
1153 0 : TALLOC_FREE(tmp_ctx);
1154 0 : return -1;
1155 : }
1156 :
1157 0 : static int add_lock_to_json(struct json_object *parent_json,
1158 : struct server_id server_id,
1159 : const char *type,
1160 : enum brl_flavour flavour,
1161 : intmax_t start,
1162 : intmax_t size)
1163 : {
1164 0 : struct json_object sub_json = {
1165 : .valid = false,
1166 : };
1167 0 : struct json_object locks_json = {
1168 : .valid = false,
1169 : };
1170 : const char *flavour_str;
1171 0 : int result = 0;
1172 :
1173 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1174 0 : if (tmp_ctx == NULL) {
1175 0 : return -1;
1176 : }
1177 :
1178 0 : locks_json = json_get_array(parent_json, "locks");
1179 0 : if (json_is_invalid(&locks_json)) {
1180 0 : goto failure;
1181 : }
1182 0 : sub_json = json_new_object();
1183 0 : if (json_is_invalid(&sub_json)) {
1184 0 : goto failure;
1185 : }
1186 :
1187 0 : result = add_server_id_to_json(&sub_json, server_id);
1188 0 : if (result < 0) {
1189 0 : goto failure;
1190 : }
1191 0 : result = json_add_string(&sub_json, "type", type);
1192 0 : if (result < 0) {
1193 0 : goto failure;
1194 : }
1195 0 : flavour_str = talloc_asprintf(tmp_ctx, "%s%s",
1196 : (flavour == WINDOWS_LOCK)?"Windows":"",
1197 : (flavour == POSIX_LOCK)?"Posix":"");
1198 0 : result = json_add_string(&sub_json, "flavour", flavour_str);
1199 0 : if (result < 0) {
1200 0 : goto failure;
1201 : }
1202 0 : result = json_add_int(&sub_json, "start", start);
1203 0 : if (result < 0) {
1204 0 : goto failure;
1205 : }
1206 0 : result = json_add_int(&sub_json, "size", size);
1207 0 : if (result < 0) {
1208 0 : goto failure;
1209 : }
1210 :
1211 0 : result = json_add_object(&locks_json, NULL, &sub_json);
1212 0 : if (result < 0) {
1213 0 : goto failure;
1214 : }
1215 0 : result = json_update_object(parent_json, "locks", &locks_json);
1216 0 : if (result < 0) {
1217 0 : goto failure;
1218 : }
1219 :
1220 0 : TALLOC_FREE(tmp_ctx);
1221 0 : return 0;
1222 0 : failure:
1223 0 : json_free(&locks_json);
1224 0 : json_free(&sub_json);
1225 0 : TALLOC_FREE(tmp_ctx);
1226 0 : return -1;
1227 : }
1228 :
1229 0 : int print_brl_json(struct traverse_state *state,
1230 : const struct server_id server_id,
1231 : struct file_id fid,
1232 : const char *type,
1233 : enum brl_flavour flavour,
1234 : intmax_t start,
1235 : intmax_t size,
1236 : const char *sharepath,
1237 : const char *filename)
1238 : {
1239 0 : struct json_object file_json = {
1240 : .valid = false,
1241 : };
1242 0 : struct json_object brl_json = {
1243 : .valid = false,
1244 : };
1245 0 : int result = 0;
1246 : char *key;
1247 :
1248 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1249 0 : if (tmp_ctx == NULL) {
1250 0 : return -1;
1251 : }
1252 :
1253 0 : if (sharepath[strlen(sharepath)-1] == '/') {
1254 0 : key = talloc_asprintf(tmp_ctx, "%s%s", sharepath, filename);
1255 : } else {
1256 0 : key = talloc_asprintf(tmp_ctx, "%s/%s", sharepath, filename);
1257 : }
1258 0 : if (key == NULL) {
1259 0 : goto failure;
1260 : }
1261 :
1262 0 : brl_json = json_get_object(&state->root_json, "byte_range_locks");
1263 0 : if (json_is_invalid(&brl_json)) {
1264 0 : goto failure;
1265 : }
1266 0 : file_json = json_get_object(&brl_json, key);
1267 0 : if (json_is_invalid(&file_json)) {
1268 0 : goto failure;
1269 : }
1270 :
1271 0 : result = add_fileid_to_json(&file_json, fid);
1272 0 : if (result < 0) {
1273 0 : goto failure;
1274 : }
1275 0 : result = json_add_string(&file_json, "file_name", filename);
1276 0 : if (result < 0) {
1277 0 : goto failure;
1278 : }
1279 0 : result = json_add_string(&file_json, "share_path", sharepath);
1280 0 : if (result < 0) {
1281 0 : goto failure;
1282 : }
1283 0 : result = add_server_id_to_json(&file_json, server_id);
1284 0 : if (result < 0) {
1285 0 : goto failure;
1286 : }
1287 0 : result = add_lock_to_json(&file_json, server_id, type, flavour, start, size);
1288 0 : if (result < 0) {
1289 0 : goto failure;
1290 : }
1291 :
1292 0 : result = json_add_object(&brl_json, key, &file_json);
1293 0 : if (result < 0) {
1294 0 : goto failure;
1295 : }
1296 0 : result = json_update_object(&state->root_json, "byte_range_locks", &brl_json);
1297 0 : if (result < 0) {
1298 0 : goto failure;
1299 : }
1300 :
1301 0 : TALLOC_FREE(tmp_ctx);
1302 0 : return 0;
1303 0 : failure:
1304 0 : json_free(&file_json);
1305 0 : json_free(&brl_json);
1306 0 : TALLOC_FREE(tmp_ctx);
1307 0 : return -1;
1308 : }
1309 :
1310 0 : bool print_notify_rec_json(struct traverse_state *state,
1311 : const struct notify_instance *instance,
1312 : const struct server_id server_id,
1313 : const char *path)
1314 : {
1315 : struct json_object sub_json;
1316 : struct json_object notify_json;
1317 0 : char *filter = NULL;
1318 0 : char *subdir_filter = NULL;
1319 : struct timeval_buf tv_buf;
1320 : struct timeval val;
1321 0 : char *time = NULL;
1322 0 : char *pid = NULL;
1323 : struct server_id_buf tmp;
1324 0 : int result = 0;
1325 :
1326 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1327 0 : if (tmp_ctx == NULL) {
1328 0 : return -1;
1329 : }
1330 :
1331 0 : sub_json = json_new_object();
1332 0 : if (json_is_invalid(&sub_json)) {
1333 0 : return false;
1334 : }
1335 0 : notify_json = json_get_object(&state->root_json, "notifies");
1336 0 : if (json_is_invalid(¬ify_json)) {
1337 0 : goto failure;
1338 : }
1339 :
1340 0 : result = add_server_id_to_json(&sub_json, server_id);
1341 0 : if (result < 0) {
1342 0 : goto failure;
1343 : }
1344 0 : result = json_add_string(&sub_json, "path", path);
1345 0 : if (result < 0) {
1346 0 : goto failure;
1347 : }
1348 0 : filter = talloc_asprintf(tmp_ctx, "%u", instance->filter);
1349 0 : if (filter == NULL) {
1350 0 : goto failure;
1351 : }
1352 0 : result = json_add_string(&sub_json, "filter", filter);
1353 0 : if (result < 0) {
1354 0 : goto failure;
1355 : }
1356 0 : subdir_filter = talloc_asprintf(tmp_ctx, "%u", instance->subdir_filter);
1357 0 : if (subdir_filter == NULL) {
1358 0 : goto failure;
1359 : }
1360 0 : result = json_add_string(&sub_json, "subdir_filter", subdir_filter);
1361 0 : if (result < 0) {
1362 0 : goto failure;
1363 : }
1364 0 : val = convert_timespec_to_timeval(instance->creation_time);
1365 0 : time = timeval_str_buf(&val, true, true, &tv_buf);
1366 0 : result = json_add_string(&sub_json, "creation_time", time);
1367 0 : if (result < 0) {
1368 0 : goto failure;
1369 : }
1370 :
1371 0 : pid = server_id_str_buf(server_id, &tmp);
1372 0 : result = json_add_object(¬ify_json, pid, &sub_json);
1373 0 : if (result < 0) {
1374 0 : goto failure;
1375 : }
1376 :
1377 0 : result = json_update_object(&state->root_json, "notifies", ¬ify_json);
1378 0 : if (result < 0) {
1379 0 : goto failure;
1380 : }
1381 :
1382 0 : TALLOC_FREE(tmp_ctx);
1383 0 : return true;
1384 0 : failure:
1385 0 : json_free(&sub_json);
1386 0 : TALLOC_FREE(tmp_ctx);
1387 0 : return false;
1388 : }
|