ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source3 / smbd / smb1_trans2.c
blob155f7c62bb17ad2c43de79d4a92f8c0e3e14e793
1 /*
2 Unix SMB/CIFS implementation.
3 SMB transaction2 handling
4 Copyright (C) Jeremy Allison 1994-2007
5 Copyright (C) Stefan (metze) Metzmacher 2003
6 Copyright (C) Volker Lendecke 2005-2007
7 Copyright (C) Steve French 2005
8 Copyright (C) James Peach 2006-2007
10 Extensively modified by Andrew Tridgell, 1995
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "includes.h"
27 #include "ntioctl.h"
28 #include "system/filesys.h"
29 #include "lib/util/time_basic.h"
30 #include "version.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "../libcli/auth/libcli_auth.h"
34 #include "../librpc/gen_ndr/xattr.h"
35 #include "../librpc/gen_ndr/ndr_security.h"
36 #include "libcli/security/security.h"
37 #include "trans2.h"
38 #include "auth.h"
39 #include "smbprofile.h"
40 #include "rpc_server/srv_pipe_hnd.h"
41 #include "printing.h"
42 #include "lib/util_ea.h"
43 #include "lib/readdir_attr.h"
44 #include "messages.h"
45 #include "libcli/smb/smb2_posix.h"
46 #include "lib/util/string_wrappers.h"
47 #include "source3/lib/substitute.h"
48 #include "source3/lib/adouble.h"
49 #include "source3/smbd/dir.h"
51 #define DIR_ENTRY_SAFETY_MARGIN 4096
53 /****************************************************************************
54 Send the required number of replies back.
55 We assume all fields other than the data fields are
56 set correctly for the type of call.
57 HACK ! Always assumes smb_setup field is zero.
58 ****************************************************************************/
60 static void send_trans2_replies(connection_struct *conn,
61 struct smb_request *req,
62 NTSTATUS status,
63 const char *params,
64 int paramsize,
65 const char *pdata,
66 int datasize,
67 int max_data_bytes)
69 /* As we are using a protocol > LANMAN1 then the max_send
70 variable must have been set in the sessetupX call.
71 This takes precedence over the max_xmit field in the
72 global struct. These different max_xmit variables should
73 be merged as this is now too confusing */
75 int data_to_send = datasize;
76 int params_to_send = paramsize;
77 int useable_space;
78 const char *pp = params;
79 const char *pd = pdata;
80 int params_sent_thistime, data_sent_thistime, total_sent_thistime;
81 int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
82 int data_alignment_offset = 0;
83 bool overflow = False;
84 struct smbXsrv_connection *xconn = req->xconn;
85 int max_send = xconn->smb1.sessions.max_send;
87 /* Modify the data_to_send and datasize and set the error if
88 we're trying to send more than max_data_bytes. We still send
89 the part of the packet(s) that fit. Strange, but needed
90 for OS/2. */
92 if (max_data_bytes > 0 && datasize > max_data_bytes) {
93 DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
94 max_data_bytes, datasize ));
95 datasize = data_to_send = max_data_bytes;
96 overflow = True;
99 /* If there genuinely are no parameters or data to send just send the empty packet */
101 if(params_to_send == 0 && data_to_send == 0) {
102 reply_smb1_outbuf(req, 10, 0);
103 if (NT_STATUS_V(status)) {
104 uint8_t eclass;
105 uint32_t ecode;
106 ntstatus_to_dos(status, &eclass, &ecode);
107 error_packet_set((char *)req->outbuf,
108 eclass, ecode, status,
109 __LINE__,__FILE__);
111 show_msg((char *)req->outbuf);
112 if (!smb1_srv_send(xconn,
113 (char *)req->outbuf,
114 true,
115 req->seqnum + 1,
116 IS_CONN_ENCRYPTED(conn))) {
117 exit_server_cleanly("send_trans2_replies: smb1_srv_send failed.");
119 TALLOC_FREE(req->outbuf);
120 return;
123 /* When sending params and data ensure that both are nicely aligned */
124 /* Only do this alignment when there is also data to send - else
125 can cause NT redirector problems. */
127 if (((params_to_send % 4) != 0) && (data_to_send != 0))
128 data_alignment_offset = 4 - (params_to_send % 4);
130 /* Space is bufsize minus Netbios over TCP header minus SMB header */
131 /* The alignment_offset is to align the param bytes on an even byte
132 boundary. NT 4.0 Beta needs this to work correctly. */
134 useable_space = max_send - (smb_size
135 + 2 * 10 /* wct */
136 + alignment_offset
137 + data_alignment_offset);
139 if (useable_space < 0) {
140 DEBUG(0, ("send_trans2_replies failed sanity useable_space "
141 "= %d!!!\n", useable_space));
142 exit_server_cleanly("send_trans2_replies: Not enough space");
145 while (params_to_send || data_to_send) {
146 /* Calculate whether we will totally or partially fill this packet */
148 total_sent_thistime = params_to_send + data_to_send;
150 /* We can never send more than useable_space */
152 * Note that 'useable_space' does not include the alignment offsets,
153 * but we must include the alignment offsets in the calculation of
154 * the length of the data we send over the wire, as the alignment offsets
155 * are sent here. Fix from Marc_Jacobsen@hp.com.
158 total_sent_thistime = MIN(total_sent_thistime, useable_space);
160 reply_smb1_outbuf(req, 10, total_sent_thistime + alignment_offset
161 + data_alignment_offset);
163 /* Set total params and data to be sent */
164 SSVAL(req->outbuf,smb_tprcnt,paramsize);
165 SSVAL(req->outbuf,smb_tdrcnt,datasize);
167 /* Calculate how many parameters and data we can fit into
168 * this packet. Parameters get precedence
171 params_sent_thistime = MIN(params_to_send,useable_space);
172 data_sent_thistime = useable_space - params_sent_thistime;
173 data_sent_thistime = MIN(data_sent_thistime,data_to_send);
175 SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
177 /* smb_proff is the offset from the start of the SMB header to the
178 parameter bytes, however the first 4 bytes of outbuf are
179 the Netbios over TCP header. Thus use smb_base() to subtract
180 them from the calculation */
182 SSVAL(req->outbuf,smb_proff,
183 ((smb_buf(req->outbuf)+alignment_offset)
184 - smb_base(req->outbuf)));
186 if(params_sent_thistime == 0)
187 SSVAL(req->outbuf,smb_prdisp,0);
188 else
189 /* Absolute displacement of param bytes sent in this packet */
190 SSVAL(req->outbuf,smb_prdisp,pp - params);
192 SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
193 if(data_sent_thistime == 0) {
194 SSVAL(req->outbuf,smb_droff,0);
195 SSVAL(req->outbuf,smb_drdisp, 0);
196 } else {
197 /* The offset of the data bytes is the offset of the
198 parameter bytes plus the number of parameters being sent this time */
199 SSVAL(req->outbuf, smb_droff,
200 ((smb_buf(req->outbuf)+alignment_offset)
201 - smb_base(req->outbuf))
202 + params_sent_thistime + data_alignment_offset);
203 SSVAL(req->outbuf,smb_drdisp, pd - pdata);
206 /* Initialize the padding for alignment */
208 if (alignment_offset != 0) {
209 memset(smb_buf(req->outbuf), 0, alignment_offset);
212 /* Copy the param bytes into the packet */
214 if(params_sent_thistime) {
215 memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
216 params_sent_thistime);
219 /* Copy in the data bytes */
220 if(data_sent_thistime) {
221 if (data_alignment_offset != 0) {
222 memset((smb_buf(req->outbuf)+alignment_offset+
223 params_sent_thistime), 0,
224 data_alignment_offset);
226 memcpy(smb_buf(req->outbuf)+alignment_offset
227 +params_sent_thistime+data_alignment_offset,
228 pd,data_sent_thistime);
231 DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
232 params_sent_thistime, data_sent_thistime, useable_space));
233 DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
234 params_to_send, data_to_send, paramsize, datasize));
236 if (overflow) {
237 error_packet_set((char *)req->outbuf,
238 ERRDOS,ERRbufferoverflow,
239 STATUS_BUFFER_OVERFLOW,
240 __LINE__,__FILE__);
241 } else if (NT_STATUS_V(status)) {
242 uint8_t eclass;
243 uint32_t ecode;
244 ntstatus_to_dos(status, &eclass, &ecode);
245 error_packet_set((char *)req->outbuf,
246 eclass, ecode, status,
247 __LINE__,__FILE__);
250 /* Send the packet */
251 show_msg((char *)req->outbuf);
252 if (!smb1_srv_send(xconn,
253 (char *)req->outbuf,
254 true,
255 req->seqnum + 1,
256 IS_CONN_ENCRYPTED(conn))) {
257 exit_server_cleanly("send_trans2_replies: smb1_srv_send failed.");
260 TALLOC_FREE(req->outbuf);
262 pp += params_sent_thistime;
263 pd += data_sent_thistime;
265 params_to_send -= params_sent_thistime;
266 data_to_send -= data_sent_thistime;
268 /* Sanity check */
269 if(params_to_send < 0 || data_to_send < 0) {
270 DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
271 params_to_send, data_to_send));
272 return;
276 return;
279 /****************************************************************************
280 Deal with SMB_SET_POSIX_LOCK.
281 ****************************************************************************/
283 static void smb_set_posix_lock_done(struct tevent_req *subreq);
285 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
286 struct smb_request *req,
287 const char *pdata,
288 int total_data,
289 files_struct *fsp)
291 struct tevent_req *subreq = NULL;
292 struct smbd_lock_element *lck = NULL;
293 uint64_t count;
294 uint64_t offset;
295 uint64_t smblctx;
296 bool blocking_lock = False;
297 enum brl_type lock_type;
299 NTSTATUS status = NT_STATUS_OK;
301 if (!CAN_WRITE(conn)) {
302 return NT_STATUS_DOS(ERRSRV, ERRaccess);
305 if (fsp == NULL ||
306 fsp->fsp_flags.is_pathref ||
307 fsp_get_io_fd(fsp) == -1)
309 return NT_STATUS_INVALID_HANDLE;
312 if (total_data != POSIX_LOCK_DATA_SIZE) {
313 return NT_STATUS_INVALID_PARAMETER;
316 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
317 case POSIX_LOCK_TYPE_READ:
318 lock_type = READ_LOCK;
319 break;
320 case POSIX_LOCK_TYPE_WRITE:
321 /* Return the right POSIX-mappable error code for files opened read-only. */
322 if (!fsp->fsp_flags.can_write) {
323 return NT_STATUS_INVALID_HANDLE;
325 lock_type = WRITE_LOCK;
326 break;
327 case POSIX_LOCK_TYPE_UNLOCK:
328 lock_type = UNLOCK_LOCK;
329 break;
330 default:
331 return NT_STATUS_INVALID_PARAMETER;
334 switch (SVAL(pdata, POSIX_LOCK_FLAGS_OFFSET)) {
335 case POSIX_LOCK_FLAG_NOWAIT:
336 blocking_lock = false;
337 break;
338 case POSIX_LOCK_FLAG_WAIT:
339 blocking_lock = true;
340 break;
341 default:
342 return NT_STATUS_INVALID_PARAMETER;
345 if (!lp_blocking_locks(SNUM(conn))) {
346 blocking_lock = False;
349 smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
350 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
351 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
352 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
353 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
355 DBG_DEBUG("file %s, lock_type = %u, smblctx = %"PRIu64", "
356 "count = %"PRIu64", offset = %"PRIu64"\n",
357 fsp_str_dbg(fsp),
358 (unsigned int)lock_type,
359 smblctx,
360 count,
361 offset);
363 if (lock_type == UNLOCK_LOCK) {
364 struct smbd_lock_element l = {
365 .req_guid = smbd_request_guid(req, 0),
366 .smblctx = smblctx,
367 .brltype = UNLOCK_LOCK,
368 .lock_flav = POSIX_LOCK,
369 .offset = offset,
370 .count = count,
372 status = smbd_do_unlocking(req, fsp, 1, &l);
373 return status;
376 lck = talloc(req, struct smbd_lock_element);
377 if (lck == NULL) {
378 return NT_STATUS_NO_MEMORY;
381 *lck = (struct smbd_lock_element) {
382 .req_guid = smbd_request_guid(req, 0),
383 .smblctx = smblctx,
384 .brltype = lock_type,
385 .lock_flav = POSIX_LOCK,
386 .count = count,
387 .offset = offset,
390 subreq = smbd_smb1_do_locks_send(
391 fsp,
392 req->sconn->ev_ctx,
393 &req,
394 fsp,
395 blocking_lock ? UINT32_MAX : 0,
396 true, /* large_offset */
398 lck);
399 if (subreq == NULL) {
400 TALLOC_FREE(lck);
401 return NT_STATUS_NO_MEMORY;
403 tevent_req_set_callback(subreq, smb_set_posix_lock_done, req);
404 return NT_STATUS_EVENT_PENDING;
407 static void smb_set_posix_lock_done(struct tevent_req *subreq)
409 struct smb_request *req = NULL;
410 NTSTATUS status;
411 bool ok;
413 ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
414 SMB_ASSERT(ok);
416 status = smbd_smb1_do_locks_recv(subreq);
417 TALLOC_FREE(subreq);
419 if (NT_STATUS_IS_OK(status)) {
420 char params[2] = {0};
421 /* Fake up max_data_bytes here - we know it fits. */
422 send_trans2_replies(
423 req->conn,
424 req,
425 NT_STATUS_OK,
426 params,
428 NULL,
430 0xffff);
431 } else {
432 reply_nterror(req, status);
433 ok = smb1_srv_send(req->xconn,
434 (char *)req->outbuf,
435 true,
436 req->seqnum + 1,
437 IS_CONN_ENCRYPTED(req->conn));
438 if (!ok) {
439 exit_server_cleanly("smb_set_posix_lock_done: "
440 "smb1_srv_send failed.");
444 TALLOC_FREE(req);
445 return;
448 /****************************************************************************
449 Read a list of EA names from an incoming data buffer. Create an ea_list with them.
450 ****************************************************************************/
452 static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
454 struct ea_list *ea_list_head = NULL;
455 size_t converted_size, offset = 0;
457 while (offset + 2 < data_size) {
458 struct ea_list *eal = talloc_zero(ctx, struct ea_list);
459 unsigned int namelen = CVAL(pdata,offset);
461 offset++; /* Go past the namelen byte. */
463 /* integer wrap paranioa. */
464 if ((offset + namelen < offset) || (offset + namelen < namelen) ||
465 (offset > data_size) || (namelen > data_size) ||
466 (offset + namelen >= data_size)) {
467 break;
469 /* Ensure the name is null terminated. */
470 if (pdata[offset + namelen] != '\0') {
471 return NULL;
473 if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
474 &converted_size)) {
475 DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
476 "failed: %s\n", strerror(errno)));
478 if (!eal->ea.name) {
479 return NULL;
482 offset += (namelen + 1); /* Go past the name + terminating zero. */
483 DLIST_ADD_END(ea_list_head, eal);
484 DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
487 return ea_list_head;
490 /****************************************************************************
491 Reply to a TRANSACT2_OPEN.
492 ****************************************************************************/
494 static void call_trans2open(connection_struct *conn,
495 struct smb_request *req,
496 char **pparams, int total_params,
497 char **ppdata, int total_data,
498 unsigned int max_data_bytes)
500 struct smb_filename *smb_fname = NULL;
501 char *params = *pparams;
502 char *pdata = *ppdata;
503 int deny_mode;
504 int32_t open_attr;
505 bool oplock_request;
506 #if 0
507 bool return_additional_info;
508 int16 open_sattr;
509 time_t open_time;
510 #endif
511 int open_ofun;
512 uint32_t open_size;
513 char *pname;
514 char *fname = NULL;
515 off_t size=0;
516 int fattr = 0;
517 SMB_INO_T inode = 0;
518 int smb_action = 0;
519 struct files_struct *dirfsp = NULL;
520 files_struct *fsp;
521 struct ea_list *ea_list = NULL;
522 uint16_t flags = 0;
523 NTSTATUS status;
524 uint32_t access_mask;
525 uint32_t share_mode;
526 uint32_t create_disposition;
527 uint32_t create_options = 0;
528 uint32_t private_flags = 0;
529 NTTIME twrp = 0;
530 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
531 TALLOC_CTX *ctx = talloc_tos();
534 * Ensure we have enough parameters to perform the operation.
537 if (total_params < 29) {
538 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
539 goto out;
542 flags = SVAL(params, 0);
543 deny_mode = SVAL(params, 2);
544 open_attr = SVAL(params,6);
545 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
546 if (oplock_request) {
547 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
550 #if 0
551 return_additional_info = BITSETW(params,0);
552 open_sattr = SVAL(params, 4);
553 open_time = make_unix_date3(params+8);
554 #endif
555 open_ofun = SVAL(params,12);
556 open_size = IVAL(params,14);
557 pname = &params[28];
559 if (IS_IPC(conn)) {
560 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
561 goto out;
564 if (req->posix_pathnames) {
565 srvstr_get_path_posix(ctx,
566 params,
567 req->flags2,
568 &fname,
569 pname,
570 total_params - 28,
571 STR_TERMINATE,
572 &status);
573 } else {
574 srvstr_get_path(ctx,
575 params,
576 req->flags2,
577 &fname,
578 pname,
579 total_params - 28,
580 STR_TERMINATE,
581 &status);
583 if (!NT_STATUS_IS_OK(status)) {
584 reply_nterror(req, status);
585 goto out;
588 DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
589 fname, (unsigned int)deny_mode, (unsigned int)open_attr,
590 (unsigned int)open_ofun, open_size));
592 if (ucf_flags & UCF_GMT_PATHNAME) {
593 extract_snapshot_token(fname, &twrp);
595 status = smb1_strip_dfs_path(ctx, &ucf_flags, &fname);
596 if (!NT_STATUS_IS_OK(status)) {
597 reply_nterror(req, status);
598 goto out;
600 status = filename_convert_dirfsp(ctx,
601 conn,
602 fname,
603 ucf_flags,
604 twrp,
605 &dirfsp,
606 &smb_fname);
607 if (!NT_STATUS_IS_OK(status)) {
608 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
609 reply_botherror(req,
610 NT_STATUS_PATH_NOT_COVERED,
611 ERRSRV, ERRbadpath);
612 goto out;
614 reply_nterror(req, status);
615 goto out;
618 if (open_ofun == 0) {
619 reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
620 goto out;
623 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
624 open_ofun,
625 &access_mask, &share_mode,
626 &create_disposition,
627 &create_options,
628 &private_flags)) {
629 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
630 goto out;
633 /* Any data in this call is an EA list. */
634 if (total_data && (total_data != 4)) {
635 if (total_data < 10) {
636 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
637 goto out;
640 if (IVAL(pdata,0) > total_data) {
641 DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
642 IVAL(pdata,0), (unsigned int)total_data));
643 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
644 goto out;
647 ea_list = read_ea_list(talloc_tos(), pdata + 4,
648 total_data - 4);
649 if (!ea_list) {
650 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
651 goto out;
654 if (!lp_ea_support(SNUM(conn))) {
655 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
656 goto out;
659 if (!req->posix_pathnames &&
660 ea_list_has_invalid_name(ea_list)) {
661 int param_len = 30;
662 *pparams = (char *)SMB_REALLOC(*pparams, param_len);
663 if(*pparams == NULL ) {
664 reply_nterror(req, NT_STATUS_NO_MEMORY);
665 goto out;
667 params = *pparams;
668 memset(params, '\0', param_len);
669 send_trans2_replies(conn, req, STATUS_INVALID_EA_NAME,
670 params, param_len, NULL, 0, max_data_bytes);
671 goto out;
675 status = SMB_VFS_CREATE_FILE(
676 conn, /* conn */
677 req, /* req */
678 dirfsp, /* dirfsp */
679 smb_fname, /* fname */
680 access_mask, /* access_mask */
681 share_mode, /* share_access */
682 create_disposition, /* create_disposition*/
683 create_options, /* create_options */
684 open_attr, /* file_attributes */
685 oplock_request, /* oplock_request */
686 NULL, /* lease */
687 open_size, /* allocation_size */
688 private_flags,
689 NULL, /* sd */
690 ea_list, /* ea_list */
691 &fsp, /* result */
692 &smb_action, /* psbuf */
693 NULL, NULL); /* create context */
695 if (!NT_STATUS_IS_OK(status)) {
696 if (open_was_deferred(req->xconn, req->mid)) {
697 /* We have re-scheduled this call. */
698 goto out;
701 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
702 reply_openerror(req, status);
703 goto out;
706 fsp = fcb_or_dos_open(
707 req,
708 smb_fname,
709 access_mask,
710 create_options,
711 private_flags);
712 if (fsp == NULL) {
713 bool ok = defer_smb1_sharing_violation(req);
714 if (ok) {
715 goto out;
717 reply_openerror(req, status);
718 goto out;
721 smb_action = FILE_WAS_OPENED;
724 size = get_file_size_stat(&smb_fname->st);
725 fattr = fdos_mode(fsp);
726 inode = smb_fname->st.st_ex_ino;
727 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
728 close_file_free(req, &fsp, ERROR_CLOSE);
729 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
730 goto out;
733 /* Realloc the size of parameters and data we will return */
734 *pparams = (char *)SMB_REALLOC(*pparams, 30);
735 if(*pparams == NULL ) {
736 reply_nterror(req, NT_STATUS_NO_MEMORY);
737 goto out;
739 params = *pparams;
741 SSVAL(params,0,fsp->fnum);
742 SSVAL(params,2,fattr);
743 srv_put_dos_date2_ts(params, 4, smb_fname->st.st_ex_mtime);
744 SIVAL(params,8, (uint32_t)size);
745 SSVAL(params,12,deny_mode);
746 SSVAL(params,14,0); /* open_type - file or directory. */
747 SSVAL(params,16,0); /* open_state - only valid for IPC device. */
749 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
750 smb_action |= EXTENDED_OPLOCK_GRANTED;
753 SSVAL(params,18,smb_action);
756 * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
758 SIVAL(params,20,inode);
759 SSVAL(params,24,0); /* Padding. */
760 if (flags & 8) {
761 uint32_t ea_size = estimate_ea_size(smb_fname->fsp);
762 SIVAL(params, 26, ea_size);
763 } else {
764 SIVAL(params, 26, 0);
767 /* Send the required number of replies */
768 send_trans2_replies(conn, req, NT_STATUS_OK, params, 30, *ppdata, 0, max_data_bytes);
769 out:
770 TALLOC_FREE(smb_fname);
773 static NTSTATUS get_lanman2_dir_entry(TALLOC_CTX *ctx,
774 connection_struct *conn,
775 struct dptr_struct *dirptr,
776 uint16_t flags2,
777 const char *path_mask,
778 uint32_t dirtype,
779 int info_level,
780 bool requires_resume_key,
781 bool dont_descend,
782 bool ask_sharemode,
783 char **ppdata,
784 char *base_data,
785 char *end_data,
786 int space_remaining,
787 int *last_entry_off,
788 struct ea_list *name_list)
790 uint8_t align = 4;
791 const bool do_pad = true;
793 if (info_level >= 1 && info_level <= 3) {
794 /* No alignment on earlier info levels. */
795 align = 1;
798 return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
799 path_mask, dirtype, info_level,
800 requires_resume_key, dont_descend, ask_sharemode,
801 true, align, do_pad,
802 ppdata, base_data, end_data,
803 space_remaining,
804 NULL,
805 last_entry_off, name_list, NULL);
808 /****************************************************************************
809 Reply to a TRANS2_FINDFIRST.
810 ****************************************************************************/
812 static void call_trans2findfirst(connection_struct *conn,
813 struct smb_request *req,
814 char **pparams, int total_params,
815 char **ppdata, int total_data,
816 unsigned int max_data_bytes)
818 /* We must be careful here that we don't return more than the
819 allowed number of data bytes. If this means returning fewer than
820 maxentries then so be it. We assume that the redirector has
821 enough room for the fixed number of parameter bytes it has
822 requested. */
823 struct smb_filename *smb_dname = NULL;
824 char *params = *pparams;
825 char *pdata = *ppdata;
826 char *data_end;
827 uint32_t dirtype;
828 int maxentries;
829 uint16_t findfirst_flags;
830 bool close_after_first;
831 bool close_if_end;
832 bool requires_resume_key;
833 int info_level;
834 char *directory = NULL;
835 char *mask = NULL;
836 char *p;
837 int last_entry_off=0;
838 int dptr_num = -1;
839 int numentries = 0;
840 int i;
841 bool finished = False;
842 bool dont_descend = False;
843 bool out_of_space = False;
844 int space_remaining;
845 struct ea_list *ea_list = NULL;
846 NTSTATUS ntstatus = NT_STATUS_OK;
847 bool ask_sharemode;
848 struct smbXsrv_connection *xconn = req->xconn;
849 struct smbd_server_connection *sconn = req->sconn;
850 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
851 bool backup_priv = false;
852 bool as_root = false;
853 files_struct *fsp = NULL;
854 struct files_struct *dirfsp = NULL;
855 const struct loadparm_substitution *lp_sub =
856 loadparm_s3_global_substitution();
858 if (total_params < 13) {
859 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
860 goto out;
863 dirtype = SVAL(params,0);
864 maxentries = SVAL(params,2);
865 findfirst_flags = SVAL(params,4);
866 close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
867 close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
868 requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
869 backup_priv = ((findfirst_flags & FLAG_TRANS2_FIND_BACKUP_INTENT) &&
870 security_token_has_privilege(get_current_nttok(conn),
871 SEC_PRIV_BACKUP));
873 info_level = SVAL(params,6);
875 DBG_NOTICE("dirtype = %"PRIx32", maxentries = %d, "
876 "close_after_first=%d, close_if_end = %d "
877 "requires_resume_key = %d backup_priv = %d level = 0x%x, "
878 "max_data_bytes = %d\n",
879 dirtype,
880 maxentries,
881 close_after_first,
882 close_if_end,
883 requires_resume_key,
884 backup_priv,
885 info_level,
886 max_data_bytes);
888 if (!maxentries) {
889 /* W2K3 seems to treat zero as 1. */
890 maxentries = 1;
893 switch (info_level) {
894 case SMB_FIND_INFO_STANDARD:
895 case SMB_FIND_EA_SIZE:
896 case SMB_FIND_EA_LIST:
897 case SMB_FIND_FILE_DIRECTORY_INFO:
898 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
899 case SMB_FIND_FILE_NAMES_INFO:
900 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
901 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
902 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
903 break;
904 case SMB_FIND_FILE_UNIX:
905 case SMB_FIND_FILE_UNIX_INFO2:
906 if (!lp_smb1_unix_extensions()) {
907 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
908 goto out;
910 if (!req->posix_pathnames) {
911 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
912 goto out;
914 break;
915 default:
916 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
917 goto out;
920 if (req->posix_pathnames) {
921 srvstr_get_path_posix(talloc_tos(),
922 params,
923 req->flags2,
924 &directory,
925 params+12,
926 total_params - 12,
927 STR_TERMINATE,
928 &ntstatus);
929 } else {
930 srvstr_get_path(talloc_tos(),
931 params,
932 req->flags2,
933 &directory,
934 params+12,
935 total_params - 12,
936 STR_TERMINATE,
937 &ntstatus);
939 if (!NT_STATUS_IS_OK(ntstatus)) {
940 reply_nterror(req, ntstatus);
941 goto out;
944 if (backup_priv) {
945 become_root();
946 as_root = true;
948 ntstatus = smb1_strip_dfs_path(talloc_tos(), &ucf_flags, &directory);
949 if (!NT_STATUS_IS_OK(ntstatus)) {
950 reply_nterror(req, ntstatus);
951 goto out;
954 ntstatus = filename_convert_smb1_search_path(talloc_tos(),
955 conn,
956 directory,
957 ucf_flags,
958 &dirfsp,
959 &smb_dname,
960 &mask);
962 if (!NT_STATUS_IS_OK(ntstatus)) {
963 if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
964 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
965 ERRSRV, ERRbadpath);
966 goto out;
968 reply_nterror(req, ntstatus);
969 goto out;
972 TALLOC_FREE(directory);
973 directory = smb_dname->base_name;
975 DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
977 if (info_level == SMB_FIND_EA_LIST) {
978 uint32_t ea_size;
980 if (total_data < 4) {
981 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
982 goto out;
985 ea_size = IVAL(pdata,0);
986 if (ea_size != total_data) {
987 DBG_NOTICE("Rejecting EA request with incorrect "
988 "total_data=%d (should be %" PRIu32 ")\n",
989 total_data,
990 ea_size);
991 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
992 goto out;
995 if (!lp_ea_support(SNUM(conn))) {
996 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
997 goto out;
1000 /* Pull out the list of names. */
1001 ea_list = read_ea_name_list(talloc_tos(), pdata + 4, ea_size - 4);
1002 if (!ea_list) {
1003 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1004 goto out;
1008 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
1009 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1010 goto out;
1013 *ppdata = (char *)SMB_REALLOC(
1014 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
1015 if(*ppdata == NULL ) {
1016 reply_nterror(req, NT_STATUS_NO_MEMORY);
1017 goto out;
1019 pdata = *ppdata;
1020 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
1022 * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
1023 * error.
1025 memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data));
1026 /* Realloc the params space */
1027 *pparams = (char *)SMB_REALLOC(*pparams, 10);
1028 if (*pparams == NULL) {
1029 reply_nterror(req, NT_STATUS_NO_MEMORY);
1030 goto out;
1032 params = *pparams;
1035 * Open an fsp on this directory for the dptr.
1037 ntstatus = SMB_VFS_CREATE_FILE(
1038 conn, /* conn */
1039 req, /* req */
1040 dirfsp, /* dirfsp */
1041 smb_dname, /* dname */
1042 FILE_LIST_DIRECTORY, /* access_mask */
1043 FILE_SHARE_READ|
1044 FILE_SHARE_WRITE, /* share_access */
1045 FILE_OPEN, /* create_disposition*/
1046 FILE_DIRECTORY_FILE, /* create_options */
1047 FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
1048 NO_OPLOCK, /* oplock_request */
1049 NULL, /* lease */
1050 0, /* allocation_size */
1051 0, /* private_flags */
1052 NULL, /* sd */
1053 NULL, /* ea_list */
1054 &fsp, /* result */
1055 NULL, /* pinfo */
1056 NULL, /* in_context */
1057 NULL);/* out_context */
1059 if (!NT_STATUS_IS_OK(ntstatus)) {
1060 DBG_ERR("failed to open directory %s\n",
1061 smb_fname_str_dbg(smb_dname));
1062 reply_nterror(req, ntstatus);
1063 goto out;
1066 /* Save the wildcard match and attribs we are using on this directory -
1067 needed as lanman2 assumes these are being saved between calls */
1069 ntstatus = dptr_create(conn,
1070 req,
1071 fsp, /* fsp */
1072 False,
1073 mask,
1074 dirtype,
1075 &fsp->dptr);
1077 if (!NT_STATUS_IS_OK(ntstatus)) {
1079 * Use NULL here for the first parameter (req)
1080 * as this is not a client visible handle so
1081 * can't be part of an SMB1 chain.
1083 close_file_free(NULL, &fsp, NORMAL_CLOSE);
1084 reply_nterror(req, ntstatus);
1085 goto out;
1088 if (backup_priv) {
1089 /* Remember this in case we have
1090 to do a findnext. */
1091 dptr_set_priv(fsp->dptr);
1094 dptr_num = dptr_dnum(fsp->dptr);
1095 DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
1097 /* We don't need to check for VOL here as this is returned by
1098 a different TRANS2 call. */
1100 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1101 directory,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn))));
1102 if (in_list(directory,
1103 lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
1104 dptr_case_sensitive(fsp->dptr))) {
1105 dont_descend = True;
1108 p = pdata;
1109 space_remaining = max_data_bytes;
1110 out_of_space = False;
1112 ask_sharemode = fsp_search_ask_sharemode(fsp);
1114 for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
1116 ntstatus = get_lanman2_dir_entry(talloc_tos(),
1117 conn,
1118 fsp->dptr,
1119 req->flags2,
1120 mask,
1121 dirtype,
1122 info_level,
1123 requires_resume_key,
1124 dont_descend,
1125 ask_sharemode,
1127 pdata,
1128 data_end,
1129 space_remaining,
1130 &last_entry_off,
1131 ea_list);
1132 if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_ILLEGAL_CHARACTER)) {
1134 * Bad character conversion on name. Ignore
1135 * this entry.
1137 continue;
1139 if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
1140 out_of_space = true;
1141 } else {
1142 finished = !NT_STATUS_IS_OK(ntstatus);
1145 if (!finished && !out_of_space) {
1146 numentries++;
1149 /* Ensure space_remaining never goes -ve. */
1150 if (PTR_DIFF(p,pdata) > max_data_bytes) {
1151 space_remaining = 0;
1152 out_of_space = true;
1153 } else {
1154 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
1158 /* Check if we can close the dirptr */
1159 if(close_after_first || (finished && close_if_end)) {
1160 DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
1161 dptr_num = -1;
1162 close_file_free(NULL, &fsp, NORMAL_CLOSE);
1166 * If there are no matching entries we must return ERRDOS/ERRbadfile -
1167 * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
1168 * the protocol level is less than NT1. Tested with smbclient. JRA.
1169 * This should fix the OS/2 client bug #2335.
1172 if(numentries == 0) {
1173 dptr_num = -1;
1175 * We may have already closed the file in the
1176 * close_after_first or finished case above.
1178 if (fsp != NULL) {
1179 close_file_free(NULL, &fsp, NORMAL_CLOSE);
1181 if (xconn->protocol < PROTOCOL_NT1) {
1182 reply_force_doserror(req, ERRDOS, ERRnofiles);
1183 goto out;
1184 } else {
1185 reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
1186 ERRDOS, ERRbadfile);
1187 goto out;
1191 /* At this point pdata points to numentries directory entries. */
1193 /* Set up the return parameter block */
1194 SSVAL(params,0,dptr_num);
1195 SSVAL(params,2,numentries);
1196 SSVAL(params,4,finished);
1197 SSVAL(params,6,0); /* Never an EA error */
1198 SSVAL(params,8,last_entry_off);
1200 send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
1201 max_data_bytes);
1203 if ((! *directory) && dptr_path(sconn, dptr_num)) {
1204 directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num));
1205 if (!directory) {
1206 reply_nterror(req, NT_STATUS_NO_MEMORY);
1210 DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
1211 smb_fn_name(req->cmd),
1212 mask, directory, dirtype, numentries ) );
1215 * Force a name mangle here to ensure that the
1216 * mask as an 8.3 name is top of the mangled cache.
1217 * The reasons for this are subtle. Don't remove
1218 * this code unless you know what you are doing
1219 * (see PR#13758). JRA.
1222 if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
1223 char mangled_name[13];
1224 name_to_8_3(mask, mangled_name, True, conn->params);
1226 out:
1228 if (as_root) {
1229 unbecome_root();
1232 TALLOC_FREE(smb_dname);
1233 return;
1236 static bool smbd_dptr_name_equal(struct dptr_struct *dptr,
1237 const char *name1,
1238 const char *name2)
1240 bool equal;
1242 if (dptr_case_sensitive(dptr)) {
1243 equal = (strcmp(name1, name2) == 0);
1244 } else {
1245 equal = strequal(name1, name2);
1248 return equal;
1251 /****************************************************************************
1252 Reply to a TRANS2_FINDNEXT.
1253 ****************************************************************************/
1255 static void call_trans2findnext(connection_struct *conn,
1256 struct smb_request *req,
1257 char **pparams, int total_params,
1258 char **ppdata, int total_data,
1259 unsigned int max_data_bytes)
1261 /* We must be careful here that we don't return more than the
1262 allowed number of data bytes. If this means returning fewer than
1263 maxentries then so be it. We assume that the redirector has
1264 enough room for the fixed number of parameter bytes it has
1265 requested. */
1266 char *params = *pparams;
1267 char *pdata = *ppdata;
1268 char *data_end;
1269 int dptr_num;
1270 int maxentries;
1271 uint16_t info_level;
1272 uint32_t resume_key;
1273 uint16_t findnext_flags;
1274 bool close_after_request;
1275 bool close_if_end;
1276 bool requires_resume_key;
1277 bool continue_bit;
1278 char *resume_name = NULL;
1279 const char *mask = NULL;
1280 const char *directory = NULL;
1281 char *p = NULL;
1282 uint16_t dirtype;
1283 int numentries = 0;
1284 int i, last_entry_off=0;
1285 bool finished = False;
1286 bool dont_descend = False;
1287 bool out_of_space = False;
1288 int space_remaining;
1289 struct ea_list *ea_list = NULL;
1290 NTSTATUS ntstatus = NT_STATUS_OK;
1291 bool ask_sharemode;
1292 TALLOC_CTX *ctx = talloc_tos();
1293 struct smbd_server_connection *sconn = req->sconn;
1294 bool backup_priv = false;
1295 bool as_root = false;
1296 files_struct *fsp = NULL;
1297 const struct loadparm_substitution *lp_sub =
1298 loadparm_s3_global_substitution();
1300 if (total_params < 13) {
1301 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1302 return;
1305 dptr_num = SVAL(params,0);
1306 maxentries = SVAL(params,2);
1307 info_level = SVAL(params,4);
1308 resume_key = IVAL(params,6);
1309 findnext_flags = SVAL(params,10);
1310 close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
1311 close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
1312 requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
1313 continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
1315 if (!continue_bit) {
1316 /* We only need resume_name if continue_bit is zero. */
1317 if (req->posix_pathnames) {
1318 srvstr_get_path_posix(ctx,
1319 params,
1320 req->flags2,
1321 &resume_name,
1322 params+12,
1323 total_params - 12,
1324 STR_TERMINATE,
1325 &ntstatus);
1326 } else {
1327 srvstr_get_path(ctx,
1328 params,
1329 req->flags2,
1330 &resume_name,
1331 params+12,
1332 total_params - 12,
1333 STR_TERMINATE,
1334 &ntstatus);
1336 if (!NT_STATUS_IS_OK(ntstatus)) {
1337 /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
1338 complain (it thinks we're asking for the directory above the shared
1339 path or an invalid name). Catch this as the resume name is only compared, never used in
1340 a file access. JRA. */
1341 srvstr_pull_talloc(ctx, params, req->flags2,
1342 &resume_name, params+12,
1343 total_params - 12,
1344 STR_TERMINATE);
1346 if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
1347 reply_nterror(req, ntstatus);
1348 return;
1353 DBG_NOTICE("dirhandle = %d, max_data_bytes = %u, maxentries = %d, "
1354 "close_after_request=%d, close_if_end = %d "
1355 "requires_resume_key = %d resume_key = %d "
1356 "resume name = %s continue=%d level = %d\n",
1357 dptr_num,
1358 max_data_bytes,
1359 maxentries,
1360 close_after_request,
1361 close_if_end,
1362 requires_resume_key,
1363 resume_key,
1364 resume_name ? resume_name : "(NULL)",
1365 continue_bit,
1366 info_level);
1368 if (!maxentries) {
1369 /* W2K3 seems to treat zero as 1. */
1370 maxentries = 1;
1373 switch (info_level) {
1374 case SMB_FIND_INFO_STANDARD:
1375 case SMB_FIND_EA_SIZE:
1376 case SMB_FIND_EA_LIST:
1377 case SMB_FIND_FILE_DIRECTORY_INFO:
1378 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1379 case SMB_FIND_FILE_NAMES_INFO:
1380 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1381 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1382 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1383 break;
1384 case SMB_FIND_FILE_UNIX:
1385 case SMB_FIND_FILE_UNIX_INFO2:
1386 if (!lp_smb1_unix_extensions()) {
1387 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1388 return;
1390 if (!req->posix_pathnames) {
1391 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1392 return;
1394 break;
1395 default:
1396 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1397 return;
1400 if (info_level == SMB_FIND_EA_LIST) {
1401 uint32_t ea_size;
1403 if (total_data < 4) {
1404 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1405 return;
1408 ea_size = IVAL(pdata,0);
1409 if (ea_size != total_data) {
1410 DBG_NOTICE("Rejecting EA request with incorrect "
1411 "total_data=%d (should be %" PRIu32 ")\n",
1412 total_data,
1413 ea_size);
1414 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1415 return;
1418 if (!lp_ea_support(SNUM(conn))) {
1419 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1420 return;
1423 /* Pull out the list of names. */
1424 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
1425 if (!ea_list) {
1426 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1427 return;
1431 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
1432 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1433 return;
1436 *ppdata = (char *)SMB_REALLOC(
1437 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
1438 if(*ppdata == NULL) {
1439 reply_nterror(req, NT_STATUS_NO_MEMORY);
1440 return;
1443 pdata = *ppdata;
1444 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
1447 * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
1448 * error.
1450 memset(pdata + total_data, 0, (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data);
1451 /* Realloc the params space */
1452 *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
1453 if(*pparams == NULL ) {
1454 reply_nterror(req, NT_STATUS_NO_MEMORY);
1455 return;
1458 params = *pparams;
1460 /* Check that the dptr is valid */
1461 fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
1462 if (fsp == NULL) {
1463 reply_nterror(req, STATUS_NO_MORE_FILES);
1464 return;
1467 directory = dptr_path(sconn, dptr_num);
1469 /* Get the wildcard mask from the dptr */
1470 if((mask = dptr_wcard(sconn, dptr_num))== NULL) {
1471 DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
1472 reply_nterror(req, STATUS_NO_MORE_FILES);
1473 return;
1476 /* Get the attr mask from the dptr */
1477 dirtype = dptr_attr(sconn, dptr_num);
1479 backup_priv = dptr_get_priv(fsp->dptr);
1481 DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX) "
1482 "backup_priv = %d\n",
1483 dptr_num, mask, dirtype,
1484 (long)fsp->dptr,
1485 (int)backup_priv));
1487 /* We don't need to check for VOL here as this is returned by
1488 a different TRANS2 call. */
1490 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1491 directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
1492 if (in_list(directory,lp_dont_descend(ctx, lp_sub, SNUM(conn)),
1493 dptr_case_sensitive(fsp->dptr)))
1494 dont_descend = True;
1496 p = pdata;
1497 space_remaining = max_data_bytes;
1498 out_of_space = False;
1500 if (backup_priv) {
1501 become_root();
1502 as_root = true;
1506 * Seek to the correct position. We no longer use the resume key but
1507 * depend on the last file name instead.
1510 if(!continue_bit && resume_name && *resume_name) {
1511 bool posix_open = fsp->fsp_flags.posix_open;
1512 char *last_name_sent = NULL;
1513 bool sequential;
1516 * Remember, name_to_8_3 is called by
1517 * get_lanman2_dir_entry(), so the resume name
1518 * could be mangled. Ensure we check the unmangled name.
1521 if (!posix_open &&
1522 mangle_is_mangled(resume_name, conn->params)) {
1523 char *new_resume_name = NULL;
1524 mangle_lookup_name_from_8_3(ctx,
1525 resume_name,
1526 &new_resume_name,
1527 conn->params);
1528 if (new_resume_name) {
1529 resume_name = new_resume_name;
1534 * Fix for NT redirector problem triggered by resume key indexes
1535 * changing between directory scans. We now return a resume key of 0
1536 * and instead look for the filename to continue from (also given
1537 * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
1538 * findfirst/findnext (as is usual) then the directory pointer
1539 * should already be at the correct place.
1542 last_name_sent = smbd_dirptr_get_last_name_sent(fsp->dptr);
1543 sequential = smbd_dptr_name_equal(fsp->dptr,
1544 resume_name,
1545 last_name_sent);
1546 if (!sequential) {
1547 char *name = NULL;
1548 bool found = false;
1550 dptr_RewindDir(fsp->dptr);
1552 while ((name = dptr_ReadDirName(talloc_tos(),
1553 fsp->dptr)) != NULL) {
1554 found = smbd_dptr_name_equal(fsp->dptr,
1555 resume_name,
1556 name);
1557 TALLOC_FREE(name);
1558 if (found) {
1559 break;
1563 if (!found) {
1565 * We got a name that used to exist
1566 * but does not anymore. Just start
1567 * from the beginning. Shown by the
1568 * "raw.search.os2 delete" smbtorture
1569 * test.
1571 dptr_RewindDir(fsp->dptr);
1574 } /* end if resume_name && !continue_bit */
1576 ask_sharemode = fsp_search_ask_sharemode(fsp);
1578 for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
1580 ntstatus = get_lanman2_dir_entry(ctx,
1581 conn,
1582 fsp->dptr,
1583 req->flags2,
1584 mask,
1585 dirtype,
1586 info_level,
1587 requires_resume_key,
1588 dont_descend,
1589 ask_sharemode,
1591 pdata,
1592 data_end,
1593 space_remaining,
1594 &last_entry_off,
1595 ea_list);
1596 if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_ILLEGAL_CHARACTER)) {
1598 * Bad character conversion on name. Ignore
1599 * this entry.
1601 continue;
1603 if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
1604 out_of_space = true;
1605 } else {
1606 finished = !NT_STATUS_IS_OK(ntstatus);
1609 if (!finished && !out_of_space) {
1610 numentries++;
1613 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
1616 DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
1617 smb_fn_name(req->cmd),
1618 mask, directory, dirtype, numentries ) );
1620 /* Check if we can close the fsp->dptr */
1621 if(close_after_request || (finished && close_if_end)) {
1622 DBG_INFO("closing dptr_num = %d\n", dptr_num);
1623 dptr_num = -1;
1624 close_file_free(NULL, &fsp, NORMAL_CLOSE);
1627 if (as_root) {
1628 unbecome_root();
1631 /* Set up the return parameter block */
1632 SSVAL(params,0,numentries);
1633 SSVAL(params,2,finished);
1634 SSVAL(params,4,0); /* Never an EA error */
1635 SSVAL(params,6,last_entry_off);
1637 send_trans2_replies(conn, req, NT_STATUS_OK, params, 8, pdata, PTR_DIFF(p,pdata),
1638 max_data_bytes);
1640 return;
1643 /****************************************************************************
1644 Reply to a TRANS2_QFSINFO (query filesystem info).
1645 ****************************************************************************/
1647 static void call_trans2qfsinfo(connection_struct *conn,
1648 struct smb_request *req,
1649 char **pparams, int total_params,
1650 char **ppdata, int total_data,
1651 unsigned int max_data_bytes)
1653 char *params = *pparams;
1654 uint16_t info_level;
1655 int data_len = 0;
1656 size_t fixed_portion;
1657 NTSTATUS status;
1659 if (total_params < 2) {
1660 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1661 return;
1664 info_level = SVAL(params,0);
1666 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
1667 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
1668 DEBUG(0,("call_trans2qfsinfo: encryption required "
1669 "and info level 0x%x sent.\n",
1670 (unsigned int)info_level));
1671 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1672 return;
1676 DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
1678 status = smbd_do_qfsinfo(req->xconn, conn, req,
1679 info_level,
1680 req->flags2,
1681 max_data_bytes,
1682 &fixed_portion,
1683 NULL,
1684 NULL,
1685 ppdata, &data_len);
1686 if (!NT_STATUS_IS_OK(status)) {
1687 reply_nterror(req, status);
1688 return;
1691 send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
1692 max_data_bytes);
1694 DEBUG( 4, ( "%s info_level = %d\n",
1695 smb_fn_name(req->cmd), info_level) );
1697 return;
1700 /****************************************************************************
1701 Reply to a TRANS2_SETFSINFO (set filesystem info).
1702 ****************************************************************************/
1704 static void call_trans2setfsinfo(connection_struct *conn,
1705 struct smb_request *req,
1706 char **pparams, int total_params,
1707 char **ppdata, int total_data,
1708 unsigned int max_data_bytes)
1710 const struct loadparm_substitution *lp_sub =
1711 loadparm_s3_global_substitution();
1712 struct smbXsrv_connection *xconn = req->xconn;
1713 char *pdata = *ppdata;
1714 char *params = *pparams;
1715 uint16_t info_level;
1717 DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
1718 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1720 /* */
1721 if (total_params < 4) {
1722 DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
1723 total_params));
1724 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1725 return;
1728 info_level = SVAL(params,2);
1730 if (IS_IPC(conn)) {
1731 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
1732 info_level != SMB_SET_CIFS_UNIX_INFO) {
1733 DEBUG(0,("call_trans2setfsinfo: not an allowed "
1734 "info level (0x%x) on IPC$.\n",
1735 (unsigned int)info_level));
1736 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1737 return;
1741 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
1742 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
1743 DEBUG(0,("call_trans2setfsinfo: encryption required "
1744 "and info level 0x%x sent.\n",
1745 (unsigned int)info_level));
1746 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1747 return;
1751 switch(info_level) {
1752 case SMB_SET_CIFS_UNIX_INFO:
1753 if (!lp_smb1_unix_extensions()) {
1754 DEBUG(2,("call_trans2setfsinfo: "
1755 "SMB_SET_CIFS_UNIX_INFO is invalid with "
1756 "unix extensions off\n"));
1757 reply_nterror(req,
1758 NT_STATUS_INVALID_LEVEL);
1759 return;
1762 /* There should be 12 bytes of capabilities set. */
1763 if (total_data < 12) {
1764 reply_nterror(
1765 req,
1766 NT_STATUS_INVALID_PARAMETER);
1767 return;
1769 xconn->smb1.unix_info.client_major = SVAL(pdata,0);
1770 xconn->smb1.unix_info.client_minor = SVAL(pdata,2);
1771 xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
1772 xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
1774 /* Just print these values for now. */
1775 DBG_DEBUG("set unix_info info. "
1776 "major = %"PRIu16", minor = %"PRIu16
1777 "cap_low = 0x%"PRIx32", "
1778 "cap_high = 0x%"PRIx32"\n",
1779 xconn->smb1.unix_info.client_major,
1780 xconn->smb1.unix_info.client_minor,
1781 xconn->smb1.unix_info.client_cap_low,
1782 xconn->smb1.unix_info.client_cap_high);
1785 * Here is where we must switch to posix
1786 * pathname processing...
1788 if (xconn->smb1.unix_info.client_cap_low &
1789 CIFS_UNIX_POSIX_PATHNAMES_CAP)
1791 lp_set_posix_pathnames();
1792 mangle_change_to_posix();
1795 if ((xconn->smb1.unix_info.client_cap_low &
1796 CIFS_UNIX_FCNTL_LOCKS_CAP) &&
1797 !(xconn->smb1.unix_info.client_cap_low &
1798 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP))
1800 /* Client that knows how to do posix locks,
1801 * but not posix open/mkdir operations. Set a
1802 * default type for read/write checks. */
1804 lp_set_posix_default_cifsx_readwrite_locktype(
1805 POSIX_LOCK);
1808 break;
1810 case SMB_REQUEST_TRANSPORT_ENCRYPTION:
1812 NTSTATUS status;
1813 size_t param_len = 0;
1814 size_t data_len = total_data;
1816 if (!lp_smb1_unix_extensions()) {
1817 reply_nterror(
1818 req,
1819 NT_STATUS_INVALID_LEVEL);
1820 return;
1823 if (lp_server_smb_encrypt(SNUM(conn)) ==
1824 SMB_ENCRYPTION_OFF) {
1825 reply_nterror(
1826 req,
1827 NT_STATUS_NOT_SUPPORTED);
1828 return;
1831 if (xconn->smb1.echo_handler.trusted_fde) {
1832 DEBUG( 2,("call_trans2setfsinfo: "
1833 "request transport encryption disabled"
1834 "with 'fork echo handler = yes'\n"));
1835 reply_nterror(
1836 req,
1837 NT_STATUS_NOT_SUPPORTED);
1838 return;
1841 DEBUG( 4,("call_trans2setfsinfo: "
1842 "request transport encryption.\n"));
1844 status = srv_request_encryption_setup(conn,
1845 (unsigned char **)ppdata,
1846 &data_len,
1847 (unsigned char **)pparams,
1848 &param_len);
1850 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
1851 !NT_STATUS_IS_OK(status)) {
1852 reply_nterror(req, status);
1853 return;
1856 send_trans2_replies(conn, req,
1857 NT_STATUS_OK,
1858 *pparams,
1859 param_len,
1860 *ppdata,
1861 data_len,
1862 max_data_bytes);
1864 if (NT_STATUS_IS_OK(status)) {
1865 /* Server-side transport
1866 * encryption is now *on*. */
1867 status = srv_encryption_start(conn);
1868 if (!NT_STATUS_IS_OK(status)) {
1869 char *reason = talloc_asprintf(talloc_tos(),
1870 "Failure in setting "
1871 "up encrypted transport: %s",
1872 nt_errstr(status));
1873 exit_server_cleanly(reason);
1876 return;
1879 case SMB_FS_QUOTA_INFORMATION:
1881 NTSTATUS status;
1882 DATA_BLOB qdata = {
1883 .data = (uint8_t *)pdata,
1884 .length = total_data
1886 files_struct *fsp = NULL;
1887 fsp = file_fsp(req, SVAL(params,0));
1889 status = smb_set_fsquota(conn,
1890 req,
1891 fsp,
1892 &qdata);
1893 if (!NT_STATUS_IS_OK(status)) {
1894 reply_nterror(req, status);
1895 return;
1897 break;
1899 default:
1900 DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
1901 info_level));
1902 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1903 return;
1904 break;
1908 * sending this reply works fine,
1909 * but I'm not sure it's the same
1910 * like windows do...
1911 * --metze
1913 reply_smb1_outbuf(req, 10, 0);
1916 /****************************************************************************
1917 Reply to a TRANSACT2_QFILEINFO on a PIPE !
1918 ****************************************************************************/
1920 static void call_trans2qpipeinfo(connection_struct *conn,
1921 struct smb_request *req,
1922 files_struct *fsp,
1923 uint16_t info_level,
1924 unsigned int tran_call,
1925 char **pparams, int total_params,
1926 char **ppdata, int total_data,
1927 unsigned int max_data_bytes)
1929 char *params = *pparams;
1930 char *pdata = *ppdata;
1931 unsigned int data_size = 0;
1932 unsigned int param_size = 2;
1934 if (!fsp_is_np(fsp)) {
1935 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1936 return;
1939 *pparams = (char *)SMB_REALLOC(*pparams,2);
1940 if (*pparams == NULL) {
1941 reply_nterror(req, NT_STATUS_NO_MEMORY);
1942 return;
1944 params = *pparams;
1945 SSVAL(params,0,0);
1946 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
1947 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1948 return;
1950 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
1951 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
1952 if (*ppdata == NULL ) {
1953 reply_nterror(req, NT_STATUS_NO_MEMORY);
1954 return;
1956 pdata = *ppdata;
1958 switch (info_level) {
1959 case SMB_FILE_STANDARD_INFORMATION:
1960 memset(pdata,0,24);
1961 SOFF_T(pdata,0,4096LL);
1962 SIVAL(pdata,16,1);
1963 SIVAL(pdata,20,1);
1964 data_size = 24;
1965 break;
1967 default:
1968 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
1969 return;
1972 send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
1973 max_data_bytes);
1976 static void handle_trans2qfilepathinfo_result(
1977 connection_struct *conn,
1978 struct smb_request *req,
1979 uint16_t info_level,
1980 NTSTATUS status,
1981 char *pdata,
1982 int data_return_size,
1983 size_t fixed_portion,
1984 unsigned int max_data_bytes)
1986 char params[2] = { 0, 0, };
1987 int param_size = 2;
1990 * draft-leach-cifs-v1-spec-02.txt
1991 * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
1992 * says:
1994 * The requested information is placed in the Data portion of the
1995 * transaction response. For the information levels greater than 0x100,
1996 * the transaction response has 1 parameter word which should be
1997 * ignored by the client.
1999 * However Windows only follows this rule for the IS_NAME_VALID call.
2001 switch (info_level) {
2002 case SMB_INFO_IS_NAME_VALID:
2003 param_size = 0;
2004 break;
2007 if (!NT_STATUS_IS_OK(status)) {
2008 if (open_was_deferred(req->xconn, req->mid)) {
2009 /* We have re-scheduled this call. */
2010 return;
2012 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
2013 bool ok = defer_smb1_sharing_violation(req);
2014 if (ok) {
2015 return;
2018 reply_nterror(req, status);
2019 return;
2022 if (fixed_portion > max_data_bytes) {
2023 reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
2024 return;
2027 send_trans2_replies(
2028 conn,
2029 req,
2030 NT_STATUS_OK,
2031 params,
2032 param_size,
2033 pdata,
2034 data_return_size,
2035 max_data_bytes);
2038 /****************************************************************************
2039 Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
2040 file name or file id).
2041 ****************************************************************************/
2043 static void call_trans2qfilepathinfo(connection_struct *conn,
2044 struct smb_request *req,
2045 unsigned int tran_call,
2046 uint16_t info_level,
2047 struct smb_filename *smb_fname,
2048 struct files_struct *fsp,
2049 bool delete_pending,
2050 struct timespec write_time_ts,
2051 char **pparams, int total_params,
2052 char **ppdata, int total_data,
2053 unsigned int max_data_bytes)
2055 char *params = *pparams;
2056 char *pdata = *ppdata;
2057 unsigned int data_size = 0;
2058 struct ea_list *ea_list = NULL;
2059 size_t fixed_portion;
2060 NTSTATUS status = NT_STATUS_OK;
2062 DEBUG(3,("call_trans2qfilepathinfo %s (%s) level=%d call=%d "
2063 "total_data=%d\n", smb_fname_str_dbg(smb_fname),
2064 fsp_fnum_dbg(fsp),
2065 info_level,tran_call,total_data));
2067 /* Pull out any data sent here before we realloc. */
2068 switch (info_level) {
2069 case SMB_INFO_QUERY_EAS_FROM_LIST:
2071 /* Pull any EA list from the data portion. */
2072 uint32_t ea_size;
2074 if (total_data < 4) {
2075 reply_nterror(
2076 req, NT_STATUS_INVALID_PARAMETER);
2077 return;
2079 ea_size = IVAL(pdata,0);
2081 if (total_data > 0 && ea_size != total_data) {
2082 DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
2083 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2084 reply_nterror(
2085 req, NT_STATUS_INVALID_PARAMETER);
2086 return;
2089 if (!lp_ea_support(SNUM(conn))) {
2090 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
2091 return;
2094 /* Pull out the list of names. */
2095 ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
2096 if (!ea_list) {
2097 reply_nterror(
2098 req, NT_STATUS_INVALID_PARAMETER);
2099 return;
2101 break;
2104 default:
2105 break;
2108 *pparams = (char *)SMB_REALLOC(*pparams,2);
2109 if (*pparams == NULL) {
2110 reply_nterror(req, NT_STATUS_NO_MEMORY);
2111 return;
2113 params = *pparams;
2114 SSVAL(params,0,0);
2116 if ((info_level & SMB2_INFO_SPECIAL) == SMB2_INFO_SPECIAL) {
2118 * We use levels that start with 0xFF00
2119 * internally to represent SMB2 specific levels
2121 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2122 return;
2125 status = smbd_do_qfilepathinfo(conn, req, req, info_level,
2126 fsp, smb_fname,
2127 delete_pending, write_time_ts,
2128 ea_list,
2129 req->flags2, max_data_bytes,
2130 &fixed_portion,
2131 ppdata, &data_size);
2133 handle_trans2qfilepathinfo_result(
2134 conn,
2135 req,
2136 info_level,
2137 status,
2138 *ppdata,
2139 data_size,
2140 fixed_portion,
2141 max_data_bytes);
2144 static NTSTATUS smb_q_unix_basic(
2145 struct connection_struct *conn,
2146 struct smb_request *req,
2147 struct smb_filename *smb_fname,
2148 struct files_struct *fsp,
2149 char **ppdata,
2150 int *ptotal_data)
2152 const int total_data = 100;
2154 *ppdata = SMB_REALLOC(*ppdata, total_data);
2155 if (*ppdata == NULL) {
2156 return NT_STATUS_NO_MEMORY;
2158 store_file_unix_basic(conn, *ppdata, fsp, &smb_fname->st);
2160 *ptotal_data = total_data;
2162 return NT_STATUS_OK;
2165 static NTSTATUS smb_q_unix_info2(
2166 struct connection_struct *conn,
2167 struct smb_request *req,
2168 struct smb_filename *smb_fname,
2169 struct files_struct *fsp,
2170 char **ppdata,
2171 int *ptotal_data)
2173 const int total_data = 116;
2175 *ppdata = SMB_REALLOC(*ppdata, total_data);
2176 if (*ppdata == NULL) {
2177 return NT_STATUS_NO_MEMORY;
2179 store_file_unix_basic_info2(conn, *ppdata, fsp, &smb_fname->st);
2181 *ptotal_data = total_data;
2183 return NT_STATUS_OK;
2186 #if defined(HAVE_POSIX_ACLS)
2187 /****************************************************************************
2188 Utility function to open a fsp for a POSIX handle operation.
2189 ****************************************************************************/
2191 static NTSTATUS get_posix_fsp(connection_struct *conn,
2192 struct smb_request *req,
2193 struct smb_filename *smb_fname,
2194 uint32_t access_mask,
2195 files_struct **ret_fsp)
2197 NTSTATUS status;
2198 uint32_t create_disposition = FILE_OPEN;
2199 uint32_t share_access = FILE_SHARE_READ|
2200 FILE_SHARE_WRITE|
2201 FILE_SHARE_DELETE;
2202 struct smb2_create_blobs *posx = NULL;
2205 * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
2206 * but set reasonable defaults.
2208 uint32_t file_attributes = 0664;
2209 uint32_t oplock = NO_OPLOCK;
2210 uint32_t create_options = FILE_NON_DIRECTORY_FILE;
2212 /* File or directory must exist. */
2213 if (!VALID_STAT(smb_fname->st)) {
2214 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2216 /* Cannot be a symlink. */
2217 if (S_ISLNK(smb_fname->st.st_ex_mode)) {
2218 return NT_STATUS_ACCESS_DENIED;
2220 /* Set options correctly for directory open. */
2221 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
2223 * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
2224 * directories, but set reasonable defaults.
2226 file_attributes = 0775;
2227 create_options = FILE_DIRECTORY_FILE;
2230 status = make_smb2_posix_create_ctx(
2231 talloc_tos(), &posx, file_attributes);
2232 if (!NT_STATUS_IS_OK(status)) {
2233 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
2234 nt_errstr(status));
2235 goto done;
2238 status = SMB_VFS_CREATE_FILE(
2239 conn, /* conn */
2240 req, /* req */
2241 NULL, /* dirfsp */
2242 smb_fname, /* fname */
2243 access_mask, /* access_mask */
2244 share_access, /* share_access */
2245 create_disposition,/* create_disposition*/
2246 create_options, /* create_options */
2247 file_attributes,/* file_attributes */
2248 oplock, /* oplock_request */
2249 NULL, /* lease */
2250 0, /* allocation_size */
2251 0, /* private_flags */
2252 NULL, /* sd */
2253 NULL, /* ea_list */
2254 ret_fsp, /* result */
2255 NULL, /* pinfo */
2256 posx, /* in_context */
2257 NULL); /* out_context */
2259 done:
2260 TALLOC_FREE(posx);
2261 return status;
2264 /****************************************************************************
2265 Utility function to count the number of entries in a POSIX acl.
2266 ****************************************************************************/
2268 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
2270 unsigned int ace_count = 0;
2271 int entry_id = SMB_ACL_FIRST_ENTRY;
2272 SMB_ACL_ENTRY_T entry;
2274 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2275 entry_id = SMB_ACL_NEXT_ENTRY;
2276 ace_count++;
2278 return ace_count;
2281 /****************************************************************************
2282 Utility function to marshall a POSIX acl into wire format.
2283 ****************************************************************************/
2285 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
2287 int entry_id = SMB_ACL_FIRST_ENTRY;
2288 SMB_ACL_ENTRY_T entry;
2290 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2291 SMB_ACL_TAG_T tagtype;
2292 SMB_ACL_PERMSET_T permset;
2293 unsigned char perms = 0;
2294 unsigned int own_grp;
2296 entry_id = SMB_ACL_NEXT_ENTRY;
2298 if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
2299 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
2300 return False;
2303 if (sys_acl_get_permset(entry, &permset) == -1) {
2304 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
2305 return False;
2308 perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
2309 perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
2310 perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
2312 SCVAL(pdata,1,perms);
2314 switch (tagtype) {
2315 case SMB_ACL_USER_OBJ:
2316 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
2317 own_grp = (unsigned int)pst->st_ex_uid;
2318 SIVAL(pdata,2,own_grp);
2319 SIVAL(pdata,6,0);
2320 break;
2321 case SMB_ACL_USER:
2323 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2324 if (!puid) {
2325 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2326 return False;
2328 own_grp = (unsigned int)*puid;
2329 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
2330 SIVAL(pdata,2,own_grp);
2331 SIVAL(pdata,6,0);
2332 break;
2334 case SMB_ACL_GROUP_OBJ:
2335 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
2336 own_grp = (unsigned int)pst->st_ex_gid;
2337 SIVAL(pdata,2,own_grp);
2338 SIVAL(pdata,6,0);
2339 break;
2340 case SMB_ACL_GROUP:
2342 gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
2343 if (!pgid) {
2344 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2345 return False;
2347 own_grp = (unsigned int)*pgid;
2348 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
2349 SIVAL(pdata,2,own_grp);
2350 SIVAL(pdata,6,0);
2351 break;
2353 case SMB_ACL_MASK:
2354 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
2355 SIVAL(pdata,2,0xFFFFFFFF);
2356 SIVAL(pdata,6,0xFFFFFFFF);
2357 break;
2358 case SMB_ACL_OTHER:
2359 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
2360 SIVAL(pdata,2,0xFFFFFFFF);
2361 SIVAL(pdata,6,0xFFFFFFFF);
2362 break;
2363 default:
2364 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
2365 return False;
2367 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
2370 return True;
2372 #endif
2374 static NTSTATUS smb_q_posix_acl(
2375 struct connection_struct *conn,
2376 struct smb_request *req,
2377 struct smb_filename *smb_fname,
2378 struct files_struct *fsp,
2379 char **ppdata,
2380 int *ptotal_data)
2382 #if !defined(HAVE_POSIX_ACLS)
2383 return NT_STATUS_INVALID_LEVEL;
2384 #else
2385 char *pdata = NULL;
2386 SMB_ACL_T file_acl = NULL;
2387 SMB_ACL_T def_acl = NULL;
2388 uint16_t num_file_acls = 0;
2389 uint16_t num_def_acls = 0;
2390 unsigned int size_needed = 0;
2391 NTSTATUS status;
2392 bool ok;
2393 bool close_fsp = false;
2396 * Ensure we always operate on a file descriptor, not just
2397 * the filename.
2399 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
2400 uint32_t access_mask = SEC_STD_READ_CONTROL|
2401 FILE_READ_ATTRIBUTES|
2402 FILE_WRITE_ATTRIBUTES;
2404 status = get_posix_fsp(conn,
2405 req,
2406 smb_fname,
2407 access_mask,
2408 &fsp);
2410 if (!NT_STATUS_IS_OK(status)) {
2411 goto out;
2413 close_fsp = true;
2416 SMB_ASSERT(fsp != NULL);
2418 status = refuse_symlink_fsp(fsp);
2419 if (!NT_STATUS_IS_OK(status)) {
2420 goto out;
2423 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, SMB_ACL_TYPE_ACCESS,
2424 talloc_tos());
2426 if (file_acl == NULL && no_acl_syscall_error(errno)) {
2427 DBG_INFO("ACLs not implemented on "
2428 "filesystem containing %s\n",
2429 fsp_str_dbg(fsp));
2430 status = NT_STATUS_NOT_IMPLEMENTED;
2431 goto out;
2434 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2436 * We can only have default POSIX ACLs on
2437 * directories.
2439 if (!fsp->fsp_flags.is_directory) {
2440 DBG_INFO("Non-directory open %s\n",
2441 fsp_str_dbg(fsp));
2442 status = NT_STATUS_INVALID_HANDLE;
2443 goto out;
2445 def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
2446 SMB_ACL_TYPE_DEFAULT,
2447 talloc_tos());
2448 def_acl = free_empty_sys_acl(conn, def_acl);
2451 num_file_acls = count_acl_entries(conn, file_acl);
2452 num_def_acls = count_acl_entries(conn, def_acl);
2454 /* Wrap checks. */
2455 if (num_file_acls + num_def_acls < num_file_acls) {
2456 status = NT_STATUS_INVALID_PARAMETER;
2457 goto out;
2460 size_needed = num_file_acls + num_def_acls;
2463 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
2464 * than UINT_MAX, so check by division.
2466 if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
2467 status = NT_STATUS_INVALID_PARAMETER;
2468 goto out;
2471 size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
2472 if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
2473 status = NT_STATUS_INVALID_PARAMETER;
2474 goto out;
2476 size_needed += SMB_POSIX_ACL_HEADER_SIZE;
2478 *ppdata = SMB_REALLOC(*ppdata, size_needed);
2479 if (*ppdata == NULL) {
2480 status = NT_STATUS_NO_MEMORY;
2481 goto out;
2483 pdata = *ppdata;
2485 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
2486 SSVAL(pdata,2,num_file_acls);
2487 SSVAL(pdata,4,num_def_acls);
2488 pdata += SMB_POSIX_ACL_HEADER_SIZE;
2490 ok = marshall_posix_acl(conn,
2491 pdata,
2492 &fsp->fsp_name->st,
2493 file_acl);
2494 if (!ok) {
2495 status = NT_STATUS_INTERNAL_ERROR;
2496 goto out;
2498 pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
2500 ok = marshall_posix_acl(conn,
2501 pdata,
2502 &fsp->fsp_name->st,
2503 def_acl);
2504 if (!ok) {
2505 status = NT_STATUS_INTERNAL_ERROR;
2506 goto out;
2509 *ptotal_data = size_needed;
2510 status = NT_STATUS_OK;
2512 out:
2514 if (close_fsp) {
2516 * Ensure the stat struct in smb_fname is up to
2517 * date. Structure copy.
2519 smb_fname->st = fsp->fsp_name->st;
2520 (void)close_file_free(req, &fsp, NORMAL_CLOSE);
2523 TALLOC_FREE(file_acl);
2524 TALLOC_FREE(def_acl);
2525 return status;
2526 #endif
2529 static NTSTATUS smb_q_posix_symlink(
2530 struct connection_struct *conn,
2531 struct smb_request *req,
2532 struct files_struct *dirfsp,
2533 struct smb_filename *smb_fname,
2534 char **ppdata,
2535 int *ptotal_data)
2537 char *target = NULL;
2538 size_t needed, len;
2539 char *pdata = NULL;
2540 NTSTATUS status;
2542 DBG_DEBUG("SMB_QUERY_FILE_UNIX_LINK for file %s\n",
2543 smb_fname_str_dbg(smb_fname));
2545 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
2546 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
2549 if (fsp_get_pathref_fd(smb_fname->fsp) != -1) {
2551 * fsp is an O_PATH open, Linux does a "freadlink"
2552 * with an empty name argument to readlinkat
2554 status = readlink_talloc(talloc_tos(),
2555 smb_fname->fsp,
2556 NULL,
2557 &target);
2558 } else {
2559 struct smb_filename smb_fname_rel = *smb_fname;
2560 char *slash = NULL;
2562 slash = strrchr_m(smb_fname->base_name, '/');
2563 if (slash != NULL) {
2564 smb_fname_rel.base_name = slash + 1;
2566 status = readlink_talloc(talloc_tos(),
2567 dirfsp,
2568 &smb_fname_rel,
2569 &target);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 DBG_DEBUG("readlink_talloc() failed: %s\n", nt_errstr(status));
2574 return status;
2577 needed = talloc_get_size(target) * 2;
2579 *ppdata = SMB_REALLOC(*ppdata, needed);
2580 if (*ppdata == NULL) {
2581 TALLOC_FREE(target);
2582 return NT_STATUS_NO_MEMORY;
2584 pdata = *ppdata;
2586 status = srvstr_push(
2587 pdata,
2588 req->flags2,
2589 pdata,
2590 target,
2591 needed,
2592 STR_TERMINATE,
2593 &len);
2594 TALLOC_FREE(target);
2595 if (!NT_STATUS_IS_OK(status)) {
2596 return status;
2598 *ptotal_data = len;
2600 return NT_STATUS_OK;
2603 static void call_trans2qpathinfo(
2604 connection_struct *conn,
2605 struct smb_request *req,
2606 char **pparams,
2607 int total_params,
2608 char **ppdata,
2609 int total_data,
2610 unsigned int max_data_bytes)
2612 char *params = *pparams;
2613 uint16_t info_level;
2614 struct smb_filename *smb_fname = NULL;
2615 bool delete_pending = False;
2616 struct timespec write_time_ts = { .tv_sec = 0, };
2617 struct files_struct *dirfsp = NULL;
2618 files_struct *fsp = NULL;
2619 char *fname = NULL;
2620 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
2621 NTTIME twrp = 0;
2622 bool info_level_handled;
2623 NTSTATUS status = NT_STATUS_OK;
2625 if (!params) {
2626 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2627 return;
2631 /* qpathinfo */
2632 if (total_params < 7) {
2633 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2634 return;
2637 info_level = SVAL(params,0);
2639 DBG_NOTICE("TRANSACT2_QPATHINFO: level = %d\n", info_level);
2641 if (INFO_LEVEL_IS_UNIX(info_level)) {
2642 if (!lp_smb1_unix_extensions()) {
2643 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2644 return;
2646 if (!req->posix_pathnames) {
2647 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2648 return;
2652 if (req->posix_pathnames) {
2653 srvstr_get_path_posix(req,
2654 params,
2655 req->flags2,
2656 &fname,
2657 &params[6],
2658 total_params - 6,
2659 STR_TERMINATE,
2660 &status);
2661 } else {
2662 srvstr_get_path(req,
2663 params,
2664 req->flags2,
2665 &fname,
2666 &params[6],
2667 total_params - 6,
2668 STR_TERMINATE,
2669 &status);
2671 if (!NT_STATUS_IS_OK(status)) {
2672 reply_nterror(req, status);
2673 return;
2676 if (ucf_flags & UCF_GMT_PATHNAME) {
2677 extract_snapshot_token(fname, &twrp);
2679 status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
2680 if (!NT_STATUS_IS_OK(status)) {
2681 reply_nterror(req, status);
2682 return;
2684 status = filename_convert_dirfsp(req,
2685 conn,
2686 fname,
2687 ucf_flags,
2688 twrp,
2689 &dirfsp,
2690 &smb_fname);
2691 if (!NT_STATUS_IS_OK(status)) {
2692 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2693 reply_botherror(req,
2694 NT_STATUS_PATH_NOT_COVERED,
2695 ERRSRV, ERRbadpath);
2696 return;
2698 reply_nterror(req, status);
2699 return;
2703 * qpathinfo must operate on an existing file, so we
2704 * can exit early if filename_convert_dirfsp() returned the
2705 * "new file" NT_STATUS_OK, !VALID_STAT case.
2708 if (!VALID_STAT(smb_fname->st)) {
2709 reply_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
2710 return;
2713 fsp = smb_fname->fsp;
2715 /* If this is a stream, check if there is a delete_pending. */
2716 if (fsp_is_alternate_stream(fsp)) {
2718 struct files_struct *base_fsp = fsp->base_fsp;
2720 get_file_infos(base_fsp->file_id,
2721 base_fsp->name_hash,
2722 &delete_pending,
2723 NULL);
2724 if (delete_pending) {
2725 reply_nterror(req, NT_STATUS_DELETE_PENDING);
2726 return;
2730 if (fsp_getinfo_ask_sharemode(fsp)) {
2731 get_file_infos(fsp->file_id,
2732 fsp->name_hash,
2733 &delete_pending,
2734 &write_time_ts);
2737 if (delete_pending) {
2738 reply_nterror(req, NT_STATUS_DELETE_PENDING);
2739 return;
2742 info_level_handled = true; /* Untouched in switch cases below */
2744 switch (info_level) {
2746 default:
2747 info_level_handled = false;
2748 break;
2750 case SMB_QUERY_FILE_UNIX_BASIC:
2751 status = smb_q_unix_basic(
2752 conn,
2753 req,
2754 smb_fname,
2755 smb_fname->fsp,
2756 ppdata,
2757 &total_data);
2758 break;
2760 case SMB_QUERY_FILE_UNIX_INFO2:
2761 status = smb_q_unix_info2(
2762 conn,
2763 req,
2764 smb_fname,
2765 smb_fname->fsp,
2766 ppdata,
2767 &total_data);
2768 break;
2770 case SMB_QUERY_POSIX_ACL:
2771 status = smb_q_posix_acl(
2772 conn,
2773 req,
2774 smb_fname,
2775 smb_fname->fsp,
2776 ppdata,
2777 &total_data);
2778 break;
2780 case SMB_QUERY_FILE_UNIX_LINK:
2781 status = smb_q_posix_symlink(
2782 conn,
2783 req,
2784 dirfsp,
2785 smb_fname,
2786 ppdata,
2787 &total_data);
2788 break;
2791 if (info_level_handled) {
2792 handle_trans2qfilepathinfo_result(
2793 conn,
2794 req,
2795 info_level,
2796 status,
2797 *ppdata,
2798 total_data,
2799 total_data,
2800 max_data_bytes);
2801 return;
2804 call_trans2qfilepathinfo(
2805 conn,
2806 req,
2807 TRANSACT2_QPATHINFO,
2808 info_level,
2809 smb_fname,
2810 fsp,
2811 false,
2812 write_time_ts,
2813 pparams,
2814 total_params,
2815 ppdata,
2816 total_data,
2817 max_data_bytes);
2820 static NTSTATUS smb_q_posix_lock(
2821 struct connection_struct *conn,
2822 struct smb_request *req,
2823 struct files_struct *fsp,
2824 char **ppdata,
2825 int *ptotal_data)
2827 char *pdata = *ppdata;
2828 int total_data = *ptotal_data;
2829 uint64_t count;
2830 uint64_t offset;
2831 uint64_t smblctx;
2832 enum brl_type lock_type;
2833 NTSTATUS status;
2835 if (fsp->fsp_flags.is_pathref || (fsp_get_io_fd(fsp) == -1)) {
2836 return NT_STATUS_INVALID_HANDLE;
2839 if (total_data != POSIX_LOCK_DATA_SIZE) {
2840 return NT_STATUS_INVALID_PARAMETER;
2843 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
2844 case POSIX_LOCK_TYPE_READ:
2845 lock_type = READ_LOCK;
2846 break;
2847 case POSIX_LOCK_TYPE_WRITE:
2848 lock_type = WRITE_LOCK;
2849 break;
2850 case POSIX_LOCK_TYPE_UNLOCK:
2851 default:
2852 /* There's no point in asking for an unlock... */
2853 return NT_STATUS_INVALID_PARAMETER;
2856 smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
2857 offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
2858 count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
2860 status = query_lock(
2861 fsp,
2862 &smblctx,
2863 &count,
2864 &offset,
2865 &lock_type,
2866 POSIX_LOCK);
2868 if (NT_STATUS_IS_OK(status)) {
2870 * For success we just return a copy of what we sent
2871 * with the lock type set to POSIX_LOCK_TYPE_UNLOCK.
2873 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
2874 return NT_STATUS_OK;
2877 if (!ERROR_WAS_LOCK_DENIED(status)) {
2878 DBG_DEBUG("query_lock() failed: %s\n", nt_errstr(status));
2879 return status;
2883 * Here we need to report who has it locked.
2886 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
2887 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
2888 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
2889 SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
2890 SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
2892 return NT_STATUS_OK;
2895 static void call_trans2qfileinfo(
2896 connection_struct *conn,
2897 struct smb_request *req,
2898 char **pparams,
2899 int total_params,
2900 char **ppdata,
2901 int total_data,
2902 unsigned int max_data_bytes)
2904 char *params = *pparams;
2905 uint16_t info_level;
2906 struct smb_filename *smb_fname = NULL;
2907 bool delete_pending = False;
2908 struct timespec write_time_ts = { .tv_sec = 0, };
2909 files_struct *fsp = NULL;
2910 struct file_id fileid;
2911 bool info_level_handled;
2912 NTSTATUS status = NT_STATUS_OK;
2913 int ret;
2915 if (params == NULL) {
2916 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2917 return;
2920 if (total_params < 4) {
2921 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2922 return;
2925 fsp = file_fsp(req, SVAL(params,0));
2926 info_level = SVAL(params,2);
2928 if (IS_IPC(conn)) {
2929 call_trans2qpipeinfo(
2930 conn,
2931 req,
2932 fsp,
2933 info_level,
2934 TRANSACT2_QFILEINFO,
2935 pparams,
2936 total_params,
2937 ppdata,
2938 total_data,
2939 max_data_bytes);
2940 return;
2943 DBG_NOTICE("TRANSACT2_QFILEINFO: level = %d\n", info_level);
2945 if (INFO_LEVEL_IS_UNIX(info_level)) {
2946 if (!lp_smb1_unix_extensions()) {
2947 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2948 return;
2950 if (!req->posix_pathnames) {
2951 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2952 return;
2956 /* Initial check for valid fsp ptr. */
2957 if (!check_fsp_open(conn, req, fsp)) {
2958 return;
2961 smb_fname = fsp->fsp_name;
2963 if(fsp->fake_file_handle) {
2965 * This is actually for the QUOTA_FAKE_FILE --metze
2968 /* We know this name is ok, it's already passed the checks. */
2970 } else if(fsp_get_pathref_fd(fsp) == -1) {
2972 * This is actually a QFILEINFO on a directory
2973 * handle (returned from an NT SMB). NT5.0 seems
2974 * to do this call. JRA.
2976 ret = vfs_stat(conn, smb_fname);
2977 if (ret != 0) {
2978 DBG_NOTICE("vfs_stat of %s failed (%s)\n",
2979 smb_fname_str_dbg(smb_fname),
2980 strerror(errno));
2981 reply_nterror(req,
2982 map_nt_error_from_unix(errno));
2983 return;
2986 if (fsp_getinfo_ask_sharemode(fsp)) {
2987 fileid = vfs_file_id_from_sbuf(
2988 conn, &smb_fname->st);
2989 get_file_infos(fileid, fsp->name_hash,
2990 &delete_pending,
2991 &write_time_ts);
2993 } else {
2995 * Original code - this is an open file.
2997 status = vfs_stat_fsp(fsp);
2998 if (!NT_STATUS_IS_OK(status)) {
2999 DEBUG(3, ("fstat of %s failed (%s)\n",
3000 fsp_fnum_dbg(fsp), nt_errstr(status)));
3001 reply_nterror(req, status);
3002 return;
3004 if (fsp_getinfo_ask_sharemode(fsp)) {
3005 fileid = vfs_file_id_from_sbuf(
3006 conn, &smb_fname->st);
3007 get_file_infos(fileid, fsp->name_hash,
3008 &delete_pending,
3009 &write_time_ts);
3013 info_level_handled = true; /* Untouched in switch cases below */
3015 switch (info_level) {
3017 default:
3018 info_level_handled = false;
3019 break;
3021 case SMB_QUERY_POSIX_LOCK:
3022 status = smb_q_posix_lock(conn, req, fsp, ppdata, &total_data);
3023 break;
3025 case SMB_QUERY_FILE_UNIX_BASIC:
3026 status = smb_q_unix_basic(
3027 conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3028 break;
3030 case SMB_QUERY_FILE_UNIX_INFO2:
3031 status = smb_q_unix_info2(
3032 conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3033 break;
3035 case SMB_QUERY_POSIX_ACL:
3036 status = smb_q_posix_acl(
3037 conn, req, fsp->fsp_name, fsp, ppdata, &total_data);
3038 break;
3041 if (info_level_handled) {
3042 handle_trans2qfilepathinfo_result(
3043 conn,
3044 req,
3045 info_level,
3046 status,
3047 *ppdata,
3048 total_data,
3049 total_data,
3050 max_data_bytes);
3051 return;
3054 call_trans2qfilepathinfo(
3055 conn,
3056 req,
3057 TRANSACT2_QFILEINFO,
3058 info_level,
3059 smb_fname,
3060 fsp,
3061 delete_pending,
3062 write_time_ts,
3063 pparams,
3064 total_params,
3065 ppdata,
3066 total_data,
3067 max_data_bytes);
3070 static void handle_trans2setfilepathinfo_result(
3071 connection_struct *conn,
3072 struct smb_request *req,
3073 uint16_t info_level,
3074 NTSTATUS status,
3075 char *pdata,
3076 int data_return_size,
3077 unsigned int max_data_bytes)
3079 char params[2] = { 0, 0, };
3081 if (NT_STATUS_IS_OK(status)) {
3082 send_trans2_replies(
3083 conn,
3084 req,
3085 NT_STATUS_OK,
3086 params,
3088 pdata,
3089 data_return_size,
3090 max_data_bytes);
3091 return;
3094 if (open_was_deferred(req->xconn, req->mid)) {
3095 /* We have re-scheduled this call. */
3096 return;
3099 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
3100 bool ok = defer_smb1_sharing_violation(req);
3101 if (ok) {
3102 return;
3106 if (NT_STATUS_EQUAL(status, NT_STATUS_EVENT_PENDING)) {
3107 /* We have re-scheduled this call. */
3108 return;
3111 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3112 reply_botherror(
3113 req,
3114 NT_STATUS_PATH_NOT_COVERED,
3115 ERRSRV,
3116 ERRbadpath);
3117 return;
3120 if (info_level == SMB_POSIX_PATH_OPEN) {
3121 reply_openerror(req, status);
3122 return;
3125 if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
3127 * Invalid EA name needs to return 2 param bytes,
3128 * not a zero-length error packet.
3131 send_trans2_replies(
3132 conn,
3133 req,
3134 status,
3135 params,
3137 NULL,
3139 max_data_bytes);
3140 return;
3143 reply_nterror(req, status);
3146 /****************************************************************************
3147 Create a directory with POSIX semantics.
3148 ****************************************************************************/
3150 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
3151 struct smb_request *req,
3152 char **ppdata,
3153 int total_data,
3154 struct smb_filename *smb_fname,
3155 int *pdata_return_size)
3157 NTSTATUS status = NT_STATUS_OK;
3158 uint32_t raw_unixmode = 0;
3159 mode_t unixmode = (mode_t)0;
3160 files_struct *fsp = NULL;
3161 uint16_t info_level_return = 0;
3162 int info;
3163 char *pdata = *ppdata;
3164 struct smb2_create_blobs *posx = NULL;
3166 if (total_data < 18) {
3167 return NT_STATUS_INVALID_PARAMETER;
3170 raw_unixmode = IVAL(pdata,8);
3171 /* Next 4 bytes are not yet defined. */
3173 status = unix_perms_from_wire(conn,
3174 &smb_fname->st,
3175 raw_unixmode,
3176 &unixmode);
3177 if (!NT_STATUS_IS_OK(status)) {
3178 return status;
3180 unixmode = apply_conf_dir_mask(conn, unixmode);
3182 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3183 if (!NT_STATUS_IS_OK(status)) {
3184 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3185 nt_errstr(status));
3186 return status;
3189 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
3190 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
3192 status = SMB_VFS_CREATE_FILE(
3193 conn, /* conn */
3194 req, /* req */
3195 NULL, /* dirfsp */
3196 smb_fname, /* fname */
3197 FILE_READ_ATTRIBUTES, /* access_mask */
3198 FILE_SHARE_NONE, /* share_access */
3199 FILE_CREATE, /* create_disposition*/
3200 FILE_DIRECTORY_FILE, /* create_options */
3201 0, /* file_attributes */
3202 0, /* oplock_request */
3203 NULL, /* lease */
3204 0, /* allocation_size */
3205 0, /* private_flags */
3206 NULL, /* sd */
3207 NULL, /* ea_list */
3208 &fsp, /* result */
3209 &info, /* pinfo */
3210 posx, /* in_context_blobs */
3211 NULL); /* out_context_blobs */
3213 TALLOC_FREE(posx);
3215 if (NT_STATUS_IS_OK(status)) {
3216 close_file_free(req, &fsp, NORMAL_CLOSE);
3219 info_level_return = SVAL(pdata,16);
3221 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3222 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3223 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3224 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3225 } else {
3226 *pdata_return_size = 12;
3229 /* Realloc the data size */
3230 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3231 if (*ppdata == NULL) {
3232 *pdata_return_size = 0;
3233 return NT_STATUS_NO_MEMORY;
3235 pdata = *ppdata;
3237 SSVAL(pdata,0,NO_OPLOCK_RETURN);
3238 SSVAL(pdata,2,0); /* No fnum. */
3239 SIVAL(pdata,4,info); /* Was directory created. */
3241 switch (info_level_return) {
3242 case SMB_QUERY_FILE_UNIX_BASIC:
3243 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3244 SSVAL(pdata,10,0); /* Padding. */
3245 store_file_unix_basic(conn, pdata + 12, fsp,
3246 &smb_fname->st);
3247 break;
3248 case SMB_QUERY_FILE_UNIX_INFO2:
3249 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3250 SSVAL(pdata,10,0); /* Padding. */
3251 store_file_unix_basic_info2(conn, pdata + 12, fsp,
3252 &smb_fname->st);
3253 break;
3254 default:
3255 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3256 SSVAL(pdata,10,0); /* Padding. */
3257 break;
3260 return status;
3263 /****************************************************************************
3264 Open/Create a file with POSIX semantics.
3265 ****************************************************************************/
3267 #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
3268 #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
3270 static NTSTATUS smb_posix_open(connection_struct *conn,
3271 struct smb_request *req,
3272 char **ppdata,
3273 int total_data,
3274 struct files_struct *dirfsp,
3275 struct smb_filename *smb_fname,
3276 int *pdata_return_size)
3278 bool extended_oplock_granted = False;
3279 char *pdata = *ppdata;
3280 uint32_t flags = 0;
3281 uint32_t wire_open_mode = 0;
3282 uint32_t raw_unixmode = 0;
3283 uint32_t attributes = 0;
3284 uint32_t create_disp = 0;
3285 uint32_t access_mask = 0;
3286 uint32_t create_options = FILE_NON_DIRECTORY_FILE;
3287 NTSTATUS status = NT_STATUS_OK;
3288 mode_t unixmode = (mode_t)0;
3289 files_struct *fsp = NULL;
3290 int oplock_request = 0;
3291 int info = 0;
3292 uint16_t info_level_return = 0;
3293 struct smb2_create_blobs *posx = NULL;
3295 if (total_data < 18) {
3296 return NT_STATUS_INVALID_PARAMETER;
3299 flags = IVAL(pdata,0);
3300 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
3301 if (oplock_request) {
3302 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
3305 wire_open_mode = IVAL(pdata,4);
3307 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
3308 return smb_posix_mkdir(conn, req,
3309 ppdata,
3310 total_data,
3311 smb_fname,
3312 pdata_return_size);
3315 switch (wire_open_mode & SMB_ACCMODE) {
3316 case SMB_O_RDONLY:
3317 access_mask = SMB_O_RDONLY_MAPPING;
3318 break;
3319 case SMB_O_WRONLY:
3320 access_mask = SMB_O_WRONLY_MAPPING;
3321 break;
3322 case SMB_O_RDWR:
3323 access_mask = (SMB_O_RDONLY_MAPPING|
3324 SMB_O_WRONLY_MAPPING);
3325 break;
3326 default:
3327 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
3328 (unsigned int)wire_open_mode ));
3329 return NT_STATUS_INVALID_PARAMETER;
3332 wire_open_mode &= ~SMB_ACCMODE;
3334 /* First take care of O_CREAT|O_EXCL interactions. */
3335 switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
3336 case (SMB_O_CREAT | SMB_O_EXCL):
3337 /* File exists fail. File not exist create. */
3338 create_disp = FILE_CREATE;
3339 break;
3340 case SMB_O_CREAT:
3341 /* File exists open. File not exist create. */
3342 create_disp = FILE_OPEN_IF;
3343 break;
3344 case SMB_O_EXCL:
3345 /* O_EXCL on its own without O_CREAT is undefined.
3346 We deliberately ignore it as some versions of
3347 Linux CIFSFS can send a bare O_EXCL on the
3348 wire which other filesystems in the kernel
3349 ignore. See bug 9519 for details. */
3351 /* Fallthrough. */
3353 case 0:
3354 /* File exists open. File not exist fail. */
3355 create_disp = FILE_OPEN;
3356 break;
3357 default:
3358 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
3359 (unsigned int)wire_open_mode ));
3360 return NT_STATUS_INVALID_PARAMETER;
3363 /* Next factor in the effects of O_TRUNC. */
3364 wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
3366 if (wire_open_mode & SMB_O_TRUNC) {
3367 switch (create_disp) {
3368 case FILE_CREATE:
3369 /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
3370 /* Leave create_disp alone as
3371 (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
3373 /* File exists fail. File not exist create. */
3374 break;
3375 case FILE_OPEN_IF:
3376 /* SMB_O_CREAT | SMB_O_TRUNC */
3377 /* File exists overwrite. File not exist create. */
3378 create_disp = FILE_OVERWRITE_IF;
3379 break;
3380 case FILE_OPEN:
3381 /* SMB_O_TRUNC */
3382 /* File exists overwrite. File not exist fail. */
3383 create_disp = FILE_OVERWRITE;
3384 break;
3385 default:
3386 /* Cannot get here. */
3387 smb_panic("smb_posix_open: logic error");
3388 return NT_STATUS_INVALID_PARAMETER;
3392 raw_unixmode = IVAL(pdata,8);
3393 /* Next 4 bytes are not yet defined. */
3395 status = unix_perms_from_wire(conn,
3396 &smb_fname->st,
3397 raw_unixmode,
3398 &unixmode);
3400 if (!NT_STATUS_IS_OK(status)) {
3401 return status;
3403 if (!VALID_STAT(smb_fname->st)) {
3404 unixmode = apply_conf_dir_mask(conn, unixmode);
3407 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3408 if (!NT_STATUS_IS_OK(status)) {
3409 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3410 nt_errstr(status));
3411 return status;
3414 if (wire_open_mode & SMB_O_SYNC) {
3415 create_options |= FILE_WRITE_THROUGH;
3417 if (wire_open_mode & SMB_O_APPEND) {
3418 access_mask |= FILE_APPEND_DATA;
3420 if (wire_open_mode & SMB_O_DIRECT) {
3422 * BUG: this doesn't work anymore since
3423 * e0814dc5082dd4ecca8a155e0ce24b073158fd92. But since
3424 * FILE_FLAG_NO_BUFFERING isn't used at all in the IO codepath,
3425 * it doesn't really matter.
3427 attributes |= FILE_FLAG_NO_BUFFERING;
3430 if ((wire_open_mode & SMB_O_DIRECTORY) ||
3431 VALID_STAT_OF_DIR(smb_fname->st)) {
3432 if (access_mask != SMB_O_RDONLY_MAPPING) {
3433 return NT_STATUS_FILE_IS_A_DIRECTORY;
3435 create_options &= ~FILE_NON_DIRECTORY_FILE;
3436 create_options |= FILE_DIRECTORY_FILE;
3439 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
3440 smb_fname_str_dbg(smb_fname),
3441 (unsigned int)wire_open_mode,
3442 (unsigned int)unixmode ));
3444 status = SMB_VFS_CREATE_FILE(
3445 conn, /* conn */
3446 req, /* req */
3447 dirfsp, /* dirfsp */
3448 smb_fname, /* fname */
3449 access_mask, /* access_mask */
3450 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3451 FILE_SHARE_DELETE),
3452 create_disp, /* create_disposition*/
3453 create_options, /* create_options */
3454 attributes, /* file_attributes */
3455 oplock_request, /* oplock_request */
3456 NULL, /* lease */
3457 0, /* allocation_size */
3458 0, /* private_flags */
3459 NULL, /* sd */
3460 NULL, /* ea_list */
3461 &fsp, /* result */
3462 &info, /* pinfo */
3463 posx, /* in_context_blobs */
3464 NULL); /* out_context_blobs */
3466 TALLOC_FREE(posx);
3468 if (!NT_STATUS_IS_OK(status)) {
3469 return status;
3472 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3473 extended_oplock_granted = True;
3476 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3477 extended_oplock_granted = True;
3480 info_level_return = SVAL(pdata,16);
3482 /* Allocate the correct return size. */
3484 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3485 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3486 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3487 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3488 } else {
3489 *pdata_return_size = 12;
3492 /* Realloc the data size */
3493 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3494 if (*ppdata == NULL) {
3495 close_file_free(req, &fsp, ERROR_CLOSE);
3496 *pdata_return_size = 0;
3497 return NT_STATUS_NO_MEMORY;
3499 pdata = *ppdata;
3501 if (extended_oplock_granted) {
3502 if (flags & REQUEST_BATCH_OPLOCK) {
3503 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
3504 } else {
3505 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
3507 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
3508 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
3509 } else {
3510 SSVAL(pdata,0,NO_OPLOCK_RETURN);
3513 SSVAL(pdata,2,fsp->fnum);
3514 SIVAL(pdata,4,info); /* Was file created etc. */
3516 switch (info_level_return) {
3517 case SMB_QUERY_FILE_UNIX_BASIC:
3518 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3519 SSVAL(pdata,10,0); /* padding. */
3520 store_file_unix_basic(conn, pdata + 12, fsp,
3521 &smb_fname->st);
3522 break;
3523 case SMB_QUERY_FILE_UNIX_INFO2:
3524 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3525 SSVAL(pdata,10,0); /* padding. */
3526 store_file_unix_basic_info2(conn, pdata + 12, fsp,
3527 &smb_fname->st);
3528 break;
3529 default:
3530 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3531 SSVAL(pdata,10,0); /* padding. */
3532 break;
3534 return NT_STATUS_OK;
3537 /****************************************************************************
3538 Delete a file with POSIX semantics.
3539 ****************************************************************************/
3541 struct smb_posix_unlink_state {
3542 struct smb_filename *smb_fname;
3543 struct files_struct *fsp;
3544 NTSTATUS status;
3547 static void smb_posix_unlink_locked(struct share_mode_lock *lck,
3548 void *private_data)
3550 struct smb_posix_unlink_state *state = private_data;
3551 char del = 1;
3552 bool other_nonposix_opens;
3554 other_nonposix_opens = has_other_nonposix_opens(lck, state->fsp);
3555 if (other_nonposix_opens) {
3556 /* Fail with sharing violation. */
3557 state->status = NT_STATUS_SHARING_VIOLATION;
3558 return;
3562 * Set the delete on close.
3564 state->status = smb_set_file_disposition_info(state->fsp->conn,
3565 &del,
3567 state->fsp,
3568 state->smb_fname);
3571 static NTSTATUS smb_posix_unlink(connection_struct *conn,
3572 struct smb_request *req,
3573 const char *pdata,
3574 int total_data,
3575 struct files_struct *dirfsp,
3576 struct smb_filename *smb_fname)
3578 struct smb_posix_unlink_state state = {};
3579 NTSTATUS status = NT_STATUS_OK;
3580 files_struct *fsp = NULL;
3581 uint16_t flags = 0;
3582 int info = 0;
3583 int create_options = FILE_OPEN_REPARSE_POINT;
3584 struct smb2_create_blobs *posx = NULL;
3586 if (!CAN_WRITE(conn)) {
3587 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3590 if (total_data < 2) {
3591 return NT_STATUS_INVALID_PARAMETER;
3594 flags = SVAL(pdata,0);
3596 if (!VALID_STAT(smb_fname->st)) {
3597 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3600 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
3601 !VALID_STAT_OF_DIR(smb_fname->st)) {
3602 return NT_STATUS_NOT_A_DIRECTORY;
3605 DEBUG(10,("smb_posix_unlink: %s %s\n",
3606 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
3607 smb_fname_str_dbg(smb_fname)));
3609 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
3610 create_options |= FILE_DIRECTORY_FILE;
3613 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
3614 if (!NT_STATUS_IS_OK(status)) {
3615 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3616 nt_errstr(status));
3617 return status;
3620 status = SMB_VFS_CREATE_FILE(
3621 conn, /* conn */
3622 req, /* req */
3623 dirfsp, /* dirfsp */
3624 smb_fname, /* fname */
3625 DELETE_ACCESS, /* access_mask */
3626 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3627 FILE_SHARE_DELETE),
3628 FILE_OPEN, /* create_disposition*/
3629 create_options, /* create_options */
3630 0, /* file_attributes */
3631 0, /* oplock_request */
3632 NULL, /* lease */
3633 0, /* allocation_size */
3634 0, /* private_flags */
3635 NULL, /* sd */
3636 NULL, /* ea_list */
3637 &fsp, /* result */
3638 &info, /* pinfo */
3639 posx, /* in_context_blobs */
3640 NULL); /* out_context_blobs */
3642 TALLOC_FREE(posx);
3644 if (!NT_STATUS_IS_OK(status)) {
3645 return status;
3649 * Don't lie to client. If we can't really delete due to
3650 * non-POSIX opens return SHARING_VIOLATION.
3653 state = (struct smb_posix_unlink_state) {
3654 .smb_fname = smb_fname,
3655 .fsp = fsp,
3658 status = share_mode_do_locked_vfs_allowed(fsp->file_id,
3659 smb_posix_unlink_locked,
3660 &state);
3661 if (!NT_STATUS_IS_OK(status)) {
3662 DBG_ERR("share_mode_do_locked_vfs_allowed(%s) failed - %s\n",
3663 fsp_str_dbg(fsp), nt_errstr(status));
3664 close_file_free(req, &fsp, NORMAL_CLOSE);
3665 return NT_STATUS_INVALID_PARAMETER;
3668 status = state.status;
3669 if (!NT_STATUS_IS_OK(status)) {
3670 close_file_free(req, &fsp, NORMAL_CLOSE);
3671 return status;
3673 return close_file_free(req, &fsp, NORMAL_CLOSE);
3676 /****************************************************************************
3677 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
3678 ****************************************************************************/
3680 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
3681 struct smb_request *req,
3682 const char *pdata,
3683 int total_data,
3684 struct files_struct *dirfsp,
3685 struct smb_filename *new_smb_fname)
3687 char *link_target = NULL;
3688 struct smb_filename target_fname;
3689 TALLOC_CTX *ctx = talloc_tos();
3690 struct smb_filename new_smb_fname_rel = {};
3691 char *slash = NULL;
3692 NTSTATUS status;
3693 int ret;
3695 if (!CAN_WRITE(conn)) {
3696 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3699 /* Set a symbolic link. */
3700 /* Don't allow this if follow links is false. */
3702 if (total_data == 0) {
3703 return NT_STATUS_INVALID_PARAMETER;
3706 if (!lp_follow_symlinks(SNUM(conn))) {
3707 return NT_STATUS_ACCESS_DENIED;
3710 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
3711 total_data, STR_TERMINATE);
3713 if (!link_target) {
3714 return NT_STATUS_INVALID_PARAMETER;
3717 target_fname = (struct smb_filename) {
3718 .base_name = link_target,
3721 /* Removes @GMT tokens if any */
3722 status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
3723 if (!NT_STATUS_IS_OK(status)) {
3724 return status;
3727 DBG_DEBUG("SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
3728 new_smb_fname->base_name, link_target);
3730 new_smb_fname_rel = *new_smb_fname;
3731 slash = strrchr_m(new_smb_fname_rel.base_name, '/');
3732 if (slash != NULL) {
3733 new_smb_fname_rel.base_name = slash + 1;
3736 ret = SMB_VFS_SYMLINKAT(conn,
3737 &target_fname,
3738 dirfsp,
3739 &new_smb_fname_rel);
3740 if (ret != 0) {
3741 return map_nt_error_from_unix(errno);
3744 return NT_STATUS_OK;
3747 /****************************************************************************
3748 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
3749 ****************************************************************************/
3751 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
3752 struct smb_request *req,
3753 const char *pdata, int total_data,
3754 struct smb_filename *smb_fname_new)
3756 char *oldname = NULL;
3757 struct files_struct *src_dirfsp = NULL;
3758 struct smb_filename *smb_fname_old = NULL;
3759 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
3760 NTTIME old_twrp = 0;
3761 TALLOC_CTX *ctx = talloc_tos();
3762 NTSTATUS status = NT_STATUS_OK;
3764 if (!CAN_WRITE(conn)) {
3765 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3768 /* Set a hard link. */
3769 if (total_data == 0) {
3770 return NT_STATUS_INVALID_PARAMETER;
3773 if (req->posix_pathnames) {
3774 srvstr_get_path_posix(ctx,
3775 pdata,
3776 req->flags2,
3777 &oldname,
3778 pdata,
3779 total_data,
3780 STR_TERMINATE,
3781 &status);
3782 } else {
3783 srvstr_get_path(ctx,
3784 pdata,
3785 req->flags2,
3786 &oldname,
3787 pdata,
3788 total_data,
3789 STR_TERMINATE,
3790 &status);
3792 if (!NT_STATUS_IS_OK(status)) {
3793 return status;
3796 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
3797 smb_fname_str_dbg(smb_fname_new), oldname));
3799 if (ucf_flags & UCF_GMT_PATHNAME) {
3800 extract_snapshot_token(oldname, &old_twrp);
3802 status = smb1_strip_dfs_path(ctx, &ucf_flags, &oldname);
3803 if (!NT_STATUS_IS_OK(status)) {
3804 return status;
3806 status = filename_convert_dirfsp(ctx,
3807 conn,
3808 oldname,
3809 ucf_flags,
3810 old_twrp,
3811 &src_dirfsp,
3812 &smb_fname_old);
3813 if (!NT_STATUS_IS_OK(status)) {
3814 return status;
3817 return hardlink_internals(ctx,
3818 conn,
3819 req,
3820 false,
3821 smb_fname_old,
3822 smb_fname_new);
3825 /****************************************************************************
3826 Allow a UNIX info mknod.
3827 ****************************************************************************/
3829 static NTSTATUS smb_unix_mknod(connection_struct *conn,
3830 const char *pdata,
3831 int total_data,
3832 struct files_struct *dirfsp,
3833 const struct smb_filename *smb_fname)
3835 uint32_t file_type = IVAL(pdata,56);
3836 #if defined(HAVE_MAKEDEV)
3837 uint32_t dev_major = IVAL(pdata,60);
3838 uint32_t dev_minor = IVAL(pdata,68);
3839 #endif
3840 SMB_DEV_T dev = (SMB_DEV_T)0;
3841 uint32_t raw_unixmode = IVAL(pdata,84);
3842 NTSTATUS status;
3843 mode_t unixmode;
3844 int ret;
3845 struct smb_filename *parent_fname = NULL;
3846 struct smb_filename *atname = NULL;
3848 if (total_data < 100) {
3849 return NT_STATUS_INVALID_PARAMETER;
3852 status = unix_perms_from_wire(conn,
3853 &smb_fname->st,
3854 raw_unixmode,
3855 &unixmode);
3856 if (!NT_STATUS_IS_OK(status)) {
3857 return status;
3859 unixmode = apply_conf_file_mask(conn, unixmode);
3861 #if defined(HAVE_MAKEDEV)
3862 dev = makedev(dev_major, dev_minor);
3863 #endif
3865 switch (file_type) {
3866 /* We can't create other objects here. */
3867 case UNIX_TYPE_FILE:
3868 case UNIX_TYPE_DIR:
3869 case UNIX_TYPE_SYMLINK:
3870 return NT_STATUS_ACCESS_DENIED;
3871 #if defined(S_IFIFO)
3872 case UNIX_TYPE_FIFO:
3873 unixmode |= S_IFIFO;
3874 break;
3875 #endif
3876 #if defined(S_IFSOCK)
3877 case UNIX_TYPE_SOCKET:
3878 unixmode |= S_IFSOCK;
3879 break;
3880 #endif
3881 #if defined(S_IFCHR)
3882 case UNIX_TYPE_CHARDEV:
3883 /* This is only allowed for root. */
3884 if (get_current_uid(conn) != sec_initial_uid()) {
3885 return NT_STATUS_ACCESS_DENIED;
3887 unixmode |= S_IFCHR;
3888 break;
3889 #endif
3890 #if defined(S_IFBLK)
3891 case UNIX_TYPE_BLKDEV:
3892 if (get_current_uid(conn) != sec_initial_uid()) {
3893 return NT_STATUS_ACCESS_DENIED;
3895 unixmode |= S_IFBLK;
3896 break;
3897 #endif
3898 default:
3899 return NT_STATUS_INVALID_PARAMETER;
3902 DBG_DEBUG("SMB_SET_FILE_UNIX_BASIC doing mknod dev "
3903 "%ju mode 0%o for file %s\n",
3904 (uintmax_t)dev,
3905 (unsigned int)unixmode,
3906 smb_fname_str_dbg(smb_fname));
3908 status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
3909 talloc_tos(),
3910 smb_fname,
3911 &parent_fname,
3912 &atname);
3913 if (!NT_STATUS_IS_OK(status)) {
3914 return status;
3917 /* Ok - do the mknod. */
3918 ret = SMB_VFS_MKNODAT(conn,
3919 dirfsp,
3920 atname,
3921 unixmode,
3922 dev);
3924 if (ret != 0) {
3925 TALLOC_FREE(parent_fname);
3926 return map_nt_error_from_unix(errno);
3929 /* If any of the other "set" calls fail we
3930 * don't want to end up with a half-constructed mknod.
3933 if (lp_inherit_permissions(SNUM(conn))) {
3934 inherit_access_posix_acl(conn,
3935 dirfsp,
3936 smb_fname,
3937 unixmode);
3939 TALLOC_FREE(parent_fname);
3941 return NT_STATUS_OK;
3944 /****************************************************************************
3945 Deal with SMB_SET_FILE_UNIX_BASIC.
3946 ****************************************************************************/
3948 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
3949 struct smb_request *req,
3950 const char *pdata,
3951 int total_data,
3952 struct files_struct *dirfsp,
3953 files_struct *fsp,
3954 struct smb_filename *smb_fname)
3956 struct smb_file_time ft;
3957 uint32_t raw_unixmode;
3958 mode_t unixmode;
3959 off_t size = 0;
3960 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
3961 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
3962 NTSTATUS status = NT_STATUS_OK;
3963 files_struct *all_fsps = NULL;
3964 bool modify_mtime = true;
3965 struct file_id id;
3966 SMB_STRUCT_STAT sbuf;
3968 if (!CAN_WRITE(conn)) {
3969 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3972 init_smb_file_time(&ft);
3974 if (total_data < 100) {
3975 return NT_STATUS_INVALID_PARAMETER;
3978 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
3979 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
3980 size=IVAL(pdata,0); /* first 8 Bytes are size */
3981 size |= (((off_t)IVAL(pdata,4)) << 32);
3984 ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
3985 ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
3986 set_owner = (uid_t)IVAL(pdata,40);
3987 set_grp = (gid_t)IVAL(pdata,48);
3988 raw_unixmode = IVAL(pdata,84);
3990 status = unix_perms_from_wire(conn,
3991 &smb_fname->st,
3992 raw_unixmode,
3993 &unixmode);
3994 if (!NT_STATUS_IS_OK(status)) {
3995 return status;
3997 if (!VALID_STAT(smb_fname->st)) {
3998 unixmode = apply_conf_file_mask(conn, unixmode);
4001 DBG_DEBUG("SMB_SET_FILE_UNIX_BASIC: name = "
4002 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
4003 smb_fname_str_dbg(smb_fname),
4004 (double)size,
4005 (unsigned int)set_owner,
4006 (unsigned int)set_grp,
4007 (int)raw_unixmode);
4009 sbuf = smb_fname->st;
4011 if (!VALID_STAT(sbuf)) {
4013 * The only valid use of this is to create character and block
4014 * devices, and named pipes. This is deprecated (IMHO) and
4015 * a new info level should be used for mknod. JRA.
4018 if (dirfsp == NULL) {
4019 return NT_STATUS_INVALID_PARAMETER;
4022 return smb_unix_mknod(conn,
4023 pdata,
4024 total_data,
4025 dirfsp,
4026 smb_fname);
4029 #if 1
4030 /* Horrible backwards compatibility hack as an old server bug
4031 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
4032 * */
4034 if (!size) {
4035 size = get_file_size_stat(&sbuf);
4037 #endif
4040 * Deal with the UNIX specific mode set.
4043 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
4044 int ret;
4046 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4047 DBG_WARNING("Can't set mode on symlink %s\n",
4048 smb_fname_str_dbg(smb_fname));
4049 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4052 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4053 "setting mode 0%o for file %s\n",
4054 (unsigned int)unixmode,
4055 smb_fname_str_dbg(smb_fname)));
4056 ret = SMB_VFS_FCHMOD(fsp, unixmode);
4057 if (ret != 0) {
4058 return map_nt_error_from_unix(errno);
4063 * Deal with the UNIX specific uid set.
4066 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
4067 (sbuf.st_ex_uid != set_owner)) {
4068 int ret;
4070 DBG_DEBUG("SMB_SET_FILE_UNIX_BASIC "
4071 "changing owner %u for path %s\n",
4072 (unsigned int)set_owner,
4073 smb_fname_str_dbg(smb_fname));
4075 if (fsp &&
4076 !fsp->fsp_flags.is_pathref &&
4077 fsp_get_io_fd(fsp) != -1)
4079 ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
4080 } else {
4082 * UNIX extensions calls must always operate
4083 * on symlinks.
4085 ret = SMB_VFS_LCHOWN(conn, smb_fname,
4086 set_owner, (gid_t)-1);
4089 if (ret != 0) {
4090 status = map_nt_error_from_unix(errno);
4091 return status;
4096 * Deal with the UNIX specific gid set.
4099 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
4100 (sbuf.st_ex_gid != set_grp)) {
4101 int ret;
4103 DBG_DEBUG("SMB_SET_FILE_UNIX_BASIC "
4104 "changing group %u for file %s\n",
4105 (unsigned int)set_grp,
4106 smb_fname_str_dbg(smb_fname));
4107 if (fsp &&
4108 !fsp->fsp_flags.is_pathref &&
4109 fsp_get_io_fd(fsp) != -1)
4111 ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
4112 } else {
4114 * UNIX extensions calls must always operate
4115 * on symlinks.
4117 ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
4118 set_grp);
4120 if (ret != 0) {
4121 status = map_nt_error_from_unix(errno);
4122 return status;
4126 /* Deal with any size changes. */
4128 if (S_ISREG(sbuf.st_ex_mode)) {
4129 status = smb_set_file_size(conn, req,
4130 fsp,
4131 smb_fname,
4132 &sbuf,
4133 size,
4134 false);
4135 if (!NT_STATUS_IS_OK(status)) {
4136 return status;
4140 /* Deal with any time changes. */
4141 if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
4142 /* No change, don't cancel anything. */
4143 return status;
4146 id = vfs_file_id_from_sbuf(conn, &sbuf);
4147 for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
4148 all_fsps = file_find_di_next(all_fsps, true)) {
4150 * We're setting the time explicitly for UNIX.
4151 * Cancel any pending changes over all handles.
4153 all_fsps->fsp_flags.update_write_time_on_close = false;
4154 TALLOC_FREE(all_fsps->update_write_time_event);
4158 * Override the "setting_write_time"
4159 * parameter here as it almost does what
4160 * we need. Just remember if we modified
4161 * mtime and send the notify ourselves.
4163 if (is_omit_timespec(&ft.mtime)) {
4164 modify_mtime = false;
4167 status = smb_set_file_time(conn,
4168 fsp,
4169 smb_fname,
4170 &ft,
4171 false);
4172 if (modify_mtime) {
4173 notify_fname(conn,
4174 NOTIFY_ACTION_MODIFIED,
4175 FILE_NOTIFY_CHANGE_LAST_WRITE,
4176 smb_fname,
4177 NULL);
4179 return status;
4182 /****************************************************************************
4183 Deal with SMB_SET_FILE_UNIX_INFO2.
4184 ****************************************************************************/
4186 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
4187 struct smb_request *req,
4188 const char *pdata,
4189 int total_data,
4190 struct files_struct *dirfsp,
4191 files_struct *fsp,
4192 struct smb_filename *smb_fname)
4194 NTSTATUS status;
4195 uint32_t smb_fflags;
4196 uint32_t smb_fmask;
4198 if (!CAN_WRITE(conn)) {
4199 return NT_STATUS_DOS(ERRSRV, ERRaccess);
4202 if (total_data < 116) {
4203 return NT_STATUS_INVALID_PARAMETER;
4206 /* Start by setting all the fields that are common between UNIX_BASIC
4207 * and UNIX_INFO2.
4209 status = smb_set_file_unix_basic(conn,
4210 req,
4211 pdata,
4212 total_data,
4213 dirfsp,
4214 fsp,
4215 smb_fname);
4216 if (!NT_STATUS_IS_OK(status)) {
4217 return status;
4220 smb_fflags = IVAL(pdata, 108);
4221 smb_fmask = IVAL(pdata, 112);
4223 /* NB: We should only attempt to alter the file flags if the client
4224 * sends a non-zero mask.
4226 if (smb_fmask != 0) {
4227 int stat_fflags = 0;
4229 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
4230 smb_fmask, &stat_fflags)) {
4231 /* Client asked to alter a flag we don't understand. */
4232 return NT_STATUS_INVALID_PARAMETER;
4235 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4236 DBG_WARNING("Can't change flags on symlink %s\n",
4237 smb_fname_str_dbg(smb_fname));
4238 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4240 if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
4241 return map_nt_error_from_unix(errno);
4245 /* XXX: need to add support for changing the create_time here. You
4246 * can do this for paths on Darwin with setattrlist(2). The right way
4247 * to hook this up is probably by extending the VFS utimes interface.
4250 return NT_STATUS_OK;
4253 /****************************************************************************
4254 Deal with SMB_SET_POSIX_ACL.
4255 ****************************************************************************/
4257 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
4258 struct smb_request *req,
4259 const char *pdata,
4260 int total_data_in,
4261 files_struct *fsp,
4262 struct smb_filename *smb_fname)
4264 #if !defined(HAVE_POSIX_ACLS)
4265 return NT_STATUS_INVALID_LEVEL;
4266 #else
4267 uint16_t posix_acl_version;
4268 uint16_t num_file_acls;
4269 uint16_t num_def_acls;
4270 bool valid_file_acls = true;
4271 bool valid_def_acls = true;
4272 NTSTATUS status;
4273 unsigned int size_needed;
4274 unsigned int total_data;
4275 bool close_fsp = false;
4277 if (total_data_in < 0) {
4278 status = NT_STATUS_INVALID_PARAMETER;
4279 goto out;
4282 total_data = total_data_in;
4284 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
4285 status = NT_STATUS_INVALID_PARAMETER;
4286 goto out;
4288 posix_acl_version = SVAL(pdata,0);
4289 num_file_acls = SVAL(pdata,2);
4290 num_def_acls = SVAL(pdata,4);
4292 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4293 valid_file_acls = false;
4294 num_file_acls = 0;
4297 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4298 valid_def_acls = false;
4299 num_def_acls = 0;
4302 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
4303 status = NT_STATUS_INVALID_PARAMETER;
4304 goto out;
4307 /* Wrap checks. */
4308 if (num_file_acls + num_def_acls < num_file_acls) {
4309 status = NT_STATUS_INVALID_PARAMETER;
4310 goto out;
4313 size_needed = num_file_acls + num_def_acls;
4316 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
4317 * than UINT_MAX, so check by division.
4319 if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
4320 status = NT_STATUS_INVALID_PARAMETER;
4321 goto out;
4324 size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
4325 if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
4326 status = NT_STATUS_INVALID_PARAMETER;
4327 goto out;
4329 size_needed += SMB_POSIX_ACL_HEADER_SIZE;
4331 if (total_data < size_needed) {
4332 status = NT_STATUS_INVALID_PARAMETER;
4333 goto out;
4337 * Ensure we always operate on a file descriptor, not just
4338 * the filename.
4340 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
4341 uint32_t access_mask = SEC_STD_WRITE_OWNER|
4342 SEC_STD_WRITE_DAC|
4343 SEC_STD_READ_CONTROL|
4344 FILE_READ_ATTRIBUTES|
4345 FILE_WRITE_ATTRIBUTES;
4347 status = get_posix_fsp(conn,
4348 req,
4349 smb_fname,
4350 access_mask,
4351 &fsp);
4353 if (!NT_STATUS_IS_OK(status)) {
4354 goto out;
4356 close_fsp = true;
4359 /* Here we know fsp != NULL */
4360 SMB_ASSERT(fsp != NULL);
4362 status = refuse_symlink_fsp(fsp);
4363 if (!NT_STATUS_IS_OK(status)) {
4364 goto out;
4367 /* If we have a default acl, this *must* be a directory. */
4368 if (valid_def_acls && !fsp->fsp_flags.is_directory) {
4369 DBG_INFO("Can't set default acls on "
4370 "non-directory %s\n",
4371 fsp_str_dbg(fsp));
4372 return NT_STATUS_INVALID_HANDLE;
4375 DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
4376 "num_def_acls = %"PRIu16"\n",
4377 fsp_str_dbg(fsp),
4378 num_file_acls,
4379 num_def_acls);
4381 /* Move pdata to the start of the file ACL entries. */
4382 pdata += SMB_POSIX_ACL_HEADER_SIZE;
4384 if (valid_file_acls) {
4385 status = set_unix_posix_acl(conn,
4386 fsp,
4387 num_file_acls,
4388 pdata);
4389 if (!NT_STATUS_IS_OK(status)) {
4390 goto out;
4394 /* Move pdata to the start of the default ACL entries. */
4395 pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
4397 if (valid_def_acls) {
4398 status = set_unix_posix_default_acl(conn,
4399 fsp,
4400 num_def_acls,
4401 pdata);
4402 if (!NT_STATUS_IS_OK(status)) {
4403 goto out;
4407 status = NT_STATUS_OK;
4409 out:
4411 if (close_fsp) {
4412 (void)close_file_free(req, &fsp, NORMAL_CLOSE);
4414 return status;
4415 #endif
4418 static void call_trans2setpathinfo(
4419 connection_struct *conn,
4420 struct smb_request *req,
4421 char **pparams,
4422 int total_params,
4423 char **ppdata,
4424 int total_data,
4425 unsigned int max_data_bytes)
4427 uint16_t info_level;
4428 struct smb_filename *smb_fname = NULL;
4429 struct files_struct *dirfsp = NULL;
4430 struct files_struct *fsp = NULL;
4431 char *params = *pparams;
4432 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4433 NTTIME twrp = 0;
4434 char *fname = NULL;
4435 bool info_level_handled;
4436 int data_return_size = 0;
4437 NTSTATUS status;
4439 if (params == NULL) {
4440 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4441 return;
4444 /* set path info */
4445 if (total_params < 7) {
4446 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4447 return;
4450 info_level = SVAL(params,0);
4452 if (INFO_LEVEL_IS_UNIX(info_level)) {
4453 if (!lp_smb1_unix_extensions()) {
4454 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4455 return;
4457 if (!req->posix_pathnames) {
4458 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4459 return;
4463 if (req->posix_pathnames) {
4464 srvstr_get_path_posix(req,
4465 params,
4466 req->flags2,
4467 &fname,
4468 &params[6],
4469 total_params - 6,
4470 STR_TERMINATE,
4471 &status);
4472 } else {
4473 srvstr_get_path(req,
4474 params,
4475 req->flags2,
4476 &fname,
4477 &params[6],
4478 total_params - 6,
4479 STR_TERMINATE,
4480 &status);
4482 if (!NT_STATUS_IS_OK(status)) {
4483 reply_nterror(req, status);
4484 return;
4487 DBG_NOTICE("fname=%s info_level=%d totdata=%d\n",
4488 fname,
4489 info_level,
4490 total_data);
4492 if (ucf_flags & UCF_GMT_PATHNAME) {
4493 extract_snapshot_token(fname, &twrp);
4495 status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
4496 if (!NT_STATUS_IS_OK(status)) {
4497 reply_nterror(req, status);
4498 return;
4500 status = filename_convert_dirfsp(req,
4501 conn,
4502 fname,
4503 ucf_flags,
4504 twrp,
4505 &dirfsp,
4506 &smb_fname);
4507 if (!NT_STATUS_IS_OK(status)) {
4508 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4509 reply_botherror(req,
4510 NT_STATUS_PATH_NOT_COVERED,
4511 ERRSRV, ERRbadpath);
4512 return;
4514 reply_nterror(req, status);
4515 return;
4518 info_level_handled = true; /* Untouched in switch cases below */
4520 switch (info_level) {
4522 default:
4523 info_level_handled = false;
4524 break;
4526 case SMB_POSIX_PATH_OPEN:
4527 status = smb_posix_open(conn,
4528 req,
4529 ppdata,
4530 total_data,
4531 dirfsp,
4532 smb_fname,
4533 &data_return_size);
4534 break;
4536 case SMB_POSIX_PATH_UNLINK:
4537 status = smb_posix_unlink(conn,
4538 req,
4539 *ppdata,
4540 total_data,
4541 dirfsp,
4542 smb_fname);
4543 break;
4545 case SMB_SET_FILE_UNIX_LINK:
4546 status = smb_set_file_unix_link(
4547 conn, req, *ppdata, total_data, dirfsp, smb_fname);
4548 break;
4550 case SMB_SET_FILE_UNIX_HLINK:
4551 status = smb_set_file_unix_hlink(
4552 conn, req, *ppdata, total_data, smb_fname);
4553 break;
4555 case SMB_SET_FILE_UNIX_BASIC:
4556 status = smb_set_file_unix_basic(conn,
4557 req,
4558 *ppdata,
4559 total_data,
4560 dirfsp,
4561 smb_fname->fsp,
4562 smb_fname);
4563 break;
4565 case SMB_SET_FILE_UNIX_INFO2:
4566 status = smb_set_file_unix_info2(conn,
4567 req,
4568 *ppdata,
4569 total_data,
4570 dirfsp,
4571 smb_fname->fsp,
4572 smb_fname);
4573 break;
4574 case SMB_SET_POSIX_ACL:
4575 status = smb_set_posix_acl(
4576 conn, req, *ppdata, total_data, NULL, smb_fname);
4577 break;
4580 if (info_level_handled) {
4581 goto done;
4585 * smb_fname->fsp may be NULL if smb_fname points at a symlink
4586 * and we're in POSIX context, so be careful when using fsp
4587 * below, it can still be NULL.
4589 fsp = smb_fname->fsp;
4590 if (fsp == NULL) {
4591 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
4592 goto done;
4595 status = smbd_do_setfilepathinfo(
4596 conn,
4597 req,
4598 req,
4599 info_level,
4600 fsp,
4601 NULL,
4602 smb_fname,
4603 *ppdata,
4604 total_data,
4605 &data_return_size);
4607 done:
4608 handle_trans2setfilepathinfo_result(
4609 conn,
4610 req,
4611 info_level,
4612 status,
4613 *ppdata,
4614 data_return_size,
4615 max_data_bytes);
4618 static void call_trans2setfileinfo(
4619 connection_struct *conn,
4620 struct smb_request *req,
4621 char **pparams,
4622 int total_params,
4623 char **ppdata,
4624 int total_data,
4625 unsigned int max_data_bytes)
4627 char *pdata = *ppdata;
4628 uint16_t info_level;
4629 struct smb_filename *smb_fname = NULL;
4630 struct files_struct *fsp = NULL;
4631 char *params = *pparams;
4632 int data_return_size = 0;
4633 bool info_level_handled;
4634 NTSTATUS status;
4635 int ret;
4637 if (params == NULL) {
4638 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4639 return;
4641 if (total_params < 4) {
4642 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4643 return;
4646 fsp = file_fsp(req, SVAL(params,0));
4647 /* Basic check for non-null fsp. */
4648 if (!check_fsp_open(conn, req, fsp)) {
4649 return;
4651 info_level = SVAL(params,2);
4653 if (INFO_LEVEL_IS_UNIX(info_level)) {
4654 if (!lp_smb1_unix_extensions()) {
4655 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4656 return;
4658 if (!req->posix_pathnames) {
4659 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4660 return;
4664 smb_fname = fsp->fsp_name;
4666 DBG_NOTICE("fnum=%s fname=%s info_level=%d totdata=%d\n",
4667 fsp_fnum_dbg(fsp),
4668 fsp_str_dbg(fsp),
4669 info_level,
4670 total_data);
4672 if (fsp_get_pathref_fd(fsp) == -1) {
4674 * This is actually a SETFILEINFO on a directory
4675 * handle (returned from an NT SMB). NT5.0 seems
4676 * to do this call. JRA.
4678 ret = vfs_stat(conn, smb_fname);
4679 if (ret != 0) {
4680 DBG_NOTICE("vfs_stat of %s failed (%s)\n",
4681 smb_fname_str_dbg(smb_fname),
4682 strerror(errno));
4683 reply_nterror(req, map_nt_error_from_unix(errno));
4684 return;
4686 } else if (fsp->print_file) {
4688 * Doing a DELETE_ON_CLOSE should cancel a print job.
4690 if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) &&
4691 CVAL(pdata,0)) {
4693 fsp->fsp_flags.delete_on_close = true;
4695 DBG_NOTICE("Cancelling print job (%s)\n",
4696 fsp_str_dbg(fsp));
4698 SSVAL(params,0,0);
4699 send_trans2_replies(
4700 conn,
4701 req,
4702 NT_STATUS_OK,
4703 params,
4705 *ppdata, 0,
4706 max_data_bytes);
4707 return;
4708 } else {
4709 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
4710 return;
4712 } else {
4714 * Original code - this is an open file.
4716 status = vfs_stat_fsp(fsp);
4717 if (!NT_STATUS_IS_OK(status)) {
4718 DBG_NOTICE("fstat of %s failed (%s)\n",
4719 fsp_fnum_dbg(fsp),
4720 nt_errstr(status));
4721 reply_nterror(req, status);
4722 return;
4726 info_level_handled = true; /* Untouched in switch cases below */
4728 switch (info_level) {
4730 default:
4731 info_level_handled = false;
4732 break;
4734 case SMB_SET_FILE_UNIX_BASIC:
4735 status = smb_set_file_unix_basic(conn,
4736 req,
4737 pdata,
4738 total_data,
4739 NULL,
4740 fsp,
4741 smb_fname);
4742 break;
4744 case SMB_SET_FILE_UNIX_INFO2:
4745 status = smb_set_file_unix_info2(conn,
4746 req,
4747 pdata,
4748 total_data,
4749 NULL,
4750 fsp,
4751 smb_fname);
4752 break;
4754 case SMB_SET_POSIX_LOCK:
4755 status = smb_set_posix_lock(
4756 conn, req, *ppdata, total_data, fsp);
4757 break;
4760 if (info_level_handled) {
4761 handle_trans2setfilepathinfo_result(
4762 conn,
4763 req,
4764 info_level,
4765 status,
4766 *ppdata,
4767 data_return_size,
4768 max_data_bytes);
4769 return;
4772 status = smbd_do_setfilepathinfo(
4773 conn,
4774 req,
4775 req,
4776 info_level,
4777 fsp,
4778 NULL,
4779 smb_fname,
4780 *ppdata,
4781 total_data,
4782 &data_return_size);
4784 handle_trans2setfilepathinfo_result(
4785 conn,
4786 req,
4787 info_level,
4788 status,
4789 *ppdata,
4790 data_return_size,
4791 max_data_bytes);
4794 /****************************************************************************
4795 Reply to a TRANS2_MKDIR (make directory with extended attributes).
4796 ****************************************************************************/
4798 static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
4799 char **pparams, int total_params,
4800 char **ppdata, int total_data,
4801 unsigned int max_data_bytes)
4803 struct files_struct *dirfsp = NULL;
4804 struct files_struct *fsp = NULL;
4805 struct smb_filename *smb_dname = NULL;
4806 char *params = *pparams;
4807 char *pdata = *ppdata;
4808 char *directory = NULL;
4809 NTSTATUS status = NT_STATUS_OK;
4810 struct ea_list *ea_list = NULL;
4811 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4812 NTTIME twrp = 0;
4813 TALLOC_CTX *ctx = talloc_tos();
4815 if (!CAN_WRITE(conn)) {
4816 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4817 return;
4820 if (total_params < 5) {
4821 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4822 return;
4825 if (req->posix_pathnames) {
4826 srvstr_get_path_posix(ctx,
4827 params,
4828 req->flags2,
4829 &directory,
4830 &params[4],
4831 total_params - 4,
4832 STR_TERMINATE,
4833 &status);
4834 } else {
4835 srvstr_get_path(ctx,
4836 params,
4837 req->flags2,
4838 &directory,
4839 &params[4],
4840 total_params - 4,
4841 STR_TERMINATE,
4842 &status);
4844 if (!NT_STATUS_IS_OK(status)) {
4845 reply_nterror(req, status);
4846 return;
4849 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
4851 if (ucf_flags & UCF_GMT_PATHNAME) {
4852 extract_snapshot_token(directory, &twrp);
4854 status = smb1_strip_dfs_path(ctx, &ucf_flags, &directory);
4855 if (!NT_STATUS_IS_OK(status)) {
4856 reply_nterror(req, status);
4857 goto out;
4859 status = filename_convert_dirfsp(ctx,
4860 conn,
4861 directory,
4862 ucf_flags,
4863 twrp,
4864 &dirfsp,
4865 &smb_dname);
4866 if (!NT_STATUS_IS_OK(status)) {
4867 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4868 reply_botherror(req,
4869 NT_STATUS_PATH_NOT_COVERED,
4870 ERRSRV, ERRbadpath);
4871 return;
4873 reply_nterror(req, status);
4874 return;
4878 * OS/2 workplace shell seems to send SET_EA requests of "null"
4879 * length (4 bytes containing IVAL 4).
4880 * They seem to have no effect. Bug #3212. JRA.
4883 if (total_data && (total_data != 4)) {
4884 /* Any data in this call is an EA list. */
4885 if (total_data < 10) {
4886 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4887 goto out;
4890 if (IVAL(pdata,0) > total_data) {
4891 DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
4892 IVAL(pdata,0), (unsigned int)total_data));
4893 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4894 goto out;
4897 ea_list = read_ea_list(talloc_tos(), pdata + 4,
4898 total_data - 4);
4899 if (!ea_list) {
4900 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4901 goto out;
4904 if (!lp_ea_support(SNUM(conn))) {
4905 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
4906 goto out;
4909 /* If total_data == 4 Windows doesn't care what values
4910 * are placed in that field, it just ignores them.
4911 * The System i QNTC IBM SMB client puts bad values here,
4912 * so ignore them. */
4914 status = SMB_VFS_CREATE_FILE(
4915 conn, /* conn */
4916 req, /* req */
4917 dirfsp, /* dirfsp */
4918 smb_dname, /* fname */
4919 MAXIMUM_ALLOWED_ACCESS, /* access_mask */
4920 FILE_SHARE_NONE, /* share_access */
4921 FILE_CREATE, /* create_disposition*/
4922 FILE_DIRECTORY_FILE, /* create_options */
4923 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
4924 0, /* oplock_request */
4925 NULL, /* lease */
4926 0, /* allocation_size */
4927 0, /* private_flags */
4928 NULL, /* sd */
4929 NULL, /* ea_list */
4930 &fsp, /* result */
4931 NULL, /* pinfo */
4932 NULL, NULL); /* create context */
4933 if (!NT_STATUS_IS_OK(status)) {
4934 reply_nterror(req, status);
4935 goto out;
4938 /* Try and set any given EA. */
4939 if (ea_list) {
4940 status = set_ea(conn, fsp, ea_list);
4941 if (!NT_STATUS_IS_OK(status)) {
4942 reply_nterror(req, status);
4943 goto out;
4947 /* Realloc the parameter and data sizes */
4948 *pparams = (char *)SMB_REALLOC(*pparams,2);
4949 if(*pparams == NULL) {
4950 reply_nterror(req, NT_STATUS_NO_MEMORY);
4951 goto out;
4953 params = *pparams;
4955 SSVAL(params,0,0);
4957 send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
4959 out:
4960 if (fsp != NULL) {
4961 close_file_free(NULL, &fsp, NORMAL_CLOSE);
4963 TALLOC_FREE(smb_dname);
4966 /****************************************************************************
4967 Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
4968 We don't actually do this - we just send a null response.
4969 ****************************************************************************/
4971 static void call_trans2findnotifyfirst(connection_struct *conn,
4972 struct smb_request *req,
4973 char **pparams, int total_params,
4974 char **ppdata, int total_data,
4975 unsigned int max_data_bytes)
4977 char *params = *pparams;
4978 uint16_t info_level;
4980 if (total_params < 6) {
4981 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4982 return;
4985 info_level = SVAL(params,4);
4986 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
4988 switch (info_level) {
4989 case 1:
4990 case 2:
4991 break;
4992 default:
4993 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4994 return;
4997 /* Realloc the parameter and data sizes */
4998 *pparams = (char *)SMB_REALLOC(*pparams,6);
4999 if (*pparams == NULL) {
5000 reply_nterror(req, NT_STATUS_NO_MEMORY);
5001 return;
5003 params = *pparams;
5005 SSVAL(params,0,fnf_handle);
5006 SSVAL(params,2,0); /* No changes */
5007 SSVAL(params,4,0); /* No EA errors */
5009 fnf_handle++;
5011 if(fnf_handle == 0)
5012 fnf_handle = 257;
5014 send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
5017 /****************************************************************************
5018 Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
5019 changes). Currently this does nothing.
5020 ****************************************************************************/
5022 static void call_trans2findnotifynext(connection_struct *conn,
5023 struct smb_request *req,
5024 char **pparams, int total_params,
5025 char **ppdata, int total_data,
5026 unsigned int max_data_bytes)
5028 char *params = *pparams;
5030 DEBUG(3,("call_trans2findnotifynext\n"));
5032 /* Realloc the parameter and data sizes */
5033 *pparams = (char *)SMB_REALLOC(*pparams,4);
5034 if (*pparams == NULL) {
5035 reply_nterror(req, NT_STATUS_NO_MEMORY);
5036 return;
5038 params = *pparams;
5040 SSVAL(params,0,0); /* No changes */
5041 SSVAL(params,2,0); /* No EA errors */
5043 send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
5046 /****************************************************************************
5047 Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
5048 ****************************************************************************/
5050 static void call_trans2getdfsreferral(connection_struct *conn,
5051 struct smb_request *req,
5052 char **pparams, int total_params,
5053 char **ppdata, int total_data,
5054 unsigned int max_data_bytes)
5056 char *params = *pparams;
5057 char *pathname = NULL;
5058 int reply_size = 0;
5059 int max_referral_level;
5060 NTSTATUS status = NT_STATUS_OK;
5061 TALLOC_CTX *ctx = talloc_tos();
5063 DEBUG(10,("call_trans2getdfsreferral\n"));
5065 if (!IS_IPC(conn)) {
5066 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5067 return;
5070 if (total_params < 3) {
5071 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5072 return;
5075 max_referral_level = SVAL(params,0);
5077 if(!lp_host_msdfs()) {
5078 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5079 return;
5082 srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
5083 total_params - 2, STR_TERMINATE);
5084 if (!pathname) {
5085 reply_nterror(req, NT_STATUS_NOT_FOUND);
5086 return;
5088 reply_size = setup_dfs_referral(
5089 conn, pathname, max_referral_level, ppdata, &status);
5090 if (reply_size < 0) {
5091 reply_nterror(req, status);
5092 return;
5095 SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
5096 SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
5097 send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
5100 #define LMCAT_SPL 0x53
5101 #define LMFUNC_GETJOBID 0x60
5103 /****************************************************************************
5104 Reply to a TRANS2_IOCTL - used for OS/2 printing.
5105 ****************************************************************************/
5107 static void call_trans2ioctl(connection_struct *conn,
5108 struct smb_request *req,
5109 char **pparams, int total_params,
5110 char **ppdata, int total_data,
5111 unsigned int max_data_bytes)
5113 const struct loadparm_substitution *lp_sub =
5114 loadparm_s3_global_substitution();
5115 char *pdata = *ppdata;
5116 files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
5117 NTSTATUS status;
5118 size_t len = 0;
5120 /* check for an invalid fid before proceeding */
5122 if (!fsp) {
5123 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5124 return;
5127 if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
5128 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5129 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
5130 if (*ppdata == NULL) {
5131 reply_nterror(req, NT_STATUS_NO_MEMORY);
5132 return;
5134 pdata = *ppdata;
5136 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
5137 CAN ACCEPT THIS IN UNICODE. JRA. */
5139 /* Job number */
5140 SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));
5142 status = srvstr_push(pdata, req->flags2, pdata + 2,
5143 lp_netbios_name(), 15,
5144 STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
5145 if (!NT_STATUS_IS_OK(status)) {
5146 reply_nterror(req, status);
5147 return;
5149 status = srvstr_push(pdata, req->flags2, pdata+18,
5150 lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13,
5151 STR_ASCII|STR_TERMINATE, &len); /* Service name */
5152 if (!NT_STATUS_IS_OK(status)) {
5153 reply_nterror(req, status);
5154 return;
5156 send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
5157 max_data_bytes);
5158 return;
5161 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
5162 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5165 static void handle_trans2(connection_struct *conn, struct smb_request *req,
5166 struct trans_state *state)
5168 struct smbXsrv_connection *xconn = req->xconn;
5170 if (xconn->protocol >= PROTOCOL_NT1) {
5171 req->flags2 |= 0x40; /* IS_LONG_NAME */
5172 SSVAL((discard_const_p(uint8_t, req->inbuf)),smb_flg2,req->flags2);
5175 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
5176 if (state->call != TRANSACT2_QFSINFO &&
5177 state->call != TRANSACT2_SETFSINFO) {
5178 DEBUG(0,("handle_trans2: encryption required "
5179 "with call 0x%x\n",
5180 (unsigned int)state->call));
5181 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5182 return;
5186 /* Now we must call the relevant TRANS2 function */
5187 switch(state->call) {
5188 case TRANSACT2_OPEN:
5190 START_PROFILE(Trans2_open);
5191 call_trans2open(conn, req,
5192 &state->param, state->total_param,
5193 &state->data, state->total_data,
5194 state->max_data_return);
5195 END_PROFILE(Trans2_open);
5196 break;
5199 case TRANSACT2_FINDFIRST:
5201 START_PROFILE(Trans2_findfirst);
5202 call_trans2findfirst(conn, req,
5203 &state->param, state->total_param,
5204 &state->data, state->total_data,
5205 state->max_data_return);
5206 END_PROFILE(Trans2_findfirst);
5207 break;
5210 case TRANSACT2_FINDNEXT:
5212 START_PROFILE(Trans2_findnext);
5213 call_trans2findnext(conn, req,
5214 &state->param, state->total_param,
5215 &state->data, state->total_data,
5216 state->max_data_return);
5217 END_PROFILE(Trans2_findnext);
5218 break;
5221 case TRANSACT2_QFSINFO:
5223 START_PROFILE(Trans2_qfsinfo);
5224 call_trans2qfsinfo(conn, req,
5225 &state->param, state->total_param,
5226 &state->data, state->total_data,
5227 state->max_data_return);
5228 END_PROFILE(Trans2_qfsinfo);
5229 break;
5232 case TRANSACT2_SETFSINFO:
5234 START_PROFILE(Trans2_setfsinfo);
5235 call_trans2setfsinfo(conn, req,
5236 &state->param, state->total_param,
5237 &state->data, state->total_data,
5238 state->max_data_return);
5239 END_PROFILE(Trans2_setfsinfo);
5240 break;
5243 case TRANSACT2_QPATHINFO:
5245 START_PROFILE(Trans2_qpathinfo);
5246 call_trans2qpathinfo(
5247 conn,
5248 req,
5249 &state->param,
5250 state->total_param,
5251 &state->data,
5252 state->total_data,
5253 state->max_data_return);
5254 END_PROFILE(Trans2_qpathinfo);
5255 break;
5258 case TRANSACT2_QFILEINFO:
5260 START_PROFILE(Trans2_qfileinfo);
5261 call_trans2qfileinfo(
5262 conn,
5263 req,
5264 &state->param,
5265 state->total_param,
5266 &state->data,
5267 state->total_data,
5268 state->max_data_return);
5269 END_PROFILE(Trans2_qfileinfo);
5270 break;
5273 case TRANSACT2_SETPATHINFO:
5275 START_PROFILE(Trans2_setpathinfo);
5276 call_trans2setpathinfo(
5277 conn,
5278 req,
5279 &state->param,
5280 state->total_param,
5281 &state->data,
5282 state->total_data,
5283 state->max_data_return);
5284 END_PROFILE(Trans2_setpathinfo);
5285 break;
5288 case TRANSACT2_SETFILEINFO:
5290 START_PROFILE(Trans2_setfileinfo);
5291 call_trans2setfileinfo(
5292 conn,
5293 req,
5294 &state->param,
5295 state->total_param,
5296 &state->data,
5297 state->total_data,
5298 state->max_data_return);
5299 END_PROFILE(Trans2_setfileinfo);
5300 break;
5303 case TRANSACT2_FINDNOTIFYFIRST:
5305 START_PROFILE(Trans2_findnotifyfirst);
5306 call_trans2findnotifyfirst(conn, req,
5307 &state->param, state->total_param,
5308 &state->data, state->total_data,
5309 state->max_data_return);
5310 END_PROFILE(Trans2_findnotifyfirst);
5311 break;
5314 case TRANSACT2_FINDNOTIFYNEXT:
5316 START_PROFILE(Trans2_findnotifynext);
5317 call_trans2findnotifynext(conn, req,
5318 &state->param, state->total_param,
5319 &state->data, state->total_data,
5320 state->max_data_return);
5321 END_PROFILE(Trans2_findnotifynext);
5322 break;
5325 case TRANSACT2_MKDIR:
5327 START_PROFILE(Trans2_mkdir);
5328 call_trans2mkdir(conn, req,
5329 &state->param, state->total_param,
5330 &state->data, state->total_data,
5331 state->max_data_return);
5332 END_PROFILE(Trans2_mkdir);
5333 break;
5336 case TRANSACT2_GET_DFS_REFERRAL:
5338 START_PROFILE(Trans2_get_dfs_referral);
5339 call_trans2getdfsreferral(conn, req,
5340 &state->param, state->total_param,
5341 &state->data, state->total_data,
5342 state->max_data_return);
5343 END_PROFILE(Trans2_get_dfs_referral);
5344 break;
5347 case TRANSACT2_IOCTL:
5349 START_PROFILE(Trans2_ioctl);
5350 call_trans2ioctl(conn, req,
5351 &state->param, state->total_param,
5352 &state->data, state->total_data,
5353 state->max_data_return);
5354 END_PROFILE(Trans2_ioctl);
5355 break;
5358 default:
5359 /* Error in request */
5360 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
5361 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5365 /****************************************************************************
5366 Reply to a SMBtrans2.
5367 ****************************************************************************/
5369 void reply_trans2(struct smb_request *req)
5371 connection_struct *conn = req->conn;
5372 unsigned int dsoff;
5373 unsigned int dscnt;
5374 unsigned int psoff;
5375 unsigned int pscnt;
5376 unsigned int tran_call;
5377 struct trans_state *state;
5378 NTSTATUS result;
5380 START_PROFILE(SMBtrans2);
5382 if (req->wct < 14) {
5383 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5384 END_PROFILE(SMBtrans2);
5385 return;
5388 dsoff = SVAL(req->vwv+12, 0);
5389 dscnt = SVAL(req->vwv+11, 0);
5390 psoff = SVAL(req->vwv+10, 0);
5391 pscnt = SVAL(req->vwv+9, 0);
5392 tran_call = SVAL(req->vwv+14, 0);
5394 result = allow_new_trans(conn->pending_trans, req->mid);
5395 if (!NT_STATUS_IS_OK(result)) {
5396 DEBUG(2, ("Got invalid trans2 request: %s\n",
5397 nt_errstr(result)));
5398 reply_nterror(req, result);
5399 END_PROFILE(SMBtrans2);
5400 return;
5403 if (IS_IPC(conn)) {
5404 switch (tran_call) {
5405 /* List the allowed trans2 calls on IPC$ */
5406 case TRANSACT2_OPEN:
5407 case TRANSACT2_GET_DFS_REFERRAL:
5408 case TRANSACT2_QFILEINFO:
5409 case TRANSACT2_QFSINFO:
5410 case TRANSACT2_SETFSINFO:
5411 break;
5412 default:
5413 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5414 END_PROFILE(SMBtrans2);
5415 return;
5419 if ((state = talloc(conn, struct trans_state)) == NULL) {
5420 DEBUG(0, ("talloc failed\n"));
5421 reply_nterror(req, NT_STATUS_NO_MEMORY);
5422 END_PROFILE(SMBtrans2);
5423 return;
5426 state->cmd = SMBtrans2;
5428 state->mid = req->mid;
5429 state->vuid = req->vuid;
5430 state->setup_count = SVAL(req->vwv+13, 0);
5431 state->setup = NULL;
5432 state->total_param = SVAL(req->vwv+0, 0);
5433 state->param = NULL;
5434 state->total_data = SVAL(req->vwv+1, 0);
5435 state->data = NULL;
5436 state->max_param_return = SVAL(req->vwv+2, 0);
5437 state->max_data_return = SVAL(req->vwv+3, 0);
5438 state->max_setup_return = SVAL(req->vwv+4, 0);
5439 state->close_on_completion = BITSETW(req->vwv+5, 0);
5440 state->one_way = BITSETW(req->vwv+5, 1);
5442 state->call = tran_call;
5444 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
5445 is so as a sanity check */
5446 if (state->setup_count != 1) {
5448 * Need to have rc=0 for ioctl to get job id for OS/2.
5449 * Network printing will fail if function is not successful.
5450 * Similar function in reply.c will be used if protocol
5451 * is LANMAN1.0 instead of LM1.2X002.
5452 * Until DosPrintSetJobInfo with PRJINFO3 is supported,
5453 * outbuf doesn't have to be set(only job id is used).
5455 if ( (state->setup_count == 4)
5456 && (tran_call == TRANSACT2_IOCTL)
5457 && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
5458 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5459 DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
5460 } else {
5461 DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
5462 DEBUG(2,("Transaction is %d\n",tran_call));
5463 TALLOC_FREE(state);
5464 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5465 END_PROFILE(SMBtrans2);
5466 return;
5470 if ((dscnt > state->total_data) || (pscnt > state->total_param))
5471 goto bad_param;
5473 if (state->total_data) {
5475 if (smb_buffer_oob(state->total_data, 0, dscnt)
5476 || smb_buffer_oob(smb_len(req->inbuf), dsoff, dscnt)) {
5477 goto bad_param;
5480 /* Can't use talloc here, the core routines do realloc on the
5481 * params and data. */
5482 state->data = (char *)SMB_MALLOC(state->total_data);
5483 if (state->data == NULL) {
5484 DEBUG(0,("reply_trans2: data malloc fail for %u "
5485 "bytes !\n", (unsigned int)state->total_data));
5486 TALLOC_FREE(state);
5487 reply_nterror(req, NT_STATUS_NO_MEMORY);
5488 END_PROFILE(SMBtrans2);
5489 return;
5492 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
5495 if (state->total_param) {
5497 if (smb_buffer_oob(state->total_param, 0, pscnt)
5498 || smb_buffer_oob(smb_len(req->inbuf), psoff, pscnt)) {
5499 goto bad_param;
5502 /* Can't use talloc here, the core routines do realloc on the
5503 * params and data. */
5504 state->param = (char *)SMB_MALLOC(state->total_param);
5505 if (state->param == NULL) {
5506 DEBUG(0,("reply_trans: param malloc fail for %u "
5507 "bytes !\n", (unsigned int)state->total_param));
5508 SAFE_FREE(state->data);
5509 TALLOC_FREE(state);
5510 reply_nterror(req, NT_STATUS_NO_MEMORY);
5511 END_PROFILE(SMBtrans2);
5512 return;
5515 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
5518 state->received_data = dscnt;
5519 state->received_param = pscnt;
5521 if ((state->received_param == state->total_param) &&
5522 (state->received_data == state->total_data)) {
5524 handle_trans2(conn, req, state);
5526 SAFE_FREE(state->data);
5527 SAFE_FREE(state->param);
5528 TALLOC_FREE(state);
5529 END_PROFILE(SMBtrans2);
5530 return;
5533 DLIST_ADD(conn->pending_trans, state);
5535 /* We need to send an interim response then receive the rest
5536 of the parameter/data bytes */
5537 reply_smb1_outbuf(req, 0, 0);
5538 show_msg((char *)req->outbuf);
5539 END_PROFILE(SMBtrans2);
5540 return;
5542 bad_param:
5544 DEBUG(0,("reply_trans2: invalid trans parameters\n"));
5545 SAFE_FREE(state->data);
5546 SAFE_FREE(state->param);
5547 TALLOC_FREE(state);
5548 END_PROFILE(SMBtrans2);
5549 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5552 /****************************************************************************
5553 Reply to a SMBtranss2
5554 ****************************************************************************/
5556 void reply_transs2(struct smb_request *req)
5558 connection_struct *conn = req->conn;
5559 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
5560 struct trans_state *state;
5562 START_PROFILE(SMBtranss2);
5564 show_msg((const char *)req->inbuf);
5566 /* Windows clients expect all replies to
5567 a transact secondary (SMBtranss2 0x33)
5568 to have a command code of transact
5569 (SMBtrans2 0x32). See bug #8989
5570 and also [MS-CIFS] section 2.2.4.47.2
5571 for details.
5573 req->cmd = SMBtrans2;
5575 if (req->wct < 8) {
5576 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5577 END_PROFILE(SMBtranss2);
5578 return;
5581 for (state = conn->pending_trans; state != NULL;
5582 state = state->next) {
5583 if (state->mid == req->mid) {
5584 break;
5588 if ((state == NULL) || (state->cmd != SMBtrans2)) {
5589 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5590 END_PROFILE(SMBtranss2);
5591 return;
5594 /* Revise state->total_param and state->total_data in case they have
5595 changed downwards */
5597 if (SVAL(req->vwv+0, 0) < state->total_param)
5598 state->total_param = SVAL(req->vwv+0, 0);
5599 if (SVAL(req->vwv+1, 0) < state->total_data)
5600 state->total_data = SVAL(req->vwv+1, 0);
5602 pcnt = SVAL(req->vwv+2, 0);
5603 poff = SVAL(req->vwv+3, 0);
5604 pdisp = SVAL(req->vwv+4, 0);
5606 dcnt = SVAL(req->vwv+5, 0);
5607 doff = SVAL(req->vwv+6, 0);
5608 ddisp = SVAL(req->vwv+7, 0);
5610 state->received_param += pcnt;
5611 state->received_data += dcnt;
5613 if ((state->received_data > state->total_data) ||
5614 (state->received_param > state->total_param))
5615 goto bad_param;
5617 if (pcnt) {
5618 if (smb_buffer_oob(state->total_param, pdisp, pcnt)
5619 || smb_buffer_oob(smb_len(req->inbuf), poff, pcnt)) {
5620 goto bad_param;
5622 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
5625 if (dcnt) {
5626 if (smb_buffer_oob(state->total_data, ddisp, dcnt)
5627 || smb_buffer_oob(smb_len(req->inbuf), doff, dcnt)) {
5628 goto bad_param;
5630 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
5633 if ((state->received_param < state->total_param) ||
5634 (state->received_data < state->total_data)) {
5635 END_PROFILE(SMBtranss2);
5636 return;
5639 handle_trans2(conn, req, state);
5641 DLIST_REMOVE(conn->pending_trans, state);
5642 SAFE_FREE(state->data);
5643 SAFE_FREE(state->param);
5644 TALLOC_FREE(state);
5646 END_PROFILE(SMBtranss2);
5647 return;
5649 bad_param:
5651 DEBUG(0,("reply_transs2: invalid trans parameters\n"));
5652 DLIST_REMOVE(conn->pending_trans, state);
5653 SAFE_FREE(state->data);
5654 SAFE_FREE(state->param);
5655 TALLOC_FREE(state);
5656 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5657 END_PROFILE(SMBtranss2);