From 9576638dbacd24183b8715febf50d8be86aa950a Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 15 Jun 2012 13:37:26 +0200 Subject: s3:smbd: add basic support for durable handle v2 request and reconnect This does not yet cover persistent handle support which is also negotiated through these create request blobs. Pair-Programmed-With: Stefan Metzmacher --- source3/smbd/smb2_create.c | 131 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) (limited to 'source3/smbd/smb2_create.c') diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 4ec03855dd..331ca49b1b 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -432,6 +432,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, struct smb2_create_blobs out_context_blobs; int requested_oplock_level; struct smb2_create_blob *dhnc = NULL; + struct smb2_create_blob *dh2c = NULL; struct smbXsrv_open *op = NULL; ZERO_STRUCT(out_context_blobs); @@ -487,10 +488,26 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } } + dh2c = smb2_create_blob_find(&in_context_blobs, + SMB2_CREATE_TAG_DH2C); + if (dh2c) { + if (dh2c->data.length != 36) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + if (in_context_blobs.num_blobs != 1) { + /* + * DH2C should be the only one. + */ + tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return tevent_req_post(req, ev); + } + } + if (IS_IPC(smb1req->conn)) { const char *pipe_name = in_name; - if (dhnc) { + if (dhnc || dh2c) { /* durable handles are not supported on IPC$ */ tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); return tevent_req_post(req, ev); @@ -508,7 +525,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } info = FILE_WAS_OPENED; } else if (CAN_PRINT(smb1req->conn)) { - if (dhnc) { + if (dhnc || dh2c) { /* durable handles are not supported on printers */ tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); return tevent_req_post(req, ev); @@ -546,6 +563,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, bool durable_requested = false; uint32_t durable_timeout_msec = 0; bool do_durable_reconnect = false; + struct smb2_create_blob *dh2q = NULL; exta = smb2_create_blob_find(&in_context_blobs, SMB2_CREATE_TAG_EXTA); @@ -561,6 +579,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, SMB2_CREATE_TAG_TWRP); qfid = smb2_create_blob_find(&in_context_blobs, SMB2_CREATE_TAG_QFID); + dh2q = smb2_create_blob_find(&in_context_blobs, + SMB2_CREATE_TAG_DH2Q); fname = talloc_strdup(state, in_name); if (tevent_req_nomem(fname, req)) { @@ -612,6 +632,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } + + if (dh2q) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + /* * durable handle request is processed below. */ @@ -625,6 +651,49 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, durable_timeout_msec = (16*60*1000); } + if (dh2q) { + const uint8_t *p = dh2q->data.data; + uint32_t durable_v2_timeout = 0; + DATA_BLOB create_guid_blob; + + if (dh2q->data.length != 32) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + if (dhnq) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + durable_v2_timeout = IVAL(p, 0); + create_guid_blob = data_blob_const(p + 16, 16); + + status = GUID_from_ndr_blob(&create_guid_blob, + &create_guid); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + /* + * we need to store the create_guid later + */ + update_open = true; + + /* + * durable handle v2 request processed below + */ + durable_requested = true; + durable_timeout_msec = durable_v2_timeout; + if (durable_timeout_msec == 0) { + /* + * Set the timeout to 1 min as default. + * + * This matches Windows 2012. + */ + durable_timeout_msec = (60*1000); + } + } + if (dhnc) { NTTIME now = timeval_to_nttime(&smb2req->request_time); uint64_t persistent_id; @@ -657,6 +726,47 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, do_durable_reconnect = true; } + if (dh2c) { + const uint8_t *p = dh2c->data.data; + NTTIME now = timeval_to_nttime(&smb2req->request_time); + uint64_t persistent_id; + DATA_BLOB create_guid_blob; + + persistent_id = BVAL(p, 0); + create_guid_blob = data_blob_const(p + 16, 16); + + status = GUID_from_ndr_blob(&create_guid_blob, + &create_guid); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + status = smb2srv_open_recreate(smb2req->sconn->conn, + smb1req->conn->session_info, + persistent_id, create_guid, + now, &op); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("smbd_smb2_create_send: " + "smb2srv_open_recreate v2 failed: %s\n", + nt_errstr(status))); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + DEBUG(10, ("smb2_create_send: DH2C: %s recreate the " + "smb2srv_open struct for a durable handle.\n", + op->global->durable ? "did" : "could not")); + + if (!op->global->durable) { + talloc_free(op); + tevent_req_nterror(req, + NT_STATUS_OBJECT_NAME_NOT_FOUND); + return tevent_req_post(req, ev); + } + + do_durable_reconnect = true; + } + if (alsi) { if (alsi->data.length != 8) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -883,6 +993,23 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } } + if (dh2q && op->global->durable) { + uint8_t p[8] = { 0, }; + DATA_BLOB blob = data_blob_const(p, sizeof(p)); + uint32_t durable_v2_response_flags = 0; + + SIVAL(p, 0, op->global->durable_timeout_msec); + SIVAL(p, 4, durable_v2_response_flags); + + status = smb2_create_blob_add(state, &out_context_blobs, + SMB2_CREATE_TAG_DH2Q, + blob); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } + if (qfid) { uint8_t p[32]; uint64_t file_index = get_FileIndex(result->conn, -- cgit