smbd: avoid a panic in close_directory()
[samba4-gss.git] / source3 / utils / status_json.c
blobf558c91dec71de1e817e825ef8e8ce921b9a313b
1 /*
2 * Samba Unix/Linux SMB client library
3 * Json output
4 * Copyright (C) Jule Anger 2022
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
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"
33 #include <jansson.h>
34 #include "audit_logging.h" /* various JSON helpers */
35 #include "auth/common_auth.h"
37 int add_general_information_to_json(struct traverse_state *state)
39 int result;
41 result = json_add_timestamp(&state->root_json);
42 if (result < 0) {
43 return -1;
46 result = json_add_string(&state->root_json, "version", samba_version_string());
47 if (result < 0) {
48 return -1;
51 result = json_add_string(&state->root_json, "smb_conf", get_dyn_CONFIGFILE());
52 if (result < 0) {
53 return -1;
56 return 0;
59 static int add_server_id_to_json(struct json_object *parent_json,
60 const struct server_id server_id)
62 struct json_object sub_json;
63 char *pid_str = NULL;
64 char *task_id_str = NULL;
65 char *vnn_str = NULL;
66 char *unique_id_str = NULL;
67 int result;
69 TALLOC_CTX *tmp_ctx = talloc_stackframe();
70 if (tmp_ctx == NULL) {
71 return -1;
74 sub_json = json_new_object();
75 if (json_is_invalid(&sub_json)) {
76 goto failure;
79 pid_str = talloc_asprintf(
80 tmp_ctx, "%lu", (unsigned long)server_id.pid);
81 result = json_add_string(&sub_json, "pid", pid_str);
82 if (result < 0) {
83 goto failure;
85 task_id_str = talloc_asprintf(tmp_ctx, "%u", server_id.task_id);
86 result = json_add_string(&sub_json, "task_id", task_id_str);
87 if (result < 0) {
88 goto failure;
90 vnn_str = talloc_asprintf(tmp_ctx, "%u", server_id.vnn);
91 result = json_add_string(&sub_json, "vnn", vnn_str);
92 if (result < 0) {
93 goto failure;
95 unique_id_str = talloc_asprintf(
96 tmp_ctx, "%"PRIu64, server_id.unique_id);
97 result = json_add_string(&sub_json, "unique_id", unique_id_str);
98 if (result < 0) {
99 goto failure;
102 result = json_add_object(parent_json, "server_id", &sub_json);
103 if (result < 0) {
104 goto failure;
107 TALLOC_FREE(tmp_ctx);
108 return 0;
109 failure:
110 json_free(&sub_json);
111 TALLOC_FREE(tmp_ctx);
112 return -1;
115 struct mask2txt {
116 uint32_t mask;
117 const char *string_desc;
121 * Convert a mask of some sort (access, oplock, leases),
122 * to key/value pairs in a JSON object.
124 static int map_mask_to_json(struct json_object *root_json,
125 uint32_t tomap,
126 const struct mask2txt *table)
128 const struct mask2txt *a = NULL;
129 int result = 0;
131 for (a = table; a->string_desc != 0; a++) {
132 result = json_add_bool(root_json, a->string_desc,
133 (tomap & a->mask) ? true : false);
135 if (result < 0) {
136 return result;
138 tomap &= ~a->mask;
141 /* Assert we know about all requested "tomap" values */
142 SMB_ASSERT(tomap == 0);
144 return 0;
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}
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}
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}
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}
187 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)
193 struct json_object section_json = {
194 .valid = false,
196 struct json_object subsection_json = {
197 .valid = false,
199 int result = 0;
201 section_json = json_get_object(&state->root_json, section);
202 if (json_is_invalid(&section_json)) {
203 goto failure;
205 subsection_json = json_get_object(&section_json, subsection);
206 if (json_is_invalid(&subsection_json)) {
207 goto failure;
210 result = json_add_int(&subsection_json, key, value);
211 if (result < 0) {
212 goto failure;
215 result = json_update_object(&section_json, subsection, &subsection_json);
216 if (result < 0) {
217 goto failure;
219 result = json_update_object(&state->root_json, section, &section_json);
220 if (result < 0) {
221 goto failure;
224 return 0;
225 failure:
226 json_free(&section_json);
227 json_free(&subsection_json);
228 return -1;
231 int add_section_to_json(struct traverse_state *state,
232 const char *key)
234 struct json_object empty_json;
235 int result;
237 empty_json = json_new_object();
238 if (json_is_invalid(&empty_json)) {
239 return -1;
242 result = json_add_object(&state->root_json, key, &empty_json);
243 if (result < 0) {
244 return -1;
247 return result;
250 static int add_crypto_to_json(struct json_object *parent_json,
251 const char *key,
252 const char *cipher,
253 enum crypto_degree degree)
255 struct json_object sub_json;
256 const char *degree_str;
257 int result;
259 if (degree == CRYPTO_DEGREE_NONE) {
260 degree_str = "none";
261 } else if (degree == CRYPTO_DEGREE_ANONYMOUS) {
262 degree_str = "anonymous";
263 } else if (degree == CRYPTO_DEGREE_PARTIAL) {
264 degree_str = "partial";
265 } else {
266 degree_str = "full";
269 sub_json = json_new_object();
270 if (json_is_invalid(&sub_json)) {
271 goto failure;
274 result = json_add_string(&sub_json, "cipher", cipher);
275 if (result < 0) {
276 goto failure;
278 result = json_add_string(&sub_json, "degree", degree_str);
279 if (result < 0) {
280 goto failure;
282 result = json_add_object(parent_json, key, &sub_json);
283 if (result < 0) {
284 goto failure;
287 return 0;
288 failure:
289 json_free(&sub_json);
290 return -1;
293 static int add_channel_to_json(struct json_object *parent_json,
294 const struct smbXsrv_channel_global0 *channel)
296 TALLOC_CTX *frame = talloc_stackframe();
297 struct json_object sub_json;
298 char *id_str = NULL;
299 struct timeval tv;
300 struct timeval_buf tv_buf;
301 char *time_str = NULL;
302 int result;
304 sub_json = json_new_object();
305 if (json_is_invalid(&sub_json)) {
306 goto failure;
309 id_str = talloc_asprintf(frame, "%"PRIu64"", channel->channel_id);
310 if (id_str == NULL) {
311 goto failure;
313 result = json_add_string(&sub_json, "channel_id", id_str);
314 if (result < 0) {
315 goto failure;
317 nttime_to_timeval(&tv, channel->creation_time);
318 time_str = timeval_str_buf(&tv, true, true, &tv_buf);
319 if (time_str == NULL) {
320 goto failure;
322 result = json_add_string(&sub_json, "creation_time", time_str);
323 if (result < 0) {
324 goto failure;
326 result = json_add_string(&sub_json, "local_address", channel->local_address);
327 if (result < 0) {
328 goto failure;
330 result = json_add_string(&sub_json, "remote_address", channel->remote_address);
331 if (result < 0) {
332 goto failure;
335 result = json_add_object(parent_json, id_str, &sub_json);
336 if (result < 0) {
337 goto failure;
340 TALLOC_FREE(frame);
341 return 0;
342 failure:
343 json_free(&sub_json);
344 TALLOC_FREE(frame);
345 return -1;
348 static int add_channels_to_json(struct json_object *parent_json,
349 const struct smbXsrv_session_global0 *global)
351 struct json_object sub_json;
352 uint32_t i;
353 int result;
355 sub_json = json_new_object();
356 if (json_is_invalid(&sub_json)) {
357 goto failure;
360 for (i = 0; i < global->num_channels; i++) {
361 const struct smbXsrv_channel_global0 *c = &global->channels[i];
363 result = add_channel_to_json(&sub_json, c);
364 if (result < 0) {
365 goto failure;
369 result = json_add_object(parent_json, "channels", &sub_json);
370 if (result < 0) {
371 goto failure;
374 return 0;
375 failure:
376 json_free(&sub_json);
377 return -1;
380 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)
387 struct json_object sub_json;
388 struct json_object connections_json;
389 struct timeval tv;
390 struct timeval_buf tv_buf;
391 char *time = NULL;
392 int result = 0;
393 char *sess_id_str = NULL;
394 char *tcon_id_str = NULL;
396 TALLOC_CTX *tmp_ctx = talloc_stackframe();
397 if (tmp_ctx == NULL) {
398 return -1;
401 sub_json = json_new_object();
402 if (json_is_invalid(&sub_json)) {
403 goto failure;
405 connections_json = json_get_object(&state->root_json, "tcons");
406 if (json_is_invalid(&connections_json)) {
407 goto failure;
410 result = json_add_string(&sub_json, "service", crec->servicename);
411 if (result < 0) {
412 goto failure;
414 result = add_server_id_to_json(&sub_json, crec->pid);
415 if (result < 0) {
416 goto failure;
418 tcon_id_str = talloc_asprintf(tmp_ctx, "%u", crec->cnum);
419 if (tcon_id_str == NULL) {
420 goto failure;
422 result = json_add_string(&sub_json, "tcon_id", tcon_id_str);
423 if (result < 0) {
424 goto failure;
426 sess_id_str = talloc_asprintf(tmp_ctx, "%u", crec->sess_id);
427 if (sess_id_str == NULL) {
428 goto failure;
430 result = json_add_string(&sub_json, "session_id", sess_id_str);
431 if (result < 0) {
432 goto failure;
434 result = json_add_string(&sub_json, "machine", crec->machine);
435 if (result < 0) {
436 goto failure;
438 nttime_to_timeval(&tv, crec->start);
439 time = timeval_str_buf(&tv, true, true, &tv_buf);
440 if (time == NULL) {
441 goto failure;
443 result = json_add_string(&sub_json, "connected_at", time);
444 if (result < 0) {
445 goto failure;
447 result = add_crypto_to_json(&sub_json, "encryption",
448 encryption_cipher, encryption_degree);
449 if (result < 0) {
450 goto failure;
452 result = add_crypto_to_json(&sub_json, "signing",
453 signing_cipher, signing_degree);
454 if (result < 0) {
455 goto failure;
458 result = json_add_object(&connections_json, tcon_id_str, &sub_json);
459 if (result < 0) {
460 goto failure;
463 result = json_update_object(&state->root_json, "tcons", &connections_json);
464 if (result < 0) {
465 goto failure;
468 TALLOC_FREE(tmp_ctx);
469 return 0;
470 failure:
471 json_free(&sub_json);
472 TALLOC_FREE(tmp_ctx);
473 return -1;
476 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)
486 struct json_object sub_json;
487 struct json_object session_json;
488 int result = 0;
489 char *id_str = NULL;
490 struct timeval tv;
491 struct timeval_buf tv_buf;
492 char *time_str = NULL;
494 TALLOC_CTX *tmp_ctx = talloc_stackframe();
495 if (tmp_ctx == NULL) {
496 return -1;
499 sub_json = json_new_object();
500 if (json_is_invalid(&sub_json)) {
501 goto failure;
504 session_json = json_get_object(&state->root_json, "sessions");
505 if (json_is_invalid(&session_json)) {
506 goto failure;
509 id_str = talloc_asprintf(tmp_ctx, "%u", session->id_num);
510 result = json_add_string(&sub_json, "session_id", id_str);
511 if (result < 0) {
512 goto failure;
514 result = add_server_id_to_json(&sub_json, session->pid);
515 if (result < 0) {
516 goto failure;
518 result = json_add_int(&sub_json, "uid", session->uid);
519 if (result < 0) {
520 goto failure;
522 result = json_add_int(&sub_json, "gid", session->gid);
523 if (result < 0) {
524 goto failure;
526 result = json_add_string(&sub_json, "username", uid_str);
527 if (result < 0) {
528 goto failure;
530 result = json_add_string(&sub_json, "groupname", gid_str);
531 if (result < 0) {
532 goto failure;
535 nttime_to_timeval(&tv, session->global->creation_time);
536 time_str = timeval_str_buf(&tv, true, true, &tv_buf);
537 if (time_str == NULL) {
538 goto failure;
540 result = json_add_string(&sub_json, "creation_time", time_str);
541 if (result < 0) {
542 goto failure;
545 nttime_to_timeval(&tv, session->global->expiration_time);
546 time_str = timeval_str_buf(&tv, true, true, &tv_buf);
547 if (time_str == NULL) {
548 goto failure;
550 result = json_add_string(&sub_json, "expiration_time", time_str);
551 if (result < 0) {
552 goto failure;
555 nttime_to_timeval(&tv, session->global->auth_time);
556 time_str = timeval_str_buf(&tv, true, true, &tv_buf);
557 if (time_str == NULL) {
558 goto failure;
560 result = json_add_string(&sub_json, "auth_time", time_str);
561 if (result < 0) {
562 goto failure;
565 result = json_add_string(&sub_json, "remote_machine", session->remote_machine);
566 if (result < 0) {
567 goto failure;
569 result = json_add_string(&sub_json, "hostname", session->hostname);
570 if (result < 0) {
571 goto failure;
573 result = json_add_string(&sub_json, "session_dialect", connection_dialect);
574 if (result < 0) {
575 goto failure;
577 result = json_add_guid(&sub_json,
578 "client_guid",
579 &session->global->client_guid);
580 if (result < 0) {
581 goto failure;
583 result = add_crypto_to_json(&sub_json, "encryption",
584 encryption_cipher, encryption_degree);
585 if (result < 0) {
586 goto failure;
588 result = add_crypto_to_json(&sub_json, "signing",
589 signing_cipher, signing_degree);
590 if (result < 0) {
591 goto failure;
594 result = add_channels_to_json(&sub_json, session->global);
595 if (result < 0) {
596 goto failure;
599 result = json_add_object(&session_json, id_str, &sub_json);
600 if (result < 0) {
601 goto failure;
604 result = json_update_object(&state->root_json, "sessions", &session_json);
605 if (result < 0) {
606 goto failure;
609 TALLOC_FREE(tmp_ctx);
610 return 0;
611 failure:
612 json_free(&sub_json);
613 TALLOC_FREE(tmp_ctx);
614 return -1;
617 static int add_access_mode_to_json(struct json_object *parent_json,
618 int access_int)
620 struct json_object access_json;
621 char *access_hex = NULL;
622 const char *access_str = NULL;
623 int result;
625 TALLOC_CTX *tmp_ctx = talloc_stackframe();
626 if (tmp_ctx == NULL) {
627 return -1;
630 access_json = json_new_object();
631 if (json_is_invalid(&access_json)) {
632 goto failure;
635 access_hex = talloc_asprintf(tmp_ctx, "0x%08x", access_int);
636 result = json_add_string(&access_json, "hex", access_hex);
637 if (result < 0) {
638 goto failure;
640 result = map_mask_to_json(&access_json, access_int, access_mask);
641 if (result < 0) {
642 goto failure;
645 access_str = talloc_asprintf(tmp_ctx, "%s%s",
646 (access_int & FILE_READ_DATA)?"R":"",
647 (access_int & (FILE_WRITE_DATA|FILE_APPEND_DATA))?"W":"");
648 result = json_add_string(&access_json, "text", access_str);
649 if (result < 0) {
650 goto failure;
653 result = json_add_object(parent_json, "access_mask", &access_json);
654 if (result < 0) {
655 goto failure;
658 TALLOC_FREE(tmp_ctx);
659 return 0;
660 failure:
661 json_free(&access_json);
662 TALLOC_FREE(tmp_ctx);
663 return -1;
666 static int add_caching_to_json(struct json_object *parent_json,
667 int op_type,
668 int lease_type)
670 struct json_object caching_json;
671 char *hex = NULL;
672 char *caching_text = NULL;
673 int caching_type = 0;
674 int result;
676 TALLOC_CTX *tmp_ctx = talloc_stackframe();
677 if (tmp_ctx == NULL) {
678 return -1;
681 caching_json = json_new_object();
682 if (json_is_invalid(&caching_json)) {
683 goto failure;
686 if (op_type & LEASE_OPLOCK) {
687 caching_type = lease_type;
688 } else {
689 if (op_type & LEVEL_II_OPLOCK) {
690 caching_type = SMB2_LEASE_READ;
691 } else if (op_type & EXCLUSIVE_OPLOCK) {
692 caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE;
693 } else if (op_type & BATCH_OPLOCK) {
694 caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE;
697 result = map_mask_to_json(&caching_json, caching_type, lease_mask);
698 if (result < 0) {
699 goto failure;
702 hex = talloc_asprintf(tmp_ctx, "0x%08x", caching_type);
703 if (hex == NULL) {
704 goto failure;
706 result = json_add_string(&caching_json, "hex", hex);
707 if (result < 0) {
708 goto failure;
711 caching_text = talloc_asprintf(tmp_ctx, "%s%s%s",
712 (caching_type & SMB2_LEASE_READ)?"R":"",
713 (caching_type & SMB2_LEASE_WRITE)?"W":"",
714 (caching_type & SMB2_LEASE_HANDLE)?"H":"");
715 if (caching_text == NULL) {
716 return -1;
719 result = json_add_string(&caching_json, "text", caching_text);
720 if (result < 0) {
721 goto failure;
724 result = json_add_object(parent_json, "caching", &caching_json);
725 if (result < 0) {
726 goto failure;
729 TALLOC_FREE(tmp_ctx);
730 return 0;
731 failure:
732 json_free(&caching_json);
733 TALLOC_FREE(tmp_ctx);
734 return -1;
737 static int add_oplock_to_json(struct json_object *parent_json,
738 uint16_t op_type,
739 const char *op_str)
741 struct json_object oplock_json;
742 int result;
744 oplock_json = json_new_object();
745 if (json_is_invalid(&oplock_json)) {
746 goto failure;
749 if (op_type != 0) {
750 result = map_mask_to_json(&oplock_json, op_type, oplock_mask);
751 if (result < 0) {
752 goto failure;
754 result = json_add_string(&oplock_json, "text", op_str);
755 if (result < 0) {
756 goto failure;
760 result = json_add_object(parent_json, "oplock", &oplock_json);
761 if (result < 0) {
762 goto failure;
765 return 0;
766 failure:
767 json_free(&oplock_json);
768 return -1;
771 static int lease_key_to_str(struct smb2_lease_key lease_key,
772 char *lease_str)
774 uint8_t _buf[16] = {0};
775 DATA_BLOB blob = data_blob_const(_buf, sizeof(_buf));
776 struct GUID guid;
777 NTSTATUS status;
778 char *tmp = NULL;
780 TALLOC_CTX *tmp_ctx = talloc_stackframe();
781 if (tmp_ctx == NULL) {
782 return -1;
785 PUSH_LE_U64(_buf, 0, lease_key.data[0]);
786 PUSH_LE_U64(_buf, 8, lease_key.data[1]);
788 status = GUID_from_ndr_blob(&blob, &guid);
789 if (!NT_STATUS_IS_OK(status)) {
790 goto failure;
792 tmp = GUID_string(tmp_ctx, &guid);
793 if (tmp == NULL) {
794 goto failure;
796 fstrcpy(lease_str, tmp);
798 TALLOC_FREE(tmp_ctx);
799 return 0;
800 failure:
801 TALLOC_FREE(tmp_ctx);
802 return -1;
805 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)
810 struct json_object lease_json;
811 char *lease_hex = NULL;
812 char *lease_text = NULL;
813 fstring lease_key_str;
814 int result;
816 TALLOC_CTX *tmp_ctx = talloc_stackframe();
817 if (tmp_ctx == NULL) {
818 return -1;
821 lease_json = json_new_object();
822 if (json_is_invalid(&lease_json)) {
823 goto failure;
827 if (add_lease) {
828 result = lease_key_to_str(lease_key, lease_key_str);
829 if (result < 0) {
830 goto failure;
832 result = json_add_string(&lease_json, "lease_key", lease_key_str);
833 if (result < 0) {
834 goto failure;
836 lease_hex = talloc_asprintf(tmp_ctx, "0x%08x", lease_type);
837 result = json_add_string(&lease_json, "hex", lease_hex);
838 if (result < 0) {
839 goto failure;
841 if (lease_type > (SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE + SMB2_LEASE_READ)) {
842 result = json_add_bool(&lease_json, "UNKNOWN", true);
843 if (result < 0) {
844 goto failure;
846 } else {
847 result = map_mask_to_json(&lease_json, lease_type, lease_mask);
848 if (result < 0) {
849 goto failure;
852 lease_text = talloc_asprintf(tmp_ctx, "%s%s%s",
853 (lease_type & SMB2_LEASE_READ)?"R":"",
854 (lease_type & SMB2_LEASE_WRITE)?"W":"",
855 (lease_type & SMB2_LEASE_HANDLE)?"H":"");
857 result = json_add_string(&lease_json, "text", lease_text);
858 if (result < 0) {
859 goto failure;
863 result = json_add_object(parent_json, "lease", &lease_json);
864 if (result < 0) {
865 goto failure;
868 TALLOC_FREE(tmp_ctx);
869 return 0;
870 failure:
871 json_free(&lease_json);
872 TALLOC_FREE(tmp_ctx);
873 return -1;
876 static int add_sharemode_to_json(struct json_object *parent_json,
877 int sharemode)
879 struct json_object sharemode_json;
880 char *hex = NULL;
881 char *text = NULL;
882 int result;
884 TALLOC_CTX *tmp_ctx = talloc_stackframe();
885 if (tmp_ctx == NULL) {
886 return -1;
889 sharemode_json = json_new_object();
890 if (json_is_invalid(&sharemode_json)) {
891 goto failure;
894 hex = talloc_asprintf(tmp_ctx, "0x%08x", sharemode);
895 if (hex == NULL) {
896 goto failure;
898 result = json_add_string(&sharemode_json, "hex", hex);
899 if (result < 0) {
900 goto failure;
902 result = map_mask_to_json(&sharemode_json, sharemode, sharemode_mask);
903 if (result < 0) {
904 goto failure;
907 text = talloc_asprintf(tmp_ctx, "%s%s%s",
908 (sharemode & FILE_SHARE_READ)?"R":"",
909 (sharemode & FILE_SHARE_WRITE)?"W":"",
910 (sharemode & FILE_SHARE_DELETE)?"D":"");
911 if (text == NULL) {
912 goto failure;
914 result = json_add_string(&sharemode_json, "text", text);
915 if (result < 0) {
916 goto failure;
919 result = json_add_object(parent_json, "sharemode", &sharemode_json);
920 if (result < 0) {
921 goto failure;
924 TALLOC_FREE(tmp_ctx);
925 return 0;
926 failure:
927 json_free(&sharemode_json);
928 TALLOC_FREE(tmp_ctx);
929 return -1;
932 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)
939 struct json_object sub_json = {
940 .valid = false,
942 struct json_object opens_json = {
943 .valid = false,
945 struct timeval_buf tv_buf;
946 int result = 0;
947 char *timestr;
948 bool add_lease = false;
949 char *key = NULL;
950 char *share_file_id = NULL;
951 char *pid = NULL;
952 struct server_id_buf tmp;
954 TALLOC_CTX *tmp_ctx = talloc_stackframe();
955 if (tmp_ctx == NULL) {
956 return -1;
959 opens_json = json_get_object(parent_json, "opens");
960 if (json_is_invalid(&opens_json)) {
961 goto failure;
963 sub_json = json_new_object();
964 if (json_is_invalid(&sub_json)) {
965 goto failure;
969 result = add_server_id_to_json(&sub_json, e->pid);
970 if (result < 0) {
971 goto failure;
973 if (resolve_uids) {
974 result = json_add_string(&sub_json, "username", uid_str);
975 if (result < 0) {
976 goto failure;
979 result = json_add_int(&sub_json, "uid", e->uid);
980 if (result < 0) {
981 goto failure;
983 share_file_id = talloc_asprintf(tmp_ctx, "%"PRIu64, e->share_file_id);
984 result = json_add_string(&sub_json, "share_file_id", share_file_id);
985 if (result < 0) {
986 goto failure;
988 result = add_sharemode_to_json(&sub_json, e->share_access);
989 if (result < 0) {
990 goto failure;
992 result = add_access_mode_to_json(&sub_json, e->access_mask);
993 if (result < 0) {
994 goto failure;
996 result = add_caching_to_json(&sub_json, e->op_type, lease_type);
997 if (result < 0) {
998 goto failure;
1000 result = add_oplock_to_json(&sub_json, e->op_type, op_str);
1001 if (result < 0) {
1002 goto failure;
1004 add_lease = e->op_type & LEASE_OPLOCK;
1005 result = add_lease_to_json(&sub_json, lease_type, e->lease_key, add_lease);
1006 if (result < 0) {
1007 goto failure;
1010 timestr = timeval_str_buf(&e->time, true, true, &tv_buf);
1011 if (timestr == NULL) {
1012 goto failure;
1014 result = json_add_string(&sub_json, "opened_at", timestr);
1015 if (result < 0) {
1016 goto failure;
1019 pid = server_id_str_buf(e->pid, &tmp);
1020 key = talloc_asprintf(tmp_ctx, "%s/%"PRIu64, pid, e->share_file_id);
1021 result = json_add_object(&opens_json, key, &sub_json);
1022 if (result < 0) {
1023 goto failure;
1025 result = json_update_object(parent_json, "opens", &opens_json);
1026 if (result < 0) {
1027 goto failure;
1030 TALLOC_FREE(tmp_ctx);
1031 return 0;
1032 failure:
1033 json_free(&opens_json);
1034 json_free(&sub_json);
1035 TALLOC_FREE(tmp_ctx);
1036 return -1;
1039 static int add_fileid_to_json(struct json_object *parent_json,
1040 struct file_id fid)
1042 struct json_object fid_json;
1043 int result;
1045 fid_json = json_new_object();
1046 if (json_is_invalid(&fid_json)) {
1047 goto failure;
1050 result = json_add_int(&fid_json, "devid", fid.devid);
1051 if (result < 0) {
1052 goto failure;
1054 result = json_add_int(&fid_json, "inode", fid.inode);
1055 if (result < 0) {
1056 goto failure;
1058 result = json_add_int(&fid_json, "extid", fid.extid);
1059 if (result < 0) {
1060 goto failure;
1063 result = json_add_object(parent_json, "fileid", &fid_json);
1064 if (result < 0) {
1065 goto failure;
1068 return 0;
1069 failure:
1070 json_free(&fid_json);
1071 return -1;
1074 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)
1083 struct json_object locks_json = {
1084 .valid = false,
1086 struct json_object file_json = {
1087 .valid = false,
1089 char *key = NULL;
1090 int result = 0;
1092 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1093 if (tmp_ctx == NULL) {
1094 return -1;
1097 if (d->servicepath[strlen(d->servicepath)-1] == '/') {
1098 key = talloc_asprintf(tmp_ctx, "%s%s", d->servicepath, filename);
1099 } else {
1100 key = talloc_asprintf(tmp_ctx, "%s/%s", d->servicepath, filename);
1103 locks_json = json_get_object(&state->root_json, "open_files");
1104 if (json_is_invalid(&locks_json)) {
1105 goto failure;
1107 file_json = json_get_object(&locks_json, key);
1108 if (json_is_invalid(&file_json)) {
1109 goto failure;
1112 result = json_add_string(&file_json, "service_path", d->servicepath);
1113 if (result < 0) {
1114 goto failure;
1116 result = json_add_string(&file_json, "filename", filename);
1117 if (result < 0) {
1118 goto failure;
1120 result = add_fileid_to_json(&file_json, fid);
1121 if (result < 0) {
1122 goto failure;
1124 result = json_add_int(&file_json, "num_pending_deletes", d->num_delete_tokens);
1125 if (result < 0) {
1126 goto failure;
1129 result = add_open_to_json(&file_json,
1131 state->resolve_uids,
1132 op_str,
1133 lease_type,
1134 uid_str);
1135 if (result < 0) {
1136 goto failure;
1139 result = json_update_object(&locks_json, key, &file_json);
1140 if (result < 0) {
1141 goto failure;
1143 result = json_update_object(&state->root_json, "open_files", &locks_json);
1144 if (result < 0) {
1145 goto failure;
1148 TALLOC_FREE(tmp_ctx);
1149 return 0;
1150 failure:
1151 json_free(&file_json);
1152 json_free(&locks_json);
1153 TALLOC_FREE(tmp_ctx);
1154 return -1;
1157 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)
1164 struct json_object sub_json = {
1165 .valid = false,
1167 struct json_object locks_json = {
1168 .valid = false,
1170 const char *flavour_str;
1171 int result = 0;
1173 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1174 if (tmp_ctx == NULL) {
1175 return -1;
1178 locks_json = json_get_array(parent_json, "locks");
1179 if (json_is_invalid(&locks_json)) {
1180 goto failure;
1182 sub_json = json_new_object();
1183 if (json_is_invalid(&sub_json)) {
1184 goto failure;
1187 result = add_server_id_to_json(&sub_json, server_id);
1188 if (result < 0) {
1189 goto failure;
1191 result = json_add_string(&sub_json, "type", type);
1192 if (result < 0) {
1193 goto failure;
1195 flavour_str = talloc_asprintf(tmp_ctx, "%s%s",
1196 (flavour == WINDOWS_LOCK)?"Windows":"",
1197 (flavour == POSIX_LOCK)?"Posix":"");
1198 result = json_add_string(&sub_json, "flavour", flavour_str);
1199 if (result < 0) {
1200 goto failure;
1202 result = json_add_int(&sub_json, "start", start);
1203 if (result < 0) {
1204 goto failure;
1206 result = json_add_int(&sub_json, "size", size);
1207 if (result < 0) {
1208 goto failure;
1211 result = json_add_object(&locks_json, NULL, &sub_json);
1212 if (result < 0) {
1213 goto failure;
1215 result = json_update_object(parent_json, "locks", &locks_json);
1216 if (result < 0) {
1217 goto failure;
1220 TALLOC_FREE(tmp_ctx);
1221 return 0;
1222 failure:
1223 json_free(&locks_json);
1224 json_free(&sub_json);
1225 TALLOC_FREE(tmp_ctx);
1226 return -1;
1229 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)
1239 struct json_object file_json = {
1240 .valid = false,
1242 struct json_object brl_json = {
1243 .valid = false,
1245 int result = 0;
1246 char *key;
1248 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1249 if (tmp_ctx == NULL) {
1250 return -1;
1253 if (sharepath[strlen(sharepath)-1] == '/') {
1254 key = talloc_asprintf(tmp_ctx, "%s%s", sharepath, filename);
1255 } else {
1256 key = talloc_asprintf(tmp_ctx, "%s/%s", sharepath, filename);
1258 if (key == NULL) {
1259 goto failure;
1262 brl_json = json_get_object(&state->root_json, "byte_range_locks");
1263 if (json_is_invalid(&brl_json)) {
1264 goto failure;
1266 file_json = json_get_object(&brl_json, key);
1267 if (json_is_invalid(&file_json)) {
1268 goto failure;
1271 result = add_fileid_to_json(&file_json, fid);
1272 if (result < 0) {
1273 goto failure;
1275 result = json_add_string(&file_json, "file_name", filename);
1276 if (result < 0) {
1277 goto failure;
1279 result = json_add_string(&file_json, "share_path", sharepath);
1280 if (result < 0) {
1281 goto failure;
1283 result = add_server_id_to_json(&file_json, server_id);
1284 if (result < 0) {
1285 goto failure;
1287 result = add_lock_to_json(&file_json, server_id, type, flavour, start, size);
1288 if (result < 0) {
1289 goto failure;
1292 result = json_add_object(&brl_json, key, &file_json);
1293 if (result < 0) {
1294 goto failure;
1296 result = json_update_object(&state->root_json, "byte_range_locks", &brl_json);
1297 if (result < 0) {
1298 goto failure;
1301 TALLOC_FREE(tmp_ctx);
1302 return 0;
1303 failure:
1304 json_free(&file_json);
1305 json_free(&brl_json);
1306 TALLOC_FREE(tmp_ctx);
1307 return -1;
1310 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)
1315 struct json_object sub_json;
1316 struct json_object notify_json;
1317 char *filter = NULL;
1318 char *subdir_filter = NULL;
1319 struct timeval_buf tv_buf;
1320 struct timeval val;
1321 char *time = NULL;
1322 char *pid = NULL;
1323 struct server_id_buf tmp;
1324 int result = 0;
1326 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1327 if (tmp_ctx == NULL) {
1328 return -1;
1331 sub_json = json_new_object();
1332 if (json_is_invalid(&sub_json)) {
1333 return false;
1335 notify_json = json_get_object(&state->root_json, "notifies");
1336 if (json_is_invalid(&notify_json)) {
1337 goto failure;
1340 result = add_server_id_to_json(&sub_json, server_id);
1341 if (result < 0) {
1342 goto failure;
1344 result = json_add_string(&sub_json, "path", path);
1345 if (result < 0) {
1346 goto failure;
1348 filter = talloc_asprintf(tmp_ctx, "%u", instance->filter);
1349 if (filter == NULL) {
1350 goto failure;
1352 result = json_add_string(&sub_json, "filter", filter);
1353 if (result < 0) {
1354 goto failure;
1356 subdir_filter = talloc_asprintf(tmp_ctx, "%u", instance->subdir_filter);
1357 if (subdir_filter == NULL) {
1358 goto failure;
1360 result = json_add_string(&sub_json, "subdir_filter", subdir_filter);
1361 if (result < 0) {
1362 goto failure;
1364 val = convert_timespec_to_timeval(instance->creation_time);
1365 time = timeval_str_buf(&val, true, true, &tv_buf);
1366 result = json_add_string(&sub_json, "creation_time", time);
1367 if (result < 0) {
1368 goto failure;
1371 pid = server_id_str_buf(server_id, &tmp);
1372 result = json_add_object(&notify_json, pid, &sub_json);
1373 if (result < 0) {
1374 goto failure;
1377 result = json_update_object(&state->root_json, "notifies", &notify_json);
1378 if (result < 0) {
1379 goto failure;
1382 TALLOC_FREE(tmp_ctx);
1383 return true;
1384 failure:
1385 json_free(&sub_json);
1386 TALLOC_FREE(tmp_ctx);
1387 return false;