2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
5 Copyright Matthieu Patou 2010 mat@matws.net
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 This file handles the parsing of transact2 requests
25 #include "smbd/service_stream.h"
26 #include "smb_server/smb_server.h"
27 #include "ntvfs/ntvfs.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "libcli/raw/raw_proto.h"
30 #include "librpc/gen_ndr/dfsblobs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "auth/session.h"
34 #include "param/param.h"
35 #include "lib/tsocket/tsocket.h"
37 #define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
39 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
40 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
41 trans2_setup_reply(trans, 0, 0, 0);\
42 return req->ntvfs->async_states->status; \
45 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
46 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
47 ptr = talloc_get_type(op->op_info, type); \
49 #define TRANS2_CHECK(cmd) do { \
52 NT_STATUS_NOT_OK_RETURN(_status); \
56 hold the state of a nttrans op while in progress. Needed to allow for async backend
60 struct smbsrv_request
*req
;
61 struct smb_trans2
*trans
;
63 NTSTATUS (*send_fn
)(struct trans_op
*);
66 /* A DC set is a group of DC, they might have been grouped together
67 because they belong to the same site, or to site with same cost ...
73 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
74 if ((blob)->length < (size)) { \
75 return NT_STATUS_INFO_LENGTH_MISMATCH; \
78 /* setup a trans2 reply, given the data and params sizes */
79 static NTSTATUS
trans2_setup_reply(struct smb_trans2
*trans
,
80 uint16_t param_size
, uint16_t data_size
,
83 trans
->out
.setup_count
= setup_count
;
84 if (setup_count
> 0) {
85 trans
->out
.setup
= talloc_zero_array(trans
, uint16_t, setup_count
);
86 NT_STATUS_HAVE_NO_MEMORY(trans
->out
.setup
);
88 trans
->out
.params
= data_blob_talloc(trans
, NULL
, param_size
);
89 if (param_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.params
.data
);
91 trans
->out
.data
= data_blob_talloc(trans
, NULL
, data_size
);
92 if (data_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.data
.data
);
97 static NTSTATUS
trans2_push_fsinfo(struct smbsrv_connection
*smb_conn
,
100 union smb_fsinfo
*fsinfo
,
101 int default_str_flags
)
103 enum smb_fsinfo_level passthru_level
;
105 switch (fsinfo
->generic
.level
) {
106 case RAW_QFS_ALLOCATION
:
107 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 18));
109 SIVAL(blob
->data
, 0, fsinfo
->allocation
.out
.fs_id
);
110 SIVAL(blob
->data
, 4, fsinfo
->allocation
.out
.sectors_per_unit
);
111 SIVAL(blob
->data
, 8, fsinfo
->allocation
.out
.total_alloc_units
);
112 SIVAL(blob
->data
, 12, fsinfo
->allocation
.out
.avail_alloc_units
);
113 SSVAL(blob
->data
, 16, fsinfo
->allocation
.out
.bytes_per_sector
);
118 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 5));
120 SIVAL(blob
->data
, 0, fsinfo
->volume
.out
.serial_number
);
121 /* w2k3 implements this incorrectly for unicode - it
122 * leaves the last byte off the string */
123 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx
, blob
,
124 fsinfo
->volume
.out
.volume_name
.s
,
125 4, default_str_flags
,
126 STR_LEN8BIT
|STR_NOALIGN
));
130 case RAW_QFS_VOLUME_INFO
:
131 passthru_level
= RAW_QFS_VOLUME_INFORMATION
;
134 case RAW_QFS_SIZE_INFO
:
135 passthru_level
= RAW_QFS_SIZE_INFORMATION
;
138 case RAW_QFS_DEVICE_INFO
:
139 passthru_level
= RAW_QFS_DEVICE_INFORMATION
;
142 case RAW_QFS_ATTRIBUTE_INFO
:
143 passthru_level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
147 passthru_level
= fsinfo
->generic
.level
;
151 return smbsrv_push_passthru_fsinfo(mem_ctx
, blob
,
152 passthru_level
, fsinfo
,
157 trans2 qfsinfo implementation send
159 static NTSTATUS
trans2_qfsinfo_send(struct trans_op
*op
)
161 struct smbsrv_request
*req
= op
->req
;
162 struct smb_trans2
*trans
= op
->trans
;
163 union smb_fsinfo
*fsinfo
;
165 TRANS2_CHECK_ASYNC_STATUS(fsinfo
, union smb_fsinfo
);
167 TRANS2_CHECK(trans2_setup_reply(trans
, 0, 0, 0));
169 TRANS2_CHECK(trans2_push_fsinfo(req
->smb_conn
, trans
,
170 &trans
->out
.data
, fsinfo
,
171 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
177 trans2 qfsinfo implementation
179 static NTSTATUS
trans2_qfsinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
181 struct smb_trans2
*trans
= op
->trans
;
182 union smb_fsinfo
*fsinfo
;
185 /* make sure we got enough parameters */
186 if (trans
->in
.params
.length
!= 2) {
187 return NT_STATUS_FOOBAR
;
190 fsinfo
= talloc(op
, union smb_fsinfo
);
191 NT_STATUS_HAVE_NO_MEMORY(fsinfo
);
193 level
= SVAL(trans
->in
.params
.data
, 0);
195 /* work out the backend level - we make it 1-1 in the header */
196 fsinfo
->generic
.level
= (enum smb_fsinfo_level
)level
;
197 if (fsinfo
->generic
.level
>= RAW_QFS_GENERIC
) {
198 return NT_STATUS_INVALID_LEVEL
;
201 op
->op_info
= fsinfo
;
202 op
->send_fn
= trans2_qfsinfo_send
;
204 return ntvfs_fsinfo(req
->ntvfs
, fsinfo
);
209 trans2 open implementation send
211 static NTSTATUS
trans2_open_send(struct trans_op
*op
)
213 struct smbsrv_request
*req
= op
->req
;
214 struct smb_trans2
*trans
= op
->trans
;
217 TRANS2_CHECK_ASYNC_STATUS(io
, union smb_open
);
219 TRANS2_CHECK(trans2_setup_reply(trans
, 30, 0, 0));
221 smbsrv_push_fnum(trans
->out
.params
.data
, VWV(0), io
->t2open
.out
.file
.ntvfs
);
222 SSVAL(trans
->out
.params
.data
, VWV(1), io
->t2open
.out
.attrib
);
223 srv_push_dos_date3(req
->smb_conn
, trans
->out
.params
.data
,
224 VWV(2), io
->t2open
.out
.write_time
);
225 SIVAL(trans
->out
.params
.data
, VWV(4), io
->t2open
.out
.size
);
226 SSVAL(trans
->out
.params
.data
, VWV(6), io
->t2open
.out
.access
);
227 SSVAL(trans
->out
.params
.data
, VWV(7), io
->t2open
.out
.ftype
);
228 SSVAL(trans
->out
.params
.data
, VWV(8), io
->t2open
.out
.devstate
);
229 SSVAL(trans
->out
.params
.data
, VWV(9), io
->t2open
.out
.action
);
230 SIVAL(trans
->out
.params
.data
, VWV(10), 0); /* reserved */
231 SSVAL(trans
->out
.params
.data
, VWV(12), 0); /* EaErrorOffset */
232 SIVAL(trans
->out
.params
.data
, VWV(13), 0); /* EaLength */
238 trans2 open implementation
240 static NTSTATUS
trans2_open(struct smbsrv_request
*req
, struct trans_op
*op
)
242 struct smb_trans2
*trans
= op
->trans
;
245 /* make sure we got enough parameters */
246 if (trans
->in
.params
.length
< 29) {
247 return NT_STATUS_FOOBAR
;
250 io
= talloc(op
, union smb_open
);
251 NT_STATUS_HAVE_NO_MEMORY(io
);
253 io
->t2open
.level
= RAW_OPEN_T2OPEN
;
254 io
->t2open
.in
.flags
= SVAL(trans
->in
.params
.data
, VWV(0));
255 io
->t2open
.in
.open_mode
= SVAL(trans
->in
.params
.data
, VWV(1));
256 io
->t2open
.in
.search_attrs
= SVAL(trans
->in
.params
.data
, VWV(2));
257 io
->t2open
.in
.file_attrs
= SVAL(trans
->in
.params
.data
, VWV(3));
258 io
->t2open
.in
.write_time
= srv_pull_dos_date(req
->smb_conn
,
259 trans
->in
.params
.data
+ VWV(4));
260 io
->t2open
.in
.open_func
= SVAL(trans
->in
.params
.data
, VWV(6));
261 io
->t2open
.in
.size
= IVAL(trans
->in
.params
.data
, VWV(7));
262 io
->t2open
.in
.timeout
= IVAL(trans
->in
.params
.data
, VWV(9));
263 io
->t2open
.in
.num_eas
= 0;
264 io
->t2open
.in
.eas
= NULL
;
266 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 28, &io
->t2open
.in
.fname
, 0);
267 if (io
->t2open
.in
.fname
== NULL
) {
268 return NT_STATUS_FOOBAR
;
271 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
, &io
->t2open
.in
.num_eas
, &io
->t2open
.in
.eas
));
274 op
->send_fn
= trans2_open_send
;
276 return ntvfs_open(req
->ntvfs
, io
);
283 static NTSTATUS
trans2_simple_send(struct trans_op
*op
)
285 struct smbsrv_request
*req
= op
->req
;
286 struct smb_trans2
*trans
= op
->trans
;
288 TRANS2_CHECK_ASYNC_STATUS_SIMPLE
;
290 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
292 SSVAL(trans
->out
.params
.data
, VWV(0), 0);
298 trans2 mkdir implementation
300 static NTSTATUS
trans2_mkdir(struct smbsrv_request
*req
, struct trans_op
*op
)
302 struct smb_trans2
*trans
= op
->trans
;
305 /* make sure we got enough parameters */
306 if (trans
->in
.params
.length
< 5) {
307 return NT_STATUS_FOOBAR
;
310 io
= talloc(op
, union smb_mkdir
);
311 NT_STATUS_HAVE_NO_MEMORY(io
);
313 io
->t2mkdir
.level
= RAW_MKDIR_T2MKDIR
;
314 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 4, &io
->t2mkdir
.in
.path
, 0);
315 if (io
->t2mkdir
.in
.path
== NULL
) {
316 return NT_STATUS_FOOBAR
;
319 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
,
320 &io
->t2mkdir
.in
.num_eas
,
321 &io
->t2mkdir
.in
.eas
));
324 op
->send_fn
= trans2_simple_send
;
326 return ntvfs_mkdir(req
->ntvfs
, io
);
329 static NTSTATUS
trans2_push_fileinfo(struct smbsrv_connection
*smb_conn
,
332 union smb_fileinfo
*st
,
333 int default_str_flags
)
336 enum smb_fileinfo_level passthru_level
;
338 switch (st
->generic
.level
) {
339 case RAW_FILEINFO_GENERIC
:
340 case RAW_FILEINFO_GETATTR
:
341 case RAW_FILEINFO_GETATTRE
:
342 case RAW_FILEINFO_SEC_DESC
:
343 case RAW_FILEINFO_SMB2_ALL_EAS
:
344 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
345 /* handled elsewhere */
346 return NT_STATUS_INVALID_LEVEL
;
348 case RAW_FILEINFO_UNIX_BASIC
:
349 case RAW_FILEINFO_UNIX_LINK
:
350 /* not implemented yet */
351 return NT_STATUS_INVALID_LEVEL
;
353 case RAW_FILEINFO_STANDARD
:
354 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 22));
356 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->standard
.out
.create_time
);
357 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->standard
.out
.access_time
);
358 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->standard
.out
.write_time
);
359 SIVAL(blob
->data
, 12, st
->standard
.out
.size
);
360 SIVAL(blob
->data
, 16, st
->standard
.out
.alloc_size
);
361 SSVAL(blob
->data
, 20, st
->standard
.out
.attrib
);
364 case RAW_FILEINFO_EA_SIZE
:
365 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 26));
367 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->ea_size
.out
.create_time
);
368 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->ea_size
.out
.access_time
);
369 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->ea_size
.out
.write_time
);
370 SIVAL(blob
->data
, 12, st
->ea_size
.out
.size
);
371 SIVAL(blob
->data
, 16, st
->ea_size
.out
.alloc_size
);
372 SSVAL(blob
->data
, 20, st
->ea_size
.out
.attrib
);
373 SIVAL(blob
->data
, 22, st
->ea_size
.out
.ea_size
);
376 case RAW_FILEINFO_EA_LIST
:
377 list_size
= ea_list_size(st
->ea_list
.out
.num_eas
,
378 st
->ea_list
.out
.eas
);
379 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
381 ea_put_list(blob
->data
,
382 st
->ea_list
.out
.num_eas
, st
->ea_list
.out
.eas
);
385 case RAW_FILEINFO_ALL_EAS
:
386 list_size
= ea_list_size(st
->all_eas
.out
.num_eas
,
387 st
->all_eas
.out
.eas
);
388 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
390 ea_put_list(blob
->data
,
391 st
->all_eas
.out
.num_eas
, st
->all_eas
.out
.eas
);
394 case RAW_FILEINFO_IS_NAME_VALID
:
397 case RAW_FILEINFO_BASIC_INFO
:
398 passthru_level
= RAW_FILEINFO_BASIC_INFORMATION
;
401 case RAW_FILEINFO_STANDARD_INFO
:
402 passthru_level
= RAW_FILEINFO_STANDARD_INFORMATION
;
405 case RAW_FILEINFO_EA_INFO
:
406 passthru_level
= RAW_FILEINFO_EA_INFORMATION
;
409 case RAW_FILEINFO_COMPRESSION_INFO
:
410 passthru_level
= RAW_FILEINFO_COMPRESSION_INFORMATION
;
413 case RAW_FILEINFO_ALL_INFO
:
414 passthru_level
= RAW_FILEINFO_ALL_INFORMATION
;
417 case RAW_FILEINFO_NAME_INFO
:
418 passthru_level
= RAW_FILEINFO_NAME_INFORMATION
;
421 case RAW_FILEINFO_ALT_NAME_INFO
:
422 passthru_level
= RAW_FILEINFO_ALT_NAME_INFORMATION
;
425 case RAW_FILEINFO_STREAM_INFO
:
426 passthru_level
= RAW_FILEINFO_STREAM_INFORMATION
;
430 passthru_level
= st
->generic
.level
;
434 return smbsrv_push_passthru_fileinfo(mem_ctx
, blob
,
440 fill in the reply from a qpathinfo or qfileinfo call
442 static NTSTATUS
trans2_fileinfo_send(struct trans_op
*op
)
444 struct smbsrv_request
*req
= op
->req
;
445 struct smb_trans2
*trans
= op
->trans
;
446 union smb_fileinfo
*st
;
448 TRANS2_CHECK_ASYNC_STATUS(st
, union smb_fileinfo
);
450 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
451 SSVAL(trans
->out
.params
.data
, 0, 0);
453 TRANS2_CHECK(trans2_push_fileinfo(req
->smb_conn
, trans
,
454 &trans
->out
.data
, st
,
455 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
461 trans2 qpathinfo implementation
463 static NTSTATUS
trans2_qpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
465 struct smb_trans2
*trans
= op
->trans
;
466 union smb_fileinfo
*st
;
469 /* make sure we got enough parameters */
470 if (trans
->in
.params
.length
< 2) {
471 return NT_STATUS_FOOBAR
;
474 st
= talloc(op
, union smb_fileinfo
);
475 NT_STATUS_HAVE_NO_MEMORY(st
);
477 level
= SVAL(trans
->in
.params
.data
, 0);
479 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
480 if (st
->generic
.in
.file
.path
== NULL
) {
481 return NT_STATUS_FOOBAR
;
484 /* work out the backend level - we make it 1-1 in the header */
485 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
486 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
487 return NT_STATUS_INVALID_LEVEL
;
490 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
491 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
492 &st
->ea_list
.in
.num_names
,
493 &st
->ea_list
.in
.ea_names
));
497 op
->send_fn
= trans2_fileinfo_send
;
499 return ntvfs_qpathinfo(req
->ntvfs
, st
);
504 trans2 qpathinfo implementation
506 static NTSTATUS
trans2_qfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
508 struct smb_trans2
*trans
= op
->trans
;
509 union smb_fileinfo
*st
;
511 struct ntvfs_handle
*h
;
513 /* make sure we got enough parameters */
514 if (trans
->in
.params
.length
< 4) {
515 return NT_STATUS_FOOBAR
;
518 st
= talloc(op
, union smb_fileinfo
);
519 NT_STATUS_HAVE_NO_MEMORY(st
);
521 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
522 level
= SVAL(trans
->in
.params
.data
, 2);
524 st
->generic
.in
.file
.ntvfs
= h
;
525 /* work out the backend level - we make it 1-1 in the header */
526 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
527 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
528 return NT_STATUS_INVALID_LEVEL
;
531 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
532 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
533 &st
->ea_list
.in
.num_names
,
534 &st
->ea_list
.in
.ea_names
));
538 op
->send_fn
= trans2_fileinfo_send
;
540 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
541 return ntvfs_qfileinfo(req
->ntvfs
, st
);
546 parse a trans2 setfileinfo/setpathinfo data blob
548 static NTSTATUS
trans2_parse_sfileinfo(struct smbsrv_request
*req
,
549 union smb_setfileinfo
*st
,
550 const DATA_BLOB
*blob
)
552 enum smb_setfileinfo_level passthru_level
;
554 switch (st
->generic
.level
) {
555 case RAW_SFILEINFO_GENERIC
:
556 case RAW_SFILEINFO_SETATTR
:
557 case RAW_SFILEINFO_SETATTRE
:
558 case RAW_SFILEINFO_SEC_DESC
:
559 /* handled elsewhere */
560 return NT_STATUS_INVALID_LEVEL
;
562 case RAW_SFILEINFO_STANDARD
:
563 CHECK_MIN_BLOB_SIZE(blob
, 12);
565 st
->standard
.in
.create_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 0);
566 st
->standard
.in
.access_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 4);
567 st
->standard
.in
.write_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 8);
571 case RAW_SFILEINFO_EA_SET
:
572 return ea_pull_list(blob
, req
,
573 &st
->ea_set
.in
.num_eas
,
576 case SMB_SFILEINFO_BASIC_INFO
:
577 case SMB_SFILEINFO_BASIC_INFORMATION
:
578 passthru_level
= SMB_SFILEINFO_BASIC_INFORMATION
;
581 case SMB_SFILEINFO_DISPOSITION_INFO
:
582 case SMB_SFILEINFO_DISPOSITION_INFORMATION
:
583 passthru_level
= SMB_SFILEINFO_DISPOSITION_INFORMATION
;
586 case SMB_SFILEINFO_ALLOCATION_INFO
:
587 case SMB_SFILEINFO_ALLOCATION_INFORMATION
:
588 passthru_level
= SMB_SFILEINFO_ALLOCATION_INFORMATION
;
591 case RAW_SFILEINFO_END_OF_FILE_INFO
:
592 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
593 passthru_level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
596 case RAW_SFILEINFO_RENAME_INFORMATION
:
597 case RAW_SFILEINFO_POSITION_INFORMATION
:
598 case RAW_SFILEINFO_MODE_INFORMATION
:
599 passthru_level
= st
->generic
.level
;
602 case RAW_SFILEINFO_UNIX_BASIC
:
603 case RAW_SFILEINFO_UNIX_LINK
:
604 case RAW_SFILEINFO_UNIX_HLINK
:
605 case RAW_SFILEINFO_PIPE_INFORMATION
:
606 case RAW_SFILEINFO_VALID_DATA_INFORMATION
:
607 case RAW_SFILEINFO_SHORT_NAME_INFORMATION
:
608 case RAW_SFILEINFO_1025
:
609 case RAW_SFILEINFO_1027
:
610 case RAW_SFILEINFO_1029
:
611 case RAW_SFILEINFO_1030
:
612 case RAW_SFILEINFO_1031
:
613 case RAW_SFILEINFO_1032
:
614 case RAW_SFILEINFO_1036
:
615 case RAW_SFILEINFO_1041
:
616 case RAW_SFILEINFO_1042
:
617 case RAW_SFILEINFO_1043
:
618 case RAW_SFILEINFO_1044
:
619 return NT_STATUS_INVALID_LEVEL
;
622 /* we need a default here to cope with invalid values on the wire */
623 return NT_STATUS_INVALID_LEVEL
;
626 return smbsrv_pull_passthru_sfileinfo(st
, passthru_level
, st
,
627 blob
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
632 trans2 setfileinfo implementation
634 static NTSTATUS
trans2_setfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
636 struct smb_trans2
*trans
= op
->trans
;
637 union smb_setfileinfo
*st
;
639 struct ntvfs_handle
*h
;
641 /* make sure we got enough parameters */
642 if (trans
->in
.params
.length
< 4) {
643 return NT_STATUS_FOOBAR
;
646 st
= talloc(op
, union smb_setfileinfo
);
647 NT_STATUS_HAVE_NO_MEMORY(st
);
649 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
650 level
= SVAL(trans
->in
.params
.data
, 2);
652 st
->generic
.in
.file
.ntvfs
= h
;
653 /* work out the backend level - we make it 1-1 in the header */
654 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
655 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
656 return NT_STATUS_INVALID_LEVEL
;
659 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
662 op
->send_fn
= trans2_simple_send
;
664 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
665 return ntvfs_setfileinfo(req
->ntvfs
, st
);
669 trans2 setpathinfo implementation
671 static NTSTATUS
trans2_setpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
673 struct smb_trans2
*trans
= op
->trans
;
674 union smb_setfileinfo
*st
;
677 /* make sure we got enough parameters */
678 if (trans
->in
.params
.length
< 4) {
679 return NT_STATUS_FOOBAR
;
682 st
= talloc(op
, union smb_setfileinfo
);
683 NT_STATUS_HAVE_NO_MEMORY(st
);
685 level
= SVAL(trans
->in
.params
.data
, 0);
687 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
688 if (st
->generic
.in
.file
.path
== NULL
) {
689 return NT_STATUS_FOOBAR
;
692 /* work out the backend level - we make it 1-1 in the header */
693 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
694 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
695 return NT_STATUS_INVALID_LEVEL
;
698 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
701 op
->send_fn
= trans2_simple_send
;
703 return ntvfs_setpathinfo(req
->ntvfs
, st
);
707 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
711 enum smb_search_data_level data_level
;
712 uint16_t last_entry_offset
;
717 fill a single entry in a trans2 find reply
719 static NTSTATUS
find_fill_info(struct find_state
*state
,
720 const union smb_search_data
*file
)
722 struct smbsrv_request
*req
= state
->op
->req
;
723 struct smb_trans2
*trans
= state
->op
->trans
;
725 unsigned int ofs
= trans
->out
.data
.length
;
728 switch (state
->data_level
) {
729 case RAW_SEARCH_DATA_GENERIC
:
730 case RAW_SEARCH_DATA_SEARCH
:
731 /* handled elsewhere */
732 return NT_STATUS_INVALID_LEVEL
;
734 case RAW_SEARCH_DATA_STANDARD
:
735 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
736 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
737 SIVAL(trans
->out
.data
.data
, ofs
, file
->standard
.resume_key
);
740 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23));
742 data
= trans
->out
.data
.data
+ ofs
;
743 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->standard
.create_time
);
744 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->standard
.access_time
);
745 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->standard
.write_time
);
746 SIVAL(data
, 12, file
->standard
.size
);
747 SIVAL(data
, 16, file
->standard
.alloc_size
);
748 SSVAL(data
, 20, file
->standard
.attrib
);
749 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->standard
.name
.s
,
750 ofs
+ 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
751 STR_LEN8BIT
| STR_TERMINATE
| STR_LEN_NOTERM
));
754 case RAW_SEARCH_DATA_EA_SIZE
:
755 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
756 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 31));
757 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_size
.resume_key
);
760 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
762 data
= trans
->out
.data
.data
+ ofs
;
763 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_size
.create_time
);
764 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_size
.access_time
);
765 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_size
.write_time
);
766 SIVAL(data
, 12, file
->ea_size
.size
);
767 SIVAL(data
, 16, file
->ea_size
.alloc_size
);
768 SSVAL(data
, 20, file
->ea_size
.attrib
);
769 SIVAL(data
, 22, file
->ea_size
.ea_size
);
770 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_size
.name
.s
,
771 ofs
+ 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
772 STR_LEN8BIT
| STR_NOALIGN
));
773 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
776 case RAW_SEARCH_DATA_EA_LIST
:
777 ea_size
= ea_list_size(file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
778 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
779 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27 + ea_size
));
780 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_list
.resume_key
);
783 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23 + ea_size
));
785 data
= trans
->out
.data
.data
+ ofs
;
786 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_list
.create_time
);
787 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_list
.access_time
);
788 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_list
.write_time
);
789 SIVAL(data
, 12, file
->ea_list
.size
);
790 SIVAL(data
, 16, file
->ea_list
.alloc_size
);
791 SSVAL(data
, 20, file
->ea_list
.attrib
);
792 ea_put_list(data
+22, file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
793 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_list
.name
.s
,
794 ofs
+ 22 + ea_size
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
795 STR_LEN8BIT
| STR_NOALIGN
));
796 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
799 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
800 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
801 case RAW_SEARCH_DATA_NAME_INFO
:
802 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
803 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
804 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
805 return smbsrv_push_passthru_search(trans
, &trans
->out
.data
, state
->data_level
, file
,
806 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
));
808 case RAW_SEARCH_DATA_UNIX_INFO
:
809 case RAW_SEARCH_DATA_UNIX_INFO2
:
810 return NT_STATUS_INVALID_LEVEL
;
816 /* callback function for trans2 findfirst/findnext */
817 static bool find_callback(void *private_data
, const union smb_search_data
*file
)
819 struct find_state
*state
= talloc_get_type(private_data
, struct find_state
);
820 struct smb_trans2
*trans
= state
->op
->trans
;
821 unsigned int old_length
;
823 old_length
= trans
->out
.data
.length
;
825 if (!NT_STATUS_IS_OK(find_fill_info(state
, file
)) ||
826 trans
->out
.data
.length
> trans
->in
.max_data
) {
827 /* restore the old length and tell the backend to stop */
828 smbsrv_blob_grow_data(trans
, &trans
->out
.data
, old_length
);
832 state
->last_entry_offset
= old_length
;
837 trans2 findfirst send
839 static NTSTATUS
trans2_findfirst_send(struct trans_op
*op
)
841 struct smbsrv_request
*req
= op
->req
;
842 struct smb_trans2
*trans
= op
->trans
;
843 union smb_search_first
*search
;
844 struct find_state
*state
;
847 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
848 search
= talloc_get_type(state
->search
, union smb_search_first
);
850 /* fill in the findfirst reply header */
851 param
= trans
->out
.params
.data
;
852 SSVAL(param
, VWV(0), search
->t2ffirst
.out
.handle
);
853 SSVAL(param
, VWV(1), search
->t2ffirst
.out
.count
);
854 SSVAL(param
, VWV(2), search
->t2ffirst
.out
.end_of_search
);
855 SSVAL(param
, VWV(3), 0);
856 SSVAL(param
, VWV(4), state
->last_entry_offset
);
863 fill a referral type structure
865 static NTSTATUS
fill_normal_dfs_referraltype(struct dfs_referral_type
*ref
,
867 const char *dfs_path
,
868 const char *server_path
, int isfirstoffset
)
874 ref
->version
= version
;
875 ref
->referral
.v3
.server_type
= DFS_SERVER_NON_ROOT
;
876 /* "normal" referral seems to always include the GUID */
877 ref
->referral
.v3
.size
= 34;
879 ref
->referral
.v3
.entry_flags
= 0;
880 ref
->referral
.v3
.ttl
= 600; /* As w2k3 */
881 ref
->referral
.v3
.referrals
.r1
.DFS_path
= dfs_path
;
882 ref
->referral
.v3
.referrals
.r1
.DFS_alt_path
= dfs_path
;
883 ref
->referral
.v3
.referrals
.r1
.netw_address
= server_path
;
887 ref
->version
= version
;
888 ref
->referral
.v4
.server_type
= DFS_SERVER_NON_ROOT
;
889 /* "normal" referral seems to always include the GUID */
890 ref
->referral
.v4
.size
= 34;
893 ref
->referral
.v4
.entry_flags
= DFS_HEADER_FLAG_TARGET_BCK
;
895 ref
->referral
.v4
.ttl
= 900; /* As w2k8r2 */
896 ref
->referral
.v4
.referrals
.r1
.DFS_path
= dfs_path
;
897 ref
->referral
.v4
.referrals
.r1
.DFS_alt_path
= dfs_path
;
898 ref
->referral
.v4
.referrals
.r1
.netw_address
= server_path
;
902 return NT_STATUS_INVALID_LEVEL
;
906 fill a domain refererral
908 static NTSTATUS
fill_domain_dfs_referraltype(struct dfs_referral_type
*ref
,
917 ref
->version
= version
;
918 ref
->referral
.v3
.server_type
= DFS_SERVER_NON_ROOT
;
919 /* It's hard coded ... don't think it's a good way but the sizeof return not the
922 * We have 18 if the GUID is not included 34 otherwise
925 /* Windows return without the guid when returning domain list
927 ref
->referral
.v3
.size
= 18;
929 ref
->referral
.v3
.size
= 34;
931 ref
->referral
.v3
.entry_flags
= DFS_FLAG_REFERRAL_DOMAIN_RESP
;
932 ref
->referral
.v3
.ttl
= 600; /* As w2k3 */
933 ref
->referral
.v3
.referrals
.r2
.special_name
= domain
;
934 ref
->referral
.v3
.referrals
.r2
.nb_expanded_names
= numnames
;
935 /* Put the final terminator */
937 const char **names2
= talloc_array(ref
, const char *, numnames
+1);
938 NT_STATUS_HAVE_NO_MEMORY(names2
);
940 for (i
= 0; i
<numnames
; i
++) {
941 names2
[i
] = talloc_asprintf(names2
, "\\%s", names
[i
]);
942 NT_STATUS_HAVE_NO_MEMORY(names2
[i
]);
944 names2
[numnames
] = 0;
945 ref
->referral
.v3
.referrals
.r2
.expanded_names
= names2
;
949 return NT_STATUS_INVALID_LEVEL
;
953 get the DCs list within a site
955 static NTSTATUS
get_dcs_insite(TALLOC_CTX
*ctx
, struct ldb_context
*ldb
,
956 struct ldb_dn
*sitedn
, struct dc_set
*list
,
959 static const char *attrs
[] = { "serverReference", NULL
};
960 static const char *attrs2
[] = { "dNSHostName", "sAMAccountName", NULL
};
961 struct ldb_result
*r
;
964 const char **dc_list
;
966 ret
= ldb_search(ldb
, ctx
, &r
, sitedn
, LDB_SCOPE_SUBTREE
, attrs
,
967 "(&(objectClass=server)(serverReference=*))");
968 if (ret
!= LDB_SUCCESS
) {
969 DEBUG(2,(__location__
": Failed to get list of servers - %s\n",
970 ldb_errstring(ldb
)));
971 return NT_STATUS_INTERNAL_ERROR
;
975 /* none in this site */
981 * need to search for all server object to know the size of the array.
982 * Search all the object of class server in this site
984 dc_list
= talloc_array(r
, const char *, r
->count
);
985 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list
, r
);
987 /* TODO put some random here in the order */
988 list
->names
= talloc_realloc(list
, list
->names
, const char *, list
->count
+ r
->count
);
989 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list
->names
, r
);
991 for (i
= 0; i
<r
->count
; i
++) {
993 struct ldb_result
*r2
;
995 dn
= ldb_msg_find_attr_as_dn(ldb
, ctx
, r
->msgs
[i
], "serverReference");
997 return NT_STATUS_INTERNAL_ERROR
;
1000 ret
= ldb_search(ldb
, r
, &r2
, dn
, LDB_SCOPE_BASE
, attrs2
, "(objectClass=computer)");
1001 if (ret
!= LDB_SUCCESS
) {
1002 DEBUG(2,(__location__
": Search for computer on %s failed - %s\n",
1003 ldb_dn_get_linearized(dn
), ldb_errstring(ldb
)));
1004 return NT_STATUS_INTERNAL_ERROR
;
1008 const char *dns
= ldb_msg_find_attr_as_string(r2
->msgs
[0], "dNSHostName", NULL
);
1010 DEBUG(2,(__location__
": dNSHostName missing on %s\n",
1011 ldb_dn_get_linearized(dn
)));
1013 return NT_STATUS_INTERNAL_ERROR
;
1016 list
->names
[list
->count
] = talloc_strdup(list
->names
, dns
);
1017 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list
->names
[list
->count
], r
);
1020 const char *acct
= ldb_msg_find_attr_as_string(r2
->msgs
[0], "sAMAccountName", NULL
);
1022 DEBUG(2,(__location__
": sAMAccountName missing on %s\n",
1023 ldb_dn_get_linearized(dn
)));
1025 return NT_STATUS_INTERNAL_ERROR
;
1028 tmp
= talloc_strdup(list
->names
, acct
);
1029 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp
, r
);
1031 /* Netbios name is also the sAMAccountName for
1032 computer but without the final $ */
1033 tmp
[strlen(tmp
) - 1] = '\0';
1034 list
->names
[list
->count
] = tmp
;
1041 return NT_STATUS_OK
;
1048 static NTSTATUS
get_dcs(TALLOC_CTX
*ctx
, struct ldb_context
*ldb
,
1049 const char *searched_site
, bool need_fqdn
,
1050 struct dc_set
***pset_list
, uint32_t flags
)
1053 * Flags will be used later to indicate things like least-expensive
1054 * or same-site options
1056 const char *attrs_none
[] = { NULL
};
1057 const char *attrs3
[] = { "name", NULL
};
1058 struct ldb_dn
*configdn
, *sitedn
, *dn
, *sitescontainerdn
;
1059 struct ldb_result
*r
;
1060 struct dc_set
**set_list
= NULL
;
1063 uint32_t current_pos
= 0;
1065 TALLOC_CTX
*subctx
= talloc_new(ctx
);
1067 *pset_list
= set_list
= NULL
;
1069 subctx
= talloc_new(ctx
);
1070 NT_STATUS_HAVE_NO_MEMORY(subctx
);
1072 configdn
= ldb_get_config_basedn(ldb
);
1074 /* Let's search for the Site container */
1075 ret
= ldb_search(ldb
, subctx
, &r
, configdn
, LDB_SCOPE_SUBTREE
, attrs_none
,
1076 "(objectClass=sitesContainer)");
1077 if (ret
!= LDB_SUCCESS
) {
1078 DEBUG(2,(__location__
": Failed to find sitesContainer within %s - %s\n",
1079 ldb_dn_get_linearized(configdn
), ldb_errstring(ldb
)));
1080 talloc_free(subctx
);
1081 return NT_STATUS_INTERNAL_ERROR
;
1084 DEBUG(2,(__location__
": Expected 1 sitesContainer - found %u within %s\n",
1085 r
->count
, ldb_dn_get_linearized(configdn
)));
1086 talloc_free(subctx
);
1087 return NT_STATUS_INTERNAL_ERROR
;
1090 sitescontainerdn
= talloc_steal(subctx
, r
->msgs
[0]->dn
);
1094 * TODO: Here we should have a more subtle handling
1095 * for the case "same-site"
1097 ret
= ldb_search(ldb
, subctx
, &r
, sitescontainerdn
, LDB_SCOPE_SUBTREE
,
1098 attrs_none
, "(objectClass=server)");
1099 if (ret
!= LDB_SUCCESS
) {
1100 DEBUG(2,(__location__
": Failed to find servers within %s - %s\n",
1101 ldb_dn_get_linearized(sitescontainerdn
), ldb_errstring(ldb
)));
1102 talloc_free(subctx
);
1103 return NT_STATUS_INTERNAL_ERROR
;
1107 if (searched_site
!= NULL
) {
1108 ret
= ldb_search(ldb
, subctx
, &r
, configdn
, LDB_SCOPE_SUBTREE
,
1109 attrs_none
, "(&(name=%s)(objectClass=site))", searched_site
);
1110 if (ret
!= LDB_SUCCESS
) {
1111 talloc_free(subctx
);
1112 return NT_STATUS_FOOBAR
;
1113 } else if (r
->count
!= 1) {
1114 talloc_free(subctx
);
1115 return NT_STATUS_FOOBAR
;
1118 /* All of this was to get the DN of the searched_site */
1119 sitedn
= r
->msgs
[0]->dn
;
1121 set_list
= talloc_realloc(subctx
, set_list
, struct dc_set
*, current_pos
+1);
1122 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
, subctx
);
1124 set_list
[current_pos
] = talloc(set_list
, struct dc_set
);
1125 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
[current_pos
], subctx
);
1127 set_list
[current_pos
]->names
= NULL
;
1128 set_list
[current_pos
]->count
= 0;
1129 status
= get_dcs_insite(subctx
, ldb
, sitedn
,
1130 set_list
[current_pos
], need_fqdn
);
1131 if (!NT_STATUS_IS_OK(status
)) {
1132 DEBUG(2,(__location__
": Failed to get DC from site %s - %s\n",
1133 ldb_dn_get_linearized(sitedn
), nt_errstr(status
)));
1134 talloc_free(subctx
);
1141 /* Let's find all the sites */
1142 ret
= ldb_search(ldb
, subctx
, &r
, configdn
, LDB_SCOPE_SUBTREE
, attrs3
, "(objectClass=site)");
1143 if (ret
!= LDB_SUCCESS
) {
1144 DEBUG(2,(__location__
": Failed to find any site containers in %s\n",
1145 ldb_dn_get_linearized(configdn
)));
1146 talloc_free(subctx
);
1147 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1152 * We should randomize the order in the main site,
1153 * it's mostly needed for sysvol/netlogon referral.
1154 * Depending of flag we either randomize order of the
1155 * not "in the same site DCs"
1156 * or we randomize by group of site that have the same cost
1157 * In the long run we want to manipulate an array of site_set
1158 * All the site in one set have the same cost (if least-expansive options is selected)
1159 * and we will put all the dc related to 1 site set into 1 DCs set.
1160 * Within a site set, site order has to be randomized
1162 * But for the moment we just return the list of sites
1166 * We will realloc + 2 because we will need one additional place
1167 * for element at current_pos + 1 for the NULL element
1169 set_list
= talloc_realloc(subctx
, set_list
, struct dc_set
*,
1171 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
, subctx
);
1173 set_list
[current_pos
] = talloc(ctx
, struct dc_set
);
1174 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
[current_pos
], subctx
);
1176 set_list
[current_pos
]->names
= NULL
;
1177 set_list
[current_pos
]->count
= 0;
1179 set_list
[current_pos
+1] = NULL
;
1182 for (i
=0; i
<r
->count
; i
++) {
1183 const char *site_name
= ldb_msg_find_attr_as_string(r
->msgs
[i
], "name", NULL
);
1184 if (site_name
== NULL
) {
1185 DEBUG(2,(__location__
": Failed to find name attribute in %s\n",
1186 ldb_dn_get_linearized(r
->msgs
[i
]->dn
)));
1187 talloc_free(subctx
);
1188 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1191 if (searched_site
== NULL
||
1192 strcmp(searched_site
, site_name
) != 0) {
1193 DEBUG(2,(__location__
": Site: %s %s\n",
1194 searched_site
, site_name
));
1197 * Do all the site but the one of the client
1198 * (because it has already been done ...)
1200 dn
= r
->msgs
[i
]->dn
;
1202 status
= get_dcs_insite(subctx
, ldb
, dn
,
1203 set_list
[current_pos
],
1205 if (!NT_STATUS_IS_OK(status
)) {
1206 talloc_free(subctx
);
1212 set_list
[current_pos
] = NULL
;
1214 *pset_list
= talloc_move(ctx
, &set_list
);
1215 talloc_free(subctx
);
1216 return NT_STATUS_OK
;
1219 static NTSTATUS
dodomain_referral(TALLOC_CTX
*ctx
,
1220 const struct dfs_GetDFSReferral_in
*dfsreq
,
1221 struct ldb_context
*ldb
,
1222 struct smb_trans2
*trans
,
1223 struct loadparm_context
*lp_ctx
)
1226 * TODO for the moment we just return the local domain
1229 enum ndr_err_code ndr_err
;
1231 const char *dns_domain
= lpcfg_dnsdomain(lp_ctx
);
1232 const char *netbios_domain
= lpcfg_workgroup(lp_ctx
);
1233 struct dfs_referral_resp resp
;
1234 struct dfs_referral_type
*tab
;
1235 struct dfs_referral_type
*referral
;
1236 const char *referral_str
;
1237 /* In the future this needs to be fetched from the ldb */
1238 uint32_t found_domain
= 2;
1239 uint32_t current_pos
= 0;
1240 TALLOC_CTX
*context
;
1242 if (lpcfg_server_role(lp_ctx
) != ROLE_DOMAIN_CONTROLLER
) {
1243 DEBUG(10 ,("Received a domain referral request on a non DC\n"));
1244 return NT_STATUS_INVALID_PARAMETER
;
1247 if (dfsreq
->max_referral_level
< 3) {
1248 DEBUG(2,("invalid max_referral_level %u\n",
1249 dfsreq
->max_referral_level
));
1250 return NT_STATUS_UNSUCCESSFUL
;
1253 context
= talloc_new(ctx
);
1254 NT_STATUS_HAVE_NO_MEMORY(context
);
1256 resp
.path_consumed
= 0;
1257 resp
.header_flags
= 0; /* Do like w2k3 */
1258 resp
.nb_referrals
= found_domain
; /* the fqdn one + the NT domain */
1260 tab
= talloc_array(context
, struct dfs_referral_type
, found_domain
);
1261 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tab
, context
);
1263 referral
= talloc(tab
, struct dfs_referral_type
);
1264 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1265 referral_str
= talloc_asprintf(referral
, "\\%s", netbios_domain
);
1266 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1267 status
= fill_domain_dfs_referraltype(referral
, 3,
1270 if (!NT_STATUS_IS_OK(status
)) {
1271 DEBUG(2,(__location__
":Unable to fill domain referral structure\n"));
1272 talloc_free(context
);
1273 return NT_STATUS_UNSUCCESSFUL
;
1276 tab
[current_pos
] = *referral
;
1279 referral
= talloc(tab
, struct dfs_referral_type
);
1280 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1281 referral_str
= talloc_asprintf(referral
, "\\%s", dns_domain
);
1282 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1283 status
= fill_domain_dfs_referraltype(referral
, 3,
1286 if (!NT_STATUS_IS_OK(status
)) {
1287 DEBUG(2,(__location__
":Unable to fill domain referral structure\n"));
1288 talloc_free(context
);
1289 return NT_STATUS_UNSUCCESSFUL
;
1291 tab
[current_pos
] = *referral
;
1295 * Put here the code from filling the array for trusted domain
1297 resp
.referral_entries
= tab
;
1299 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1301 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1303 DEBUG(2,(__location__
":NDR marchalling of domain deferral response failed\n"));
1304 talloc_free(context
);
1305 return NT_STATUS_INTERNAL_ERROR
;
1308 if (outblob
.length
> trans
->in
.max_data
) {
1311 DEBUG(3, ("Blob is too big for the output buffer "
1313 (unsigned int)outblob
.length
, trans
->in
.max_data
));
1315 if (trans
->in
.max_data
!= MAX_DFS_RESPONSE
) {
1316 /* As specified in MS-DFSC.pdf 3.3.5.2 */
1317 talloc_free(context
);
1318 return STATUS_BUFFER_OVERFLOW
;
1322 * The answer is too big, so let's remove some answers
1324 while (!ok
&& resp
.nb_referrals
> 2) {
1325 data_blob_free(&outblob
);
1328 * Let's scrap the first referral (for now)
1330 resp
.nb_referrals
-= 1;
1331 resp
.referral_entries
+= 1;
1333 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1335 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1337 talloc_free(context
);
1338 return NT_STATUS_INTERNAL_ERROR
;
1341 if (outblob
.length
<= MAX_DFS_RESPONSE
) {
1342 DEBUG(10,("DFS: managed to reduce the size of referral initial"
1343 "number of referral %d, actual count: %d",
1344 found_domain
, resp
.nb_referrals
));
1350 if (!ok
&& resp
.nb_referrals
== 2) {
1351 DEBUG(0, (__location__
"; Not able to fit the domain and realm in DFS a "
1352 " 56K buffer, something must be broken"));
1353 talloc_free(context
);
1354 return NT_STATUS_INTERNAL_ERROR
;
1358 TRANS2_CHECK(trans2_setup_reply(trans
, 0, outblob
.length
, 0));
1360 trans
->out
.data
= outblob
;
1361 talloc_steal(ctx
, outblob
.data
);
1362 talloc_free(context
);
1363 return NT_STATUS_OK
;
1367 * Handle the logic for dfs referral request like \\domain
1368 * or \\domain\sysvol or \\fqdn or \\fqdn\netlogon
1370 static NTSTATUS
dodc_or_sysvol_referral(TALLOC_CTX
*ctx
,
1371 const struct dfs_GetDFSReferral_in dfsreq
,
1372 const char* requestedname
,
1373 struct ldb_context
*ldb
,
1374 struct smb_trans2
*trans
,
1375 struct smbsrv_request
*req
,
1376 struct loadparm_context
*lp_ctx
)
1379 * It's not a "standard" DFS referral but a referral to get the DC list
1380 * or sysvol/netlogon
1381 * Let's check that it's for one of our domain ...
1385 unsigned int num_domain
= 1;
1386 enum ndr_err_code ndr_err
;
1387 const char *requesteddomain
;
1388 const char *realm
= lpcfg_realm(lp_ctx
);
1389 const char *domain
= lpcfg_workgroup(lp_ctx
);
1390 const char *site_name
= NULL
; /* Name of the site where the client is */
1393 bool need_fqdn
= false;
1394 bool dc_referral
= true;
1397 struct dc_set
**set
;
1398 char const **domain_list
;
1399 struct tsocket_address
*remote_address
;
1400 char *client_addr
= NULL
;
1401 TALLOC_CTX
*context
;
1403 if (lpcfg_server_role(lp_ctx
) != ROLE_DOMAIN_CONTROLLER
) {
1404 return NT_STATUS_INVALID_PARAMETER
;
1407 if (dfsreq
.max_referral_level
< 3) {
1408 DEBUG(2,("invalid max_referral_level %u\n",
1409 dfsreq
.max_referral_level
));
1410 return NT_STATUS_UNSUCCESSFUL
;
1413 context
= talloc_new(ctx
);
1414 NT_STATUS_HAVE_NO_MEMORY(context
);
1416 if (requestedname
[0] == '\\' && !strchr(requestedname
+1,'\\')) {
1419 requesteddomain
= requestedname
;
1421 if (strchr(requestedname
,'\\')) {
1423 /* we have a second part */
1424 requesteddomain
= talloc_strdup(context
, requestedname
+1);
1425 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(requesteddomain
, context
);
1426 subpart
= strchr(requesteddomain
,'\\');
1429 tmp
= strchr(requestedname
+ 1,'\\'); /* To get second \ if any */
1432 /* There was a share */
1434 dc_referral
= false;
1438 * We will fetch the trusted domain list soon with something like this:
1440 * "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)
1441 * (trustPartner=%s))(objectclass=trustedDomain))"
1443 * Allocate for num_domain + 1 so that the last element will be NULL)
1445 domain_list
= talloc_array(context
, const char*, num_domain
+1);
1446 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_list
, context
);
1448 domain_list
[0] = realm
;
1449 domain_list
[1] = domain
;
1450 for (i
=0; i
<=num_domain
; i
++) {
1451 if (strncasecmp(domain_list
[i
], requesteddomain
, strlen(domain_list
[i
])) == 0) {
1458 /* The requested domain is not one that we support */
1459 DEBUG(3,("Requested referral for domain %s, but we don't handle it",
1461 return NT_STATUS_INVALID_PARAMETER
;
1464 if (strchr(requestedname
,'.')) {
1468 remote_address
= req
->smb_conn
->connection
->remote_address
;
1469 if (tsocket_address_is_inet(remote_address
, "ip")) {
1470 client_addr
= tsocket_address_inet_addr_string(remote_address
, context
);
1471 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_addr
, context
);
1474 status
= get_dcs(context
, ldb
, site_name
, need_fqdn
, &set
, 0);
1475 if (!NT_STATUS_IS_OK(status
)) {
1476 DEBUG(3,("Unable to get list of DCs\n"));
1477 talloc_free(context
);
1482 const char **dc_list
= NULL
;
1483 uint32_t num_dcs
= 0;
1484 struct dfs_referral_type
*referral
;
1485 const char *referral_str
;
1486 struct dfs_referral_resp resp
;
1488 for(i
=0; set
[i
]; i
++) {
1491 dc_list
= talloc_realloc(context
, dc_list
, const char*,
1492 num_dcs
+ set
[i
]->count
+ 1);
1493 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list
, context
);
1495 for(j
=0; j
<set
[i
]->count
; j
++) {
1496 dc_list
[num_dcs
+ j
] = talloc_steal(context
, set
[i
]->names
[j
]);
1498 num_dcs
= num_dcs
+ set
[i
]->count
;
1499 TALLOC_FREE(set
[i
]);
1500 dc_list
[num_dcs
] = NULL
;
1503 resp
.path_consumed
= 0;
1504 resp
.header_flags
= 0; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1507 * The NumberOfReferrals field MUST be set to 1,
1508 * independent of the number of DC names
1509 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1511 resp
.nb_referrals
= 1;
1513 /* Put here the code from filling the array for trusted domain */
1514 referral
= talloc(context
, struct dfs_referral_type
);
1515 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1517 referral_str
= talloc_asprintf(referral
, "\\%s",
1519 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1521 status
= fill_domain_dfs_referraltype(referral
, 3,
1524 if (!NT_STATUS_IS_OK(status
)) {
1525 DEBUG(2,(__location__
":Unable to fill domain referral structure\n"));
1526 talloc_free(context
);
1527 return NT_STATUS_UNSUCCESSFUL
;
1529 resp
.referral_entries
= referral
;
1531 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1533 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1534 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1535 DEBUG(2,(__location__
":NDR marshalling of dfs referral response failed\n"));
1536 talloc_free(context
);
1537 return NT_STATUS_INTERNAL_ERROR
;
1540 unsigned int nb_entries
= 0;
1541 unsigned int current
= 0;
1542 struct dfs_referral_type
*tab
;
1543 struct dfs_referral_resp resp
;
1545 for(i
=0; set
[i
]; i
++) {
1546 nb_entries
= nb_entries
+ set
[i
]->count
;
1549 resp
.path_consumed
= 2*strlen(requestedname
); /* The length is expected in bytes */
1550 resp
.header_flags
= DFS_HEADER_FLAG_STORAGE_SVR
; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1553 * The NumberOfReferrals field MUST be set to 1,
1554 * independent of the number of DC names
1555 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1557 resp
.nb_referrals
= nb_entries
;
1559 tab
= talloc_array(context
, struct dfs_referral_type
, nb_entries
);
1560 NT_STATUS_HAVE_NO_MEMORY(tab
);
1562 for(i
=0; set
[i
]; i
++) {
1565 for(j
=0; j
< set
[i
]->count
; j
++) {
1566 struct dfs_referral_type
*referral
;
1567 const char *referral_str
;
1569 referral
= talloc(tab
, struct dfs_referral_type
);
1570 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1572 referral_str
= talloc_asprintf(referral
, "\\%s\\%s",
1573 set
[i
]->names
[j
], share
);
1574 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1576 status
= fill_normal_dfs_referraltype(referral
,
1577 dfsreq
.max_referral_level
,
1578 requestedname
, referral_str
, j
==0);
1579 if (!NT_STATUS_IS_OK(status
)) {
1580 DEBUG(2, (__location__
": Unable to fill a normal dfs referral object"));
1581 talloc_free(context
);
1582 return NT_STATUS_UNSUCCESSFUL
;
1584 tab
[current
] = *referral
;
1588 resp
.referral_entries
= tab
;
1590 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1592 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1593 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1594 DEBUG(2,(__location__
":NDR marchalling of domain deferral response failed\n"));
1595 talloc_free(context
);
1596 return NT_STATUS_INTERNAL_ERROR
;
1600 TRANS2_CHECK(trans2_setup_reply(trans
, 0, outblob
.length
, 0));
1603 * TODO If the size is too big we should remove
1604 * some DC from the answer or return STATUS_BUFFER_OVERFLOW
1606 trans
->out
.data
= outblob
;
1607 talloc_steal(ctx
, outblob
.data
);
1608 talloc_free(context
);
1609 return NT_STATUS_OK
;
1613 trans2 getdfsreferral implementation
1615 static NTSTATUS
trans2_getdfsreferral(struct smbsrv_request
*req
,
1616 struct trans_op
*op
)
1618 enum ndr_err_code ndr_err
;
1619 struct smb_trans2
*trans
= op
->trans
;
1620 struct dfs_GetDFSReferral_in dfsreq
;
1621 TALLOC_CTX
*context
;
1622 struct ldb_context
*ldb
;
1623 struct loadparm_context
*lp_ctx
;
1624 const char *realm
, *nbname
, *requestedname
;
1628 lp_ctx
= req
->tcon
->ntvfs
->lp_ctx
;
1629 if (!lpcfg_host_msdfs(lp_ctx
)) {
1630 return NT_STATUS_NOT_IMPLEMENTED
;
1633 context
= talloc_new(req
);
1634 NT_STATUS_HAVE_NO_MEMORY(context
);
1636 ldb
= samdb_connect(context
, req
->tcon
->ntvfs
->event_ctx
, lp_ctx
, system_session(lp_ctx
), 0);
1638 DEBUG(2,(__location__
": Failed to open samdb\n"));
1639 talloc_free(context
);
1640 return NT_STATUS_INTERNAL_ERROR
;
1643 ndr_err
= ndr_pull_struct_blob(&trans
->in
.params
, op
,
1645 (ndr_pull_flags_fn_t
)ndr_pull_dfs_GetDFSReferral_in
);
1646 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1647 status
= ndr_map_error2ntstatus(ndr_err
);
1648 DEBUG(2,(__location__
": Failed to parse GetDFSReferral_in - %s\n",
1649 nt_errstr(status
)));
1650 talloc_free(context
);
1654 DEBUG(10, ("Requested DFS name: %s length: %u\n",
1655 dfsreq
.servername
, (unsigned int)strlen(dfsreq
.servername
)));
1658 * If the servername is "" then we are in a case of domain dfs
1659 * and the client just searches for the list of local domain
1660 * it is attached and also trusted ones.
1662 requestedname
= dfsreq
.servername
;
1663 if (requestedname
== NULL
|| requestedname
[0] == '\0') {
1664 return dodomain_referral(op
, &dfsreq
, ldb
, trans
, lp_ctx
);
1667 realm
= lpcfg_realm(lp_ctx
);
1668 nbname
= lpcfg_netbios_name(lp_ctx
);
1669 fqdn
= talloc_asprintf(context
, "%s.%s", nbname
, realm
);
1671 if ((strncasecmp(requestedname
+1, nbname
, strlen(nbname
)) == 0) ||
1672 (strncasecmp(requestedname
+1, fqdn
, strlen(fqdn
)) == 0) ) {
1674 * the referral request starts with \NETBIOSNAME or \fqdn
1675 * it's a standalone referral we do not do it
1676 * (TODO correct this)
1677 * If a DFS link that is a complete prefix of the DFS referral
1678 * request path is identified, the server MUST return a DFS link
1679 * referral response; otherwise, if it has a match for the DFS root,
1680 * it MUST return a root referral response.
1682 DEBUG(3, ("Received a standalone request for %s, we do not support standalone referral yet",requestedname
));
1683 talloc_free(context
);
1684 return NT_STATUS_NOT_FOUND
;
1688 tmp
= strchr(requestedname
+ 1,'\\'); /* To get second \ if any */
1691 * If we have no slash at the first position or (foo.bar.domain.net)
1692 * a slash at the first position but no other slash (\foo.bar.domain.net)
1693 * or a slash at the first position and another slash
1694 * and netlogon or sysvol after the second slash
1695 * (\foo.bar.domain.net\sysvol) then we will handle it because
1696 * it's either a dc referral or a sysvol/netlogon referral
1698 if (requestedname
[0] != '\\' ||
1700 strcasecmp(tmp
+1, "sysvol") == 0 ||
1701 strcasecmp(tmp
+1, "netlogon") == 0) {
1702 status
= dodc_or_sysvol_referral(op
, dfsreq
, requestedname
,
1703 ldb
, trans
, req
, lp_ctx
);
1704 talloc_free(context
);
1708 if (requestedname
[0] == '\\' &&
1710 strchr(tmp
+1, '\\') &&
1711 (strncasecmp(tmp
+1, "sysvol", 6) == 0 ||
1712 strncasecmp(tmp
+1, "netlogon", 8) == 0)) {
1714 * We have more than two \ so it something like
1715 * \domain\sysvol\foobar
1717 talloc_free(context
);
1718 return NT_STATUS_NOT_FOUND
;
1721 talloc_free(context
);
1722 /* By default until all the case are handled*/
1723 return NT_STATUS_NOT_FOUND
;
1727 trans2 findfirst implementation
1729 static NTSTATUS
trans2_findfirst(struct smbsrv_request
*req
, struct trans_op
*op
)
1731 struct smb_trans2
*trans
= op
->trans
;
1732 union smb_search_first
*search
;
1734 struct find_state
*state
;
1736 /* make sure we got all the parameters */
1737 if (trans
->in
.params
.length
< 14) {
1738 return NT_STATUS_FOOBAR
;
1741 search
= talloc(op
, union smb_search_first
);
1742 NT_STATUS_HAVE_NO_MEMORY(search
);
1744 search
->t2ffirst
.in
.search_attrib
= SVAL(trans
->in
.params
.data
, 0);
1745 search
->t2ffirst
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1746 search
->t2ffirst
.in
.flags
= SVAL(trans
->in
.params
.data
, 4);
1747 level
= SVAL(trans
->in
.params
.data
, 6);
1748 search
->t2ffirst
.in
.storage_type
= IVAL(trans
->in
.params
.data
, 8);
1750 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2ffirst
.in
.pattern
, 0);
1751 if (search
->t2ffirst
.in
.pattern
== NULL
) {
1752 return NT_STATUS_FOOBAR
;
1755 search
->t2ffirst
.level
= RAW_SEARCH_TRANS2
;
1756 search
->t2ffirst
.data_level
= (enum smb_search_data_level
)level
;
1757 if (search
->t2ffirst
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
1758 return NT_STATUS_INVALID_LEVEL
;
1761 if (search
->t2ffirst
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
1762 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
1763 &search
->t2ffirst
.in
.num_names
,
1764 &search
->t2ffirst
.in
.ea_names
));
1767 /* setup the private state structure that the backend will
1768 give us in the callback */
1769 state
= talloc(op
, struct find_state
);
1770 NT_STATUS_HAVE_NO_MEMORY(state
);
1772 state
->search
= search
;
1773 state
->data_level
= search
->t2ffirst
.data_level
;
1774 state
->last_entry_offset
= 0;
1775 state
->flags
= search
->t2ffirst
.in
.flags
;
1777 /* setup for just a header in the reply */
1778 TRANS2_CHECK(trans2_setup_reply(trans
, 10, 0, 0));
1780 op
->op_info
= state
;
1781 op
->send_fn
= trans2_findfirst_send
;
1783 return ntvfs_search_first(req
->ntvfs
, search
, state
, find_callback
);
1788 trans2 findnext send
1790 static NTSTATUS
trans2_findnext_send(struct trans_op
*op
)
1792 struct smbsrv_request
*req
= op
->req
;
1793 struct smb_trans2
*trans
= op
->trans
;
1794 union smb_search_next
*search
;
1795 struct find_state
*state
;
1798 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
1799 search
= talloc_get_type(state
->search
, union smb_search_next
);
1801 /* fill in the findfirst reply header */
1802 param
= trans
->out
.params
.data
;
1803 SSVAL(param
, VWV(0), search
->t2fnext
.out
.count
);
1804 SSVAL(param
, VWV(1), search
->t2fnext
.out
.end_of_search
);
1805 SSVAL(param
, VWV(2), 0);
1806 SSVAL(param
, VWV(3), state
->last_entry_offset
);
1808 return NT_STATUS_OK
;
1813 trans2 findnext implementation
1815 static NTSTATUS
trans2_findnext(struct smbsrv_request
*req
, struct trans_op
*op
)
1817 struct smb_trans2
*trans
= op
->trans
;
1818 union smb_search_next
*search
;
1820 struct find_state
*state
;
1822 /* make sure we got all the parameters */
1823 if (trans
->in
.params
.length
< 12) {
1824 return NT_STATUS_FOOBAR
;
1827 search
= talloc(op
, union smb_search_next
);
1828 NT_STATUS_HAVE_NO_MEMORY(search
);
1830 search
->t2fnext
.in
.handle
= SVAL(trans
->in
.params
.data
, 0);
1831 search
->t2fnext
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1832 level
= SVAL(trans
->in
.params
.data
, 4);
1833 search
->t2fnext
.in
.resume_key
= IVAL(trans
->in
.params
.data
, 6);
1834 search
->t2fnext
.in
.flags
= SVAL(trans
->in
.params
.data
, 10);
1836 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2fnext
.in
.last_name
, 0);
1837 if (search
->t2fnext
.in
.last_name
== NULL
) {
1838 return NT_STATUS_FOOBAR
;
1841 search
->t2fnext
.level
= RAW_SEARCH_TRANS2
;
1842 search
->t2fnext
.data_level
= (enum smb_search_data_level
)level
;
1843 if (search
->t2fnext
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
1844 return NT_STATUS_INVALID_LEVEL
;
1847 if (search
->t2fnext
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
1848 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
1849 &search
->t2fnext
.in
.num_names
,
1850 &search
->t2fnext
.in
.ea_names
));
1853 /* setup the private state structure that the backend will give us in the callback */
1854 state
= talloc(op
, struct find_state
);
1855 NT_STATUS_HAVE_NO_MEMORY(state
);
1857 state
->search
= search
;
1858 state
->data_level
= search
->t2fnext
.data_level
;
1859 state
->last_entry_offset
= 0;
1860 state
->flags
= search
->t2fnext
.in
.flags
;
1862 /* setup for just a header in the reply */
1863 TRANS2_CHECK(trans2_setup_reply(trans
, 8, 0, 0));
1865 op
->op_info
= state
;
1866 op
->send_fn
= trans2_findnext_send
;
1868 return ntvfs_search_next(req
->ntvfs
, search
, state
, find_callback
);
1873 backend for trans2 requests
1875 static NTSTATUS
trans2_backend(struct smbsrv_request
*req
, struct trans_op
*op
)
1877 struct smb_trans2
*trans
= op
->trans
;
1880 /* direct trans2 pass thru */
1881 status
= ntvfs_trans2(req
->ntvfs
, trans
);
1882 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED
, status
)) {
1886 /* must have at least one setup word */
1887 if (trans
->in
.setup_count
< 1) {
1888 return NT_STATUS_FOOBAR
;
1891 /* the trans2 command is in setup[0] */
1892 switch (trans
->in
.setup
[0]) {
1893 case TRANSACT2_GET_DFS_REFERRAL
:
1894 return trans2_getdfsreferral(req
, op
);
1895 case TRANSACT2_FINDFIRST
:
1896 return trans2_findfirst(req
, op
);
1897 case TRANSACT2_FINDNEXT
:
1898 return trans2_findnext(req
, op
);
1899 case TRANSACT2_QPATHINFO
:
1900 return trans2_qpathinfo(req
, op
);
1901 case TRANSACT2_QFILEINFO
:
1902 return trans2_qfileinfo(req
, op
);
1903 case TRANSACT2_SETFILEINFO
:
1904 return trans2_setfileinfo(req
, op
);
1905 case TRANSACT2_SETPATHINFO
:
1906 return trans2_setpathinfo(req
, op
);
1907 case TRANSACT2_QFSINFO
:
1908 return trans2_qfsinfo(req
, op
);
1909 case TRANSACT2_OPEN
:
1910 return trans2_open(req
, op
);
1911 case TRANSACT2_MKDIR
:
1912 return trans2_mkdir(req
, op
);
1915 /* an unknown trans2 command */
1916 return NT_STATUS_FOOBAR
;
1919 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial
*tp
)
1921 DLIST_REMOVE(tp
->req
->smb_conn
->trans_partial
, tp
);
1927 send a continue request
1929 static void reply_trans_continue(struct smbsrv_request
*req
, uint8_t command
,
1930 struct smb_trans2
*trans
)
1932 struct smbsrv_request
*req2
;
1933 struct smbsrv_trans_partial
*tp
;
1936 /* make sure they don't flood us */
1937 for (count
=0,tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) count
++;
1939 smbsrv_send_error(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1943 tp
= talloc(req
, struct smbsrv_trans_partial
);
1946 tp
->u
.trans
= trans
;
1947 tp
->command
= command
;
1949 DLIST_ADD(req
->smb_conn
->trans_partial
, tp
);
1950 talloc_set_destructor(tp
, smbsrv_trans_partial_destructor
);
1952 req2
= smbsrv_setup_secondary_request(req
);
1954 /* send a 'please continue' reply */
1955 smbsrv_setup_reply(req2
, 0, 0);
1956 smbsrv_send_reply(req2
);
1961 answer a reconstructed trans request
1963 static void reply_trans_send(struct ntvfs_request
*ntvfs
)
1965 struct smbsrv_request
*req
;
1966 struct trans_op
*op
;
1967 struct smb_trans2
*trans
;
1968 uint16_t params_left
, data_left
;
1969 uint8_t *params
, *data
;
1972 SMBSRV_CHECK_ASYNC_STATUS_ERR(op
, struct trans_op
);
1975 /* if this function needs work to form the nttrans reply buffer, then
1977 if (op
->send_fn
!= NULL
) {
1979 status
= op
->send_fn(op
);
1980 if (!NT_STATUS_IS_OK(status
)) {
1981 smbsrv_send_error(req
, status
);
1986 params_left
= trans
->out
.params
.length
;
1987 data_left
= trans
->out
.data
.length
;
1988 params
= trans
->out
.params
.data
;
1989 data
= trans
->out
.data
.data
;
1991 smbsrv_setup_reply(req
, 10 + trans
->out
.setup_count
, 0);
1993 if (!NT_STATUS_IS_OK(req
->ntvfs
->async_states
->status
)) {
1994 smbsrv_setup_error(req
, req
->ntvfs
->async_states
->status
);
1997 /* we need to divide up the reply into chunks that fit into
1998 the negotiated buffer size */
2000 uint16_t this_data
, this_param
, max_bytes
;
2001 unsigned int align1
= 1, align2
= (params_left
? 2 : 0);
2002 struct smbsrv_request
*this_req
;
2004 max_bytes
= req_max_data(req
) - (align1
+ align2
);
2006 this_param
= params_left
;
2007 if (this_param
> max_bytes
) {
2008 this_param
= max_bytes
;
2010 max_bytes
-= this_param
;
2012 this_data
= data_left
;
2013 if (this_data
> max_bytes
) {
2014 this_data
= max_bytes
;
2017 /* don't destroy unless this is the last chunk */
2018 if (params_left
- this_param
!= 0 ||
2019 data_left
- this_data
!= 0) {
2020 this_req
= smbsrv_setup_secondary_request(req
);
2025 req_grow_data(this_req
, this_param
+ this_data
+ (align1
+ align2
));
2027 SSVAL(this_req
->out
.vwv
, VWV(0), trans
->out
.params
.length
);
2028 SSVAL(this_req
->out
.vwv
, VWV(1), trans
->out
.data
.length
);
2029 SSVAL(this_req
->out
.vwv
, VWV(2), 0);
2031 SSVAL(this_req
->out
.vwv
, VWV(3), this_param
);
2032 SSVAL(this_req
->out
.vwv
, VWV(4), align1
+ PTR_DIFF(this_req
->out
.data
, this_req
->out
.hdr
));
2033 SSVAL(this_req
->out
.vwv
, VWV(5), PTR_DIFF(params
, trans
->out
.params
.data
));
2035 SSVAL(this_req
->out
.vwv
, VWV(6), this_data
);
2036 SSVAL(this_req
->out
.vwv
, VWV(7), align1
+ align2
+
2037 PTR_DIFF(this_req
->out
.data
+ this_param
, this_req
->out
.hdr
));
2038 SSVAL(this_req
->out
.vwv
, VWV(8), PTR_DIFF(data
, trans
->out
.data
.data
));
2040 SCVAL(this_req
->out
.vwv
, VWV(9), trans
->out
.setup_count
);
2041 SCVAL(this_req
->out
.vwv
, VWV(9)+1, 0); /* reserved */
2042 for (i
=0;i
<trans
->out
.setup_count
;i
++) {
2043 SSVAL(this_req
->out
.vwv
, VWV(10+i
), trans
->out
.setup
[i
]);
2046 memset(this_req
->out
.data
, 0, align1
);
2047 if (this_param
!= 0) {
2048 memcpy(this_req
->out
.data
+ align1
, params
, this_param
);
2050 memset(this_req
->out
.data
+this_param
+align1
, 0, align2
);
2051 if (this_data
!= 0) {
2052 memcpy(this_req
->out
.data
+this_param
+align1
+align2
, data
, this_data
);
2055 params_left
-= this_param
;
2056 data_left
-= this_data
;
2057 params
+= this_param
;
2060 smbsrv_send_reply(this_req
);
2061 } while (params_left
!= 0 || data_left
!= 0);
2066 answer a reconstructed trans request
2068 static void reply_trans_complete(struct smbsrv_request
*req
, uint8_t command
,
2069 struct smb_trans2
*trans
)
2071 struct trans_op
*op
;
2073 SMBSRV_TALLOC_IO_PTR(op
, struct trans_op
);
2074 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
2078 op
->command
= command
;
2082 /* its a full request, give it to the backend */
2083 if (command
== SMBtrans
) {
2084 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req
->ntvfs
, trans
));
2087 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req
, op
));
2093 Reply to an SMBtrans or SMBtrans2 request
2095 static void reply_trans_generic(struct smbsrv_request
*req
, uint8_t command
)
2097 struct smb_trans2
*trans
;
2099 uint16_t param_ofs
, data_ofs
;
2100 uint16_t param_count
, data_count
;
2101 uint16_t param_total
, data_total
;
2104 if (req
->in
.wct
< 14) {
2105 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2109 trans
= talloc(req
, struct smb_trans2
);
2110 if (trans
== NULL
) {
2111 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
2115 param_total
= SVAL(req
->in
.vwv
, VWV(0));
2116 data_total
= SVAL(req
->in
.vwv
, VWV(1));
2117 trans
->in
.max_param
= SVAL(req
->in
.vwv
, VWV(2));
2118 trans
->in
.max_data
= SVAL(req
->in
.vwv
, VWV(3));
2119 trans
->in
.max_setup
= CVAL(req
->in
.vwv
, VWV(4));
2120 trans
->in
.flags
= SVAL(req
->in
.vwv
, VWV(5));
2121 trans
->in
.timeout
= IVAL(req
->in
.vwv
, VWV(6));
2122 param_count
= SVAL(req
->in
.vwv
, VWV(9));
2123 param_ofs
= SVAL(req
->in
.vwv
, VWV(10));
2124 data_count
= SVAL(req
->in
.vwv
, VWV(11));
2125 data_ofs
= SVAL(req
->in
.vwv
, VWV(12));
2126 trans
->in
.setup_count
= CVAL(req
->in
.vwv
, VWV(13));
2128 if (req
->in
.wct
!= 14 + trans
->in
.setup_count
) {
2129 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
2133 /* parse out the setup words */
2134 trans
->in
.setup
= talloc_array(trans
, uint16_t, trans
->in
.setup_count
);
2135 if (trans
->in
.setup_count
&& !trans
->in
.setup
) {
2136 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
2139 for (i
=0;i
<trans
->in
.setup_count
;i
++) {
2140 trans
->in
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(14+i
));
2143 if (command
== SMBtrans
) {
2144 req_pull_string(&req
->in
.bufinfo
, &trans
->in
.trans_name
, req
->in
.data
, -1, STR_TERMINATE
);
2147 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
->in
.params
) ||
2148 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
->in
.data
)) {
2149 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
2153 /* is it a partial request? if so, then send a 'send more' message */
2154 if (param_total
> param_count
|| data_total
> data_count
) {
2155 reply_trans_continue(req
, command
, trans
);
2159 reply_trans_complete(req
, command
, trans
);
2164 Reply to an SMBtranss2 request
2166 static void reply_transs_generic(struct smbsrv_request
*req
, uint8_t command
)
2168 struct smbsrv_trans_partial
*tp
;
2169 struct smb_trans2
*trans
= NULL
;
2170 uint16_t param_ofs
, data_ofs
;
2171 uint16_t param_count
, data_count
;
2172 uint16_t param_disp
, data_disp
;
2173 uint16_t param_total
, data_total
;
2174 DATA_BLOB params
, data
;
2177 if (command
== SMBtrans2
) {
2184 if (req
->in
.wct
!= wct
) {
2186 * TODO: add some error code tests
2187 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
2189 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2193 for (tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) {
2194 if (tp
->command
== command
&&
2195 SVAL(tp
->req
->in
.hdr
, HDR_MID
) == SVAL(req
->in
.hdr
, HDR_MID
)) {
2196 /* TODO: check the VUID, PID and TID too? */
2202 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2206 trans
= tp
->u
.trans
;
2208 param_total
= SVAL(req
->in
.vwv
, VWV(0));
2209 data_total
= SVAL(req
->in
.vwv
, VWV(1));
2210 param_count
= SVAL(req
->in
.vwv
, VWV(2));
2211 param_ofs
= SVAL(req
->in
.vwv
, VWV(3));
2212 param_disp
= SVAL(req
->in
.vwv
, VWV(4));
2213 data_count
= SVAL(req
->in
.vwv
, VWV(5));
2214 data_ofs
= SVAL(req
->in
.vwv
, VWV(6));
2215 data_disp
= SVAL(req
->in
.vwv
, VWV(7));
2217 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, ¶ms
) ||
2218 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &data
)) {
2219 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2223 /* only allow contiguous requests */
2224 if ((param_count
!= 0 &&
2225 param_disp
!= trans
->in
.params
.length
) ||
2227 data_disp
!= trans
->in
.data
.length
)) {
2228 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2232 /* add to the existing request */
2233 if (param_count
!= 0) {
2234 trans
->in
.params
.data
= talloc_realloc(trans
,
2235 trans
->in
.params
.data
,
2237 param_disp
+ param_count
);
2238 if (trans
->in
.params
.data
== NULL
) {
2239 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
2242 trans
->in
.params
.length
= param_disp
+ param_count
;
2245 if (data_count
!= 0) {
2246 trans
->in
.data
.data
= talloc_realloc(trans
,
2247 trans
->in
.data
.data
,
2249 data_disp
+ data_count
);
2250 if (trans
->in
.data
.data
== NULL
) {
2251 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
2254 trans
->in
.data
.length
= data_disp
+ data_count
;
2257 memcpy(trans
->in
.params
.data
+ param_disp
, params
.data
, params
.length
);
2258 memcpy(trans
->in
.data
.data
+ data_disp
, data
.data
, data
.length
);
2260 /* the sequence number of the reply is taken from the last secondary
2262 tp
->req
->seq_num
= req
->seq_num
;
2264 /* we don't reply to Transs2 requests */
2267 if (trans
->in
.params
.length
== param_total
&&
2268 trans
->in
.data
.length
== data_total
) {
2269 /* its now complete */
2272 reply_trans_complete(req
, command
, trans
);
2279 Reply to an SMBtrans2
2281 void smbsrv_reply_trans2(struct smbsrv_request
*req
)
2283 reply_trans_generic(req
, SMBtrans2
);
2287 Reply to an SMBtrans
2289 void smbsrv_reply_trans(struct smbsrv_request
*req
)
2291 reply_trans_generic(req
, SMBtrans
);
2295 Reply to an SMBtranss request
2297 void smbsrv_reply_transs(struct smbsrv_request
*req
)
2299 reply_transs_generic(req
, SMBtrans
);
2303 Reply to an SMBtranss2 request
2305 void smbsrv_reply_transs2(struct smbsrv_request
*req
)
2307 reply_transs_generic(req
, SMBtrans2
);