s4-dfs: Add workaround so that XP really works well
[Samba/gebeck_regimport.git] / source4 / smb_server / smb / trans2.c
blobb3aa690e857e83c6db1bb0b065b0154da91d7c77
1 /*
2 Unix SMB/CIFS implementation.
3 transaction2 handling
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
24 #include "includes.h"
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; \
43 } \
44 } while (0)
45 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
46 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
47 ptr = talloc_get_type(op->op_info, type); \
48 } while (0)
49 #define TRANS2_CHECK(cmd) do { \
50 NTSTATUS _status; \
51 _status = cmd; \
52 NT_STATUS_NOT_OK_RETURN(_status); \
53 } while (0)
56 hold the state of a nttrans op while in progress. Needed to allow for async backend
57 functions.
59 struct trans_op {
60 struct smbsrv_request *req;
61 struct smb_trans2 *trans;
62 uint8_t command;
63 NTSTATUS (*send_fn)(struct trans_op *);
64 void *op_info;
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 ...
69 struct dc_set {
70 const char **names;
71 uint32_t count;
73 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
74 if ((blob)->length < (size)) { \
75 return NT_STATUS_INFO_LENGTH_MISMATCH; \
76 }} while (0)
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,
81 uint8_t setup_count)
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);
94 return NT_STATUS_OK;
97 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
98 TALLOC_CTX *mem_ctx,
99 DATA_BLOB *blob,
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);
115 return NT_STATUS_OK;
117 case RAW_QFS_VOLUME:
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));
128 return NT_STATUS_OK;
130 case RAW_QFS_VOLUME_INFO:
131 passthru_level = RAW_QFS_VOLUME_INFORMATION;
132 break;
134 case RAW_QFS_SIZE_INFO:
135 passthru_level = RAW_QFS_SIZE_INFORMATION;
136 break;
138 case RAW_QFS_DEVICE_INFO:
139 passthru_level = RAW_QFS_DEVICE_INFORMATION;
140 break;
142 case RAW_QFS_ATTRIBUTE_INFO:
143 passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
144 break;
146 default:
147 passthru_level = fsinfo->generic.level;
148 break;
151 return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
152 passthru_level, fsinfo,
153 default_str_flags);
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)));
173 return NT_STATUS_OK;
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;
183 uint16_t level;
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;
215 union smb_open *io;
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 */
234 return NT_STATUS_OK;
238 trans2 open implementation
240 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
242 struct smb_trans2 *trans = op->trans;
243 union smb_open *io;
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));
273 op->op_info = io;
274 op->send_fn = trans2_open_send;
276 return ntvfs_open(req->ntvfs, io);
281 trans2 simple send
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);
294 return NT_STATUS_OK;
298 trans2 mkdir implementation
300 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
302 struct smb_trans2 *trans = op->trans;
303 union smb_mkdir *io;
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));
323 op->op_info = io;
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,
330 TALLOC_CTX *mem_ctx,
331 DATA_BLOB *blob,
332 union smb_fileinfo *st,
333 int default_str_flags)
335 uint32_t list_size;
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);
362 return NT_STATUS_OK;
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);
374 return NT_STATUS_OK;
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);
383 return NT_STATUS_OK;
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);
392 return NT_STATUS_OK;
394 case RAW_FILEINFO_IS_NAME_VALID:
395 return NT_STATUS_OK;
397 case RAW_FILEINFO_BASIC_INFO:
398 passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
399 break;
401 case RAW_FILEINFO_STANDARD_INFO:
402 passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
403 break;
405 case RAW_FILEINFO_EA_INFO:
406 passthru_level = RAW_FILEINFO_EA_INFORMATION;
407 break;
409 case RAW_FILEINFO_COMPRESSION_INFO:
410 passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
411 break;
413 case RAW_FILEINFO_ALL_INFO:
414 passthru_level = RAW_FILEINFO_ALL_INFORMATION;
415 break;
417 case RAW_FILEINFO_NAME_INFO:
418 passthru_level = RAW_FILEINFO_NAME_INFORMATION;
419 break;
421 case RAW_FILEINFO_ALT_NAME_INFO:
422 passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
423 break;
425 case RAW_FILEINFO_STREAM_INFO:
426 passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
427 break;
429 default:
430 passthru_level = st->generic.level;
431 break;
434 return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
435 passthru_level, st,
436 default_str_flags);
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)));
457 return NT_STATUS_OK;
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;
467 uint16_t level;
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));
496 op->op_info = st;
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;
510 uint16_t level;
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));
537 op->op_info = st;
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);
569 return NT_STATUS_OK;
571 case RAW_SFILEINFO_EA_SET:
572 return ea_pull_list(blob, req,
573 &st->ea_set.in.num_eas,
574 &st->ea_set.in.eas);
576 case SMB_SFILEINFO_BASIC_INFO:
577 case SMB_SFILEINFO_BASIC_INFORMATION:
578 passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
579 break;
581 case SMB_SFILEINFO_DISPOSITION_INFO:
582 case SMB_SFILEINFO_DISPOSITION_INFORMATION:
583 passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
584 break;
586 case SMB_SFILEINFO_ALLOCATION_INFO:
587 case SMB_SFILEINFO_ALLOCATION_INFORMATION:
588 passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
589 break;
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;
594 break;
596 case RAW_SFILEINFO_RENAME_INFORMATION:
597 case RAW_SFILEINFO_POSITION_INFORMATION:
598 case RAW_SFILEINFO_MODE_INFORMATION:
599 passthru_level = st->generic.level;
600 break;
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;
621 default:
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),
628 &req->in.bufinfo);
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;
638 uint16_t level;
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));
661 op->op_info = st;
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;
675 uint16_t level;
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));
700 op->op_info = st;
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 */
708 struct find_state {
709 struct trans_op *op;
710 void *search;
711 enum smb_search_data_level data_level;
712 uint16_t last_entry_offset;
713 uint16_t flags;
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;
724 uint8_t *data;
725 unsigned int ofs = trans->out.data.length;
726 uint32_t ea_size;
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);
738 ofs += 4;
739 } else {
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));
752 break;
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);
758 ofs += 4;
759 } else {
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));
774 break;
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);
781 ofs += 4;
782 } else {
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));
797 break;
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;
813 return NT_STATUS_OK;
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);
829 return false;
832 state->last_entry_offset = old_length;
833 return true;
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;
845 uint8_t *param;
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);
858 return NT_STATUS_OK;
863 fill a referral type structure
865 static NTSTATUS fill_normal_dfs_referraltype(struct dfs_referral_type *ref,
866 uint16_t version,
867 const char *dfs_path,
868 const char *server_path, int isfirstoffset)
870 ZERO_STRUCTP(ref);
871 switch (version) {
872 case 4:
873 version = 3;
874 # if 0
875 /* For the moment there is a bug with XP that don't seems to appriciate much
876 * level4 so we return just level 3 for everyone
878 ref->referral.v4.server_type = DFS_SERVER_NON_ROOT;
879 /* "normal" referral seems to always include the GUID */
880 ref->referral.v4.size = 34;
882 if (isfirstoffset) {
883 ref->referral.v4.entry_flags = DFS_HEADER_FLAG_TARGET_BCK;
885 ref->referral.v4.ttl = 900; /* As w2k8r2 */
886 ref->referral.v4.referrals.r1.DFS_path = talloc_strdup(ref, dfs_path);
887 ref->referral.v4.referrals.r1.DFS_alt_path = talloc_strdup(ref, dfs_path);
888 ref->referral.v4.referrals.r1.netw_address = talloc_strdup(ref, server_path);
889 return NT_STATUS_OK;
890 #endif
891 case 3:
892 ref->version = version;
893 ref->referral.v3.server_type = DFS_SERVER_NON_ROOT;
894 /* "normal" referral seems to always include the GUID */
895 ref->referral.v3.size = 34;
897 ref->referral.v3.entry_flags = 0;
898 ref->referral.v3.ttl = 600; /* As w2k3 */
899 ref->referral.v3.referrals.r1.DFS_path = talloc_strdup(ref, dfs_path);
900 ref->referral.v3.referrals.r1.DFS_alt_path = talloc_strdup(ref, dfs_path);
901 ref->referral.v3.referrals.r1.netw_address = talloc_strdup(ref, server_path);
902 return NT_STATUS_OK;
904 return NT_STATUS_INVALID_LEVEL;
908 fill a domain refererral
910 static NTSTATUS fill_domain_dfs_referraltype(struct dfs_referral_type *ref,
911 uint16_t version,
912 const char *domain,
913 const char **names,
914 uint16_t numnames)
916 switch (version) {
917 case 3:
918 ZERO_STRUCTP(ref);
919 DEBUG(8, ("Called fill_domain_dfs_referraltype\n"));
920 ref->version = version;
921 ref->referral.v3.server_type = DFS_SERVER_NON_ROOT;
922 /* It's hard coded ... don't think it's a good way but the sizeof return not the
923 * correct values
925 * We have 18 if the GUID is not included 34 otherwise
927 if (numnames == 0) {
928 /* Windows return without the guid when returning domain list
930 ref->referral.v3.size = 18;
931 } else {
932 ref->referral.v3.size = 34;
934 ref->referral.v3.entry_flags = DFS_FLAG_REFERRAL_DOMAIN_RESP;
935 ref->referral.v3.ttl = 600; /* As w2k3 */
936 ref->referral.v3.referrals.r2.special_name = domain;
937 ref->referral.v3.referrals.r2.nb_expanded_names = numnames;
938 /* Put the final terminator */
939 if (names) {
940 const char **names2 = talloc_array(ref, const char *, numnames+1);
941 NT_STATUS_HAVE_NO_MEMORY(names2);
942 int i;
943 for (i = 0; i<numnames; i++) {
944 names2[i] = talloc_asprintf(names2, "\\%s", names[i]);
945 NT_STATUS_HAVE_NO_MEMORY(names2[i]);
947 names2[numnames] = NULL;
948 ref->referral.v3.referrals.r2.expanded_names = names2;
950 return NT_STATUS_OK;
952 return NT_STATUS_INVALID_LEVEL;
956 get the DCs list within a site
958 static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
959 struct ldb_dn *sitedn, struct dc_set *list,
960 bool dofqdn)
962 static const char *attrs[] = { "serverReference", NULL };
963 static const char *attrs2[] = { "dNSHostName", "sAMAccountName", NULL };
964 struct ldb_result *r;
965 unsigned int i;
966 int ret;
967 const char **dc_list;
969 ret = ldb_search(ldb, ctx, &r, sitedn, LDB_SCOPE_SUBTREE, attrs,
970 "(&(objectClass=server)(serverReference=*))");
971 if (ret != LDB_SUCCESS) {
972 DEBUG(2,(__location__ ": Failed to get list of servers - %s\n",
973 ldb_errstring(ldb)));
974 return NT_STATUS_INTERNAL_ERROR;
977 if (r->count == 0) {
978 /* none in this site */
979 talloc_free(r);
980 return NT_STATUS_OK;
984 * need to search for all server object to know the size of the array.
985 * Search all the object of class server in this site
987 dc_list = talloc_array(r, const char *, r->count);
988 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, r);
990 /* TODO put some random here in the order */
991 list->names = talloc_realloc(list, list->names, const char *, list->count + r->count);
992 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names, r);
994 for (i = 0; i<r->count; i++) {
995 struct ldb_dn *dn;
996 struct ldb_result *r2;
998 dn = ldb_msg_find_attr_as_dn(ldb, ctx, r->msgs[i], "serverReference");
999 if (!dn) {
1000 return NT_STATUS_INTERNAL_ERROR;
1003 ret = ldb_search(ldb, r, &r2, dn, LDB_SCOPE_BASE, attrs2, "(objectClass=computer)");
1004 if (ret != LDB_SUCCESS) {
1005 DEBUG(2,(__location__ ": Search for computer on %s failed - %s\n",
1006 ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1007 return NT_STATUS_INTERNAL_ERROR;
1010 if (dofqdn) {
1011 const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL);
1012 if (dns == NULL) {
1013 DEBUG(2,(__location__ ": dNSHostName missing on %s\n",
1014 ldb_dn_get_linearized(dn)));
1015 talloc_free(r);
1016 return NT_STATUS_INTERNAL_ERROR;
1019 list->names[list->count] = talloc_strdup(list->names, dns);
1020 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r);
1021 } else {
1022 char *tmp;
1023 const char *acct = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", NULL);
1024 if (acct == NULL) {
1025 DEBUG(2,(__location__ ": sAMAccountName missing on %s\n",
1026 ldb_dn_get_linearized(dn)));
1027 talloc_free(r);
1028 return NT_STATUS_INTERNAL_ERROR;
1031 tmp = talloc_strdup(list->names, acct);
1032 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r);
1034 /* Netbios name is also the sAMAccountName for
1035 computer but without the final $ */
1036 tmp[strlen(tmp) - 1] = '\0';
1037 list->names[list->count] = tmp;
1039 list->count++;
1040 talloc_free(r2);
1043 talloc_free(r);
1044 return NT_STATUS_OK;
1049 get all DCs
1051 static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
1052 const char *searched_site, bool need_fqdn,
1053 struct dc_set ***pset_list, uint32_t flags)
1056 * Flags will be used later to indicate things like least-expensive
1057 * or same-site options
1059 const char *attrs_none[] = { NULL };
1060 const char *attrs3[] = { "name", NULL };
1061 struct ldb_dn *configdn, *sitedn, *dn, *sitescontainerdn;
1062 struct ldb_result *r;
1063 struct dc_set **set_list = NULL;
1064 uint32_t i;
1065 int ret;
1066 uint32_t current_pos = 0;
1067 NTSTATUS status;
1068 TALLOC_CTX *subctx = talloc_new(ctx);
1070 *pset_list = set_list = NULL;
1072 subctx = talloc_new(ctx);
1073 NT_STATUS_HAVE_NO_MEMORY(subctx);
1075 configdn = ldb_get_config_basedn(ldb);
1077 /* Let's search for the Site container */
1078 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs_none,
1079 "(objectClass=sitesContainer)");
1080 if (ret != LDB_SUCCESS) {
1081 DEBUG(2,(__location__ ": Failed to find sitesContainer within %s - %s\n",
1082 ldb_dn_get_linearized(configdn), ldb_errstring(ldb)));
1083 talloc_free(subctx);
1084 return NT_STATUS_INTERNAL_ERROR;
1086 if (r->count > 1) {
1087 DEBUG(2,(__location__ ": Expected 1 sitesContainer - found %u within %s\n",
1088 r->count, ldb_dn_get_linearized(configdn)));
1089 talloc_free(subctx);
1090 return NT_STATUS_INTERNAL_ERROR;
1093 sitescontainerdn = talloc_steal(subctx, r->msgs[0]->dn);
1094 talloc_free(r);
1097 * TODO: Here we should have a more subtle handling
1098 * for the case "same-site"
1100 ret = ldb_search(ldb, subctx, &r, sitescontainerdn, LDB_SCOPE_SUBTREE,
1101 attrs_none, "(objectClass=server)");
1102 if (ret != LDB_SUCCESS) {
1103 DEBUG(2,(__location__ ": Failed to find servers within %s - %s\n",
1104 ldb_dn_get_linearized(sitescontainerdn), ldb_errstring(ldb)));
1105 talloc_free(subctx);
1106 return NT_STATUS_INTERNAL_ERROR;
1108 talloc_free(r);
1110 if (searched_site != NULL) {
1111 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE,
1112 attrs_none, "(&(name=%s)(objectClass=site))", searched_site);
1113 if (ret != LDB_SUCCESS) {
1114 talloc_free(subctx);
1115 return NT_STATUS_FOOBAR;
1116 } else if (r->count != 1) {
1117 talloc_free(subctx);
1118 return NT_STATUS_FOOBAR;
1121 /* All of this was to get the DN of the searched_site */
1122 sitedn = r->msgs[0]->dn;
1124 set_list = talloc_realloc(subctx, set_list, struct dc_set *, current_pos+1);
1125 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1127 set_list[current_pos] = talloc(set_list, struct dc_set);
1128 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1130 set_list[current_pos]->names = NULL;
1131 set_list[current_pos]->count = 0;
1132 status = get_dcs_insite(subctx, ldb, sitedn,
1133 set_list[current_pos], need_fqdn);
1134 if (!NT_STATUS_IS_OK(status)) {
1135 DEBUG(2,(__location__ ": Failed to get DC from site %s - %s\n",
1136 ldb_dn_get_linearized(sitedn), nt_errstr(status)));
1137 talloc_free(subctx);
1138 return status;
1140 talloc_free(r);
1141 current_pos++;
1144 /* Let's find all the sites */
1145 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs3, "(objectClass=site)");
1146 if (ret != LDB_SUCCESS) {
1147 DEBUG(2,(__location__ ": Failed to find any site containers in %s\n",
1148 ldb_dn_get_linearized(configdn)));
1149 talloc_free(subctx);
1150 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1154 * TODO:
1155 * We should randomize the order in the main site,
1156 * it's mostly needed for sysvol/netlogon referral.
1157 * Depending of flag we either randomize order of the
1158 * not "in the same site DCs"
1159 * or we randomize by group of site that have the same cost
1160 * In the long run we want to manipulate an array of site_set
1161 * All the site in one set have the same cost (if least-expansive options is selected)
1162 * and we will put all the dc related to 1 site set into 1 DCs set.
1163 * Within a site set, site order has to be randomized
1165 * But for the moment we just return the list of sites
1167 if (r->count) {
1169 * We will realloc + 2 because we will need one additional place
1170 * for element at current_pos + 1 for the NULL element
1172 set_list = talloc_realloc(subctx, set_list, struct dc_set *,
1173 current_pos+2);
1174 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1176 set_list[current_pos] = talloc(ctx, struct dc_set);
1177 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1179 set_list[current_pos]->names = NULL;
1180 set_list[current_pos]->count = 0;
1182 set_list[current_pos+1] = NULL;
1185 for (i=0; i<r->count; i++) {
1186 const char *site_name = ldb_msg_find_attr_as_string(r->msgs[i], "name", NULL);
1187 if (site_name == NULL) {
1188 DEBUG(2,(__location__ ": Failed to find name attribute in %s\n",
1189 ldb_dn_get_linearized(r->msgs[i]->dn)));
1190 talloc_free(subctx);
1191 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1194 if (searched_site == NULL ||
1195 strcmp(searched_site, site_name) != 0) {
1196 DEBUG(2,(__location__ ": Site: %s %s\n",
1197 searched_site, site_name));
1200 * Do all the site but the one of the client
1201 * (because it has already been done ...)
1203 dn = r->msgs[i]->dn;
1205 status = get_dcs_insite(subctx, ldb, dn,
1206 set_list[current_pos],
1207 need_fqdn);
1208 if (!NT_STATUS_IS_OK(status)) {
1209 talloc_free(subctx);
1210 return status;
1214 current_pos++;
1215 set_list[current_pos] = NULL;
1217 *pset_list = talloc_move(ctx, &set_list);
1218 talloc_free(subctx);
1219 return NT_STATUS_OK;
1222 static NTSTATUS dodomain_referral(TALLOC_CTX *ctx,
1223 const struct dfs_GetDFSReferral_in *dfsreq,
1224 struct ldb_context *ldb,
1225 struct smb_trans2 *trans,
1226 struct loadparm_context *lp_ctx)
1229 * TODO for the moment we just return the local domain
1231 DATA_BLOB outblob;
1232 enum ndr_err_code ndr_err;
1233 NTSTATUS status;
1234 const char *dns_domain = lpcfg_dnsdomain(lp_ctx);
1235 const char *netbios_domain = lpcfg_workgroup(lp_ctx);
1236 struct dfs_referral_resp resp;
1237 struct dfs_referral_type *tab;
1238 struct dfs_referral_type *referral;
1239 const char *referral_str;
1240 /* In the future this needs to be fetched from the ldb */
1241 uint32_t found_domain = 2;
1242 uint32_t current_pos = 0;
1243 TALLOC_CTX *context;
1245 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1246 DEBUG(10 ,("Received a domain referral request on a non DC\n"));
1247 return NT_STATUS_INVALID_PARAMETER;
1250 if (dfsreq->max_referral_level < 3) {
1251 DEBUG(2,("invalid max_referral_level %u\n",
1252 dfsreq->max_referral_level));
1253 return NT_STATUS_UNSUCCESSFUL;
1256 context = talloc_new(ctx);
1257 NT_STATUS_HAVE_NO_MEMORY(context);
1259 resp.path_consumed = 0;
1260 resp.header_flags = 0; /* Do like w2k3 */
1261 resp.nb_referrals = found_domain; /* the fqdn one + the NT domain */
1263 tab = talloc_array(context, struct dfs_referral_type, found_domain);
1264 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tab, context);
1266 referral = talloc(tab, struct dfs_referral_type);
1267 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1268 referral_str = talloc_asprintf(referral, "\\%s", netbios_domain);
1269 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1270 status = fill_domain_dfs_referraltype(referral, 3,
1271 referral_str,
1272 NULL, 0);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1275 talloc_free(context);
1276 return NT_STATUS_UNSUCCESSFUL;
1279 tab[current_pos] = *referral;
1280 current_pos++;
1282 referral = talloc(tab, struct dfs_referral_type);
1283 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1284 referral_str = talloc_asprintf(referral, "\\%s", dns_domain);
1285 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1286 status = fill_domain_dfs_referraltype(referral, 3,
1287 referral_str,
1288 NULL, 0);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1291 talloc_free(context);
1292 return NT_STATUS_UNSUCCESSFUL;
1294 tab[current_pos] = *referral;
1295 current_pos++;
1298 * Put here the code from filling the array for trusted domain
1300 resp.referral_entries = tab;
1302 ndr_err = ndr_push_struct_blob(&outblob, context,
1303 &resp,
1304 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1305 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1306 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1307 talloc_free(context);
1308 return NT_STATUS_INTERNAL_ERROR;
1311 if (outblob.length > trans->in.max_data) {
1312 bool ok = false;
1314 DEBUG(3, ("Blob is too big for the output buffer "
1315 "size %u max %u\n",
1316 (unsigned int)outblob.length, trans->in.max_data));
1318 if (trans->in.max_data != MAX_DFS_RESPONSE) {
1319 /* As specified in MS-DFSC.pdf 3.3.5.2 */
1320 talloc_free(context);
1321 return STATUS_BUFFER_OVERFLOW;
1325 * The answer is too big, so let's remove some answers
1327 while (!ok && resp.nb_referrals > 2) {
1328 data_blob_free(&outblob);
1331 * Let's scrap the first referral (for now)
1333 resp.nb_referrals -= 1;
1334 resp.referral_entries += 1;
1336 ndr_err = ndr_push_struct_blob(&outblob, context,
1337 &resp,
1338 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1339 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1340 talloc_free(context);
1341 return NT_STATUS_INTERNAL_ERROR;
1344 if (outblob.length <= MAX_DFS_RESPONSE) {
1345 DEBUG(10,("DFS: managed to reduce the size of referral initial"
1346 "number of referral %d, actual count: %d",
1347 found_domain, resp.nb_referrals));
1348 ok = true;
1349 break;
1353 if (!ok && resp.nb_referrals == 2) {
1354 DEBUG(8, (__location__ "; Not able to fit the domain and realm in DFS a "
1355 " 56K buffer, something must be broken"));
1356 talloc_free(context);
1357 return NT_STATUS_INTERNAL_ERROR;
1361 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1363 trans->out.data = outblob;
1364 talloc_steal(ctx, outblob.data);
1365 talloc_free(context);
1366 return NT_STATUS_OK;
1370 * Handle the logic for dfs referral request like \\domain
1371 * or \\domain\sysvol or \\fqdn or \\fqdn\netlogon
1373 static NTSTATUS dodc_or_sysvol_referral(TALLOC_CTX *ctx,
1374 const struct dfs_GetDFSReferral_in dfsreq,
1375 const char* requesteddomain,
1376 const char* requestedshare,
1377 const char* requestedname,
1378 struct ldb_context *ldb,
1379 struct smb_trans2 *trans,
1380 struct smbsrv_request *req,
1381 struct loadparm_context *lp_ctx)
1384 * It's not a "standard" DFS referral but a referral to get the DC list
1385 * or sysvol/netlogon
1386 * Let's check that it's for one of our domain ...
1388 DATA_BLOB outblob;
1389 NTSTATUS status;
1390 unsigned int num_domain = 1;
1391 enum ndr_err_code ndr_err;
1392 const char *realm = lpcfg_realm(lp_ctx);
1393 const char *domain = lpcfg_workgroup(lp_ctx);
1394 const char *site_name = NULL; /* Name of the site where the client is */
1395 bool found = false;
1396 bool need_fqdn = false;
1397 bool dc_referral = true;
1398 unsigned int i;
1399 struct dc_set **set;
1400 char const **domain_list;
1401 struct tsocket_address *remote_address;
1402 char *client_addr = NULL;
1403 TALLOC_CTX *context;
1405 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1406 return NT_STATUS_INVALID_PARAMETER;
1409 if (dfsreq.max_referral_level < 3) {
1410 DEBUG(2,("invalid max_referral_level %u\n",
1411 dfsreq.max_referral_level));
1412 return NT_STATUS_UNSUCCESSFUL;
1415 context = talloc_new(ctx);
1416 NT_STATUS_HAVE_NO_MEMORY(context);
1418 DEBUG(10, ("in this we have request for %s and share %s requested is %s\n",
1419 requesteddomain,
1420 requestedshare,
1421 requestedname));
1423 if (requestedshare) {
1424 DEBUG(10, ("Have a non DC domain referal\n"));
1425 dc_referral = false;
1429 * We will fetch the trusted domain list soon with something like this:
1431 * "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)
1432 * (trustPartner=%s))(objectclass=trustedDomain))"
1434 * Allocate for num_domain + 1 so that the last element will be NULL)
1436 domain_list = talloc_array(context, const char*, num_domain+1);
1437 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_list, context);
1439 domain_list[0] = realm;
1440 domain_list[1] = domain;
1441 for (i=0; i<=num_domain; i++) {
1442 if (strncasecmp(domain_list[i], requesteddomain, strlen(domain_list[i])) == 0) {
1443 found = true;
1444 break;
1448 if (!found) {
1449 /* The requested domain is not one that we support */
1450 DEBUG(3,("Requested referral for domain %s, but we don't handle it",
1451 requesteddomain));
1452 return NT_STATUS_INVALID_PARAMETER;
1455 if (strchr(requestedname,'.')) {
1456 need_fqdn = 1;
1459 remote_address = req->smb_conn->connection->remote_address;
1460 if (tsocket_address_is_inet(remote_address, "ip")) {
1461 client_addr = tsocket_address_inet_addr_string(remote_address, context);
1462 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_addr, context);
1465 status = get_dcs(context, ldb, site_name, need_fqdn, &set, 0);
1466 if (!NT_STATUS_IS_OK(status)) {
1467 DEBUG(3,("Unable to get list of DCs\n"));
1468 talloc_free(context);
1469 return status;
1472 if (dc_referral) {
1473 const char **dc_list = NULL;
1474 uint32_t num_dcs = 0;
1475 struct dfs_referral_type *referral;
1476 const char *referral_str;
1477 struct dfs_referral_resp resp;
1479 for(i=0; set[i]; i++) {
1480 uint32_t j;
1482 dc_list = talloc_realloc(context, dc_list, const char*,
1483 num_dcs + set[i]->count + 1);
1484 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, context);
1486 for(j=0; j<set[i]->count; j++) {
1487 dc_list[num_dcs + j] = talloc_steal(context, set[i]->names[j]);
1489 num_dcs = num_dcs + set[i]->count;
1490 TALLOC_FREE(set[i]);
1491 dc_list[num_dcs] = NULL;
1494 resp.path_consumed = 0;
1495 resp.header_flags = 0; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1498 * The NumberOfReferrals field MUST be set to 1,
1499 * independent of the number of DC names
1500 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1502 resp.nb_referrals = 1;
1504 /* Put here the code from filling the array for trusted domain */
1505 referral = talloc(context, struct dfs_referral_type);
1506 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1508 if (requestedname[0] == '\\') {
1509 referral_str = talloc_asprintf(referral, "%s",
1510 requestedname);
1511 } else {
1512 referral_str = talloc_asprintf(referral, "\\%s",
1513 requestedname);
1515 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1517 status = fill_domain_dfs_referraltype(referral, 3,
1518 referral_str,
1519 dc_list, num_dcs);
1520 if (!NT_STATUS_IS_OK(status)) {
1521 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1522 talloc_free(context);
1523 return NT_STATUS_UNSUCCESSFUL;
1525 resp.referral_entries = referral;
1527 ndr_err = ndr_push_struct_blob(&outblob, context,
1528 &resp,
1529 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1530 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1531 DEBUG(2,(__location__ ":NDR marshalling of dfs referral response failed\n"));
1532 talloc_free(context);
1533 return NT_STATUS_INTERNAL_ERROR;
1535 } else {
1536 unsigned int nb_entries = 0;
1537 unsigned int current = 0;
1538 struct dfs_referral_type *tab;
1539 struct dfs_referral_resp resp;
1541 for(i=0; set[i]; i++) {
1542 nb_entries = nb_entries + set[i]->count;
1545 resp.path_consumed = 2*strlen(requestedname); /* The length is expected in bytes */
1546 resp.header_flags = DFS_HEADER_FLAG_STORAGE_SVR; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1549 * The NumberOfReferrals field MUST be set to 1,
1550 * independent of the number of DC names
1551 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1553 resp.nb_referrals = nb_entries;
1555 tab = talloc_array(context, struct dfs_referral_type, nb_entries);
1556 NT_STATUS_HAVE_NO_MEMORY(tab);
1558 for(i=0; set[i]; i++) {
1559 uint32_t j;
1561 for(j=0; j< set[i]->count; j++) {
1562 struct dfs_referral_type *referral;
1563 const char *referral_str;
1565 referral = talloc(tab, struct dfs_referral_type);
1566 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1568 referral_str = talloc_asprintf(referral, "\\%s\\%s",
1569 set[i]->names[j], requestedshare);
1570 DEBUG(8, ("Doing a dfs referral for %s with this value %s requested %s\n", set[i]->names[j], referral_str, requestedname));
1571 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1573 status = fill_normal_dfs_referraltype(referral,
1574 dfsreq.max_referral_level,
1575 requestedname, referral_str, j==0);
1577 if (!NT_STATUS_IS_OK(status)) {
1578 DEBUG(2, (__location__ ": Unable to fill a normal dfs referral object"));
1579 talloc_free(context);
1580 return NT_STATUS_UNSUCCESSFUL;
1582 tab[current] = *referral;
1583 current++;
1586 resp.referral_entries = tab;
1588 ndr_err = ndr_push_struct_blob(&outblob, context,
1589 &resp,
1590 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1591 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1592 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1593 talloc_free(context);
1594 return NT_STATUS_INTERNAL_ERROR;
1598 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1601 * TODO If the size is too big we should remove
1602 * some DC from the answer or return STATUS_BUFFER_OVERFLOW
1604 trans->out.data = outblob;
1605 talloc_steal(ctx, outblob.data);
1606 talloc_free(context);
1607 return NT_STATUS_OK;
1611 trans2 getdfsreferral implementation
1613 static NTSTATUS trans2_getdfsreferral(struct smbsrv_request *req,
1614 struct trans_op *op)
1616 enum ndr_err_code ndr_err;
1617 struct smb_trans2 *trans = op->trans;
1618 struct dfs_GetDFSReferral_in dfsreq;
1619 TALLOC_CTX *context;
1620 struct ldb_context *ldb;
1621 struct loadparm_context *lp_ctx;
1622 const char *realm, *nbname, *requestedname;
1623 char *fqdn, *share, *domain, *tmp;
1624 NTSTATUS status;
1626 lp_ctx = req->tcon->ntvfs->lp_ctx;
1627 if (!lpcfg_host_msdfs(lp_ctx)) {
1628 return NT_STATUS_NOT_IMPLEMENTED;
1631 context = talloc_new(req);
1632 NT_STATUS_HAVE_NO_MEMORY(context);
1634 ldb = samdb_connect(context, req->tcon->ntvfs->event_ctx, lp_ctx, system_session(lp_ctx), 0);
1635 if (ldb == NULL) {
1636 DEBUG(2,(__location__ ": Failed to open samdb\n"));
1637 talloc_free(context);
1638 return NT_STATUS_INTERNAL_ERROR;
1641 ndr_err = ndr_pull_struct_blob(&trans->in.params, op,
1642 &dfsreq,
1643 (ndr_pull_flags_fn_t)ndr_pull_dfs_GetDFSReferral_in);
1644 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1645 status = ndr_map_error2ntstatus(ndr_err);
1646 DEBUG(2,(__location__ ": Failed to parse GetDFSReferral_in - %s\n",
1647 nt_errstr(status)));
1648 talloc_free(context);
1649 return status;
1652 DEBUG(8, ("Requested DFS name: %s length: %u\n",
1653 dfsreq.servername, (unsigned int)strlen(dfsreq.servername)));
1656 * If the servername is "" then we are in a case of domain dfs
1657 * and the client just searches for the list of local domain
1658 * it is attached and also trusted ones.
1660 requestedname = dfsreq.servername;
1661 if (requestedname == NULL || requestedname[0] == '\0') {
1662 return dodomain_referral(op, &dfsreq, ldb, trans, lp_ctx);
1665 realm = lpcfg_realm(lp_ctx);
1666 nbname = lpcfg_netbios_name(lp_ctx);
1667 fqdn = talloc_asprintf(context, "%s.%s", nbname, realm);
1669 if ((strncasecmp(requestedname+1, nbname, strlen(nbname)) == 0) ||
1670 (strncasecmp(requestedname+1, fqdn, strlen(fqdn)) == 0) ) {
1672 * the referral request starts with \NETBIOSNAME or \fqdn
1673 * it's a standalone referral we do not do it
1674 * (TODO correct this)
1675 * If a DFS link that is a complete prefix of the DFS referral
1676 * request path is identified, the server MUST return a DFS link
1677 * referral response; otherwise, if it has a match for the DFS root,
1678 * it MUST return a root referral response.
1680 DEBUG(3, ("Received a standalone request for %s, we do not support standalone referral yet",requestedname));
1681 talloc_free(context);
1682 return NT_STATUS_NOT_FOUND;
1684 talloc_free(fqdn);
1686 domain = talloc_strdup(context, requestedname);
1687 while(*domain && *domain == '\\') {
1688 domain++;
1691 tmp = strchr(domain,'\\'); /* To get second \ if any */
1692 share = NULL;
1693 if (tmp) {
1695 * We are finishing properly the domain string
1696 * and the share one will start after the \
1698 tmp[0] = '\\';
1699 tmp++;
1700 share = talloc_strdup(context, tmp);
1703 * Here we have filtered the thing the requested name don't contain our DNS name.
1704 * So if the share == NULL or if share in ("sysvol", "netlogon")
1705 * then we proceed. In the first case it will be a dc refereal in the second it will
1706 * be just a sysvol/netlogon referral.
1708 if (share == NULL ||
1709 strcasecmp(share, "sysvol") == 0 ||
1710 strcasecmp(share, "netlogon") == 0) {
1711 status = dodc_or_sysvol_referral(op, dfsreq, domain, share, requestedname,
1712 ldb, trans, req, lp_ctx);
1713 talloc_free(context);
1714 return status;
1717 tmp = strchr(share, '\\');
1718 if (tmp &&
1719 (strncasecmp(share, "sysvol", 6) == 0 ||
1720 strncasecmp(share, "netlogon", 8) == 0)) {
1722 * We have more than two \ so it something like
1723 * \domain\sysvol\foobar
1725 talloc_free(context);
1726 return NT_STATUS_NOT_FOUND;
1729 talloc_free(context);
1730 /* By default until all the case are handled*/
1731 return NT_STATUS_NOT_FOUND;
1735 trans2 findfirst implementation
1737 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1739 struct smb_trans2 *trans = op->trans;
1740 union smb_search_first *search;
1741 uint16_t level;
1742 struct find_state *state;
1744 /* make sure we got all the parameters */
1745 if (trans->in.params.length < 14) {
1746 return NT_STATUS_FOOBAR;
1749 search = talloc(op, union smb_search_first);
1750 NT_STATUS_HAVE_NO_MEMORY(search);
1752 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1753 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1754 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1755 level = SVAL(trans->in.params.data, 6);
1756 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1758 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1759 if (search->t2ffirst.in.pattern == NULL) {
1760 return NT_STATUS_FOOBAR;
1763 search->t2ffirst.level = RAW_SEARCH_TRANS2;
1764 search->t2ffirst.data_level = (enum smb_search_data_level)level;
1765 if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
1766 return NT_STATUS_INVALID_LEVEL;
1769 if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
1770 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1771 &search->t2ffirst.in.num_names,
1772 &search->t2ffirst.in.ea_names));
1775 /* setup the private state structure that the backend will
1776 give us in the callback */
1777 state = talloc(op, struct find_state);
1778 NT_STATUS_HAVE_NO_MEMORY(state);
1779 state->op = op;
1780 state->search = search;
1781 state->data_level = search->t2ffirst.data_level;
1782 state->last_entry_offset= 0;
1783 state->flags = search->t2ffirst.in.flags;
1785 /* setup for just a header in the reply */
1786 TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
1788 op->op_info = state;
1789 op->send_fn = trans2_findfirst_send;
1791 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1796 trans2 findnext send
1798 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1800 struct smbsrv_request *req = op->req;
1801 struct smb_trans2 *trans = op->trans;
1802 union smb_search_next *search;
1803 struct find_state *state;
1804 uint8_t *param;
1806 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1807 search = talloc_get_type(state->search, union smb_search_next);
1809 /* fill in the findfirst reply header */
1810 param = trans->out.params.data;
1811 SSVAL(param, VWV(0), search->t2fnext.out.count);
1812 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1813 SSVAL(param, VWV(2), 0);
1814 SSVAL(param, VWV(3), state->last_entry_offset);
1816 return NT_STATUS_OK;
1821 trans2 findnext implementation
1823 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1825 struct smb_trans2 *trans = op->trans;
1826 union smb_search_next *search;
1827 uint16_t level;
1828 struct find_state *state;
1830 /* make sure we got all the parameters */
1831 if (trans->in.params.length < 12) {
1832 return NT_STATUS_FOOBAR;
1835 search = talloc(op, union smb_search_next);
1836 NT_STATUS_HAVE_NO_MEMORY(search);
1838 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1839 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1840 level = SVAL(trans->in.params.data, 4);
1841 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1842 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1844 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1845 if (search->t2fnext.in.last_name == NULL) {
1846 return NT_STATUS_FOOBAR;
1849 search->t2fnext.level = RAW_SEARCH_TRANS2;
1850 search->t2fnext.data_level = (enum smb_search_data_level)level;
1851 if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
1852 return NT_STATUS_INVALID_LEVEL;
1855 if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
1856 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1857 &search->t2fnext.in.num_names,
1858 &search->t2fnext.in.ea_names));
1861 /* setup the private state structure that the backend will give us in the callback */
1862 state = talloc(op, struct find_state);
1863 NT_STATUS_HAVE_NO_MEMORY(state);
1864 state->op = op;
1865 state->search = search;
1866 state->data_level = search->t2fnext.data_level;
1867 state->last_entry_offset= 0;
1868 state->flags = search->t2fnext.in.flags;
1870 /* setup for just a header in the reply */
1871 TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
1873 op->op_info = state;
1874 op->send_fn = trans2_findnext_send;
1876 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1881 backend for trans2 requests
1883 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1885 struct smb_trans2 *trans = op->trans;
1886 NTSTATUS status;
1888 /* direct trans2 pass thru */
1889 status = ntvfs_trans2(req->ntvfs, trans);
1890 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1891 return status;
1894 /* must have at least one setup word */
1895 if (trans->in.setup_count < 1) {
1896 return NT_STATUS_FOOBAR;
1899 /* the trans2 command is in setup[0] */
1900 switch (trans->in.setup[0]) {
1901 case TRANSACT2_GET_DFS_REFERRAL:
1902 return trans2_getdfsreferral(req, op);
1903 case TRANSACT2_FINDFIRST:
1904 return trans2_findfirst(req, op);
1905 case TRANSACT2_FINDNEXT:
1906 return trans2_findnext(req, op);
1907 case TRANSACT2_QPATHINFO:
1908 return trans2_qpathinfo(req, op);
1909 case TRANSACT2_QFILEINFO:
1910 return trans2_qfileinfo(req, op);
1911 case TRANSACT2_SETFILEINFO:
1912 return trans2_setfileinfo(req, op);
1913 case TRANSACT2_SETPATHINFO:
1914 return trans2_setpathinfo(req, op);
1915 case TRANSACT2_QFSINFO:
1916 return trans2_qfsinfo(req, op);
1917 case TRANSACT2_OPEN:
1918 return trans2_open(req, op);
1919 case TRANSACT2_MKDIR:
1920 return trans2_mkdir(req, op);
1923 /* an unknown trans2 command */
1924 return NT_STATUS_FOOBAR;
1927 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
1929 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1930 return 0;
1935 send a continue request
1937 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1938 struct smb_trans2 *trans)
1940 struct smbsrv_request *req2;
1941 struct smbsrv_trans_partial *tp;
1942 int count;
1944 /* make sure they don't flood us */
1945 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1946 if (count > 100) {
1947 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1948 return;
1951 tp = talloc(req, struct smbsrv_trans_partial);
1953 tp->req = req;
1954 tp->u.trans = trans;
1955 tp->command = command;
1957 DLIST_ADD(req->smb_conn->trans_partial, tp);
1958 talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1960 req2 = smbsrv_setup_secondary_request(req);
1962 /* send a 'please continue' reply */
1963 smbsrv_setup_reply(req2, 0, 0);
1964 smbsrv_send_reply(req2);
1969 answer a reconstructed trans request
1971 static void reply_trans_send(struct ntvfs_request *ntvfs)
1973 struct smbsrv_request *req;
1974 struct trans_op *op;
1975 struct smb_trans2 *trans;
1976 uint16_t params_left, data_left;
1977 uint8_t *params, *data;
1978 int i;
1980 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1981 trans = op->trans;
1983 /* if this function needs work to form the nttrans reply buffer, then
1984 call that now */
1985 if (op->send_fn != NULL) {
1986 NTSTATUS status;
1987 status = op->send_fn(op);
1988 if (!NT_STATUS_IS_OK(status)) {
1989 smbsrv_send_error(req, status);
1990 return;
1994 params_left = trans->out.params.length;
1995 data_left = trans->out.data.length;
1996 params = trans->out.params.data;
1997 data = trans->out.data.data;
1999 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
2001 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
2002 smbsrv_setup_error(req, req->ntvfs->async_states->status);
2005 /* we need to divide up the reply into chunks that fit into
2006 the negotiated buffer size */
2007 do {
2008 uint16_t this_data, this_param, max_bytes;
2009 unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
2010 struct smbsrv_request *this_req;
2012 max_bytes = req_max_data(req) - (align1 + align2);
2014 this_param = params_left;
2015 if (this_param > max_bytes) {
2016 this_param = max_bytes;
2018 max_bytes -= this_param;
2020 this_data = data_left;
2021 if (this_data > max_bytes) {
2022 this_data = max_bytes;
2025 /* don't destroy unless this is the last chunk */
2026 if (params_left - this_param != 0 ||
2027 data_left - this_data != 0) {
2028 this_req = smbsrv_setup_secondary_request(req);
2029 } else {
2030 this_req = req;
2033 req_grow_data(this_req, this_param + this_data + (align1 + align2));
2035 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
2036 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
2037 SSVAL(this_req->out.vwv, VWV(2), 0);
2039 SSVAL(this_req->out.vwv, VWV(3), this_param);
2040 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
2041 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
2043 SSVAL(this_req->out.vwv, VWV(6), this_data);
2044 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
2045 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
2046 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
2048 SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
2049 SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
2050 for (i=0;i<trans->out.setup_count;i++) {
2051 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
2054 memset(this_req->out.data, 0, align1);
2055 if (this_param != 0) {
2056 memcpy(this_req->out.data + align1, params, this_param);
2058 memset(this_req->out.data+this_param+align1, 0, align2);
2059 if (this_data != 0) {
2060 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
2063 params_left -= this_param;
2064 data_left -= this_data;
2065 params += this_param;
2066 data += this_data;
2068 smbsrv_send_reply(this_req);
2069 } while (params_left != 0 || data_left != 0);
2074 answer a reconstructed trans request
2076 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
2077 struct smb_trans2 *trans)
2079 struct trans_op *op;
2081 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
2082 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2084 op->req = req;
2085 op->trans = trans;
2086 op->command = command;
2087 op->op_info = NULL;
2088 op->send_fn = NULL;
2090 /* its a full request, give it to the backend */
2091 if (command == SMBtrans) {
2092 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
2093 return;
2094 } else {
2095 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
2096 return;
2101 Reply to an SMBtrans or SMBtrans2 request
2103 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
2105 struct smb_trans2 *trans;
2106 int i;
2107 uint16_t param_ofs, data_ofs;
2108 uint16_t param_count, data_count;
2109 uint16_t param_total, data_total;
2111 /* parse request */
2112 if (req->in.wct < 14) {
2113 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2114 return;
2117 trans = talloc(req, struct smb_trans2);
2118 if (trans == NULL) {
2119 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2120 return;
2123 param_total = SVAL(req->in.vwv, VWV(0));
2124 data_total = SVAL(req->in.vwv, VWV(1));
2125 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
2126 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
2127 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
2128 trans->in.flags = SVAL(req->in.vwv, VWV(5));
2129 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
2130 param_count = SVAL(req->in.vwv, VWV(9));
2131 param_ofs = SVAL(req->in.vwv, VWV(10));
2132 data_count = SVAL(req->in.vwv, VWV(11));
2133 data_ofs = SVAL(req->in.vwv, VWV(12));
2134 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
2136 if (req->in.wct != 14 + trans->in.setup_count) {
2137 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
2138 return;
2141 /* parse out the setup words */
2142 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
2143 if (trans->in.setup_count && !trans->in.setup) {
2144 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2145 return;
2147 for (i=0;i<trans->in.setup_count;i++) {
2148 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
2151 if (command == SMBtrans) {
2152 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
2155 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
2156 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
2157 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2158 return;
2161 /* is it a partial request? if so, then send a 'send more' message */
2162 if (param_total > param_count || data_total > data_count) {
2163 reply_trans_continue(req, command, trans);
2164 return;
2167 reply_trans_complete(req, command, trans);
2172 Reply to an SMBtranss2 request
2174 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
2176 struct smbsrv_trans_partial *tp;
2177 struct smb_trans2 *trans = NULL;
2178 uint16_t param_ofs, data_ofs;
2179 uint16_t param_count, data_count;
2180 uint16_t param_disp, data_disp;
2181 uint16_t param_total, data_total;
2182 DATA_BLOB params, data;
2183 uint8_t wct;
2185 if (command == SMBtrans2) {
2186 wct = 9;
2187 } else {
2188 wct = 8;
2191 /* parse request */
2192 if (req->in.wct != wct) {
2194 * TODO: add some error code tests
2195 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
2197 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2198 return;
2201 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
2202 if (tp->command == command &&
2203 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
2204 /* TODO: check the VUID, PID and TID too? */
2205 break;
2209 if (tp == NULL) {
2210 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2211 return;
2214 trans = tp->u.trans;
2216 param_total = SVAL(req->in.vwv, VWV(0));
2217 data_total = SVAL(req->in.vwv, VWV(1));
2218 param_count = SVAL(req->in.vwv, VWV(2));
2219 param_ofs = SVAL(req->in.vwv, VWV(3));
2220 param_disp = SVAL(req->in.vwv, VWV(4));
2221 data_count = SVAL(req->in.vwv, VWV(5));
2222 data_ofs = SVAL(req->in.vwv, VWV(6));
2223 data_disp = SVAL(req->in.vwv, VWV(7));
2225 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &params) ||
2226 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
2227 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2228 return;
2231 /* only allow contiguous requests */
2232 if ((param_count != 0 &&
2233 param_disp != trans->in.params.length) ||
2234 (data_count != 0 &&
2235 data_disp != trans->in.data.length)) {
2236 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2237 return;
2240 /* add to the existing request */
2241 if (param_count != 0) {
2242 trans->in.params.data = talloc_realloc(trans,
2243 trans->in.params.data,
2244 uint8_t,
2245 param_disp + param_count);
2246 if (trans->in.params.data == NULL) {
2247 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2248 return;
2250 trans->in.params.length = param_disp + param_count;
2253 if (data_count != 0) {
2254 trans->in.data.data = talloc_realloc(trans,
2255 trans->in.data.data,
2256 uint8_t,
2257 data_disp + data_count);
2258 if (trans->in.data.data == NULL) {
2259 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2260 return;
2262 trans->in.data.length = data_disp + data_count;
2265 memcpy(trans->in.params.data + param_disp, params.data, params.length);
2266 memcpy(trans->in.data.data + data_disp, data.data, data.length);
2268 /* the sequence number of the reply is taken from the last secondary
2269 response */
2270 tp->req->seq_num = req->seq_num;
2272 /* we don't reply to Transs2 requests */
2273 talloc_free(req);
2275 if (trans->in.params.length == param_total &&
2276 trans->in.data.length == data_total) {
2277 /* its now complete */
2278 req = tp->req;
2279 talloc_free(tp);
2280 reply_trans_complete(req, command, trans);
2282 return;
2287 Reply to an SMBtrans2
2289 void smbsrv_reply_trans2(struct smbsrv_request *req)
2291 reply_trans_generic(req, SMBtrans2);
2295 Reply to an SMBtrans
2297 void smbsrv_reply_trans(struct smbsrv_request *req)
2299 reply_trans_generic(req, SMBtrans);
2303 Reply to an SMBtranss request
2305 void smbsrv_reply_transs(struct smbsrv_request *req)
2307 reply_transs_generic(req, SMBtrans);
2311 Reply to an SMBtranss2 request
2313 void smbsrv_reply_transs2(struct smbsrv_request *req)
2315 reply_transs_generic(req, SMBtrans2);