2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
5 Copyright Matthieu Patou 2010 mat@matws.net
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 This file handles the parsing of transact2 requests
25 #include "smbd/service_stream.h"
26 #include "smb_server/smb_server.h"
27 #include "ntvfs/ntvfs.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "libcli/raw/raw_proto.h"
30 #include "librpc/gen_ndr/dfsblobs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "auth/session.h"
34 #include "param/param.h"
35 #include "lib/tsocket/tsocket.h"
37 #define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
39 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
40 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
41 trans2_setup_reply(trans, 0, 0, 0);\
42 return req->ntvfs->async_states->status; \
45 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
46 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
47 ptr = talloc_get_type(op->op_info, type); \
49 #define TRANS2_CHECK(cmd) do { \
52 NT_STATUS_NOT_OK_RETURN(_status); \
56 hold the state of a nttrans op while in progress. Needed to allow for async backend
60 struct smbsrv_request *req;
61 struct smb_trans2 *trans;
63 NTSTATUS (*send_fn)(struct trans_op *);
66 /* A DC set is a group of DC, they might have been grouped together
67 because they belong to the same site, or to site with same cost ...
73 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
74 if ((blob)->length < (size)) { \
75 return NT_STATUS_INFO_LENGTH_MISMATCH; \
78 /* setup a trans2 reply, given the data and params sizes */
79 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
80 uint16_t param_size, uint16_t data_size,
83 trans->out.setup_count = setup_count;
84 if (setup_count > 0) {
85 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
86 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
88 trans->out.params = data_blob_talloc(trans, NULL, param_size);
89 if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
91 trans->out.data = data_blob_talloc(trans, NULL, data_size);
92 if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
97 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
100 union smb_fsinfo *fsinfo,
101 int default_str_flags)
103 enum smb_fsinfo_level passthru_level;
105 switch (fsinfo->generic.level) {
106 case RAW_QFS_ALLOCATION:
107 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
109 SIVAL(blob->data, 0, fsinfo->allocation.out.fs_id);
110 SIVAL(blob->data, 4, fsinfo->allocation.out.sectors_per_unit);
111 SIVAL(blob->data, 8, fsinfo->allocation.out.total_alloc_units);
112 SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
113 SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
118 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
120 SIVAL(blob->data, 0, fsinfo->volume.out.serial_number);
121 /* w2k3 implements this incorrectly for unicode - it
122 * leaves the last byte off the string */
123 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
124 fsinfo->volume.out.volume_name.s,
125 4, default_str_flags,
126 STR_LEN8BIT|STR_NOALIGN));
130 case RAW_QFS_VOLUME_INFO:
131 passthru_level = RAW_QFS_VOLUME_INFORMATION;
134 case RAW_QFS_SIZE_INFO:
135 passthru_level = RAW_QFS_SIZE_INFORMATION;
138 case RAW_QFS_DEVICE_INFO:
139 passthru_level = RAW_QFS_DEVICE_INFORMATION;
142 case RAW_QFS_ATTRIBUTE_INFO:
143 passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
147 passthru_level = fsinfo->generic.level;
151 return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
152 passthru_level, fsinfo,
157 trans2 qfsinfo implementation send
159 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
161 struct smbsrv_request *req = op->req;
162 struct smb_trans2 *trans = op->trans;
163 union smb_fsinfo *fsinfo;
165 TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
167 TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
169 TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
170 &trans->out.data, fsinfo,
171 SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
177 trans2 qfsinfo implementation
179 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
181 struct smb_trans2 *trans = op->trans;
182 union smb_fsinfo *fsinfo;
185 /* make sure we got enough parameters */
186 if (trans->in.params.length != 2) {
187 return NT_STATUS_FOOBAR;
190 fsinfo = talloc(op, union smb_fsinfo);
191 NT_STATUS_HAVE_NO_MEMORY(fsinfo);
193 level = SVAL(trans->in.params.data, 0);
195 /* work out the backend level - we make it 1-1 in the header */
196 fsinfo->generic.level = (enum smb_fsinfo_level)level;
197 if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
198 return NT_STATUS_INVALID_LEVEL;
201 op->op_info = fsinfo;
202 op->send_fn = trans2_qfsinfo_send;
204 return ntvfs_fsinfo(req->ntvfs, fsinfo);
209 trans2 open implementation send
211 static NTSTATUS trans2_open_send(struct trans_op *op)
213 struct smbsrv_request *req = op->req;
214 struct smb_trans2 *trans = op->trans;
217 TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
219 TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
221 smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
222 SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
223 srv_push_dos_date3(req->smb_conn, trans->out.params.data,
224 VWV(2), io->t2open.out.write_time);
225 SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
226 SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
227 SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
228 SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
229 SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
230 SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
231 SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
232 SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
238 trans2 open implementation
240 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
242 struct smb_trans2 *trans = op->trans;
245 /* make sure we got enough parameters */
246 if (trans->in.params.length < 29) {
247 return NT_STATUS_FOOBAR;
250 io = talloc(op, union smb_open);
251 NT_STATUS_HAVE_NO_MEMORY(io);
253 io->t2open.level = RAW_OPEN_T2OPEN;
254 io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0));
255 io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1));
256 io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
257 io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3));
258 io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn,
259 trans->in.params.data + VWV(4));
260 io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6));
261 io->t2open.in.size = IVAL(trans->in.params.data, VWV(7));
262 io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9));
263 io->t2open.in.num_eas = 0;
264 io->t2open.in.eas = NULL;
266 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 28, &io->t2open.in.fname, 0);
267 if (io->t2open.in.fname == NULL) {
268 return NT_STATUS_FOOBAR;
271 TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
274 op->send_fn = trans2_open_send;
276 return ntvfs_open(req->ntvfs, io);
283 static NTSTATUS trans2_simple_send(struct trans_op *op)
285 struct smbsrv_request *req = op->req;
286 struct smb_trans2 *trans = op->trans;
288 TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
290 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
292 SSVAL(trans->out.params.data, VWV(0), 0);
298 trans2 mkdir implementation
300 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
302 struct smb_trans2 *trans = op->trans;
305 /* make sure we got enough parameters */
306 if (trans->in.params.length < 5) {
307 return NT_STATUS_FOOBAR;
310 io = talloc(op, union smb_mkdir);
311 NT_STATUS_HAVE_NO_MEMORY(io);
313 io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
314 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
315 if (io->t2mkdir.in.path == NULL) {
316 return NT_STATUS_FOOBAR;
319 TRANS2_CHECK(ea_pull_list(&trans->in.data, io,
320 &io->t2mkdir.in.num_eas,
321 &io->t2mkdir.in.eas));
324 op->send_fn = trans2_simple_send;
326 return ntvfs_mkdir(req->ntvfs, io);
329 static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
332 union smb_fileinfo *st,
333 int default_str_flags)
336 enum smb_fileinfo_level passthru_level;
338 switch (st->generic.level) {
339 case RAW_FILEINFO_GENERIC:
340 case RAW_FILEINFO_GETATTR:
341 case RAW_FILEINFO_GETATTRE:
342 case RAW_FILEINFO_SEC_DESC:
343 case RAW_FILEINFO_SMB2_ALL_EAS:
344 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
345 /* handled elsewhere */
346 return NT_STATUS_INVALID_LEVEL;
348 case RAW_FILEINFO_UNIX_BASIC:
349 case RAW_FILEINFO_UNIX_LINK:
350 /* not implemented yet */
351 return NT_STATUS_INVALID_LEVEL;
353 case RAW_FILEINFO_STANDARD:
354 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
356 srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
357 srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
358 srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
359 SIVAL(blob->data, 12, st->standard.out.size);
360 SIVAL(blob->data, 16, st->standard.out.alloc_size);
361 SSVAL(blob->data, 20, st->standard.out.attrib);
364 case RAW_FILEINFO_EA_SIZE:
365 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
367 srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
368 srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
369 srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
370 SIVAL(blob->data, 12, st->ea_size.out.size);
371 SIVAL(blob->data, 16, st->ea_size.out.alloc_size);
372 SSVAL(blob->data, 20, st->ea_size.out.attrib);
373 SIVAL(blob->data, 22, st->ea_size.out.ea_size);
376 case RAW_FILEINFO_EA_LIST:
377 list_size = ea_list_size(st->ea_list.out.num_eas,
378 st->ea_list.out.eas);
379 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
381 ea_put_list(blob->data,
382 st->ea_list.out.num_eas, st->ea_list.out.eas);
385 case RAW_FILEINFO_ALL_EAS:
386 list_size = ea_list_size(st->all_eas.out.num_eas,
387 st->all_eas.out.eas);
388 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
390 ea_put_list(blob->data,
391 st->all_eas.out.num_eas, st->all_eas.out.eas);
394 case RAW_FILEINFO_IS_NAME_VALID:
397 case RAW_FILEINFO_BASIC_INFO:
398 passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
401 case RAW_FILEINFO_STANDARD_INFO:
402 passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
405 case RAW_FILEINFO_EA_INFO:
406 passthru_level = RAW_FILEINFO_EA_INFORMATION;
409 case RAW_FILEINFO_COMPRESSION_INFO:
410 passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
413 case RAW_FILEINFO_ALL_INFO:
414 passthru_level = RAW_FILEINFO_ALL_INFORMATION;
417 case RAW_FILEINFO_NAME_INFO:
418 passthru_level = RAW_FILEINFO_NAME_INFORMATION;
421 case RAW_FILEINFO_ALT_NAME_INFO:
422 passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
425 case RAW_FILEINFO_STREAM_INFO:
426 passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
430 passthru_level = st->generic.level;
434 return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
440 fill in the reply from a qpathinfo or qfileinfo call
442 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
444 struct smbsrv_request *req = op->req;
445 struct smb_trans2 *trans = op->trans;
446 union smb_fileinfo *st;
448 TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
450 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
451 SSVAL(trans->out.params.data, 0, 0);
453 TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
454 &trans->out.data, st,
455 SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
461 trans2 qpathinfo implementation
463 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
465 struct smb_trans2 *trans = op->trans;
466 union smb_fileinfo *st;
469 /* make sure we got enough parameters */
470 if (trans->in.params.length < 2) {
471 return NT_STATUS_FOOBAR;
474 st = talloc(op, union smb_fileinfo);
475 NT_STATUS_HAVE_NO_MEMORY(st);
477 level = SVAL(trans->in.params.data, 0);
479 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
480 if (st->generic.in.file.path == NULL) {
481 return NT_STATUS_FOOBAR;
484 /* work out the backend level - we make it 1-1 in the header */
485 st->generic.level = (enum smb_fileinfo_level)level;
486 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
487 return NT_STATUS_INVALID_LEVEL;
490 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
491 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
492 &st->ea_list.in.num_names,
493 &st->ea_list.in.ea_names));
497 op->send_fn = trans2_fileinfo_send;
499 return ntvfs_qpathinfo(req->ntvfs, st);
504 trans2 qpathinfo implementation
506 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
508 struct smb_trans2 *trans = op->trans;
509 union smb_fileinfo *st;
511 struct ntvfs_handle *h;
513 /* make sure we got enough parameters */
514 if (trans->in.params.length < 4) {
515 return NT_STATUS_FOOBAR;
518 st = talloc(op, union smb_fileinfo);
519 NT_STATUS_HAVE_NO_MEMORY(st);
521 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
522 level = SVAL(trans->in.params.data, 2);
524 st->generic.in.file.ntvfs = h;
525 /* work out the backend level - we make it 1-1 in the header */
526 st->generic.level = (enum smb_fileinfo_level)level;
527 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
528 return NT_STATUS_INVALID_LEVEL;
531 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
532 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
533 &st->ea_list.in.num_names,
534 &st->ea_list.in.ea_names));
538 op->send_fn = trans2_fileinfo_send;
540 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
541 return ntvfs_qfileinfo(req->ntvfs, st);
546 parse a trans2 setfileinfo/setpathinfo data blob
548 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
549 union smb_setfileinfo *st,
550 const DATA_BLOB *blob)
552 enum smb_setfileinfo_level passthru_level;
554 switch (st->generic.level) {
555 case RAW_SFILEINFO_GENERIC:
556 case RAW_SFILEINFO_SETATTR:
557 case RAW_SFILEINFO_SETATTRE:
558 case RAW_SFILEINFO_SEC_DESC:
559 /* handled elsewhere */
560 return NT_STATUS_INVALID_LEVEL;
562 case RAW_SFILEINFO_STANDARD:
563 CHECK_MIN_BLOB_SIZE(blob, 12);
565 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
566 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
567 st->standard.in.write_time = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
571 case RAW_SFILEINFO_EA_SET:
572 return ea_pull_list(blob, req,
573 &st->ea_set.in.num_eas,
576 case SMB_SFILEINFO_BASIC_INFO:
577 case SMB_SFILEINFO_BASIC_INFORMATION:
578 passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
581 case SMB_SFILEINFO_DISPOSITION_INFO:
582 case SMB_SFILEINFO_DISPOSITION_INFORMATION:
583 passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
586 case SMB_SFILEINFO_ALLOCATION_INFO:
587 case SMB_SFILEINFO_ALLOCATION_INFORMATION:
588 passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
591 case RAW_SFILEINFO_END_OF_FILE_INFO:
592 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
593 passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
596 case RAW_SFILEINFO_RENAME_INFORMATION:
597 case RAW_SFILEINFO_POSITION_INFORMATION:
598 case RAW_SFILEINFO_MODE_INFORMATION:
599 passthru_level = st->generic.level;
602 case RAW_SFILEINFO_UNIX_BASIC:
603 case RAW_SFILEINFO_UNIX_LINK:
604 case RAW_SFILEINFO_UNIX_HLINK:
605 case RAW_SFILEINFO_PIPE_INFORMATION:
606 case RAW_SFILEINFO_VALID_DATA_INFORMATION:
607 case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
608 case RAW_SFILEINFO_1025:
609 case RAW_SFILEINFO_1027:
610 case RAW_SFILEINFO_1029:
611 case RAW_SFILEINFO_1030:
612 case RAW_SFILEINFO_1031:
613 case RAW_SFILEINFO_1032:
614 case RAW_SFILEINFO_1036:
615 case RAW_SFILEINFO_1041:
616 case RAW_SFILEINFO_1042:
617 case RAW_SFILEINFO_1043:
618 case RAW_SFILEINFO_1044:
619 return NT_STATUS_INVALID_LEVEL;
622 /* we need a default here to cope with invalid values on the wire */
623 return NT_STATUS_INVALID_LEVEL;
626 return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
627 blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
632 trans2 setfileinfo implementation
634 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
636 struct smb_trans2 *trans = op->trans;
637 union smb_setfileinfo *st;
639 struct ntvfs_handle *h;
641 /* make sure we got enough parameters */
642 if (trans->in.params.length < 4) {
643 return NT_STATUS_FOOBAR;
646 st = talloc(op, union smb_setfileinfo);
647 NT_STATUS_HAVE_NO_MEMORY(st);
649 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
650 level = SVAL(trans->in.params.data, 2);
652 st->generic.in.file.ntvfs = h;
653 /* work out the backend level - we make it 1-1 in the header */
654 st->generic.level = (enum smb_setfileinfo_level)level;
655 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
656 return NT_STATUS_INVALID_LEVEL;
659 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
662 op->send_fn = trans2_simple_send;
664 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
665 return ntvfs_setfileinfo(req->ntvfs, st);
669 trans2 setpathinfo implementation
671 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
673 struct smb_trans2 *trans = op->trans;
674 union smb_setfileinfo *st;
677 /* make sure we got enough parameters */
678 if (trans->in.params.length < 4) {
679 return NT_STATUS_FOOBAR;
682 st = talloc(op, union smb_setfileinfo);
683 NT_STATUS_HAVE_NO_MEMORY(st);
685 level = SVAL(trans->in.params.data, 0);
687 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
688 if (st->generic.in.file.path == NULL) {
689 return NT_STATUS_FOOBAR;
692 /* work out the backend level - we make it 1-1 in the header */
693 st->generic.level = (enum smb_setfileinfo_level)level;
694 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
695 return NT_STATUS_INVALID_LEVEL;
698 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
701 op->send_fn = trans2_simple_send;
703 return ntvfs_setpathinfo(req->ntvfs, st);
707 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
711 enum smb_search_data_level data_level;
712 uint16_t last_entry_offset;
717 fill a single entry in a trans2 find reply
719 static NTSTATUS find_fill_info(struct find_state *state,
720 const union smb_search_data *file)
722 struct smbsrv_request *req = state->op->req;
723 struct smb_trans2 *trans = state->op->trans;
725 unsigned int ofs = trans->out.data.length;
728 switch (state->data_level) {
729 case RAW_SEARCH_DATA_GENERIC:
730 case RAW_SEARCH_DATA_SEARCH:
731 /* handled elsewhere */
732 return NT_STATUS_INVALID_LEVEL;
734 case RAW_SEARCH_DATA_STANDARD:
735 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
736 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
737 SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
740 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
742 data = trans->out.data.data + ofs;
743 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
744 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
745 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
746 SIVAL(data, 12, file->standard.size);
747 SIVAL(data, 16, file->standard.alloc_size);
748 SSVAL(data, 20, file->standard.attrib);
749 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s,
750 ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
751 STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
754 case RAW_SEARCH_DATA_EA_SIZE:
755 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
756 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
757 SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
760 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
762 data = trans->out.data.data + ofs;
763 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
764 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
765 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
766 SIVAL(data, 12, file->ea_size.size);
767 SIVAL(data, 16, file->ea_size.alloc_size);
768 SSVAL(data, 20, file->ea_size.attrib);
769 SIVAL(data, 22, file->ea_size.ea_size);
770 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s,
771 ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
772 STR_LEN8BIT | STR_NOALIGN));
773 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
776 case RAW_SEARCH_DATA_EA_LIST:
777 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
778 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
779 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
780 SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
783 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
785 data = trans->out.data.data + ofs;
786 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
787 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
788 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
789 SIVAL(data, 12, file->ea_list.size);
790 SIVAL(data, 16, file->ea_list.alloc_size);
791 SSVAL(data, 20, file->ea_list.attrib);
792 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
793 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s,
794 ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
795 STR_LEN8BIT | STR_NOALIGN));
796 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
799 case RAW_SEARCH_DATA_DIRECTORY_INFO:
800 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
801 case RAW_SEARCH_DATA_NAME_INFO:
802 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
803 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
804 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
805 return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
806 SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
808 case RAW_SEARCH_DATA_UNIX_INFO:
809 case RAW_SEARCH_DATA_UNIX_INFO2:
810 return NT_STATUS_INVALID_LEVEL;
816 /* callback function for trans2 findfirst/findnext */
817 static bool find_callback(void *private_data, const union smb_search_data *file)
819 struct find_state *state = talloc_get_type(private_data, struct find_state);
820 struct smb_trans2 *trans = state->op->trans;
821 unsigned int old_length;
823 old_length = trans->out.data.length;
825 if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
826 trans->out.data.length > trans->in.max_data) {
827 /* restore the old length and tell the backend to stop */
828 smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
832 state->last_entry_offset = old_length;
837 trans2 findfirst send
839 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
841 struct smbsrv_request *req = op->req;
842 struct smb_trans2 *trans = op->trans;
843 union smb_search_first *search;
844 struct find_state *state;
847 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
848 search = talloc_get_type(state->search, union smb_search_first);
850 /* fill in the findfirst reply header */
851 param = trans->out.params.data;
852 SSVAL(param, VWV(0), search->t2ffirst.out.handle);
853 SSVAL(param, VWV(1), search->t2ffirst.out.count);
854 SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
855 SSVAL(param, VWV(3), 0);
856 SSVAL(param, VWV(4), state->last_entry_offset);
863 fill a referral type structure
865 static NTSTATUS fill_normal_dfs_referraltype(struct dfs_referral_type *ref,
867 const char *dfs_path,
868 const char *server_path, int isfirstoffset)
874 ref->version = version;
875 ref->referral.v3.server_type = DFS_SERVER_NON_ROOT;
876 /* "normal" referral seems to always include the GUID */
877 ref->referral.v3.size = 34;
879 ref->referral.v3.entry_flags = 0;
880 ref->referral.v3.ttl = 600; /* As w2k3 */
881 ref->referral.v3.referrals.r1.DFS_path = dfs_path;
882 ref->referral.v3.referrals.r1.DFS_alt_path = dfs_path;
883 ref->referral.v3.referrals.r1.netw_address = server_path;
887 ref->version = version;
888 ref->referral.v4.server_type = DFS_SERVER_NON_ROOT;
889 /* "normal" referral seems to always include the GUID */
890 ref->referral.v4.size = 34;
893 ref->referral.v4.entry_flags = DFS_HEADER_FLAG_TARGET_BCK;
895 ref->referral.v4.ttl = 900; /* As w2k8r2 */
896 ref->referral.v4.referrals.r1.DFS_path = dfs_path;
897 ref->referral.v4.referrals.r1.DFS_alt_path = dfs_path;
898 ref->referral.v4.referrals.r1.netw_address = server_path;
902 return NT_STATUS_INVALID_LEVEL;
906 fill a domain refererral
908 static NTSTATUS fill_domain_dfs_referraltype(struct dfs_referral_type *ref,
917 DEBUG(8, ("Called fill_domain_dfs_referraltype\n"));
918 ref->version = version;
919 ref->referral.v3.server_type = DFS_SERVER_NON_ROOT;
920 /* It's hard coded ... don't think it's a good way but the sizeof return not the
923 * We have 18 if the GUID is not included 34 otherwise
926 /* Windows return without the guid when returning domain list
928 ref->referral.v3.size = 18;
930 ref->referral.v3.size = 34;
932 ref->referral.v3.entry_flags = DFS_FLAG_REFERRAL_DOMAIN_RESP;
933 ref->referral.v3.ttl = 600; /* As w2k3 */
934 ref->referral.v3.referrals.r2.special_name = domain;
935 ref->referral.v3.referrals.r2.nb_expanded_names = numnames;
936 /* Put the final terminator */
938 const char **names2 = talloc_array(ref, const char *, numnames+1);
939 NT_STATUS_HAVE_NO_MEMORY(names2);
941 for (i = 0; i<numnames; i++) {
942 names2[i] = talloc_asprintf(names2, "\\%s", names[i]);
943 NT_STATUS_HAVE_NO_MEMORY(names2[i]);
945 names2[numnames] = NULL;
946 ref->referral.v3.referrals.r2.expanded_names = names2;
950 return NT_STATUS_INVALID_LEVEL;
954 get the DCs list within a site
956 static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
957 struct ldb_dn *sitedn, struct dc_set *list,
960 static const char *attrs[] = { "serverReference", NULL };
961 static const char *attrs2[] = { "dNSHostName", "sAMAccountName", NULL };
962 struct ldb_result *r;
965 const char **dc_list;
967 ret = ldb_search(ldb, ctx, &r, sitedn, LDB_SCOPE_SUBTREE, attrs,
968 "(&(objectClass=server)(serverReference=*))");
969 if (ret != LDB_SUCCESS) {
970 DEBUG(2,(__location__ ": Failed to get list of servers - %s\n",
971 ldb_errstring(ldb)));
972 return NT_STATUS_INTERNAL_ERROR;
976 /* none in this site */
982 * need to search for all server object to know the size of the array.
983 * Search all the object of class server in this site
985 dc_list = talloc_array(r, const char *, r->count);
986 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, r);
988 /* TODO put some random here in the order */
989 list->names = talloc_realloc(list, list->names, const char *, list->count + r->count);
990 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names, r);
992 for (i = 0; i<r->count; i++) {
994 struct ldb_result *r2;
996 dn = ldb_msg_find_attr_as_dn(ldb, ctx, r->msgs[i], "serverReference");
998 return NT_STATUS_INTERNAL_ERROR;
1001 ret = ldb_search(ldb, r, &r2, dn, LDB_SCOPE_BASE, attrs2, "(objectClass=computer)");
1002 if (ret != LDB_SUCCESS) {
1003 DEBUG(2,(__location__ ": Search for computer on %s failed - %s\n",
1004 ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1005 return NT_STATUS_INTERNAL_ERROR;
1009 const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL);
1011 DEBUG(2,(__location__ ": dNSHostName missing on %s\n",
1012 ldb_dn_get_linearized(dn)));
1014 return NT_STATUS_INTERNAL_ERROR;
1017 list->names[list->count] = talloc_strdup(list->names, dns);
1018 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r);
1021 const char *acct = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", NULL);
1023 DEBUG(2,(__location__ ": sAMAccountName missing on %s\n",
1024 ldb_dn_get_linearized(dn)));
1026 return NT_STATUS_INTERNAL_ERROR;
1029 tmp = talloc_strdup(list->names, acct);
1030 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r);
1032 /* Netbios name is also the sAMAccountName for
1033 computer but without the final $ */
1034 tmp[strlen(tmp) - 1] = '\0';
1035 list->names[list->count] = tmp;
1042 return NT_STATUS_OK;
1049 static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
1050 const char *searched_site, bool need_fqdn,
1051 struct dc_set ***pset_list, uint32_t flags)
1054 * Flags will be used later to indicate things like least-expensive
1055 * or same-site options
1057 const char *attrs_none[] = { NULL };
1058 const char *attrs3[] = { "name", NULL };
1059 struct ldb_dn *configdn, *sitedn, *dn, *sitescontainerdn;
1060 struct ldb_result *r;
1061 struct dc_set **set_list = NULL;
1064 uint32_t current_pos = 0;
1066 TALLOC_CTX *subctx = talloc_new(ctx);
1068 *pset_list = set_list = NULL;
1070 subctx = talloc_new(ctx);
1071 NT_STATUS_HAVE_NO_MEMORY(subctx);
1073 configdn = ldb_get_config_basedn(ldb);
1075 /* Let's search for the Site container */
1076 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs_none,
1077 "(objectClass=sitesContainer)");
1078 if (ret != LDB_SUCCESS) {
1079 DEBUG(2,(__location__ ": Failed to find sitesContainer within %s - %s\n",
1080 ldb_dn_get_linearized(configdn), ldb_errstring(ldb)));
1081 talloc_free(subctx);
1082 return NT_STATUS_INTERNAL_ERROR;
1085 DEBUG(2,(__location__ ": Expected 1 sitesContainer - found %u within %s\n",
1086 r->count, ldb_dn_get_linearized(configdn)));
1087 talloc_free(subctx);
1088 return NT_STATUS_INTERNAL_ERROR;
1091 sitescontainerdn = talloc_steal(subctx, r->msgs[0]->dn);
1095 * TODO: Here we should have a more subtle handling
1096 * for the case "same-site"
1098 ret = ldb_search(ldb, subctx, &r, sitescontainerdn, LDB_SCOPE_SUBTREE,
1099 attrs_none, "(objectClass=server)");
1100 if (ret != LDB_SUCCESS) {
1101 DEBUG(2,(__location__ ": Failed to find servers within %s - %s\n",
1102 ldb_dn_get_linearized(sitescontainerdn), ldb_errstring(ldb)));
1103 talloc_free(subctx);
1104 return NT_STATUS_INTERNAL_ERROR;
1108 if (searched_site != NULL) {
1109 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE,
1110 attrs_none, "(&(name=%s)(objectClass=site))", searched_site);
1111 if (ret != LDB_SUCCESS) {
1112 talloc_free(subctx);
1113 return NT_STATUS_FOOBAR;
1114 } else if (r->count != 1) {
1115 talloc_free(subctx);
1116 return NT_STATUS_FOOBAR;
1119 /* All of this was to get the DN of the searched_site */
1120 sitedn = r->msgs[0]->dn;
1122 set_list = talloc_realloc(subctx, set_list, struct dc_set *, current_pos+1);
1123 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1125 set_list[current_pos] = talloc(set_list, struct dc_set);
1126 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1128 set_list[current_pos]->names = NULL;
1129 set_list[current_pos]->count = 0;
1130 status = get_dcs_insite(subctx, ldb, sitedn,
1131 set_list[current_pos], need_fqdn);
1132 if (!NT_STATUS_IS_OK(status)) {
1133 DEBUG(2,(__location__ ": Failed to get DC from site %s - %s\n",
1134 ldb_dn_get_linearized(sitedn), nt_errstr(status)));
1135 talloc_free(subctx);
1142 /* Let's find all the sites */
1143 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs3, "(objectClass=site)");
1144 if (ret != LDB_SUCCESS) {
1145 DEBUG(2,(__location__ ": Failed to find any site containers in %s\n",
1146 ldb_dn_get_linearized(configdn)));
1147 talloc_free(subctx);
1148 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1153 * We should randomize the order in the main site,
1154 * it's mostly needed for sysvol/netlogon referral.
1155 * Depending of flag we either randomize order of the
1156 * not "in the same site DCs"
1157 * or we randomize by group of site that have the same cost
1158 * In the long run we want to manipulate an array of site_set
1159 * All the site in one set have the same cost (if least-expansive options is selected)
1160 * and we will put all the dc related to 1 site set into 1 DCs set.
1161 * Within a site set, site order has to be randomized
1163 * But for the moment we just return the list of sites
1167 * We will realloc + 2 because we will need one additional place
1168 * for element at current_pos + 1 for the NULL element
1170 set_list = talloc_realloc(subctx, set_list, struct dc_set *,
1172 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1174 set_list[current_pos] = talloc(ctx, struct dc_set);
1175 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1177 set_list[current_pos]->names = NULL;
1178 set_list[current_pos]->count = 0;
1180 set_list[current_pos+1] = NULL;
1183 for (i=0; i<r->count; i++) {
1184 const char *site_name = ldb_msg_find_attr_as_string(r->msgs[i], "name", NULL);
1185 if (site_name == NULL) {
1186 DEBUG(2,(__location__ ": Failed to find name attribute in %s\n",
1187 ldb_dn_get_linearized(r->msgs[i]->dn)));
1188 talloc_free(subctx);
1189 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1192 if (searched_site == NULL ||
1193 strcmp(searched_site, site_name) != 0) {
1194 DEBUG(2,(__location__ ": Site: %s %s\n",
1195 searched_site, site_name));
1198 * Do all the site but the one of the client
1199 * (because it has already been done ...)
1201 dn = r->msgs[i]->dn;
1203 status = get_dcs_insite(subctx, ldb, dn,
1204 set_list[current_pos],
1206 if (!NT_STATUS_IS_OK(status)) {
1207 talloc_free(subctx);
1213 set_list[current_pos] = NULL;
1215 *pset_list = talloc_move(ctx, &set_list);
1216 talloc_free(subctx);
1217 return NT_STATUS_OK;
1220 static NTSTATUS dodomain_referral(TALLOC_CTX *ctx,
1221 const struct dfs_GetDFSReferral_in *dfsreq,
1222 struct ldb_context *ldb,
1223 struct smb_trans2 *trans,
1224 struct loadparm_context *lp_ctx)
1227 * TODO for the moment we just return the local domain
1230 enum ndr_err_code ndr_err;
1232 const char *dns_domain = lpcfg_dnsdomain(lp_ctx);
1233 const char *netbios_domain = lpcfg_workgroup(lp_ctx);
1234 struct dfs_referral_resp resp;
1235 struct dfs_referral_type *tab;
1236 struct dfs_referral_type *referral;
1237 const char *referral_str;
1238 /* In the future this needs to be fetched from the ldb */
1239 uint32_t found_domain = 2;
1240 uint32_t current_pos = 0;
1241 TALLOC_CTX *context;
1243 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1244 DEBUG(10 ,("Received a domain referral request on a non DC\n"));
1245 return NT_STATUS_INVALID_PARAMETER;
1248 if (dfsreq->max_referral_level < 3) {
1249 DEBUG(2,("invalid max_referral_level %u\n",
1250 dfsreq->max_referral_level));
1251 return NT_STATUS_UNSUCCESSFUL;
1254 context = talloc_new(ctx);
1255 NT_STATUS_HAVE_NO_MEMORY(context);
1257 resp.path_consumed = 0;
1258 resp.header_flags = 0; /* Do like w2k3 */
1259 resp.nb_referrals = found_domain; /* the fqdn one + the NT domain */
1261 tab = talloc_array(context, struct dfs_referral_type, found_domain);
1262 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tab, context);
1264 referral = talloc(tab, struct dfs_referral_type);
1265 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1266 referral_str = talloc_asprintf(referral, "\\%s", netbios_domain);
1267 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1268 status = fill_domain_dfs_referraltype(referral, 3,
1271 if (!NT_STATUS_IS_OK(status)) {
1272 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1273 talloc_free(context);
1274 return NT_STATUS_UNSUCCESSFUL;
1277 tab[current_pos] = *referral;
1280 referral = talloc(tab, struct dfs_referral_type);
1281 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1282 referral_str = talloc_asprintf(referral, "\\%s", dns_domain);
1283 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1284 status = fill_domain_dfs_referraltype(referral, 3,
1287 if (!NT_STATUS_IS_OK(status)) {
1288 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1289 talloc_free(context);
1290 return NT_STATUS_UNSUCCESSFUL;
1292 tab[current_pos] = *referral;
1296 * Put here the code from filling the array for trusted domain
1298 resp.referral_entries = tab;
1300 ndr_err = ndr_push_struct_blob(&outblob, context,
1302 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1303 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1304 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1305 talloc_free(context);
1306 return NT_STATUS_INTERNAL_ERROR;
1309 if (outblob.length > trans->in.max_data) {
1312 DEBUG(3, ("Blob is too big for the output buffer "
1314 (unsigned int)outblob.length, trans->in.max_data));
1316 if (trans->in.max_data != MAX_DFS_RESPONSE) {
1317 /* As specified in MS-DFSC.pdf 3.3.5.2 */
1318 talloc_free(context);
1319 return STATUS_BUFFER_OVERFLOW;
1323 * The answer is too big, so let's remove some answers
1325 while (!ok && resp.nb_referrals > 2) {
1326 data_blob_free(&outblob);
1329 * Let's scrap the first referral (for now)
1331 resp.nb_referrals -= 1;
1332 resp.referral_entries += 1;
1334 ndr_err = ndr_push_struct_blob(&outblob, context,
1336 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1337 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1338 talloc_free(context);
1339 return NT_STATUS_INTERNAL_ERROR;
1342 if (outblob.length <= MAX_DFS_RESPONSE) {
1343 DEBUG(10,("DFS: managed to reduce the size of referral initial"
1344 "number of referral %d, actual count: %d",
1345 found_domain, resp.nb_referrals));
1351 if (!ok && resp.nb_referrals == 2) {
1352 DEBUG(8, (__location__ "; Not able to fit the domain and realm in DFS a "
1353 " 56K buffer, something must be broken"));
1354 talloc_free(context);
1355 return NT_STATUS_INTERNAL_ERROR;
1359 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1361 trans->out.data = outblob;
1362 talloc_steal(ctx, outblob.data);
1363 talloc_free(context);
1364 return NT_STATUS_OK;
1368 * Handle the logic for dfs referral request like \\domain
1369 * or \\domain\sysvol or \\fqdn or \\fqdn\netlogon
1371 static NTSTATUS dodc_or_sysvol_referral(TALLOC_CTX *ctx,
1372 const struct dfs_GetDFSReferral_in dfsreq,
1373 const char* requesteddomain,
1374 const char* requestedshare,
1375 const char* requestedname,
1376 struct ldb_context *ldb,
1377 struct smb_trans2 *trans,
1378 struct smbsrv_request *req,
1379 struct loadparm_context *lp_ctx)
1382 * It's not a "standard" DFS referral but a referral to get the DC list
1383 * or sysvol/netlogon
1384 * Let's check that it's for one of our domain ...
1388 unsigned int num_domain = 1;
1389 enum ndr_err_code ndr_err;
1390 const char *realm = lpcfg_realm(lp_ctx);
1391 const char *domain = lpcfg_workgroup(lp_ctx);
1392 const char *site_name = NULL; /* Name of the site where the client is */
1394 bool need_fqdn = false;
1395 bool dc_referral = true;
1397 struct dc_set **set;
1398 char const **domain_list;
1399 struct tsocket_address *remote_address;
1400 char *client_addr = NULL;
1401 TALLOC_CTX *context;
1403 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1404 return NT_STATUS_INVALID_PARAMETER;
1407 if (dfsreq.max_referral_level < 3) {
1408 DEBUG(2,("invalid max_referral_level %u\n",
1409 dfsreq.max_referral_level));
1410 return NT_STATUS_UNSUCCESSFUL;
1413 context = talloc_new(ctx);
1414 NT_STATUS_HAVE_NO_MEMORY(context);
1416 DEBUG(10, ("in this we have request for %s and share %s requested is %s\n",
1421 if (requestedshare) {
1422 DEBUG(10, ("Have a non DC domain referal\n"));
1423 dc_referral = false;
1427 * We will fetch the trusted domain list soon with something like this:
1429 * "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)
1430 * (trustPartner=%s))(objectclass=trustedDomain))"
1432 * Allocate for num_domain + 1 so that the last element will be NULL)
1434 domain_list = talloc_array(context, const char*, num_domain+1);
1435 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_list, context);
1437 domain_list[0] = realm;
1438 domain_list[1] = domain;
1439 for (i=0; i<=num_domain; i++) {
1440 if (strncasecmp(domain_list[i], requesteddomain, strlen(domain_list[i])) == 0) {
1447 /* The requested domain is not one that we support */
1448 DEBUG(3,("Requested referral for domain %s, but we don't handle it",
1450 return NT_STATUS_INVALID_PARAMETER;
1453 if (strchr(requestedname,'.')) {
1457 remote_address = req->smb_conn->connection->remote_address;
1458 if (tsocket_address_is_inet(remote_address, "ip")) {
1459 client_addr = tsocket_address_inet_addr_string(remote_address, context);
1460 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_addr, context);
1463 status = get_dcs(context, ldb, site_name, need_fqdn, &set, 0);
1464 if (!NT_STATUS_IS_OK(status)) {
1465 DEBUG(3,("Unable to get list of DCs\n"));
1466 talloc_free(context);
1471 const char **dc_list = NULL;
1472 uint32_t num_dcs = 0;
1473 struct dfs_referral_type *referral;
1474 const char *referral_str;
1475 struct dfs_referral_resp resp;
1477 for(i=0; set[i]; i++) {
1480 dc_list = talloc_realloc(context, dc_list, const char*,
1481 num_dcs + set[i]->count + 1);
1482 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, context);
1484 for(j=0; j<set[i]->count; j++) {
1485 dc_list[num_dcs + j] = talloc_steal(context, set[i]->names[j]);
1487 num_dcs = num_dcs + set[i]->count;
1488 TALLOC_FREE(set[i]);
1489 dc_list[num_dcs] = NULL;
1492 resp.path_consumed = 0;
1493 resp.header_flags = 0; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1496 * The NumberOfReferrals field MUST be set to 1,
1497 * independent of the number of DC names
1498 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1500 resp.nb_referrals = 1;
1502 /* Put here the code from filling the array for trusted domain */
1503 referral = talloc(context, struct dfs_referral_type);
1504 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1506 if (requestedname[0] == '\\') {
1507 referral_str = talloc_asprintf(referral, "%s",
1510 referral_str = talloc_asprintf(referral, "\\%s",
1513 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1515 status = fill_domain_dfs_referraltype(referral, 3,
1518 if (!NT_STATUS_IS_OK(status)) {
1519 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1520 talloc_free(context);
1521 return NT_STATUS_UNSUCCESSFUL;
1523 resp.referral_entries = referral;
1525 ndr_err = ndr_push_struct_blob(&outblob, context,
1527 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1528 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1529 DEBUG(2,(__location__ ":NDR marshalling of dfs referral response failed\n"));
1530 talloc_free(context);
1531 return NT_STATUS_INTERNAL_ERROR;
1534 unsigned int nb_entries = 0;
1535 unsigned int current = 0;
1536 struct dfs_referral_type *tab;
1537 struct dfs_referral_resp resp;
1539 for(i=0; set[i]; i++) {
1540 nb_entries = nb_entries + set[i]->count;
1543 resp.path_consumed = 2*strlen(requestedname); /* The length is expected in bytes */
1544 resp.header_flags = DFS_HEADER_FLAG_STORAGE_SVR; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1547 * The NumberOfReferrals field MUST be set to 1,
1548 * independent of the number of DC names
1549 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1551 resp.nb_referrals = nb_entries;
1553 tab = talloc_array(context, struct dfs_referral_type, nb_entries);
1554 NT_STATUS_HAVE_NO_MEMORY(tab);
1556 for(i=0; set[i]; i++) {
1559 for(j=0; j< set[i]->count; j++) {
1560 struct dfs_referral_type *referral;
1561 const char *referral_str;
1563 referral = talloc(tab, struct dfs_referral_type);
1564 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1566 referral_str = talloc_asprintf(referral, "\\%s\\%s",
1567 set[i]->names[j], requestedshare);
1568 DEBUG(8, ("Doing a dfs referral for %s with this value %s requested %s\n", set[i]->names[j], referral_str, requestedname));
1569 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1571 status = fill_normal_dfs_referraltype(referral,
1572 dfsreq.max_referral_level,
1573 requestedname, referral_str, j==0);
1575 if (!NT_STATUS_IS_OK(status)) {
1576 DEBUG(2, (__location__ ": Unable to fill a normal dfs referral object"));
1577 talloc_free(context);
1578 return NT_STATUS_UNSUCCESSFUL;
1580 tab[current] = *referral;
1584 resp.referral_entries = tab;
1586 ndr_err = ndr_push_struct_blob(&outblob, context,
1588 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1589 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1590 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1591 talloc_free(context);
1592 return NT_STATUS_INTERNAL_ERROR;
1596 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1599 * TODO If the size is too big we should remove
1600 * some DC from the answer or return STATUS_BUFFER_OVERFLOW
1602 trans->out.data = outblob;
1603 talloc_steal(ctx, outblob.data);
1604 talloc_free(context);
1605 return NT_STATUS_OK;
1609 trans2 getdfsreferral implementation
1611 static NTSTATUS trans2_getdfsreferral(struct smbsrv_request *req,
1612 struct trans_op *op)
1614 enum ndr_err_code ndr_err;
1615 struct smb_trans2 *trans = op->trans;
1616 struct dfs_GetDFSReferral_in dfsreq;
1617 TALLOC_CTX *context;
1618 struct ldb_context *ldb;
1619 struct loadparm_context *lp_ctx;
1620 const char *realm, *nbname, *requestedname;
1621 char *fqdn, *share, *domain, *tmp;
1624 lp_ctx = req->tcon->ntvfs->lp_ctx;
1625 if (!lpcfg_host_msdfs(lp_ctx)) {
1626 return NT_STATUS_NOT_IMPLEMENTED;
1629 context = talloc_new(req);
1630 NT_STATUS_HAVE_NO_MEMORY(context);
1632 ldb = samdb_connect(context, req->tcon->ntvfs->event_ctx, lp_ctx, system_session(lp_ctx), 0);
1634 DEBUG(2,(__location__ ": Failed to open samdb\n"));
1635 talloc_free(context);
1636 return NT_STATUS_INTERNAL_ERROR;
1639 ndr_err = ndr_pull_struct_blob(&trans->in.params, op,
1641 (ndr_pull_flags_fn_t)ndr_pull_dfs_GetDFSReferral_in);
1642 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1643 status = ndr_map_error2ntstatus(ndr_err);
1644 DEBUG(2,(__location__ ": Failed to parse GetDFSReferral_in - %s\n",
1645 nt_errstr(status)));
1646 talloc_free(context);
1650 DEBUG(8, ("Requested DFS name: %s length: %u\n",
1651 dfsreq.servername, (unsigned int)strlen(dfsreq.servername)));
1654 * If the servername is "" then we are in a case of domain dfs
1655 * and the client just searches for the list of local domain
1656 * it is attached and also trusted ones.
1658 requestedname = dfsreq.servername;
1659 if (requestedname == NULL || requestedname[0] == '\0') {
1660 return dodomain_referral(op, &dfsreq, ldb, trans, lp_ctx);
1663 realm = lpcfg_realm(lp_ctx);
1664 nbname = lpcfg_netbios_name(lp_ctx);
1665 fqdn = talloc_asprintf(context, "%s.%s", nbname, realm);
1667 if ((strncasecmp(requestedname+1, nbname, strlen(nbname)) == 0) ||
1668 (strncasecmp(requestedname+1, fqdn, strlen(fqdn)) == 0) ) {
1670 * the referral request starts with \NETBIOSNAME or \fqdn
1671 * it's a standalone referral we do not do it
1672 * (TODO correct this)
1673 * If a DFS link that is a complete prefix of the DFS referral
1674 * request path is identified, the server MUST return a DFS link
1675 * referral response; otherwise, if it has a match for the DFS root,
1676 * it MUST return a root referral response.
1678 DEBUG(3, ("Received a standalone request for %s, we do not support standalone referral yet",requestedname));
1679 talloc_free(context);
1680 return NT_STATUS_NOT_FOUND;
1684 domain = talloc_strdup(context, requestedname);
1685 while(*domain && *domain == '\\') {
1689 tmp = strchr(domain,'\\'); /* To get second \ if any */
1693 * We are finishing properly the domain string
1694 * and the share one will start after the \
1698 share = talloc_strdup(context, tmp);
1701 * Here we have filtered the thing the requested name don't contain our DNS name.
1702 * So if the share == NULL or if share in ("sysvol", "netlogon")
1703 * then we proceed. In the first case it will be a dc refereal in the second it will
1704 * be just a sysvol/netlogon referral.
1706 if (share == NULL ||
1707 strcasecmp(share, "sysvol") == 0 ||
1708 strcasecmp(share, "netlogon") == 0) {
1709 status = dodc_or_sysvol_referral(op, dfsreq, domain, share, requestedname,
1710 ldb, trans, req, lp_ctx);
1711 talloc_free(context);
1715 tmp = strchr(share, '\\');
1717 (strncasecmp(share, "sysvol", 6) == 0 ||
1718 strncasecmp(share, "netlogon", 8) == 0)) {
1720 * We have more than two \ so it something like
1721 * \domain\sysvol\foobar
1723 talloc_free(context);
1724 return NT_STATUS_NOT_FOUND;
1727 talloc_free(context);
1728 /* By default until all the case are handled*/
1729 return NT_STATUS_NOT_FOUND;
1733 trans2 findfirst implementation
1735 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1737 struct smb_trans2 *trans = op->trans;
1738 union smb_search_first *search;
1740 struct find_state *state;
1742 /* make sure we got all the parameters */
1743 if (trans->in.params.length < 14) {
1744 return NT_STATUS_FOOBAR;
1747 search = talloc(op, union smb_search_first);
1748 NT_STATUS_HAVE_NO_MEMORY(search);
1750 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1751 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1752 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1753 level = SVAL(trans->in.params.data, 6);
1754 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1756 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1757 if (search->t2ffirst.in.pattern == NULL) {
1758 return NT_STATUS_FOOBAR;
1761 search->t2ffirst.level = RAW_SEARCH_TRANS2;
1762 search->t2ffirst.data_level = (enum smb_search_data_level)level;
1763 if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
1764 return NT_STATUS_INVALID_LEVEL;
1767 if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
1768 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1769 &search->t2ffirst.in.num_names,
1770 &search->t2ffirst.in.ea_names));
1773 /* setup the private state structure that the backend will
1774 give us in the callback */
1775 state = talloc(op, struct find_state);
1776 NT_STATUS_HAVE_NO_MEMORY(state);
1778 state->search = search;
1779 state->data_level = search->t2ffirst.data_level;
1780 state->last_entry_offset= 0;
1781 state->flags = search->t2ffirst.in.flags;
1783 /* setup for just a header in the reply */
1784 TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
1786 op->op_info = state;
1787 op->send_fn = trans2_findfirst_send;
1789 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1794 trans2 findnext send
1796 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1798 struct smbsrv_request *req = op->req;
1799 struct smb_trans2 *trans = op->trans;
1800 union smb_search_next *search;
1801 struct find_state *state;
1804 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1805 search = talloc_get_type(state->search, union smb_search_next);
1807 /* fill in the findfirst reply header */
1808 param = trans->out.params.data;
1809 SSVAL(param, VWV(0), search->t2fnext.out.count);
1810 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1811 SSVAL(param, VWV(2), 0);
1812 SSVAL(param, VWV(3), state->last_entry_offset);
1814 return NT_STATUS_OK;
1819 trans2 findnext implementation
1821 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1823 struct smb_trans2 *trans = op->trans;
1824 union smb_search_next *search;
1826 struct find_state *state;
1828 /* make sure we got all the parameters */
1829 if (trans->in.params.length < 12) {
1830 return NT_STATUS_FOOBAR;
1833 search = talloc(op, union smb_search_next);
1834 NT_STATUS_HAVE_NO_MEMORY(search);
1836 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1837 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1838 level = SVAL(trans->in.params.data, 4);
1839 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1840 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1842 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1843 if (search->t2fnext.in.last_name == NULL) {
1844 return NT_STATUS_FOOBAR;
1847 search->t2fnext.level = RAW_SEARCH_TRANS2;
1848 search->t2fnext.data_level = (enum smb_search_data_level)level;
1849 if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
1850 return NT_STATUS_INVALID_LEVEL;
1853 if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
1854 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1855 &search->t2fnext.in.num_names,
1856 &search->t2fnext.in.ea_names));
1859 /* setup the private state structure that the backend will give us in the callback */
1860 state = talloc(op, struct find_state);
1861 NT_STATUS_HAVE_NO_MEMORY(state);
1863 state->search = search;
1864 state->data_level = search->t2fnext.data_level;
1865 state->last_entry_offset= 0;
1866 state->flags = search->t2fnext.in.flags;
1868 /* setup for just a header in the reply */
1869 TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
1871 op->op_info = state;
1872 op->send_fn = trans2_findnext_send;
1874 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1879 backend for trans2 requests
1881 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1883 struct smb_trans2 *trans = op->trans;
1886 /* direct trans2 pass thru */
1887 status = ntvfs_trans2(req->ntvfs, trans);
1888 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1892 /* must have at least one setup word */
1893 if (trans->in.setup_count < 1) {
1894 return NT_STATUS_FOOBAR;
1897 /* the trans2 command is in setup[0] */
1898 switch (trans->in.setup[0]) {
1899 case TRANSACT2_GET_DFS_REFERRAL:
1900 return trans2_getdfsreferral(req, op);
1901 case TRANSACT2_FINDFIRST:
1902 return trans2_findfirst(req, op);
1903 case TRANSACT2_FINDNEXT:
1904 return trans2_findnext(req, op);
1905 case TRANSACT2_QPATHINFO:
1906 return trans2_qpathinfo(req, op);
1907 case TRANSACT2_QFILEINFO:
1908 return trans2_qfileinfo(req, op);
1909 case TRANSACT2_SETFILEINFO:
1910 return trans2_setfileinfo(req, op);
1911 case TRANSACT2_SETPATHINFO:
1912 return trans2_setpathinfo(req, op);
1913 case TRANSACT2_QFSINFO:
1914 return trans2_qfsinfo(req, op);
1915 case TRANSACT2_OPEN:
1916 return trans2_open(req, op);
1917 case TRANSACT2_MKDIR:
1918 return trans2_mkdir(req, op);
1921 /* an unknown trans2 command */
1922 return NT_STATUS_FOOBAR;
1925 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
1927 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1933 send a continue request
1935 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1936 struct smb_trans2 *trans)
1938 struct smbsrv_request *req2;
1939 struct smbsrv_trans_partial *tp;
1942 /* make sure they don't flood us */
1943 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1945 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1949 tp = talloc(req, struct smbsrv_trans_partial);
1952 tp->u.trans = trans;
1953 tp->command = command;
1955 DLIST_ADD(req->smb_conn->trans_partial, tp);
1956 talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1958 req2 = smbsrv_setup_secondary_request(req);
1960 /* send a 'please continue' reply */
1961 smbsrv_setup_reply(req2, 0, 0);
1962 smbsrv_send_reply(req2);
1967 answer a reconstructed trans request
1969 static void reply_trans_send(struct ntvfs_request *ntvfs)
1971 struct smbsrv_request *req;
1972 struct trans_op *op;
1973 struct smb_trans2 *trans;
1974 uint16_t params_left, data_left;
1975 uint8_t *params, *data;
1978 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1981 /* if this function needs work to form the nttrans reply buffer, then
1983 if (op->send_fn != NULL) {
1985 status = op->send_fn(op);
1986 if (!NT_STATUS_IS_OK(status)) {
1987 smbsrv_send_error(req, status);
1992 params_left = trans->out.params.length;
1993 data_left = trans->out.data.length;
1994 params = trans->out.params.data;
1995 data = trans->out.data.data;
1997 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1999 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
2000 smbsrv_setup_error(req, req->ntvfs->async_states->status);
2003 /* we need to divide up the reply into chunks that fit into
2004 the negotiated buffer size */
2006 uint16_t this_data, this_param, max_bytes;
2007 unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
2008 struct smbsrv_request *this_req;
2010 max_bytes = req_max_data(req) - (align1 + align2);
2012 this_param = params_left;
2013 if (this_param > max_bytes) {
2014 this_param = max_bytes;
2016 max_bytes -= this_param;
2018 this_data = data_left;
2019 if (this_data > max_bytes) {
2020 this_data = max_bytes;
2023 /* don't destroy unless this is the last chunk */
2024 if (params_left - this_param != 0 ||
2025 data_left - this_data != 0) {
2026 this_req = smbsrv_setup_secondary_request(req);
2031 req_grow_data(this_req, this_param + this_data + (align1 + align2));
2033 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
2034 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
2035 SSVAL(this_req->out.vwv, VWV(2), 0);
2037 SSVAL(this_req->out.vwv, VWV(3), this_param);
2038 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
2039 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
2041 SSVAL(this_req->out.vwv, VWV(6), this_data);
2042 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
2043 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
2044 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
2046 SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
2047 SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
2048 for (i=0;i<trans->out.setup_count;i++) {
2049 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
2052 memset(this_req->out.data, 0, align1);
2053 if (this_param != 0) {
2054 memcpy(this_req->out.data + align1, params, this_param);
2056 memset(this_req->out.data+this_param+align1, 0, align2);
2057 if (this_data != 0) {
2058 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
2061 params_left -= this_param;
2062 data_left -= this_data;
2063 params += this_param;
2066 smbsrv_send_reply(this_req);
2067 } while (params_left != 0 || data_left != 0);
2072 answer a reconstructed trans request
2074 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
2075 struct smb_trans2 *trans)
2077 struct trans_op *op;
2079 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
2080 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2084 op->command = command;
2088 /* its a full request, give it to the backend */
2089 if (command == SMBtrans) {
2090 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
2093 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
2099 Reply to an SMBtrans or SMBtrans2 request
2101 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
2103 struct smb_trans2 *trans;
2105 uint16_t param_ofs, data_ofs;
2106 uint16_t param_count, data_count;
2107 uint16_t param_total, data_total;
2110 if (req->in.wct < 14) {
2111 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2115 trans = talloc(req, struct smb_trans2);
2116 if (trans == NULL) {
2117 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2121 param_total = SVAL(req->in.vwv, VWV(0));
2122 data_total = SVAL(req->in.vwv, VWV(1));
2123 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
2124 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
2125 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
2126 trans->in.flags = SVAL(req->in.vwv, VWV(5));
2127 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
2128 param_count = SVAL(req->in.vwv, VWV(9));
2129 param_ofs = SVAL(req->in.vwv, VWV(10));
2130 data_count = SVAL(req->in.vwv, VWV(11));
2131 data_ofs = SVAL(req->in.vwv, VWV(12));
2132 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
2134 if (req->in.wct != 14 + trans->in.setup_count) {
2135 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
2139 /* parse out the setup words */
2140 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
2141 if (trans->in.setup_count && !trans->in.setup) {
2142 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2145 for (i=0;i<trans->in.setup_count;i++) {
2146 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
2149 if (command == SMBtrans) {
2150 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
2153 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
2154 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
2155 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2159 /* is it a partial request? if so, then send a 'send more' message */
2160 if (param_total > param_count || data_total > data_count) {
2161 reply_trans_continue(req, command, trans);
2165 reply_trans_complete(req, command, trans);
2170 Reply to an SMBtranss2 request
2172 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
2174 struct smbsrv_trans_partial *tp;
2175 struct smb_trans2 *trans = NULL;
2176 uint16_t param_ofs, data_ofs;
2177 uint16_t param_count, data_count;
2178 uint16_t param_disp, data_disp;
2179 uint16_t param_total, data_total;
2180 DATA_BLOB params, data;
2183 if (command == SMBtrans2) {
2190 if (req->in.wct != wct) {
2192 * TODO: add some error code tests
2193 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
2195 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2199 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
2200 if (tp->command == command &&
2201 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
2202 /* TODO: check the VUID, PID and TID too? */
2208 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2212 trans = tp->u.trans;
2214 param_total = SVAL(req->in.vwv, VWV(0));
2215 data_total = SVAL(req->in.vwv, VWV(1));
2216 param_count = SVAL(req->in.vwv, VWV(2));
2217 param_ofs = SVAL(req->in.vwv, VWV(3));
2218 param_disp = SVAL(req->in.vwv, VWV(4));
2219 data_count = SVAL(req->in.vwv, VWV(5));
2220 data_ofs = SVAL(req->in.vwv, VWV(6));
2221 data_disp = SVAL(req->in.vwv, VWV(7));
2223 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, ¶ms) ||
2224 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
2225 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2229 /* only allow contiguous requests */
2230 if ((param_count != 0 &&
2231 param_disp != trans->in.params.length) ||
2233 data_disp != trans->in.data.length)) {
2234 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2238 /* add to the existing request */
2239 if (param_count != 0) {
2240 trans->in.params.data = talloc_realloc(trans,
2241 trans->in.params.data,
2243 param_disp + param_count);
2244 if (trans->in.params.data == NULL) {
2245 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2248 trans->in.params.length = param_disp + param_count;
2251 if (data_count != 0) {
2252 trans->in.data.data = talloc_realloc(trans,
2253 trans->in.data.data,
2255 data_disp + data_count);
2256 if (trans->in.data.data == NULL) {
2257 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2260 trans->in.data.length = data_disp + data_count;
2263 memcpy(trans->in.params.data + param_disp, params.data, params.length);
2264 memcpy(trans->in.data.data + data_disp, data.data, data.length);
2266 /* the sequence number of the reply is taken from the last secondary
2268 tp->req->seq_num = req->seq_num;
2270 /* we don't reply to Transs2 requests */
2273 if (trans->in.params.length == param_total &&
2274 trans->in.data.length == data_total) {
2275 /* its now complete */
2278 reply_trans_complete(req, command, trans);
2285 Reply to an SMBtrans2
2287 void smbsrv_reply_trans2(struct smbsrv_request *req)
2289 reply_trans_generic(req, SMBtrans2);
2293 Reply to an SMBtrans
2295 void smbsrv_reply_trans(struct smbsrv_request *req)
2297 reply_trans_generic(req, SMBtrans);
2301 Reply to an SMBtranss request
2303 void smbsrv_reply_transs(struct smbsrv_request *req)
2305 reply_transs_generic(req, SMBtrans);
2309 Reply to an SMBtranss2 request
2311 void smbsrv_reply_transs2(struct smbsrv_request *req)
2313 reply_transs_generic(req, SMBtrans2);