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.data.server_type = DFS_SERVER_NON_ROOT;
876 ref->referral.v3.size = 18;
878 ref->referral.v3.data.entry_flags = 0;
879 ref->referral.v3.data.ttl = 600; /* As w2k3 */
880 ref->referral.v3.data.referrals.r1.DFS_path = dfs_path;
881 ref->referral.v3.data.referrals.r1.DFS_alt_path = dfs_path;
882 ref->referral.v3.data.referrals.r1.netw_address = server_path;
886 ref->version = version;
887 ref->referral.v4.server_type = DFS_SERVER_NON_ROOT;
888 ref->referral.v4.size = 18;
891 ref->referral.v4.entry_flags = DFS_HEADER_FLAG_TARGET_BCK;
893 ref->referral.v4.ttl = 600; /* As w2k3 */
894 ref->referral.v4.r1.DFS_path = dfs_path;
895 ref->referral.v4.r1.DFS_alt_path = dfs_path;
896 ref->referral.v4.r1.netw_address = server_path;
900 return NT_STATUS_INVALID_LEVEL;
904 fill a domain refererral
906 static NTSTATUS fill_domain_dfs_referraltype(struct dfs_referral_type *ref,
915 ref->version = version;
916 ref->referral.v3.data.server_type = DFS_SERVER_NON_ROOT;
917 ref->referral.v3.size = 34;
918 ref->referral.v3.data.entry_flags = DFS_FLAG_REFERRAL_DOMAIN_RESP;
919 ref->referral.v3.data.ttl = 600; /* As w2k3 */
920 ref->referral.v3.data.referrals.r2.special_name = domain;
921 ref->referral.v3.data.referrals.r2.nb_expanded_names = numnames;
922 /* Put the final terminator */
924 const char **names2 = talloc_array(ref, const char *, numnames+1);
925 NT_STATUS_HAVE_NO_MEMORY(names2);
927 for (i = 0; i<numnames; i++) {
928 names2[i] = talloc_asprintf(names2, "\\%s", names[i]);
929 NT_STATUS_HAVE_NO_MEMORY(names2[i]);
931 names2[numnames] = 0;
932 ref->referral.v3.data.referrals.r2.expanded_names = names2;
936 return NT_STATUS_INVALID_LEVEL;
940 get the DCs list within a site
942 static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
943 struct ldb_dn *sitedn, struct dc_set *list,
946 static const char *attrs[] = { "serverReference", NULL };
947 static const char *attrs2[] = { "dNSHostName", "sAMAccountName", NULL };
948 struct ldb_result *r;
951 const char **dc_list;
953 ret = ldb_search(ldb, ctx, &r, sitedn, LDB_SCOPE_SUBTREE, attrs,
954 "(&(objectClass=server)(serverReference=*))");
955 if (ret != LDB_SUCCESS) {
956 DEBUG(2,(__location__ ": Failed to get list of servers - %s\n",
957 ldb_errstring(ldb)));
958 return NT_STATUS_INTERNAL_ERROR;
962 /* none in this site */
968 * need to search for all server object to know the size of the array.
969 * Search all the object of class server in this site
971 dc_list = talloc_array(r, const char *, r->count);
972 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, r);
974 /* TODO put some random here in the order */
975 list->names = talloc_realloc(list, list->names, const char *, list->count + r->count);
976 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names, r);
978 for (i = 0; i<r->count; i++) {
980 struct ldb_result *r2;
982 dn = ldb_msg_find_attr_as_dn(ldb, ctx, r->msgs[i], "serverReference");
984 return NT_STATUS_INTERNAL_ERROR;
987 ret = ldb_search(ldb, r, &r2, dn, LDB_SCOPE_BASE, attrs2, "(objectClass=computer)");
988 if (ret != LDB_SUCCESS) {
989 DEBUG(2,(__location__ ": Search for computer on %s failed - %s\n",
990 ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
991 return NT_STATUS_INTERNAL_ERROR;
995 const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL);
997 DEBUG(2,(__location__ ": dNSHostName missing on %s\n",
998 ldb_dn_get_linearized(dn)));
1000 return NT_STATUS_INTERNAL_ERROR;
1003 list->names[list->count] = talloc_strdup(list->names, dns);
1004 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r);
1007 const char *acct = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", NULL);
1009 DEBUG(2,(__location__ ": sAMAccountName missing on %s\n",
1010 ldb_dn_get_linearized(dn)));
1012 return NT_STATUS_INTERNAL_ERROR;
1015 tmp = talloc_strdup(list->names, acct);
1016 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r);
1018 /* Netbios name is also the sAMAccountName for
1019 computer but without the final $ */
1020 tmp[strlen(tmp) - 1] = '\0';
1021 list->names[list->count] = tmp;
1028 return NT_STATUS_OK;
1035 static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
1036 const char *searched_site, bool need_fqdn,
1037 struct dc_set ***pset_list, uint32_t flags)
1040 * Flags will be used later to indicate things like least-expensive
1041 * or same-site options
1043 const char *attrs_none[] = { NULL };
1044 const char *attrs3[] = { "name", NULL };
1045 struct ldb_dn *configdn, *sitedn, *dn, *sitescontainerdn;
1046 struct ldb_result *r;
1047 struct dc_set **set_list = NULL;
1050 uint32_t current_pos = 0;
1052 TALLOC_CTX *subctx = talloc_new(ctx);
1054 *pset_list = set_list = NULL;
1056 subctx = talloc_new(ctx);
1057 NT_STATUS_HAVE_NO_MEMORY(subctx);
1059 configdn = ldb_get_config_basedn(ldb);
1061 /* Let's search for the Site container */
1062 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs_none,
1063 "(objectClass=sitesContainer)");
1064 if (ret != LDB_SUCCESS) {
1065 DEBUG(2,(__location__ ": Failed to find sitesContainer within %s - %s\n",
1066 ldb_dn_get_linearized(configdn), ldb_errstring(ldb)));
1067 talloc_free(subctx);
1068 return NT_STATUS_INTERNAL_ERROR;
1071 DEBUG(2,(__location__ ": Expected 1 sitesContainer - found %u within %s\n",
1072 r->count, ldb_dn_get_linearized(configdn)));
1073 talloc_free(subctx);
1074 return NT_STATUS_INTERNAL_ERROR;
1077 sitescontainerdn = talloc_steal(subctx, r->msgs[0]->dn);
1081 * TODO: Here we should have a more subtle handling
1082 * for the case "same-site"
1084 ret = ldb_search(ldb, subctx, &r, sitescontainerdn, LDB_SCOPE_SUBTREE,
1085 attrs_none, "(objectClass=server)");
1086 if (ret != LDB_SUCCESS) {
1087 DEBUG(2,(__location__ ": Failed to find servers within %s - %s\n",
1088 ldb_dn_get_linearized(sitescontainerdn), ldb_errstring(ldb)));
1089 talloc_free(subctx);
1090 return NT_STATUS_INTERNAL_ERROR;
1094 if (searched_site != NULL) {
1095 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE,
1096 attrs_none, "(&(name=%s)(objectClass=site))", searched_site);
1097 if (ret != LDB_SUCCESS) {
1098 talloc_free(subctx);
1099 return NT_STATUS_FOOBAR;
1100 } else if (r->count != 1) {
1101 talloc_free(subctx);
1102 return NT_STATUS_FOOBAR;
1105 /* All of this was to get the DN of the searched_site */
1106 sitedn = r->msgs[0]->dn;
1108 set_list = talloc_realloc(subctx, set_list, struct dc_set *, current_pos+1);
1109 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1111 set_list[current_pos] = talloc(set_list, struct dc_set);
1112 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1114 set_list[current_pos]->names = NULL;
1115 set_list[current_pos]->count = 0;
1116 status = get_dcs_insite(subctx, ldb, sitedn,
1117 set_list[current_pos], need_fqdn);
1118 if (!NT_STATUS_IS_OK(status)) {
1119 DEBUG(2,(__location__ ": Failed to get DC from site %s - %s\n",
1120 ldb_dn_get_linearized(sitedn), nt_errstr(status)));
1121 talloc_free(subctx);
1128 /* Let's find all the sites */
1129 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs3, "(objectClass=site)");
1130 if (ret != LDB_SUCCESS) {
1131 DEBUG(2,(__location__ ": Failed to find any site containers in %s\n",
1132 ldb_dn_get_linearized(configdn)));
1133 talloc_free(subctx);
1134 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1139 * We should randomize the order in the main site,
1140 * it's mostly needed for sysvol/netlogon referral.
1141 * Depending of flag we either randomize order of the
1142 * not "in the same site DCs"
1143 * or we randomize by group of site that have the same cost
1144 * In the long run we want to manipulate an array of site_set
1145 * All the site in one set have the same cost (if least-expansive options is selected)
1146 * and we will put all the dc related to 1 site set into 1 DCs set.
1147 * Within a site set, site order has to be randomized
1149 * But for the moment we just return the list of sites
1153 * We will realloc + 2 because we will need one additional place
1154 * for element at current_pos + 1 for the NULL element
1156 set_list = talloc_realloc(subctx, set_list, struct dc_set *,
1158 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1160 set_list[current_pos] = talloc(ctx, struct dc_set);
1161 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1163 set_list[current_pos]->names = NULL;
1164 set_list[current_pos]->count = 0;
1166 set_list[current_pos+1] = NULL;
1169 for (i=0; i<r->count; i++) {
1170 const char *site_name = ldb_msg_find_attr_as_string(r->msgs[i], "name", NULL);
1171 if (site_name == NULL) {
1172 DEBUG(2,(__location__ ": Failed to find name attribute in %s\n",
1173 ldb_dn_get_linearized(r->msgs[i]->dn)));
1174 talloc_free(subctx);
1175 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1178 if (searched_site == NULL ||
1179 strcmp(searched_site, site_name) != 0) {
1180 DEBUG(2,(__location__ ": Site: %s %s\n",
1181 searched_site, site_name));
1184 * Do all the site but the one of the client
1185 * (because it has already been done ...)
1187 dn = r->msgs[i]->dn;
1189 status = get_dcs_insite(subctx, ldb, dn,
1190 set_list[current_pos],
1192 if (!NT_STATUS_IS_OK(status)) {
1193 talloc_free(subctx);
1199 set_list[current_pos] = NULL;
1201 *pset_list = talloc_move(ctx, &set_list);
1202 talloc_free(subctx);
1203 return NT_STATUS_OK;
1206 static NTSTATUS dodomain_referral(TALLOC_CTX *ctx,
1207 const struct dfs_GetDFSReferral_in *dfsreq,
1208 struct ldb_context *ldb,
1209 struct smb_trans2 *trans,
1210 struct loadparm_context *lp_ctx)
1213 * TODO for the moment we just return the local domain
1216 enum ndr_err_code ndr_err;
1218 const char *dns_domain = lpcfg_dnsdomain(lp_ctx);
1219 const char *netbios_domain = lpcfg_workgroup(lp_ctx);
1220 struct dfs_referral_resp resp;
1221 struct dfs_referral_type *tab;
1222 struct dfs_referral_type *referral;
1223 const char *referral_str;
1224 /* In the future this needs to be fetched from the ldb */
1225 uint32_t found_domain = 2;
1226 uint32_t current_pos = 0;
1227 TALLOC_CTX *context;
1229 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1230 DEBUG(10 ,("Received a domain referral request on a non DC\n"));
1231 return NT_STATUS_INVALID_PARAMETER;
1234 if (dfsreq->max_referral_level < 3) {
1235 DEBUG(2,("invalid max_referral_level %u\n",
1236 dfsreq->max_referral_level));
1237 return NT_STATUS_UNSUCCESSFUL;
1240 context = talloc_new(ctx);
1241 NT_STATUS_HAVE_NO_MEMORY(context);
1243 resp.path_consumed = 0;
1244 resp.header_flags = 0; /* Do like w2k3 */
1245 resp.nb_referrals = found_domain; /* the fqdn one + the NT domain */
1247 tab = talloc_array(context, struct dfs_referral_type, found_domain);
1248 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tab, context);
1250 referral = talloc(tab, struct dfs_referral_type);
1251 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1252 referral_str = talloc_asprintf(referral, "\\%s", dns_domain);
1253 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1254 status = fill_domain_dfs_referraltype(referral, 3,
1257 if (!NT_STATUS_IS_OK(status)) {
1258 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1259 talloc_free(context);
1260 return NT_STATUS_UNSUCCESSFUL;
1263 tab[current_pos] = *referral;
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;
1278 tab[current_pos] = *referral;
1282 * Put here the code from filling the array for trusted domain
1284 resp.referral_entries = tab;
1286 ndr_err = ndr_push_struct_blob(&outblob, context,
1288 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1289 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1290 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1291 talloc_free(context);
1292 return NT_STATUS_INTERNAL_ERROR;
1295 if (outblob.length > trans->in.max_data) {
1298 DEBUG(3, ("Blob is too big for the output buffer "
1300 (unsigned int)outblob.length, trans->in.max_data));
1302 if (trans->in.max_data != MAX_DFS_RESPONSE) {
1303 /* As specified in MS-DFSC.pdf 3.3.5.2 */
1304 talloc_free(context);
1305 return STATUS_BUFFER_OVERFLOW;
1309 * The answer is too big, so let's remove some answers
1311 while (!ok && resp.nb_referrals > 2) {
1312 data_blob_free(&outblob);
1315 * Let's scrap the first referral (for now)
1317 resp.nb_referrals -= 1;
1318 resp.referral_entries += 1;
1320 ndr_err = ndr_push_struct_blob(&outblob, context,
1322 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1323 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1324 talloc_free(context);
1325 return NT_STATUS_INTERNAL_ERROR;
1328 if (outblob.length <= MAX_DFS_RESPONSE) {
1329 DEBUG(10,("DFS: managed to reduce the size of referral initial"
1330 "number of referral %d, actual count: %d",
1331 found_domain, resp.nb_referrals));
1337 if (!ok && resp.nb_referrals == 2) {
1338 DEBUG(0, (__location__ "; Not able to fit the domain and realm in DFS a "
1339 " 56K buffer, something must be broken"));
1340 talloc_free(context);
1341 return NT_STATUS_INTERNAL_ERROR;
1345 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1347 trans->out.data = outblob;
1348 talloc_steal(ctx, outblob.data);
1349 talloc_free(context);
1350 return NT_STATUS_OK;
1354 * Handle the logic for dfs referral request like \\domain
1355 * or \\domain\sysvol or \\fqdn or \\fqdn\netlogon
1357 static NTSTATUS dodc_or_sysvol_referral(TALLOC_CTX *ctx,
1358 const struct dfs_GetDFSReferral_in dfsreq,
1359 const char* requestedname,
1360 struct ldb_context *ldb,
1361 struct smb_trans2 *trans,
1362 struct smbsrv_request *req,
1363 struct loadparm_context *lp_ctx)
1366 * It's not a "standard" DFS referral but a referral to get the DC list
1367 * or sysvol/netlogon
1368 * Let's check that it's for one of our domain ...
1372 unsigned int num_domain = 1;
1373 enum ndr_err_code ndr_err;
1374 const char *requesteddomain;
1375 const char *realm = lpcfg_realm(lp_ctx);
1376 const char *domain = lpcfg_workgroup(lp_ctx);
1377 const char *site_name = NULL; /* Name of the site where the client is */
1380 bool need_fqdn = false;
1381 bool dc_referral = true;
1384 struct dc_set **set;
1385 char const **domain_list;
1386 struct tsocket_address *remote_address;
1387 char *client_addr = NULL;
1388 TALLOC_CTX *context;
1390 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1391 return NT_STATUS_INVALID_PARAMETER;
1394 if (dfsreq.max_referral_level < 3) {
1395 DEBUG(2,("invalid max_referral_level %u\n",
1396 dfsreq.max_referral_level));
1397 return NT_STATUS_UNSUCCESSFUL;
1400 context = talloc_new(ctx);
1401 NT_STATUS_HAVE_NO_MEMORY(context);
1403 if (requestedname[0] == '\\' && !strchr(requestedname+1,'\\')) {
1406 requesteddomain = requestedname;
1408 if (strchr(requestedname,'\\')) {
1410 /* we have a second part */
1411 requesteddomain = talloc_strdup(context, requestedname+1);
1412 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(requesteddomain, context);
1413 subpart = strchr(requesteddomain,'\\');
1416 tmp = strchr(requestedname + 1,'\\'); /* To get second \ if any */
1419 /* There was a share */
1421 dc_referral = false;
1425 * We will fetch the trusted domain list soon with something like this:
1427 * "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)
1428 * (trustPartner=%s))(objectclass=trustedDomain))"
1430 * Allocate for num_domain + 1 so that the last element will be NULL)
1432 domain_list = talloc_array(context, const char*, num_domain+1);
1433 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_list, context);
1435 domain_list[0] = realm;
1436 domain_list[1] = domain;
1437 for (i=0; i<=num_domain; i++) {
1438 if (strncasecmp(domain_list[i], requesteddomain, strlen(domain_list[i])) == 0) {
1445 /* The requested domain is not one that we support */
1446 DEBUG(3,("Requested referral for domain %s, but we don't handle it",
1448 return NT_STATUS_INVALID_PARAMETER;
1451 if (strchr(requestedname,'.')) {
1455 remote_address = req->smb_conn->connection->remote_address;
1456 if (tsocket_address_is_inet(remote_address, "ip")) {
1457 client_addr = tsocket_address_inet_addr_string(remote_address, context);
1458 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_addr, context);
1461 status = get_dcs(context, ldb, site_name, need_fqdn, &set, 0);
1462 if (!NT_STATUS_IS_OK(status)) {
1463 DEBUG(3,("Unable to get list of DCs\n"));
1464 talloc_free(context);
1469 const char **dc_list = NULL;
1470 uint32_t num_dcs = 0;
1471 struct dfs_referral_type *referral;
1472 const char *referral_str;
1473 struct dfs_referral_resp resp;
1475 for(i=0; set[i]; i++) {
1478 dc_list = talloc_realloc(context, dc_list, const char*,
1479 num_dcs + set[i]->count + 1);
1480 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, context);
1482 for(j=0; j<set[i]->count; j++) {
1483 dc_list[num_dcs + j] = talloc_move(context, &set[i]->names[j]);
1485 num_dcs = num_dcs + set[i]->count;
1486 TALLOC_FREE(set[i]);
1487 dc_list[num_dcs] = NULL;
1490 resp.path_consumed = 0;
1491 resp.header_flags = 0; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1494 * The NumberOfReferrals field MUST be set to 1,
1495 * independent of the number of DC names
1496 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1498 resp.nb_referrals = 1;
1500 /* Put here the code from filling the array for trusted domain */
1501 referral = talloc(context, struct dfs_referral_type);
1502 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1504 referral_str = talloc_asprintf(referral, "\\%s",
1506 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1508 status = fill_domain_dfs_referraltype(referral, 3,
1511 if (!NT_STATUS_IS_OK(status)) {
1512 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1513 talloc_free(context);
1514 return NT_STATUS_UNSUCCESSFUL;
1516 resp.referral_entries = referral;
1518 ndr_err = ndr_push_struct_blob(&outblob, context,
1520 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1521 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1522 DEBUG(2,(__location__ ":NDR marshalling of dfs referral response failed\n"));
1523 talloc_free(context);
1524 return NT_STATUS_INTERNAL_ERROR;
1527 unsigned int nb_entries = 0;
1528 unsigned int current = 0;
1529 struct dfs_referral_type *tab;
1530 struct dfs_referral_resp resp;
1532 for(i=0; set[i]; i++) {
1533 nb_entries = nb_entries + set[i]->count;
1536 resp.path_consumed = 2*strlen(requestedname); /* The length is expected in bytes */
1537 resp.header_flags = DFS_HEADER_FLAG_STORAGE_SVR; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1540 * The NumberOfReferrals field MUST be set to 1,
1541 * independent of the number of DC names
1542 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1544 resp.nb_referrals = nb_entries;
1546 tab = talloc_array(context, struct dfs_referral_type, nb_entries);
1547 NT_STATUS_HAVE_NO_MEMORY(tab);
1549 for(i=0; set[i]; i++) {
1552 for(j=0; j< set[i]->count; j++) {
1553 struct dfs_referral_type *referral;
1554 const char *referral_str;
1556 referral = talloc(tab, struct dfs_referral_type);
1557 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1559 referral_str = talloc_asprintf(referral, "\\%s\\%s",
1560 set[i]->names[j], share);
1561 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1563 status = fill_normal_dfs_referraltype(referral,
1564 dfsreq.max_referral_level,
1565 requestedname, referral_str, j==0);
1566 if (!NT_STATUS_IS_OK(status)) {
1567 DEBUG(2, (__location__ ": Unable to fill a normal dfs referral object"));
1568 talloc_free(context);
1569 return NT_STATUS_UNSUCCESSFUL;
1571 tab[current] = *referral;
1575 resp.referral_entries = tab;
1577 ndr_err = ndr_push_struct_blob(&outblob, context,
1579 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1580 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1581 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1582 talloc_free(context);
1583 return NT_STATUS_INTERNAL_ERROR;
1587 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1590 * TODO If the size is too big we should remove
1591 * some DC from the answer or return STATUS_BUFFER_OVERFLOW
1593 trans->out.data = outblob;
1594 talloc_steal(ctx, outblob.data);
1595 talloc_free(context);
1596 return NT_STATUS_OK;
1600 trans2 getdfsreferral implementation
1602 static NTSTATUS trans2_getdfsreferral(struct smbsrv_request *req,
1603 struct trans_op *op)
1605 enum ndr_err_code ndr_err;
1606 struct smb_trans2 *trans = op->trans;
1607 struct dfs_GetDFSReferral_in dfsreq;
1608 TALLOC_CTX *context;
1609 struct ldb_context *ldb;
1610 struct loadparm_context *lp_ctx;
1611 const char *realm, *nbname, *requestedname;
1615 lp_ctx = req->tcon->ntvfs->lp_ctx;
1616 if (!lpcfg_host_msdfs(lp_ctx)) {
1617 return NT_STATUS_NOT_IMPLEMENTED;
1620 context = talloc_new(req);
1621 NT_STATUS_HAVE_NO_MEMORY(context);
1623 ldb = samdb_connect(context, req->tcon->ntvfs->event_ctx, lp_ctx, system_session(lp_ctx));
1625 DEBUG(2,(__location__ ": Failed to open samdb\n"));
1626 talloc_free(context);
1627 return NT_STATUS_INTERNAL_ERROR;
1630 ndr_err = ndr_pull_struct_blob(&trans->in.params, op,
1632 (ndr_pull_flags_fn_t)ndr_pull_dfs_GetDFSReferral_in);
1633 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1634 status = ndr_map_error2ntstatus(ndr_err);
1635 DEBUG(2,(__location__ ": Failed to parse GetDFSReferral_in - %s\n",
1636 nt_errstr(status)));
1637 talloc_free(context);
1641 DEBUG(10, ("Requested DFS name: %s length: %u\n",
1642 dfsreq.servername, (unsigned int)strlen(dfsreq.servername)));
1645 * If the servername is "" then we are in a case of domain dfs
1646 * and the client just searches for the list of local domain
1647 * it is attached and also trusted ones.
1649 requestedname = dfsreq.servername;
1650 if (requestedname == NULL || requestedname[0] == '\0') {
1651 return dodomain_referral(op, &dfsreq, ldb, trans, lp_ctx);
1654 realm = lpcfg_realm(lp_ctx);
1655 nbname = lpcfg_netbios_name(lp_ctx);
1656 fqdn = talloc_asprintf(context, "%s.%s", nbname, realm);
1658 if ((strncasecmp(requestedname+1, nbname, strlen(nbname)) == 0) ||
1659 (strncasecmp(requestedname+1, fqdn, strlen(fqdn)) == 0) ) {
1661 * the referral request starts with \NETBIOSNAME or \fqdn
1662 * it's a standalone referral we do not do it
1663 * (TODO correct this)
1664 * If a DFS link that is a complete prefix of the DFS referral
1665 * request path is identified, the server MUST return a DFS link
1666 * referral response; otherwise, if it has a match for the DFS root,
1667 * it MUST return a root referral response.
1669 DEBUG(3, ("Received a standalone request for %s, we do not support standalone referral yet",requestedname));
1670 talloc_free(context);
1671 return NT_STATUS_NOT_FOUND;
1675 tmp = strchr(requestedname + 1,'\\'); /* To get second \ if any */
1678 * If we have no slash at the first position or (foo.bar.domain.net)
1679 * a slash at the first position but no other slash (\foo.bar.domain.net)
1680 * or a slash at the first position and another slash
1681 * and netlogon or sysvol after the second slash
1682 * (\foo.bar.domain.net\sysvol) then we will handle it because
1683 * it's either a dc referral or a sysvol/netlogon referral
1685 if (requestedname[0] != '\\' ||
1687 strcasecmp(tmp+1, "sysvol") == 0 ||
1688 strcasecmp(tmp+1, "netlogon") == 0) {
1689 status = dodc_or_sysvol_referral(op, dfsreq, requestedname,
1690 ldb, trans, req, lp_ctx);
1691 talloc_free(context);
1695 if (requestedname[0] == '\\' &&
1697 strchr(tmp+1, '\\') &&
1698 (strncasecmp(tmp+1, "sysvol", 6) == 0 ||
1699 strncasecmp(tmp+1, "netlogon", 8) == 0)) {
1701 * We have more than two \ so it something like
1702 * \domain\sysvol\foobar
1704 talloc_free(context);
1705 return NT_STATUS_NOT_FOUND;
1708 talloc_free(context);
1709 /* By default until all the case are handled*/
1710 return NT_STATUS_NOT_FOUND;
1714 trans2 findfirst implementation
1716 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1718 struct smb_trans2 *trans = op->trans;
1719 union smb_search_first *search;
1721 struct find_state *state;
1723 /* make sure we got all the parameters */
1724 if (trans->in.params.length < 14) {
1725 return NT_STATUS_FOOBAR;
1728 search = talloc(op, union smb_search_first);
1729 NT_STATUS_HAVE_NO_MEMORY(search);
1731 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1732 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1733 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1734 level = SVAL(trans->in.params.data, 6);
1735 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1737 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1738 if (search->t2ffirst.in.pattern == NULL) {
1739 return NT_STATUS_FOOBAR;
1742 search->t2ffirst.level = RAW_SEARCH_TRANS2;
1743 search->t2ffirst.data_level = (enum smb_search_data_level)level;
1744 if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
1745 return NT_STATUS_INVALID_LEVEL;
1748 if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
1749 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1750 &search->t2ffirst.in.num_names,
1751 &search->t2ffirst.in.ea_names));
1754 /* setup the private state structure that the backend will
1755 give us in the callback */
1756 state = talloc(op, struct find_state);
1757 NT_STATUS_HAVE_NO_MEMORY(state);
1759 state->search = search;
1760 state->data_level = search->t2ffirst.data_level;
1761 state->last_entry_offset= 0;
1762 state->flags = search->t2ffirst.in.flags;
1764 /* setup for just a header in the reply */
1765 TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
1767 op->op_info = state;
1768 op->send_fn = trans2_findfirst_send;
1770 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1775 trans2 findnext send
1777 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1779 struct smbsrv_request *req = op->req;
1780 struct smb_trans2 *trans = op->trans;
1781 union smb_search_next *search;
1782 struct find_state *state;
1785 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1786 search = talloc_get_type(state->search, union smb_search_next);
1788 /* fill in the findfirst reply header */
1789 param = trans->out.params.data;
1790 SSVAL(param, VWV(0), search->t2fnext.out.count);
1791 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1792 SSVAL(param, VWV(2), 0);
1793 SSVAL(param, VWV(3), state->last_entry_offset);
1795 return NT_STATUS_OK;
1800 trans2 findnext implementation
1802 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1804 struct smb_trans2 *trans = op->trans;
1805 union smb_search_next *search;
1807 struct find_state *state;
1809 /* make sure we got all the parameters */
1810 if (trans->in.params.length < 12) {
1811 return NT_STATUS_FOOBAR;
1814 search = talloc(op, union smb_search_next);
1815 NT_STATUS_HAVE_NO_MEMORY(search);
1817 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1818 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1819 level = SVAL(trans->in.params.data, 4);
1820 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1821 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1823 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1824 if (search->t2fnext.in.last_name == NULL) {
1825 return NT_STATUS_FOOBAR;
1828 search->t2fnext.level = RAW_SEARCH_TRANS2;
1829 search->t2fnext.data_level = (enum smb_search_data_level)level;
1830 if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
1831 return NT_STATUS_INVALID_LEVEL;
1834 if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
1835 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1836 &search->t2fnext.in.num_names,
1837 &search->t2fnext.in.ea_names));
1840 /* setup the private state structure that the backend will give us in the callback */
1841 state = talloc(op, struct find_state);
1842 NT_STATUS_HAVE_NO_MEMORY(state);
1844 state->search = search;
1845 state->data_level = search->t2fnext.data_level;
1846 state->last_entry_offset= 0;
1847 state->flags = search->t2fnext.in.flags;
1849 /* setup for just a header in the reply */
1850 TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
1852 op->op_info = state;
1853 op->send_fn = trans2_findnext_send;
1855 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1860 backend for trans2 requests
1862 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1864 struct smb_trans2 *trans = op->trans;
1867 /* direct trans2 pass thru */
1868 status = ntvfs_trans2(req->ntvfs, trans);
1869 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1873 /* must have at least one setup word */
1874 if (trans->in.setup_count < 1) {
1875 return NT_STATUS_FOOBAR;
1878 /* the trans2 command is in setup[0] */
1879 switch (trans->in.setup[0]) {
1880 case TRANSACT2_GET_DFS_REFERRAL:
1881 return trans2_getdfsreferral(req, op);
1882 case TRANSACT2_FINDFIRST:
1883 return trans2_findfirst(req, op);
1884 case TRANSACT2_FINDNEXT:
1885 return trans2_findnext(req, op);
1886 case TRANSACT2_QPATHINFO:
1887 return trans2_qpathinfo(req, op);
1888 case TRANSACT2_QFILEINFO:
1889 return trans2_qfileinfo(req, op);
1890 case TRANSACT2_SETFILEINFO:
1891 return trans2_setfileinfo(req, op);
1892 case TRANSACT2_SETPATHINFO:
1893 return trans2_setpathinfo(req, op);
1894 case TRANSACT2_QFSINFO:
1895 return trans2_qfsinfo(req, op);
1896 case TRANSACT2_OPEN:
1897 return trans2_open(req, op);
1898 case TRANSACT2_MKDIR:
1899 return trans2_mkdir(req, op);
1902 /* an unknown trans2 command */
1903 return NT_STATUS_FOOBAR;
1906 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
1908 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1914 send a continue request
1916 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1917 struct smb_trans2 *trans)
1919 struct smbsrv_request *req2;
1920 struct smbsrv_trans_partial *tp;
1923 /* make sure they don't flood us */
1924 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1926 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1930 tp = talloc(req, struct smbsrv_trans_partial);
1933 tp->u.trans = trans;
1934 tp->command = command;
1936 DLIST_ADD(req->smb_conn->trans_partial, tp);
1937 talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1939 req2 = smbsrv_setup_secondary_request(req);
1941 /* send a 'please continue' reply */
1942 smbsrv_setup_reply(req2, 0, 0);
1943 smbsrv_send_reply(req2);
1948 answer a reconstructed trans request
1950 static void reply_trans_send(struct ntvfs_request *ntvfs)
1952 struct smbsrv_request *req;
1953 struct trans_op *op;
1954 struct smb_trans2 *trans;
1955 uint16_t params_left, data_left;
1956 uint8_t *params, *data;
1959 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1962 /* if this function needs work to form the nttrans reply buffer, then
1964 if (op->send_fn != NULL) {
1966 status = op->send_fn(op);
1967 if (!NT_STATUS_IS_OK(status)) {
1968 smbsrv_send_error(req, status);
1973 params_left = trans->out.params.length;
1974 data_left = trans->out.data.length;
1975 params = trans->out.params.data;
1976 data = trans->out.data.data;
1978 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1980 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1981 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1984 /* we need to divide up the reply into chunks that fit into
1985 the negotiated buffer size */
1987 uint16_t this_data, this_param, max_bytes;
1988 unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
1989 struct smbsrv_request *this_req;
1991 max_bytes = req_max_data(req) - (align1 + align2);
1993 this_param = params_left;
1994 if (this_param > max_bytes) {
1995 this_param = max_bytes;
1997 max_bytes -= this_param;
1999 this_data = data_left;
2000 if (this_data > max_bytes) {
2001 this_data = max_bytes;
2004 /* don't destroy unless this is the last chunk */
2005 if (params_left - this_param != 0 ||
2006 data_left - this_data != 0) {
2007 this_req = smbsrv_setup_secondary_request(req);
2012 req_grow_data(this_req, this_param + this_data + (align1 + align2));
2014 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
2015 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
2016 SSVAL(this_req->out.vwv, VWV(2), 0);
2018 SSVAL(this_req->out.vwv, VWV(3), this_param);
2019 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
2020 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
2022 SSVAL(this_req->out.vwv, VWV(6), this_data);
2023 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
2024 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
2025 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
2027 SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
2028 SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
2029 for (i=0;i<trans->out.setup_count;i++) {
2030 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
2033 memset(this_req->out.data, 0, align1);
2034 if (this_param != 0) {
2035 memcpy(this_req->out.data + align1, params, this_param);
2037 memset(this_req->out.data+this_param+align1, 0, align2);
2038 if (this_data != 0) {
2039 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
2042 params_left -= this_param;
2043 data_left -= this_data;
2044 params += this_param;
2047 smbsrv_send_reply(this_req);
2048 } while (params_left != 0 || data_left != 0);
2053 answer a reconstructed trans request
2055 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
2056 struct smb_trans2 *trans)
2058 struct trans_op *op;
2060 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
2061 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2065 op->command = command;
2069 /* its a full request, give it to the backend */
2070 if (command == SMBtrans) {
2071 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
2074 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
2080 Reply to an SMBtrans or SMBtrans2 request
2082 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
2084 struct smb_trans2 *trans;
2086 uint16_t param_ofs, data_ofs;
2087 uint16_t param_count, data_count;
2088 uint16_t param_total, data_total;
2091 if (req->in.wct < 14) {
2092 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2096 trans = talloc(req, struct smb_trans2);
2097 if (trans == NULL) {
2098 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2102 param_total = SVAL(req->in.vwv, VWV(0));
2103 data_total = SVAL(req->in.vwv, VWV(1));
2104 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
2105 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
2106 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
2107 trans->in.flags = SVAL(req->in.vwv, VWV(5));
2108 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
2109 param_count = SVAL(req->in.vwv, VWV(9));
2110 param_ofs = SVAL(req->in.vwv, VWV(10));
2111 data_count = SVAL(req->in.vwv, VWV(11));
2112 data_ofs = SVAL(req->in.vwv, VWV(12));
2113 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
2115 if (req->in.wct != 14 + trans->in.setup_count) {
2116 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
2120 /* parse out the setup words */
2121 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
2122 if (trans->in.setup_count && !trans->in.setup) {
2123 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2126 for (i=0;i<trans->in.setup_count;i++) {
2127 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
2130 if (command == SMBtrans) {
2131 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
2134 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
2135 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
2136 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2140 /* is it a partial request? if so, then send a 'send more' message */
2141 if (param_total > param_count || data_total > data_count) {
2142 reply_trans_continue(req, command, trans);
2146 reply_trans_complete(req, command, trans);
2151 Reply to an SMBtranss2 request
2153 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
2155 struct smbsrv_trans_partial *tp;
2156 struct smb_trans2 *trans = NULL;
2157 uint16_t param_ofs, data_ofs;
2158 uint16_t param_count, data_count;
2159 uint16_t param_disp, data_disp;
2160 uint16_t param_total, data_total;
2161 DATA_BLOB params, data;
2164 if (command == SMBtrans2) {
2171 if (req->in.wct != wct) {
2173 * TODO: add some error code tests
2174 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
2176 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2180 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
2181 if (tp->command == command &&
2182 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
2183 /* TODO: check the VUID, PID and TID too? */
2189 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2193 trans = tp->u.trans;
2195 param_total = SVAL(req->in.vwv, VWV(0));
2196 data_total = SVAL(req->in.vwv, VWV(1));
2197 param_count = SVAL(req->in.vwv, VWV(2));
2198 param_ofs = SVAL(req->in.vwv, VWV(3));
2199 param_disp = SVAL(req->in.vwv, VWV(4));
2200 data_count = SVAL(req->in.vwv, VWV(5));
2201 data_ofs = SVAL(req->in.vwv, VWV(6));
2202 data_disp = SVAL(req->in.vwv, VWV(7));
2204 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, ¶ms) ||
2205 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
2206 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2210 /* only allow contiguous requests */
2211 if ((param_count != 0 &&
2212 param_disp != trans->in.params.length) ||
2214 data_disp != trans->in.data.length)) {
2215 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2219 /* add to the existing request */
2220 if (param_count != 0) {
2221 trans->in.params.data = talloc_realloc(trans,
2222 trans->in.params.data,
2224 param_disp + param_count);
2225 if (trans->in.params.data == NULL) {
2226 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2229 trans->in.params.length = param_disp + param_count;
2232 if (data_count != 0) {
2233 trans->in.data.data = talloc_realloc(trans,
2234 trans->in.data.data,
2236 data_disp + data_count);
2237 if (trans->in.data.data == NULL) {
2238 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2241 trans->in.data.length = data_disp + data_count;
2244 memcpy(trans->in.params.data + param_disp, params.data, params.length);
2245 memcpy(trans->in.data.data + data_disp, data.data, data.length);
2247 /* the sequence number of the reply is taken from the last secondary
2249 tp->req->seq_num = req->seq_num;
2251 /* we don't reply to Transs2 requests */
2254 if (trans->in.params.length == param_total &&
2255 trans->in.data.length == data_total) {
2256 /* its now complete */
2259 reply_trans_complete(req, command, trans);
2266 Reply to an SMBtrans2
2268 void smbsrv_reply_trans2(struct smbsrv_request *req)
2270 reply_trans_generic(req, SMBtrans2);
2274 Reply to an SMBtrans
2276 void smbsrv_reply_trans(struct smbsrv_request *req)
2278 reply_trans_generic(req, SMBtrans);
2282 Reply to an SMBtranss request
2284 void smbsrv_reply_transs(struct smbsrv_request *req)
2286 reply_transs_generic(req, SMBtrans);
2290 Reply to an SMBtranss2 request
2292 void smbsrv_reply_transs2(struct smbsrv_request *req)
2294 reply_transs_generic(req, SMBtrans2);