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

Generated by: LCOV version 1.14