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/service_smb_proto.h"
25 #include "smb_server/smb2/smb2_server.h"
26 #include "ntvfs/ntvfs.h"
27 #include "librpc/gen_ndr/ndr_security.h"
29 struct smb2srv_getinfo_op
{
30 struct smb2srv_request
*req
;
31 struct smb2_getinfo
*info
;
33 NTSTATUS (*send_fn
)(struct smb2srv_getinfo_op
*op
);
36 static void smb2srv_getinfo_send(struct ntvfs_request
*ntvfs
)
38 struct smb2srv_getinfo_op
*op
;
39 struct smb2srv_request
*req
;
42 * SMB2 uses NT_STATUS_INVALID_INFO_CLASS
43 * so we need to translated it here
45 if (NT_STATUS_EQUAL(NT_STATUS_INVALID_LEVEL
, ntvfs
->async_states
->status
)) {
46 ntvfs
->async_states
->status
= NT_STATUS_INVALID_INFO_CLASS
;
49 SMB2SRV_CHECK_ASYNC_STATUS(op
, struct smb2srv_getinfo_op
);
51 ZERO_STRUCT(op
->info
->out
);
53 SMB2SRV_CHECK(op
->send_fn(op
));
56 if (op
->info
->in
.output_buffer_length
< op
->info
->out
.blob
.length
) {
57 smb2srv_send_error(req
, NT_STATUS_INFO_LENGTH_MISMATCH
);
61 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, true, op
->info
->out
.blob
.length
));
63 SMB2SRV_CHECK(smb2_push_o16s32_blob(&req
->out
, 0x02, op
->info
->out
.blob
));
64 SSVAL(req
->out
.body
, 0x06, 0);
66 smb2srv_send_reply(req
);
69 static NTSTATUS
smb2srv_getinfo_file_send(struct smb2srv_getinfo_op
*op
)
71 union smb_fileinfo
*io
= talloc_get_type(op
->io_ptr
, union smb_fileinfo
);
74 status
= smbsrv_push_passthru_fileinfo(op
->req
,
76 io
->generic
.level
, io
,
78 NT_STATUS_NOT_OK_RETURN(status
);
83 static NTSTATUS
smb2srv_getinfo_file(struct smb2srv_getinfo_op
*op
, uint8_t smb2_level
)
85 union smb_fileinfo
*io
;
88 io
= talloc(op
, union smb_fileinfo
);
89 NT_STATUS_HAVE_NO_MEMORY(io
);
91 level
= op
->info
->in
.info_type
| (op
->info
->in
.info_class
<< 8);
93 case RAW_FILEINFO_SMB2_ALL_EAS
:
94 io
->all_eas
.level
= level
;
95 io
->all_eas
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
96 io
->all_eas
.in
.continue_flags
= op
->info
->in
.getinfo_flags
;
99 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
100 io
->all_info2
.level
= level
;
101 io
->all_info2
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
105 /* the rest directly maps to the passthru levels */
106 io
->generic
.level
= smb2_level
+ 1000;
107 io
->generic
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
112 op
->send_fn
= smb2srv_getinfo_file_send
;
114 return ntvfs_qfileinfo(op
->req
->ntvfs
, io
);
117 static NTSTATUS
smb2srv_getinfo_fs_send(struct smb2srv_getinfo_op
*op
)
119 union smb_fsinfo
*io
= talloc_get_type(op
->io_ptr
, union smb_fsinfo
);
122 status
= smbsrv_push_passthru_fsinfo(op
->req
,
124 io
->generic
.level
, io
,
126 NT_STATUS_NOT_OK_RETURN(status
);
131 static NTSTATUS
smb2srv_getinfo_fs(struct smb2srv_getinfo_op
*op
, uint8_t smb2_level
)
133 union smb_fsinfo
*io
;
135 io
= talloc(op
, union smb_fsinfo
);
136 NT_STATUS_HAVE_NO_MEMORY(io
);
138 /* the rest directly maps to the passthru levels */
139 io
->generic
.level
= smb2_level
+ 1000;
141 /* TODO: allow qfsinfo only the share root directory handle */
144 op
->send_fn
= smb2srv_getinfo_fs_send
;
146 return ntvfs_fsinfo(op
->req
->ntvfs
, io
);
149 static NTSTATUS
smb2srv_getinfo_security_send(struct smb2srv_getinfo_op
*op
)
151 union smb_fileinfo
*io
= talloc_get_type(op
->io_ptr
, union smb_fileinfo
);
152 enum ndr_err_code ndr_err
;
154 ndr_err
= ndr_push_struct_blob(&op
->info
->out
.blob
, op
->req
, NULL
,
155 io
->query_secdesc
.out
.sd
,
156 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
157 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
158 return ndr_map_error2ntstatus(ndr_err
);
164 static NTSTATUS
smb2srv_getinfo_security(struct smb2srv_getinfo_op
*op
, uint8_t smb2_level
)
166 union smb_fileinfo
*io
;
168 switch (smb2_level
) {
170 io
= talloc(op
, union smb_fileinfo
);
171 NT_STATUS_HAVE_NO_MEMORY(io
);
173 io
->query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
174 io
->query_secdesc
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
175 io
->query_secdesc
.in
.secinfo_flags
= op
->info
->in
.additional_information
;
178 op
->send_fn
= smb2srv_getinfo_security_send
;
180 return ntvfs_qfileinfo(op
->req
->ntvfs
, io
);
183 return NT_STATUS_INVALID_PARAMETER
;
186 static NTSTATUS
smb2srv_getinfo_backend(struct smb2srv_getinfo_op
*op
)
188 switch (op
->info
->in
.info_type
) {
189 case SMB2_GETINFO_FILE
:
190 return smb2srv_getinfo_file(op
, op
->info
->in
.info_class
);
192 case SMB2_GETINFO_FS
:
193 return smb2srv_getinfo_fs(op
, op
->info
->in
.info_class
);
195 case SMB2_GETINFO_SECURITY
:
196 return smb2srv_getinfo_security(op
, op
->info
->in
.info_class
);
198 case SMB2_GETINFO_QUOTA
:
199 return NT_STATUS_NOT_SUPPORTED
;
202 return NT_STATUS_INVALID_PARAMETER
;
205 void smb2srv_getinfo_recv(struct smb2srv_request
*req
)
207 struct smb2_getinfo
*info
;
208 struct smb2srv_getinfo_op
*op
;
210 SMB2SRV_CHECK_BODY_SIZE(req
, 0x28, true);
211 SMB2SRV_TALLOC_IO_PTR(info
, struct smb2_getinfo
);
212 /* this overwrites req->io_ptr !*/
213 SMB2SRV_TALLOC_IO_PTR(op
, struct smb2srv_getinfo_op
);
218 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_getinfo_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
220 info
->in
.info_type
= CVAL(req
->in
.body
, 0x02);
221 info
->in
.info_class
= CVAL(req
->in
.body
, 0x03);
222 info
->in
.output_buffer_length
= IVAL(req
->in
.body
, 0x04);
223 info
->in
.reserved
= IVAL(req
->in
.body
, 0x0C);
224 info
->in
.additional_information
= IVAL(req
->in
.body
, 0x10);
225 info
->in
.getinfo_flags
= IVAL(req
->in
.body
, 0x14);
226 info
->in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x18);
227 SMB2SRV_CHECK(smb2_pull_o16As32_blob(&req
->in
, op
,
228 req
->in
.body
+0x08, &info
->in
.blob
));
230 SMB2SRV_CHECK_FILE_HANDLE(info
->in
.file
.ntvfs
);
231 SMB2SRV_CALL_NTVFS_BACKEND(smb2srv_getinfo_backend(op
));
234 struct smb2srv_setinfo_op
{
235 struct smb2srv_request
*req
;
236 struct smb2_setinfo
*info
;
239 static void smb2srv_setinfo_send(struct ntvfs_request
*ntvfs
)
241 struct smb2srv_setinfo_op
*op
;
242 struct smb2srv_request
*req
;
245 * SMB2 uses NT_STATUS_INVALID_INFO_CLASS
246 * so we need to translated it here
248 if (NT_STATUS_EQUAL(NT_STATUS_INVALID_LEVEL
, ntvfs
->async_states
->status
)) {
249 ntvfs
->async_states
->status
= NT_STATUS_INVALID_INFO_CLASS
;
252 SMB2SRV_CHECK_ASYNC_STATUS(op
, struct smb2srv_setinfo_op
);
254 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x02, false, 0));
256 smb2srv_send_reply(req
);
259 static NTSTATUS
smb2srv_setinfo_file(struct smb2srv_setinfo_op
*op
, uint8_t smb2_level
)
261 union smb_setfileinfo
*io
;
264 io
= talloc(op
, union smb_setfileinfo
);
265 NT_STATUS_HAVE_NO_MEMORY(io
);
267 /* the levels directly map to the passthru levels */
268 io
->generic
.level
= smb2_level
+ 1000;
269 io
->generic
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
271 /* handle cases that don't map directly */
272 if (io
->generic
.level
== RAW_SFILEINFO_RENAME_INFORMATION
) {
273 io
->generic
.level
= RAW_SFILEINFO_RENAME_INFORMATION_SMB2
;
276 status
= smbsrv_pull_passthru_sfileinfo(io
, io
->generic
.level
, io
,
278 STR_UNICODE
, &op
->req
->in
.bufinfo
);
279 NT_STATUS_NOT_OK_RETURN(status
);
281 return ntvfs_setfileinfo(op
->req
->ntvfs
, io
);
284 static NTSTATUS
smb2srv_setinfo_fs(struct smb2srv_setinfo_op
*op
, uint8_t smb2_level
)
286 switch (smb2_level
) {
288 return NT_STATUS_NOT_IMPLEMENTED
;
291 return NT_STATUS_ACCESS_DENIED
;
294 return NT_STATUS_ACCESS_DENIED
;
297 return NT_STATUS_ACCESS_DENIED
;
300 return NT_STATUS_INVALID_INFO_CLASS
;
303 static NTSTATUS
smb2srv_setinfo_security(struct smb2srv_setinfo_op
*op
, uint8_t smb2_level
)
305 union smb_setfileinfo
*io
;
306 enum ndr_err_code ndr_err
;
308 switch (smb2_level
) {
310 io
= talloc(op
, union smb_setfileinfo
);
311 NT_STATUS_HAVE_NO_MEMORY(io
);
313 io
->set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
314 io
->set_secdesc
.in
.file
.ntvfs
= op
->info
->in
.file
.ntvfs
;
315 io
->set_secdesc
.in
.secinfo_flags
= op
->info
->in
.flags
;
317 io
->set_secdesc
.in
.sd
= talloc(io
, struct security_descriptor
);
318 NT_STATUS_HAVE_NO_MEMORY(io
->set_secdesc
.in
.sd
);
320 ndr_err
= ndr_pull_struct_blob(&op
->info
->in
.blob
, io
, NULL
,
321 io
->set_secdesc
.in
.sd
,
322 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
323 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
324 return ndr_map_error2ntstatus(ndr_err
);
327 return ntvfs_setfileinfo(op
->req
->ntvfs
, io
);
330 return NT_STATUS_INVALID_INFO_CLASS
;
333 static NTSTATUS
smb2srv_setinfo_backend(struct smb2srv_setinfo_op
*op
)
338 smb2_class
= 0xFF & op
->info
->in
.level
;
339 smb2_level
= 0xFF & (op
->info
->in
.level
>>8);
341 switch (smb2_class
) {
342 case SMB2_GETINFO_FILE
:
343 return smb2srv_setinfo_file(op
, smb2_level
);
345 case SMB2_GETINFO_FS
:
346 return smb2srv_setinfo_fs(op
, smb2_level
);
348 case SMB2_GETINFO_SECURITY
:
349 return smb2srv_setinfo_security(op
, smb2_level
);
352 return NT_STATUS_NOT_SUPPORTED
;
355 return NT_STATUS_INVALID_PARAMETER
;
358 void smb2srv_setinfo_recv(struct smb2srv_request
*req
)
360 struct smb2_setinfo
*info
;
361 struct smb2srv_setinfo_op
*op
;
363 SMB2SRV_CHECK_BODY_SIZE(req
, 0x20, true);
364 SMB2SRV_TALLOC_IO_PTR(info
, struct smb2_setinfo
);
365 /* this overwrites req->io_ptr !*/
366 SMB2SRV_TALLOC_IO_PTR(op
, struct smb2srv_setinfo_op
);
369 SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_setinfo_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
371 info
->in
.level
= SVAL(req
->in
.body
, 0x02);
372 SMB2SRV_CHECK(smb2_pull_s32o16_blob(&req
->in
, info
, req
->in
.body
+0x04, &info
->in
.blob
));
373 info
->in
.flags
= IVAL(req
->in
.body
, 0x0C);
374 info
->in
.file
.ntvfs
= smb2srv_pull_handle(req
, req
->in
.body
, 0x10);
376 SMB2SRV_CHECK_FILE_HANDLE(info
->in
.file
.ntvfs
);
377 SMB2SRV_CALL_NTVFS_BACKEND(smb2srv_setinfo_backend(op
));