LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - audit_util.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 201 260 77.3 %
Date: 2024-04-13 12:30:31 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /*
       2             :    ldb database module utility library
       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             :  * Common utility functions for SamDb audit logging.
      22             :  *
      23             :  */
      24             : 
      25             : #include "includes.h"
      26             : #include "ldb_module.h"
      27             : #include "lib/audit_logging/audit_logging.h"
      28             : 
      29             : #include "dsdb/samdb/samdb.h"
      30             : #include "dsdb/samdb/ldb_modules/util.h"
      31             : #include "libcli/security/dom_sid.h"
      32             : #include "libcli/security/security_token.h"
      33             : #include "auth/common_auth.h"
      34             : #include "param/param.h"
      35             : #include "dsdb/samdb/ldb_modules/util.h"
      36             : #include "dsdb/samdb/ldb_modules/audit_util_proto.h"
      37             : 
      38             : #define MAX_LENGTH 1024
      39             : 
      40             : #define min(a, b) (((a)>(b))?(b):(a))
      41             : 
      42             : /*
      43             :  * List of attributes considered secret or confidential the values of these
      44             :  * attributes should not be displayed in log messages.
      45             :  */
      46             : static const char * const secret_attributes[] = {
      47             :         DSDB_SECRET_ATTRIBUTES,
      48             :         NULL};
      49             : /*
      50             :  * List of attributes that contain a password, used to detect password changes
      51             :  */
      52             : static const char * const password_attributes[] = {
      53             :         DSDB_PASSWORD_ATTRIBUTES,
      54             :         NULL};
      55             : 
      56             : /*
      57             :  * @brief Should the value of the specified value be redacted.
      58             :  *
      59             :  * The values of secret or password attributes should not be displayed.
      60             :  *
      61             :  * @param name The attributes name.
      62             :  *
      63             :  * @return True if the attribute should be redacted
      64             :  */
      65     1742011 : bool dsdb_audit_redact_attribute(const char * name)
      66             : {
      67             : 
      68     1742011 :         if (ldb_attr_in_list(secret_attributes, name)) {
      69       12099 :                 return true;
      70             :         }
      71             : 
      72     1729768 :         if (ldb_attr_in_list(password_attributes, name)) {
      73        2756 :                 return true;
      74             :         }
      75             : 
      76     1644578 :         return false;
      77             : }
      78             : 
      79             : /*
      80             :  * @brief is the attribute a password attribute?
      81             :  *
      82             :  * Is the attribute a password attribute.
      83             :  *
      84             :  * @return True if the attribute is a "Password" attribute.
      85             :  */
      86     5597887 : bool dsdb_audit_is_password_attribute(const char * name)
      87             : {
      88             : 
      89     5597887 :         bool is_password = ldb_attr_in_list(password_attributes, name);
      90     5597887 :         return is_password;
      91             : }
      92             : 
      93             : /*
      94             :  * @brief Get the remote address from the ldb context.
      95             :  *
      96             :  * The remote address is stored in the ldb opaque value "remoteAddress"
      97             :  * it is the responsibility of the higher level code to ensure that this
      98             :  * value is set.
      99             :  *
     100             :  * @param ldb the ldb_context.
     101             :  *
     102             :  * @return the remote address if known, otherwise NULL.
     103             :  */
     104      417603 : const struct tsocket_address *dsdb_audit_get_remote_address(
     105             :         struct ldb_context *ldb)
     106             : {
     107      417603 :         void *opaque_remote_address = NULL;
     108       10191 :         struct tsocket_address *remote_address;
     109             : 
     110      417603 :         opaque_remote_address = ldb_get_opaque(ldb,
     111             :                                                "remoteAddress");
     112      417603 :         if (opaque_remote_address == NULL) {
     113      211892 :                 return NULL;
     114             :         }
     115             : 
     116      196435 :         remote_address = talloc_get_type(opaque_remote_address,
     117             :                                          struct tsocket_address);
     118      196435 :         return remote_address;
     119             : }
     120             : 
     121             : /*
     122             :  * @brief Get the actual user SID from ldb context.
     123             :  *
     124             :  * The actual user SID is stored in the ldb opaque value "networkSessionInfo"
     125             :  * it is the responsibility of the higher level code to ensure that this
     126             :  * value is set.
     127             :  *
     128             :  * @param ldb the ldb_context.
     129             :  *
     130             :  * @return the users actual sid.
     131             :  */
     132        5084 : const struct dom_sid *dsdb_audit_get_actual_sid(struct ldb_context *ldb)
     133             : {
     134        5084 :         void *opaque_session = NULL;
     135        5084 :         struct auth_session_info *session = NULL;
     136        5084 :         struct security_token *user_token = NULL;
     137             : 
     138        5084 :         opaque_session = ldb_get_opaque(ldb, DSDB_NETWORK_SESSION_INFO);
     139        5084 :         if (opaque_session == NULL) {
     140          22 :                 return NULL;
     141             :         }
     142             : 
     143        5060 :         session = talloc_get_type(opaque_session, struct auth_session_info);
     144        5060 :         if (session == NULL) {
     145           0 :                 return NULL;
     146             :         }
     147             : 
     148        5060 :         user_token = session->security_token;
     149        5060 :         if (user_token == NULL) {
     150           0 :                 return NULL;
     151             :         }
     152        5059 :         return &user_token->sids[PRIMARY_USER_SID_INDEX];
     153             : }
     154             : /*
     155             :  * @brief get the ldb error string.
     156             :  *
     157             :  * Get the ldb error string if set, otherwise get the generic error code
     158             :  * for the status code.
     159             :  *
     160             :  * @param ldb the ldb_context.
     161             :  * @param status the ldb_status code.
     162             :  *
     163             :  * @return a string describing the error.
     164             :  */
     165           3 : const char *dsdb_audit_get_ldb_error_string(
     166             :         struct ldb_module *module,
     167             :         int status)
     168             : {
     169           3 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     170           3 :         const char *err_string = ldb_errstring(ldb);
     171             : 
     172           3 :         if (err_string == NULL) {
     173           1 :                 return ldb_strerror(status);
     174             :         }
     175           1 :         return err_string;
     176             : }
     177             : 
     178             : /*
     179             :  * @brief get the SID of the user performing the operation.
     180             :  *
     181             :  * Get the SID of the user performing the operation.
     182             :  *
     183             :  * @param module the ldb_module.
     184             :  *
     185             :  * @return the SID of the currently logged on user.
     186             :  */
     187      412525 : const struct dom_sid *dsdb_audit_get_user_sid(const struct ldb_module *module)
     188             : {
     189      412525 :         struct security_token *user_token = NULL;
     190             : 
     191             :         /*
     192             :          * acl_user_token does not alter module so it's safe
     193             :          * to discard the const.
     194             :          */
     195      412525 :         user_token = acl_user_token(discard_const(module));
     196      412525 :         if (user_token == NULL) {
     197           0 :                 return NULL;
     198             :         }
     199      412518 :         return &user_token->sids[PRIMARY_USER_SID_INDEX];
     200             : 
     201             : }
     202             : 
     203             : /*
     204             :  * @brief is operation being performed using the system session.
     205             :  *
     206             :  * Is the operation being performed using the system session.
     207             :  *
     208             :  * @param module the ldb_module.
     209             :  *
     210             :  * @return true if the operation is being performed using the system session.
     211             :  */
     212      136617 : bool dsdb_audit_is_system_session(const struct ldb_module *module)
     213             : {
     214      136617 :         struct security_token *user_token = NULL;
     215             : 
     216             :         /*
     217             :          * acl_user_token does not alter module and security_token_is_system
     218             :          * does not alter the security token so it's safe to discard the const.
     219             :          */
     220      136617 :         user_token = acl_user_token(discard_const(module));
     221      136617 :         if (user_token == NULL) {
     222           0 :                 return false;
     223             :         }
     224      136614 :         return security_token_is_system(user_token);;
     225             : 
     226             : }
     227             : 
     228             : /*
     229             :  * @brief get the session identifier GUID
     230             :  *
     231             :  * Get the GUID that uniquely identifies the current authenticated session.
     232             :  *
     233             :  * @param module the ldb_module.
     234             :  *
     235             :  * @return the unique session GUID
     236             :  */
     237      412516 : const struct GUID *dsdb_audit_get_unique_session_token(
     238             :         const struct ldb_module *module)
     239             : {
     240      412516 :         struct ldb_context *ldb = ldb_module_get_ctx(discard_const(module));
     241       10148 :         struct auth_session_info *session_info
     242      412516 :                 = (struct auth_session_info *)ldb_get_opaque(
     243             :                         ldb,
     244             :                         DSDB_SESSION_INFO);
     245      412516 :         if(!session_info) {
     246           0 :                 return NULL;
     247             :         }
     248      412512 :         return &session_info->unique_session_token;
     249             : }
     250             : 
     251             : /*
     252             :  * @brief get the actual user session identifier
     253             :  *
     254             :  * Get the GUID that uniquely identifies the current authenticated session.
     255             :  * This is the session of the connected user, as it may differ from the
     256             :  * session the operation is being performed as, i.e. for operations performed
     257             :  * under the system session.
     258             :  *
     259             :  * @param context the ldb_context.
     260             :  *
     261             :  * @return the unique session GUID
     262             :  */
     263        5080 : const struct GUID *dsdb_audit_get_actual_unique_session_token(
     264             :         struct ldb_context *ldb)
     265             : {
     266          36 :         struct auth_session_info *session_info
     267        5080 :                 = (struct auth_session_info *)ldb_get_opaque(
     268             :                         ldb,
     269             :                         DSDB_NETWORK_SESSION_INFO);
     270        5080 :         if(!session_info) {
     271          22 :                 return NULL;
     272             :         }
     273        5056 :         return &session_info->unique_session_token;
     274             : }
     275             : 
     276             : /*
     277             :  * @brief Get a printable string value for the remote host address.
     278             :  *
     279             :  * Get a printable string representation of the remote host, for display in the
     280             :  * the audit logs.
     281             :  *
     282             :  * @param ldb the ldb context.
     283             :  * @param mem_ctx the talloc memory context that will own the returned string.
     284             :  *
     285             :  * @return A string representation of the remote host address or "Unknown"
     286             :  *
     287             :  */
     288           9 : char *dsdb_audit_get_remote_host(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
     289             : {
     290           9 :         const struct tsocket_address *remote_address;
     291           9 :         char* remote_host = NULL;
     292             : 
     293           9 :         remote_address = dsdb_audit_get_remote_address(ldb);
     294           9 :         if (remote_address == NULL) {
     295           4 :                 remote_host = talloc_asprintf(mem_ctx, "Unknown");
     296           4 :                 return remote_host;
     297             :         }
     298             : 
     299           5 :         remote_host = tsocket_address_string(remote_address, mem_ctx);
     300           5 :         return remote_host;
     301             : }
     302             : 
     303             : /*
     304             :  * @brief get a printable representation of the primary DN.
     305             :  *
     306             :  * Get a printable representation of the primary DN. The primary DN is the
     307             :  * DN of the object being added, deleted, modified or renamed.
     308             :  *
     309             :  * @param the ldb_request.
     310             :  *
     311             :  * @return a printable and linearized DN
     312             :  */
     313      437539 : const char* dsdb_audit_get_primary_dn(const struct ldb_request *request)
     314             : {
     315      437539 :         struct ldb_dn *dn = NULL;
     316      437539 :         switch (request->operation) {
     317      235648 :         case LDB_ADD:
     318      235648 :                 if (request->op.add.message != NULL) {
     319      235639 :                         dn = request->op.add.message->dn;
     320             :                 }
     321      227543 :                 break;
     322      150228 :         case LDB_MODIFY:
     323      150228 :                 if (request->op.mod.message != NULL) {
     324      150227 :                         dn = request->op.mod.message->dn;
     325             :                 }
     326      148170 :                 break;
     327       51654 :         case LDB_DELETE:
     328       51654 :                 dn = request->op.del.dn;
     329       51654 :                 break;
     330           2 :         case LDB_RENAME:
     331           2 :                 dn = request->op.rename.olddn;
     332           2 :                 break;
     333           0 :         default:
     334           0 :                 dn = NULL;
     335           0 :                 break;
     336             :         }
     337      437522 :         if (dn == NULL) {
     338           0 :                 return NULL;
     339             :         }
     340      437515 :         return ldb_dn_get_linearized(dn);
     341             : }
     342             : 
     343             : /*
     344             :  * @brief Get the ldb_message from a request.
     345             :  *
     346             :  * Get the ldb_message for the request, returns NULL is there is no
     347             :  * associated ldb_message
     348             :  *
     349             :  * @param The request
     350             :  *
     351             :  * @return the message associated with this request, or NULL
     352             :  */
     353     2718327 : const struct ldb_message *dsdb_audit_get_message(
     354             :         const struct ldb_request *request)
     355             : {
     356     2718327 :         switch (request->operation) {
     357     1072980 :         case LDB_ADD:
     358     1072980 :                 return request->op.add.message;
     359     1483522 :         case LDB_MODIFY:
     360     1483522 :                 return request->op.mod.message;
     361      161545 :         default:
     362      161545 :                 return NULL;
     363             :         }
     364             : }
     365             : 
     366             : /*
     367             :  * @brief get the secondary dn, i.e. the target dn for a rename.
     368             :  *
     369             :  * Get the secondary dn, i.e. the target for a rename. This is only applicable
     370             :  * got a rename operation, for the non rename operations this function returns
     371             :  * NULL.
     372             :  *
     373             :  * @param request the ldb_request.
     374             :  *
     375             :  * @return the secondary dn in a printable and linearized form.
     376             :  */
     377           6 : const char *dsdb_audit_get_secondary_dn(const struct ldb_request *request)
     378             : {
     379           6 :         switch (request->operation) {
     380           2 :         case LDB_RENAME:
     381           2 :                 return ldb_dn_get_linearized(request->op.rename.newdn);
     382           0 :         default:
     383           0 :                 return NULL;
     384             :         }
     385             : }
     386             : 
     387             : /*
     388             :  * @brief Map the request operation to a description.
     389             :  *
     390             :  * Get a description of the operation for logging
     391             :  *
     392             :  * @param request the ldb_request
     393             :  *
     394             :  * @return a string describing the operation, or "Unknown" if the operation
     395             :  *         is not known.
     396             :  */
     397      352229 : const char *dsdb_audit_get_operation_name(const struct ldb_request *request)
     398             : {
     399      352229 :         switch (request->operation) {
     400           0 :         case LDB_SEARCH:
     401           0 :                 return "Search";
     402      170032 :         case LDB_ADD:
     403      170032 :                 return "Add";
     404      130536 :         case LDB_MODIFY:
     405      130536 :                 return "Modify";
     406       51653 :         case LDB_DELETE:
     407       51653 :                 return "Delete";
     408           1 :         case LDB_RENAME:
     409           1 :                 return "Rename";
     410           1 :         case LDB_EXTENDED:
     411           1 :                 return "Extended";
     412           1 :         case LDB_REQ_REGISTER_CONTROL:
     413           1 :                 return "Register Control";
     414           1 :         case LDB_REQ_REGISTER_PARTITION:
     415           1 :                 return "Register Partition";
     416           1 :         default:
     417           1 :                 return "Unknown";
     418             :         }
     419             : }
     420             : 
     421             : /*
     422             :  * @brief get a description of a modify action for logging.
     423             :  *
     424             :  * Get a brief description of the modification action suitable for logging.
     425             :  *
     426             :  * @param flags the ldb_attributes flags.
     427             :  *
     428             :  * @return a brief description, or "unknown".
     429             :  */
     430      224645 : const char *dsdb_audit_get_modification_action(unsigned int flags)
     431             : {
     432      224645 :         switch (LDB_FLAG_MOD_TYPE(flags)) {
     433       68065 :         case LDB_FLAG_MOD_ADD:
     434       68065 :                 return "add";
     435       51770 :         case LDB_FLAG_MOD_DELETE:
     436       51770 :                 return "delete";
     437      104678 :         case LDB_FLAG_MOD_REPLACE:
     438      104678 :                 return "replace";
     439           7 :         default:
     440           7 :                 return "unknown";
     441             :         }
     442             : }
     443             : 
     444             : /*
     445             :  * @brief Add an ldb_value to a json object array
     446             :  *
     447             :  * Convert the current ldb_value to a JSON object and append it to array.
     448             :  * {
     449             :  *      "value":"xxxxxxxx",
     450             :  *      "base64":true
     451             :  *      "truncated":true
     452             :  * }
     453             :  *
     454             :  * value     is the JSON string representation of the ldb_val,
     455             :  *           will be null if the value is zero length. The value will be
     456             :  *           truncated if it is more than MAX_LENGTH bytes long. It will also
     457             :  *           be base64 encoded if it contains any non printable characters.
     458             :  *
     459             :  * base64    Indicates that the value is base64 encoded, will be absent if the
     460             :  *           value is not encoded.
     461             :  *
     462             :  * truncated Indicates that the length of the value exceeded MAX_LENGTH and was
     463             :  *           truncated.  Note that values are truncated and then base64 encoded.
     464             :  *           so an encoded value can be longer than MAX_LENGTH.
     465             :  *
     466             :  * @param array the JSON array to append the value to.
     467             :  * @param lv the ldb_val to convert and append to the array.
     468             :  *
     469             :  */
     470     2400348 : static int dsdb_audit_add_ldb_value(struct json_object *array,
     471             :                                     const struct ldb_val lv)
     472             : {
     473      117916 :         bool base64;
     474      117916 :         int len;
     475     2400348 :         struct json_object value = json_empty_object;
     476     2400348 :         int rc = 0;
     477             : 
     478     2400348 :         json_assert_is_array(array);
     479     2400348 :         if (json_is_invalid(array)) {
     480           0 :                 return -1;
     481             :         }
     482             : 
     483     2400347 :         if (lv.length == 0 || lv.data == NULL) {
     484           3 :                 rc = json_add_object(array, NULL, NULL);
     485           3 :                 if (rc != 0) {
     486           0 :                         goto failure;
     487             :                 }
     488           0 :                 return 0;
     489             :         }
     490             : 
     491     2400344 :         base64 = ldb_should_b64_encode(NULL, &lv);
     492     2400344 :         len = min(lv.length, MAX_LENGTH);
     493     2400344 :         value = json_new_object();
     494     2400344 :         if (json_is_invalid(&value)) {
     495           0 :                 goto failure;
     496             :         }
     497             : 
     498     2400344 :         if (lv.length > MAX_LENGTH) {
     499        5553 :                 rc = json_add_bool(&value, "truncated", true);
     500        5553 :                 if (rc != 0) {
     501           0 :                         goto failure;
     502             :                 }
     503             :         }
     504     2400344 :         if (base64) {
     505      376075 :                 TALLOC_CTX *ctx = talloc_new(NULL);
     506      394450 :                 char *encoded = ldb_base64_encode(
     507             :                         ctx,
     508      376075 :                         (char*) lv.data,
     509             :                         len);
     510             : 
     511      376075 :                 if (ctx == NULL) {
     512           0 :                         goto failure;
     513             :                 }
     514             : 
     515      376075 :                 rc = json_add_bool(&value, "base64", true);
     516      376075 :                 if (rc != 0) {
     517           0 :                         TALLOC_FREE(ctx);
     518           0 :                         goto failure;
     519             :                 }
     520      376075 :                 rc = json_add_string(&value, "value", encoded);
     521      376075 :                 if (rc != 0) {
     522           0 :                         TALLOC_FREE(ctx);
     523           0 :                         goto failure;
     524             :                 }
     525      376075 :                 TALLOC_FREE(ctx);
     526             :         } else {
     527     2024269 :                 rc = json_add_stringn(&value, "value", (char *)lv.data, len);
     528     2024269 :                 if (rc != 0) {
     529           0 :                         goto failure;
     530             :                 }
     531             :         }
     532             :         /*
     533             :          * As array is a JSON array the element name is NULL
     534             :          */
     535     2400344 :         rc = json_add_object(array, NULL, &value);
     536     2400344 :         if (rc != 0) {
     537           0 :                 goto failure;
     538             :         }
     539     2282432 :         return 0;
     540           0 : failure:
     541             :         /*
     542             :          * In the event of a failure value will not have been added to array
     543             :          * so it needs to be freed to prevent a leak.
     544             :          */
     545           0 :         json_free(&value);
     546           0 :         DBG_ERR("unable to add ldb value to JSON audit message\n");
     547           0 :         return -1;
     548             : }
     549             : 
     550             : /*
     551             :  * @brief Build a JSON object containing the attributes in an ldb_message.
     552             :  *
     553             :  * Build a JSON object containing all the attributes in an ldb_message.
     554             :  * The attributes are keyed by attribute name, the values of "secret attributes"
     555             :  * are suppressed.
     556             :  *
     557             :  * {
     558             :  *      "password":{
     559             :  *              "redacted":true,
     560             :  *              "action":"delete"
     561             :  *      },
     562             :  *      "name":{
     563             :  *              "values": [
     564             :  *                      {
     565             :  *                              "value":"xxxxxxxx",
     566             :  *                              "base64":true
     567             :  *                              "truncated":true
     568             :  *                      },
     569             :  *              ],
     570             :  *              "action":"add",
     571             :  *      }
     572             :  * }
     573             :  *
     574             :  * values is an array of json objects generated by add_ldb_value.
     575             :  * redacted indicates that the attribute is secret.
     576             :  * action is only set for modification operations.
     577             :  *
     578             :  * @param operation the ldb operation being performed
     579             :  * @param message the ldb_message to process.
     580             :  *
     581             :  * @return A populated json object.
     582             :  *
     583             :  */
     584      300569 : struct json_object dsdb_audit_attributes_json(
     585             :         enum ldb_request_type operation,
     586             :         const struct ldb_message* message)
     587             : {
     588             : 
     589        9643 :         unsigned int i, j;
     590      300569 :         struct json_object attributes = json_new_object();
     591             : 
     592      300569 :         if (json_is_invalid(&attributes)) {
     593           0 :                 goto failure;
     594             :         }
     595     2042565 :         for (i=0;i<message->num_elements;i++) {
     596     1741996 :                 struct json_object actions = json_empty_object;
     597     1741996 :                 struct json_object attribute = json_empty_object;
     598     1741996 :                 struct json_object action = json_empty_object;
     599     1741996 :                 const char *name = message->elements[i].name;
     600     1741996 :                 int rc = 0;
     601             : 
     602     1741996 :                 action = json_new_object();
     603     1741996 :                 if (json_is_invalid(&action)) {
     604           0 :                         goto failure;
     605             :                 }
     606             : 
     607             :                 /*
     608             :                  * If this is a modify operation tag the attribute with
     609             :                  * the modification action.
     610             :                  */
     611     1741996 :                 if (operation == LDB_MODIFY) {
     612      224637 :                         const char *act = NULL;
     613      224637 :                         const int flags =  message->elements[i].flags;
     614      224637 :                         act = dsdb_audit_get_modification_action(flags);
     615      224637 :                         rc = json_add_string(&action, "action", act);
     616      224637 :                         if (rc != 0) {
     617           0 :                                 json_free(&action);
     618           0 :                                 goto failure;
     619             :                         }
     620             :                 }
     621     1741996 :                 if (operation == LDB_ADD) {
     622     1517359 :                         rc = json_add_string(&action, "action", "add");
     623     1517359 :                         if (rc != 0) {
     624           0 :                                 json_free(&action);
     625           0 :                                 goto failure;
     626             :                         }
     627             :                 }
     628             : 
     629             :                 /*
     630             :                  * If the attribute is a secret attribute, tag it as redacted
     631             :                  * and don't include the values
     632             :                  */
     633     1741996 :                 if (dsdb_audit_redact_attribute(name)) {
     634       14993 :                         rc = json_add_bool(&action, "redacted", true);
     635       14993 :                         if (rc != 0) {
     636           0 :                                 json_free(&action);
     637           0 :                                 goto failure;
     638             :                         }
     639             :                 } else {
     640       82425 :                         struct json_object values;
     641             :                         /*
     642             :                          * Add the values for the action
     643             :                          */
     644     1727003 :                         values = json_new_array();
     645     1727003 :                         if (json_is_invalid(&values)) {
     646           0 :                                 json_free(&action);
     647           0 :                                 goto failure;
     648             :                         }
     649             : 
     650     4127341 :                         for (j=0;j<message->elements[i].num_values;j++) {
     651     2518244 :                                 rc = dsdb_audit_add_ldb_value(
     652     2400338 :                                     &values, message->elements[i].values[j]);
     653     2400338 :                                 if (rc != 0) {
     654           0 :                                         json_free(&values);
     655           0 :                                         json_free(&action);
     656           0 :                                         goto failure;
     657             :                                 }
     658             :                         }
     659     1727003 :                         rc = json_add_object(&action, "values", &values);
     660     1727003 :                         if (rc != 0) {
     661           0 :                                 json_free(&values);
     662           0 :                                 json_free(&action);
     663           0 :                                 goto failure;
     664             :                         }
     665             :                 }
     666     1741996 :                 attribute = json_get_object(&attributes, name);
     667     1741996 :                 if (json_is_invalid(&attribute)) {
     668           0 :                         json_free(&action);
     669           0 :                         goto failure;
     670             :                 }
     671     1741996 :                 actions = json_get_array(&attribute, "actions");
     672     1741996 :                 if (json_is_invalid(&actions)) {
     673           0 :                         json_free(&action);
     674           0 :                         goto failure;
     675             :                 }
     676     1741996 :                 rc = json_add_object(&actions, NULL, &action);
     677     1741996 :                 if (rc != 0) {
     678           0 :                         json_free(&action);
     679           0 :                         goto failure;
     680             :                 }
     681     1741996 :                 rc = json_add_object(&attribute, "actions", &actions);
     682     1741996 :                 if (rc != 0) {
     683           0 :                         json_free(&actions);
     684           0 :                         goto failure;
     685             :                 }
     686     1741996 :                 rc = json_add_object(&attributes, name, &attribute);
     687     1741996 :                 if (rc != 0) {
     688           0 :                         json_free(&attribute);
     689           0 :                         goto failure;
     690             :                 }
     691             :         }
     692      300569 :         return attributes;
     693           0 : failure:
     694           0 :         json_free(&attributes);
     695           0 :         DBG_ERR("Unable to create ldb attributes JSON audit message\n");
     696           0 :         return attributes;
     697             : }

Generated by: LCOV version 1.14