2 Unix SMB2 implementation.
4 Copyright (C) Stefan Metzmacher 2006
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "libcli/smb2/smb2.h"
22 #include "libcli/smb2/smb2_calls.h"
23 #include "smb_server/smb_server.h"
24 #include "smb_server/smb2/smb2_server.h"
25 #include "ntvfs/ntvfs.h"
26 #include "librpc/gen_ndr/ndr_security.h"
28 struct smb2srv_getinfo_op
{
29 struct smb2srv_request
*req
;
30 struct smb2_getinfo
*info
;
32 NTSTATUS (*send_fn
)(struct smb2srv_getinfo_op
*op
);
35 static void smb2srv_getinfo_send(struct ntvfs_request
*ntvfs
)
37 struct smb2srv_getinfo_op
*op
;
38 struct smb2srv_request
*req
;
41 * SMB2 uses NT_STATUS_INVALID_INFO_CLASS
42 * so we need to translated it here
44 if (NT_STATUS_EQUAL(NT_STATUS_INVALID_LEVEL
, ntvfs
->async_states
->status
)) {
45 ntvfs
->async_states
->status
= NT_STATUS_INVALID_INFO_CLASS
;
48 SMB2SRV_CHECK_ASYNC_STATUS(op
, struct smb2srv_getinfo_op
);
50 ZERO_STRUCT(op
->info
->out
);
52 SMB2SRV_CHECK(op
->send_fn(op
));
55 if (op
->info
->in
.output_buffer_length
< op
->info
->out
.blob
.length
) {
56 smb2srv_send_error(req
, NT_STATUS_INFO_LENGTH_MISMATCH
);
60 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, true, op
->info
->out
.blob
.length
));
62 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, op
->info
->out
.blob
));
63 SSVAL(req
->out
.body
, 0x06, 0);
65 smb2srv_send_reply(req
);
68 static NTSTATUS
smb2srv_getinfo_file_send(struct smb2srv_getinfo_op
*op
)
70 union smb_fileinfo
*io
= talloc_get_type(op
->io_ptr
, union smb_fileinfo
);
73 status
= smbsrv_push_passthru_fileinfo(op
->req
,
75 io
->generic
.level
, io
,
77 NT_STATUS_NOT_OK_RETURN(status
);
82 static NTSTATUS
smb2srv_getinfo_file(struct smb2srv_getinfo_op
*op
, uint8_t smb2_level
)
84 union smb_fileinfo
*io
;
87 io
= talloc(op
, union smb_fileinfo
);
88 NT_STATUS_HAVE_NO_MEMORY(io
);
90 level
= op
->info
->in
.info_type
| (op
->info
->in
.info_class
<< 8);
92 case RAW_FILEINFO_SMB2_ALL_EAS
:
93 io
->all_eas
.level
= level
;
94 io
->all_eas
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
95 io
->all_eas
.in
.continue_flags
= op
->info
->in
.getinfo_flags
;
98 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
99 io
->all_info2
.level
= level
;
100 io
->all_info2
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
104 /* the rest directly maps to the passthru levels */
105 io
->generic
.level
= smb2_level
+ 1000;
106 io
->generic
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
111 op
->send_fn
= smb2srv_getinfo_file_send
;
113 return ntvfs_qfileinfo(op
->req
->ntvfs
, io
);
116 static NTSTATUS
smb2srv_getinfo_fs_send(struct smb2srv_getinfo_op
*op
)
118 union smb_fsinfo
*io
= talloc_get_type(op
->io_ptr
, union smb_fsinfo
);
121 status
= smbsrv_push_passthru_fsinfo(op
->req
,
123 io
->generic
.level
, io
,
125 NT_STATUS_NOT_OK_RETURN(status
);
130 static NTSTATUS
smb2srv_getinfo_fs(struct smb2srv_getinfo_op
*op
, uint8_t smb2_level
)
132 union smb_fsinfo
*io
;
134 io
= talloc(op
, union smb_fsinfo
);
135 NT_STATUS_HAVE_NO_MEMORY(io
);
137 /* the rest directly maps to the passthru levels */
138 io
->generic
.level
= smb2_level
+ 1000;
140 /* TODO: allow qfsinfo only the share root directory handle */
143 op
->send_fn
= smb2srv_getinfo_fs_send
;
145 return ntvfs_fsinfo(op
->req
->ntvfs
, io
);
148 static NTSTATUS
smb2srv_getinfo_security_send(struct smb2srv_getinfo_op
*op
)
150 union smb_fileinfo
*io
= talloc_get_type(op
->io_ptr
, union smb_fileinfo
);
151 enum ndr_err_code ndr_err
;
153 ndr_err
= ndr_push_struct_blob(&op
->info
->out
.blob
, op
->req
,
154 io
->query_secdesc
.out
.sd
,
155 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
156 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
157 return ndr_map_error2ntstatus(ndr_err
);
163 static NTSTATUS
smb2srv_getinfo_security(struct smb2srv_getinfo_op
*op
, uint8_t smb2_level
)
165 union smb_fileinfo
*io
;
167 switch (smb2_level
) {
169 io
= talloc(op
, union smb_fileinfo
);
170 NT_STATUS_HAVE_NO_MEMORY(io
);
172 io
->query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
173 io
->query_secdesc
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
174 io
->query_secdesc
.in
.secinfo_flags
= op
->info
->in
.additional_information
;
177 op
->send_fn
= smb2srv_getinfo_security_send
;
179 return ntvfs_qfileinfo(op
->req
->ntvfs
, io
);
182 return NT_STATUS_INVALID_PARAMETER
;
185 static NTSTATUS
smb2srv_getinfo_backend(struct smb2srv_getinfo_op
*op
)
187 switch (op
->info
->in
.info_type
) {
188 case SMB2_0_INFO_FILE
:
189 return smb2srv_getinfo_file(op
, op
->info
->in
.info_class
);
191 case SMB2_0_INFO_FILESYSTEM
:
192 return smb2srv_getinfo_fs(op
, op
->info
->in
.info_class
);
194 case SMB2_0_INFO_SECURITY
:
195 return smb2srv_getinfo_security(op
, op
->info
->in
.info_class
);
197 case SMB2_0_INFO_QUOTA
:
198 return NT_STATUS_NOT_SUPPORTED
;
201 return NT_STATUS_INVALID_PARAMETER
;
204 void smb2srv_getinfo_recv(struct smb2srv_request
*req
)
206 struct smb2_getinfo
*info
;
207 struct smb2srv_getinfo_op
*op
;
209 SMB2SRV_CHECK_BODY_SIZE(req
, 0x28, true);
210 SMB2SRV_TALLOC_IO_PTR(info
, struct smb2_getinfo
);
211 /* this overwrites req->io_ptr !*/
212 SMB2SRV_TALLOC_IO_PTR(op
, struct smb2srv_getinfo_op
);
217 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_getinfo_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
219 info
->in
.info_type
= CVAL(req
->in
.body
, 0x02);
220 info
->in
.info_class
= CVAL(req
->in
.body
, 0x03);
221 info
->in
.output_buffer_length
= IVAL(req
->in
.body
, 0x04);
222 info
->in
.reserved
= IVAL(req
->in
.body
, 0x0C);
223 info
->in
.additional_information
= IVAL(req
->in
.body
, 0x10);
224 info
->in
.getinfo_flags
= IVAL(req
->in
.body
, 0x14);
225 info
->in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x18);
226 SMB2SRV_CHECK(smb2_pull_o16As32_blob(&req
->in
, op
,
227 req
->in
.body
+0x08, &info
->in
.input_buffer
));
229 SMB2SRV_CHECK_FILE_HANDLE(info
->in
.file
.ntvfs
);
230 SMB2SRV_CALL_NTVFS_BACKEND(smb2srv_getinfo_backend(op
));
233 struct smb2srv_setinfo_op
{
234 struct smb2srv_request
*req
;
235 struct smb2_setinfo
*info
;
238 static void smb2srv_setinfo_send(struct ntvfs_request
*ntvfs
)
240 struct smb2srv_setinfo_op
*op
;
241 struct smb2srv_request
*req
;
244 * SMB2 uses NT_STATUS_INVALID_INFO_CLASS
245 * so we need to translated it here
247 if (NT_STATUS_EQUAL(NT_STATUS_INVALID_LEVEL
, ntvfs
->async_states
->status
)) {
248 ntvfs
->async_states
->status
= NT_STATUS_INVALID_INFO_CLASS
;
251 SMB2SRV_CHECK_ASYNC_STATUS(op
, struct smb2srv_setinfo_op
);
253 SMB2SRV_CHECK(smb2srv_setup_reply(op
->req
, 0x02, false, 0));
255 smb2srv_send_reply(req
);
258 static NTSTATUS
smb2srv_setinfo_file(struct smb2srv_setinfo_op
*op
, uint8_t smb2_level
)
260 union smb_setfileinfo
*io
;
263 io
= talloc(op
, union smb_setfileinfo
);
264 NT_STATUS_HAVE_NO_MEMORY(io
);
266 /* the levels directly map to the passthru levels */
267 io
->generic
.level
= smb2_level
+ 1000;
268 io
->generic
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
270 /* handle cases that don't map directly */
271 if (io
->generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
) {
272 io
->generic
.level
= RAW_SFILEINFO_RENAME_INFORMATION_SMB2
;
275 status
= smbsrv_pull_passthru_sfileinfo(io
, io
->generic
.level
, io
,
277 STR_UNICODE
, &op
->req
->in
.bufinfo
);
278 NT_STATUS_NOT_OK_RETURN(status
);
280 return ntvfs_setfileinfo(op
->req
->ntvfs
, io
);
283 static NTSTATUS
smb2srv_setinfo_fs(struct smb2srv_setinfo_op
*op
, uint8_t smb2_level
)
285 switch (smb2_level
) {
287 return NT_STATUS_NOT_IMPLEMENTED
;
290 return NT_STATUS_ACCESS_DENIED
;
293 return NT_STATUS_ACCESS_DENIED
;
296 return NT_STATUS_ACCESS_DENIED
;
299 return NT_STATUS_INVALID_INFO_CLASS
;
302 static NTSTATUS
smb2srv_setinfo_security(struct smb2srv_setinfo_op
*op
, uint8_t smb2_level
)
304 union smb_setfileinfo
*io
;
305 enum ndr_err_code ndr_err
;
307 switch (smb2_level
) {
309 io
= talloc(op
, union smb_setfileinfo
);
310 NT_STATUS_HAVE_NO_MEMORY(io
);
312 io
->set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
313 io
->set_secdesc
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
314 io
->set_secdesc
.in
.secinfo_flags
= op
->info
->in
.flags
;
316 io
->set_secdesc
.in
.sd
= talloc(io
, struct security_descriptor
);
317 NT_STATUS_HAVE_NO_MEMORY(io
->set_secdesc
.in
.sd
);
319 ndr_err
= ndr_pull_struct_blob(&op
->info
->in
.blob
, io
,
320 io
->set_secdesc
.in
.sd
,
321 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
322 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
323 return ndr_map_error2ntstatus(ndr_err
);
326 return ntvfs_setfileinfo(op
->req
->ntvfs
, io
);
329 return NT_STATUS_INVALID_INFO_CLASS
;
332 static NTSTATUS
smb2srv_setinfo_backend(struct smb2srv_setinfo_op
*op
)
337 smb2_class
= 0xFF & op
->info
->in
.level
;
338 smb2_level
= 0xFF & (op
->info
->in
.level
>>8);
340 switch (smb2_class
) {
341 case SMB2_0_INFO_FILE
:
342 return smb2srv_setinfo_file(op
, smb2_level
);
344 case SMB2_0_INFO_FILESYSTEM
:
345 return smb2srv_setinfo_fs(op
, smb2_level
);
347 case SMB2_0_INFO_SECURITY
:
348 return smb2srv_setinfo_security(op
, smb2_level
);
350 case SMB2_0_INFO_QUOTA
:
351 return NT_STATUS_NOT_SUPPORTED
;
354 return NT_STATUS_INVALID_PARAMETER
;
357 void smb2srv_setinfo_recv(struct smb2srv_request
*req
)
359 struct smb2_setinfo
*info
;
360 struct smb2srv_setinfo_op
*op
;
362 SMB2SRV_CHECK_BODY_SIZE(req
, 0x20, true);
363 SMB2SRV_TALLOC_IO_PTR(info
, struct smb2_setinfo
);
364 /* this overwrites req->io_ptr !*/
365 SMB2SRV_TALLOC_IO_PTR(op
, struct smb2srv_setinfo_op
);
368 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_setinfo_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
370 info
->in
.level
= SVAL(req
->in
.body
, 0x02);
371 SMB2SRV_CHECK(smb2_pull_s32o16_blob(&req
->in
, info
, req
->in
.body
+0x04, &info
->in
.blob
));
372 info
->in
.flags
= IVAL(req
->in
.body
, 0x0C);
373 info
->in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
375 SMB2SRV_CHECK_FILE_HANDLE(info
->in
.file
.ntvfs
);
376 SMB2SRV_CALL_NTVFS_BACKEND(smb2srv_setinfo_backend(op
));