X-Git-Url: http://git.samba.org/samba.git/?p=ira%2Fwip.git;a=blobdiff_plain;f=source3%2Fsmbd%2Fsmb2_ioctl.c;h=9ff6c8ea979436fe180444f597ffab4beed761a7;hp=cc3b537f2a63877c6c3bc860b8de36468d9a54ad;hb=0e261d0e9c89ff11dc37b2bfd70c74c3a06486bd;hpb=d1db140a73e6d443fb2f82ea6a02479c98e97e67 diff --git a/source3/smbd/smb2_ioctl.c b/source3/smbd/smb2_ioctl.c index cc3b537f2a6..9ff6c8ea979 100644 --- a/source3/smbd/smb2_ioctl.c +++ b/source3/smbd/smb2_ioctl.c @@ -109,10 +109,15 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) { struct smbd_smb2_request *req = tevent_req_callback_data(subreq, struct smbd_smb2_request); + const uint8_t *inbody; int i = req->current_idx; uint8_t *outhdr; DATA_BLOB outbody; DATA_BLOB outdyn; + uint32_t in_ctl_code; + uint64_t in_file_id_persistent; + uint64_t in_file_id_volatile; + uint32_t out_input_offset; uint32_t out_output_offset; DATA_BLOB out_output_buffer; NTSTATUS status; @@ -132,8 +137,15 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) return; } + out_input_offset = SMB2_HDR_BODY + 0x30; out_output_offset = SMB2_HDR_BODY + 0x30; + inbody = (const uint8_t *)req->in.vector[i+1].iov_base; + + in_ctl_code = IVAL(inbody, 0x04); + in_file_id_persistent = BVAL(inbody, 0x08); + in_file_id_volatile = BVAL(inbody, 0x10); + outhdr = (uint8_t *)req->out.vector[i].iov_base; outbody = data_blob_talloc(req->out.vector, NULL, 0x30); @@ -149,10 +161,14 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) SSVAL(outbody.data, 0x00, 0x30 + 1); /* struct size */ SSVAL(outbody.data, 0x02, 0); /* reserved */ - SIVAL(outbody.data, 0x04, 0); /* ctl code */ - SBVAL(outbody.data, 0x08, 0); /* file id (persistent) */ - SBVAL(outbody.data, 0x10, 0); /* file id (volatile) */ - SIVAL(outbody.data, 0x18, 0); /* input offset */ + SIVAL(outbody.data, 0x04, + in_ctl_code); /* ctl code */ + SBVAL(outbody.data, 0x08, + in_file_id_persistent); /* file id (persistent) */ + SBVAL(outbody.data, 0x10, + in_file_id_volatile); /* file id (volatile) */ + SIVAL(outbody.data, 0x18, + out_input_offset); /* input offset */ SIVAL(outbody.data, 0x1C, 0); /* input count */ SIVAL(outbody.data, 0x20, out_output_offset); /* output offset */ @@ -162,9 +178,9 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) SIVAL(outbody.data, 0x2C, 0); /* reserved */ /* - * Note: Windows sends back also the input from the request. - * I think this is stupid and I hope not required. - * For now we avoid a talloc + memcopy here... + * Note: Windows Vista and 2008 send back also the + * input from the request. But it was fixed in + * Windows 7. */ outdyn = out_output_buffer; @@ -243,13 +259,87 @@ static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx, } switch (in_ctl_code) { - case 0x0011C017: /* FSCTL_PIPE_TRANSCEIVE */ + case 0x00060194: /* FSCTL_DFS_GET_REFERRALS */ + { + uint16_t in_max_referral_level; + DATA_BLOB in_file_name_buffer; + char *in_file_name_string; + size_t in_file_name_string_size; + bool ok; + bool overflow = false; + NTSTATUS status; + int dfs_size; + char *dfs_data = NULL; if (!IS_IPC(smbreq->conn)) { tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); return tevent_req_post(req, ev); } + if (!lp_host_msdfs()) { + tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED); + return tevent_req_post(req, ev); + } + + if (in_input.length < (2 + 2)) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + in_max_referral_level = SVAL(in_input.data, 0); + in_file_name_buffer.data = in_input.data + 2; + in_file_name_buffer.length = in_input.length - 2; + + ok = convert_string_talloc(state, CH_UTF16, CH_UNIX, + in_file_name_buffer.data, + in_file_name_buffer.length, + &in_file_name_string, + &in_file_name_string_size, false); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_ILLEGAL_CHARACTER); + return tevent_req_post(req, ev); + } + + dfs_size = setup_dfs_referral(smbreq->conn, + in_file_name_string, + in_max_referral_level, + &dfs_data, &status); + if (dfs_size < 0) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + if (dfs_size > in_max_output) { + /* + * TODO: we need a testsuite for this + */ + overflow = true; + dfs_size = in_max_output; + } + + state->out_output = data_blob_talloc(state, + (uint8_t *)dfs_data, + dfs_size); + SAFE_FREE(dfs_data); + if (dfs_size > 0 && + tevent_req_nomem(state->out_output.data, req)) { + return tevent_req_post(req, ev); + } + + if (overflow) { + tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW); + } else { + tevent_req_done(req); + } + return tevent_req_post(req, ev); + } + case 0x0011C017: /* FSCTL_PIPE_TRANSCEIVE */ + + if (!IS_IPC(smbreq->conn)) { + tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); + return tevent_req_post(req, ev); + } + if (fsp == NULL) { tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); return tevent_req_post(req, ev);