audit_logging: Simplify json_add_stringn() with json_stringn()
[samba.git] / lib / audit_logging / audit_logging.c
1 /*
2    common routines for audit logging
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
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 /*
21  * Error handling:
22  *
23  */
24
25 #include "includes.h"
26
27 #include "librpc/ndr/libndr.h"
28 #include "lib/tsocket/tsocket.h"
29 #include "libcli/security/dom_sid.h"
30 #include "libcli/security/security_token.h"
31 #include "lib/messaging/messaging.h"
32 #include "auth/common_auth.h"
33 #include "audit_logging.h"
34 #include "auth/authn_policy.h"
35
36 /*
37  * @brief Get a human readable timestamp.
38  *
39  * Returns the current time formatted as
40  *  "Tue, 14 Mar 2017 08:38:42.209028 NZDT"
41  *
42  * The returned string is allocated by talloc in the supplied context.
43  * It is the callers responsibility to free it.
44  *
45  * @param mem_ctx talloc memory context that owns the returned string.
46  *
47  * @return a human readable time stamp, or NULL in the event of an error.
48  *
49  */
50 char* audit_get_timestamp(TALLOC_CTX *frame)
51 {
52         char buffer[40];        /* formatted time less usec and timezone */
53         char tz[10];            /* formatted time zone                   */
54         struct tm* tm_info;     /* current local time                    */
55         struct timeval tv;      /* current system time                   */
56         int ret;                /* response code                         */
57         char * ts;              /* formatted time stamp                  */
58
59         ret = gettimeofday(&tv, NULL);
60         if (ret != 0) {
61                 DBG_ERR("Unable to get time of day: (%d) %s\n",
62                         errno,
63                         strerror(errno));
64                 return NULL;
65         }
66
67         tm_info = localtime(&tv.tv_sec);
68         if (tm_info == NULL) {
69                 DBG_ERR("Unable to determine local time\n");
70                 return NULL;
71         }
72
73         strftime(buffer, sizeof(buffer)-1, "%a, %d %b %Y %H:%M:%S", tm_info);
74         strftime(tz, sizeof(tz)-1, "%Z", tm_info);
75         ts = talloc_asprintf(frame, "%s.%06ld %s", buffer, (long)tv.tv_usec, tz);
76         if (ts == NULL) {
77                 DBG_ERR("Out of memory formatting time stamp\n");
78         }
79         return ts;
80 }
81
82 /*
83  * @brief write an audit message to the audit logs.
84  *
85  * Write a human readable text audit message to the samba logs.
86  *
87  * @param prefix Text to be printed at the start of the log line
88  * @param message The content of the log line.
89  * @param debub_class The debug class to log the message with.
90  * @param debug_level The debug level to log the message with.
91  */
92 void audit_log_human_text(const char* prefix,
93                           const char* message,
94                           int debug_class,
95                           int debug_level)
96 {
97         DEBUGC(debug_class, debug_level, ("%s %s\n", prefix, message));
98 }
99
100 #ifdef HAVE_JANSSON
101 /*
102  * Constant for empty json object initialisation
103  */
104 const struct json_object json_empty_object = {.valid = false, .root = NULL};
105 /*
106  * @brief write a json object to the samba audit logs.
107  *
108  * Write the json object to the audit logs as a formatted string
109  *
110  * @param message The content of the log line.
111  * @param debub_class The debug class to log the message with.
112  * @param debug_level The debug level to log the message with.
113  */
114 void audit_log_json(struct json_object* message,
115                     int debug_class,
116                     int debug_level)
117 {
118         TALLOC_CTX *frame = NULL;
119         char *s = NULL;
120
121         if (json_is_invalid(message)) {
122                 DBG_ERR("Invalid JSON object, unable to log\n");
123                 return;
124         }
125
126         frame = talloc_stackframe();
127         s = json_to_string(frame, message);
128         if (s == NULL) {
129                 DBG_ERR("json_to_string returned NULL, "
130                         "JSON audit message could not written\n");
131                 TALLOC_FREE(frame);
132                 return;
133         }
134         /*
135          * This is very strange, but we call this routine to get a log
136          * output without the header.  JSON logs all have timestamps
137          * so this only makes parsing harder.
138          *
139          * We push out the raw JSON blob without a prefix, consumers
140          * can find such lines by the leading {
141          */
142         DEBUGADDC(debug_class, debug_level, ("%s\n", s));
143         TALLOC_FREE(frame);
144 }
145
146 /*
147  * @brief get a connection to the messaging event server.
148  *
149  * Get a connection to the messaging event server registered by server_name.
150  *
151  * @param msg_ctx a valid imessaging_context.
152  * @param server_name name of messaging event server to connect to.
153  * @param server_id The event server details to populate
154  *
155  * @return NTSTATUS
156  */
157 static NTSTATUS get_event_server(
158         struct imessaging_context *msg_ctx,
159         const char *server_name,
160         struct server_id *event_server)
161 {
162         NTSTATUS status;
163         TALLOC_CTX *frame = talloc_stackframe();
164         unsigned num_servers, i;
165         struct server_id *servers;
166
167         status = irpc_servers_byname(
168                 msg_ctx,
169                 frame,
170                 server_name,
171                 &num_servers,
172                 &servers);
173
174         if (!NT_STATUS_IS_OK(status)) {
175                 DBG_DEBUG("Failed to find the target '%s' on the message bus "
176                           "to send JSON audit events to: %s\n",
177                           server_name,
178                           nt_errstr(status));
179                 TALLOC_FREE(frame);
180                 return status;
181         }
182
183         /*
184          * Select the first server that is listening, because we get
185          * connection refused as NT_STATUS_OBJECT_NAME_NOT_FOUND
186          * without waiting
187          */
188         for (i = 0; i < num_servers; i++) {
189                 status = imessaging_send(
190                         msg_ctx,
191                         servers[i],
192                         MSG_PING,
193                         &data_blob_null);
194                 if (NT_STATUS_IS_OK(status)) {
195                         *event_server = servers[i];
196                         TALLOC_FREE(frame);
197                         return NT_STATUS_OK;
198                 }
199         }
200         DBG_NOTICE(
201                 "Failed to find '%s' registered on the message bus to "
202                 "send JSON audit events to: %s\n",
203                 server_name,
204                 nt_errstr(status));
205         TALLOC_FREE(frame);
206         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
207 }
208
209 /*
210  * @brief send an audit message to a messaging event server.
211  *
212  * Send the message to a registered and listening event server.
213  * Note: Any errors are logged, and the message is not sent.  This is to ensure
214  *       that a poorly behaved event server does not impact Samba.
215  *
216  *       As it is possible to lose messages, especially during server
217  *       shut down, currently this function is primarily intended for use
218  *       in integration tests.
219  *
220  * @param msg_ctx an imessaging_context, can be NULL in which case no message
221  *                will be sent.
222  * @param server_name the naname of the event server to send the message to.
223  * @param messag_type A message type defined in librpc/idl/messaging.idl
224  * @param message The message to send.
225  *
226  */
227 void audit_message_send(
228         struct imessaging_context *msg_ctx,
229         const char *server_name,
230         uint32_t message_type,
231         struct json_object *message)
232 {
233         struct server_id event_server = {
234                 .pid = 0,
235         };
236         NTSTATUS status;
237
238         const char *message_string = NULL;
239         DATA_BLOB message_blob = data_blob_null;
240         TALLOC_CTX *ctx = NULL;
241
242         if (json_is_invalid(message)) {
243                 DBG_ERR("Invalid JSON object, unable to send\n");
244                 return;
245         }
246         if (msg_ctx == NULL) {
247                 DBG_DEBUG("No messaging context\n");
248                 return;
249         }
250
251         ctx = talloc_new(NULL);
252         if (ctx == NULL) {
253                 DBG_ERR("Out of memory creating temporary context\n");
254                 return;
255         }
256
257         /* Need to refetch the address each time as the destination server may
258          * have disconnected and reconnected in the interim, in which case
259          * messages may get lost
260          */
261         status = get_event_server(msg_ctx, server_name, &event_server);
262         if (!NT_STATUS_IS_OK(status)) {
263                 TALLOC_FREE(ctx);
264                 return;
265         }
266
267         message_string = json_to_string(ctx, message);
268         message_blob = data_blob_string_const(message_string);
269         status = imessaging_send(
270                 msg_ctx,
271                 event_server,
272                 message_type,
273                 &message_blob);
274
275         /*
276          * If the server crashed, try to find it again
277          */
278         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
279                 status = get_event_server(msg_ctx, server_name, &event_server);
280                 if (!NT_STATUS_IS_OK(status)) {
281                         TALLOC_FREE(ctx);
282                         return;
283                 }
284                 imessaging_send(
285                         msg_ctx,
286                         event_server,
287                         message_type,
288                         &message_blob);
289         }
290         TALLOC_FREE(ctx);
291 }
292
293 /*
294  * @brief Create a new struct json_object, wrapping a JSON Object.
295  *
296  * Create a new json object, the json_object wraps the underlying json
297  * implementations JSON Object representation.
298  *
299  * Free with a call to json_free_object, note that the jansson implementation
300  * allocates memory with malloc and not talloc.
301  *
302  * @return a struct json_object, valid will be set to false if the object
303  *         could not be created.
304  *
305  */
306 struct json_object json_new_object(void) {
307
308         struct json_object object = json_empty_object;
309
310         object.root = json_object();
311         if (object.root == NULL) {
312                 object.valid = false;
313                 DBG_ERR("Unable to create JSON object\n");
314                 return object;
315         }
316         object.valid = true;
317         return object;
318 }
319
320 /*
321  * @brief Create a new struct json_object wrapping a JSON Array.
322  *
323  * Create a new json object, the json_object wraps the underlying json
324  * implementations JSON Array representation.
325  *
326  * Free with a call to json_free_object, note that the jansson implementation
327  * allocates memory with malloc and not talloc.
328  *
329  * @return a struct json_object, error will be set to true if the array
330  *         could not be created.
331  *
332  */
333 struct json_object json_new_array(void) {
334
335         struct json_object array = json_empty_object;
336
337         array.root = json_array();
338         if (array.root == NULL) {
339                 array.valid = false;
340                 DBG_ERR("Unable to create JSON array\n");
341                 return array;
342         }
343         array.valid = true;
344         return array;
345 }
346
347
348 /*
349  * @brief free and invalidate a previously created JSON object.
350  *
351  * Release any resources owned by a json_object, and then mark the structure
352  * as invalid.  It is safe to call this multiple times on an object.
353  *
354  */
355 void json_free(struct json_object *object)
356 {
357         if (object->root != NULL) {
358                 json_decref(object->root);
359         }
360         object->root = NULL;
361         object->valid = false;
362 }
363
364 /*
365  * @brief is the current JSON object invalid?
366  *
367  * Check the state of the object to determine if it is invalid.
368  *
369  * @return is the object valid?
370  *
371  */
372 bool json_is_invalid(const struct json_object *object)
373 {
374         return !object->valid;
375 }
376
377 /*
378  * @brief Add an integer value to a JSON object.
379  *
380  * Add an integer value named 'name' to the json object.
381  *
382  * @param object the JSON object to be updated.
383  * @param name the name of the value.
384  * @param value the value.
385  *
386  * @return 0 the operation was successful
387  *        -1 the operation failed
388  *
389  */
390 int json_add_int(struct json_object *object, const char *name, const json_int_t value)
391 {
392         int ret = 0;
393         json_t *integer = NULL;
394
395         if (json_is_invalid(object)) {
396                 DBG_ERR("Unable to add int [%s] value [%jd], "
397                         "target object is invalid\n",
398                         name,
399                         (intmax_t)value);
400                 return JSON_ERROR;
401         }
402
403         integer = json_integer(value);
404         if (integer == NULL) {
405                 DBG_ERR("Unable to create integer value [%s] value [%jd]\n",
406                         name,
407                         (intmax_t)value);
408                 return JSON_ERROR;
409         }
410
411         ret = json_object_set_new(object->root, name, integer);
412         if (ret != 0) {
413                 json_decref(integer);
414                 DBG_ERR("Unable to add int [%s] value [%jd]\n",
415                         name,
416                         (intmax_t)value);
417         }
418         return ret;
419 }
420
421 /*
422  * @brief Add a boolean value to a JSON object.
423  *
424  * Add a boolean value named 'name' to the json object.
425  *
426  * @param object the JSON object to be updated.
427  * @param name the name.
428  * @param value the value.
429  *
430  * @return 0 the operation was successful
431  *        -1 the operation failed
432  *
433  */
434 int json_add_bool(struct json_object *object,
435                   const char *name,
436                   const bool value)
437 {
438         int ret = 0;
439
440         if (json_is_invalid(object)) {
441                 DBG_ERR("Unable to add boolean [%s] value [%d], "
442                         "target object is invalid\n",
443                         name,
444                         value);
445                 return JSON_ERROR;
446         }
447
448         ret = json_object_set_new(object->root, name, json_boolean(value));
449         if (ret != 0) {
450                 DBG_ERR("Unable to add boolean [%s] value [%d]\n", name, value);
451         }
452         return ret;
453 }
454
455 /*
456  * @brief Add an optional boolean value to a JSON object.
457  *
458  * Add an optional boolean value named 'name' to the json object.
459  *
460  * @param object the JSON object to be updated.
461  * @param name the name.
462  * @param value the value.
463  *
464  * @return 0 the operation was successful
465  *        -1 the operation failed
466  *
467  */
468 int json_add_optional_bool(struct json_object *object,
469                            const char *name,
470                            const bool *value)
471 {
472         int ret = 0;
473
474         if (json_is_invalid(object)) {
475                 DBG_ERR("Unable to add boolean [%s] value [%d], "
476                         "target object is invalid\n",
477                         name,
478                         *value);
479                 return JSON_ERROR;
480         }
481
482         if (value != NULL) {
483                 ret = json_object_set_new(object->root, name, json_boolean(*value));
484                 if (ret != 0) {
485                         DBG_ERR("Unable to add boolean [%s] value [%d]\n", name, *value);
486                         return ret;
487                 }
488         } else {
489                 ret = json_object_set_new(object->root, name, json_null());
490                 if (ret != 0) {
491                         DBG_ERR("Unable to add null boolean [%s]\n", name);
492                         return ret;
493                 }
494         }
495
496         return ret;
497 }
498
499 /*
500  * @brief Add a string value to a JSON object.
501  *
502  * Add a string value named 'name' to the json object.
503  *
504  * @param object the JSON object to be updated.
505  * @param name the name.
506  * @param value the value.
507  *
508  * @return 0 the operation was successful
509  *        -1 the operation failed
510  *
511  */
512 int json_add_string(struct json_object *object,
513                     const char *name,
514                     const char *value)
515 {
516         int ret = 0;
517
518         if (json_is_invalid(object)) {
519                 DBG_ERR("Unable to add string [%s], target object is invalid\n",
520                         name);
521                 return JSON_ERROR;
522         }
523         if (value) {
524                 json_t *string = json_string(value);
525                 if (string == NULL) {
526                         DBG_ERR("Unable to add string [%s], "
527                                 "could not create string object\n",
528                                 name);
529                         return JSON_ERROR;
530                 }
531                 ret = json_object_set_new(object->root, name, string);
532                 if (ret != 0) {
533                         json_decref(string);
534                         DBG_ERR("Unable to add string [%s]\n", name);
535                         return ret;
536                 }
537         } else {
538                 ret = json_object_set_new(object->root, name, json_null());
539                 if (ret != 0) {
540                         DBG_ERR("Unable to add null string [%s]\n", name);
541                         return ret;
542                 }
543         }
544         return ret;
545 }
546
547 /*
548  * @brief Assert that the current JSON object is an array.
549  *
550  * Check that the current object is a JSON array, and if not
551  * invalidate the object. We also log an error message as this indicates
552  * bug in the calling code.
553  *
554  * @param object the JSON object to be validated.
555  */
556 void json_assert_is_array(struct json_object *array) {
557
558         if (json_is_invalid(array)) {
559                 return;
560         }
561
562         if (json_is_array(array->root) == false) {
563                 DBG_ERR("JSON object is not an array\n");
564                 array->valid = false;
565                 return;
566         }
567 }
568
569 /*
570  * @brief Add a JSON object to a JSON object.
571  *
572  * Add a JSON object named 'name' to the json object.
573  *
574  * @param object the JSON object to be updated.
575  * @param name the name.
576  * @param value the value.
577  *
578  * @return 0 the operation was successful
579  *        -1 the operation failed
580  *
581  */
582 int json_add_object(struct json_object *object,
583                     const char *name,
584                     struct json_object *value)
585 {
586         int ret = 0;
587         json_t *jv = NULL;
588
589         if (value != NULL && json_is_invalid(value)) {
590                 DBG_ERR("Invalid JSON object [%s] supplied\n", name);
591                 return JSON_ERROR;
592         }
593         if (json_is_invalid(object)) {
594                 DBG_ERR("Unable to add object [%s], target object is invalid\n",
595                         name);
596                 return JSON_ERROR;
597         }
598
599         jv = value == NULL ? json_null() : value->root;
600
601         if (json_is_array(object->root)) {
602                 ret = json_array_append_new(object->root, jv);
603         } else if (json_is_object(object->root)) {
604                 ret = json_object_set_new(object->root, name, jv);
605         } else {
606                 DBG_ERR("Invalid JSON object type\n");
607                 ret = JSON_ERROR;
608         }
609         if (ret != 0) {
610                 DBG_ERR("Unable to add object [%s]\n", name);
611         }
612         return ret;
613 }
614
615 /*
616  * @brief Add a string to a JSON object, truncating if necessary.
617  *
618  *
619  * Add a string value named 'name' to the json object, the string will be
620  * truncated if it is more than len characters long. If len is 0 the value
621  * is encoded as a JSON null.
622  *
623  *
624  * @param object the JSON object to be updated.
625  * @param name the name.
626  * @param value the value.
627  * @param len the maximum number of characters to be copied.
628  *
629  * @return 0 the operation was successful
630  *        -1 the operation failed
631  *
632  */
633 int json_add_stringn(struct json_object *object,
634                      const char *name,
635                      const char *value,
636                      const size_t len)
637 {
638
639         int ret = 0;
640         if (json_is_invalid(object)) {
641                 DBG_ERR("Unable to add string [%s], target object is invalid\n",
642                         name);
643                 return JSON_ERROR;
644         }
645
646         if (value != NULL && len > 0) {
647                 json_t *string = json_stringn(value, len);
648                 if (string == NULL) {
649                         DBG_ERR("Unable to add string [%s], "
650                                 "could not create string object\n",
651                                 name);
652                         return JSON_ERROR;
653                 }
654                 ret = json_object_set_new(object->root, name, string);
655                 if (ret != 0) {
656                         json_decref(string);
657                         DBG_ERR("Unable to add string [%s]\n", name);
658                         return ret;
659                 }
660         } else {
661                 ret = json_object_set_new(object->root, name, json_null());
662                 if (ret != 0) {
663                         DBG_ERR("Unable to add null string [%s]\n", name);
664                         return ret;
665                 }
666         }
667         return ret;
668 }
669
670 /*
671  * @brief Add a version object to a JSON object
672  *
673  * Add a version object to the JSON object
674  *      "version":{"major":1, "minor":0}
675  *
676  * The version tag is intended to aid the processing of the JSON messages
677  * The major version number should change when an attribute is:
678  *  - renamed
679  *  - removed
680  *  - its meaning changes
681  *  - its contents change format
682  * The minor version should change whenever a new attribute is added and for
683  * minor bug fixes to an attributes content.
684  *
685  *
686  * @param object the JSON object to be updated.
687  * @param major the major version number
688  * @param minor the minor version number
689  *
690  * @return 0 the operation was successful
691  *        -1 the operation failed
692  */
693 int json_add_version(struct json_object *object, int major, int minor)
694 {
695         int ret = 0;
696         struct json_object version;
697
698         if (json_is_invalid(object)) {
699                 DBG_ERR("Unable to add version, target object is invalid\n");
700                 return JSON_ERROR;
701         }
702
703         version = json_new_object();
704         if (json_is_invalid(&version)) {
705                 DBG_ERR("Unable to add version, failed to create object\n");
706                 return JSON_ERROR;
707         }
708         ret = json_add_int(&version, "major", major);
709         if (ret != 0) {
710                 json_free(&version);
711                 return ret;
712         }
713         ret = json_add_int(&version, "minor", minor);
714         if (ret != 0) {
715                 json_free(&version);
716                 return ret;
717         }
718         ret = json_add_object(object, "version", &version);
719         if (ret != 0) {
720                 json_free(&version);
721                 return ret;
722         }
723         return ret;
724 }
725
726 /*
727  * @brief add an ISO 8601 timestamp to the object.
728  *
729  * Add a date and time as a timestamp in ISO 8601 format to a JSON object
730  *
731  * "time":"2017-03-06T17:18:04.455081+1300"
732  *
733  *
734  * @param object the JSON object to be updated.
735  * @param name the name.
736  * @param time the value to set.
737  *
738  * @return 0 the operation was successful
739  *        -1 the operation failed
740  */
741 int json_add_time(struct json_object *object, const char *name, const struct timeval tv)
742 {
743         char buffer[40];        /* formatted time less usec and timezone */
744         char timestamp[65];     /* the formatted ISO 8601 time stamp     */
745         char tz[10];            /* formatted time zone                   */
746         struct tm* tm_info;     /* current local time                    */
747         int ret;                /* return code from json operations     */
748
749         if (json_is_invalid(object)) {
750                 DBG_ERR("Unable to add time, target object is invalid\n");
751                 return JSON_ERROR;
752         }
753
754         tm_info = localtime(&tv.tv_sec);
755         if (tm_info == NULL) {
756                 DBG_ERR("Unable to determine local time\n");
757                 return JSON_ERROR;
758         }
759
760         strftime(buffer, sizeof(buffer)-1, "%Y-%m-%dT%T", tm_info);
761         strftime(tz, sizeof(tz)-1, "%z", tm_info);
762         snprintf(
763                 timestamp,
764                 sizeof(timestamp),
765                 "%s.%06ld%s",
766                 buffer,
767                 tv.tv_usec,
768                 tz);
769         ret = json_add_string(object, name, timestamp);
770         if (ret != 0) {
771                 DBG_ERR("Unable to add time to JSON object\n");
772         }
773         return ret;
774 }
775
776 /*
777  * @brief add an ISO 8601 timestamp to the object.
778  *
779  * Add the current date and time as a timestamp in ISO 8601 format
780  * to a JSON object
781  *
782  * "timestamp":"2017-03-06T17:18:04.455081+1300"
783  *
784  *
785  * @param object the JSON object to be updated.
786  *
787  * @return 0 the operation was successful
788  *        -1 the operation failed
789  */
790 int json_add_timestamp(struct json_object *object)
791 {
792         struct timeval tv;      /* current system time                   */
793         int r;                  /* response code from gettimeofday       */
794
795         if (json_is_invalid(object)) {
796                 DBG_ERR("Unable to add time stamp, target object is invalid\n");
797                 return JSON_ERROR;
798         }
799
800         r = gettimeofday(&tv, NULL);
801         if (r) {
802                 DBG_ERR("Unable to get time of day: (%d) %s\n",
803                         errno,
804                         strerror(errno));
805                 return JSON_ERROR;
806         }
807
808         return json_add_time(object, "timestamp", tv);
809 }
810
811 /*
812  *@brief Add a tsocket_address to a JSON object
813  *
814  * Add the string representation of a Samba tsocket_address to the object.
815  *
816  * "localAddress":"ipv6::::0"
817  *
818  *
819  * @param object the JSON object to be updated.
820  * @param name the name.
821  * @param address the tsocket_address.
822  *
823  * @return 0 the operation was successful
824  *        -1 the operation failed
825  *
826  */
827 int json_add_address(struct json_object *object,
828                      const char *name,
829                      const struct tsocket_address *address)
830 {
831         int ret = 0;
832
833         if (json_is_invalid(object)) {
834                 DBG_ERR("Unable to add address [%s], "
835                         "target object is invalid\n",
836                         name);
837                 return JSON_ERROR;
838         }
839
840         if (address == NULL) {
841                 ret = json_object_set_new(object->root, name, json_null());
842                 if (ret != 0) {
843                         DBG_ERR("Unable to add null address [%s]\n", name);
844                         return JSON_ERROR;
845                 }
846         } else {
847                 TALLOC_CTX *ctx = talloc_new(NULL);
848                 char *s = NULL;
849
850                 if (ctx == NULL) {
851                         DBG_ERR("Out of memory adding address [%s]\n", name);
852                         return JSON_ERROR;
853                 }
854
855                 s = tsocket_address_string(address, ctx);
856                 if (s == NULL) {
857                         DBG_ERR("Out of memory adding address [%s]\n", name);
858                         TALLOC_FREE(ctx);
859                         return JSON_ERROR;
860                 }
861                 ret = json_add_string(object, name, s);
862                 if (ret != 0) {
863                         DBG_ERR(
864                             "Unable to add address [%s] value [%s]\n", name, s);
865                         TALLOC_FREE(ctx);
866                         return JSON_ERROR;
867                 }
868                 TALLOC_FREE(ctx);
869         }
870         return ret;
871 }
872
873 /*
874  * @brief Add a formatted string representation of a sid to a json object.
875  *
876  * Add the string representation of a Samba sid to the object.
877  *
878  * "sid":"S-1-5-18"
879  *
880  *
881  * @param object the JSON object to be updated.
882  * @param name the name.
883  * @param sid the sid
884  *
885  * @return 0 the operation was successful
886  *        -1 the operation failed
887  *
888  */
889 int json_add_sid(struct json_object *object,
890                  const char *name,
891                  const struct dom_sid *sid)
892 {
893         int ret = 0;
894
895         if (json_is_invalid(object)) {
896                 DBG_ERR("Unable to add SID [%s], "
897                         "target object is invalid\n",
898                         name);
899                 return JSON_ERROR;
900         }
901
902         if (sid == NULL) {
903                 ret = json_object_set_new(object->root, name, json_null());
904                 if (ret != 0) {
905                         DBG_ERR("Unable to add null SID [%s]\n", name);
906                         return ret;
907                 }
908         } else {
909                 struct dom_sid_buf sid_buf;
910
911                 ret = json_add_string(
912                         object, name, dom_sid_str_buf(sid, &sid_buf));
913                 if (ret != 0) {
914                         DBG_ERR("Unable to add SID [%s] value [%s]\n",
915                                 name,
916                                 sid_buf.buf);
917                         return ret;
918                 }
919         }
920         return ret;
921 }
922
923 /*
924  * @brief Add a formatted string representation of a guid to a json object.
925  *
926  * Add the string representation of a Samba GUID to the object.
927  *
928  * "guid":"1fb9f2ee-2a4d-4bf8-af8b-cb9d4529a9ab"
929  *
930  *
931  * @param object the JSON object to be updated.
932  * @param name the name.
933  * @param guid the guid.
934  *
935  * @return 0 the operation was successful
936  *        -1 the operation failed
937  *
938  *
939  */
940 int json_add_guid(struct json_object *object,
941                   const char *name,
942                   const struct GUID *guid)
943 {
944
945         int ret = 0;
946
947         if (json_is_invalid(object)) {
948                 DBG_ERR("Unable to add GUID [%s], "
949                         "target object is invalid\n",
950                         name);
951                 return JSON_ERROR;
952         }
953
954         if (guid == NULL) {
955                 ret = json_object_set_new(object->root, name, json_null());
956                 if (ret != 0) {
957                         DBG_ERR("Unable to add null GUID [%s]\n", name);
958                         return ret;
959                 }
960         } else {
961                 char *guid_str;
962                 struct GUID_txt_buf guid_buff;
963
964                 guid_str = GUID_buf_string(guid, &guid_buff);
965                 ret = json_add_string(object, name, guid_str);
966                 if (ret != 0) {
967                         DBG_ERR("Unable to add GUID [%s] value [%s]\n",
968                                 name,
969                                 guid_str);
970                         return ret;
971                 }
972         }
973         return ret;
974 }
975
976 /*
977  * @brief Add a hex-formatted string representation of a 32-bit integer to a
978  * json object.
979  *
980  * Add a hex-formatted string representation of a 32-bit flags integer to the
981  * object.
982  *
983  * "accountFlags":"0x12345678"
984  *
985  *
986  * @param object the JSON object to be updated.
987  * @param name the name.
988  * @param flags the flags.
989  *
990  * @return 0 the operation was successful
991  *        -1 the operation failed
992  *
993  *
994  */
995 int json_add_flags32(struct json_object *object,
996                   const char *name,
997                   const uint32_t flags)
998 {
999         int ret = 0;
1000         char buf[sizeof("0x12345678")];
1001
1002         if (json_is_invalid(object)) {
1003                 DBG_ERR("Unable to add flags [%s], "
1004                         "target object is invalid\n",
1005                         name);
1006                 return JSON_ERROR;
1007         }
1008
1009         ret = snprintf(buf, sizeof (buf), "0x%08X", flags);
1010         if (ret != sizeof (buf) - 1) {
1011                 DBG_ERR("Unable to format flags [%s] value [0x%08X]\n",
1012                         name,
1013                         flags);
1014                 return JSON_ERROR;
1015         }
1016
1017         ret = json_add_string(object, name, buf);
1018         if (ret != 0) {
1019                 DBG_ERR("Unable to add flags [%s] value [%s]\n",
1020                         name,
1021                         buf);
1022         }
1023
1024         return ret;
1025 }
1026
1027 /*
1028  * @brief Replaces the object for a given key with a given json object.
1029  *
1030  * If key already exists, the value will be replaced. Otherwise the given
1031  * value will be added under the given key.
1032  *
1033  * @param object the JSON object to be updated.
1034  * @param key the key which will be updated.
1035  * @param new_obj the new value object to be inserted.
1036  *
1037  * @return 0 the operation was successful
1038  *        -1 the operation failed (e.j. if one of the parameters is invalid)
1039  */
1040 int json_update_object(struct json_object *object,
1041                        const char *key,
1042                        struct json_object *new_obj)
1043 {
1044         int ret = 0;
1045
1046         if (json_is_invalid(object)) {
1047                 DBG_ERR("Unable to update key [%s], "
1048                         "target object is invalid\n",
1049                         key);
1050                 return JSON_ERROR;
1051         }
1052         if (json_is_invalid(new_obj)) {
1053                 DBG_ERR("Unable to update key [%s], "
1054                         "new object is invalid\n",
1055                         key);
1056                 return JSON_ERROR;
1057         }
1058
1059         if (key == NULL) {
1060                 DBG_ERR("Unable to add null String as key\n");
1061                 return JSON_ERROR;
1062         }
1063
1064         ret = json_object_set(object->root, key, new_obj->root);
1065         if (ret != 0) {
1066                 DBG_ERR("Unable to update object\n");
1067                 return ret;
1068         }
1069
1070         return ret;
1071 }
1072
1073 /*
1074  * @brief Convert a JSON object into a string
1075  *
1076  * Convert the json object into a string suitable for printing on a log line,
1077  * i.e. with no embedded line breaks.
1078  *
1079  * If the object is invalid it logs an error and returns NULL.
1080  *
1081  * @param mem_ctx the talloc memory context owning the returned string
1082  * @param object the json object.
1083  *
1084  * @return A string representation of the object or NULL if the object
1085  *         is invalid.
1086  */
1087 char *json_to_string(TALLOC_CTX *mem_ctx, const struct json_object *object)
1088 {
1089         char *json = NULL;
1090         char *json_string = NULL;
1091
1092         if (json_is_invalid(object)) {
1093                 DBG_ERR("Invalid JSON object, unable to convert to string\n");
1094                 return NULL;
1095         }
1096
1097         if (object->root == NULL) {
1098                 return NULL;
1099         }
1100
1101         /*
1102          * json_dumps uses malloc, so need to call free(json) to release
1103          * the memory
1104          */
1105         json = json_dumps(object->root, 0);
1106         if (json == NULL) {
1107                 DBG_ERR("Unable to convert JSON object to string\n");
1108                 return NULL;
1109         }
1110
1111         json_string = talloc_strdup(mem_ctx, json);
1112         if (json_string == NULL) {
1113                 free(json);
1114                 DBG_ERR("Unable to copy JSON object string to talloc string\n");
1115                 return NULL;
1116         }
1117         free(json);
1118
1119         return json_string;
1120 }
1121
1122 /*
1123  * @brief get a json array named "name" from the json object.
1124  *
1125  * Get the array attribute named name, creating it if it does not exist.
1126  *
1127  * @param object the json object.
1128  * @param name the name of the array attribute
1129  *
1130  * @return The array object, will be created if it did not exist.
1131  */
1132 struct json_object json_get_array(struct json_object *object, const char *name)
1133 {
1134
1135         struct json_object array = json_empty_object;
1136         json_t *a = NULL;
1137         int ret = 0;
1138
1139         if (json_is_invalid(object)) {
1140                 DBG_ERR("Invalid JSON object, unable to get array [%s]\n",
1141                         name);
1142                 json_free(&array);
1143                 return array;
1144         }
1145
1146         array = json_new_array();
1147         if (json_is_invalid(&array)) {
1148                 DBG_ERR("Unable to create new array for [%s]\n", name);
1149                 return array;
1150         }
1151
1152         a = json_object_get(object->root, name);
1153         if (a == NULL) {
1154                 return array;
1155         }
1156
1157         ret = json_array_extend(array.root, a);
1158         if (ret != 0) {
1159                 DBG_ERR("Unable to get array [%s]\n", name);
1160                 json_free(&array);
1161                 return array;
1162         }
1163
1164         return array;
1165 }
1166
1167 /*
1168  * @brief get a json object named "name" from the json object.
1169  *
1170  * Get the object attribute named name, creating it if it does not exist.
1171  *
1172  * @param object the json object.
1173  * @param name the name of the object attribute
1174  *
1175  * @return The object, will be created if it did not exist.
1176  */
1177 struct json_object json_get_object(struct json_object *object, const char *name)
1178 {
1179
1180         struct json_object o = json_new_object();
1181         json_t *v = NULL;
1182         int ret = 0;
1183
1184         if (json_is_invalid(&o)) {
1185                 DBG_ERR("Unable to get object [%s]\n", name);
1186                 json_free(&o);
1187                 return o;
1188         }
1189
1190         if (json_is_invalid(object)) {
1191                 DBG_ERR("Invalid JSON object, unable to get object [%s]\n",
1192                         name);
1193                 json_free(&o);
1194                 return o;
1195         }
1196
1197         v = json_object_get(object->root, name);
1198         if (v == NULL) {
1199                 return o;
1200         }
1201         ret = json_object_update(o.root, v);
1202         if (ret != 0) {
1203                 DBG_ERR("Unable to get object [%s]\n", name);
1204                 json_free(&o);
1205                 return o;
1206         }
1207         return o;
1208 }
1209
1210 /*
1211  * @brief Return the JSON null object.
1212  *
1213  * @return the JSON null object.
1214  */
1215 _WARN_UNUSED_RESULT_ struct json_object json_null_object(void)
1216 {
1217         struct json_object object = json_empty_object;
1218
1219         object.root = json_null();
1220         if (object.root != NULL) {
1221                 object.valid = true;
1222         }
1223
1224         return object;
1225 }
1226
1227 /*
1228  * @brief Create a JSON object from a structure containing audit information.
1229  *
1230  * @param audit_info the audit information from which to create a JSON object.
1231  *
1232  * @return the JSON object (which may be valid or not)
1233  *
1234  *
1235  */
1236 struct json_object json_from_audit_info(const struct authn_audit_info *audit_info)
1237 {
1238         struct json_object object = json_new_object();
1239         enum auth_event_id_type auth_event_id;
1240         const struct auth_user_info_dc *client_info = NULL;
1241         const char *policy_name = NULL;
1242         const char *silo_name = NULL;
1243         const bool *policy_enforced = NULL;
1244         NTSTATUS policy_status;
1245         struct authn_int64_optional tgt_lifetime_mins;
1246         const char *location = NULL;
1247         const char *audit_event = NULL;
1248         const char *audit_reason = NULL;
1249         int rc = 0;
1250
1251         if (json_is_invalid(&object)) {
1252                 goto failure;
1253         }
1254
1255         auth_event_id = authn_audit_info_event_id(audit_info);
1256         rc = json_add_int(&object, "eventId", auth_event_id);
1257         if (rc != 0) {
1258                 goto failure;
1259         }
1260
1261         policy_name = authn_audit_info_policy_name(audit_info);
1262         rc = json_add_string(&object, "policyName", policy_name);
1263         if (rc != 0) {
1264                 goto failure;
1265         }
1266
1267         silo_name = authn_audit_info_silo_name(audit_info);
1268         rc = json_add_string(&object, "siloName", silo_name);
1269         if (rc != 0) {
1270                 goto failure;
1271         }
1272
1273         policy_enforced = authn_audit_info_policy_enforced(audit_info);
1274         rc = json_add_optional_bool(&object, "policyEnforced", policy_enforced);
1275         if (rc != 0) {
1276                 goto failure;
1277         }
1278
1279         policy_status = authn_audit_info_policy_status(audit_info);
1280         rc = json_add_string(&object, "status", nt_errstr(policy_status));
1281         if (rc != 0) {
1282                 goto failure;
1283         }
1284
1285         tgt_lifetime_mins = authn_audit_info_policy_tgt_lifetime_mins(audit_info);
1286         if (tgt_lifetime_mins.is_present) {
1287                 rc = json_add_int(&object, "tgtLifetime", tgt_lifetime_mins.val);
1288                 if (rc != 0) {
1289                         goto failure;
1290                 }
1291         }
1292
1293         location = authn_audit_info_location(audit_info);
1294         rc = json_add_string(&object, "location", location);
1295         if (rc != 0) {
1296                 goto failure;
1297         }
1298
1299         audit_event = authn_audit_info_event(audit_info);
1300         rc = json_add_string(&object, "auditEvent", audit_event);
1301         if (rc != 0) {
1302                 goto failure;
1303         }
1304
1305         audit_reason = authn_audit_info_reason(audit_info);
1306         rc = json_add_string(&object, "reason", audit_reason);
1307         if (rc != 0) {
1308                 goto failure;
1309         }
1310
1311         client_info = authn_audit_info_client_info(audit_info);
1312         if (client_info != NULL) {
1313                 const struct auth_user_info *client_user_info = NULL;
1314
1315                 client_user_info = client_info->info;
1316                 if (client_user_info != NULL) {
1317                         rc = json_add_string(&object, "checkedDomain", client_user_info->domain_name);
1318                         if (rc != 0) {
1319                                 goto failure;
1320                         }
1321
1322                         rc = json_add_string(&object, "checkedAccount", client_user_info->account_name);
1323                         if (rc != 0) {
1324                                 goto failure;
1325                         }
1326
1327                         rc = json_add_string(&object, "checkedLogonServer", client_user_info->logon_server);
1328                         if (rc != 0) {
1329                                 goto failure;
1330                         }
1331
1332                         rc = json_add_flags32(&object, "checkedAccountFlags", client_user_info->acct_flags);
1333                         if (rc != 0) {
1334                                 goto failure;
1335                         }
1336                 }
1337
1338                 if (client_info->num_sids) {
1339                         const struct dom_sid *policy_checked_sid = NULL;
1340
1341                         policy_checked_sid = &client_info->sids[PRIMARY_USER_SID_INDEX].sid;
1342                         rc = json_add_sid(&object, "checkedSid", policy_checked_sid);
1343                         if (rc != 0) {
1344                                 goto failure;
1345                         }
1346                 }
1347         }
1348
1349         return object;
1350
1351 failure:
1352         json_free(&object);
1353         return object;
1354 }
1355
1356 #endif