From b43f4602b81841f978b0228279788b4842195315 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Aug 2016 16:58:39 -0700 Subject: [PATCH 1/5] s3: libsmb: Correctly align create contexts in a create call. SMB2 shadow copy requests are the first time we've used create contexts in anger in this codepath. This took me longer than I'd like to admit to find :-). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166 Signed-off-by: Jeremy Allison Reviewed-by: Uri Simchoni (cherry picked from commit f8caadfc78a15fa3aefc9ef6249195767c47aa8f) --- libcli/smb/smb2cli_create.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c index 0db546c..778b501 100644 --- a/libcli/smb/smb2cli_create.c +++ b/libcli/smb/smb2cli_create.c @@ -113,6 +113,7 @@ struct tevent_req *smb2cli_create_send( blobs_offset = ((blobs_offset + 3) & ~3); if (blob.length > 0) { + blobs_offset = ((blobs_offset + 7) & ~7); SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56); SIVAL(fixed, 52, blob.length); } -- 2.8.0.rc3.226.g39d4020 From 6e3464ab52bc36ef16ca1d804ba260f4248272a0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 18 Aug 2016 17:15:01 -0700 Subject: [PATCH 2/5] s3: libsmb: Add return args to clistr_is_previous_version_path(). Not yet used - we will use these to construct the SMB2 TWrp blob. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166 Signed-off-by: Jeremy Allison Reviewed-by: Uri Simchoni (cherry picked from commit 14fd6dca4ef33ee85a2f8578f1ad608d6056da1f) --- source3/libsmb/clifile.c | 28 ++++++++++++++-------------- source3/libsmb/clilist.c | 4 ++-- source3/libsmb/clistr.c | 17 ++++++++++++++++- source3/libsmb/proto.h | 5 ++++- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 0964b3a..75ec3a2 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -197,7 +197,7 @@ struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(path) && + if (clistr_is_previous_version_path(path, NULL, NULL, NULL) && !INFO_LEVEL_IS_UNIX(level)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -1155,7 +1155,7 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname_src)) { + if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -1290,7 +1290,7 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname_src)) { + if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -1495,7 +1495,7 @@ struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname)) { + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -1610,7 +1610,7 @@ struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(dname)) { + if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -1725,7 +1725,7 @@ struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(dname)) { + if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -1978,7 +1978,7 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx, fname, strlen(fname)+1, &converted_len); - if (clistr_is_previous_version_path(fname)) { + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -2282,7 +2282,7 @@ struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname)) { + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -2508,7 +2508,7 @@ struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname)) { + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -3765,7 +3765,7 @@ struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname)) { + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -4057,7 +4057,7 @@ struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname)) { + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -4178,7 +4178,7 @@ struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname)) { + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -4489,7 +4489,7 @@ struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(path)) { + if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -5651,7 +5651,7 @@ struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(fname) && + if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) && !INFO_LEVEL_IS_UNIX(level)) { additional_flags2 = FLAGS2_REPARSE_PATH; } diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index d6116f0..41f5851 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -600,7 +600,7 @@ static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (clistr_is_previous_version_path(state->mask)) { + if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } @@ -792,7 +792,7 @@ static void cli_list_trans_done(struct tevent_req *subreq) } param_len = talloc_get_size(state->param); - if (clistr_is_previous_version_path(state->mask)) { + if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) { additional_flags2 = FLAGS2_REPARSE_PATH; } diff --git a/source3/libsmb/clistr.c b/source3/libsmb/clistr.c index c3611be..154b9a1 100644 --- a/source3/libsmb/clistr.c +++ b/source3/libsmb/clistr.c @@ -38,7 +38,10 @@ size_t clistr_pull_talloc(TALLOC_CTX *ctx, flags); } -bool clistr_is_previous_version_path(const char *path) +bool clistr_is_previous_version_path(const char *path, + const char **startp, + const char **endp, + time_t *ptime) { char *q; time_t timestamp; @@ -63,5 +66,17 @@ bool clistr_is_previous_version_path(const char *path) if (q[0] != '\0' && q[0] != '\\') { return false; } + if (startp) { + *startp = p; + } + if (endp) { + if (q[0] == '\\') { + q++; + } + *endp = q; + } + if (ptime) { + *ptime = timestamp; + } return true; } diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index f9bb985..c0e1b74 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -868,7 +868,10 @@ size_t clistr_pull_talloc(TALLOC_CTX *ctx, const void *src, int src_len, int flags); -bool clistr_is_previous_version_path(const char *path); +bool clistr_is_previous_version_path(const char *path, + const char **startp, + const char **endp, + time_t *ptime); /* The following definitions come from libsmb/clitrans.c */ -- 2.8.0.rc3.226.g39d4020 From 105f4118ac18e8e5a0a3668d26dc2dad1b6253d7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 16 Aug 2016 15:26:53 -0700 Subject: [PATCH 3/5] s3: libsmb: Add cli_smb2_shadow_copy_data() function that gets shadow copy info over SMB2. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166 Signed-off-by: Jeremy Allison Reviewed-by: Uri Simchoni (cherry picked from commit 0c6329bc152fcf08fcef385d2f7ee829485eb1a6) --- source3/libsmb/cli_smb2_fnum.c | 229 +++++++++++++++++++++++++++++++++++++++++ source3/libsmb/cli_smb2_fnum.h | 6 ++ 2 files changed, 235 insertions(+) diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c index c5b1434..70fa798 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -39,6 +39,7 @@ #include "../libcli/security/security.h" #include "lib/util_ea.h" #include "librpc/gen_ndr/ndr_ioctl.h" +#include "ntioctl.h" struct smb2_hnd { uint64_t fid_persistent; @@ -2873,3 +2874,231 @@ NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written) tevent_req_received(req); return NT_STATUS_OK; } + +/*************************************************************** + SMB2 enum shadow copy data. +***************************************************************/ + +struct cli_smb2_shadow_copy_data_fnum_state { + struct cli_state *cli; + uint16_t fnum; + struct smb2_hnd *ph; + DATA_BLOB out_input_buffer; + DATA_BLOB out_output_buffer; +}; + +static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq); + +static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + bool get_names) +{ + struct tevent_req *req, *subreq; + struct cli_smb2_close_fnum_state *state; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct cli_smb2_shadow_copy_data_fnum_state); + if (req == NULL) { + return NULL; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + state->cli = cli; + state->fnum = fnum; + + status = map_fnum_to_smb2_handle(cli, fnum, &state->ph); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + /* + * TODO. Under SMB2 we should send a zero max_output_length + * ioctl to get the required size, then send another ioctl + * to get the data, but the current SMB1 implementation just + * does one roundtrip with a 64K buffer size. Do the same + * for now. JRA. + */ + + subreq = smb2cli_ioctl_send(state, ev, state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + state->ph->fid_persistent, /* in_fid_persistent */ + state->ph->fid_volatile, /* in_fid_volatile */ + FSCTL_GET_SHADOW_COPY_DATA, + 0, /* in_max_input_length */ + NULL, /* in_input_buffer */ + get_names ? + CLI_BUFFER_SIZE : 16, /* in_max_output_length */ + NULL, /* in_output_buffer */ + SMB2_IOCTL_FLAG_IS_FSCTL); + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, + cli_smb2_shadow_copy_data_fnum_done, + req); + + return req; +} + +static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data( + req, struct cli_smb2_shadow_copy_data_fnum_state); + NTSTATUS status; + + status = smb2cli_ioctl_recv(subreq, state, + &state->out_input_buffer, + &state->out_output_buffer); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + tevent_req_done(req); +} + +static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + bool get_names, + char ***pnames, + int *pnum_names) +{ + struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data( + req, struct cli_smb2_shadow_copy_data_fnum_state); + char **names = NULL; + uint32_t num_names = 0; + uint32_t num_names_returned = 0; + uint32_t dlength = 0; + uint32_t i; + uint8_t *endp = NULL; + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + if (state->out_output_buffer.length < 16) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + num_names = IVAL(state->out_output_buffer.data, 0); + num_names_returned = IVAL(state->out_output_buffer.data, 4); + dlength = IVAL(state->out_output_buffer.data, 8); + + if (num_names > 0x7FFFFFFF) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + if (get_names == false) { + *pnum_names = (int)num_names; + return NT_STATUS_OK; + } + if (num_names != num_names_returned) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (dlength + 12 < 12) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + /* + * NB. The below is an allowable return if there are + * more snapshots than the buffer size we told the + * server we can receive. We currently don't support + * this. + */ + if (dlength + 12 > state->out_output_buffer.length) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (state->out_output_buffer.length + + (2 * sizeof(SHADOW_COPY_LABEL)) < + state->out_output_buffer.length) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + names = talloc_array(mem_ctx, char *, num_names_returned); + if (names == NULL) { + return NT_STATUS_NO_MEMORY; + } + + endp = state->out_output_buffer.data + + state->out_output_buffer.length; + + for (i=0; iout_output_buffer.data + 12 + + (i * 2 * sizeof(SHADOW_COPY_LABEL)); + + if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + ret = convert_string_talloc( + names, CH_UTF16LE, CH_UNIX, + src, 2 * sizeof(SHADOW_COPY_LABEL), + &names[i], &converted_size); + if (!ret) { + TALLOC_FREE(names); + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + } + *pnum_names = num_names; + *pnames = names; + return NT_STATUS_OK; +} + +NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx, + struct cli_state *cli, + uint16_t fnum, + bool get_names, + char ***pnames, + int *pnum_names) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + goto fail; + } + req = cli_smb2_shadow_copy_data_fnum_send(frame, + ev, + cli, + fnum, + get_names); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + status = cli_smb2_shadow_copy_data_fnum_recv(req, + mem_ctx, + get_names, + pnames, + pnum_names); + fail: + TALLOC_FREE(frame); + return status; +} diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h index ceb5629..0436c68 100644 --- a/source3/libsmb/cli_smb2_fnum.h +++ b/source3/libsmb/cli_smb2_fnum.h @@ -184,4 +184,10 @@ struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx, off_t size, off_t src_offset, off_t dst_offset, int (*splice_cb)(off_t n, void *priv), void *priv); NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written); +NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx, + struct cli_state *cli, + uint16_t fnum, + bool get_names, + char ***pnames, + int *pnum_names); #endif /* __SMB2CLI_FNUM_H__ */ -- 2.8.0.rc3.226.g39d4020 From 82b20089cd707210860c20a1a5369f97ac3a2689 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 16 Aug 2016 15:27:55 -0700 Subject: [PATCH 4/5] s3: libsmb: Plumb new SMB2 shadow copy call into cli_shadow_copy_data(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166 Signed-off-by: Jeremy Allison Reviewed-by: Uri Simchoni (cherry picked from commit 03bf1f858d1c474f9522cb0f5b264c4f6c2ca5b9) --- source3/libsmb/clifile.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 75ec3a2..fca7c91 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -6116,11 +6116,22 @@ NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum, bool get_names, char ***pnames, int *pnum_names) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_shadow_copy_data(mem_ctx, + cli, + fnum, + get_names, + pnames, + pnum_names); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 2.8.0.rc3.226.g39d4020 From cbeab8b94dbca4a9f975c1cb7d47691abe6bef37 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Aug 2016 17:00:25 -0700 Subject: [PATCH 5/5] s3: libsmb: Add the capability to find a @GMT- path in an SMB2 create and transform to a timewarp token. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166 Signed-off-by: Jeremy Allison Reviewed-by: Uri Simchoni Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Mon Aug 22 22:59:22 CEST 2016 on sn-devel-144 (cherry picked from commit 272f5c95cfb3d8035939dada7bd473058c7b6517) --- source3/libsmb/cli_smb2_fnum.c | 45 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c index 70fa798..ac72090 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -178,6 +178,10 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx, struct tevent_req *req, *subreq; struct cli_smb2_create_fnum_state *state; size_t fname_len = 0; + const char *startp = NULL; + const char *endp = NULL; + time_t tstamp = (time_t)0; + struct smb2_create_blobs *cblobs = NULL; req = tevent_req_create(mem_ctx, &state, struct cli_smb2_create_fnum_state); @@ -195,14 +199,51 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx, create_options |= FILE_OPEN_FOR_BACKUP_INTENT; } + /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */ + fname_len = strlen(fname); + if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) { + size_t len_before_gmt = startp - fname; + size_t len_after_gmt = fname + fname_len - endp; + DATA_BLOB twrp_blob; + NTTIME ntt; + NTSTATUS status; + + char *new_fname = talloc_array(state, char, + len_before_gmt + len_after_gmt + 1); + + if (tevent_req_nomem(new_fname, req)) { + return tevent_req_post(req, ev); + } + + memcpy(new_fname, fname, len_before_gmt); + memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1); + fname = new_fname; + fname_len = len_before_gmt + len_after_gmt; + + unix_to_nt_time(&ntt, tstamp); + twrp_blob = data_blob_const((const void *)&ntt, 8); + + cblobs = talloc_zero(state, struct smb2_create_blobs); + if (tevent_req_nomem(cblobs, req)) { + return tevent_req_post(req, ev); + } + + status = smb2_create_blob_add(state, cblobs, + SMB2_CREATE_TAG_TWRP, twrp_blob); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } + /* SMB2 is pickier about pathnames. Ensure it doesn't start in a '\' */ if (*fname == '\\') { fname++; + fname_len--; } /* Or end in a '\' */ - fname_len = strlen(fname); if (fname_len > 0 && fname[fname_len-1] == '\\') { char *new_fname = talloc_strdup(state, fname); if (tevent_req_nomem(new_fname, req)) { @@ -225,7 +266,7 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx, share_access, create_disposition, create_options, - NULL); + cblobs); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } -- 2.8.0.rc3.226.g39d4020