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
)
875 /* For the moment there is a bug with XP that don't seems to appriciate much
876 * level4 so we return just level 3 for everyone
878 ref
->referral
.v4
.server_type
= DFS_SERVER_NON_ROOT
;
879 /* "normal" referral seems to always include the GUID */
880 ref
->referral
.v4
.size
= 34;
883 ref
->referral
.v4
.entry_flags
= DFS_HEADER_FLAG_TARGET_BCK
;
885 ref
->referral
.v4
.ttl
= 900; /* As w2k8r2 */
886 ref
->referral
.v4
.referrals
.r1
.DFS_path
= talloc_strdup(ref
, dfs_path
);
887 ref
->referral
.v4
.referrals
.r1
.DFS_alt_path
= talloc_strdup(ref
, dfs_path
);
888 ref
->referral
.v4
.referrals
.r1
.netw_address
= talloc_strdup(ref
, server_path
);
892 ref
->version
= version
;
893 ref
->referral
.v3
.server_type
= DFS_SERVER_NON_ROOT
;
894 /* "normal" referral seems to always include the GUID */
895 ref
->referral
.v3
.size
= 34;
897 ref
->referral
.v3
.entry_flags
= 0;
898 ref
->referral
.v3
.ttl
= 600; /* As w2k3 */
899 ref
->referral
.v3
.referrals
.r1
.DFS_path
= talloc_strdup(ref
, dfs_path
);
900 ref
->referral
.v3
.referrals
.r1
.DFS_alt_path
= talloc_strdup(ref
, dfs_path
);
901 ref
->referral
.v3
.referrals
.r1
.netw_address
= talloc_strdup(ref
, server_path
);
904 return NT_STATUS_INVALID_LEVEL
;
908 fill a domain refererral
910 static NTSTATUS
fill_domain_dfs_referraltype(struct dfs_referral_type
*ref
,
919 DEBUG(8, ("Called fill_domain_dfs_referraltype\n"));
920 ref
->version
= version
;
921 ref
->referral
.v3
.server_type
= DFS_SERVER_NON_ROOT
;
922 /* It's hard coded ... don't think it's a good way but the sizeof return not the
925 * We have 18 if the GUID is not included 34 otherwise
928 /* Windows return without the guid when returning domain list
930 ref
->referral
.v3
.size
= 18;
932 ref
->referral
.v3
.size
= 34;
934 ref
->referral
.v3
.entry_flags
= DFS_FLAG_REFERRAL_DOMAIN_RESP
;
935 ref
->referral
.v3
.ttl
= 600; /* As w2k3 */
936 ref
->referral
.v3
.referrals
.r2
.special_name
= domain
;
937 ref
->referral
.v3
.referrals
.r2
.nb_expanded_names
= numnames
;
938 /* Put the final terminator */
940 const char **names2
= talloc_array(ref
, const char *, numnames
+1);
941 NT_STATUS_HAVE_NO_MEMORY(names2
);
943 for (i
= 0; i
<numnames
; i
++) {
944 names2
[i
] = talloc_asprintf(names2
, "\\%s", names
[i
]);
945 NT_STATUS_HAVE_NO_MEMORY(names2
[i
]);
947 names2
[numnames
] = NULL
;
948 ref
->referral
.v3
.referrals
.r2
.expanded_names
= names2
;
952 return NT_STATUS_INVALID_LEVEL
;
956 get the DCs list within a site
958 static NTSTATUS
get_dcs_insite(TALLOC_CTX
*ctx
, struct ldb_context
*ldb
,
959 struct ldb_dn
*sitedn
, struct dc_set
*list
,
962 static const char *attrs
[] = { "serverReference", NULL
};
963 static const char *attrs2
[] = { "dNSHostName", "sAMAccountName", NULL
};
964 struct ldb_result
*r
;
967 const char **dc_list
;
969 ret
= ldb_search(ldb
, ctx
, &r
, sitedn
, LDB_SCOPE_SUBTREE
, attrs
,
970 "(&(objectClass=server)(serverReference=*))");
971 if (ret
!= LDB_SUCCESS
) {
972 DEBUG(2,(__location__
": Failed to get list of servers - %s\n",
973 ldb_errstring(ldb
)));
974 return NT_STATUS_INTERNAL_ERROR
;
978 /* none in this site */
984 * need to search for all server object to know the size of the array.
985 * Search all the object of class server in this site
987 dc_list
= talloc_array(r
, const char *, r
->count
);
988 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list
, r
);
990 /* TODO put some random here in the order */
991 list
->names
= talloc_realloc(list
, list
->names
, const char *, list
->count
+ r
->count
);
992 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list
->names
, r
);
994 for (i
= 0; i
<r
->count
; i
++) {
996 struct ldb_result
*r2
;
998 dn
= ldb_msg_find_attr_as_dn(ldb
, ctx
, r
->msgs
[i
], "serverReference");
1000 return NT_STATUS_INTERNAL_ERROR
;
1003 ret
= ldb_search(ldb
, r
, &r2
, dn
, LDB_SCOPE_BASE
, attrs2
, "(objectClass=computer)");
1004 if (ret
!= LDB_SUCCESS
) {
1005 DEBUG(2,(__location__
": Search for computer on %s failed - %s\n",
1006 ldb_dn_get_linearized(dn
), ldb_errstring(ldb
)));
1007 return NT_STATUS_INTERNAL_ERROR
;
1011 const char *dns
= ldb_msg_find_attr_as_string(r2
->msgs
[0], "dNSHostName", NULL
);
1013 DEBUG(2,(__location__
": dNSHostName missing on %s\n",
1014 ldb_dn_get_linearized(dn
)));
1016 return NT_STATUS_INTERNAL_ERROR
;
1019 list
->names
[list
->count
] = talloc_strdup(list
->names
, dns
);
1020 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list
->names
[list
->count
], r
);
1023 const char *acct
= ldb_msg_find_attr_as_string(r2
->msgs
[0], "sAMAccountName", NULL
);
1025 DEBUG(2,(__location__
": sAMAccountName missing on %s\n",
1026 ldb_dn_get_linearized(dn
)));
1028 return NT_STATUS_INTERNAL_ERROR
;
1031 tmp
= talloc_strdup(list
->names
, acct
);
1032 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp
, r
);
1034 /* Netbios name is also the sAMAccountName for
1035 computer but without the final $ */
1036 tmp
[strlen(tmp
) - 1] = '\0';
1037 list
->names
[list
->count
] = tmp
;
1044 return NT_STATUS_OK
;
1051 static NTSTATUS
get_dcs(TALLOC_CTX
*ctx
, struct ldb_context
*ldb
,
1052 const char *searched_site
, bool need_fqdn
,
1053 struct dc_set
***pset_list
, uint32_t flags
)
1056 * Flags will be used later to indicate things like least-expensive
1057 * or same-site options
1059 const char *attrs_none
[] = { NULL
};
1060 const char *attrs3
[] = { "name", NULL
};
1061 struct ldb_dn
*configdn
, *sitedn
, *dn
, *sitescontainerdn
;
1062 struct ldb_result
*r
;
1063 struct dc_set
**set_list
= NULL
;
1066 uint32_t current_pos
= 0;
1068 TALLOC_CTX
*subctx
= talloc_new(ctx
);
1070 *pset_list
= set_list
= NULL
;
1072 subctx
= talloc_new(ctx
);
1073 NT_STATUS_HAVE_NO_MEMORY(subctx
);
1075 configdn
= ldb_get_config_basedn(ldb
);
1077 /* Let's search for the Site container */
1078 ret
= ldb_search(ldb
, subctx
, &r
, configdn
, LDB_SCOPE_SUBTREE
, attrs_none
,
1079 "(objectClass=sitesContainer)");
1080 if (ret
!= LDB_SUCCESS
) {
1081 DEBUG(2,(__location__
": Failed to find sitesContainer within %s - %s\n",
1082 ldb_dn_get_linearized(configdn
), ldb_errstring(ldb
)));
1083 talloc_free(subctx
);
1084 return NT_STATUS_INTERNAL_ERROR
;
1087 DEBUG(2,(__location__
": Expected 1 sitesContainer - found %u within %s\n",
1088 r
->count
, ldb_dn_get_linearized(configdn
)));
1089 talloc_free(subctx
);
1090 return NT_STATUS_INTERNAL_ERROR
;
1093 sitescontainerdn
= talloc_steal(subctx
, r
->msgs
[0]->dn
);
1097 * TODO: Here we should have a more subtle handling
1098 * for the case "same-site"
1100 ret
= ldb_search(ldb
, subctx
, &r
, sitescontainerdn
, LDB_SCOPE_SUBTREE
,
1101 attrs_none
, "(objectClass=server)");
1102 if (ret
!= LDB_SUCCESS
) {
1103 DEBUG(2,(__location__
": Failed to find servers within %s - %s\n",
1104 ldb_dn_get_linearized(sitescontainerdn
), ldb_errstring(ldb
)));
1105 talloc_free(subctx
);
1106 return NT_STATUS_INTERNAL_ERROR
;
1110 if (searched_site
!= NULL
) {
1111 ret
= ldb_search(ldb
, subctx
, &r
, configdn
, LDB_SCOPE_SUBTREE
,
1112 attrs_none
, "(&(name=%s)(objectClass=site))", searched_site
);
1113 if (ret
!= LDB_SUCCESS
) {
1114 talloc_free(subctx
);
1115 return NT_STATUS_FOOBAR
;
1116 } else if (r
->count
!= 1) {
1117 talloc_free(subctx
);
1118 return NT_STATUS_FOOBAR
;
1121 /* All of this was to get the DN of the searched_site */
1122 sitedn
= r
->msgs
[0]->dn
;
1124 set_list
= talloc_realloc(subctx
, set_list
, struct dc_set
*, current_pos
+1);
1125 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
, subctx
);
1127 set_list
[current_pos
] = talloc(set_list
, struct dc_set
);
1128 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
[current_pos
], subctx
);
1130 set_list
[current_pos
]->names
= NULL
;
1131 set_list
[current_pos
]->count
= 0;
1132 status
= get_dcs_insite(subctx
, ldb
, sitedn
,
1133 set_list
[current_pos
], need_fqdn
);
1134 if (!NT_STATUS_IS_OK(status
)) {
1135 DEBUG(2,(__location__
": Failed to get DC from site %s - %s\n",
1136 ldb_dn_get_linearized(sitedn
), nt_errstr(status
)));
1137 talloc_free(subctx
);
1144 /* Let's find all the sites */
1145 ret
= ldb_search(ldb
, subctx
, &r
, configdn
, LDB_SCOPE_SUBTREE
, attrs3
, "(objectClass=site)");
1146 if (ret
!= LDB_SUCCESS
) {
1147 DEBUG(2,(__location__
": Failed to find any site containers in %s\n",
1148 ldb_dn_get_linearized(configdn
)));
1149 talloc_free(subctx
);
1150 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1155 * We should randomize the order in the main site,
1156 * it's mostly needed for sysvol/netlogon referral.
1157 * Depending of flag we either randomize order of the
1158 * not "in the same site DCs"
1159 * or we randomize by group of site that have the same cost
1160 * In the long run we want to manipulate an array of site_set
1161 * All the site in one set have the same cost (if least-expansive options is selected)
1162 * and we will put all the dc related to 1 site set into 1 DCs set.
1163 * Within a site set, site order has to be randomized
1165 * But for the moment we just return the list of sites
1169 * We will realloc + 2 because we will need one additional place
1170 * for element at current_pos + 1 for the NULL element
1172 set_list
= talloc_realloc(subctx
, set_list
, struct dc_set
*,
1174 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
, subctx
);
1176 set_list
[current_pos
] = talloc(ctx
, struct dc_set
);
1177 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list
[current_pos
], subctx
);
1179 set_list
[current_pos
]->names
= NULL
;
1180 set_list
[current_pos
]->count
= 0;
1182 set_list
[current_pos
+1] = NULL
;
1185 for (i
=0; i
<r
->count
; i
++) {
1186 const char *site_name
= ldb_msg_find_attr_as_string(r
->msgs
[i
], "name", NULL
);
1187 if (site_name
== NULL
) {
1188 DEBUG(2,(__location__
": Failed to find name attribute in %s\n",
1189 ldb_dn_get_linearized(r
->msgs
[i
]->dn
)));
1190 talloc_free(subctx
);
1191 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1194 if (searched_site
== NULL
||
1195 strcmp(searched_site
, site_name
) != 0) {
1196 DEBUG(2,(__location__
": Site: %s %s\n",
1197 searched_site
, site_name
));
1200 * Do all the site but the one of the client
1201 * (because it has already been done ...)
1203 dn
= r
->msgs
[i
]->dn
;
1205 status
= get_dcs_insite(subctx
, ldb
, dn
,
1206 set_list
[current_pos
],
1208 if (!NT_STATUS_IS_OK(status
)) {
1209 talloc_free(subctx
);
1215 set_list
[current_pos
] = NULL
;
1217 *pset_list
= talloc_move(ctx
, &set_list
);
1218 talloc_free(subctx
);
1219 return NT_STATUS_OK
;
1222 static NTSTATUS
dodomain_referral(TALLOC_CTX
*ctx
,
1223 const struct dfs_GetDFSReferral_in
*dfsreq
,
1224 struct ldb_context
*ldb
,
1225 struct smb_trans2
*trans
,
1226 struct loadparm_context
*lp_ctx
)
1229 * TODO for the moment we just return the local domain
1232 enum ndr_err_code ndr_err
;
1234 const char *dns_domain
= lpcfg_dnsdomain(lp_ctx
);
1235 const char *netbios_domain
= lpcfg_workgroup(lp_ctx
);
1236 struct dfs_referral_resp resp
;
1237 struct dfs_referral_type
*tab
;
1238 struct dfs_referral_type
*referral
;
1239 const char *referral_str
;
1240 /* In the future this needs to be fetched from the ldb */
1241 uint32_t found_domain
= 2;
1242 uint32_t current_pos
= 0;
1243 TALLOC_CTX
*context
;
1245 if (lpcfg_server_role(lp_ctx
) != ROLE_DOMAIN_CONTROLLER
) {
1246 DEBUG(10 ,("Received a domain referral request on a non DC\n"));
1247 return NT_STATUS_INVALID_PARAMETER
;
1250 if (dfsreq
->max_referral_level
< 3) {
1251 DEBUG(2,("invalid max_referral_level %u\n",
1252 dfsreq
->max_referral_level
));
1253 return NT_STATUS_UNSUCCESSFUL
;
1256 context
= talloc_new(ctx
);
1257 NT_STATUS_HAVE_NO_MEMORY(context
);
1259 resp
.path_consumed
= 0;
1260 resp
.header_flags
= 0; /* Do like w2k3 */
1261 resp
.nb_referrals
= found_domain
; /* the fqdn one + the NT domain */
1263 tab
= talloc_array(context
, struct dfs_referral_type
, found_domain
);
1264 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tab
, context
);
1266 referral
= talloc(tab
, struct dfs_referral_type
);
1267 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1268 referral_str
= talloc_asprintf(referral
, "\\%s", netbios_domain
);
1269 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1270 status
= fill_domain_dfs_referraltype(referral
, 3,
1273 if (!NT_STATUS_IS_OK(status
)) {
1274 DEBUG(2,(__location__
":Unable to fill domain referral structure\n"));
1275 talloc_free(context
);
1276 return NT_STATUS_UNSUCCESSFUL
;
1279 tab
[current_pos
] = *referral
;
1282 referral
= talloc(tab
, struct dfs_referral_type
);
1283 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1284 referral_str
= talloc_asprintf(referral
, "\\%s", dns_domain
);
1285 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1286 status
= fill_domain_dfs_referraltype(referral
, 3,
1289 if (!NT_STATUS_IS_OK(status
)) {
1290 DEBUG(2,(__location__
":Unable to fill domain referral structure\n"));
1291 talloc_free(context
);
1292 return NT_STATUS_UNSUCCESSFUL
;
1294 tab
[current_pos
] = *referral
;
1298 * Put here the code from filling the array for trusted domain
1300 resp
.referral_entries
= tab
;
1302 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1304 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1305 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1306 DEBUG(2,(__location__
":NDR marchalling of domain deferral response failed\n"));
1307 talloc_free(context
);
1308 return NT_STATUS_INTERNAL_ERROR
;
1311 if (outblob
.length
> trans
->in
.max_data
) {
1314 DEBUG(3, ("Blob is too big for the output buffer "
1316 (unsigned int)outblob
.length
, trans
->in
.max_data
));
1318 if (trans
->in
.max_data
!= MAX_DFS_RESPONSE
) {
1319 /* As specified in MS-DFSC.pdf 3.3.5.2 */
1320 talloc_free(context
);
1321 return STATUS_BUFFER_OVERFLOW
;
1325 * The answer is too big, so let's remove some answers
1327 while (!ok
&& resp
.nb_referrals
> 2) {
1328 data_blob_free(&outblob
);
1331 * Let's scrap the first referral (for now)
1333 resp
.nb_referrals
-= 1;
1334 resp
.referral_entries
+= 1;
1336 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1338 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1339 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1340 talloc_free(context
);
1341 return NT_STATUS_INTERNAL_ERROR
;
1344 if (outblob
.length
<= MAX_DFS_RESPONSE
) {
1345 DEBUG(10,("DFS: managed to reduce the size of referral initial"
1346 "number of referral %d, actual count: %d",
1347 found_domain
, resp
.nb_referrals
));
1353 if (!ok
&& resp
.nb_referrals
== 2) {
1354 DEBUG(8, (__location__
"; Not able to fit the domain and realm in DFS a "
1355 " 56K buffer, something must be broken"));
1356 talloc_free(context
);
1357 return NT_STATUS_INTERNAL_ERROR
;
1361 TRANS2_CHECK(trans2_setup_reply(trans
, 0, outblob
.length
, 0));
1363 trans
->out
.data
= outblob
;
1364 talloc_steal(ctx
, outblob
.data
);
1365 talloc_free(context
);
1366 return NT_STATUS_OK
;
1370 * Handle the logic for dfs referral request like \\domain
1371 * or \\domain\sysvol or \\fqdn or \\fqdn\netlogon
1373 static NTSTATUS
dodc_or_sysvol_referral(TALLOC_CTX
*ctx
,
1374 const struct dfs_GetDFSReferral_in dfsreq
,
1375 const char* requesteddomain
,
1376 const char* requestedshare
,
1377 const char* requestedname
,
1378 struct ldb_context
*ldb
,
1379 struct smb_trans2
*trans
,
1380 struct smbsrv_request
*req
,
1381 struct loadparm_context
*lp_ctx
)
1384 * It's not a "standard" DFS referral but a referral to get the DC list
1385 * or sysvol/netlogon
1386 * Let's check that it's for one of our domain ...
1390 unsigned int num_domain
= 1;
1391 enum ndr_err_code ndr_err
;
1392 const char *realm
= lpcfg_realm(lp_ctx
);
1393 const char *domain
= lpcfg_workgroup(lp_ctx
);
1394 const char *site_name
= NULL
; /* Name of the site where the client is */
1396 bool need_fqdn
= false;
1397 bool dc_referral
= true;
1399 struct dc_set
**set
;
1400 char const **domain_list
;
1401 struct tsocket_address
*remote_address
;
1402 char *client_addr
= NULL
;
1403 TALLOC_CTX
*context
;
1405 if (lpcfg_server_role(lp_ctx
) != ROLE_DOMAIN_CONTROLLER
) {
1406 return NT_STATUS_INVALID_PARAMETER
;
1409 if (dfsreq
.max_referral_level
< 3) {
1410 DEBUG(2,("invalid max_referral_level %u\n",
1411 dfsreq
.max_referral_level
));
1412 return NT_STATUS_UNSUCCESSFUL
;
1415 context
= talloc_new(ctx
);
1416 NT_STATUS_HAVE_NO_MEMORY(context
);
1418 DEBUG(10, ("in this we have request for %s and share %s requested is %s\n",
1423 if (requestedshare
) {
1424 DEBUG(10, ("Have a non DC domain referal\n"));
1425 dc_referral
= false;
1429 * We will fetch the trusted domain list soon with something like this:
1431 * "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)
1432 * (trustPartner=%s))(objectclass=trustedDomain))"
1434 * Allocate for num_domain + 1 so that the last element will be NULL)
1436 domain_list
= talloc_array(context
, const char*, num_domain
+1);
1437 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_list
, context
);
1439 domain_list
[0] = realm
;
1440 domain_list
[1] = domain
;
1441 for (i
=0; i
<=num_domain
; i
++) {
1442 if (strncasecmp(domain_list
[i
], requesteddomain
, strlen(domain_list
[i
])) == 0) {
1449 /* The requested domain is not one that we support */
1450 DEBUG(3,("Requested referral for domain %s, but we don't handle it",
1452 return NT_STATUS_INVALID_PARAMETER
;
1455 if (strchr(requestedname
,'.')) {
1459 remote_address
= req
->smb_conn
->connection
->remote_address
;
1460 if (tsocket_address_is_inet(remote_address
, "ip")) {
1461 client_addr
= tsocket_address_inet_addr_string(remote_address
, context
);
1462 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_addr
, context
);
1465 status
= get_dcs(context
, ldb
, site_name
, need_fqdn
, &set
, 0);
1466 if (!NT_STATUS_IS_OK(status
)) {
1467 DEBUG(3,("Unable to get list of DCs\n"));
1468 talloc_free(context
);
1473 const char **dc_list
= NULL
;
1474 uint32_t num_dcs
= 0;
1475 struct dfs_referral_type
*referral
;
1476 const char *referral_str
;
1477 struct dfs_referral_resp resp
;
1479 for(i
=0; set
[i
]; i
++) {
1482 dc_list
= talloc_realloc(context
, dc_list
, const char*,
1483 num_dcs
+ set
[i
]->count
+ 1);
1484 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list
, context
);
1486 for(j
=0; j
<set
[i
]->count
; j
++) {
1487 dc_list
[num_dcs
+ j
] = talloc_steal(context
, set
[i
]->names
[j
]);
1489 num_dcs
= num_dcs
+ set
[i
]->count
;
1490 TALLOC_FREE(set
[i
]);
1491 dc_list
[num_dcs
] = NULL
;
1494 resp
.path_consumed
= 0;
1495 resp
.header_flags
= 0; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1498 * The NumberOfReferrals field MUST be set to 1,
1499 * independent of the number of DC names
1500 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1502 resp
.nb_referrals
= 1;
1504 /* Put here the code from filling the array for trusted domain */
1505 referral
= talloc(context
, struct dfs_referral_type
);
1506 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1508 if (requestedname
[0] == '\\') {
1509 referral_str
= talloc_asprintf(referral
, "%s",
1512 referral_str
= talloc_asprintf(referral
, "\\%s",
1515 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1517 status
= fill_domain_dfs_referraltype(referral
, 3,
1520 if (!NT_STATUS_IS_OK(status
)) {
1521 DEBUG(2,(__location__
":Unable to fill domain referral structure\n"));
1522 talloc_free(context
);
1523 return NT_STATUS_UNSUCCESSFUL
;
1525 resp
.referral_entries
= referral
;
1527 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1529 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1530 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1531 DEBUG(2,(__location__
":NDR marshalling of dfs referral response failed\n"));
1532 talloc_free(context
);
1533 return NT_STATUS_INTERNAL_ERROR
;
1536 unsigned int nb_entries
= 0;
1537 unsigned int current
= 0;
1538 struct dfs_referral_type
*tab
;
1539 struct dfs_referral_resp resp
;
1541 for(i
=0; set
[i
]; i
++) {
1542 nb_entries
= nb_entries
+ set
[i
]->count
;
1545 resp
.path_consumed
= 2*strlen(requestedname
); /* The length is expected in bytes */
1546 resp
.header_flags
= DFS_HEADER_FLAG_STORAGE_SVR
; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1549 * The NumberOfReferrals field MUST be set to 1,
1550 * independent of the number of DC names
1551 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1553 resp
.nb_referrals
= nb_entries
;
1555 tab
= talloc_array(context
, struct dfs_referral_type
, nb_entries
);
1556 NT_STATUS_HAVE_NO_MEMORY(tab
);
1558 for(i
=0; set
[i
]; i
++) {
1561 for(j
=0; j
< set
[i
]->count
; j
++) {
1562 struct dfs_referral_type
*referral
;
1563 const char *referral_str
;
1565 referral
= talloc(tab
, struct dfs_referral_type
);
1566 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral
, context
);
1568 referral_str
= talloc_asprintf(referral
, "\\%s\\%s",
1569 set
[i
]->names
[j
], requestedshare
);
1570 DEBUG(8, ("Doing a dfs referral for %s with this value %s requested %s\n", set
[i
]->names
[j
], referral_str
, requestedname
));
1571 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str
, context
);
1573 status
= fill_normal_dfs_referraltype(referral
,
1574 dfsreq
.max_referral_level
,
1575 requestedname
, referral_str
, j
==0);
1577 if (!NT_STATUS_IS_OK(status
)) {
1578 DEBUG(2, (__location__
": Unable to fill a normal dfs referral object"));
1579 talloc_free(context
);
1580 return NT_STATUS_UNSUCCESSFUL
;
1582 tab
[current
] = *referral
;
1586 resp
.referral_entries
= tab
;
1588 ndr_err
= ndr_push_struct_blob(&outblob
, context
,
1590 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1591 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1592 DEBUG(2,(__location__
":NDR marchalling of domain deferral response failed\n"));
1593 talloc_free(context
);
1594 return NT_STATUS_INTERNAL_ERROR
;
1598 TRANS2_CHECK(trans2_setup_reply(trans
, 0, outblob
.length
, 0));
1601 * TODO If the size is too big we should remove
1602 * some DC from the answer or return STATUS_BUFFER_OVERFLOW
1604 trans
->out
.data
= outblob
;
1605 talloc_steal(ctx
, outblob
.data
);
1606 talloc_free(context
);
1607 return NT_STATUS_OK
;
1611 trans2 getdfsreferral implementation
1613 static NTSTATUS
trans2_getdfsreferral(struct smbsrv_request
*req
,
1614 struct trans_op
*op
)
1616 enum ndr_err_code ndr_err
;
1617 struct smb_trans2
*trans
= op
->trans
;
1618 struct dfs_GetDFSReferral_in dfsreq
;
1619 TALLOC_CTX
*context
;
1620 struct ldb_context
*ldb
;
1621 struct loadparm_context
*lp_ctx
;
1622 const char *realm
, *nbname
, *requestedname
;
1623 char *fqdn
, *share
, *domain
, *tmp
;
1626 lp_ctx
= req
->tcon
->ntvfs
->lp_ctx
;
1627 if (!lpcfg_host_msdfs(lp_ctx
)) {
1628 return NT_STATUS_NOT_IMPLEMENTED
;
1631 context
= talloc_new(req
);
1632 NT_STATUS_HAVE_NO_MEMORY(context
);
1634 ldb
= samdb_connect(context
, req
->tcon
->ntvfs
->event_ctx
, lp_ctx
, system_session(lp_ctx
), 0);
1636 DEBUG(2,(__location__
": Failed to open samdb\n"));
1637 talloc_free(context
);
1638 return NT_STATUS_INTERNAL_ERROR
;
1641 ndr_err
= ndr_pull_struct_blob(&trans
->in
.params
, op
,
1643 (ndr_pull_flags_fn_t
)ndr_pull_dfs_GetDFSReferral_in
);
1644 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1645 status
= ndr_map_error2ntstatus(ndr_err
);
1646 DEBUG(2,(__location__
": Failed to parse GetDFSReferral_in - %s\n",
1647 nt_errstr(status
)));
1648 talloc_free(context
);
1652 DEBUG(8, ("Requested DFS name: %s length: %u\n",
1653 dfsreq
.servername
, (unsigned int)strlen(dfsreq
.servername
)));
1656 * If the servername is "" then we are in a case of domain dfs
1657 * and the client just searches for the list of local domain
1658 * it is attached and also trusted ones.
1660 requestedname
= dfsreq
.servername
;
1661 if (requestedname
== NULL
|| requestedname
[0] == '\0') {
1662 return dodomain_referral(op
, &dfsreq
, ldb
, trans
, lp_ctx
);
1665 realm
= lpcfg_realm(lp_ctx
);
1666 nbname
= lpcfg_netbios_name(lp_ctx
);
1667 fqdn
= talloc_asprintf(context
, "%s.%s", nbname
, realm
);
1669 if ((strncasecmp(requestedname
+1, nbname
, strlen(nbname
)) == 0) ||
1670 (strncasecmp(requestedname
+1, fqdn
, strlen(fqdn
)) == 0) ) {
1672 * the referral request starts with \NETBIOSNAME or \fqdn
1673 * it's a standalone referral we do not do it
1674 * (TODO correct this)
1675 * If a DFS link that is a complete prefix of the DFS referral
1676 * request path is identified, the server MUST return a DFS link
1677 * referral response; otherwise, if it has a match for the DFS root,
1678 * it MUST return a root referral response.
1680 DEBUG(3, ("Received a standalone request for %s, we do not support standalone referral yet",requestedname
));
1681 talloc_free(context
);
1682 return NT_STATUS_NOT_FOUND
;
1686 domain
= talloc_strdup(context
, requestedname
);
1687 while(*domain
&& *domain
== '\\') {
1691 tmp
= strchr(domain
,'\\'); /* To get second \ if any */
1695 * We are finishing properly the domain string
1696 * and the share one will start after the \
1700 share
= talloc_strdup(context
, tmp
);
1703 * Here we have filtered the thing the requested name don't contain our DNS name.
1704 * So if the share == NULL or if share in ("sysvol", "netlogon")
1705 * then we proceed. In the first case it will be a dc refereal in the second it will
1706 * be just a sysvol/netlogon referral.
1708 if (share
== NULL
||
1709 strcasecmp(share
, "sysvol") == 0 ||
1710 strcasecmp(share
, "netlogon") == 0) {
1711 status
= dodc_or_sysvol_referral(op
, dfsreq
, domain
, share
, requestedname
,
1712 ldb
, trans
, req
, lp_ctx
);
1713 talloc_free(context
);
1717 tmp
= strchr(share
, '\\');
1719 (strncasecmp(share
, "sysvol", 6) == 0 ||
1720 strncasecmp(share
, "netlogon", 8) == 0)) {
1722 * We have more than two \ so it something like
1723 * \domain\sysvol\foobar
1725 talloc_free(context
);
1726 return NT_STATUS_NOT_FOUND
;
1729 talloc_free(context
);
1730 /* By default until all the case are handled*/
1731 return NT_STATUS_NOT_FOUND
;
1735 trans2 findfirst implementation
1737 static NTSTATUS
trans2_findfirst(struct smbsrv_request
*req
, struct trans_op
*op
)
1739 struct smb_trans2
*trans
= op
->trans
;
1740 union smb_search_first
*search
;
1742 struct find_state
*state
;
1744 /* make sure we got all the parameters */
1745 if (trans
->in
.params
.length
< 14) {
1746 return NT_STATUS_FOOBAR
;
1749 search
= talloc(op
, union smb_search_first
);
1750 NT_STATUS_HAVE_NO_MEMORY(search
);
1752 search
->t2ffirst
.in
.search_attrib
= SVAL(trans
->in
.params
.data
, 0);
1753 search
->t2ffirst
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1754 search
->t2ffirst
.in
.flags
= SVAL(trans
->in
.params
.data
, 4);
1755 level
= SVAL(trans
->in
.params
.data
, 6);
1756 search
->t2ffirst
.in
.storage_type
= IVAL(trans
->in
.params
.data
, 8);
1758 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2ffirst
.in
.pattern
, 0);
1759 if (search
->t2ffirst
.in
.pattern
== NULL
) {
1760 return NT_STATUS_FOOBAR
;
1763 search
->t2ffirst
.level
= RAW_SEARCH_TRANS2
;
1764 search
->t2ffirst
.data_level
= (enum smb_search_data_level
)level
;
1765 if (search
->t2ffirst
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
1766 return NT_STATUS_INVALID_LEVEL
;
1769 if (search
->t2ffirst
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
1770 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
1771 &search
->t2ffirst
.in
.num_names
,
1772 &search
->t2ffirst
.in
.ea_names
));
1775 /* setup the private state structure that the backend will
1776 give us in the callback */
1777 state
= talloc(op
, struct find_state
);
1778 NT_STATUS_HAVE_NO_MEMORY(state
);
1780 state
->search
= search
;
1781 state
->data_level
= search
->t2ffirst
.data_level
;
1782 state
->last_entry_offset
= 0;
1783 state
->flags
= search
->t2ffirst
.in
.flags
;
1785 /* setup for just a header in the reply */
1786 TRANS2_CHECK(trans2_setup_reply(trans
, 10, 0, 0));
1788 op
->op_info
= state
;
1789 op
->send_fn
= trans2_findfirst_send
;
1791 return ntvfs_search_first(req
->ntvfs
, search
, state
, find_callback
);
1796 trans2 findnext send
1798 static NTSTATUS
trans2_findnext_send(struct trans_op
*op
)
1800 struct smbsrv_request
*req
= op
->req
;
1801 struct smb_trans2
*trans
= op
->trans
;
1802 union smb_search_next
*search
;
1803 struct find_state
*state
;
1806 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
1807 search
= talloc_get_type(state
->search
, union smb_search_next
);
1809 /* fill in the findfirst reply header */
1810 param
= trans
->out
.params
.data
;
1811 SSVAL(param
, VWV(0), search
->t2fnext
.out
.count
);
1812 SSVAL(param
, VWV(1), search
->t2fnext
.out
.end_of_search
);
1813 SSVAL(param
, VWV(2), 0);
1814 SSVAL(param
, VWV(3), state
->last_entry_offset
);
1816 return NT_STATUS_OK
;
1821 trans2 findnext implementation
1823 static NTSTATUS
trans2_findnext(struct smbsrv_request
*req
, struct trans_op
*op
)
1825 struct smb_trans2
*trans
= op
->trans
;
1826 union smb_search_next
*search
;
1828 struct find_state
*state
;
1830 /* make sure we got all the parameters */
1831 if (trans
->in
.params
.length
< 12) {
1832 return NT_STATUS_FOOBAR
;
1835 search
= talloc(op
, union smb_search_next
);
1836 NT_STATUS_HAVE_NO_MEMORY(search
);
1838 search
->t2fnext
.in
.handle
= SVAL(trans
->in
.params
.data
, 0);
1839 search
->t2fnext
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1840 level
= SVAL(trans
->in
.params
.data
, 4);
1841 search
->t2fnext
.in
.resume_key
= IVAL(trans
->in
.params
.data
, 6);
1842 search
->t2fnext
.in
.flags
= SVAL(trans
->in
.params
.data
, 10);
1844 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2fnext
.in
.last_name
, 0);
1845 if (search
->t2fnext
.in
.last_name
== NULL
) {
1846 return NT_STATUS_FOOBAR
;
1849 search
->t2fnext
.level
= RAW_SEARCH_TRANS2
;
1850 search
->t2fnext
.data_level
= (enum smb_search_data_level
)level
;
1851 if (search
->t2fnext
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
1852 return NT_STATUS_INVALID_LEVEL
;
1855 if (search
->t2fnext
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
1856 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
1857 &search
->t2fnext
.in
.num_names
,
1858 &search
->t2fnext
.in
.ea_names
));
1861 /* setup the private state structure that the backend will give us in the callback */
1862 state
= talloc(op
, struct find_state
);
1863 NT_STATUS_HAVE_NO_MEMORY(state
);
1865 state
->search
= search
;
1866 state
->data_level
= search
->t2fnext
.data_level
;
1867 state
->last_entry_offset
= 0;
1868 state
->flags
= search
->t2fnext
.in
.flags
;
1870 /* setup for just a header in the reply */
1871 TRANS2_CHECK(trans2_setup_reply(trans
, 8, 0, 0));
1873 op
->op_info
= state
;
1874 op
->send_fn
= trans2_findnext_send
;
1876 return ntvfs_search_next(req
->ntvfs
, search
, state
, find_callback
);
1881 backend for trans2 requests
1883 static NTSTATUS
trans2_backend(struct smbsrv_request
*req
, struct trans_op
*op
)
1885 struct smb_trans2
*trans
= op
->trans
;
1888 /* direct trans2 pass thru */
1889 status
= ntvfs_trans2(req
->ntvfs
, trans
);
1890 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED
, status
)) {
1894 /* must have at least one setup word */
1895 if (trans
->in
.setup_count
< 1) {
1896 return NT_STATUS_FOOBAR
;
1899 /* the trans2 command is in setup[0] */
1900 switch (trans
->in
.setup
[0]) {
1901 case TRANSACT2_GET_DFS_REFERRAL
:
1902 return trans2_getdfsreferral(req
, op
);
1903 case TRANSACT2_FINDFIRST
:
1904 return trans2_findfirst(req
, op
);
1905 case TRANSACT2_FINDNEXT
:
1906 return trans2_findnext(req
, op
);
1907 case TRANSACT2_QPATHINFO
:
1908 return trans2_qpathinfo(req
, op
);
1909 case TRANSACT2_QFILEINFO
:
1910 return trans2_qfileinfo(req
, op
);
1911 case TRANSACT2_SETFILEINFO
:
1912 return trans2_setfileinfo(req
, op
);
1913 case TRANSACT2_SETPATHINFO
:
1914 return trans2_setpathinfo(req
, op
);
1915 case TRANSACT2_QFSINFO
:
1916 return trans2_qfsinfo(req
, op
);
1917 case TRANSACT2_OPEN
:
1918 return trans2_open(req
, op
);
1919 case TRANSACT2_MKDIR
:
1920 return trans2_mkdir(req
, op
);
1923 /* an unknown trans2 command */
1924 return NT_STATUS_FOOBAR
;
1927 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial
*tp
)
1929 DLIST_REMOVE(tp
->req
->smb_conn
->trans_partial
, tp
);
1935 send a continue request
1937 static void reply_trans_continue(struct smbsrv_request
*req
, uint8_t command
,
1938 struct smb_trans2
*trans
)
1940 struct smbsrv_request
*req2
;
1941 struct smbsrv_trans_partial
*tp
;
1944 /* make sure they don't flood us */
1945 for (count
=0,tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) count
++;
1947 smbsrv_send_error(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1951 tp
= talloc(req
, struct smbsrv_trans_partial
);
1954 tp
->u
.trans
= trans
;
1955 tp
->command
= command
;
1957 DLIST_ADD(req
->smb_conn
->trans_partial
, tp
);
1958 talloc_set_destructor(tp
, smbsrv_trans_partial_destructor
);
1960 req2
= smbsrv_setup_secondary_request(req
);
1962 /* send a 'please continue' reply */
1963 smbsrv_setup_reply(req2
, 0, 0);
1964 smbsrv_send_reply(req2
);
1969 answer a reconstructed trans request
1971 static void reply_trans_send(struct ntvfs_request
*ntvfs
)
1973 struct smbsrv_request
*req
;
1974 struct trans_op
*op
;
1975 struct smb_trans2
*trans
;
1976 uint16_t params_left
, data_left
;
1977 uint8_t *params
, *data
;
1980 SMBSRV_CHECK_ASYNC_STATUS_ERR(op
, struct trans_op
);
1983 /* if this function needs work to form the nttrans reply buffer, then
1985 if (op
->send_fn
!= NULL
) {
1987 status
= op
->send_fn(op
);
1988 if (!NT_STATUS_IS_OK(status
)) {
1989 smbsrv_send_error(req
, status
);
1994 params_left
= trans
->out
.params
.length
;
1995 data_left
= trans
->out
.data
.length
;
1996 params
= trans
->out
.params
.data
;
1997 data
= trans
->out
.data
.data
;
1999 smbsrv_setup_reply(req
, 10 + trans
->out
.setup_count
, 0);
2001 if (!NT_STATUS_IS_OK(req
->ntvfs
->async_states
->status
)) {
2002 smbsrv_setup_error(req
, req
->ntvfs
->async_states
->status
);
2005 /* we need to divide up the reply into chunks that fit into
2006 the negotiated buffer size */
2008 uint16_t this_data
, this_param
, max_bytes
;
2009 unsigned int align1
= 1, align2
= (params_left
? 2 : 0);
2010 struct smbsrv_request
*this_req
;
2012 max_bytes
= req_max_data(req
) - (align1
+ align2
);
2014 this_param
= params_left
;
2015 if (this_param
> max_bytes
) {
2016 this_param
= max_bytes
;
2018 max_bytes
-= this_param
;
2020 this_data
= data_left
;
2021 if (this_data
> max_bytes
) {
2022 this_data
= max_bytes
;
2025 /* don't destroy unless this is the last chunk */
2026 if (params_left
- this_param
!= 0 ||
2027 data_left
- this_data
!= 0) {
2028 this_req
= smbsrv_setup_secondary_request(req
);
2033 req_grow_data(this_req
, this_param
+ this_data
+ (align1
+ align2
));
2035 SSVAL(this_req
->out
.vwv
, VWV(0), trans
->out
.params
.length
);
2036 SSVAL(this_req
->out
.vwv
, VWV(1), trans
->out
.data
.length
);
2037 SSVAL(this_req
->out
.vwv
, VWV(2), 0);
2039 SSVAL(this_req
->out
.vwv
, VWV(3), this_param
);
2040 SSVAL(this_req
->out
.vwv
, VWV(4), align1
+ PTR_DIFF(this_req
->out
.data
, this_req
->out
.hdr
));
2041 SSVAL(this_req
->out
.vwv
, VWV(5), PTR_DIFF(params
, trans
->out
.params
.data
));
2043 SSVAL(this_req
->out
.vwv
, VWV(6), this_data
);
2044 SSVAL(this_req
->out
.vwv
, VWV(7), align1
+ align2
+
2045 PTR_DIFF(this_req
->out
.data
+ this_param
, this_req
->out
.hdr
));
2046 SSVAL(this_req
->out
.vwv
, VWV(8), PTR_DIFF(data
, trans
->out
.data
.data
));
2048 SCVAL(this_req
->out
.vwv
, VWV(9), trans
->out
.setup_count
);
2049 SCVAL(this_req
->out
.vwv
, VWV(9)+1, 0); /* reserved */
2050 for (i
=0;i
<trans
->out
.setup_count
;i
++) {
2051 SSVAL(this_req
->out
.vwv
, VWV(10+i
), trans
->out
.setup
[i
]);
2054 memset(this_req
->out
.data
, 0, align1
);
2055 if (this_param
!= 0) {
2056 memcpy(this_req
->out
.data
+ align1
, params
, this_param
);
2058 memset(this_req
->out
.data
+this_param
+align1
, 0, align2
);
2059 if (this_data
!= 0) {
2060 memcpy(this_req
->out
.data
+this_param
+align1
+align2
, data
, this_data
);
2063 params_left
-= this_param
;
2064 data_left
-= this_data
;
2065 params
+= this_param
;
2068 smbsrv_send_reply(this_req
);
2069 } while (params_left
!= 0 || data_left
!= 0);
2074 answer a reconstructed trans request
2076 static void reply_trans_complete(struct smbsrv_request
*req
, uint8_t command
,
2077 struct smb_trans2
*trans
)
2079 struct trans_op
*op
;
2081 SMBSRV_TALLOC_IO_PTR(op
, struct trans_op
);
2082 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
2086 op
->command
= command
;
2090 /* its a full request, give it to the backend */
2091 if (command
== SMBtrans
) {
2092 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req
->ntvfs
, trans
));
2095 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req
, op
));
2101 Reply to an SMBtrans or SMBtrans2 request
2103 static void reply_trans_generic(struct smbsrv_request
*req
, uint8_t command
)
2105 struct smb_trans2
*trans
;
2107 uint16_t param_ofs
, data_ofs
;
2108 uint16_t param_count
, data_count
;
2109 uint16_t param_total
, data_total
;
2112 if (req
->in
.wct
< 14) {
2113 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2117 trans
= talloc(req
, struct smb_trans2
);
2118 if (trans
== NULL
) {
2119 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
2123 param_total
= SVAL(req
->in
.vwv
, VWV(0));
2124 data_total
= SVAL(req
->in
.vwv
, VWV(1));
2125 trans
->in
.max_param
= SVAL(req
->in
.vwv
, VWV(2));
2126 trans
->in
.max_data
= SVAL(req
->in
.vwv
, VWV(3));
2127 trans
->in
.max_setup
= CVAL(req
->in
.vwv
, VWV(4));
2128 trans
->in
.flags
= SVAL(req
->in
.vwv
, VWV(5));
2129 trans
->in
.timeout
= IVAL(req
->in
.vwv
, VWV(6));
2130 param_count
= SVAL(req
->in
.vwv
, VWV(9));
2131 param_ofs
= SVAL(req
->in
.vwv
, VWV(10));
2132 data_count
= SVAL(req
->in
.vwv
, VWV(11));
2133 data_ofs
= SVAL(req
->in
.vwv
, VWV(12));
2134 trans
->in
.setup_count
= CVAL(req
->in
.vwv
, VWV(13));
2136 if (req
->in
.wct
!= 14 + trans
->in
.setup_count
) {
2137 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
2141 /* parse out the setup words */
2142 trans
->in
.setup
= talloc_array(trans
, uint16_t, trans
->in
.setup_count
);
2143 if (trans
->in
.setup_count
&& !trans
->in
.setup
) {
2144 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
2147 for (i
=0;i
<trans
->in
.setup_count
;i
++) {
2148 trans
->in
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(14+i
));
2151 if (command
== SMBtrans
) {
2152 req_pull_string(&req
->in
.bufinfo
, &trans
->in
.trans_name
, req
->in
.data
, -1, STR_TERMINATE
);
2155 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
->in
.params
) ||
2156 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
->in
.data
)) {
2157 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
2161 /* is it a partial request? if so, then send a 'send more' message */
2162 if (param_total
> param_count
|| data_total
> data_count
) {
2163 reply_trans_continue(req
, command
, trans
);
2167 reply_trans_complete(req
, command
, trans
);
2172 Reply to an SMBtranss2 request
2174 static void reply_transs_generic(struct smbsrv_request
*req
, uint8_t command
)
2176 struct smbsrv_trans_partial
*tp
;
2177 struct smb_trans2
*trans
= NULL
;
2178 uint16_t param_ofs
, data_ofs
;
2179 uint16_t param_count
, data_count
;
2180 uint16_t param_disp
, data_disp
;
2181 uint16_t param_total
, data_total
;
2182 DATA_BLOB params
, data
;
2185 if (command
== SMBtrans2
) {
2192 if (req
->in
.wct
!= wct
) {
2194 * TODO: add some error code tests
2195 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
2197 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2201 for (tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) {
2202 if (tp
->command
== command
&&
2203 SVAL(tp
->req
->in
.hdr
, HDR_MID
) == SVAL(req
->in
.hdr
, HDR_MID
)) {
2204 /* TODO: check the VUID, PID and TID too? */
2210 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2214 trans
= tp
->u
.trans
;
2216 param_total
= SVAL(req
->in
.vwv
, VWV(0));
2217 data_total
= SVAL(req
->in
.vwv
, VWV(1));
2218 param_count
= SVAL(req
->in
.vwv
, VWV(2));
2219 param_ofs
= SVAL(req
->in
.vwv
, VWV(3));
2220 param_disp
= SVAL(req
->in
.vwv
, VWV(4));
2221 data_count
= SVAL(req
->in
.vwv
, VWV(5));
2222 data_ofs
= SVAL(req
->in
.vwv
, VWV(6));
2223 data_disp
= SVAL(req
->in
.vwv
, VWV(7));
2225 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, ¶ms
) ||
2226 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &data
)) {
2227 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2231 /* only allow contiguous requests */
2232 if ((param_count
!= 0 &&
2233 param_disp
!= trans
->in
.params
.length
) ||
2235 data_disp
!= trans
->in
.data
.length
)) {
2236 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
2240 /* add to the existing request */
2241 if (param_count
!= 0) {
2242 trans
->in
.params
.data
= talloc_realloc(trans
,
2243 trans
->in
.params
.data
,
2245 param_disp
+ param_count
);
2246 if (trans
->in
.params
.data
== NULL
) {
2247 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
2250 trans
->in
.params
.length
= param_disp
+ param_count
;
2253 if (data_count
!= 0) {
2254 trans
->in
.data
.data
= talloc_realloc(trans
,
2255 trans
->in
.data
.data
,
2257 data_disp
+ data_count
);
2258 if (trans
->in
.data
.data
== NULL
) {
2259 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
2262 trans
->in
.data
.length
= data_disp
+ data_count
;
2265 memcpy(trans
->in
.params
.data
+ param_disp
, params
.data
, params
.length
);
2266 memcpy(trans
->in
.data
.data
+ data_disp
, data
.data
, data
.length
);
2268 /* the sequence number of the reply is taken from the last secondary
2270 tp
->req
->seq_num
= req
->seq_num
;
2272 /* we don't reply to Transs2 requests */
2275 if (trans
->in
.params
.length
== param_total
&&
2276 trans
->in
.data
.length
== data_total
) {
2277 /* its now complete */
2280 reply_trans_complete(req
, command
, trans
);
2287 Reply to an SMBtrans2
2289 void smbsrv_reply_trans2(struct smbsrv_request
*req
)
2291 reply_trans_generic(req
, SMBtrans2
);
2295 Reply to an SMBtrans
2297 void smbsrv_reply_trans(struct smbsrv_request
*req
)
2299 reply_trans_generic(req
, SMBtrans
);
2303 Reply to an SMBtranss request
2305 void smbsrv_reply_transs(struct smbsrv_request
*req
)
2307 reply_transs_generic(req
, SMBtrans
);
2311 Reply to an SMBtranss2 request
2313 void smbsrv_reply_transs2(struct smbsrv_request
*req
)
2315 reply_transs_generic(req
, SMBtrans2
);