s4-dfs: fix bugs in idl and adapt code accordingly
[Samba/gebeck_regimport.git] / source4 / smb_server / smb / trans2.c
blobfbddc177edf396dd0c9131d5e7b59193132093a0
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)
871 switch (version) {
872 case 3:
873 ZERO_STRUCTP(ref);
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;
884 return NT_STATUS_OK;
885 case 4:
886 ZERO_STRUCTP(ref);
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;
892 if (isfirstoffset) {
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;
900 return NT_STATUS_OK;
902 return NT_STATUS_INVALID_LEVEL;
906 fill a domain refererral
908 static NTSTATUS fill_domain_dfs_referraltype(struct dfs_referral_type *ref,
909 uint16_t version,
910 const char *domain,
911 const char **names,
912 uint16_t numnames)
914 switch (version) {
915 case 3:
916 ZERO_STRUCTP(ref);
917 ref->version = version;
918 ref->referral.v3.server_type = DFS_SERVER_NON_ROOT;
919 /* It's hard coded ... don't think it's a good way but the sizeof return not the
920 * correct values
922 * We have 18 if the GUID is not included 34 otherwise
924 if (numnames == 0) {
925 /* Windows return without the guid when returning domain list
927 ref->referral.v3.size = 18;
928 } else {
929 ref->referral.v3.size = 34;
931 ref->referral.v3.entry_flags = DFS_FLAG_REFERRAL_DOMAIN_RESP;
932 ref->referral.v3.ttl = 600; /* As w2k3 */
933 ref->referral.v3.referrals.r2.special_name = domain;
934 ref->referral.v3.referrals.r2.nb_expanded_names = numnames;
935 /* Put the final terminator */
936 if (names) {
937 const char **names2 = talloc_array(ref, const char *, numnames+1);
938 NT_STATUS_HAVE_NO_MEMORY(names2);
939 int i;
940 for (i = 0; i<numnames; i++) {
941 names2[i] = talloc_asprintf(names2, "\\%s", names[i]);
942 NT_STATUS_HAVE_NO_MEMORY(names2[i]);
944 names2[numnames] = 0;
945 ref->referral.v3.referrals.r2.expanded_names = names2;
947 return NT_STATUS_OK;
949 return NT_STATUS_INVALID_LEVEL;
953 get the DCs list within a site
955 static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
956 struct ldb_dn *sitedn, struct dc_set *list,
957 bool dofqdn)
959 static const char *attrs[] = { "serverReference", NULL };
960 static const char *attrs2[] = { "dNSHostName", "sAMAccountName", NULL };
961 struct ldb_result *r;
962 unsigned int i;
963 int ret;
964 const char **dc_list;
966 ret = ldb_search(ldb, ctx, &r, sitedn, LDB_SCOPE_SUBTREE, attrs,
967 "(&(objectClass=server)(serverReference=*))");
968 if (ret != LDB_SUCCESS) {
969 DEBUG(2,(__location__ ": Failed to get list of servers - %s\n",
970 ldb_errstring(ldb)));
971 return NT_STATUS_INTERNAL_ERROR;
974 if (r->count == 0) {
975 /* none in this site */
976 talloc_free(r);
977 return NT_STATUS_OK;
981 * need to search for all server object to know the size of the array.
982 * Search all the object of class server in this site
984 dc_list = talloc_array(r, const char *, r->count);
985 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, r);
987 /* TODO put some random here in the order */
988 list->names = talloc_realloc(list, list->names, const char *, list->count + r->count);
989 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names, r);
991 for (i = 0; i<r->count; i++) {
992 struct ldb_dn *dn;
993 struct ldb_result *r2;
995 dn = ldb_msg_find_attr_as_dn(ldb, ctx, r->msgs[i], "serverReference");
996 if (!dn) {
997 return NT_STATUS_INTERNAL_ERROR;
1000 ret = ldb_search(ldb, r, &r2, dn, LDB_SCOPE_BASE, attrs2, "(objectClass=computer)");
1001 if (ret != LDB_SUCCESS) {
1002 DEBUG(2,(__location__ ": Search for computer on %s failed - %s\n",
1003 ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1004 return NT_STATUS_INTERNAL_ERROR;
1007 if (dofqdn) {
1008 const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL);
1009 if (dns == NULL) {
1010 DEBUG(2,(__location__ ": dNSHostName missing on %s\n",
1011 ldb_dn_get_linearized(dn)));
1012 talloc_free(r);
1013 return NT_STATUS_INTERNAL_ERROR;
1016 list->names[list->count] = talloc_strdup(list->names, dns);
1017 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r);
1018 } else {
1019 char *tmp;
1020 const char *acct = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", NULL);
1021 if (acct == NULL) {
1022 DEBUG(2,(__location__ ": sAMAccountName missing on %s\n",
1023 ldb_dn_get_linearized(dn)));
1024 talloc_free(r);
1025 return NT_STATUS_INTERNAL_ERROR;
1028 tmp = talloc_strdup(list->names, acct);
1029 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r);
1031 /* Netbios name is also the sAMAccountName for
1032 computer but without the final $ */
1033 tmp[strlen(tmp) - 1] = '\0';
1034 list->names[list->count] = tmp;
1036 list->count++;
1037 talloc_free(r2);
1040 talloc_free(r);
1041 return NT_STATUS_OK;
1046 get all DCs
1048 static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
1049 const char *searched_site, bool need_fqdn,
1050 struct dc_set ***pset_list, uint32_t flags)
1053 * Flags will be used later to indicate things like least-expensive
1054 * or same-site options
1056 const char *attrs_none[] = { NULL };
1057 const char *attrs3[] = { "name", NULL };
1058 struct ldb_dn *configdn, *sitedn, *dn, *sitescontainerdn;
1059 struct ldb_result *r;
1060 struct dc_set **set_list = NULL;
1061 uint32_t i;
1062 int ret;
1063 uint32_t current_pos = 0;
1064 NTSTATUS status;
1065 TALLOC_CTX *subctx = talloc_new(ctx);
1067 *pset_list = set_list = NULL;
1069 subctx = talloc_new(ctx);
1070 NT_STATUS_HAVE_NO_MEMORY(subctx);
1072 configdn = ldb_get_config_basedn(ldb);
1074 /* Let's search for the Site container */
1075 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs_none,
1076 "(objectClass=sitesContainer)");
1077 if (ret != LDB_SUCCESS) {
1078 DEBUG(2,(__location__ ": Failed to find sitesContainer within %s - %s\n",
1079 ldb_dn_get_linearized(configdn), ldb_errstring(ldb)));
1080 talloc_free(subctx);
1081 return NT_STATUS_INTERNAL_ERROR;
1083 if (r->count > 1) {
1084 DEBUG(2,(__location__ ": Expected 1 sitesContainer - found %u within %s\n",
1085 r->count, ldb_dn_get_linearized(configdn)));
1086 talloc_free(subctx);
1087 return NT_STATUS_INTERNAL_ERROR;
1090 sitescontainerdn = talloc_steal(subctx, r->msgs[0]->dn);
1091 talloc_free(r);
1094 * TODO: Here we should have a more subtle handling
1095 * for the case "same-site"
1097 ret = ldb_search(ldb, subctx, &r, sitescontainerdn, LDB_SCOPE_SUBTREE,
1098 attrs_none, "(objectClass=server)");
1099 if (ret != LDB_SUCCESS) {
1100 DEBUG(2,(__location__ ": Failed to find servers within %s - %s\n",
1101 ldb_dn_get_linearized(sitescontainerdn), ldb_errstring(ldb)));
1102 talloc_free(subctx);
1103 return NT_STATUS_INTERNAL_ERROR;
1105 talloc_free(r);
1107 if (searched_site != NULL) {
1108 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE,
1109 attrs_none, "(&(name=%s)(objectClass=site))", searched_site);
1110 if (ret != LDB_SUCCESS) {
1111 talloc_free(subctx);
1112 return NT_STATUS_FOOBAR;
1113 } else if (r->count != 1) {
1114 talloc_free(subctx);
1115 return NT_STATUS_FOOBAR;
1118 /* All of this was to get the DN of the searched_site */
1119 sitedn = r->msgs[0]->dn;
1121 set_list = talloc_realloc(subctx, set_list, struct dc_set *, current_pos+1);
1122 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1124 set_list[current_pos] = talloc(set_list, struct dc_set);
1125 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1127 set_list[current_pos]->names = NULL;
1128 set_list[current_pos]->count = 0;
1129 status = get_dcs_insite(subctx, ldb, sitedn,
1130 set_list[current_pos], need_fqdn);
1131 if (!NT_STATUS_IS_OK(status)) {
1132 DEBUG(2,(__location__ ": Failed to get DC from site %s - %s\n",
1133 ldb_dn_get_linearized(sitedn), nt_errstr(status)));
1134 talloc_free(subctx);
1135 return status;
1137 talloc_free(r);
1138 current_pos++;
1141 /* Let's find all the sites */
1142 ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs3, "(objectClass=site)");
1143 if (ret != LDB_SUCCESS) {
1144 DEBUG(2,(__location__ ": Failed to find any site containers in %s\n",
1145 ldb_dn_get_linearized(configdn)));
1146 talloc_free(subctx);
1147 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1151 * TODO:
1152 * We should randomize the order in the main site,
1153 * it's mostly needed for sysvol/netlogon referral.
1154 * Depending of flag we either randomize order of the
1155 * not "in the same site DCs"
1156 * or we randomize by group of site that have the same cost
1157 * In the long run we want to manipulate an array of site_set
1158 * All the site in one set have the same cost (if least-expansive options is selected)
1159 * and we will put all the dc related to 1 site set into 1 DCs set.
1160 * Within a site set, site order has to be randomized
1162 * But for the moment we just return the list of sites
1164 if (r->count) {
1166 * We will realloc + 2 because we will need one additional place
1167 * for element at current_pos + 1 for the NULL element
1169 set_list = talloc_realloc(subctx, set_list, struct dc_set *,
1170 current_pos+2);
1171 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
1173 set_list[current_pos] = talloc(ctx, struct dc_set);
1174 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
1176 set_list[current_pos]->names = NULL;
1177 set_list[current_pos]->count = 0;
1179 set_list[current_pos+1] = NULL;
1182 for (i=0; i<r->count; i++) {
1183 const char *site_name = ldb_msg_find_attr_as_string(r->msgs[i], "name", NULL);
1184 if (site_name == NULL) {
1185 DEBUG(2,(__location__ ": Failed to find name attribute in %s\n",
1186 ldb_dn_get_linearized(r->msgs[i]->dn)));
1187 talloc_free(subctx);
1188 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1191 if (searched_site == NULL ||
1192 strcmp(searched_site, site_name) != 0) {
1193 DEBUG(2,(__location__ ": Site: %s %s\n",
1194 searched_site, site_name));
1197 * Do all the site but the one of the client
1198 * (because it has already been done ...)
1200 dn = r->msgs[i]->dn;
1202 status = get_dcs_insite(subctx, ldb, dn,
1203 set_list[current_pos],
1204 need_fqdn);
1205 if (!NT_STATUS_IS_OK(status)) {
1206 talloc_free(subctx);
1207 return status;
1211 current_pos++;
1212 set_list[current_pos] = NULL;
1214 *pset_list = talloc_move(ctx, &set_list);
1215 talloc_free(subctx);
1216 return NT_STATUS_OK;
1219 static NTSTATUS dodomain_referral(TALLOC_CTX *ctx,
1220 const struct dfs_GetDFSReferral_in *dfsreq,
1221 struct ldb_context *ldb,
1222 struct smb_trans2 *trans,
1223 struct loadparm_context *lp_ctx)
1226 * TODO for the moment we just return the local domain
1228 DATA_BLOB outblob;
1229 enum ndr_err_code ndr_err;
1230 NTSTATUS status;
1231 const char *dns_domain = lpcfg_dnsdomain(lp_ctx);
1232 const char *netbios_domain = lpcfg_workgroup(lp_ctx);
1233 struct dfs_referral_resp resp;
1234 struct dfs_referral_type *tab;
1235 struct dfs_referral_type *referral;
1236 const char *referral_str;
1237 /* In the future this needs to be fetched from the ldb */
1238 uint32_t found_domain = 2;
1239 uint32_t current_pos = 0;
1240 TALLOC_CTX *context;
1242 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1243 DEBUG(10 ,("Received a domain referral request on a non DC\n"));
1244 return NT_STATUS_INVALID_PARAMETER;
1247 if (dfsreq->max_referral_level < 3) {
1248 DEBUG(2,("invalid max_referral_level %u\n",
1249 dfsreq->max_referral_level));
1250 return NT_STATUS_UNSUCCESSFUL;
1253 context = talloc_new(ctx);
1254 NT_STATUS_HAVE_NO_MEMORY(context);
1256 resp.path_consumed = 0;
1257 resp.header_flags = 0; /* Do like w2k3 */
1258 resp.nb_referrals = found_domain; /* the fqdn one + the NT domain */
1260 tab = talloc_array(context, struct dfs_referral_type, found_domain);
1261 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tab, context);
1263 referral = talloc(tab, struct dfs_referral_type);
1264 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1265 referral_str = talloc_asprintf(referral, "\\%s", netbios_domain);
1266 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1267 status = fill_domain_dfs_referraltype(referral, 3,
1268 referral_str,
1269 NULL, 0);
1270 if (!NT_STATUS_IS_OK(status)) {
1271 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1272 talloc_free(context);
1273 return NT_STATUS_UNSUCCESSFUL;
1276 tab[current_pos] = *referral;
1277 current_pos++;
1279 referral = talloc(tab, struct dfs_referral_type);
1280 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1281 referral_str = talloc_asprintf(referral, "\\%s", dns_domain);
1282 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1283 status = fill_domain_dfs_referraltype(referral, 3,
1284 referral_str,
1285 NULL, 0);
1286 if (!NT_STATUS_IS_OK(status)) {
1287 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1288 talloc_free(context);
1289 return NT_STATUS_UNSUCCESSFUL;
1291 tab[current_pos] = *referral;
1292 current_pos++;
1295 * Put here the code from filling the array for trusted domain
1297 resp.referral_entries = tab;
1299 ndr_err = ndr_push_struct_blob(&outblob, context,
1300 &resp,
1301 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1303 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1304 talloc_free(context);
1305 return NT_STATUS_INTERNAL_ERROR;
1308 if (outblob.length > trans->in.max_data) {
1309 bool ok = false;
1311 DEBUG(3, ("Blob is too big for the output buffer "
1312 "size %u max %u\n",
1313 (unsigned int)outblob.length, trans->in.max_data));
1315 if (trans->in.max_data != MAX_DFS_RESPONSE) {
1316 /* As specified in MS-DFSC.pdf 3.3.5.2 */
1317 talloc_free(context);
1318 return STATUS_BUFFER_OVERFLOW;
1322 * The answer is too big, so let's remove some answers
1324 while (!ok && resp.nb_referrals > 2) {
1325 data_blob_free(&outblob);
1328 * Let's scrap the first referral (for now)
1330 resp.nb_referrals -= 1;
1331 resp.referral_entries += 1;
1333 ndr_err = ndr_push_struct_blob(&outblob, context,
1334 &resp,
1335 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1337 talloc_free(context);
1338 return NT_STATUS_INTERNAL_ERROR;
1341 if (outblob.length <= MAX_DFS_RESPONSE) {
1342 DEBUG(10,("DFS: managed to reduce the size of referral initial"
1343 "number of referral %d, actual count: %d",
1344 found_domain, resp.nb_referrals));
1345 ok = true;
1346 break;
1350 if (!ok && resp.nb_referrals == 2) {
1351 DEBUG(0, (__location__ "; Not able to fit the domain and realm in DFS a "
1352 " 56K buffer, something must be broken"));
1353 talloc_free(context);
1354 return NT_STATUS_INTERNAL_ERROR;
1358 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1360 trans->out.data = outblob;
1361 talloc_steal(ctx, outblob.data);
1362 talloc_free(context);
1363 return NT_STATUS_OK;
1367 * Handle the logic for dfs referral request like \\domain
1368 * or \\domain\sysvol or \\fqdn or \\fqdn\netlogon
1370 static NTSTATUS dodc_or_sysvol_referral(TALLOC_CTX *ctx,
1371 const struct dfs_GetDFSReferral_in dfsreq,
1372 const char* requestedname,
1373 struct ldb_context *ldb,
1374 struct smb_trans2 *trans,
1375 struct smbsrv_request *req,
1376 struct loadparm_context *lp_ctx)
1379 * It's not a "standard" DFS referral but a referral to get the DC list
1380 * or sysvol/netlogon
1381 * Let's check that it's for one of our domain ...
1383 DATA_BLOB outblob;
1384 NTSTATUS status;
1385 unsigned int num_domain = 1;
1386 enum ndr_err_code ndr_err;
1387 const char *requesteddomain;
1388 const char *realm = lpcfg_realm(lp_ctx);
1389 const char *domain = lpcfg_workgroup(lp_ctx);
1390 const char *site_name = NULL; /* Name of the site where the client is */
1391 char *share = NULL;
1392 bool found = false;
1393 bool need_fqdn = false;
1394 bool dc_referral = true;
1395 unsigned int i;
1396 char *tmp;
1397 struct dc_set **set;
1398 char const **domain_list;
1399 struct tsocket_address *remote_address;
1400 char *client_addr = NULL;
1401 TALLOC_CTX *context;
1403 if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
1404 return NT_STATUS_INVALID_PARAMETER;
1407 if (dfsreq.max_referral_level < 3) {
1408 DEBUG(2,("invalid max_referral_level %u\n",
1409 dfsreq.max_referral_level));
1410 return NT_STATUS_UNSUCCESSFUL;
1413 context = talloc_new(ctx);
1414 NT_STATUS_HAVE_NO_MEMORY(context);
1416 if (requestedname[0] == '\\' && !strchr(requestedname+1,'\\')) {
1417 requestedname++;
1419 requesteddomain = requestedname;
1421 if (strchr(requestedname,'\\')) {
1422 char *subpart;
1423 /* we have a second part */
1424 requesteddomain = talloc_strdup(context, requestedname+1);
1425 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(requesteddomain, context);
1426 subpart = strchr(requesteddomain,'\\');
1427 subpart[0] = '\0';
1429 tmp = strchr(requestedname + 1,'\\'); /* To get second \ if any */
1431 if (tmp != NULL) {
1432 /* There was a share */
1433 share = tmp+1;
1434 dc_referral = false;
1438 * We will fetch the trusted domain list soon with something like this:
1440 * "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)
1441 * (trustPartner=%s))(objectclass=trustedDomain))"
1443 * Allocate for num_domain + 1 so that the last element will be NULL)
1445 domain_list = talloc_array(context, const char*, num_domain+1);
1446 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_list, context);
1448 domain_list[0] = realm;
1449 domain_list[1] = domain;
1450 for (i=0; i<=num_domain; i++) {
1451 if (strncasecmp(domain_list[i], requesteddomain, strlen(domain_list[i])) == 0) {
1452 found = true;
1453 break;
1457 if (!found) {
1458 /* The requested domain is not one that we support */
1459 DEBUG(3,("Requested referral for domain %s, but we don't handle it",
1460 requesteddomain));
1461 return NT_STATUS_INVALID_PARAMETER;
1464 if (strchr(requestedname,'.')) {
1465 need_fqdn = 1;
1468 remote_address = req->smb_conn->connection->remote_address;
1469 if (tsocket_address_is_inet(remote_address, "ip")) {
1470 client_addr = tsocket_address_inet_addr_string(remote_address, context);
1471 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_addr, context);
1474 status = get_dcs(context, ldb, site_name, need_fqdn, &set, 0);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 DEBUG(3,("Unable to get list of DCs\n"));
1477 talloc_free(context);
1478 return status;
1481 if (dc_referral) {
1482 const char **dc_list = NULL;
1483 uint32_t num_dcs = 0;
1484 struct dfs_referral_type *referral;
1485 const char *referral_str;
1486 struct dfs_referral_resp resp;
1488 for(i=0; set[i]; i++) {
1489 uint32_t j;
1491 dc_list = talloc_realloc(context, dc_list, const char*,
1492 num_dcs + set[i]->count + 1);
1493 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, context);
1495 for(j=0; j<set[i]->count; j++) {
1496 dc_list[num_dcs + j] = talloc_steal(context, set[i]->names[j]);
1498 num_dcs = num_dcs + set[i]->count;
1499 TALLOC_FREE(set[i]);
1500 dc_list[num_dcs] = NULL;
1503 resp.path_consumed = 0;
1504 resp.header_flags = 0; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1507 * The NumberOfReferrals field MUST be set to 1,
1508 * independent of the number of DC names
1509 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1511 resp.nb_referrals = 1;
1513 /* Put here the code from filling the array for trusted domain */
1514 referral = talloc(context, struct dfs_referral_type);
1515 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1517 referral_str = talloc_asprintf(referral, "\\%s",
1518 requestedname);
1519 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1521 status = fill_domain_dfs_referraltype(referral, 3,
1522 referral_str,
1523 dc_list, num_dcs);
1524 if (!NT_STATUS_IS_OK(status)) {
1525 DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
1526 talloc_free(context);
1527 return NT_STATUS_UNSUCCESSFUL;
1529 resp.referral_entries = referral;
1531 ndr_err = ndr_push_struct_blob(&outblob, context,
1532 &resp,
1533 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1534 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1535 DEBUG(2,(__location__ ":NDR marshalling of dfs referral response failed\n"));
1536 talloc_free(context);
1537 return NT_STATUS_INTERNAL_ERROR;
1539 } else {
1540 unsigned int nb_entries = 0;
1541 unsigned int current = 0;
1542 struct dfs_referral_type *tab;
1543 struct dfs_referral_resp resp;
1545 for(i=0; set[i]; i++) {
1546 nb_entries = nb_entries + set[i]->count;
1549 resp.path_consumed = 2*strlen(requestedname); /* The length is expected in bytes */
1550 resp.header_flags = DFS_HEADER_FLAG_STORAGE_SVR; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
1553 * The NumberOfReferrals field MUST be set to 1,
1554 * independent of the number of DC names
1555 * returned. (as stated in 3.3.5.3 of MS-DFSC)
1557 resp.nb_referrals = nb_entries;
1559 tab = talloc_array(context, struct dfs_referral_type, nb_entries);
1560 NT_STATUS_HAVE_NO_MEMORY(tab);
1562 for(i=0; set[i]; i++) {
1563 uint32_t j;
1565 for(j=0; j< set[i]->count; j++) {
1566 struct dfs_referral_type *referral;
1567 const char *referral_str;
1569 referral = talloc(tab, struct dfs_referral_type);
1570 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
1572 referral_str = talloc_asprintf(referral, "\\%s\\%s",
1573 set[i]->names[j], share);
1574 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
1576 status = fill_normal_dfs_referraltype(referral,
1577 dfsreq.max_referral_level,
1578 requestedname, referral_str, j==0);
1579 if (!NT_STATUS_IS_OK(status)) {
1580 DEBUG(2, (__location__ ": Unable to fill a normal dfs referral object"));
1581 talloc_free(context);
1582 return NT_STATUS_UNSUCCESSFUL;
1584 tab[current] = *referral;
1585 current++;
1588 resp.referral_entries = tab;
1590 ndr_err = ndr_push_struct_blob(&outblob, context,
1591 &resp,
1592 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1593 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1594 DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
1595 talloc_free(context);
1596 return NT_STATUS_INTERNAL_ERROR;
1600 TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
1603 * TODO If the size is too big we should remove
1604 * some DC from the answer or return STATUS_BUFFER_OVERFLOW
1606 trans->out.data = outblob;
1607 talloc_steal(ctx, outblob.data);
1608 talloc_free(context);
1609 return NT_STATUS_OK;
1613 trans2 getdfsreferral implementation
1615 static NTSTATUS trans2_getdfsreferral(struct smbsrv_request *req,
1616 struct trans_op *op)
1618 enum ndr_err_code ndr_err;
1619 struct smb_trans2 *trans = op->trans;
1620 struct dfs_GetDFSReferral_in dfsreq;
1621 TALLOC_CTX *context;
1622 struct ldb_context *ldb;
1623 struct loadparm_context *lp_ctx;
1624 const char *realm, *nbname, *requestedname;
1625 char *fqdn, *tmp;
1626 NTSTATUS status;
1628 lp_ctx = req->tcon->ntvfs->lp_ctx;
1629 if (!lpcfg_host_msdfs(lp_ctx)) {
1630 return NT_STATUS_NOT_IMPLEMENTED;
1633 context = talloc_new(req);
1634 NT_STATUS_HAVE_NO_MEMORY(context);
1636 ldb = samdb_connect(context, req->tcon->ntvfs->event_ctx, lp_ctx, system_session(lp_ctx), 0);
1637 if (ldb == NULL) {
1638 DEBUG(2,(__location__ ": Failed to open samdb\n"));
1639 talloc_free(context);
1640 return NT_STATUS_INTERNAL_ERROR;
1643 ndr_err = ndr_pull_struct_blob(&trans->in.params, op,
1644 &dfsreq,
1645 (ndr_pull_flags_fn_t)ndr_pull_dfs_GetDFSReferral_in);
1646 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1647 status = ndr_map_error2ntstatus(ndr_err);
1648 DEBUG(2,(__location__ ": Failed to parse GetDFSReferral_in - %s\n",
1649 nt_errstr(status)));
1650 talloc_free(context);
1651 return status;
1654 DEBUG(10, ("Requested DFS name: %s length: %u\n",
1655 dfsreq.servername, (unsigned int)strlen(dfsreq.servername)));
1658 * If the servername is "" then we are in a case of domain dfs
1659 * and the client just searches for the list of local domain
1660 * it is attached and also trusted ones.
1662 requestedname = dfsreq.servername;
1663 if (requestedname == NULL || requestedname[0] == '\0') {
1664 return dodomain_referral(op, &dfsreq, ldb, trans, lp_ctx);
1667 realm = lpcfg_realm(lp_ctx);
1668 nbname = lpcfg_netbios_name(lp_ctx);
1669 fqdn = talloc_asprintf(context, "%s.%s", nbname, realm);
1671 if ((strncasecmp(requestedname+1, nbname, strlen(nbname)) == 0) ||
1672 (strncasecmp(requestedname+1, fqdn, strlen(fqdn)) == 0) ) {
1674 * the referral request starts with \NETBIOSNAME or \fqdn
1675 * it's a standalone referral we do not do it
1676 * (TODO correct this)
1677 * If a DFS link that is a complete prefix of the DFS referral
1678 * request path is identified, the server MUST return a DFS link
1679 * referral response; otherwise, if it has a match for the DFS root,
1680 * it MUST return a root referral response.
1682 DEBUG(3, ("Received a standalone request for %s, we do not support standalone referral yet",requestedname));
1683 talloc_free(context);
1684 return NT_STATUS_NOT_FOUND;
1686 talloc_free(fqdn);
1688 tmp = strchr(requestedname + 1,'\\'); /* To get second \ if any */
1691 * If we have no slash at the first position or (foo.bar.domain.net)
1692 * a slash at the first position but no other slash (\foo.bar.domain.net)
1693 * or a slash at the first position and another slash
1694 * and netlogon or sysvol after the second slash
1695 * (\foo.bar.domain.net\sysvol) then we will handle it because
1696 * it's either a dc referral or a sysvol/netlogon referral
1698 if (requestedname[0] != '\\' ||
1699 tmp == NULL ||
1700 strcasecmp(tmp+1, "sysvol") == 0 ||
1701 strcasecmp(tmp+1, "netlogon") == 0) {
1702 status = dodc_or_sysvol_referral(op, dfsreq, requestedname,
1703 ldb, trans, req, lp_ctx);
1704 talloc_free(context);
1705 return status;
1708 if (requestedname[0] == '\\' &&
1709 tmp &&
1710 strchr(tmp+1, '\\') &&
1711 (strncasecmp(tmp+1, "sysvol", 6) == 0 ||
1712 strncasecmp(tmp+1, "netlogon", 8) == 0)) {
1714 * We have more than two \ so it something like
1715 * \domain\sysvol\foobar
1717 talloc_free(context);
1718 return NT_STATUS_NOT_FOUND;
1721 talloc_free(context);
1722 /* By default until all the case are handled*/
1723 return NT_STATUS_NOT_FOUND;
1727 trans2 findfirst implementation
1729 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1731 struct smb_trans2 *trans = op->trans;
1732 union smb_search_first *search;
1733 uint16_t level;
1734 struct find_state *state;
1736 /* make sure we got all the parameters */
1737 if (trans->in.params.length < 14) {
1738 return NT_STATUS_FOOBAR;
1741 search = talloc(op, union smb_search_first);
1742 NT_STATUS_HAVE_NO_MEMORY(search);
1744 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1745 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1746 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1747 level = SVAL(trans->in.params.data, 6);
1748 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1750 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1751 if (search->t2ffirst.in.pattern == NULL) {
1752 return NT_STATUS_FOOBAR;
1755 search->t2ffirst.level = RAW_SEARCH_TRANS2;
1756 search->t2ffirst.data_level = (enum smb_search_data_level)level;
1757 if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
1758 return NT_STATUS_INVALID_LEVEL;
1761 if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
1762 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1763 &search->t2ffirst.in.num_names,
1764 &search->t2ffirst.in.ea_names));
1767 /* setup the private state structure that the backend will
1768 give us in the callback */
1769 state = talloc(op, struct find_state);
1770 NT_STATUS_HAVE_NO_MEMORY(state);
1771 state->op = op;
1772 state->search = search;
1773 state->data_level = search->t2ffirst.data_level;
1774 state->last_entry_offset= 0;
1775 state->flags = search->t2ffirst.in.flags;
1777 /* setup for just a header in the reply */
1778 TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
1780 op->op_info = state;
1781 op->send_fn = trans2_findfirst_send;
1783 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1788 trans2 findnext send
1790 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1792 struct smbsrv_request *req = op->req;
1793 struct smb_trans2 *trans = op->trans;
1794 union smb_search_next *search;
1795 struct find_state *state;
1796 uint8_t *param;
1798 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1799 search = talloc_get_type(state->search, union smb_search_next);
1801 /* fill in the findfirst reply header */
1802 param = trans->out.params.data;
1803 SSVAL(param, VWV(0), search->t2fnext.out.count);
1804 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1805 SSVAL(param, VWV(2), 0);
1806 SSVAL(param, VWV(3), state->last_entry_offset);
1808 return NT_STATUS_OK;
1813 trans2 findnext implementation
1815 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1817 struct smb_trans2 *trans = op->trans;
1818 union smb_search_next *search;
1819 uint16_t level;
1820 struct find_state *state;
1822 /* make sure we got all the parameters */
1823 if (trans->in.params.length < 12) {
1824 return NT_STATUS_FOOBAR;
1827 search = talloc(op, union smb_search_next);
1828 NT_STATUS_HAVE_NO_MEMORY(search);
1830 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1831 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1832 level = SVAL(trans->in.params.data, 4);
1833 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1834 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1836 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1837 if (search->t2fnext.in.last_name == NULL) {
1838 return NT_STATUS_FOOBAR;
1841 search->t2fnext.level = RAW_SEARCH_TRANS2;
1842 search->t2fnext.data_level = (enum smb_search_data_level)level;
1843 if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
1844 return NT_STATUS_INVALID_LEVEL;
1847 if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
1848 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1849 &search->t2fnext.in.num_names,
1850 &search->t2fnext.in.ea_names));
1853 /* setup the private state structure that the backend will give us in the callback */
1854 state = talloc(op, struct find_state);
1855 NT_STATUS_HAVE_NO_MEMORY(state);
1856 state->op = op;
1857 state->search = search;
1858 state->data_level = search->t2fnext.data_level;
1859 state->last_entry_offset= 0;
1860 state->flags = search->t2fnext.in.flags;
1862 /* setup for just a header in the reply */
1863 TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
1865 op->op_info = state;
1866 op->send_fn = trans2_findnext_send;
1868 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1873 backend for trans2 requests
1875 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1877 struct smb_trans2 *trans = op->trans;
1878 NTSTATUS status;
1880 /* direct trans2 pass thru */
1881 status = ntvfs_trans2(req->ntvfs, trans);
1882 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1883 return status;
1886 /* must have at least one setup word */
1887 if (trans->in.setup_count < 1) {
1888 return NT_STATUS_FOOBAR;
1891 /* the trans2 command is in setup[0] */
1892 switch (trans->in.setup[0]) {
1893 case TRANSACT2_GET_DFS_REFERRAL:
1894 return trans2_getdfsreferral(req, op);
1895 case TRANSACT2_FINDFIRST:
1896 return trans2_findfirst(req, op);
1897 case TRANSACT2_FINDNEXT:
1898 return trans2_findnext(req, op);
1899 case TRANSACT2_QPATHINFO:
1900 return trans2_qpathinfo(req, op);
1901 case TRANSACT2_QFILEINFO:
1902 return trans2_qfileinfo(req, op);
1903 case TRANSACT2_SETFILEINFO:
1904 return trans2_setfileinfo(req, op);
1905 case TRANSACT2_SETPATHINFO:
1906 return trans2_setpathinfo(req, op);
1907 case TRANSACT2_QFSINFO:
1908 return trans2_qfsinfo(req, op);
1909 case TRANSACT2_OPEN:
1910 return trans2_open(req, op);
1911 case TRANSACT2_MKDIR:
1912 return trans2_mkdir(req, op);
1915 /* an unknown trans2 command */
1916 return NT_STATUS_FOOBAR;
1919 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
1921 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1922 return 0;
1927 send a continue request
1929 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1930 struct smb_trans2 *trans)
1932 struct smbsrv_request *req2;
1933 struct smbsrv_trans_partial *tp;
1934 int count;
1936 /* make sure they don't flood us */
1937 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1938 if (count > 100) {
1939 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1940 return;
1943 tp = talloc(req, struct smbsrv_trans_partial);
1945 tp->req = req;
1946 tp->u.trans = trans;
1947 tp->command = command;
1949 DLIST_ADD(req->smb_conn->trans_partial, tp);
1950 talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1952 req2 = smbsrv_setup_secondary_request(req);
1954 /* send a 'please continue' reply */
1955 smbsrv_setup_reply(req2, 0, 0);
1956 smbsrv_send_reply(req2);
1961 answer a reconstructed trans request
1963 static void reply_trans_send(struct ntvfs_request *ntvfs)
1965 struct smbsrv_request *req;
1966 struct trans_op *op;
1967 struct smb_trans2 *trans;
1968 uint16_t params_left, data_left;
1969 uint8_t *params, *data;
1970 int i;
1972 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1973 trans = op->trans;
1975 /* if this function needs work to form the nttrans reply buffer, then
1976 call that now */
1977 if (op->send_fn != NULL) {
1978 NTSTATUS status;
1979 status = op->send_fn(op);
1980 if (!NT_STATUS_IS_OK(status)) {
1981 smbsrv_send_error(req, status);
1982 return;
1986 params_left = trans->out.params.length;
1987 data_left = trans->out.data.length;
1988 params = trans->out.params.data;
1989 data = trans->out.data.data;
1991 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1993 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1994 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1997 /* we need to divide up the reply into chunks that fit into
1998 the negotiated buffer size */
1999 do {
2000 uint16_t this_data, this_param, max_bytes;
2001 unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
2002 struct smbsrv_request *this_req;
2004 max_bytes = req_max_data(req) - (align1 + align2);
2006 this_param = params_left;
2007 if (this_param > max_bytes) {
2008 this_param = max_bytes;
2010 max_bytes -= this_param;
2012 this_data = data_left;
2013 if (this_data > max_bytes) {
2014 this_data = max_bytes;
2017 /* don't destroy unless this is the last chunk */
2018 if (params_left - this_param != 0 ||
2019 data_left - this_data != 0) {
2020 this_req = smbsrv_setup_secondary_request(req);
2021 } else {
2022 this_req = req;
2025 req_grow_data(this_req, this_param + this_data + (align1 + align2));
2027 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
2028 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
2029 SSVAL(this_req->out.vwv, VWV(2), 0);
2031 SSVAL(this_req->out.vwv, VWV(3), this_param);
2032 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
2033 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
2035 SSVAL(this_req->out.vwv, VWV(6), this_data);
2036 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
2037 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
2038 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
2040 SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
2041 SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
2042 for (i=0;i<trans->out.setup_count;i++) {
2043 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
2046 memset(this_req->out.data, 0, align1);
2047 if (this_param != 0) {
2048 memcpy(this_req->out.data + align1, params, this_param);
2050 memset(this_req->out.data+this_param+align1, 0, align2);
2051 if (this_data != 0) {
2052 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
2055 params_left -= this_param;
2056 data_left -= this_data;
2057 params += this_param;
2058 data += this_data;
2060 smbsrv_send_reply(this_req);
2061 } while (params_left != 0 || data_left != 0);
2066 answer a reconstructed trans request
2068 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
2069 struct smb_trans2 *trans)
2071 struct trans_op *op;
2073 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
2074 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2076 op->req = req;
2077 op->trans = trans;
2078 op->command = command;
2079 op->op_info = NULL;
2080 op->send_fn = NULL;
2082 /* its a full request, give it to the backend */
2083 if (command == SMBtrans) {
2084 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
2085 return;
2086 } else {
2087 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
2088 return;
2093 Reply to an SMBtrans or SMBtrans2 request
2095 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
2097 struct smb_trans2 *trans;
2098 int i;
2099 uint16_t param_ofs, data_ofs;
2100 uint16_t param_count, data_count;
2101 uint16_t param_total, data_total;
2103 /* parse request */
2104 if (req->in.wct < 14) {
2105 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2106 return;
2109 trans = talloc(req, struct smb_trans2);
2110 if (trans == NULL) {
2111 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2112 return;
2115 param_total = SVAL(req->in.vwv, VWV(0));
2116 data_total = SVAL(req->in.vwv, VWV(1));
2117 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
2118 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
2119 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
2120 trans->in.flags = SVAL(req->in.vwv, VWV(5));
2121 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
2122 param_count = SVAL(req->in.vwv, VWV(9));
2123 param_ofs = SVAL(req->in.vwv, VWV(10));
2124 data_count = SVAL(req->in.vwv, VWV(11));
2125 data_ofs = SVAL(req->in.vwv, VWV(12));
2126 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
2128 if (req->in.wct != 14 + trans->in.setup_count) {
2129 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
2130 return;
2133 /* parse out the setup words */
2134 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
2135 if (trans->in.setup_count && !trans->in.setup) {
2136 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
2137 return;
2139 for (i=0;i<trans->in.setup_count;i++) {
2140 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
2143 if (command == SMBtrans) {
2144 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
2147 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
2148 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
2149 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2150 return;
2153 /* is it a partial request? if so, then send a 'send more' message */
2154 if (param_total > param_count || data_total > data_count) {
2155 reply_trans_continue(req, command, trans);
2156 return;
2159 reply_trans_complete(req, command, trans);
2164 Reply to an SMBtranss2 request
2166 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
2168 struct smbsrv_trans_partial *tp;
2169 struct smb_trans2 *trans = NULL;
2170 uint16_t param_ofs, data_ofs;
2171 uint16_t param_count, data_count;
2172 uint16_t param_disp, data_disp;
2173 uint16_t param_total, data_total;
2174 DATA_BLOB params, data;
2175 uint8_t wct;
2177 if (command == SMBtrans2) {
2178 wct = 9;
2179 } else {
2180 wct = 8;
2183 /* parse request */
2184 if (req->in.wct != wct) {
2186 * TODO: add some error code tests
2187 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
2189 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2190 return;
2193 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
2194 if (tp->command == command &&
2195 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
2196 /* TODO: check the VUID, PID and TID too? */
2197 break;
2201 if (tp == NULL) {
2202 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2203 return;
2206 trans = tp->u.trans;
2208 param_total = SVAL(req->in.vwv, VWV(0));
2209 data_total = SVAL(req->in.vwv, VWV(1));
2210 param_count = SVAL(req->in.vwv, VWV(2));
2211 param_ofs = SVAL(req->in.vwv, VWV(3));
2212 param_disp = SVAL(req->in.vwv, VWV(4));
2213 data_count = SVAL(req->in.vwv, VWV(5));
2214 data_ofs = SVAL(req->in.vwv, VWV(6));
2215 data_disp = SVAL(req->in.vwv, VWV(7));
2217 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &params) ||
2218 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
2219 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2220 return;
2223 /* only allow contiguous requests */
2224 if ((param_count != 0 &&
2225 param_disp != trans->in.params.length) ||
2226 (data_count != 0 &&
2227 data_disp != trans->in.data.length)) {
2228 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2229 return;
2232 /* add to the existing request */
2233 if (param_count != 0) {
2234 trans->in.params.data = talloc_realloc(trans,
2235 trans->in.params.data,
2236 uint8_t,
2237 param_disp + param_count);
2238 if (trans->in.params.data == NULL) {
2239 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2240 return;
2242 trans->in.params.length = param_disp + param_count;
2245 if (data_count != 0) {
2246 trans->in.data.data = talloc_realloc(trans,
2247 trans->in.data.data,
2248 uint8_t,
2249 data_disp + data_count);
2250 if (trans->in.data.data == NULL) {
2251 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
2252 return;
2254 trans->in.data.length = data_disp + data_count;
2257 memcpy(trans->in.params.data + param_disp, params.data, params.length);
2258 memcpy(trans->in.data.data + data_disp, data.data, data.length);
2260 /* the sequence number of the reply is taken from the last secondary
2261 response */
2262 tp->req->seq_num = req->seq_num;
2264 /* we don't reply to Transs2 requests */
2265 talloc_free(req);
2267 if (trans->in.params.length == param_total &&
2268 trans->in.data.length == data_total) {
2269 /* its now complete */
2270 req = tp->req;
2271 talloc_free(tp);
2272 reply_trans_complete(req, command, trans);
2274 return;
2279 Reply to an SMBtrans2
2281 void smbsrv_reply_trans2(struct smbsrv_request *req)
2283 reply_trans_generic(req, SMBtrans2);
2287 Reply to an SMBtrans
2289 void smbsrv_reply_trans(struct smbsrv_request *req)
2291 reply_trans_generic(req, SMBtrans);
2295 Reply to an SMBtranss request
2297 void smbsrv_reply_transs(struct smbsrv_request *req)
2299 reply_transs_generic(req, SMBtrans);
2303 Reply to an SMBtranss2 request
2305 void smbsrv_reply_transs2(struct smbsrv_request *req)
2307 reply_transs_generic(req, SMBtrans2);