From 372e27d49a5d0f846e5acfa9fec76dfadf76117c Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Wed, 21 Jan 2015 18:16:55 +0100 Subject: [PATCH 1/3] vfs_snapper: free dbus req messages in error paths Bug: https://bugzilla.samba.org/show_bug.cgi?id=11055 Signed-off-by: David Disseldorp Reviewed-by: Jeremy Allison (cherry picked from commit f72fa6390b73f47a57033282335786c24664a3f8) --- source3/modules/vfs_snapper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c index 12a3b9a..ed6e073 100644 --- a/source3/modules/vfs_snapper.c +++ b/source3/modules/vfs_snapper.c @@ -472,6 +472,7 @@ static NTSTATUS snapper_list_snaps_pack(char *snapper_conf, dbus_message_iter_init_append(msg, &args); if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &snapper_conf)) { + dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } @@ -690,16 +691,19 @@ static NTSTATUS snapper_list_snaps_at_time_pack(const char *snapper_conf, dbus_message_iter_init_append(msg, &args); if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &snapper_conf)) { + dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT64, &time_lower)) { + dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT64, &time_upper)) { + dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } -- 2.1.2 From ce6934ce448ea895dae0a384e970712d01a18e7b Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Wed, 21 Jan 2015 18:16:56 +0100 Subject: [PATCH 2/3] vfs_snapper: add DBus string encoding and decoding helpers Snapper uses the following mechanism for encoding and decoding strings used in DBus traffic: Characters above 127 (0x7F - ASCII DEL) must be encoded hexadecimal as "\x??". As a consequence "\" must be encoded as "\\". This change adds string encoding and decoding helpers to vfs_snapper. Bug: https://bugzilla.samba.org/show_bug.cgi?id=11055 Signed-off-by: David Disseldorp Reviewed-by: Jeremy Allison (cherry picked from commit 3d48fc96739bde631f8197aa313a81808481adf3) --- source3/modules/vfs_snapper.c | 124 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c index ed6e073..35f2a82 100644 --- a/source3/modules/vfs_snapper.c +++ b/source3/modules/vfs_snapper.c @@ -91,6 +91,130 @@ static NTSTATUS snapper_err_ntstatus_map(const char *snapper_err_str) return NT_STATUS_UNSUCCESSFUL; } +/* + * Strings are UTF-8. Other characters must be encoded hexadecimal as "\x??". + * As a consequence "\" must be encoded as "\\". + */ +static NTSTATUS snapper_dbus_str_encode(TALLOC_CTX *mem_ctx, const char *in_str, + char **_out_str) +{ + size_t in_len; + char *out_str; + int i; + int out_off; + int out_len; + + if (in_str == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + in_len = strlen(in_str); + + /* output can be max 4 times the length of @in_str, +1 for terminator */ + out_len = (in_len * 4) + 1; + + out_str = talloc_array(mem_ctx, char, out_len); + if (out_str == NULL) { + return NT_STATUS_NO_MEMORY; + } + + out_off = 0; + for (i = 0; i < in_len; i++) { + size_t pushed; + + if (in_str[i] == '\\') { + pushed = snprintf(out_str + out_off, out_len - out_off, + "\\\\"); + } else if ((unsigned char)in_str[i] > 127) { + pushed = snprintf(out_str + out_off, out_len - out_off, + "\\x%02x", (unsigned char)in_str[i]); + } else { + /* regular character */ + *(out_str + out_off) = in_str[i]; + pushed = sizeof(char); + } + if (pushed >= out_len - out_off) { + /* truncated, should never happen */ + talloc_free(out_str); + return NT_STATUS_INTERNAL_ERROR; + } + out_off += pushed; + } + + *(out_str + out_off) = '\0'; + *_out_str = out_str; + + return NT_STATUS_OK; +} + +static NTSTATUS snapper_dbus_str_decode(TALLOC_CTX *mem_ctx, const char *in_str, + char **_out_str) +{ + size_t in_len; + char *out_str; + int i; + int out_off; + int out_len; + + if (in_str == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + in_len = strlen(in_str); + + /* output cannot be larger than input, +1 for terminator */ + out_len = in_len + 1; + + out_str = talloc_array(mem_ctx, char, out_len); + if (out_str == NULL) { + return NT_STATUS_NO_MEMORY; + } + + out_off = 0; + for (i = 0; i < in_len; i++) { + int j; + char hex_buf[3]; + unsigned int non_ascii_byte; + + if (in_str[i] != '\\') { + out_str[out_off] = in_str[i]; + out_off++; + continue; + } + + i++; + if (in_str[i] == '\\') { + out_str[out_off] = '\\'; + out_off++; + continue; + } else if (in_str[i] != 'x') { + goto err_invalid_src_encoding; + } + + /* non-ASCII, encoded as two hex chars */ + for (j = 0; j < 2; j++) { + i++; + if ((in_str[i] == '\0') || !isxdigit(in_str[i])) { + goto err_invalid_src_encoding; + } + hex_buf[j] = in_str[i]; + } + hex_buf[2] = '\0'; + + sscanf(hex_buf, "%x", &non_ascii_byte); + out_str[out_off] = (unsigned char)non_ascii_byte; + out_off++; + } + + out_str[out_off] = '\0'; + *_out_str = out_str; + + return NT_STATUS_OK; +err_invalid_src_encoding: + DEBUG(0, ("invalid encoding %s\n", in_str)); + return NT_STATUS_INVALID_PARAMETER; +} + static DBusConnection *snapper_dbus_conn_create(void) { DBusError err; -- 2.1.2 From 5c590251b8efcc9ccc880099120622d146268742 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Wed, 21 Jan 2015 18:16:57 +0100 Subject: [PATCH 3/3] vfs_snapper: encode and decode Snapper DBus strings Snapper uses a special character encoding for strings used in DBus requests and responses. This change ensures that Samba packs and unpacks strings in the corresponding format, using the previously added encode/decode helper functions. Bug: https://bugzilla.samba.org/show_bug.cgi?id=11055 Signed-off-by: David Disseldorp Reviewed-by: Jeremy Allison (cherry picked from commit 32e9d7fa220d05f5ca95ed61cf6c7aa7d0261c03) --- source3/modules/vfs_snapper.c | 110 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c index 35f2a82..b5e7628 100644 --- a/source3/modules/vfs_snapper.c +++ b/source3/modules/vfs_snapper.c @@ -319,12 +319,15 @@ static NTSTATUS snapper_type_check_get(DBusMessageIter *iter, return NT_STATUS_OK; } -static NTSTATUS snapper_dict_unpack(DBusMessageIter *iter, +static NTSTATUS snapper_dict_unpack(TALLOC_CTX *mem_ctx, + DBusMessageIter *iter, struct snapper_dict *dict_out) { NTSTATUS status; DBusMessageIter dct_iter; + char *key_encoded; + char *val_encoded; status = snapper_type_check(iter, DBUS_TYPE_DICT_ENTRY); if (!NT_STATUS_IS_OK(status)) { @@ -333,15 +336,25 @@ static NTSTATUS snapper_dict_unpack(DBusMessageIter *iter, dbus_message_iter_recurse(iter, &dct_iter); status = snapper_type_check_get(&dct_iter, DBUS_TYPE_STRING, - &dict_out->key); + &key_encoded); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = snapper_dbus_str_decode(mem_ctx, key_encoded, &dict_out->key); if (!NT_STATUS_IS_OK(status)) { return status; } dbus_message_iter_next(&dct_iter); status = snapper_type_check_get(&dct_iter, DBUS_TYPE_STRING, - &dict_out->val); + &val_encoded); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(dict_out->key); + return status; + } + status = snapper_dbus_str_decode(mem_ctx, val_encoded, &dict_out->val); if (!NT_STATUS_IS_OK(status)) { + talloc_free(dict_out->key); return status; } @@ -384,7 +397,7 @@ static NTSTATUS snapper_dict_array_unpack(TALLOC_CTX *mem_ctx, if (dicts == NULL) abort(); - status = snapper_dict_unpack(&array_iter, + status = snapper_dict_unpack(mem_ctx, &array_iter, &dicts[num_dicts - 1]); if (!NT_STATUS_IS_OK(status)) { talloc_free(dicts); @@ -424,6 +437,8 @@ static NTSTATUS snapper_conf_unpack(TALLOC_CTX *mem_ctx, { NTSTATUS status; DBusMessageIter st_iter; + char *name_encoded; + char *mnt_encoded; status = snapper_type_check(iter, DBUS_TYPE_STRUCT); if (!NT_STATUS_IS_OK(status)) { @@ -432,15 +447,29 @@ static NTSTATUS snapper_conf_unpack(TALLOC_CTX *mem_ctx, dbus_message_iter_recurse(iter, &st_iter); status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING, - &conf_out->name); + &name_encoded); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = snapper_dbus_str_decode(mem_ctx, name_encoded, + &conf_out->name); if (!NT_STATUS_IS_OK(status)) { return status; } dbus_message_iter_next(&st_iter); status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING, - &conf_out->mnt); + &mnt_encoded); if (!NT_STATUS_IS_OK(status)) { + talloc_free(conf_out->name); + return status; + } + + status = snapper_dbus_str_decode(mem_ctx, mnt_encoded, + &conf_out->mnt); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(conf_out->name); return status; } @@ -448,8 +477,13 @@ static NTSTATUS snapper_conf_unpack(TALLOC_CTX *mem_ctx, status = snapper_dict_array_unpack(mem_ctx, &st_iter, &conf_out->num_attrs, &conf_out->attrs); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(conf_out->mnt); + talloc_free(conf_out->name); + return status; + } - return status; + return NT_STATUS_OK; } static struct snapper_conf *snapper_conf_array_base_find(int32_t num_confs, @@ -577,11 +611,14 @@ static NTSTATUS snapper_list_confs_unpack(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } -static NTSTATUS snapper_list_snaps_pack(char *snapper_conf, +static NTSTATUS snapper_list_snaps_pack(TALLOC_CTX *mem_ctx, + char *snapper_conf, DBusMessage **req_msg_out) { DBusMessage *msg; DBusMessageIter args; + char *conf_encoded; + NTSTATUS status; msg = dbus_message_new_method_call("org.opensuse.Snapper", /* target for the method call */ "/org/opensuse/Snapper", /* object to call on */ @@ -592,10 +629,17 @@ static NTSTATUS snapper_list_snaps_pack(char *snapper_conf, return NT_STATUS_NO_MEMORY; } + status = snapper_dbus_str_encode(mem_ctx, snapper_conf, &conf_encoded); + if (!NT_STATUS_IS_OK(status)) { + dbus_message_unref(msg); + return status; + } + /* append arguments */ dbus_message_iter_init_append(msg, &args); if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, - &snapper_conf)) { + &conf_encoded)) { + talloc_free(conf_encoded); dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } @@ -611,6 +655,8 @@ static NTSTATUS snapper_snap_struct_unpack(TALLOC_CTX *mem_ctx, { NTSTATUS status; DBusMessageIter st_iter; + char *desc_encoded; + char *cleanup_encoded; status = snapper_type_check(iter, DBUS_TYPE_STRUCT); if (!NT_STATUS_IS_OK(status)) { @@ -654,15 +700,29 @@ static NTSTATUS snapper_snap_struct_unpack(TALLOC_CTX *mem_ctx, dbus_message_iter_next(&st_iter); status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING, - &snap_out->desc); + &desc_encoded); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = snapper_dbus_str_decode(mem_ctx, desc_encoded, + &snap_out->desc); if (!NT_STATUS_IS_OK(status)) { return status; } dbus_message_iter_next(&st_iter); status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING, - &snap_out->cleanup); + &cleanup_encoded); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(snap_out->desc); + return status; + } + + status = snapper_dbus_str_decode(mem_ctx, cleanup_encoded, + &snap_out->cleanup); if (!NT_STATUS_IS_OK(status)) { + talloc_free(snap_out->desc); return status; } @@ -670,8 +730,13 @@ static NTSTATUS snapper_snap_struct_unpack(TALLOC_CTX *mem_ctx, status = snapper_dict_array_unpack(mem_ctx, &st_iter, &snap_out->num_user_data, &snap_out->user_data); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(snap_out->cleanup); + talloc_free(snap_out->desc); + return status; + } - return status; + return NT_STATUS_OK; } static void snapper_snap_array_print(int32_t num_snaps, @@ -795,13 +860,16 @@ static NTSTATUS snapper_list_snaps_unpack(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } -static NTSTATUS snapper_list_snaps_at_time_pack(const char *snapper_conf, +static NTSTATUS snapper_list_snaps_at_time_pack(TALLOC_CTX *mem_ctx, + const char *snapper_conf, time_t time_lower, time_t time_upper, DBusMessage **req_msg_out) { DBusMessage *msg; DBusMessageIter args; + char *conf_encoded; + NTSTATUS status; msg = dbus_message_new_method_call("org.opensuse.Snapper", "/org/opensuse/Snapper", @@ -812,21 +880,30 @@ static NTSTATUS snapper_list_snaps_at_time_pack(const char *snapper_conf, return NT_STATUS_NO_MEMORY; } + status = snapper_dbus_str_encode(mem_ctx, snapper_conf, &conf_encoded); + if (!NT_STATUS_IS_OK(status)) { + dbus_message_unref(msg); + return status; + } + dbus_message_iter_init_append(msg, &args); if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, - &snapper_conf)) { + &conf_encoded)) { + talloc_free(conf_encoded); dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT64, &time_lower)) { + talloc_free(conf_encoded); dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT64, &time_upper)) { + talloc_free(conf_encoded); dbus_message_unref(msg); return NT_STATUS_NO_MEMORY; } @@ -975,7 +1052,7 @@ static int snapper_get_shadow_copy_data(struct vfs_handle_struct *handle, goto err_conn_free; } - status = snapper_list_snaps_pack(conf_name, &req_msg); + status = snapper_list_snaps_pack(tmp_ctx, conf_name, &req_msg); if (!NT_STATUS_IS_OK(status)) { goto err_conn_free; } @@ -1141,7 +1218,8 @@ static NTSTATUS snapper_get_snap_at_time_call(TALLOC_CTX *mem_ctx, struct snapper_snap *snaps; char *snap_path; - status = snapper_list_snaps_at_time_pack(conf_name, + status = snapper_list_snaps_at_time_pack(mem_ctx, + conf_name, snaptime, snaptime, &req_msg); -- 2.1.2