json: Modify API to use return codes
[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 "lib/messaging/messaging.h"
31 #include "auth/common_auth.h"
32 #include "audit_logging.h"
33
34 /*
35  * @brief Get a human readable timestamp.
36  *
37  * Returns the current time formatted as
38  *  "Tue, 14 Mar 2017 08:38:42.209028 NZDT"
39  *
40  * The returned string is allocated by talloc in the supplied context.
41  * It is the callers responsibility to free it.
42  *
43  * @param mem_ctx talloc memory context that owns the returned string.
44  *
45  * @return a human readable time stamp, or NULL in the event of an error.
46  *
47  */
48 char* audit_get_timestamp(TALLOC_CTX *frame)
49 {
50         char buffer[40];        /* formatted time less usec and timezone */
51         char tz[10];            /* formatted time zone                   */
52         struct tm* tm_info;     /* current local time                    */
53         struct timeval tv;      /* current system time                   */
54         int ret;                /* response code                         */
55         char * ts;              /* formatted time stamp                  */
56
57         ret = gettimeofday(&tv, NULL);
58         if (ret != 0) {
59                 DBG_ERR("Unable to get time of day: (%d) %s\n",
60                         errno,
61                         strerror(errno));
62                 return NULL;
63         }
64
65         tm_info = localtime(&tv.tv_sec);
66         if (tm_info == NULL) {
67                 DBG_ERR("Unable to determine local time\n");
68                 return NULL;
69         }
70
71         strftime(buffer, sizeof(buffer)-1, "%a, %d %b %Y %H:%M:%S", tm_info);
72         strftime(tz, sizeof(tz)-1, "%Z", tm_info);
73         ts = talloc_asprintf(frame, "%s.%06ld %s", buffer, tv.tv_usec, tz);
74         if (ts == NULL) {
75                 DBG_ERR("Out of memory formatting time stamp\n");
76         }
77         return ts;
78 }
79
80 /*
81  * @brief write an audit message to the audit logs.
82  *
83  * Write a human readable text audit message to the samba logs.
84  *
85  * @param prefix Text to be printed at the start of the log line
86  * @param message The content of the log line.
87  * @param debub_class The debug class to log the message with.
88  * @param debug_level The debug level to log the message with.
89  */
90 void audit_log_human_text(const char* prefix,
91                           const char* message,
92                           int debug_class,
93                           int debug_level)
94 {
95         DEBUGC(debug_class, debug_level, ("%s %s\n", prefix, message));
96 }
97
98 #ifdef HAVE_JANSSON
99 /*
100  * Constant for empty json object initialisation
101  */
102 const struct json_object json_empty_object = {.valid = false, .root = NULL};
103 /*
104  * @brief write a json object to the samba audit logs.
105  *
106  * Write the json object to the audit logs as a formatted string
107  *
108  * @param prefix Text to be printed at the start of the log line
109  * @param message The content of the log line.
110  * @param debub_class The debug class to log the message with.
111  * @param debug_level The debug level to log the message with.
112  */
113 void audit_log_json(const char* prefix,
114                     struct json_object* message,
115                     int debug_class,
116                     int debug_level)
117 {
118         TALLOC_CTX *ctx = 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         ctx = talloc_new(NULL);
127         s = json_to_string(ctx, message);
128         if (s == NULL) {
129                 DBG_ERR("json_to_string for (%s) returned NULL, "
130                         "JSON audit message could not written\n",
131                         prefix);
132                 TALLOC_FREE(ctx);
133                 return;
134         }
135         DEBUGC(debug_class, debug_level, ("JSON %s: %s\n", prefix, s));
136         TALLOC_FREE(ctx);
137 }
138
139 /*
140  * @brief get a connection to the messaging event server.
141  *
142  * Get a connection to the messaging event server registered by server_name.
143  *
144  * @param msg_ctx a valid imessaging_context.
145  * @param server_name name of messaging event server to connect to.
146  * @param server_id The event server details to populate
147  *
148  * @return NTSTATUS
149  */
150 static NTSTATUS get_event_server(
151         struct imessaging_context *msg_ctx,
152         const char *server_name,
153         struct server_id *event_server)
154 {
155         NTSTATUS status;
156         TALLOC_CTX *frame = talloc_stackframe();
157         unsigned num_servers, i;
158         struct server_id *servers;
159
160         status = irpc_servers_byname(
161                 msg_ctx,
162                 frame,
163                 server_name,
164                 &num_servers,
165                 &servers);
166
167         if (!NT_STATUS_IS_OK(status)) {
168                 DBG_NOTICE(
169                         "Failed to find '%s' registered on the message bus to "
170                         "send JSON audit events to: %s\n",
171                         server_name,
172                         nt_errstr(status));
173                 TALLOC_FREE(frame);
174                 return status;
175         }
176
177         /*
178          * Select the first server that is listening, because we get
179          * connection refused as NT_STATUS_OBJECT_NAME_NOT_FOUND
180          * without waiting
181          */
182         for (i = 0; i < num_servers; i++) {
183                 status = imessaging_send(
184                         msg_ctx,
185                         servers[i],
186                         MSG_PING,
187                         &data_blob_null);
188                 if (NT_STATUS_IS_OK(status)) {
189                         *event_server = servers[i];
190                         TALLOC_FREE(frame);
191                         return NT_STATUS_OK;
192                 }
193         }
194         DBG_NOTICE(
195                 "Failed to find '%s' registered on the message bus to "
196                 "send JSON audit events to: %s\n",
197                 server_name,
198                 nt_errstr(status));
199         TALLOC_FREE(frame);
200         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
201 }
202
203 /*
204  * @brief send an audit message to a messaging event server.
205  *
206  * Send the message to a registered and listening event server.
207  * Note: Any errors are logged, and the message is not sent.  This is to ensure
208  *       that a poorly behaved event server does not impact Samba.
209  *
210  *       As it is possible to lose messages, especially during server
211  *       shut down, currently this function is primarily intended for use
212  *       in integration tests.
213  *
214  * @param msg_ctx an imessaging_context, can be NULL in which case no message
215  *                will be sent.
216  * @param server_name the naname of the event server to send the message to.
217  * @param messag_type A message type defined in librpc/idl/messaging.idl
218  * @param message The message to send.
219  *
220  */
221 void audit_message_send(
222         struct imessaging_context *msg_ctx,
223         const char *server_name,
224         uint32_t message_type,
225         struct json_object *message)
226 {
227         struct server_id event_server = {};
228         NTSTATUS status;
229
230         const char *message_string = NULL;
231         DATA_BLOB message_blob = data_blob_null;
232         TALLOC_CTX *ctx = NULL;
233
234         if (json_is_invalid(message)) {
235                 DBG_ERR("Invalid JSON object, unable to send\n");
236                 return;
237         }
238         if (msg_ctx == NULL) {
239                 DBG_DEBUG("No messaging context\n");
240                 return;
241         }
242
243         /* Need to refetch the address each time as the destination server may
244          * have disconnected and reconnected in the interim, in which case
245          * messages may get lost
246          */
247         status = get_event_server(msg_ctx, server_name, &event_server);
248         if (!NT_STATUS_IS_OK(status)) {
249                 TALLOC_FREE(ctx);
250                 return;
251         }
252
253         message_string = json_to_string(ctx, message);
254         message_blob = data_blob_string_const(message_string);
255         status = imessaging_send(
256                 msg_ctx,
257                 event_server,
258                 message_type,
259                 &message_blob);
260
261         /*
262          * If the server crashed, try to find it again
263          */
264         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
265                 status = get_event_server(msg_ctx, server_name, &event_server);
266                 if (!NT_STATUS_IS_OK(status)) {
267                         TALLOC_FREE(ctx);
268                         return;
269                 }
270                 imessaging_send(
271                         msg_ctx,
272                         event_server,
273                         message_type,
274                         &message_blob);
275         }
276         TALLOC_FREE(ctx);
277 }
278
279 /*
280  * @brief Create a new struct json_object, wrapping a JSON Object.
281  *
282  * Create a new json object, the json_object wraps the underlying json
283  * implementations JSON Object representation.
284  *
285  * Free with a call to json_free_object, note that the jansson inplementation
286  * allocates memory with malloc and not talloc.
287  *
288  * @return a struct json_object, valid will be set to false if the object
289  *         could not be created.
290  *
291  */
292 struct json_object json_new_object(void) {
293
294         struct json_object object = json_empty_object;
295
296         object.root = json_object();
297         if (object.root == NULL) {
298                 object.valid = false;
299                 DBG_ERR("Unable to create JSON object\n");
300                 return object;
301         }
302         object.valid = true;
303         return object;
304 }
305
306 /*
307  * @brief Create a new struct json_object wrapping a JSON Array.
308  *
309  * Create a new json object, the json_object wraps the underlying json
310  * implementations JSON Array representation.
311  *
312  * Free with a call to json_free_object, note that the jansson inplementation
313  * allocates memory with malloc and not talloc.
314  *
315  * @return a struct json_object, error will be set to true if the array
316  *         could not be created.
317  *
318  */
319 struct json_object json_new_array(void) {
320
321         struct json_object array = json_empty_object;
322
323         array.root = json_array();
324         if (array.root == NULL) {
325                 array.valid = false;
326                 DBG_ERR("Unable to create JSON array\n");
327                 return array;
328         }
329         array.valid = true;
330         return array;
331 }
332
333
334 /*
335  * @brief free and invalidate a previously created JSON object.
336  *
337  * Release any resources owned by a json_object, and then mark the structure
338  * as invalid.  It is safe to call this multiple times on an object.
339  *
340  */
341 void json_free(struct json_object *object)
342 {
343         if (object->root != NULL) {
344                 json_decref(object->root);
345         }
346         object->root = NULL;
347         object->valid = false;
348 }
349
350 /*
351  * @brief is the current JSON object invalid?
352  *
353  * Check the state of the object to determine if it is invalid.
354  *
355  * @return is the object valid?
356  *
357  */
358 bool json_is_invalid(struct json_object *object)
359 {
360         return !object->valid;
361 }
362
363 /*
364  * @brief Add an integer value to a JSON object.
365  *
366  * Add an integer value named 'name' to the json object.
367  *
368  * @param object the JSON object to be updated.
369  * @param name the name of the value.
370  * @param value the value.
371  *
372  * @return 0 the operation was successful
373  *        -1 the operation failed
374  *
375  */
376 int json_add_int(struct json_object *object, const char *name, const int value)
377 {
378         int ret = 0;
379         json_t *integer = NULL;
380
381         if (json_is_invalid(object)) {
382                 DBG_ERR("Unable to add int [%s] value [%d], "
383                         "target object is invalid\n",
384                         name,
385                         value);
386                 return JSON_ERROR;
387         }
388
389         integer = json_integer(value);
390         if (integer == NULL) {
391                 DBG_ERR("Unable to create integer value [%s] value [%d]\n",
392                         name,
393                         value);
394                 return JSON_ERROR;
395         }
396
397         ret = json_object_set_new(object->root, name, integer);
398         if (ret != 0) {
399                 json_decref(integer);
400                 DBG_ERR("Unable to add int [%s] value [%d]\n", name, value);
401         }
402         return ret;
403 }
404
405 /*
406  * @brief Add a boolean value to a JSON object.
407  *
408  * Add a boolean value named 'name' to the json object.
409  *
410  * @param object the JSON object to be updated.
411  * @param name the name.
412  * @param value the value.
413  *
414  * @return 0 the operation was successful
415  *        -1 the operation failed
416  *
417  */
418 int json_add_bool(struct json_object *object,
419                   const char *name,
420                   const bool value)
421 {
422         int ret = 0;
423
424         if (json_is_invalid(object)) {
425                 DBG_ERR("Unable to add boolean [%s] value [%d], "
426                         "target object is invalid\n",
427                         name,
428                         value);
429                 return JSON_ERROR;
430         }
431
432         ret = json_object_set_new(object->root, name, json_boolean(value));
433         if (ret != 0) {
434                 DBG_ERR("Unable to add boolean [%s] value [%d]\n", name, value);
435         }
436         return ret;
437 }
438
439 /*
440  * @brief Add a string value to a JSON object.
441  *
442  * Add a string value named 'name' to the json object.
443  *
444  * @param object the JSON object to be updated.
445  * @param name the name.
446  * @param value the value.
447  *
448  * @return 0 the operation was successful
449  *        -1 the operation failed
450  *
451  */
452 int json_add_string(struct json_object *object,
453                     const char *name,
454                     const char *value)
455 {
456         int ret = 0;
457
458         if (json_is_invalid(object)) {
459                 DBG_ERR("Unable to add string [%s], target object is invalid\n",
460                         name);
461                 return JSON_ERROR;
462         }
463         if (value) {
464                 json_t *string = json_string(value);
465                 if (string == NULL) {
466                         DBG_ERR("Unable to add string [%s], "
467                                 "could not create string object\n",
468                                 name);
469                         return JSON_ERROR;
470                 }
471                 ret = json_object_set_new(object->root, name, string);
472                 if (ret != 0) {
473                         json_decref(string);
474                         DBG_ERR("Unable to add string [%s]\n", name);
475                         return ret;
476                 }
477         } else {
478                 ret = json_object_set_new(object->root, name, json_null());
479                 if (ret != 0) {
480                         DBG_ERR("Unable to add null string [%s]\n", name);
481                         return ret;
482                 }
483         }
484         return ret;
485 }
486
487 /*
488  * @brief Assert that the current JSON object is an array.
489  *
490  * Check that the current object is a JSON array, and if not
491  * invalidate the object. We also log an error message as this indicates
492  * bug in the calling code.
493  *
494  * @param object the JSON object to be validated.
495  */
496 void json_assert_is_array(struct json_object *array) {
497
498         if (json_is_invalid(array)) {
499                 return;
500         }
501
502         if (json_is_array(array->root) == false) {
503                 DBG_ERR("JSON object is not an array\n");
504                 array->valid = false;
505                 return;
506         }
507 }
508
509 /*
510  * @brief Add a JSON object to a JSON object.
511  *
512  * Add a JSON object named 'name' to the json object.
513  *
514  * @param object the JSON object to be updated.
515  * @param name the name.
516  * @param value the value.
517  *
518  * @return 0 the operation was successful
519  *        -1 the operation failed
520  *
521  */
522 int json_add_object(struct json_object *object,
523                     const char *name,
524                     struct json_object *value)
525 {
526         int ret = 0;
527         json_t *jv = NULL;
528
529         if (value != NULL && json_is_invalid(value)) {
530                 DBG_ERR("Invalid JSON object [%s] supplied\n", name);
531                 return JSON_ERROR;
532         }
533         if (json_is_invalid(object)) {
534                 DBG_ERR("Unable to add object [%s], target object is invalid\n",
535                         name);
536                 return JSON_ERROR;
537         }
538
539         jv = value == NULL ? json_null() : value->root;
540
541         if (json_is_array(object->root)) {
542                 ret = json_array_append_new(object->root, jv);
543         } else if (json_is_object(object->root)) {
544                 ret = json_object_set_new(object->root, name, jv);
545         } else {
546                 DBG_ERR("Invalid JSON object type\n");
547                 ret = JSON_ERROR;
548         }
549         if (ret != 0) {
550                 DBG_ERR("Unable to add object [%s]\n", name);
551         }
552         return ret;
553 }
554
555 /*
556  * @brief Add a string to a JSON object, truncating if necessary.
557  *
558  *
559  * Add a string value named 'name' to the json object, the string will be
560  * truncated if it is more than len characters long. If len is 0 the value
561  * is encoded as a JSON null.
562  *
563  *
564  * @param object the JSON object to be updated.
565  * @param name the name.
566  * @param value the value.
567  * @param len the maximum number of characters to be copied.
568  *
569  * @return 0 the operation was successful
570  *        -1 the operation failed
571  *
572  */
573 int json_add_stringn(struct json_object *object,
574                      const char *name,
575                      const char *value,
576                      const size_t len)
577 {
578
579         int ret = 0;
580         if (json_is_invalid(object)) {
581                 DBG_ERR("Unable to add string [%s], target object is invalid\n",
582                         name);
583                 return JSON_ERROR;
584         }
585
586         if (value != NULL && len > 0) {
587                 json_t *string = NULL;
588                 char buffer[len+1];
589
590                 strncpy(buffer, value, len);
591                 buffer[len] = '\0';
592
593                 string = json_string(buffer);
594                 if (string == NULL) {
595                         DBG_ERR("Unable to add string [%s], "
596                                 "could not create string object\n",
597                                 name);
598                         return JSON_ERROR;
599                 }
600                 ret = json_object_set_new(object->root, name, string);
601                 if (ret != 0) {
602                         json_decref(string);
603                         DBG_ERR("Unable to add string [%s]\n", name);
604                         return ret;
605                 }
606         } else {
607                 ret = json_object_set_new(object->root, name, json_null());
608                 if (ret != 0) {
609                         DBG_ERR("Unable to add null string [%s]\n", name);
610                         return ret;
611                 }
612         }
613         return ret;
614 }
615
616 /*
617  * @brief Add a version object to a JSON object
618  *
619  * Add a version object to the JSON object
620  *      "version":{"major":1, "minor":0}
621  *
622  * The version tag is intended to aid the processing of the JSON messages
623  * The major version number should change when an attribute is:
624  *  - renamed
625  *  - removed
626  *  - its meaning changes
627  *  - its contents change format
628  * The minor version should change whenever a new attribute is added and for
629  * minor bug fixes to an attributes content.
630  *
631  *
632  * @param object the JSON object to be updated.
633  * @param major the major version number
634  * @param minor the minor version number
635  *
636  * @return 0 the operation was successful
637  *        -1 the operation failed
638  */
639 int json_add_version(struct json_object *object, int major, int minor)
640 {
641         int ret = 0;
642         struct json_object version;
643
644         if (json_is_invalid(object)) {
645                 DBG_ERR("Unable to add version, target object is invalid\n");
646                 return JSON_ERROR;
647         }
648
649         version = json_new_object();
650         if (json_is_invalid(&version)) {
651                 DBG_ERR("Unable to add version, failed to create object\n");
652                 return JSON_ERROR;
653         }
654         ret = json_add_int(&version, "major", major);
655         if (ret != 0) {
656                 json_free(&version);
657                 return ret;
658         }
659         ret = json_add_int(&version, "minor", minor);
660         if (ret != 0) {
661                 json_free(&version);
662                 return ret;
663         }
664         ret = json_add_object(object, "version", &version);
665         if (ret != 0) {
666                 json_free(&version);
667                 return ret;
668         }
669         return ret;
670 }
671
672 /*
673  * @brief add an ISO 8601 timestamp to the object.
674  *
675  * Add the current date and time as a timestamp in ISO 8601 format
676  * to a JSON object
677  *
678  * "timestamp":"2017-03-06T17:18:04.455081+1300"
679  *
680  *
681  * @param object the JSON object to be updated.
682  *
683  * @return 0 the operation was successful
684  *        -1 the operation failed
685  */
686 int json_add_timestamp(struct json_object *object)
687 {
688         char buffer[40];        /* formatted time less usec and timezone */
689         char timestamp[65];     /* the formatted ISO 8601 time stamp     */
690         char tz[10];            /* formatted time zone                   */
691         struct tm* tm_info;     /* current local time                    */
692         struct timeval tv;      /* current system time                   */
693         int r;                  /* response code from gettimeofday       */
694         int ret;                /* return code from json operations     */
695
696         if (json_is_invalid(object)) {
697                 DBG_ERR("Unable to add time stamp, target object is invalid\n");
698                 return JSON_ERROR;
699         }
700
701         r = gettimeofday(&tv, NULL);
702         if (r) {
703                 DBG_ERR("Unable to get time of day: (%d) %s\n",
704                         errno,
705                         strerror(errno));
706                 return JSON_ERROR;
707         }
708
709         tm_info = localtime(&tv.tv_sec);
710         if (tm_info == NULL) {
711                 DBG_ERR("Unable to determine local time\n");
712                 return JSON_ERROR;
713         }
714
715         strftime(buffer, sizeof(buffer)-1, "%Y-%m-%dT%T", tm_info);
716         strftime(tz, sizeof(tz)-1, "%z", tm_info);
717         snprintf(
718                 timestamp,
719                 sizeof(timestamp),
720                 "%s.%06ld%s",
721                 buffer,
722                 tv.tv_usec,
723                 tz);
724         ret = json_add_string(object, "timestamp", timestamp);
725         if (ret != 0) {
726                 DBG_ERR("Unable to add time stamp to JSON object\n");
727         }
728         return ret;
729 }
730
731 /*
732  *@brief Add a tsocket_address to a JSON object
733  *
734  * Add the string representation of a Samba tsocket_address to the object.
735  *
736  * "localAddress":"ipv6::::0"
737  *
738  *
739  * @param object the JSON object to be updated.
740  * @param name the name.
741  * @param address the tsocket_address.
742  *
743  * @return 0 the operation was successful
744  *        -1 the operation failed
745  *
746  */
747 int json_add_address(struct json_object *object,
748                      const char *name,
749                      const struct tsocket_address *address)
750 {
751         int ret = 0;
752
753         if (json_is_invalid(object)) {
754                 DBG_ERR("Unable to add address [%s], "
755                         "target object is invalid\n",
756                         name);
757                 return JSON_ERROR;
758         }
759
760         if (address == NULL) {
761                 ret = json_object_set_new(object->root, name, json_null());
762                 if (ret != 0) {
763                         DBG_ERR("Unable to add null address [%s]\n", name);
764                         return JSON_ERROR;
765                 }
766         } else {
767                 TALLOC_CTX *ctx = talloc_new(NULL);
768                 char *s = NULL;
769
770                 if (ctx == NULL) {
771                         DBG_ERR("Out of memory adding address [%s]\n", name);
772                         return JSON_ERROR;
773                 }
774
775                 s = tsocket_address_string(address, ctx);
776                 if (s == NULL) {
777                         DBG_ERR("Out of memory adding address [%s]\n", name);
778                         TALLOC_FREE(ctx);
779                         return JSON_ERROR;
780                 }
781                 ret = json_add_string(object, name, s);
782                 if (ret != 0) {
783                         DBG_ERR(
784                             "Unable to add address [%s] value [%s]\n", name, s);
785                         TALLOC_FREE(ctx);
786                         return JSON_ERROR;
787                 }
788                 TALLOC_FREE(ctx);
789         }
790         return ret;
791 }
792
793 /*
794  * @brief Add a formatted string representation of a sid to a json object.
795  *
796  * Add the string representation of a Samba sid to the object.
797  *
798  * "sid":"S-1-5-18"
799  *
800  *
801  * @param object the JSON object to be updated.
802  * @param name the name.
803  * @param sid the sid
804  *
805  * @return 0 the operation was successful
806  *        -1 the operation failed
807  *
808  */
809 int json_add_sid(struct json_object *object,
810                  const char *name,
811                  const struct dom_sid *sid)
812 {
813         int ret = 0;
814
815         if (json_is_invalid(object)) {
816                 DBG_ERR("Unable to add SID [%s], "
817                         "target object is invalid\n",
818                         name);
819                 return JSON_ERROR;
820         }
821
822         if (sid == NULL) {
823                 ret = json_object_set_new(object->root, name, json_null());
824                 if (ret != 0) {
825                         DBG_ERR("Unable to add null SID [%s]\n", name);
826                         return ret;
827                 }
828         } else {
829                 char sid_buf[DOM_SID_STR_BUFLEN];
830
831                 dom_sid_string_buf(sid, sid_buf, sizeof(sid_buf));
832                 ret = json_add_string(object, name, sid_buf);
833                 if (ret != 0) {
834                         DBG_ERR("Unable to add SID [%s] value [%s]\n",
835                                 name,
836                                 sid_buf);
837                         return ret;
838                 }
839         }
840         return ret;
841 }
842
843 /*
844  * @brief Add a formatted string representation of a guid to a json object.
845  *
846  * Add the string representation of a Samba GUID to the object.
847  *
848  * "guid":"1fb9f2ee-2a4d-4bf8-af8b-cb9d4529a9ab"
849  *
850  *
851  * @param object the JSON object to be updated.
852  * @param name the name.
853  * @param guid the guid.
854  *
855  * @return 0 the operation was successful
856  *        -1 the operation failed
857  *
858  *
859  */
860 int json_add_guid(struct json_object *object,
861                   const char *name,
862                   const struct GUID *guid)
863 {
864
865         int ret = 0;
866
867         if (json_is_invalid(object)) {
868                 DBG_ERR("Unable to add GUID [%s], "
869                         "target object is invalid\n",
870                         name);
871                 return JSON_ERROR;
872         }
873
874         if (guid == NULL) {
875                 ret = json_object_set_new(object->root, name, json_null());
876                 if (ret != 0) {
877                         DBG_ERR("Unable to add null GUID [%s]\n", name);
878                         return ret;
879                 }
880         } else {
881                 char *guid_str;
882                 struct GUID_txt_buf guid_buff;
883
884                 guid_str = GUID_buf_string(guid, &guid_buff);
885                 ret = json_add_string(object, name, guid_str);
886                 if (ret != 0) {
887                         DBG_ERR("Unable to guid GUID [%s] value [%s]\n",
888                                 name,
889                                 guid_str);
890                         return ret;
891                 }
892         }
893         return ret;
894 }
895
896 /*
897  * @brief Convert a JSON object into a string
898  *
899  * Convert the jsom object into a string suitable for printing on a log line,
900  * i.e. with no embedded line breaks.
901  *
902  * If the object is invalid it logs an error and returns NULL.
903  *
904  * @param mem_ctx the talloc memory context owning the returned string
905  * @param object the json object.
906  *
907  * @return A string representation of the object or NULL if the object
908  *         is invalid.
909  */
910 char *json_to_string(TALLOC_CTX *mem_ctx, struct json_object *object)
911 {
912         char *json = NULL;
913         char *json_string = NULL;
914
915         if (json_is_invalid(object)) {
916                 DBG_ERR("Invalid JSON object, unable to convert to string\n");
917                 return NULL;
918         }
919
920         if (object->root == NULL) {
921                 return NULL;
922         }
923
924         /*
925          * json_dumps uses malloc, so need to call free(json) to release
926          * the memory
927          */
928         json = json_dumps(object->root, 0);
929         if (json == NULL) {
930                 DBG_ERR("Unable to convert JSON object to string\n");
931                 return NULL;
932         }
933
934         json_string = talloc_strdup(mem_ctx, json);
935         if (json_string == NULL) {
936                 free(json);
937                 DBG_ERR("Unable to copy JSON object string to talloc string\n");
938                 return NULL;
939         }
940         free(json);
941
942         return json_string;
943 }
944
945 /*
946  * @brief get a json array named "name" from the json object.
947  *
948  * Get the array attribute named name, creating it if it does not exist.
949  *
950  * @param object the json object.
951  * @param name the name of the array attribute
952  *
953  * @return The array object, will be created if it did not exist.
954  */
955 struct json_object json_get_array(struct json_object *object, const char *name)
956 {
957
958         struct json_object array = json_empty_object;
959         json_t *a = NULL;
960         int ret = 0;
961
962         if (json_is_invalid(object)) {
963                 DBG_ERR("Invalid JSON object, unable to get array [%s]\n",
964                         name);
965                 json_free(&array);
966                 return array;
967         }
968
969         array = json_new_array();
970         if (json_is_invalid(&array)) {
971                 DBG_ERR("Unable to create new array for [%s]\n", name);
972                 return array;
973         }
974
975         a = json_object_get(object->root, name);
976         if (a == NULL) {
977                 return array;
978         }
979
980         ret = json_array_extend(array.root, a);
981         if (ret != 0) {
982                 DBG_ERR("Unable to get array [%s]\n", name);
983                 json_free(&array);
984                 return array;
985         }
986
987         return array;
988 }
989
990 /*
991  * @brief get a json object named "name" from the json object.
992  *
993  * Get the object attribute named name, creating it if it does not exist.
994  *
995  * @param object the json object.
996  * @param name the name of the object attribute
997  *
998  * @return The object, will be created if it did not exist.
999  */
1000 struct json_object json_get_object(struct json_object *object, const char *name)
1001 {
1002
1003         struct json_object o = json_new_object();
1004         json_t *v = NULL;
1005         int ret = 0;
1006
1007         if (json_is_invalid(object)) {
1008                 DBG_ERR("Invalid JSON object, unable to get object [%s]\n",
1009                         name);
1010                 json_free(&o);
1011                 return o;
1012         }
1013
1014         v = json_object_get(object->root, name);
1015         if (v == NULL) {
1016                 return o;
1017         }
1018         ret = json_object_update(o.root, v);
1019         if (ret != 0) {
1020                 DBG_ERR("Unable to get object [%s]\n", name);
1021                 json_free(&o);
1022                 return o;
1023         }
1024         return o;
1025 }
1026 #endif