5
5
Copyright (C) Stefan Metzmacher 2009
6
Copyright (C) Jeremy Allison 2010
7
8
This program is free software; you can redistribute it and/or modify
8
9
it under the terms of the GNU General Public License as published by
21
22
#include "includes.h"
23
#include "smbd/smbd.h"
22
24
#include "smbd/globals.h"
23
25
#include "../libcli/smb/smb_common.h"
27
#include "../lib/util/tevent_ntstatus.h"
25
29
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
26
30
struct tevent_context *ev,
34
38
uint64_t in_file_id_volatile);
35
39
static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req,
36
40
TALLOC_CTX *mem_ctx,
37
DATA_BLOB *out_output_buffer);
41
DATA_BLOB *out_output_buffer,
42
NTSTATUS *p_call_status);
39
44
static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq);
40
45
NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req)
43
48
const uint8_t *inbody;
44
49
int i = req->current_idx;
45
size_t expected_body_size = 0x29;
47
50
uint8_t in_info_type;
48
51
uint8_t in_file_info_class;
49
52
uint32_t in_output_buffer_length;
56
59
uint64_t in_file_id_volatile;
57
60
struct tevent_req *subreq;
59
inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
60
if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
61
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
62
status = smbd_smb2_request_verify_sizes(req, 0x29);
63
if (!NT_STATUS_IS_OK(status)) {
64
return smbd_smb2_request_error(req, status);
64
66
inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
66
body_size = SVAL(inbody, 0x00);
67
if (body_size != expected_body_size) {
68
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
71
68
in_info_type = CVAL(inbody, 0x02);
72
69
in_file_info_class = CVAL(inbody, 0x03);
73
70
in_output_buffer_length = IVAL(inbody, 0x04);
82
79
if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) {
84
81
} else if (in_input_buffer_offset !=
85
(SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
82
(SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
86
83
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
93
90
in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
94
91
in_input_buffer.length = in_input_buffer_length;
93
if (in_input_buffer.length > req->sconn->smb2.max_trans) {
94
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
96
if (in_output_buffer_length > req->sconn->smb2.max_trans) {
97
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
96
100
if (req->compat_chain_fsp) {
98
} else if (in_file_id_persistent != 0) {
102
} else if (in_file_id_persistent != in_file_id_volatile) {
99
103
return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
128
132
uint16_t out_output_buffer_offset;
129
133
DATA_BLOB out_output_buffer = data_blob_null;
135
NTSTATUS call_status = NT_STATUS_OK;
131
136
NTSTATUS error; /* transport error */
133
138
status = smbd_smb2_getinfo_recv(subreq,
136
142
TALLOC_FREE(subreq);
137
143
if (!NT_STATUS_IS_OK(status)) {
138
144
error = smbd_smb2_request_error(req, status);
153
if (!NT_STATUS_IS_OK(call_status)) {
154
/* Return a specific error with data. */
155
error = smbd_smb2_request_error_ex(req,
159
if (!NT_STATUS_IS_OK(error)) {
160
smbd_server_connection_terminate(req->sconn,
147
167
out_output_buffer_offset = SMB2_HDR_BODY + 0x08;
149
169
outhdr = (uint8_t *)req->out.vector[i].iov_base;
181
201
DATA_BLOB out_output_buffer;
204
static void smb2_ipc_getinfo(struct tevent_req *req,
205
struct smbd_smb2_getinfo_state *state,
206
struct tevent_context *ev,
207
uint8_t in_info_type,
208
uint8_t in_file_info_class)
210
/* We want to reply to SMB2_GETINFO_FILE
211
with a class of SMB2_FILE_STANDARD_INFO as
212
otherwise a Win7 client issues this request
213
twice (2xroundtrips) if we return NOT_SUPPORTED.
214
NB. We do the same for SMB1 in call_trans2qpipeinfo() */
216
if (in_info_type == 0x01 && /* SMB2_GETINFO_FILE */
217
in_file_info_class == 0x05) { /* SMB2_FILE_STANDARD_INFO */
218
state->out_output_buffer = data_blob_talloc(state,
220
if (tevent_req_nomem(state->out_output_buffer.data, req)) {
224
memset(state->out_output_buffer.data,0,24);
225
SOFF_T(state->out_output_buffer.data,0,4096LL);
226
SIVAL(state->out_output_buffer.data,16,1);
227
SIVAL(state->out_output_buffer.data,20,1);
228
tevent_req_done(req);
230
tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
184
234
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
185
235
struct tevent_context *ev,
186
236
struct smbd_smb2_request *smb2req,
197
247
struct smb_request *smbreq;
198
248
connection_struct *conn = smb2req->tcon->compat_conn;
199
249
files_struct *fsp;
201
252
req = tevent_req_create(mem_ctx, &state,
202
253
struct smbd_smb2_getinfo_state);
206
257
state->smb2req = smb2req;
207
state->status = NT_STATUS_INTERNAL_ERROR;
258
state->status = NT_STATUS_OK;
208
259
state->out_output_buffer = data_blob_null;
210
261
DEBUG(10,("smbd_smb2_getinfo_send: file_id[0x%016llX]\n",
232
283
if (IS_IPC(conn)) {
233
tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
284
smb2_ipc_getinfo(req, state, ev,
285
in_info_type, in_file_info_class);
234
286
return tevent_req_post(req, ev);
274
324
/* We know this name is ok, it's already passed the checks. */
276
} else if (fsp && (fsp->is_directory || fsp->fh->fd == -1)) {
326
} else if (fsp && fsp->fh->fd == -1) {
278
328
* This is actually a QFILEINFO on a directory
279
329
* handle (returned from an NT SMB). NT5.0 seems
304
354
fileid = vfs_file_id_from_sbuf(conn,
305
355
&fsp->fsp_name->st);
306
get_file_infos(fileid, &delete_pending, &write_time_ts);
356
get_file_infos(fileid, fsp->name_hash,
357
&delete_pending, &write_time_ts);
309
360
* Original code - this is an open file.
320
371
fileid = vfs_file_id_from_sbuf(conn,
321
372
&fsp->fsp_name->st);
322
get_file_infos(fileid, &delete_pending, &write_time_ts);
373
get_file_infos(fileid, fsp->name_hash,
374
&delete_pending, &write_time_ts);
325
377
status = smbd_do_qfilepathinfo(conn, state,
447
case 0x03:/* SMB2_GETINFO_SEC */
449
uint8_t *p_marshalled_sd = NULL;
452
status = smbd_do_query_security_desc(conn,
455
/* Security info wanted. */
456
in_additional_information,
457
in_output_buffer_length,
461
if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
462
/* Return needed size. */
463
state->out_output_buffer = data_blob_talloc(state,
466
if (tevent_req_nomem(state->out_output_buffer.data, req)) {
467
return tevent_req_post(req, ev);
469
SIVAL(state->out_output_buffer.data,0,(uint32_t)sd_size);
470
state->status = NT_STATUS_BUFFER_TOO_SMALL;
473
if (!NT_STATUS_IS_OK(status)) {
474
DEBUG(10,("smbd_smb2_getinfo_send: "
475
"smbd_do_query_security_desc of %s failed "
476
"(%s)\n", fsp_str_dbg(fsp),
478
tevent_req_nterror(req, status);
479
return tevent_req_post(req, ev);
483
state->out_output_buffer = data_blob_talloc(state,
486
if (tevent_req_nomem(state->out_output_buffer.data, req)) {
487
return tevent_req_post(req, ev);
494
DEBUG(10,("smbd_smb2_getinfo_send: "
495
"unknown in_info_type of %u "
497
(unsigned int)in_info_type,
398
500
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
399
501
return tevent_req_post(req, ev);
406
508
static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req,
407
509
TALLOC_CTX *mem_ctx,
408
DATA_BLOB *out_output_buffer)
510
DATA_BLOB *out_output_buffer,
411
514
struct smbd_smb2_getinfo_state *state = tevent_req_data(req,
419
522
*out_output_buffer = state->out_output_buffer;
420
523
talloc_steal(mem_ctx, out_output_buffer->data);
524
*pstatus = state->status;
422
526
tevent_req_received(req);
423
527
return NT_STATUS_OK;