LCOV - code coverage report
Current view: top level - lib/audit_logging - audit_logging.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 210 371 56.6 %
Date: 2024-06-13 04:01:37 Functions: 21 24 87.5 %

          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           0 : 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           0 :         ret = gettimeofday(&tv, NULL);
      58           0 :         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           0 :         tm_info = localtime(&tv.tv_sec);
      66           0 :         if (tm_info == NULL) {
      67           0 :                 DBG_ERR("Unable to determine local time\n");
      68           0 :                 return NULL;
      69             :         }
      70             : 
      71           0 :         strftime(buffer, sizeof(buffer)-1, "%a, %d %b %Y %H:%M:%S", tm_info);
      72           0 :         strftime(tz, sizeof(tz)-1, "%Z", tm_info);
      73           0 :         ts = talloc_asprintf(frame, "%s.%06ld %s", buffer, (long)tv.tv_usec, tz);
      74           0 :         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      427920 : void audit_log_json(struct json_object* message,
     113             :                     int debug_class,
     114             :                     int debug_level)
     115             : {
     116      427920 :         TALLOC_CTX *frame = NULL;
     117      427920 :         char *s = NULL;
     118             : 
     119      427920 :         if (json_is_invalid(message)) {
     120           0 :                 DBG_ERR("Invalid JSON object, unable to log\n");
     121           0 :                 return;
     122             :         }
     123             : 
     124      427920 :         frame = talloc_stackframe();
     125      427920 :         s = json_to_string(frame, message);
     126      427920 :         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      427920 :         DEBUGADDC(debug_class, debug_level, ("%s\n", s));
     141      427920 :         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      427920 : 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      427920 :         TALLOC_CTX *frame = talloc_stackframe();
     162             :         unsigned num_servers, i;
     163             :         struct server_id *servers;
     164             : 
     165      427920 :         status = irpc_servers_byname(
     166             :                 msg_ctx,
     167             :                 frame,
     168             :                 server_name,
     169             :                 &num_servers,
     170             :                 &servers);
     171             : 
     172      427920 :         if (!NT_STATUS_IS_OK(status)) {
     173      427705 :                 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      427705 :                 TALLOC_FREE(frame);
     178      427705 :                 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         215 :         for (i = 0; i < num_servers; i++) {
     187         215 :                 status = imessaging_send(
     188             :                         msg_ctx,
     189         215 :                         servers[i],
     190             :                         MSG_PING,
     191             :                         &data_blob_null);
     192         215 :                 if (NT_STATUS_IS_OK(status)) {
     193         215 :                         *event_server = servers[i];
     194         215 :                         TALLOC_FREE(frame);
     195         215 :                         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      427920 : 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      427920 :         struct server_id event_server = {
     232             :                 .pid = 0,
     233             :         };
     234             :         NTSTATUS status;
     235             : 
     236      427920 :         const char *message_string = NULL;
     237      427920 :         DATA_BLOB message_blob = data_blob_null;
     238      427920 :         TALLOC_CTX *ctx = NULL;
     239             : 
     240      427920 :         if (json_is_invalid(message)) {
     241           0 :                 DBG_ERR("Invalid JSON object, unable to send\n");
     242      427705 :                 return;
     243             :         }
     244      427920 :         if (msg_ctx == NULL) {
     245           0 :                 DBG_DEBUG("No messaging context\n");
     246           0 :                 return;
     247             :         }
     248             : 
     249      427920 :         ctx = talloc_new(NULL);
     250      427920 :         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      427920 :         status = get_event_server(msg_ctx, server_name, &event_server);
     260      427920 :         if (!NT_STATUS_IS_OK(status)) {
     261      427705 :                 TALLOC_FREE(ctx);
     262      427705 :                 return;
     263             :         }
     264             : 
     265         215 :         message_string = json_to_string(ctx, message);
     266         215 :         message_blob = data_blob_string_const(message_string);
     267         215 :         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         215 :         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         215 :         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     5658890 : struct json_object json_new_object(void) {
     305             : 
     306     5658890 :         struct json_object object = json_empty_object;
     307             : 
     308     5658890 :         object.root = json_object();
     309     5658890 :         if (object.root == NULL) {
     310           0 :                 object.valid = false;
     311           0 :                 DBG_ERR("Unable to create JSON object\n");
     312           0 :                 return object;
     313             :         }
     314     5658890 :         object.valid = true;
     315     5658890 :         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     2449028 : struct json_object json_new_array(void) {
     332             : 
     333     2449028 :         struct json_object array = json_empty_object;
     334             : 
     335     2449028 :         array.root = json_array();
     336     2449028 :         if (array.root == NULL) {
     337           0 :                 array.valid = false;
     338           0 :                 DBG_ERR("Unable to create JSON array\n");
     339           0 :                 return array;
     340             :         }
     341     2449028 :         array.valid = true;
     342     2449028 :         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      427924 : void json_free(struct json_object *object)
     354             : {
     355      427924 :         if (object->root != NULL) {
     356      427924 :                 json_decref(object->root);
     357             :         }
     358      427924 :         object->root = NULL;
     359      427924 :         object->valid = false;
     360      427924 : }
     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    42797368 : bool json_is_invalid(const struct json_object *object)
     371             : {
     372    42797368 :         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     1375317 : int json_add_int(struct json_object *object, const char *name, const int value)
     389             : {
     390     1375317 :         int ret = 0;
     391     1375317 :         json_t *integer = NULL;
     392             : 
     393     1375317 :         if (json_is_invalid(object)) {
     394           0 :                 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     1375317 :         integer = json_integer(value);
     402     1375317 :         if (integer == NULL) {
     403           0 :                 DBG_ERR("Unable to create integer value [%s] value [%d]\n",
     404             :                         name,
     405             :                         value);
     406           0 :                 return JSON_ERROR;
     407             :         }
     408             : 
     409     1375317 :         ret = json_object_set_new(object->root, name, integer);
     410     1375317 :         if (ret != 0) {
     411           0 :                 json_decref(integer);
     412           0 :                 DBG_ERR("Unable to add int [%s] value [%d]\n", name, value);
     413             :         }
     414     1375317 :         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      521866 : int json_add_bool(struct json_object *object,
     431             :                   const char *name,
     432             :                   const bool value)
     433             : {
     434      521866 :         int ret = 0;
     435             : 
     436      521866 :         if (json_is_invalid(object)) {
     437           0 :                 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      521866 :         ret = json_object_set_new(object->root, name, json_boolean(value));
     445      521866 :         if (ret != 0) {
     446           0 :                 DBG_ERR("Unable to add boolean [%s] value [%d]\n", name, value);
     447             :         }
     448      521866 :         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     5131029 : int json_add_string(struct json_object *object,
     465             :                     const char *name,
     466             :                     const char *value)
     467             : {
     468     5131029 :         int ret = 0;
     469             : 
     470     5131029 :         if (json_is_invalid(object)) {
     471           0 :                 DBG_ERR("Unable to add string [%s], target object is invalid\n",
     472             :                         name);
     473           0 :                 return JSON_ERROR;
     474             :         }
     475     5131029 :         if (value) {
     476     5056835 :                 json_t *string = json_string(value);
     477     5056835 :                 if (string == NULL) {
     478           0 :                         DBG_ERR("Unable to add string [%s], "
     479             :                                 "could not create string object\n",
     480             :                                 name);
     481           0 :                         return JSON_ERROR;
     482             :                 }
     483     5056835 :                 ret = json_object_set_new(object->root, name, string);
     484     5056835 :                 if (ret != 0) {
     485           0 :                         json_decref(string);
     486           0 :                         DBG_ERR("Unable to add string [%s]\n", name);
     487           0 :                         return ret;
     488             :                 }
     489             :         } else {
     490       74194 :                 ret = json_object_set_new(object->root, name, json_null());
     491       74194 :                 if (ret != 0) {
     492           0 :                         DBG_ERR("Unable to add null string [%s]\n", name);
     493           0 :                         return ret;
     494             :                 }
     495             :         }
     496     5131029 :         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     1710518 : void json_assert_is_array(struct json_object *array) {
     509             : 
     510     1710518 :         if (json_is_invalid(array)) {
     511           0 :                 return;
     512             :         }
     513             : 
     514     1710518 :         if (json_is_array(array->root) == false) {
     515           0 :                 DBG_ERR("JSON object is not an array\n");
     516           0 :                 array->valid = false;
     517           0 :                 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     7679994 : int json_add_object(struct json_object *object,
     535             :                     const char *name,
     536             :                     struct json_object *value)
     537             : {
     538     7679994 :         int ret = 0;
     539     7679994 :         json_t *jv = NULL;
     540             : 
     541     7679994 :         if (value != NULL && json_is_invalid(value)) {
     542           0 :                 DBG_ERR("Invalid JSON object [%s] supplied\n", name);
     543           0 :                 return JSON_ERROR;
     544             :         }
     545     7679994 :         if (json_is_invalid(object)) {
     546           0 :                 DBG_ERR("Unable to add object [%s], target object is invalid\n",
     547             :                         name);
     548           0 :                 return JSON_ERROR;
     549             :         }
     550             : 
     551     7679994 :         jv = value == NULL ? json_null() : value->root;
     552             : 
     553     7679994 :         if (json_is_array(object->root)) {
     554     2939367 :                 ret = json_array_append_new(object->root, jv);
     555     4740627 :         } else if (json_is_object(object->root)) {
     556     4740627 :                 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     7679994 :         if (ret != 0) {
     562           0 :                 DBG_ERR("Unable to add object [%s]\n", name);
     563             :         }
     564     7679994 :         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     1437141 : int json_add_stringn(struct json_object *object,
     586             :                      const char *name,
     587             :                      const char *value,
     588             :                      const size_t len)
     589             : {
     590             : 
     591     1437141 :         int ret = 0;
     592     1437141 :         if (json_is_invalid(object)) {
     593           0 :                 DBG_ERR("Unable to add string [%s], target object is invalid\n",
     594             :                         name);
     595           0 :                 return JSON_ERROR;
     596             :         }
     597             : 
     598     2874282 :         if (value != NULL && len > 0) {
     599     1437141 :                 json_t *string = NULL;
     600     1437141 :                 char buffer[len+1];
     601             : 
     602     1437141 :                 strncpy(buffer, value, len);
     603     1437141 :                 buffer[len] = '\0';
     604             : 
     605     1437141 :                 string = json_string(buffer);
     606     1437141 :                 if (string == NULL) {
     607           0 :                         DBG_ERR("Unable to add string [%s], "
     608             :                                 "could not create string object\n",
     609             :                                 name);
     610           0 :                         return JSON_ERROR;
     611             :                 }
     612     1437141 :                 ret = json_object_set_new(object->root, name, string);
     613     1437141 :                 if (ret != 0) {
     614           0 :                         json_decref(string);
     615           0 :                         DBG_ERR("Unable to add string [%s]\n", name);
     616           0 :                         return ret;
     617             :                 }
     618             :         } else {
     619           0 :                 ret = json_object_set_new(object->root, name, json_null());
     620           0 :                 if (ret != 0) {
     621           0 :                         DBG_ERR("Unable to add null string [%s]\n", name);
     622           0 :                         return ret;
     623             :                 }
     624             :         }
     625     1437141 :         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      427920 : int json_add_version(struct json_object *object, int major, int minor)
     652             : {
     653      427920 :         int ret = 0;
     654             :         struct json_object version;
     655             : 
     656      427920 :         if (json_is_invalid(object)) {
     657           0 :                 DBG_ERR("Unable to add version, target object is invalid\n");
     658           0 :                 return JSON_ERROR;
     659             :         }
     660             : 
     661      427920 :         version = json_new_object();
     662      427920 :         if (json_is_invalid(&version)) {
     663           0 :                 DBG_ERR("Unable to add version, failed to create object\n");
     664           0 :                 return JSON_ERROR;
     665             :         }
     666      427920 :         ret = json_add_int(&version, "major", major);
     667      427920 :         if (ret != 0) {
     668           0 :                 json_free(&version);
     669           0 :                 return ret;
     670             :         }
     671      427920 :         ret = json_add_int(&version, "minor", minor);
     672      427920 :         if (ret != 0) {
     673           0 :                 json_free(&version);
     674           0 :                 return ret;
     675             :         }
     676      427920 :         ret = json_add_object(object, "version", &version);
     677      427920 :         if (ret != 0) {
     678           0 :                 json_free(&version);
     679           0 :                 return ret;
     680             :         }
     681      427920 :         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      427920 : 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      427920 :         if (json_is_invalid(object)) {
     709           0 :                 DBG_ERR("Unable to add time stamp, target object is invalid\n");
     710           0 :                 return JSON_ERROR;
     711             :         }
     712             : 
     713      427920 :         r = gettimeofday(&tv, NULL);
     714      427920 :         if (r) {
     715           0 :                 DBG_ERR("Unable to get time of day: (%d) %s\n",
     716             :                         errno,
     717             :                         strerror(errno));
     718           0 :                 return JSON_ERROR;
     719             :         }
     720             : 
     721      427920 :         tm_info = localtime(&tv.tv_sec);
     722      427920 :         if (tm_info == NULL) {
     723           0 :                 DBG_ERR("Unable to determine local time\n");
     724           0 :                 return JSON_ERROR;
     725             :         }
     726             : 
     727      427920 :         strftime(buffer, sizeof(buffer)-1, "%Y-%m-%dT%T", tm_info);
     728      427920 :         strftime(tz, sizeof(tz)-1, "%z", tm_info);
     729      427920 :         snprintf(
     730             :                 timestamp,
     731             :                 sizeof(timestamp),
     732             :                 "%s.%06ld%s",
     733             :                 buffer,
     734             :                 tv.tv_usec,
     735             :                 tz);
     736      427920 :         ret = json_add_string(object, "timestamp", timestamp);
     737      427920 :         if (ret != 0) {
     738           0 :                 DBG_ERR("Unable to add time stamp to JSON object\n");
     739             :         }
     740      427920 :         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      379452 : int json_add_address(struct json_object *object,
     760             :                      const char *name,
     761             :                      const struct tsocket_address *address)
     762             : {
     763      379452 :         int ret = 0;
     764             : 
     765      379452 :         if (json_is_invalid(object)) {
     766           0 :                 DBG_ERR("Unable to add address [%s], "
     767             :                         "target object is invalid\n",
     768             :                         name);
     769           0 :                 return JSON_ERROR;
     770             :         }
     771             : 
     772      379452 :         if (address == NULL) {
     773      171081 :                 ret = json_object_set_new(object->root, name, json_null());
     774      171081 :                 if (ret != 0) {
     775           0 :                         DBG_ERR("Unable to add null address [%s]\n", name);
     776           0 :                         return JSON_ERROR;
     777             :                 }
     778             :         } else {
     779      208371 :                 TALLOC_CTX *ctx = talloc_new(NULL);
     780      208371 :                 char *s = NULL;
     781             : 
     782      208371 :                 if (ctx == NULL) {
     783           0 :                         DBG_ERR("Out of memory adding address [%s]\n", name);
     784           0 :                         return JSON_ERROR;
     785             :                 }
     786             : 
     787      208371 :                 s = tsocket_address_string(address, ctx);
     788      208371 :                 if (s == NULL) {
     789           0 :                         DBG_ERR("Out of memory adding address [%s]\n", name);
     790           0 :                         TALLOC_FREE(ctx);
     791           0 :                         return JSON_ERROR;
     792             :                 }
     793      208371 :                 ret = json_add_string(object, name, s);
     794      208371 :                 if (ret != 0) {
     795           0 :                         DBG_ERR(
     796             :                             "Unable to add address [%s] value [%s]\n", name, s);
     797           0 :                         TALLOC_FREE(ctx);
     798           0 :                         return JSON_ERROR;
     799             :                 }
     800      208371 :                 TALLOC_FREE(ctx);
     801             :         }
     802      379452 :         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      356899 : int json_add_sid(struct json_object *object,
     822             :                  const char *name,
     823             :                  const struct dom_sid *sid)
     824             : {
     825      356899 :         int ret = 0;
     826             : 
     827      356899 :         if (json_is_invalid(object)) {
     828           0 :                 DBG_ERR("Unable to add SID [%s], "
     829             :                         "target object is invalid\n",
     830             :                         name);
     831           0 :                 return JSON_ERROR;
     832             :         }
     833             : 
     834      356899 :         if (sid == NULL) {
     835       22451 :                 ret = json_object_set_new(object->root, name, json_null());
     836       22451 :                 if (ret != 0) {
     837           0 :                         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      334448 :                 ret = json_add_string(
     844      334448 :                         object, name, dom_sid_str_buf(sid, &sid_buf));
     845      334448 :                 if (ret != 0) {
     846           0 :                         DBG_ERR("Unable to add SID [%s] value [%s]\n",
     847             :                                 name,
     848             :                                 sid_buf.buf);
     849           0 :                         return ret;
     850             :                 }
     851             :         }
     852      356899 :         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      673444 : int json_add_guid(struct json_object *object,
     873             :                   const char *name,
     874             :                   const struct GUID *guid)
     875             : {
     876             : 
     877      673444 :         int ret = 0;
     878             : 
     879      673444 :         if (json_is_invalid(object)) {
     880           0 :                 DBG_ERR("Unable to add GUID [%s], "
     881             :                         "target object is invalid\n",
     882             :                         name);
     883           0 :                 return JSON_ERROR;
     884             :         }
     885             : 
     886      673444 :         if (guid == NULL) {
     887        3625 :                 ret = json_object_set_new(object->root, name, json_null());
     888        3625 :                 if (ret != 0) {
     889           0 :                         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      669819 :                 guid_str = GUID_buf_string(guid, &guid_buff);
     897      669819 :                 ret = json_add_string(object, name, guid_str);
     898      669819 :                 if (ret != 0) {
     899           0 :                         DBG_ERR("Unable to guid GUID [%s] value [%s]\n",
     900             :                                 name,
     901             :                                 guid_str);
     902           0 :                         return ret;
     903             :                 }
     904             :         }
     905      673444 :         return ret;
     906             : }
     907             : 
     908             : /*
     909             :  * @brief Replaces the object for a given key with a given json object.
     910             :  *
     911             :  * If key already exists, the value will be replaced. Otherwise the given
     912             :  * value will be added under the given key.
     913             :  *
     914             :  * @param object the JSON object to be updated.
     915             :  * @param key the key which will be updated.
     916             :  * @param new_obj the new value object to be inserted.
     917             :  *
     918             :  * @return 0 the operation was successful
     919             :  *        -1 the operation failed (e.j. if one of the paramters is invalid)
     920             :  */
     921           0 : int json_update_object(struct json_object *object,
     922             :                        const char *key,
     923             :                        struct json_object *new_obj)
     924             : {
     925           0 :         int ret = 0;
     926             : 
     927           0 :         if (json_is_invalid(object)) {
     928           0 :                 DBG_ERR("Unable to update key [%s], "
     929             :                         "target object is invalid\n",
     930             :                         key);
     931           0 :                 return JSON_ERROR;
     932             :         }
     933           0 :         if (json_is_invalid(new_obj)) {
     934           0 :                 DBG_ERR("Unable to update key [%s], "
     935             :                         "new object is invalid\n",
     936             :                         key);
     937           0 :                 return JSON_ERROR;
     938             :         }
     939             : 
     940           0 :         if (key == NULL) {
     941           0 :                 DBG_ERR("Unable to add null String as key\n");
     942           0 :                 return JSON_ERROR;
     943             :         }
     944             : 
     945           0 :         ret = json_object_set(object->root, key, new_obj->root);
     946           0 :         if (ret != 0) {
     947           0 :                 DBG_ERR("Unable to update object\n");
     948           0 :                 return ret;
     949             :         }
     950             : 
     951           0 :         return ret;
     952             : }
     953             : 
     954             : /*
     955             :  * @brief Convert a JSON object into a string
     956             :  *
     957             :  * Convert the json object into a string suitable for printing on a log line,
     958             :  * i.e. with no embedded line breaks.
     959             :  *
     960             :  * If the object is invalid it logs an error and returns NULL.
     961             :  *
     962             :  * @param mem_ctx the talloc memory context owning the returned string
     963             :  * @param object the json object.
     964             :  *
     965             :  * @return A string representation of the object or NULL if the object
     966             :  *         is invalid.
     967             :  */
     968      428139 : char *json_to_string(TALLOC_CTX *mem_ctx, const struct json_object *object)
     969             : {
     970      428139 :         char *json = NULL;
     971      428139 :         char *json_string = NULL;
     972             : 
     973      428139 :         if (json_is_invalid(object)) {
     974           0 :                 DBG_ERR("Invalid JSON object, unable to convert to string\n");
     975           0 :                 return NULL;
     976             :         }
     977             : 
     978      428139 :         if (object->root == NULL) {
     979           0 :                 return NULL;
     980             :         }
     981             : 
     982             :         /*
     983             :          * json_dumps uses malloc, so need to call free(json) to release
     984             :          * the memory
     985             :          */
     986      428139 :         json = json_dumps(object->root, 0);
     987      428139 :         if (json == NULL) {
     988           0 :                 DBG_ERR("Unable to convert JSON object to string\n");
     989           0 :                 return NULL;
     990             :         }
     991             : 
     992      428139 :         json_string = talloc_strdup(mem_ctx, json);
     993      428139 :         if (json_string == NULL) {
     994           0 :                 free(json);
     995           0 :                 DBG_ERR("Unable to copy JSON object string to talloc string\n");
     996           0 :                 return NULL;
     997             :         }
     998      428139 :         free(json);
     999             : 
    1000      428139 :         return json_string;
    1001             : }
    1002             : 
    1003             : /*
    1004             :  * @brief get a json array named "name" from the json object.
    1005             :  *
    1006             :  * Get the array attribute named name, creating it if it does not exist.
    1007             :  *
    1008             :  * @param object the json object.
    1009             :  * @param name the name of the array attribute
    1010             :  *
    1011             :  * @return The array object, will be created if it did not exist.
    1012             :  */
    1013     1228849 : struct json_object json_get_array(struct json_object *object, const char *name)
    1014             : {
    1015             : 
    1016     1228849 :         struct json_object array = json_empty_object;
    1017     1228849 :         json_t *a = NULL;
    1018     1228849 :         int ret = 0;
    1019             : 
    1020     1228849 :         if (json_is_invalid(object)) {
    1021           0 :                 DBG_ERR("Invalid JSON object, unable to get array [%s]\n",
    1022             :                         name);
    1023           0 :                 json_free(&array);
    1024           0 :                 return array;
    1025             :         }
    1026             : 
    1027     1228849 :         array = json_new_array();
    1028     1228849 :         if (json_is_invalid(&array)) {
    1029           0 :                 DBG_ERR("Unable to create new array for [%s]\n", name);
    1030           0 :                 return array;
    1031             :         }
    1032             : 
    1033     1228849 :         a = json_object_get(object->root, name);
    1034     1228849 :         if (a == NULL) {
    1035     1185425 :                 return array;
    1036             :         }
    1037             : 
    1038       43424 :         ret = json_array_extend(array.root, a);
    1039       43424 :         if (ret != 0) {
    1040           0 :                 DBG_ERR("Unable to get array [%s]\n", name);
    1041           0 :                 json_free(&array);
    1042           0 :                 return array;
    1043             :         }
    1044             : 
    1045       43424 :         return array;
    1046             : }
    1047             : 
    1048             : /*
    1049             :  * @brief get a json object named "name" from the json object.
    1050             :  *
    1051             :  * Get the object attribute named name, creating it if it does not exist.
    1052             :  *
    1053             :  * @param object the json object.
    1054             :  * @param name the name of the object attribute
    1055             :  *
    1056             :  * @return The object, will be created if it did not exist.
    1057             :  */
    1058     1228849 : struct json_object json_get_object(struct json_object *object, const char *name)
    1059             : {
    1060             : 
    1061     1228849 :         struct json_object o = json_new_object();
    1062     1228849 :         json_t *v = NULL;
    1063     1228849 :         int ret = 0;
    1064             : 
    1065     1228849 :         if (json_is_invalid(object)) {
    1066           0 :                 DBG_ERR("Invalid JSON object, unable to get object [%s]\n",
    1067             :                         name);
    1068           0 :                 json_free(&o);
    1069           0 :                 return o;
    1070             :         }
    1071             : 
    1072     1228849 :         v = json_object_get(object->root, name);
    1073     1228849 :         if (v == NULL) {
    1074     1185425 :                 return o;
    1075             :         }
    1076       43424 :         ret = json_object_update(o.root, v);
    1077       43424 :         if (ret != 0) {
    1078           0 :                 DBG_ERR("Unable to get object [%s]\n", name);
    1079           0 :                 json_free(&o);
    1080           0 :                 return o;
    1081             :         }
    1082       43424 :         return o;
    1083             : }
    1084             : #endif

Generated by: LCOV version 1.13