From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- source3/utils/status_json.c | 1386 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1386 insertions(+) create mode 100644 source3/utils/status_json.c (limited to 'source3/utils/status_json.c') diff --git a/source3/utils/status_json.c b/source3/utils/status_json.c new file mode 100644 index 0000000..ee24a3b --- /dev/null +++ b/source3/utils/status_json.c @@ -0,0 +1,1386 @@ +/* + * Samba Unix/Linux SMB client library + * Json output + * Copyright (C) Jule Anger 2022 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "includes.h" +#include "smbprofile.h" +#include "lib/util/time_basic.h" +#include "conn_tdb.h" +#include "session.h" +#include "librpc/gen_ndr/smbXsrv.h" +#include "librpc/gen_ndr/open_files.h" +#include "status_json.h" +#include "../libcli/security/security.h" +#include "status.h" +#include "lib/util/server_id.h" +#include "lib/util/string_wrappers.h" + +#include +#include "audit_logging.h" /* various JSON helpers */ +#include "auth/common_auth.h" + +int add_general_information_to_json(struct traverse_state *state) +{ + int result; + + result = json_add_timestamp(&state->root_json); + if (result < 0) { + return -1; + } + + result = json_add_string(&state->root_json, "version", samba_version_string()); + if (result < 0) { + return -1; + } + + result = json_add_string(&state->root_json, "smb_conf", get_dyn_CONFIGFILE()); + if (result < 0) { + return -1; + } + + return 0; +} + +static int add_server_id_to_json(struct json_object *parent_json, + const struct server_id server_id) +{ + struct json_object sub_json; + char *pid_str = NULL; + char *task_id_str = NULL; + char *vnn_str = NULL; + char *unique_id_str = NULL; + int result; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + + pid_str = talloc_asprintf( + tmp_ctx, "%lu", (unsigned long)server_id.pid); + result = json_add_string(&sub_json, "pid", pid_str); + if (result < 0) { + goto failure; + } + task_id_str = talloc_asprintf(tmp_ctx, "%u", server_id.task_id); + result = json_add_string(&sub_json, "task_id", task_id_str); + if (result < 0) { + goto failure; + } + vnn_str = talloc_asprintf(tmp_ctx, "%u", server_id.vnn); + result = json_add_string(&sub_json, "vnn", vnn_str); + if (result < 0) { + goto failure; + } + unique_id_str = talloc_asprintf( + tmp_ctx, "%"PRIu64, server_id.unique_id); + result = json_add_string(&sub_json, "unique_id", unique_id_str); + if (result < 0) { + goto failure; + } + + result = json_add_object(parent_json, "server_id", &sub_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&sub_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +struct mask2txt { + uint32_t mask; + const char *string_desc; +}; + +/* + * Convert a mask of some sort (access, oplock, leases), + * to key/value pairs in a JSON object. + */ +static int map_mask_to_json(struct json_object *root_json, + uint32_t tomap, + const struct mask2txt *table) +{ + const struct mask2txt *a = NULL; + int result = 0; + + for (a = table; a->string_desc != 0; a++) { + result = json_add_bool(root_json, a->string_desc, + (tomap & a->mask) ? true : false); + + if (result < 0) { + return result; + } + tomap &= ~a->mask; + } + + /* Assert we know about all requested "tomap" values */ + SMB_ASSERT(tomap == 0); + + return 0; +} + +static const struct mask2txt access_mask[] = { + {FILE_READ_DATA, "READ_DATA"}, + {FILE_WRITE_DATA, "WRITE_DATA"}, + {FILE_APPEND_DATA, "APPEND_DATA"}, + {FILE_READ_EA, "READ_EA"}, + {FILE_WRITE_EA, "WRITE_EA"}, + {FILE_EXECUTE, "EXECUTE"}, + {FILE_READ_ATTRIBUTES, "READ_ATTRIBUTES"}, + {FILE_WRITE_ATTRIBUTES, "WRITE_ATTRIBUTES"}, + {FILE_DELETE_CHILD, "DELETE_CHILD"}, + {SEC_STD_DELETE, "DELETE"}, + {SEC_STD_READ_CONTROL, "READ_CONTROL"}, + {SEC_STD_WRITE_DAC, "WRITE_DAC"}, + {SEC_STD_SYNCHRONIZE, "SYNCHRONIZE"}, + {SEC_FLAG_SYSTEM_SECURITY, "ACCESS_SYSTEM_SECURITY"}, + {0, NULL} +}; + +static const struct mask2txt oplock_mask[] = { + {EXCLUSIVE_OPLOCK, "EXCLUSIVE"}, + {BATCH_OPLOCK, "BATCH"}, + {LEVEL_II_OPLOCK, "LEVEL_II"}, + {LEASE_OPLOCK, "LEASE"}, + {0, NULL} +}; + +static const struct mask2txt sharemode_mask[] = { + {FILE_SHARE_READ, "READ"}, + {FILE_SHARE_WRITE, "WRITE"}, + {FILE_SHARE_DELETE, "DELETE"}, + {0, NULL} +}; + +static const struct mask2txt lease_mask[] = { + {SMB2_LEASE_READ, "READ"}, + {SMB2_LEASE_WRITE, "WRITE"}, + {SMB2_LEASE_HANDLE, "HANDLE"}, + {0, NULL} +}; + +int add_profile_item_to_json(struct traverse_state *state, + const char *section, + const char *subsection, + const char *key, + uintmax_t value) +{ + struct json_object section_json = { + .valid = false, + }; + struct json_object subsection_json = { + .valid = false, + }; + int result = 0; + + section_json = json_get_object(&state->root_json, section); + if (json_is_invalid(§ion_json)) { + goto failure; + } + subsection_json = json_get_object(§ion_json, subsection); + if (json_is_invalid(&subsection_json)) { + goto failure; + } + + result = json_add_int(&subsection_json, key, value); + if (result < 0) { + goto failure; + } + + result = json_update_object(§ion_json, subsection, &subsection_json); + if (result < 0) { + goto failure; + } + result = json_update_object(&state->root_json, section, §ion_json); + if (result < 0) { + goto failure; + } + + return 0; +failure: + json_free(§ion_json); + json_free(&subsection_json); + return -1; +} + +int add_section_to_json(struct traverse_state *state, + const char *key) +{ + struct json_object empty_json; + int result; + + empty_json = json_new_object(); + if (json_is_invalid(&empty_json)) { + return -1; + } + + result = json_add_object(&state->root_json, key, &empty_json); + if (result < 0) { + return -1; + } + + return result; +} + +static int add_crypto_to_json(struct json_object *parent_json, + const char *key, + const char *cipher, + enum crypto_degree degree) +{ + struct json_object sub_json; + const char *degree_str; + int result; + + if (degree == CRYPTO_DEGREE_NONE) { + degree_str = "none"; + } else if (degree == CRYPTO_DEGREE_PARTIAL) { + degree_str = "partial"; + } else { + degree_str = "full"; + } + + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + + result = json_add_string(&sub_json, "cipher", cipher); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "degree", degree_str); + if (result < 0) { + goto failure; + } + result = json_add_object(parent_json, key, &sub_json); + if (result < 0) { + goto failure; + } + + return 0; +failure: + json_free(&sub_json); + return -1; +} + +static int add_channel_to_json(struct json_object *parent_json, + const struct smbXsrv_channel_global0 *channel) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct json_object sub_json; + char *id_str = NULL; + struct timeval tv; + struct timeval_buf tv_buf; + char *time_str = NULL; + int result; + + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + + id_str = talloc_asprintf(frame, "%"PRIu64"", channel->channel_id); + if (id_str == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "channel_id", id_str); + if (result < 0) { + goto failure; + } + nttime_to_timeval(&tv, channel->creation_time); + time_str = timeval_str_buf(&tv, true, true, &tv_buf); + if (time_str == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "creation_time", time_str); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "local_address", channel->local_address); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "remote_address", channel->remote_address); + if (result < 0) { + goto failure; + } + + result = json_add_object(parent_json, id_str, &sub_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(frame); + return 0; +failure: + json_free(&sub_json); + TALLOC_FREE(frame); + return -1; +} + +static int add_channels_to_json(struct json_object *parent_json, + const struct smbXsrv_session_global0 *global) +{ + struct json_object sub_json; + uint32_t i; + int result; + + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + + for (i = 0; i < global->num_channels; i++) { + const struct smbXsrv_channel_global0 *c = &global->channels[i]; + + result = add_channel_to_json(&sub_json, c); + if (result < 0) { + goto failure; + } + } + + result = json_add_object(parent_json, "channels", &sub_json); + if (result < 0) { + goto failure; + } + + return 0; +failure: + json_free(&sub_json); + return -1; +} + +int traverse_connections_json(struct traverse_state *state, + const struct connections_data *crec, + const char *encryption_cipher, + enum crypto_degree encryption_degree, + const char *signing_cipher, + enum crypto_degree signing_degree) +{ + struct json_object sub_json; + struct json_object connections_json; + struct timeval tv; + struct timeval_buf tv_buf; + char *time = NULL; + int result = 0; + char *sess_id_str = NULL; + char *tcon_id_str = NULL; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + connections_json = json_get_object(&state->root_json, "tcons"); + if (json_is_invalid(&connections_json)) { + goto failure; + } + + result = json_add_string(&sub_json, "service", crec->servicename); + if (result < 0) { + goto failure; + } + result = add_server_id_to_json(&sub_json, crec->pid); + if (result < 0) { + goto failure; + } + tcon_id_str = talloc_asprintf(tmp_ctx, "%u", crec->cnum); + if (tcon_id_str == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "tcon_id", tcon_id_str); + if (result < 0) { + goto failure; + } + sess_id_str = talloc_asprintf(tmp_ctx, "%u", crec->sess_id); + if (sess_id_str == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "session_id", sess_id_str); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "machine", crec->machine); + if (result < 0) { + goto failure; + } + nttime_to_timeval(&tv, crec->start); + time = timeval_str_buf(&tv, true, true, &tv_buf); + if (time == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "connected_at", time); + if (result < 0) { + goto failure; + } + result = add_crypto_to_json(&sub_json, "encryption", + encryption_cipher, encryption_degree); + if (result < 0) { + goto failure; + } + result = add_crypto_to_json(&sub_json, "signing", + signing_cipher, signing_degree); + if (result < 0) { + goto failure; + } + + result = json_add_object(&connections_json, tcon_id_str, &sub_json); + if (result < 0) { + goto failure; + } + + result = json_update_object(&state->root_json, "tcons", &connections_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&sub_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +int traverse_sessionid_json(struct traverse_state *state, + struct sessionid *session, + char *uid_str, + char *gid_str, + const char *encryption_cipher, + enum crypto_degree encryption_degree, + const char *signing_cipher, + enum crypto_degree signing_degree, + const char *connection_dialect) +{ + struct json_object sub_json; + struct json_object session_json; + int result = 0; + char *id_str = NULL; + struct timeval tv; + struct timeval_buf tv_buf; + char *time_str = NULL; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + + session_json = json_get_object(&state->root_json, "sessions"); + if (json_is_invalid(&session_json)) { + goto failure; + } + + id_str = talloc_asprintf(tmp_ctx, "%u", session->id_num); + result = json_add_string(&sub_json, "session_id", id_str); + if (result < 0) { + goto failure; + } + result = add_server_id_to_json(&sub_json, session->pid); + if (result < 0) { + goto failure; + } + result = json_add_int(&sub_json, "uid", session->uid); + if (result < 0) { + goto failure; + } + result = json_add_int(&sub_json, "gid", session->gid); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "username", uid_str); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "groupname", gid_str); + if (result < 0) { + goto failure; + } + + nttime_to_timeval(&tv, session->global->creation_time); + time_str = timeval_str_buf(&tv, true, true, &tv_buf); + if (time_str == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "creation_time", time_str); + if (result < 0) { + goto failure; + } + + nttime_to_timeval(&tv, session->global->expiration_time); + time_str = timeval_str_buf(&tv, true, true, &tv_buf); + if (time_str == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "expiration_time", time_str); + if (result < 0) { + goto failure; + } + + nttime_to_timeval(&tv, session->global->auth_time); + time_str = timeval_str_buf(&tv, true, true, &tv_buf); + if (time_str == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "auth_time", time_str); + if (result < 0) { + goto failure; + } + + result = json_add_string(&sub_json, "remote_machine", session->remote_machine); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "hostname", session->hostname); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "session_dialect", connection_dialect); + if (result < 0) { + goto failure; + } + result = json_add_guid(&sub_json, + "client_guid", + &session->global->client_guid); + if (result < 0) { + goto failure; + } + result = add_crypto_to_json(&sub_json, "encryption", + encryption_cipher, encryption_degree); + if (result < 0) { + goto failure; + } + result = add_crypto_to_json(&sub_json, "signing", + signing_cipher, signing_degree); + if (result < 0) { + goto failure; + } + + result = add_channels_to_json(&sub_json, session->global); + if (result < 0) { + goto failure; + } + + result = json_add_object(&session_json, id_str, &sub_json); + if (result < 0) { + goto failure; + } + + result = json_update_object(&state->root_json, "sessions", &session_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&sub_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_access_mode_to_json(struct json_object *parent_json, + int access_int) +{ + struct json_object access_json; + char *access_hex = NULL; + const char *access_str = NULL; + int result; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + access_json = json_new_object(); + if (json_is_invalid(&access_json)) { + goto failure; + } + + access_hex = talloc_asprintf(tmp_ctx, "0x%08x", access_int); + result = json_add_string(&access_json, "hex", access_hex); + if (result < 0) { + goto failure; + } + result = map_mask_to_json(&access_json, access_int, access_mask); + if (result < 0) { + goto failure; + } + + access_str = talloc_asprintf(tmp_ctx, "%s%s", + (access_int & FILE_READ_DATA)?"R":"", + (access_int & (FILE_WRITE_DATA|FILE_APPEND_DATA))?"W":""); + result = json_add_string(&access_json, "text", access_str); + if (result < 0) { + goto failure; + } + + result = json_add_object(parent_json, "access_mask", &access_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&access_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_caching_to_json(struct json_object *parent_json, + int op_type, + int lease_type) +{ + struct json_object caching_json; + char *hex = NULL; + char *caching_text = NULL; + int caching_type = 0; + int result; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + caching_json = json_new_object(); + if (json_is_invalid(&caching_json)) { + goto failure; + } + + if (op_type & LEASE_OPLOCK) { + caching_type = lease_type; + } else { + if (op_type & LEVEL_II_OPLOCK) { + caching_type = SMB2_LEASE_READ; + } else if (op_type & EXCLUSIVE_OPLOCK) { + caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE; + } else if (op_type & BATCH_OPLOCK) { + caching_type = SMB2_LEASE_READ + SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE; + } + } + result = map_mask_to_json(&caching_json, caching_type, lease_mask); + if (result < 0) { + goto failure; + } + + hex = talloc_asprintf(tmp_ctx, "0x%08x", caching_type); + if (hex == NULL) { + goto failure; + } + result = json_add_string(&caching_json, "hex", hex); + if (result < 0) { + goto failure; + } + + caching_text = talloc_asprintf(tmp_ctx, "%s%s%s", + (caching_type & SMB2_LEASE_READ)?"R":"", + (caching_type & SMB2_LEASE_WRITE)?"W":"", + (caching_type & SMB2_LEASE_HANDLE)?"H":""); + if (caching_text == NULL) { + return -1; + } + + result = json_add_string(&caching_json, "text", caching_text); + if (result < 0) { + goto failure; + } + + result = json_add_object(parent_json, "caching", &caching_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&caching_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_oplock_to_json(struct json_object *parent_json, + uint16_t op_type, + const char *op_str) +{ + struct json_object oplock_json; + int result; + + oplock_json = json_new_object(); + if (json_is_invalid(&oplock_json)) { + goto failure; + } + + if (op_type != 0) { + result = map_mask_to_json(&oplock_json, op_type, oplock_mask); + if (result < 0) { + goto failure; + } + result = json_add_string(&oplock_json, "text", op_str); + if (result < 0) { + goto failure; + } + } + + result = json_add_object(parent_json, "oplock", &oplock_json); + if (result < 0) { + goto failure; + } + + return 0; +failure: + json_free(&oplock_json); + return -1; +} + +static int lease_key_to_str(struct smb2_lease_key lease_key, + char *lease_str) +{ + uint8_t _buf[16] = {0}; + DATA_BLOB blob = data_blob_const(_buf, sizeof(_buf)); + struct GUID guid; + NTSTATUS status; + char *tmp = NULL; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + PUSH_LE_U64(_buf, 0, lease_key.data[0]); + PUSH_LE_U64(_buf, 8, lease_key.data[1]); + + status = GUID_from_ndr_blob(&blob, &guid); + if (!NT_STATUS_IS_OK(status)) { + goto failure; + } + tmp = GUID_string(tmp_ctx, &guid); + if (tmp == NULL) { + goto failure; + } + fstrcpy(lease_str, tmp); + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_lease_to_json(struct json_object *parent_json, + int lease_type, + struct smb2_lease_key lease_key, + bool add_lease) +{ + struct json_object lease_json; + char *lease_hex = NULL; + char *lease_text = NULL; + fstring lease_key_str; + int result; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + lease_json = json_new_object(); + if (json_is_invalid(&lease_json)) { + goto failure; + } + + + if (add_lease) { + result = lease_key_to_str(lease_key, lease_key_str); + if (result < 0) { + goto failure; + } + result = json_add_string(&lease_json, "lease_key", lease_key_str); + if (result < 0) { + goto failure; + } + lease_hex = talloc_asprintf(tmp_ctx, "0x%08x", lease_type); + result = json_add_string(&lease_json, "hex", lease_hex); + if (result < 0) { + goto failure; + } + if (lease_type > (SMB2_LEASE_WRITE + SMB2_LEASE_HANDLE + SMB2_LEASE_READ)) { + result = json_add_bool(&lease_json, "UNKNOWN", true); + if (result < 0) { + goto failure; + } + } else { + result = map_mask_to_json(&lease_json, lease_type, lease_mask); + if (result < 0) { + goto failure; + } + } + lease_text = talloc_asprintf(tmp_ctx, "%s%s%s", + (lease_type & SMB2_LEASE_READ)?"R":"", + (lease_type & SMB2_LEASE_WRITE)?"W":"", + (lease_type & SMB2_LEASE_HANDLE)?"H":""); + + result = json_add_string(&lease_json, "text", lease_text); + if (result < 0) { + goto failure; + } + } + + result = json_add_object(parent_json, "lease", &lease_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&lease_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_sharemode_to_json(struct json_object *parent_json, + int sharemode) +{ + struct json_object sharemode_json; + char *hex = NULL; + char *text = NULL; + int result; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + sharemode_json = json_new_object(); + if (json_is_invalid(&sharemode_json)) { + goto failure; + } + + hex = talloc_asprintf(tmp_ctx, "0x%08x", sharemode); + if (hex == NULL) { + goto failure; + } + result = json_add_string(&sharemode_json, "hex", hex); + if (result < 0) { + goto failure; + } + result = map_mask_to_json(&sharemode_json, sharemode, sharemode_mask); + if (result < 0) { + goto failure; + } + + text = talloc_asprintf(tmp_ctx, "%s%s%s", + (sharemode & FILE_SHARE_READ)?"R":"", + (sharemode & FILE_SHARE_WRITE)?"W":"", + (sharemode & FILE_SHARE_DELETE)?"D":""); + if (text == NULL) { + goto failure; + } + result = json_add_string(&sharemode_json, "text", text); + if (result < 0) { + goto failure; + } + + result = json_add_object(parent_json, "sharemode", &sharemode_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&sharemode_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_open_to_json(struct json_object *parent_json, + const struct share_mode_entry *e, + bool resolve_uids, + const char *op_str, + uint32_t lease_type, + const char *uid_str) +{ + struct json_object sub_json = { + .valid = false, + }; + struct json_object opens_json = { + .valid = false, + }; + struct timeval_buf tv_buf; + int result = 0; + char *timestr; + bool add_lease = false; + char *key = NULL; + char *share_file_id = NULL; + char *pid = NULL; + struct server_id_buf tmp; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + opens_json = json_get_object(parent_json, "opens"); + if (json_is_invalid(&opens_json)) { + goto failure; + } + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + + + result = add_server_id_to_json(&sub_json, e->pid); + if (result < 0) { + goto failure; + } + if (resolve_uids) { + result = json_add_string(&sub_json, "username", uid_str); + if (result < 0) { + goto failure; + } + } + result = json_add_int(&sub_json, "uid", e->uid); + if (result < 0) { + goto failure; + } + share_file_id = talloc_asprintf(tmp_ctx, "%"PRIu64, e->share_file_id); + result = json_add_string(&sub_json, "share_file_id", share_file_id); + if (result < 0) { + goto failure; + } + result = add_sharemode_to_json(&sub_json, e->share_access); + if (result < 0) { + goto failure; + } + result = add_access_mode_to_json(&sub_json, e->access_mask); + if (result < 0) { + goto failure; + } + result = add_caching_to_json(&sub_json, e->op_type, lease_type); + if (result < 0) { + goto failure; + } + result = add_oplock_to_json(&sub_json, e->op_type, op_str); + if (result < 0) { + goto failure; + } + add_lease = e->op_type & LEASE_OPLOCK; + result = add_lease_to_json(&sub_json, lease_type, e->lease_key, add_lease); + if (result < 0) { + goto failure; + } + + timestr = timeval_str_buf(&e->time, true, true, &tv_buf); + if (timestr == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "opened_at", timestr); + if (result < 0) { + goto failure; + } + + pid = server_id_str_buf(e->pid, &tmp); + key = talloc_asprintf(tmp_ctx, "%s/%"PRIu64, pid, e->share_file_id); + result = json_add_object(&opens_json, key, &sub_json); + if (result < 0) { + goto failure; + } + result = json_update_object(parent_json, "opens", &opens_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&opens_json); + json_free(&sub_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_fileid_to_json(struct json_object *parent_json, + struct file_id fid) +{ + struct json_object fid_json; + int result; + + fid_json = json_new_object(); + if (json_is_invalid(&fid_json)) { + goto failure; + } + + result = json_add_int(&fid_json, "devid", fid.devid); + if (result < 0) { + goto failure; + } + result = json_add_int(&fid_json, "inode", fid.inode); + if (result < 0) { + goto failure; + } + result = json_add_int(&fid_json, "extid", fid.extid); + if (result < 0) { + goto failure; + } + + result = json_add_object(parent_json, "fileid", &fid_json); + if (result < 0) { + goto failure; + } + + return 0; +failure: + json_free(&fid_json); + return -1; +} + +int print_share_mode_json(struct traverse_state *state, + const struct share_mode_data *d, + const struct share_mode_entry *e, + struct file_id fid, + const char *uid_str, + const char *op_str, + uint32_t lease_type, + const char *filename) +{ + struct json_object locks_json = { + .valid = false, + }; + struct json_object file_json = { + .valid = false, + }; + char *key = NULL; + int result = 0; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + if (d->servicepath[strlen(d->servicepath)-1] == '/') { + key = talloc_asprintf(tmp_ctx, "%s%s", d->servicepath, filename); + } else { + key = talloc_asprintf(tmp_ctx, "%s/%s", d->servicepath, filename); + } + + locks_json = json_get_object(&state->root_json, "open_files"); + if (json_is_invalid(&locks_json)) { + goto failure; + } + file_json = json_get_object(&locks_json, key); + if (json_is_invalid(&file_json)) { + goto failure; + } + + result = json_add_string(&file_json, "service_path", d->servicepath); + if (result < 0) { + goto failure; + } + result = json_add_string(&file_json, "filename", filename); + if (result < 0) { + goto failure; + } + result = add_fileid_to_json(&file_json, fid); + if (result < 0) { + goto failure; + } + result = json_add_int(&file_json, "num_pending_deletes", d->num_delete_tokens); + if (result < 0) { + goto failure; + } + + result = add_open_to_json(&file_json, + e, + state->resolve_uids, + op_str, + lease_type, + uid_str); + if (result < 0) { + goto failure; + } + + result = json_update_object(&locks_json, key, &file_json); + if (result < 0) { + goto failure; + } + result = json_update_object(&state->root_json, "open_files", &locks_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&file_json); + json_free(&locks_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +static int add_lock_to_json(struct json_object *parent_json, + struct server_id server_id, + const char *type, + enum brl_flavour flavour, + intmax_t start, + intmax_t size) +{ + struct json_object sub_json = { + .valid = false, + }; + struct json_object locks_json = { + .valid = false, + }; + const char *flavour_str; + int result = 0; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + locks_json = json_get_array(parent_json, "locks"); + if (json_is_invalid(&locks_json)) { + goto failure; + } + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + goto failure; + } + + result = add_server_id_to_json(&sub_json, server_id); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "type", type); + if (result < 0) { + goto failure; + } + flavour_str = talloc_asprintf(tmp_ctx, "%s%s", + (flavour == WINDOWS_LOCK)?"Windows":"", + (flavour == POSIX_LOCK)?"Posix":""); + result = json_add_string(&sub_json, "flavour", flavour_str); + if (result < 0) { + goto failure; + } + result = json_add_int(&sub_json, "start", start); + if (result < 0) { + goto failure; + } + result = json_add_int(&sub_json, "size", size); + if (result < 0) { + goto failure; + } + + result = json_add_object(&locks_json, NULL, &sub_json); + if (result < 0) { + goto failure; + } + result = json_update_object(parent_json, "locks", &locks_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&locks_json); + json_free(&sub_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +int print_brl_json(struct traverse_state *state, + const struct server_id server_id, + struct file_id fid, + const char *type, + enum brl_flavour flavour, + intmax_t start, + intmax_t size, + const char *sharepath, + const char *filename) +{ + struct json_object file_json = { + .valid = false, + }; + struct json_object brl_json = { + .valid = false, + }; + int result = 0; + char *key; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + if (sharepath[strlen(sharepath)-1] == '/') { + key = talloc_asprintf(tmp_ctx, "%s%s", sharepath, filename); + } else { + key = talloc_asprintf(tmp_ctx, "%s/%s", sharepath, filename); + } + if (key == NULL) { + goto failure; + } + + brl_json = json_get_object(&state->root_json, "byte_range_locks"); + if (json_is_invalid(&brl_json)) { + goto failure; + } + file_json = json_get_object(&brl_json, key); + if (json_is_invalid(&file_json)) { + goto failure; + } + + result = add_fileid_to_json(&file_json, fid); + if (result < 0) { + goto failure; + } + result = json_add_string(&file_json, "file_name", filename); + if (result < 0) { + goto failure; + } + result = json_add_string(&file_json, "share_path", sharepath); + if (result < 0) { + goto failure; + } + result = add_server_id_to_json(&file_json, server_id); + if (result < 0) { + goto failure; + } + result = add_lock_to_json(&file_json, server_id, type, flavour, start, size); + if (result < 0) { + goto failure; + } + + result = json_add_object(&brl_json, key, &file_json); + if (result < 0) { + goto failure; + } + result = json_update_object(&state->root_json, "byte_range_locks", &brl_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return 0; +failure: + json_free(&file_json); + json_free(&brl_json); + TALLOC_FREE(tmp_ctx); + return -1; +} + +bool print_notify_rec_json(struct traverse_state *state, + const struct notify_instance *instance, + const struct server_id server_id, + const char *path) +{ + struct json_object sub_json; + struct json_object notify_json; + char *filter = NULL; + char *subdir_filter = NULL; + struct timeval_buf tv_buf; + struct timeval val; + char *time = NULL; + char *pid = NULL; + struct server_id_buf tmp; + int result = 0; + + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return -1; + } + + sub_json = json_new_object(); + if (json_is_invalid(&sub_json)) { + return false; + } + notify_json = json_get_object(&state->root_json, "notifies"); + if (json_is_invalid(¬ify_json)) { + goto failure; + } + + result = add_server_id_to_json(&sub_json, server_id); + if (result < 0) { + goto failure; + } + result = json_add_string(&sub_json, "path", path); + if (result < 0) { + goto failure; + } + filter = talloc_asprintf(tmp_ctx, "%u", instance->filter); + if (filter == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "filter", filter); + if (result < 0) { + goto failure; + } + subdir_filter = talloc_asprintf(tmp_ctx, "%u", instance->subdir_filter); + if (subdir_filter == NULL) { + goto failure; + } + result = json_add_string(&sub_json, "subdir_filter", subdir_filter); + if (result < 0) { + goto failure; + } + val = convert_timespec_to_timeval(instance->creation_time); + time = timeval_str_buf(&val, true, true, &tv_buf); + result = json_add_string(&sub_json, "creation_time", time); + if (result < 0) { + goto failure; + } + + pid = server_id_str_buf(server_id, &tmp); + result = json_add_object(¬ify_json, pid, &sub_json); + if (result < 0) { + goto failure; + } + + result = json_update_object(&state->root_json, "notifies", ¬ify_json); + if (result < 0) { + goto failure; + } + + TALLOC_FREE(tmp_ctx); + return true; +failure: + json_free(&sub_json); + TALLOC_FREE(tmp_ctx); + return false; +} -- cgit v1.2.3