s3:utils: Fix auth callback with smburl
[samba.git] / source3 / utils / status_json.c
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/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"
31
32 #include <jansson.h>
33 #include "audit_logging.h" /* various JSON helpers */
34 #include "auth/common_auth.h"
35
36 int add_general_information_to_json(struct traverse_state *state)
37 {
38         int result;
39
40         result = json_add_timestamp(&state->root_json);
41         if (result < 0) {
42                 return -1;
43         }
44
45         result = json_add_string(&state->root_json, "version", samba_version_string());
46         if (result < 0) {
47                 return -1;
48         }
49
50         result = json_add_string(&state->root_json, "smb_conf", get_dyn_CONFIGFILE());
51         if (result < 0) {
52                 return -1;
53         }
54
55         return 0;
56 }
57
58 static int add_server_id_to_json(struct json_object *parent_json,
59                                  const struct server_id server_id)
60 {
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;
67
68         TALLOC_CTX *tmp_ctx = talloc_stackframe();
69         if (tmp_ctx == NULL) {
70                 return -1;
71         }
72
73         sub_json = json_new_object();
74         if (json_is_invalid(&sub_json)) {
75                 goto failure;
76         }
77
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;
83         }
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;
88         }
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;
93         }
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;
99         }
100
101         result = json_add_object(parent_json, "server_id", &sub_json);
102         if (result < 0) {
103                 goto failure;
104         }
105
106         TALLOC_FREE(tmp_ctx);
107         return 0;
108 failure:
109         json_free(&sub_json);
110         TALLOC_FREE(tmp_ctx);
111         return -1;
112 }
113
114 struct mask2txt {
115         uint32_t mask;
116         const char *string_desc;
117 };
118
119 /*
120  * Convert a mask of some sort (access, oplock, leases),
121  * to key/value pairs in a JSON object.
122  */
123 static int map_mask_to_json(struct json_object *root_json,
124                             uint32_t tomap,
125                             const struct mask2txt *table)
126 {
127         const struct mask2txt *a = NULL;
128         int result = 0;
129
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);
133
134                 if (result < 0) {
135                         return result;
136                 }
137                 tomap &= ~a->mask;
138         }
139
140         /* Assert we know about all requested "tomap" values */
141         SMB_ASSERT(tomap == 0);
142
143         return 0;
144 }
145
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}
162 };
163
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}
170 };
171
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}
177 };
178
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}
184 };
185
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)
191 {
192         struct json_object section_json = {
193                 .valid = false,
194         };
195         struct json_object subsection_json = {
196                 .valid = false,
197         };
198         int result = 0;
199
200         section_json = json_get_object(&state->root_json, section);
201         if (json_is_invalid(&section_json)) {
202                 goto failure;
203         }
204         subsection_json = json_get_object(&section_json, subsection);
205         if (json_is_invalid(&subsection_json)) {
206                 goto failure;
207         }
208
209         result = json_add_int(&subsection_json, key, value);
210         if (result < 0) {
211                 goto failure;
212         }
213
214         result = json_update_object(&section_json, subsection,  &subsection_json);
215         if (result < 0) {
216                 goto failure;
217         }
218         result = json_update_object(&state->root_json, section, &section_json);
219         if (result < 0) {
220                 goto failure;
221         }
222
223         return 0;
224 failure:
225         json_free(&section_json);
226         json_free(&subsection_json);
227         return -1;
228 }
229
230 int add_section_to_json(struct traverse_state *state,
231                         const char *key)
232 {
233         struct json_object empty_json;
234         int result;
235
236         empty_json = json_new_object();
237         if (json_is_invalid(&empty_json)) {
238                 return -1;
239         }
240
241         result = json_add_object(&state->root_json, key, &empty_json);
242         if (result < 0) {
243                 return -1;
244         }
245
246         return result;
247 }
248
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)
253 {
254         struct json_object sub_json;
255         const char *degree_str;
256         int result;
257
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";
264         }
265
266         sub_json = json_new_object();
267         if (json_is_invalid(&sub_json)) {
268                 goto failure;
269         }
270
271         result = json_add_string(&sub_json, "cipher", cipher);
272         if (result < 0) {
273                 goto failure;
274         }
275         result = json_add_string(&sub_json, "degree", degree_str);
276         if (result < 0) {
277                 goto failure;
278         }
279         result = json_add_object(parent_json, key, &sub_json);
280         if (result < 0) {
281                 goto failure;
282         }
283
284         return 0;
285 failure:
286         json_free(&sub_json);
287         return -1;
288 }
289
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)
296 {
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;
305
306         TALLOC_CTX *tmp_ctx = talloc_stackframe();
307         if (tmp_ctx == NULL) {
308                 return -1;
309         }
310
311         sub_json = json_new_object();
312         if (json_is_invalid(&sub_json)) {
313                 goto failure;
314         }
315         connections_json = json_get_object(&state->root_json, "tcons");
316         if (json_is_invalid(&connections_json)) {
317                 goto failure;
318         }
319
320         result = json_add_string(&sub_json, "service", crec->servicename);
321         if (result < 0) {
322                 goto failure;
323         }
324         result = add_server_id_to_json(&sub_json, crec->pid);
325         if (result < 0) {
326                 goto failure;
327         }
328         tcon_id_str = talloc_asprintf(tmp_ctx, "%u", crec->cnum);
329         if (tcon_id_str == NULL) {
330                 goto failure;
331         }
332         result = json_add_string(&sub_json, "tcon_id", tcon_id_str);
333         if (result < 0) {
334                 goto failure;
335         }
336         sess_id_str = talloc_asprintf(tmp_ctx, "%u", crec->sess_id);
337         if (sess_id_str == NULL) {
338                 goto failure;
339         }
340         result = json_add_string(&sub_json, "session_id", sess_id_str);
341         if (result < 0) {
342                 goto failure;
343         }
344         result = json_add_string(&sub_json, "machine", crec->machine);
345         if (result < 0) {
346                 goto failure;
347         }
348         nttime_to_timeval(&tv, crec->start);
349         time = timeval_str_buf(&tv, true, true, &tv_buf);
350         if (time == NULL) {
351                 goto failure;
352         }
353         result = json_add_string(&sub_json, "connected_at", time);
354         if (result < 0) {
355                 goto failure;
356         }
357         result = add_crypto_to_json(&sub_json, "encryption",
358                                    encryption_cipher, encryption_degree);
359         if (result < 0) {
360                 goto failure;
361         }
362         result = add_crypto_to_json(&sub_json, "signing",
363                                    signing_cipher, signing_degree);
364         if (result < 0) {
365                 goto failure;
366         }
367
368         result = json_add_object(&connections_json, tcon_id_str, &sub_json);
369         if (result < 0) {
370                 goto failure;
371         }
372
373         result = json_update_object(&state->root_json, "tcons", &connections_json);
374         if (result < 0) {
375                 goto failure;
376         }
377
378         TALLOC_FREE(tmp_ctx);
379         return 0;
380 failure:
381         json_free(&sub_json);
382         TALLOC_FREE(tmp_ctx);
383         return -1;
384 }
385
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)
395 {
396         struct json_object sub_json;
397         struct json_object session_json;
398         int result = 0;
399         char *id_str = NULL;
400
401         TALLOC_CTX *tmp_ctx = talloc_stackframe();
402         if (tmp_ctx == NULL) {
403                 return -1;
404         }
405
406         sub_json = json_new_object();
407         if (json_is_invalid(&sub_json)) {
408                 goto failure;
409         }
410
411         session_json = json_get_object(&state->root_json, "sessions");
412         if (json_is_invalid(&session_json)) {
413                 goto failure;
414         }
415
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;
420         }
421         result = add_server_id_to_json(&sub_json, session->pid);
422         if (result < 0) {
423                 goto failure;
424         }
425         result = json_add_int(&sub_json, "uid", session->uid);
426         if (result < 0) {
427                 goto failure;
428         }
429         result = json_add_int(&sub_json, "gid", session->gid);
430         if (result < 0) {
431                 goto failure;
432         }
433         result = json_add_string(&sub_json, "username", uid_str);
434         if (result < 0) {
435                 goto failure;
436         }
437         result = json_add_string(&sub_json, "groupname", gid_str);
438         if (result < 0) {
439                 goto failure;
440         }
441         result = json_add_string(&sub_json, "remote_machine", session->remote_machine);
442         if (result < 0) {
443                 goto failure;
444         }
445         result = json_add_string(&sub_json, "hostname", session->hostname);
446         if (result < 0) {
447                 goto failure;
448         }
449         result = json_add_string(&sub_json, "session_dialect", connection_dialect);
450         if (result < 0) {
451                 goto failure;
452         }
453         result = add_crypto_to_json(&sub_json, "encryption",
454                                     encryption_cipher, encryption_degree);
455         if (result < 0) {
456                 goto failure;
457         }
458         result = add_crypto_to_json(&sub_json, "signing",
459                                     signing_cipher, signing_degree);
460         if (result < 0) {
461                 goto failure;
462         }
463
464         result = json_add_object(&session_json, id_str, &sub_json);
465         if (result < 0) {
466                 goto failure;
467         }
468
469         result = json_update_object(&state->root_json, "sessions", &session_json);
470         if (result < 0) {
471                 goto failure;
472         }
473
474         TALLOC_FREE(tmp_ctx);
475         return 0;
476 failure:
477         json_free(&sub_json);
478         TALLOC_FREE(tmp_ctx);
479         return -1;
480 }
481
482 static int add_access_mode_to_json(struct json_object *parent_json,
483                                    int access_int)
484 {
485         struct json_object access_json;
486         char *access_hex = NULL;
487         const char *access_str = NULL;
488         int result;
489
490         TALLOC_CTX *tmp_ctx = talloc_stackframe();
491         if (tmp_ctx == NULL) {
492                 return -1;
493         }
494
495         access_json = json_new_object();
496         if (json_is_invalid(&access_json)) {
497                 goto failure;
498         }
499
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;
504         }
505         result = map_mask_to_json(&access_json, access_int, access_mask);
506         if (result < 0) {
507                 goto failure;
508         }
509
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;
516         }
517
518         result = json_add_object(parent_json, "access_mask", &access_json);
519         if (result < 0) {
520                 goto failure;
521         }
522
523         TALLOC_FREE(tmp_ctx);
524         return 0;
525 failure:
526         json_free(&access_json);
527         TALLOC_FREE(tmp_ctx);
528         return -1;
529 }
530
531 static int add_caching_to_json(struct json_object *parent_json,
532                               int op_type,
533                               int lease_type)
534 {
535         struct json_object caching_json;
536         char *hex = NULL;
537         char *caching_text = NULL;
538         int caching_type = 0;
539         int result;
540
541         TALLOC_CTX *tmp_ctx = talloc_stackframe();
542         if (tmp_ctx == NULL) {
543                 return -1;
544         }
545
546         caching_json = json_new_object();
547         if (json_is_invalid(&caching_json)) {
548                 goto failure;
549         }
550
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;
560                 }
561         }
562         result = map_mask_to_json(&caching_json, caching_type, lease_mask);
563         if (result < 0) {
564                 goto failure;
565         }
566
567         hex = talloc_asprintf(tmp_ctx, "0x%08x", caching_type);
568         if (hex == NULL) {
569                 goto failure;
570         }
571         result = json_add_string(&caching_json, "hex", hex);
572         if (result < 0) {
573                 goto failure;
574         }
575
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;
582         }
583
584         result = json_add_string(&caching_json, "text", caching_text);
585         if (result < 0) {
586                 goto failure;
587         }
588
589         result = json_add_object(parent_json, "caching", &caching_json);
590         if (result < 0) {
591                 goto failure;
592         }
593
594         TALLOC_FREE(tmp_ctx);
595         return 0;
596 failure:
597         json_free(&caching_json);
598         TALLOC_FREE(tmp_ctx);
599         return -1;
600 }
601
602 static int add_oplock_to_json(struct json_object *parent_json,
603                               uint16_t op_type,
604                               const char *op_str)
605 {
606         struct json_object oplock_json;
607         int result;
608
609         oplock_json = json_new_object();
610         if (json_is_invalid(&oplock_json)) {
611                 goto failure;
612         }
613
614         if (op_type != 0) {
615                 result = map_mask_to_json(&oplock_json, op_type, oplock_mask);
616                 if (result < 0) {
617                         goto failure;
618                 }
619                 result = json_add_string(&oplock_json, "text", op_str);
620                 if (result < 0) {
621                         goto failure;
622                 }
623         }
624
625         result = json_add_object(parent_json, "oplock", &oplock_json);
626         if (result < 0) {
627                 goto failure;
628         }
629
630         return 0;
631 failure:
632         json_free(&oplock_json);
633         return -1;
634 }
635
636 static int lease_key_to_str(struct smb2_lease_key lease_key,
637                             char *lease_str)
638 {
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;
644
645         TALLOC_CTX *tmp_ctx = talloc_stackframe();
646         if (tmp_ctx == NULL) {
647                 return -1;
648         }
649
650         PUSH_LE_U64(_buf, 0, lease_key.data[0]);
651         PUSH_LE_U64(_buf, 8, lease_key.data[1]);
652
653         status = GUID_from_ndr_blob(&blob, &guid);
654         if (!NT_STATUS_IS_OK(status)) {
655                 goto failure;
656         }
657         tmp = GUID_string(tmp_ctx, &guid);
658         if (tmp == NULL) {
659                 goto failure;
660         }
661         fstrcpy(lease_str, tmp);
662
663         TALLOC_FREE(tmp_ctx);
664         return 0;
665 failure:
666         TALLOC_FREE(tmp_ctx);
667         return -1;
668 }
669
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)
674 {
675         struct json_object lease_json;
676         char *lease_hex = NULL;
677         char *lease_text = NULL;
678         fstring lease_key_str;
679         int result;
680
681         TALLOC_CTX *tmp_ctx = talloc_stackframe();
682         if (tmp_ctx == NULL) {
683                 return -1;
684         }
685
686         lease_json = json_new_object();
687         if (json_is_invalid(&lease_json)) {
688                 goto failure;
689         }
690
691
692         if (add_lease) {
693                 result = lease_key_to_str(lease_key, lease_key_str);
694                 if (result < 0) {
695                         goto failure;
696                 }
697                 result = json_add_string(&lease_json, "lease_key", lease_key_str);
698                 if (result < 0) {
699                         goto failure;
700                 }
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;
705                 }
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;
710                         }
711                 } else {
712                         result = map_mask_to_json(&lease_json, lease_type, lease_mask);
713                         if (result < 0) {
714                                 goto failure;
715                         }
716                 }
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":"");
721
722                 result = json_add_string(&lease_json, "text", lease_text);
723                 if (result < 0) {
724                         goto failure;
725                 }
726         }
727
728         result = json_add_object(parent_json, "lease", &lease_json);
729         if (result < 0) {
730                 goto failure;
731         }
732
733         TALLOC_FREE(tmp_ctx);
734         return 0;
735 failure:
736         json_free(&lease_json);
737         TALLOC_FREE(tmp_ctx);
738         return -1;
739 }
740
741 static int add_sharemode_to_json(struct json_object *parent_json,
742                                  int sharemode)
743 {
744         struct json_object sharemode_json;
745         char *hex = NULL;
746         char *text = NULL;
747         int result;
748
749         TALLOC_CTX *tmp_ctx = talloc_stackframe();
750         if (tmp_ctx == NULL) {
751                 return -1;
752         }
753
754         sharemode_json = json_new_object();
755         if (json_is_invalid(&sharemode_json)) {
756                 goto failure;
757         }
758
759         hex = talloc_asprintf(tmp_ctx, "0x%08x", sharemode);
760         if (hex == NULL) {
761                 goto failure;
762         }
763         result = json_add_string(&sharemode_json, "hex", hex);
764         if (result < 0) {
765                 goto failure;
766         }
767         result = map_mask_to_json(&sharemode_json, sharemode, sharemode_mask);
768         if (result < 0) {
769                 goto failure;
770         }
771
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;
778         }
779         result = json_add_string(&sharemode_json, "text", text);
780         if (result < 0) {
781                 goto failure;
782         }
783
784         result = json_add_object(parent_json, "sharemode", &sharemode_json);
785         if (result < 0) {
786                 goto failure;
787         }
788
789         TALLOC_FREE(tmp_ctx);
790         return 0;
791 failure:
792         json_free(&sharemode_json);
793         TALLOC_FREE(tmp_ctx);
794         return -1;
795 }
796
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)
803 {
804         struct json_object sub_json = {
805                 .valid = false,
806         };
807         struct json_object opens_json = {
808                 .valid = false,
809         };
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;
818
819         TALLOC_CTX *tmp_ctx = talloc_stackframe();
820         if (tmp_ctx == NULL) {
821                 return -1;
822         }
823
824         opens_json = json_get_object(parent_json, "opens");
825         if (json_is_invalid(&opens_json)) {
826                 goto failure;
827         }
828         sub_json = json_new_object();
829         if (json_is_invalid(&sub_json)) {
830                 goto failure;
831         }
832
833
834         result = add_server_id_to_json(&sub_json, e->pid);
835         if (result < 0) {
836                 goto failure;
837         }
838         if (resolve_uids) {
839                 result = json_add_string(&sub_json, "username", uid_str);
840                 if (result < 0) {
841                         goto failure;
842                 }
843         }
844         result = json_add_int(&sub_json, "uid", e->uid);
845         if (result < 0) {
846                 goto failure;
847         }
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;
852         }
853         result = add_sharemode_to_json(&sub_json, e->share_access);
854         if (result < 0) {
855                 goto failure;
856         }
857         result = add_access_mode_to_json(&sub_json, e->access_mask);
858         if (result < 0) {
859                 goto failure;
860         }
861         result = add_caching_to_json(&sub_json, e->op_type, lease_type);
862         if (result < 0) {
863                 goto failure;
864         }
865         result = add_oplock_to_json(&sub_json, e->op_type, op_str);
866         if (result < 0) {
867                 goto failure;
868         }
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;
873         }
874
875         timestr = timeval_str_buf(&e->time, true, true, &tv_buf);
876         if (timestr == NULL) {
877                 goto failure;
878         }
879         result = json_add_string(&sub_json, "opened_at", timestr);
880         if (result < 0) {
881                 goto failure;
882         }
883
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;
889         }
890         result = json_update_object(parent_json, "opens", &opens_json);
891         if (result < 0) {
892                 goto failure;
893         }
894
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;
902 }
903
904 static int add_fileid_to_json(struct json_object *parent_json,
905                               struct file_id fid)
906 {
907         struct json_object fid_json;
908         int result;
909
910         fid_json = json_new_object();
911         if (json_is_invalid(&fid_json)) {
912                 goto failure;
913         }
914
915         result = json_add_int(&fid_json, "devid", fid.devid);
916         if (result < 0) {
917                 goto failure;
918         }
919         result = json_add_int(&fid_json, "inode", fid.inode);
920         if (result < 0) {
921                 goto failure;
922         }
923         result = json_add_int(&fid_json, "extid", fid.extid);
924         if (result < 0) {
925                 goto failure;
926         }
927
928         result = json_add_object(parent_json, "fileid", &fid_json);
929         if (result < 0) {
930                 goto failure;
931         }
932
933         return 0;
934 failure:
935         json_free(&fid_json);
936         return -1;
937 }
938
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)
947 {
948         struct json_object locks_json = {
949                 .valid = false,
950         };
951         struct json_object file_json = {
952                 .valid = false,
953         };
954         char *key = NULL;
955         int result = 0;
956
957         TALLOC_CTX *tmp_ctx = talloc_stackframe();
958         if (tmp_ctx == NULL) {
959                 return -1;
960         }
961
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);
966         }
967
968         locks_json = json_get_object(&state->root_json, "open_files");
969         if (json_is_invalid(&locks_json)) {
970                 goto failure;
971         }
972         file_json = json_get_object(&locks_json, key);
973         if (json_is_invalid(&file_json)) {
974                 goto failure;
975         }
976
977         result = json_add_string(&file_json, "service_path", d->servicepath);
978         if (result < 0) {
979                 goto failure;
980         }
981         result = json_add_string(&file_json, "filename", filename);
982         if (result < 0) {
983                 goto failure;
984         }
985         result = add_fileid_to_json(&file_json, fid);
986         if (result < 0) {
987                 goto failure;
988         }
989         result = json_add_int(&file_json, "num_pending_deletes", d->num_delete_tokens);
990         if (result < 0) {
991                 goto failure;
992         }
993
994         result = add_open_to_json(&file_json,
995                                   e,
996                                   state->resolve_uids,
997                                   op_str,
998                                   lease_type,
999                                   uid_str);
1000         if (result < 0) {
1001                 goto failure;
1002         }
1003
1004         result = json_update_object(&locks_json, key, &file_json);
1005         if (result < 0) {
1006                 goto failure;
1007         }
1008         result = json_update_object(&state->root_json, "open_files", &locks_json);
1009         if (result < 0) {
1010                 goto failure;
1011         }
1012
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;
1020 }
1021
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)
1028 {
1029         struct json_object sub_json = {
1030                 .valid = false,
1031         };
1032         struct json_object locks_json = {
1033                 .valid = false,
1034         };
1035         const char *flavour_str;
1036         int result = 0;
1037
1038         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1039         if (tmp_ctx == NULL) {
1040                 return -1;
1041         }
1042
1043         locks_json = json_get_array(parent_json, "locks");
1044         if (json_is_invalid(&locks_json)) {
1045                 goto failure;
1046         }
1047         sub_json = json_new_object();
1048         if (json_is_invalid(&sub_json)) {
1049                 goto failure;
1050         }
1051
1052         result = add_server_id_to_json(&sub_json, server_id);
1053         if (result < 0) {
1054                 goto failure;
1055         }
1056         result = json_add_string(&sub_json, "type", type);
1057         if (result < 0) {
1058                 goto failure;
1059         }
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;
1066         }
1067         result = json_add_int(&sub_json, "start", start);
1068         if (result < 0) {
1069                 goto failure;
1070         }
1071         result = json_add_int(&sub_json, "size", size);
1072         if (result < 0) {
1073                 goto failure;
1074         }
1075
1076         result = json_add_object(&locks_json, NULL, &sub_json);
1077         if (result < 0) {
1078                 goto failure;
1079         }
1080         result = json_update_object(parent_json, "locks", &locks_json);
1081         if (result < 0) {
1082                 goto failure;
1083         }
1084
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;
1092 }
1093
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)
1103 {
1104         struct json_object file_json = {
1105                 .valid = false,
1106         };
1107         struct json_object brl_json = {
1108                 .valid = false,
1109         };
1110         int result = 0;
1111         char *key;
1112
1113         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1114         if (tmp_ctx == NULL) {
1115                 return -1;
1116         }
1117
1118         if (sharepath[strlen(sharepath)-1] == '/') {
1119                 key = talloc_asprintf(tmp_ctx, "%s%s", sharepath, filename);
1120         } else {
1121                 key = talloc_asprintf(tmp_ctx, "%s/%s", sharepath, filename);
1122         }
1123         if (key == NULL) {
1124                 goto failure;
1125         }
1126
1127         brl_json = json_get_object(&state->root_json, "byte_range_locks");
1128         if (json_is_invalid(&brl_json)) {
1129                 goto failure;
1130         }
1131         file_json = json_get_object(&brl_json, key);
1132         if (json_is_invalid(&file_json)) {
1133                 goto failure;
1134         }
1135
1136         result = add_fileid_to_json(&file_json, fid);
1137         if (result < 0) {
1138                 goto failure;
1139         }
1140         result = json_add_string(&file_json, "file_name", filename);
1141         if (result < 0) {
1142                 goto failure;
1143         }
1144         result = json_add_string(&file_json, "share_path", sharepath);
1145         if (result < 0) {
1146                 goto failure;
1147         }
1148         result = add_server_id_to_json(&file_json, server_id);
1149         if (result < 0) {
1150                 goto failure;
1151         }
1152         result = add_lock_to_json(&file_json, server_id, type, flavour, start, size);
1153         if (result < 0) {
1154                 goto failure;
1155         }
1156
1157         result = json_add_object(&brl_json, key, &file_json);
1158         if (result < 0) {
1159                 goto failure;
1160         }
1161         result = json_update_object(&state->root_json, "byte_range_locks", &brl_json);
1162         if (result < 0) {
1163                 goto failure;
1164          }
1165
1166         TALLOC_FREE(tmp_ctx);
1167         return 0;
1168 failure:
1169         json_free(&file_json);
1170         json_free(&brl_json);
1171         TALLOC_FREE(tmp_ctx);
1172         return -1;
1173 }
1174
1175 bool print_notify_rec_json(struct traverse_state *state,
1176                            const struct notify_instance *instance,
1177                            const struct server_id server_id,
1178                            const char *path)
1179 {
1180         struct json_object sub_json;
1181         struct json_object notify_json;
1182         char *filter = NULL;
1183         char *subdir_filter = NULL;
1184         struct timeval_buf tv_buf;
1185         struct timeval val;
1186         char *time = NULL;
1187         char *pid = NULL;
1188         struct server_id_buf tmp;
1189         int result = 0;
1190
1191         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1192         if (tmp_ctx == NULL) {
1193                 return -1;
1194         }
1195
1196         sub_json = json_new_object();
1197         if (json_is_invalid(&sub_json)) {
1198                 return false;
1199         }
1200         notify_json = json_get_object(&state->root_json, "notifies");
1201         if (json_is_invalid(&notify_json)) {
1202                 goto failure;
1203         }
1204
1205         result = add_server_id_to_json(&sub_json, server_id);
1206         if (result < 0) {
1207                 goto failure;
1208         }
1209         result = json_add_string(&sub_json, "path", path);
1210         if (result < 0) {
1211                 goto failure;
1212         }
1213         filter = talloc_asprintf(tmp_ctx, "%u", instance->filter);
1214         if (filter == NULL) {
1215                 goto failure;
1216         }
1217         result = json_add_string(&sub_json, "filter", filter);
1218         if (result < 0) {
1219                 goto failure;
1220         }
1221         subdir_filter = talloc_asprintf(tmp_ctx, "%u", instance->subdir_filter);
1222         if (subdir_filter == NULL) {
1223                 goto failure;
1224         }
1225         result = json_add_string(&sub_json, "subdir_filter", subdir_filter);
1226         if (result < 0) {
1227                 goto failure;
1228         }
1229         val = convert_timespec_to_timeval(instance->creation_time);
1230         time = timeval_str_buf(&val, true, true, &tv_buf);
1231         result = json_add_string(&sub_json, "creation_time", time);
1232         if (result < 0) {
1233                 goto failure;
1234         }
1235
1236         pid = server_id_str_buf(server_id, &tmp);
1237         result = json_add_object(&notify_json, pid, &sub_json);
1238         if (result < 0) {
1239                 goto failure;
1240         }
1241
1242         result = json_update_object(&state->root_json, "notifies", &notify_json);
1243         if (result < 0) {
1244                 goto failure;
1245         }
1246
1247         TALLOC_FREE(tmp_ctx);
1248         return true;
1249 failure:
1250         json_free(&sub_json);
1251         TALLOC_FREE(tmp_ctx);
1252         return false;
1253 }