smbd: reject FILE_ATTRIBUTE_TEMPORARY on directories
[Samba.git] / source3 / utils / status_json.c
blob79cb1dfe1e412f1778deebfe78ee8435cbb5a572
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/open_files.h"
26 #include "status_json.h"
27 #include "../libcli/security/security.h"
28 #include "status.h"
29 #include "lib/util/server_id.h"
30 #include "lib/util/string_wrappers.h"
32 #include <jansson.h>
33 #include "audit_logging.h" /* various JSON helpers */
34 #include "auth/common_auth.h"
36 int add_general_information_to_json(struct traverse_state *state)
38 int result;
40 result = json_add_timestamp(&state->root_json);
41 if (result < 0) {
42 return -1;
45 result = json_add_string(&state->root_json, "version", samba_version_string());
46 if (result < 0) {
47 return -1;
50 result = json_add_string(&state->root_json, "smb_conf", get_dyn_CONFIGFILE());
51 if (result < 0) {
52 return -1;
55 return 0;
58 static int add_server_id_to_json(struct json_object *parent_json,
59 const struct server_id server_id)
61 struct json_object sub_json;
62 char *pid_str = NULL;
63 char *task_id_str = NULL;
64 char *vnn_str = NULL;
65 char *unique_id_str = NULL;
66 int result;
68 TALLOC_CTX *tmp_ctx = talloc_stackframe();
69 if (tmp_ctx == NULL) {
70 return -1;
73 sub_json = json_new_object();
74 if (json_is_invalid(&sub_json)) {
75 goto failure;
78 pid_str = talloc_asprintf(
79 tmp_ctx, "%lu", (unsigned long)server_id.pid);
80 result = json_add_string(&sub_json, "pid", pid_str);
81 if (result < 0) {
82 goto failure;
84 task_id_str = talloc_asprintf(tmp_ctx, "%u", server_id.task_id);
85 result = json_add_string(&sub_json, "task_id", task_id_str);
86 if (result < 0) {
87 goto failure;
89 vnn_str = talloc_asprintf(tmp_ctx, "%u", server_id.vnn);
90 result = json_add_string(&sub_json, "vnn", vnn_str);
91 if (result < 0) {
92 goto failure;
94 unique_id_str = talloc_asprintf(
95 tmp_ctx, "%"PRIu64, server_id.unique_id);
96 result = json_add_string(&sub_json, "unique_id", unique_id_str);
97 if (result < 0) {
98 goto failure;
101 result = json_add_object(parent_json, "server_id", &sub_json);
102 if (result < 0) {
103 goto failure;
106 TALLOC_FREE(tmp_ctx);
107 return 0;
108 failure:
109 json_free(&sub_json);
110 TALLOC_FREE(tmp_ctx);
111 return -1;
114 struct mask2txt {
115 uint32_t mask;
116 const char *string_desc;
120 * Convert a mask of some sort (access, oplock, leases),
121 * to key/value pairs in a JSON object.
123 static int map_mask_to_json(struct json_object *root_json,
124 uint32_t tomap,
125 const struct mask2txt *table)
127 const struct mask2txt *a = NULL;
128 int result = 0;
130 for (a = table; a->string_desc != 0; a++) {
131 result = json_add_bool(root_json, a->string_desc,
132 (tomap & a->mask) ? true : false);
134 if (result < 0) {
135 return result;
137 tomap &= ~a->mask;
140 /* Assert we know about all requested "tomap" values */
141 SMB_ASSERT(tomap == 0);
143 return 0;
146 static const struct mask2txt access_mask[] = {
147 {FILE_READ_DATA, "READ_DATA"},
148 {FILE_WRITE_DATA, "WRITE_DATA"},
149 {FILE_APPEND_DATA, "APPEND_DATA"},
150 {FILE_READ_EA, "READ_EA"},
151 {FILE_WRITE_EA, "WRITE_EA"},
152 {FILE_EXECUTE, "EXECUTE"},
153 {FILE_READ_ATTRIBUTES, "READ_ATTRIBUTES"},
154 {FILE_WRITE_ATTRIBUTES, "WRITE_ATTRIBUTES"},
155 {FILE_DELETE_CHILD, "DELETE_CHILD"},
156 {SEC_STD_DELETE, "DELETE"},
157 {SEC_STD_READ_CONTROL, "READ_CONTROL"},
158 {SEC_STD_WRITE_DAC, "WRITE_DAC"},
159 {SEC_STD_SYNCHRONIZE, "SYNCHRONIZE"},
160 {SEC_FLAG_SYSTEM_SECURITY, "ACCESS_SYSTEM_SECURITY"},
161 {0, NULL}
164 static const struct mask2txt oplock_mask[] = {
165 {EXCLUSIVE_OPLOCK, "EXCLUSIVE"},
166 {BATCH_OPLOCK, "BATCH"},
167 {LEVEL_II_OPLOCK, "LEVEL_II"},
168 {LEASE_OPLOCK, "LEASE"},
169 {0, NULL}
172 static const struct mask2txt sharemode_mask[] = {
173 {FILE_SHARE_READ, "READ"},
174 {FILE_SHARE_WRITE, "WRITE"},
175 {FILE_SHARE_DELETE, "DELETE"},
176 {0, NULL}
179 static const struct mask2txt lease_mask[] = {
180 {SMB2_LEASE_READ, "READ"},
181 {SMB2_LEASE_WRITE, "WRITE"},
182 {SMB2_LEASE_HANDLE, "HANDLE"},
183 {0, NULL}
186 int add_profile_item_to_json(struct traverse_state *state,
187 const char *section,
188 const char *subsection,
189 const char *key,
190 uintmax_t value)
192 struct json_object section_json = {
193 .valid = false,
195 struct json_object subsection_json = {
196 .valid = false,
198 int result = 0;
200 section_json = json_get_object(&state->root_json, section);
201 if (json_is_invalid(&section_json)) {
202 goto failure;
204 subsection_json = json_get_object(&section_json, subsection);
205 if (json_is_invalid(&subsection_json)) {
206 goto failure;
209 result = json_add_int(&subsection_json, key, value);
210 if (result < 0) {
211 goto failure;
214 result = json_update_object(&section_json, subsection, &subsection_json);
215 if (result < 0) {
216 goto failure;
218 result = json_update_object(&state->root_json, section, &section_json);
219 if (result < 0) {
220 goto failure;
223 return 0;
224 failure:
225 json_free(&section_json);
226 json_free(&subsection_json);
227 return -1;
230 int add_section_to_json(struct traverse_state *state,
231 const char *key)
233 struct json_object empty_json;
234 int result;
236 empty_json = json_new_object();
237 if (json_is_invalid(&empty_json)) {
238 return -1;
241 result = json_add_object(&state->root_json, key, &empty_json);
242 if (result < 0) {
243 return -1;
246 return result;
249 static int add_crypto_to_json(struct json_object *parent_json,
250 const char *key,
251 const char *cipher,
252 enum crypto_degree degree)
254 struct json_object sub_json;
255 const char *degree_str;
256 int result;
258 if (degree == CRYPTO_DEGREE_NONE) {
259 degree_str = "none";
260 } else if (degree == CRYPTO_DEGREE_PARTIAL) {
261 degree_str = "partial";
262 } else {
263 degree_str = "full";
266 sub_json = json_new_object();
267 if (json_is_invalid(&sub_json)) {
268 goto failure;
271 result = json_add_string(&sub_json, "cipher", cipher);
272 if (result < 0) {
273 goto failure;
275 result = json_add_string(&sub_json, "degree", degree_str);
276 if (result < 0) {
277 goto failure;
279 result = json_add_object(parent_json, key, &sub_json);
280 if (result < 0) {
281 goto failure;
284 return 0;
285 failure:
286 json_free(&sub_json);
287 return -1;
290 int traverse_connections_json(struct traverse_state *state,
291 const struct connections_data *crec,
292 const char *encryption_cipher,
293 enum crypto_degree encryption_degree,
294 const char *signing_cipher,
295 enum crypto_degree signing_degree)
297 struct json_object sub_json;
298 struct json_object connections_json;
299 struct timeval tv;
300 struct timeval_buf tv_buf;
301 char *time = NULL;
302 int result = 0;
303 char *sess_id_str = NULL;
304 char *tcon_id_str = NULL;
306 TALLOC_CTX *tmp_ctx = talloc_stackframe();
307 if (tmp_ctx == NULL) {
308 return -1;
311 sub_json = json_new_object();
312 if (json_is_invalid(&sub_json)) {
313 goto failure;
315 connections_json = json_get_object(&state->root_json, "tcons");
316 if (json_is_invalid(&connections_json)) {
317 goto failure;
320 result = json_add_string(&sub_json, "service", crec->servicename);
321 if (result < 0) {
322 goto failure;
324 result = add_server_id_to_json(&sub_json, crec->pid);
325 if (result < 0) {
326 goto failure;
328 tcon_id_str = talloc_asprintf(tmp_ctx, "%u", crec->cnum);
329 if (tcon_id_str == NULL) {
330 goto failure;
332 result = json_add_string(&sub_json, "tcon_id", tcon_id_str);
333 if (result < 0) {
334 goto failure;
336 sess_id_str = talloc_asprintf(tmp_ctx, "%u", crec->sess_id);
337 if (sess_id_str == NULL) {
338 goto failure;
340 result = json_add_string(&sub_json, "session_id", sess_id_str);
341 if (result < 0) {
342 goto failure;
344 result = json_add_string(&sub_json, "machine", crec->machine);
345 if (result < 0) {
346 goto failure;
348 nttime_to_timeval(&tv, crec->start);
349 time = timeval_str_buf(&tv, true, true, &tv_buf);
350 if (time == NULL) {
351 goto failure;
353 result = json_add_string(&sub_json, "connected_at", time);
354 if (result < 0) {
355 goto failure;
357 result = add_crypto_to_json(&sub_json, "encryption",
358 encryption_cipher, encryption_degree);
359 if (result < 0) {
360 goto failure;
362 result = add_crypto_to_json(&sub_json, "signing",
363 signing_cipher, signing_degree);
364 if (result < 0) {
365 goto failure;
368 result = json_add_object(&connections_json, tcon_id_str, &sub_json);
369 if (result < 0) {
370 goto failure;
373 result = json_update_object(&state->root_json, "tcons", &connections_json);
374 if (result < 0) {
375 goto failure;
378 TALLOC_FREE(tmp_ctx);
379 return 0;
380 failure:
381 json_free(&sub_json);
382 TALLOC_FREE(tmp_ctx);
383 return -1;
386 int traverse_sessionid_json(struct traverse_state *state,
387 struct sessionid *session,
388 char *uid_str,
389 char *gid_str,
390 const char *encryption_cipher,
391 enum crypto_degree encryption_degree,
392 const char *signing_cipher,
393 enum crypto_degree signing_degree,
394 const char *connection_dialect)
396 struct json_object sub_json;
397 struct json_object session_json;
398 int result = 0;
399 char *id_str = NULL;
401 TALLOC_CTX *tmp_ctx = talloc_stackframe();
402 if (tmp_ctx == NULL) {
403 return -1;
406 sub_json = json_new_object();
407 if (json_is_invalid(&sub_json)) {
408 goto failure;
411 session_json = json_get_object(&state->root_json, "sessions");
412 if (json_is_invalid(&session_json)) {
413 goto failure;
416 id_str = talloc_asprintf(tmp_ctx, "%u", session->id_num);
417 result = json_add_string(&sub_json, "session_id", id_str);
418 if (result < 0) {
419 goto failure;
421 result = add_server_id_to_json(&sub_json, session->pid);
422 if (result < 0) {
423 goto failure;
425 result = json_add_int(&sub_json, "uid", session->uid);
426 if (result < 0) {
427 goto failure;
429 result = json_add_int(&sub_json, "gid", session->gid);
430 if (result < 0) {
431 goto failure;
433 result = json_add_string(&sub_json, "username", uid_str);
434 if (result < 0) {
435 goto failure;
437 result = json_add_string(&sub_json, "groupname", gid_str);
438 if (result < 0) {
439 goto failure;
441 result = json_add_string(&sub_json, "remote_machine", session->remote_machine);
442 if (result < 0) {
443 goto failure;
445 result = json_add_string(&sub_json, "hostname", session->hostname);
446 if (result < 0) {
447 goto failure;
449 result = json_add_string(&sub_json, "session_dialect", connection_dialect);
450 if (result < 0) {
451 goto failure;
453 result = add_crypto_to_json(&sub_json, "encryption",
454 encryption_cipher, encryption_degree);
455 if (result < 0) {
456 goto failure;
458 result = add_crypto_to_json(&sub_json, "signing",
459 signing_cipher, signing_degree);
460 if (result < 0) {
461 goto failure;
464 result = json_add_object(&session_json, id_str, &sub_json);
465 if (result < 0) {
466 goto failure;
469 result = json_update_object(&state->root_json, "sessions", &session_json);
470 if (result < 0) {
471 goto failure;
474 TALLOC_FREE(tmp_ctx);
475 return 0;
476 failure:
477 json_free(&sub_json);
478 TALLOC_FREE(tmp_ctx);
479 return -1;
482 static int add_access_mode_to_json(struct json_object *parent_json,
483 int access_int)
485 struct json_object access_json;
486 char *access_hex = NULL;
487 const char *access_str = NULL;
488 int result;
490 TALLOC_CTX *tmp_ctx = talloc_stackframe();
491 if (tmp_ctx == NULL) {
492 return -1;
495 access_json = json_new_object();
496 if (json_is_invalid(&access_json)) {
497 goto failure;
500 access_hex = talloc_asprintf(tmp_ctx, "0x%08x", access_int);
501 result = json_add_string(&access_json, "hex", access_hex);
502 if (result < 0) {
503 goto failure;
505 result = map_mask_to_json(&access_json, access_int, access_mask);
506 if (result < 0) {
507 goto failure;
510 access_str = talloc_asprintf(tmp_ctx, "%s%s",
511 (access_int & FILE_READ_DATA)?"R":"",
512 (access_int & (FILE_WRITE_DATA|FILE_APPEND_DATA))?"W":"");
513 result = json_add_string(&access_json, "text", access_str);
514 if (result < 0) {
515 goto failure;
518 result = json_add_object(parent_json, "access_mask", &access_json);
519 if (result < 0) {
520 goto failure;
523 TALLOC_FREE(tmp_ctx);
524 return 0;
525 failure:
526 json_free(&access_json);
527 TALLOC_FREE(tmp_ctx);
528 return -1;
531 static int add_caching_to_json(struct json_object *parent_json,
532 int op_type,
533 int lease_type)
535 struct json_object caching_json;
536 char *hex = NULL;
537 char *caching_text = NULL;
538 int caching_type = 0;
539 int result;
541 TALLOC_CTX *tmp_ctx = talloc_stackframe();
542 if (tmp_ctx == NULL) {
543 return -1;
546 caching_json = json_new_object();
547 if (json_is_invalid(&caching_json)) {
548 goto failure;
551 if (op_type & LEASE_OPLOCK) {
552 caching_type = lease_type;
553 } else {
554 if (op_type & LEVEL_II_OPLOCK) {
555 caching_type = SMB2_LEASE_READ;
556 } else if (op_type & EXCLUSIVE_OPLOCK) {
557 caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE;
558 } else if (op_type & BATCH_OPLOCK) {
559 caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE;
562 result = map_mask_to_json(&caching_json, caching_type, lease_mask);
563 if (result < 0) {
564 goto failure;
567 hex = talloc_asprintf(tmp_ctx, "0x%08x", caching_type);
568 if (hex == NULL) {
569 goto failure;
571 result = json_add_string(&caching_json, "hex", hex);
572 if (result < 0) {
573 goto failure;
576 caching_text = talloc_asprintf(tmp_ctx, "%s%s%s",
577 (caching_type & SMB2_LEASE_READ)?"R":"",
578 (caching_type & SMB2_LEASE_WRITE)?"W":"",
579 (caching_type & SMB2_LEASE_HANDLE)?"H":"");
580 if (caching_text == NULL) {
581 return -1;
584 result = json_add_string(&caching_json, "text", caching_text);
585 if (result < 0) {
586 goto failure;
589 result = json_add_object(parent_json, "caching", &caching_json);
590 if (result < 0) {
591 goto failure;
594 TALLOC_FREE(tmp_ctx);
595 return 0;
596 failure:
597 json_free(&caching_json);
598 TALLOC_FREE(tmp_ctx);
599 return -1;
602 static int add_oplock_to_json(struct json_object *parent_json,
603 uint16_t op_type,
604 const char *op_str)
606 struct json_object oplock_json;
607 int result;
609 oplock_json = json_new_object();
610 if (json_is_invalid(&oplock_json)) {
611 goto failure;
614 if (op_type != 0) {
615 result = map_mask_to_json(&oplock_json, op_type, oplock_mask);
616 if (result < 0) {
617 goto failure;
619 result = json_add_string(&oplock_json, "text", op_str);
620 if (result < 0) {
621 goto failure;
625 result = json_add_object(parent_json, "oplock", &oplock_json);
626 if (result < 0) {
627 goto failure;
630 return 0;
631 failure:
632 json_free(&oplock_json);
633 return -1;
636 static int lease_key_to_str(struct smb2_lease_key lease_key,
637 char *lease_str)
639 uint8_t _buf[16] = {0};
640 DATA_BLOB blob = data_blob_const(_buf, sizeof(_buf));
641 struct GUID guid;
642 NTSTATUS status;
643 char *tmp = NULL;
645 TALLOC_CTX *tmp_ctx = talloc_stackframe();
646 if (tmp_ctx == NULL) {
647 return -1;
650 PUSH_LE_U64(_buf, 0, lease_key.data[0]);
651 PUSH_LE_U64(_buf, 8, lease_key.data[1]);
653 status = GUID_from_ndr_blob(&blob, &guid);
654 if (!NT_STATUS_IS_OK(status)) {
655 goto failure;
657 tmp = GUID_string(tmp_ctx, &guid);
658 if (tmp == NULL) {
659 goto failure;
661 fstrcpy(lease_str, tmp);
663 TALLOC_FREE(tmp_ctx);
664 return 0;
665 failure:
666 TALLOC_FREE(tmp_ctx);
667 return -1;
670 static int add_lease_to_json(struct json_object *parent_json,
671 int lease_type,
672 struct smb2_lease_key lease_key,
673 bool add_lease)
675 struct json_object lease_json;
676 char *lease_hex = NULL;
677 char *lease_text = NULL;
678 fstring lease_key_str;
679 int result;
681 TALLOC_CTX *tmp_ctx = talloc_stackframe();
682 if (tmp_ctx == NULL) {
683 return -1;
686 lease_json = json_new_object();
687 if (json_is_invalid(&lease_json)) {
688 goto failure;
692 if (add_lease) {
693 result = lease_key_to_str(lease_key, lease_key_str);
694 if (result < 0) {
695 goto failure;
697 result = json_add_string(&lease_json, "lease_key", lease_key_str);
698 if (result < 0) {
699 goto failure;
701 lease_hex = talloc_asprintf(tmp_ctx, "0x%08x", lease_type);
702 result = json_add_string(&lease_json, "hex", lease_hex);
703 if (result < 0) {
704 goto failure;
706 if (lease_type > (SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE + SMB2_LEASE_READ)) {
707 result = json_add_bool(&lease_json, "UNKNOWN", true);
708 if (result < 0) {
709 goto failure;
711 } else {
712 result = map_mask_to_json(&lease_json, lease_type, lease_mask);
713 if (result < 0) {
714 goto failure;
717 lease_text = talloc_asprintf(tmp_ctx, "%s%s%s",
718 (lease_type & SMB2_LEASE_READ)?"R":"",
719 (lease_type & SMB2_LEASE_WRITE)?"W":"",
720 (lease_type & SMB2_LEASE_HANDLE)?"H":"");
722 result = json_add_string(&lease_json, "text", lease_text);
723 if (result < 0) {
724 goto failure;
728 result = json_add_object(parent_json, "lease", &lease_json);
729 if (result < 0) {
730 goto failure;
733 TALLOC_FREE(tmp_ctx);
734 return 0;
735 failure:
736 json_free(&lease_json);
737 TALLOC_FREE(tmp_ctx);
738 return -1;
741 static int add_sharemode_to_json(struct json_object *parent_json,
742 int sharemode)
744 struct json_object sharemode_json;
745 char *hex = NULL;
746 char *text = NULL;
747 int result;
749 TALLOC_CTX *tmp_ctx = talloc_stackframe();
750 if (tmp_ctx == NULL) {
751 return -1;
754 sharemode_json = json_new_object();
755 if (json_is_invalid(&sharemode_json)) {
756 goto failure;
759 hex = talloc_asprintf(tmp_ctx, "0x%08x", sharemode);
760 if (hex == NULL) {
761 goto failure;
763 result = json_add_string(&sharemode_json, "hex", hex);
764 if (result < 0) {
765 goto failure;
767 result = map_mask_to_json(&sharemode_json, sharemode, sharemode_mask);
768 if (result < 0) {
769 goto failure;
772 text = talloc_asprintf(tmp_ctx, "%s%s%s",
773 (sharemode & FILE_SHARE_READ)?"R":"",
774 (sharemode & FILE_SHARE_WRITE)?"W":"",
775 (sharemode & FILE_SHARE_DELETE)?"D":"");
776 if (text == NULL) {
777 goto failure;
779 result = json_add_string(&sharemode_json, "text", text);
780 if (result < 0) {
781 goto failure;
784 result = json_add_object(parent_json, "sharemode", &sharemode_json);
785 if (result < 0) {
786 goto failure;
789 TALLOC_FREE(tmp_ctx);
790 return 0;
791 failure:
792 json_free(&sharemode_json);
793 TALLOC_FREE(tmp_ctx);
794 return -1;
797 static int add_open_to_json(struct json_object *parent_json,
798 const struct share_mode_entry *e,
799 bool resolve_uids,
800 const char *op_str,
801 uint32_t lease_type,
802 const char *uid_str)
804 struct json_object sub_json = {
805 .valid = false,
807 struct json_object opens_json = {
808 .valid = false,
810 struct timeval_buf tv_buf;
811 int result = 0;
812 char *timestr;
813 bool add_lease = false;
814 char *key = NULL;
815 char *share_file_id = NULL;
816 char *pid = NULL;
817 struct server_id_buf tmp;
819 TALLOC_CTX *tmp_ctx = talloc_stackframe();
820 if (tmp_ctx == NULL) {
821 return -1;
824 opens_json = json_get_object(parent_json, "opens");
825 if (json_is_invalid(&opens_json)) {
826 goto failure;
828 sub_json = json_new_object();
829 if (json_is_invalid(&sub_json)) {
830 goto failure;
834 result = add_server_id_to_json(&sub_json, e->pid);
835 if (result < 0) {
836 goto failure;
838 if (resolve_uids) {
839 result = json_add_string(&sub_json, "username", uid_str);
840 if (result < 0) {
841 goto failure;
844 result = json_add_int(&sub_json, "uid", e->uid);
845 if (result < 0) {
846 goto failure;
848 share_file_id = talloc_asprintf(tmp_ctx, "%"PRIu64, e->share_file_id);
849 result = json_add_string(&sub_json, "share_file_id", share_file_id);
850 if (result < 0) {
851 goto failure;
853 result = add_sharemode_to_json(&sub_json, e->share_access);
854 if (result < 0) {
855 goto failure;
857 result = add_access_mode_to_json(&sub_json, e->access_mask);
858 if (result < 0) {
859 goto failure;
861 result = add_caching_to_json(&sub_json, e->op_type, lease_type);
862 if (result < 0) {
863 goto failure;
865 result = add_oplock_to_json(&sub_json, e->op_type, op_str);
866 if (result < 0) {
867 goto failure;
869 add_lease = e->op_type & LEASE_OPLOCK;
870 result = add_lease_to_json(&sub_json, lease_type, e->lease_key, add_lease);
871 if (result < 0) {
872 goto failure;
875 timestr = timeval_str_buf(&e->time, true, true, &tv_buf);
876 if (timestr == NULL) {
877 goto failure;
879 result = json_add_string(&sub_json, "opened_at", timestr);
880 if (result < 0) {
881 goto failure;
884 pid = server_id_str_buf(e->pid, &tmp);
885 key = talloc_asprintf(tmp_ctx, "%s/%"PRIu64, pid, e->share_file_id);
886 result = json_add_object(&opens_json, key, &sub_json);
887 if (result < 0) {
888 goto failure;
890 result = json_update_object(parent_json, "opens", &opens_json);
891 if (result < 0) {
892 goto failure;
895 TALLOC_FREE(tmp_ctx);
896 return 0;
897 failure:
898 json_free(&opens_json);
899 json_free(&sub_json);
900 TALLOC_FREE(tmp_ctx);
901 return -1;
904 static int add_fileid_to_json(struct json_object *parent_json,
905 struct file_id fid)
907 struct json_object fid_json;
908 int result;
910 fid_json = json_new_object();
911 if (json_is_invalid(&fid_json)) {
912 goto failure;
915 result = json_add_int(&fid_json, "devid", fid.devid);
916 if (result < 0) {
917 goto failure;
919 result = json_add_int(&fid_json, "inode", fid.inode);
920 if (result < 0) {
921 goto failure;
923 result = json_add_int(&fid_json, "extid", fid.extid);
924 if (result < 0) {
925 goto failure;
928 result = json_add_object(parent_json, "fileid", &fid_json);
929 if (result < 0) {
930 goto failure;
933 return 0;
934 failure:
935 json_free(&fid_json);
936 return -1;
939 int print_share_mode_json(struct traverse_state *state,
940 const struct share_mode_data *d,
941 const struct share_mode_entry *e,
942 struct file_id fid,
943 const char *uid_str,
944 const char *op_str,
945 uint32_t lease_type,
946 const char *filename)
948 struct json_object locks_json = {
949 .valid = false,
951 struct json_object file_json = {
952 .valid = false,
954 char *key = NULL;
955 int result = 0;
957 TALLOC_CTX *tmp_ctx = talloc_stackframe();
958 if (tmp_ctx == NULL) {
959 return -1;
962 if (d->servicepath[strlen(d->servicepath)-1] == '/') {
963 key = talloc_asprintf(tmp_ctx, "%s%s", d->servicepath, filename);
964 } else {
965 key = talloc_asprintf(tmp_ctx, "%s/%s", d->servicepath, filename);
968 locks_json = json_get_object(&state->root_json, "open_files");
969 if (json_is_invalid(&locks_json)) {
970 goto failure;
972 file_json = json_get_object(&locks_json, key);
973 if (json_is_invalid(&file_json)) {
974 goto failure;
977 result = json_add_string(&file_json, "service_path", d->servicepath);
978 if (result < 0) {
979 goto failure;
981 result = json_add_string(&file_json, "filename", filename);
982 if (result < 0) {
983 goto failure;
985 result = add_fileid_to_json(&file_json, fid);
986 if (result < 0) {
987 goto failure;
989 result = json_add_int(&file_json, "num_pending_deletes", d->num_delete_tokens);
990 if (result < 0) {
991 goto failure;
994 result = add_open_to_json(&file_json,
996 state->resolve_uids,
997 op_str,
998 lease_type,
999 uid_str);
1000 if (result < 0) {
1001 goto failure;
1004 result = json_update_object(&locks_json, key, &file_json);
1005 if (result < 0) {
1006 goto failure;
1008 result = json_update_object(&state->root_json, "open_files", &locks_json);
1009 if (result < 0) {
1010 goto failure;
1013 TALLOC_FREE(tmp_ctx);
1014 return 0;
1015 failure:
1016 json_free(&file_json);
1017 json_free(&locks_json);
1018 TALLOC_FREE(tmp_ctx);
1019 return -1;
1022 static int add_lock_to_json(struct json_object *parent_json,
1023 struct server_id server_id,
1024 const char *type,
1025 enum brl_flavour flavour,
1026 intmax_t start,
1027 intmax_t size)
1029 struct json_object sub_json = {
1030 .valid = false,
1032 struct json_object locks_json = {
1033 .valid = false,
1035 const char *flavour_str;
1036 int result = 0;
1038 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1039 if (tmp_ctx == NULL) {
1040 return -1;
1043 locks_json = json_get_array(parent_json, "locks");
1044 if (json_is_invalid(&locks_json)) {
1045 goto failure;
1047 sub_json = json_new_object();
1048 if (json_is_invalid(&sub_json)) {
1049 goto failure;
1052 result = add_server_id_to_json(&sub_json, server_id);
1053 if (result < 0) {
1054 goto failure;
1056 result = json_add_string(&sub_json, "type", type);
1057 if (result < 0) {
1058 goto failure;
1060 flavour_str = talloc_asprintf(tmp_ctx, "%s%s",
1061 (flavour == WINDOWS_LOCK)?"Windows":"",
1062 (flavour == POSIX_LOCK)?"Posix":"");
1063 result = json_add_string(&sub_json, "flavour", flavour_str);
1064 if (result < 0) {
1065 goto failure;
1067 result = json_add_int(&sub_json, "start", start);
1068 if (result < 0) {
1069 goto failure;
1071 result = json_add_int(&sub_json, "size", size);
1072 if (result < 0) {
1073 goto failure;
1076 result = json_add_object(&locks_json, NULL, &sub_json);
1077 if (result < 0) {
1078 goto failure;
1080 result = json_update_object(parent_json, "locks", &locks_json);
1081 if (result < 0) {
1082 goto failure;
1085 TALLOC_FREE(tmp_ctx);
1086 return 0;
1087 failure:
1088 json_free(&locks_json);
1089 json_free(&sub_json);
1090 TALLOC_FREE(tmp_ctx);
1091 return -1;
1094 int print_brl_json(struct traverse_state *state,
1095 const struct server_id server_id,
1096 struct file_id fid,
1097 const char *type,
1098 enum brl_flavour flavour,
1099 intmax_t start,
1100 intmax_t size,
1101 const char *sharepath,
1102 const char *filename)
1104 struct json_object file_json;
1105 struct json_object brl_json;
1106 int result = 0;
1107 char *key;
1109 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1110 if (tmp_ctx == NULL) {
1111 return -1;
1114 if (sharepath[strlen(sharepath)-1] == '/') {
1115 key = talloc_asprintf(tmp_ctx, "%s%s", sharepath, filename);
1116 } else {
1117 key = talloc_asprintf(tmp_ctx, "%s/%s", sharepath, filename);
1119 if (key == NULL) {
1120 goto failure;
1123 brl_json = json_get_object(&state->root_json, "byte_range_locks");
1124 if (json_is_invalid(&brl_json)) {
1125 goto failure;
1127 file_json = json_get_object(&brl_json, key);
1128 if (json_is_invalid(&file_json)) {
1129 goto failure;
1132 result = add_fileid_to_json(&file_json, fid);
1133 if (result < 0) {
1134 goto failure;
1136 result = json_add_string(&file_json, "file_name", filename);
1137 if (result < 0) {
1138 goto failure;
1140 result = json_add_string(&file_json, "share_path", sharepath);
1141 if (result < 0) {
1142 goto failure;
1144 result = add_server_id_to_json(&file_json, server_id);
1145 if (result < 0) {
1146 goto failure;
1148 result = add_lock_to_json(&file_json, server_id, type, flavour, start, size);
1149 if (result < 0) {
1150 goto failure;
1153 result = json_add_object(&brl_json, key, &file_json);
1154 if (result < 0) {
1155 goto failure;
1157 result = json_update_object(&state->root_json, "byte_range_locks", &brl_json);
1158 if (result < 0) {
1159 goto failure;
1162 TALLOC_FREE(tmp_ctx);
1163 return 0;
1164 failure:
1165 json_free(&file_json);
1166 json_free(&brl_json);
1167 TALLOC_FREE(tmp_ctx);
1168 return -1;
1171 bool print_notify_rec_json(struct traverse_state *state,
1172 const struct notify_instance *instance,
1173 const struct server_id server_id,
1174 const char *path)
1176 struct json_object sub_json;
1177 struct json_object notify_json;
1178 char *filter = NULL;
1179 char *subdir_filter = NULL;
1180 struct timeval_buf tv_buf;
1181 struct timeval val;
1182 char *time = NULL;
1183 char *pid = NULL;
1184 struct server_id_buf tmp;
1185 int result = 0;
1187 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1188 if (tmp_ctx == NULL) {
1189 return -1;
1192 sub_json = json_new_object();
1193 if (json_is_invalid(&sub_json)) {
1194 return false;
1196 notify_json = json_get_object(&state->root_json, "notifies");
1197 if (json_is_invalid(&notify_json)) {
1198 goto failure;
1201 result = add_server_id_to_json(&sub_json, server_id);
1202 if (result < 0) {
1203 goto failure;
1205 result = json_add_string(&sub_json, "path", path);
1206 if (result < 0) {
1207 goto failure;
1209 filter = talloc_asprintf(tmp_ctx, "%u", instance->filter);
1210 if (filter == NULL) {
1211 goto failure;
1213 result = json_add_string(&sub_json, "filter", filter);
1214 if (result < 0) {
1215 goto failure;
1217 subdir_filter = talloc_asprintf(tmp_ctx, "%u", instance->subdir_filter);
1218 if (subdir_filter == NULL) {
1219 goto failure;
1221 result = json_add_string(&sub_json, "subdir_filter", subdir_filter);
1222 if (result < 0) {
1223 goto failure;
1225 val = convert_timespec_to_timeval(instance->creation_time);
1226 time = timeval_str_buf(&val, true, true, &tv_buf);
1227 result = json_add_string(&sub_json, "creation_time", time);
1228 if (result < 0) {
1229 goto failure;
1232 pid = server_id_str_buf(server_id, &tmp);
1233 result = json_add_object(&notify_json, pid, &sub_json);
1234 if (result < 0) {
1235 goto failure;
1238 result = json_update_object(&state->root_json, "notifies", &notify_json);
1239 if (result < 0) {
1240 goto failure;
1243 TALLOC_FREE(tmp_ctx);
1244 return true;
1245 failure:
1246 json_free(&sub_json);
1247 TALLOC_FREE(tmp_ctx);
1248 return false;