LCOV - code coverage report
Current view: top level - lib/audit_logging - audit_logging.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 294 355 82.8 %
Date: 2021-08-25 13:27:56 Functions: 22 23 95.7 %

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

Generated by: LCOV version 1.13