smbd: Simplify an if-condition
[Samba.git] / source3 / smbd / smb1_trans2.c
blobe31bdf02fe8297bc6ba09174d47620ec006df32d
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->posix_flags & FSP_POSIX_FLAGS_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, &smb_fname->st, raw_unixmode,
3174 PERM_NEW_DIR, &unixmode);
3175 if (!NT_STATUS_IS_OK(status)) {
3176 return status;
3179 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3180 if (!NT_STATUS_IS_OK(status)) {
3181 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3182 nt_errstr(status));
3183 return status;
3186 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
3187 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
3189 status = SMB_VFS_CREATE_FILE(
3190 conn, /* conn */
3191 req, /* req */
3192 NULL, /* dirfsp */
3193 smb_fname, /* fname */
3194 FILE_READ_ATTRIBUTES, /* access_mask */
3195 FILE_SHARE_NONE, /* share_access */
3196 FILE_CREATE, /* create_disposition*/
3197 FILE_DIRECTORY_FILE, /* create_options */
3198 0, /* file_attributes */
3199 0, /* oplock_request */
3200 NULL, /* lease */
3201 0, /* allocation_size */
3202 0, /* private_flags */
3203 NULL, /* sd */
3204 NULL, /* ea_list */
3205 &fsp, /* result */
3206 &info, /* pinfo */
3207 posx, /* in_context_blobs */
3208 NULL); /* out_context_blobs */
3210 TALLOC_FREE(posx);
3212 if (NT_STATUS_IS_OK(status)) {
3213 close_file_free(req, &fsp, NORMAL_CLOSE);
3216 info_level_return = SVAL(pdata,16);
3218 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3219 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3220 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3221 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3222 } else {
3223 *pdata_return_size = 12;
3226 /* Realloc the data size */
3227 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3228 if (*ppdata == NULL) {
3229 *pdata_return_size = 0;
3230 return NT_STATUS_NO_MEMORY;
3232 pdata = *ppdata;
3234 SSVAL(pdata,0,NO_OPLOCK_RETURN);
3235 SSVAL(pdata,2,0); /* No fnum. */
3236 SIVAL(pdata,4,info); /* Was directory created. */
3238 switch (info_level_return) {
3239 case SMB_QUERY_FILE_UNIX_BASIC:
3240 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3241 SSVAL(pdata,10,0); /* Padding. */
3242 store_file_unix_basic(conn, pdata + 12, fsp,
3243 &smb_fname->st);
3244 break;
3245 case SMB_QUERY_FILE_UNIX_INFO2:
3246 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3247 SSVAL(pdata,10,0); /* Padding. */
3248 store_file_unix_basic_info2(conn, pdata + 12, fsp,
3249 &smb_fname->st);
3250 break;
3251 default:
3252 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3253 SSVAL(pdata,10,0); /* Padding. */
3254 break;
3257 return status;
3260 /****************************************************************************
3261 Open/Create a file with POSIX semantics.
3262 ****************************************************************************/
3264 #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
3265 #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
3267 static NTSTATUS smb_posix_open(connection_struct *conn,
3268 struct smb_request *req,
3269 char **ppdata,
3270 int total_data,
3271 struct files_struct *dirfsp,
3272 struct smb_filename *smb_fname,
3273 int *pdata_return_size)
3275 bool extended_oplock_granted = False;
3276 char *pdata = *ppdata;
3277 uint32_t flags = 0;
3278 uint32_t wire_open_mode = 0;
3279 uint32_t raw_unixmode = 0;
3280 uint32_t attributes = 0;
3281 uint32_t create_disp = 0;
3282 uint32_t access_mask = 0;
3283 uint32_t create_options = FILE_NON_DIRECTORY_FILE;
3284 NTSTATUS status = NT_STATUS_OK;
3285 mode_t unixmode = (mode_t)0;
3286 files_struct *fsp = NULL;
3287 int oplock_request = 0;
3288 int info = 0;
3289 uint16_t info_level_return = 0;
3290 struct smb2_create_blobs *posx = NULL;
3292 if (total_data < 18) {
3293 return NT_STATUS_INVALID_PARAMETER;
3296 flags = IVAL(pdata,0);
3297 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
3298 if (oplock_request) {
3299 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
3302 wire_open_mode = IVAL(pdata,4);
3304 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
3305 return smb_posix_mkdir(conn, req,
3306 ppdata,
3307 total_data,
3308 smb_fname,
3309 pdata_return_size);
3312 switch (wire_open_mode & SMB_ACCMODE) {
3313 case SMB_O_RDONLY:
3314 access_mask = SMB_O_RDONLY_MAPPING;
3315 break;
3316 case SMB_O_WRONLY:
3317 access_mask = SMB_O_WRONLY_MAPPING;
3318 break;
3319 case SMB_O_RDWR:
3320 access_mask = (SMB_O_RDONLY_MAPPING|
3321 SMB_O_WRONLY_MAPPING);
3322 break;
3323 default:
3324 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
3325 (unsigned int)wire_open_mode ));
3326 return NT_STATUS_INVALID_PARAMETER;
3329 wire_open_mode &= ~SMB_ACCMODE;
3331 /* First take care of O_CREAT|O_EXCL interactions. */
3332 switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
3333 case (SMB_O_CREAT | SMB_O_EXCL):
3334 /* File exists fail. File not exist create. */
3335 create_disp = FILE_CREATE;
3336 break;
3337 case SMB_O_CREAT:
3338 /* File exists open. File not exist create. */
3339 create_disp = FILE_OPEN_IF;
3340 break;
3341 case SMB_O_EXCL:
3342 /* O_EXCL on its own without O_CREAT is undefined.
3343 We deliberately ignore it as some versions of
3344 Linux CIFSFS can send a bare O_EXCL on the
3345 wire which other filesystems in the kernel
3346 ignore. See bug 9519 for details. */
3348 /* Fallthrough. */
3350 case 0:
3351 /* File exists open. File not exist fail. */
3352 create_disp = FILE_OPEN;
3353 break;
3354 default:
3355 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
3356 (unsigned int)wire_open_mode ));
3357 return NT_STATUS_INVALID_PARAMETER;
3360 /* Next factor in the effects of O_TRUNC. */
3361 wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
3363 if (wire_open_mode & SMB_O_TRUNC) {
3364 switch (create_disp) {
3365 case FILE_CREATE:
3366 /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
3367 /* Leave create_disp alone as
3368 (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
3370 /* File exists fail. File not exist create. */
3371 break;
3372 case FILE_OPEN_IF:
3373 /* SMB_O_CREAT | SMB_O_TRUNC */
3374 /* File exists overwrite. File not exist create. */
3375 create_disp = FILE_OVERWRITE_IF;
3376 break;
3377 case FILE_OPEN:
3378 /* SMB_O_TRUNC */
3379 /* File exists overwrite. File not exist fail. */
3380 create_disp = FILE_OVERWRITE;
3381 break;
3382 default:
3383 /* Cannot get here. */
3384 smb_panic("smb_posix_open: logic error");
3385 return NT_STATUS_INVALID_PARAMETER;
3389 raw_unixmode = IVAL(pdata,8);
3390 /* Next 4 bytes are not yet defined. */
3392 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3393 (VALID_STAT(smb_fname->st) ?
3394 PERM_EXISTING_FILE : PERM_NEW_FILE),
3395 &unixmode);
3397 if (!NT_STATUS_IS_OK(status)) {
3398 return status;
3401 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
3402 if (!NT_STATUS_IS_OK(status)) {
3403 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3404 nt_errstr(status));
3405 return status;
3408 if (wire_open_mode & SMB_O_SYNC) {
3409 create_options |= FILE_WRITE_THROUGH;
3411 if (wire_open_mode & SMB_O_APPEND) {
3412 access_mask |= FILE_APPEND_DATA;
3414 if (wire_open_mode & SMB_O_DIRECT) {
3416 * BUG: this doesn't work anymore since
3417 * e0814dc5082dd4ecca8a155e0ce24b073158fd92. But since
3418 * FILE_FLAG_NO_BUFFERING isn't used at all in the IO codepath,
3419 * it doesn't really matter.
3421 attributes |= FILE_FLAG_NO_BUFFERING;
3424 if ((wire_open_mode & SMB_O_DIRECTORY) ||
3425 VALID_STAT_OF_DIR(smb_fname->st)) {
3426 if (access_mask != SMB_O_RDONLY_MAPPING) {
3427 return NT_STATUS_FILE_IS_A_DIRECTORY;
3429 create_options &= ~FILE_NON_DIRECTORY_FILE;
3430 create_options |= FILE_DIRECTORY_FILE;
3433 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
3434 smb_fname_str_dbg(smb_fname),
3435 (unsigned int)wire_open_mode,
3436 (unsigned int)unixmode ));
3438 status = SMB_VFS_CREATE_FILE(
3439 conn, /* conn */
3440 req, /* req */
3441 dirfsp, /* dirfsp */
3442 smb_fname, /* fname */
3443 access_mask, /* access_mask */
3444 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3445 FILE_SHARE_DELETE),
3446 create_disp, /* create_disposition*/
3447 create_options, /* create_options */
3448 attributes, /* file_attributes */
3449 oplock_request, /* oplock_request */
3450 NULL, /* lease */
3451 0, /* allocation_size */
3452 0, /* private_flags */
3453 NULL, /* sd */
3454 NULL, /* ea_list */
3455 &fsp, /* result */
3456 &info, /* pinfo */
3457 posx, /* in_context_blobs */
3458 NULL); /* out_context_blobs */
3460 TALLOC_FREE(posx);
3462 if (!NT_STATUS_IS_OK(status)) {
3463 return status;
3466 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
3467 extended_oplock_granted = True;
3470 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3471 extended_oplock_granted = True;
3474 info_level_return = SVAL(pdata,16);
3476 /* Allocate the correct return size. */
3478 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
3479 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
3480 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
3481 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
3482 } else {
3483 *pdata_return_size = 12;
3486 /* Realloc the data size */
3487 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
3488 if (*ppdata == NULL) {
3489 close_file_free(req, &fsp, ERROR_CLOSE);
3490 *pdata_return_size = 0;
3491 return NT_STATUS_NO_MEMORY;
3493 pdata = *ppdata;
3495 if (extended_oplock_granted) {
3496 if (flags & REQUEST_BATCH_OPLOCK) {
3497 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
3498 } else {
3499 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
3501 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
3502 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
3503 } else {
3504 SSVAL(pdata,0,NO_OPLOCK_RETURN);
3507 SSVAL(pdata,2,fsp->fnum);
3508 SIVAL(pdata,4,info); /* Was file created etc. */
3510 switch (info_level_return) {
3511 case SMB_QUERY_FILE_UNIX_BASIC:
3512 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
3513 SSVAL(pdata,10,0); /* padding. */
3514 store_file_unix_basic(conn, pdata + 12, fsp,
3515 &smb_fname->st);
3516 break;
3517 case SMB_QUERY_FILE_UNIX_INFO2:
3518 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
3519 SSVAL(pdata,10,0); /* padding. */
3520 store_file_unix_basic_info2(conn, pdata + 12, fsp,
3521 &smb_fname->st);
3522 break;
3523 default:
3524 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
3525 SSVAL(pdata,10,0); /* padding. */
3526 break;
3528 return NT_STATUS_OK;
3531 /****************************************************************************
3532 Delete a file with POSIX semantics.
3533 ****************************************************************************/
3535 struct smb_posix_unlink_state {
3536 struct smb_filename *smb_fname;
3537 struct files_struct *fsp;
3538 NTSTATUS status;
3541 static void smb_posix_unlink_locked(struct share_mode_lock *lck,
3542 void *private_data)
3544 struct smb_posix_unlink_state *state = private_data;
3545 char del = 1;
3546 bool other_nonposix_opens;
3548 other_nonposix_opens = has_other_nonposix_opens(lck, state->fsp);
3549 if (other_nonposix_opens) {
3550 /* Fail with sharing violation. */
3551 state->status = NT_STATUS_SHARING_VIOLATION;
3552 return;
3556 * Set the delete on close.
3558 state->status = smb_set_file_disposition_info(state->fsp->conn,
3559 &del,
3561 state->fsp,
3562 state->smb_fname);
3565 static NTSTATUS smb_posix_unlink(connection_struct *conn,
3566 struct smb_request *req,
3567 const char *pdata,
3568 int total_data,
3569 struct files_struct *dirfsp,
3570 struct smb_filename *smb_fname)
3572 struct smb_posix_unlink_state state = {};
3573 NTSTATUS status = NT_STATUS_OK;
3574 files_struct *fsp = NULL;
3575 uint16_t flags = 0;
3576 int info = 0;
3577 int create_options = FILE_OPEN_REPARSE_POINT;
3578 struct smb2_create_blobs *posx = NULL;
3580 if (!CAN_WRITE(conn)) {
3581 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3584 if (total_data < 2) {
3585 return NT_STATUS_INVALID_PARAMETER;
3588 flags = SVAL(pdata,0);
3590 if (!VALID_STAT(smb_fname->st)) {
3591 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3594 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
3595 !VALID_STAT_OF_DIR(smb_fname->st)) {
3596 return NT_STATUS_NOT_A_DIRECTORY;
3599 DEBUG(10,("smb_posix_unlink: %s %s\n",
3600 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
3601 smb_fname_str_dbg(smb_fname)));
3603 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
3604 create_options |= FILE_DIRECTORY_FILE;
3607 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
3608 if (!NT_STATUS_IS_OK(status)) {
3609 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
3610 nt_errstr(status));
3611 return status;
3614 status = SMB_VFS_CREATE_FILE(
3615 conn, /* conn */
3616 req, /* req */
3617 dirfsp, /* dirfsp */
3618 smb_fname, /* fname */
3619 DELETE_ACCESS, /* access_mask */
3620 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
3621 FILE_SHARE_DELETE),
3622 FILE_OPEN, /* create_disposition*/
3623 create_options, /* create_options */
3624 0, /* file_attributes */
3625 0, /* oplock_request */
3626 NULL, /* lease */
3627 0, /* allocation_size */
3628 0, /* private_flags */
3629 NULL, /* sd */
3630 NULL, /* ea_list */
3631 &fsp, /* result */
3632 &info, /* pinfo */
3633 posx, /* in_context_blobs */
3634 NULL); /* out_context_blobs */
3636 TALLOC_FREE(posx);
3638 if (!NT_STATUS_IS_OK(status)) {
3639 return status;
3643 * Don't lie to client. If we can't really delete due to
3644 * non-POSIX opens return SHARING_VIOLATION.
3647 state = (struct smb_posix_unlink_state) {
3648 .smb_fname = smb_fname,
3649 .fsp = fsp,
3652 status = share_mode_do_locked_vfs_allowed(fsp->file_id,
3653 smb_posix_unlink_locked,
3654 &state);
3655 if (!NT_STATUS_IS_OK(status)) {
3656 DBG_ERR("share_mode_do_locked_vfs_allowed(%s) failed - %s\n",
3657 fsp_str_dbg(fsp), nt_errstr(status));
3658 close_file_free(req, &fsp, NORMAL_CLOSE);
3659 return NT_STATUS_INVALID_PARAMETER;
3662 status = state.status;
3663 if (!NT_STATUS_IS_OK(status)) {
3664 close_file_free(req, &fsp, NORMAL_CLOSE);
3665 return status;
3667 return close_file_free(req, &fsp, NORMAL_CLOSE);
3670 /****************************************************************************
3671 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
3672 ****************************************************************************/
3674 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
3675 struct smb_request *req,
3676 const char *pdata,
3677 int total_data,
3678 struct files_struct *dirfsp,
3679 struct smb_filename *new_smb_fname)
3681 char *link_target = NULL;
3682 struct smb_filename target_fname;
3683 TALLOC_CTX *ctx = talloc_tos();
3684 struct smb_filename new_smb_fname_rel = {};
3685 char *slash = NULL;
3686 NTSTATUS status;
3687 int ret;
3689 if (!CAN_WRITE(conn)) {
3690 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3693 /* Set a symbolic link. */
3694 /* Don't allow this if follow links is false. */
3696 if (total_data == 0) {
3697 return NT_STATUS_INVALID_PARAMETER;
3700 if (!lp_follow_symlinks(SNUM(conn))) {
3701 return NT_STATUS_ACCESS_DENIED;
3704 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
3705 total_data, STR_TERMINATE);
3707 if (!link_target) {
3708 return NT_STATUS_INVALID_PARAMETER;
3711 target_fname = (struct smb_filename) {
3712 .base_name = link_target,
3715 /* Removes @GMT tokens if any */
3716 status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
3717 if (!NT_STATUS_IS_OK(status)) {
3718 return status;
3721 DBG_DEBUG("SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
3722 new_smb_fname->base_name, link_target);
3724 new_smb_fname_rel = *new_smb_fname;
3725 slash = strrchr_m(new_smb_fname_rel.base_name, '/');
3726 if (slash != NULL) {
3727 new_smb_fname_rel.base_name = slash + 1;
3730 ret = SMB_VFS_SYMLINKAT(conn,
3731 &target_fname,
3732 dirfsp,
3733 &new_smb_fname_rel);
3734 if (ret != 0) {
3735 return map_nt_error_from_unix(errno);
3738 return NT_STATUS_OK;
3741 /****************************************************************************
3742 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
3743 ****************************************************************************/
3745 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
3746 struct smb_request *req,
3747 const char *pdata, int total_data,
3748 struct smb_filename *smb_fname_new)
3750 char *oldname = NULL;
3751 struct files_struct *src_dirfsp = NULL;
3752 struct smb_filename *smb_fname_old = NULL;
3753 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
3754 NTTIME old_twrp = 0;
3755 TALLOC_CTX *ctx = talloc_tos();
3756 NTSTATUS status = NT_STATUS_OK;
3758 if (!CAN_WRITE(conn)) {
3759 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3762 /* Set a hard link. */
3763 if (total_data == 0) {
3764 return NT_STATUS_INVALID_PARAMETER;
3767 if (req->posix_pathnames) {
3768 srvstr_get_path_posix(ctx,
3769 pdata,
3770 req->flags2,
3771 &oldname,
3772 pdata,
3773 total_data,
3774 STR_TERMINATE,
3775 &status);
3776 } else {
3777 srvstr_get_path(ctx,
3778 pdata,
3779 req->flags2,
3780 &oldname,
3781 pdata,
3782 total_data,
3783 STR_TERMINATE,
3784 &status);
3786 if (!NT_STATUS_IS_OK(status)) {
3787 return status;
3790 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
3791 smb_fname_str_dbg(smb_fname_new), oldname));
3793 if (ucf_flags & UCF_GMT_PATHNAME) {
3794 extract_snapshot_token(oldname, &old_twrp);
3796 status = smb1_strip_dfs_path(ctx, &ucf_flags, &oldname);
3797 if (!NT_STATUS_IS_OK(status)) {
3798 return status;
3800 status = filename_convert_dirfsp(ctx,
3801 conn,
3802 oldname,
3803 ucf_flags,
3804 old_twrp,
3805 &src_dirfsp,
3806 &smb_fname_old);
3807 if (!NT_STATUS_IS_OK(status)) {
3808 return status;
3811 return hardlink_internals(ctx,
3812 conn,
3813 req,
3814 false,
3815 smb_fname_old,
3816 smb_fname_new);
3819 /****************************************************************************
3820 Allow a UNIX info mknod.
3821 ****************************************************************************/
3823 static NTSTATUS smb_unix_mknod(connection_struct *conn,
3824 const char *pdata,
3825 int total_data,
3826 struct files_struct *dirfsp,
3827 const struct smb_filename *smb_fname)
3829 uint32_t file_type = IVAL(pdata,56);
3830 #if defined(HAVE_MAKEDEV)
3831 uint32_t dev_major = IVAL(pdata,60);
3832 uint32_t dev_minor = IVAL(pdata,68);
3833 #endif
3834 SMB_DEV_T dev = (SMB_DEV_T)0;
3835 uint32_t raw_unixmode = IVAL(pdata,84);
3836 NTSTATUS status;
3837 mode_t unixmode;
3838 int ret;
3839 struct smb_filename *parent_fname = NULL;
3840 struct smb_filename *atname = NULL;
3842 if (total_data < 100) {
3843 return NT_STATUS_INVALID_PARAMETER;
3846 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3847 PERM_NEW_FILE, &unixmode);
3848 if (!NT_STATUS_IS_OK(status)) {
3849 return status;
3852 #if defined(HAVE_MAKEDEV)
3853 dev = makedev(dev_major, dev_minor);
3854 #endif
3856 switch (file_type) {
3857 /* We can't create other objects here. */
3858 case UNIX_TYPE_FILE:
3859 case UNIX_TYPE_DIR:
3860 case UNIX_TYPE_SYMLINK:
3861 return NT_STATUS_ACCESS_DENIED;
3862 #if defined(S_IFIFO)
3863 case UNIX_TYPE_FIFO:
3864 unixmode |= S_IFIFO;
3865 break;
3866 #endif
3867 #if defined(S_IFSOCK)
3868 case UNIX_TYPE_SOCKET:
3869 unixmode |= S_IFSOCK;
3870 break;
3871 #endif
3872 #if defined(S_IFCHR)
3873 case UNIX_TYPE_CHARDEV:
3874 /* This is only allowed for root. */
3875 if (get_current_uid(conn) != sec_initial_uid()) {
3876 return NT_STATUS_ACCESS_DENIED;
3878 unixmode |= S_IFCHR;
3879 break;
3880 #endif
3881 #if defined(S_IFBLK)
3882 case UNIX_TYPE_BLKDEV:
3883 if (get_current_uid(conn) != sec_initial_uid()) {
3884 return NT_STATUS_ACCESS_DENIED;
3886 unixmode |= S_IFBLK;
3887 break;
3888 #endif
3889 default:
3890 return NT_STATUS_INVALID_PARAMETER;
3893 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
3894 "%.0f mode 0%o for file %s\n", (double)dev,
3895 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
3897 status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
3898 talloc_tos(),
3899 smb_fname,
3900 &parent_fname,
3901 &atname);
3902 if (!NT_STATUS_IS_OK(status)) {
3903 return status;
3906 /* Ok - do the mknod. */
3907 ret = SMB_VFS_MKNODAT(conn,
3908 dirfsp,
3909 atname,
3910 unixmode,
3911 dev);
3913 if (ret != 0) {
3914 TALLOC_FREE(parent_fname);
3915 return map_nt_error_from_unix(errno);
3918 /* If any of the other "set" calls fail we
3919 * don't want to end up with a half-constructed mknod.
3922 if (lp_inherit_permissions(SNUM(conn))) {
3923 inherit_access_posix_acl(conn,
3924 dirfsp,
3925 smb_fname,
3926 unixmode);
3928 TALLOC_FREE(parent_fname);
3930 return NT_STATUS_OK;
3933 /****************************************************************************
3934 Deal with SMB_SET_FILE_UNIX_BASIC.
3935 ****************************************************************************/
3937 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
3938 struct smb_request *req,
3939 const char *pdata,
3940 int total_data,
3941 struct files_struct *dirfsp,
3942 files_struct *fsp,
3943 struct smb_filename *smb_fname)
3945 struct smb_file_time ft;
3946 uint32_t raw_unixmode;
3947 mode_t unixmode;
3948 off_t size = 0;
3949 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
3950 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
3951 NTSTATUS status = NT_STATUS_OK;
3952 enum perm_type ptype;
3953 files_struct *all_fsps = NULL;
3954 bool modify_mtime = true;
3955 struct file_id id;
3956 SMB_STRUCT_STAT sbuf;
3958 if (!CAN_WRITE(conn)) {
3959 return NT_STATUS_DOS(ERRSRV, ERRaccess);
3962 init_smb_file_time(&ft);
3964 if (total_data < 100) {
3965 return NT_STATUS_INVALID_PARAMETER;
3968 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
3969 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
3970 size=IVAL(pdata,0); /* first 8 Bytes are size */
3971 size |= (((off_t)IVAL(pdata,4)) << 32);
3974 ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
3975 ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
3976 set_owner = (uid_t)IVAL(pdata,40);
3977 set_grp = (gid_t)IVAL(pdata,48);
3978 raw_unixmode = IVAL(pdata,84);
3980 if (VALID_STAT(smb_fname->st)) {
3981 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
3982 ptype = PERM_EXISTING_DIR;
3983 } else {
3984 ptype = PERM_EXISTING_FILE;
3986 } else {
3987 ptype = PERM_NEW_FILE;
3990 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
3991 ptype, &unixmode);
3992 if (!NT_STATUS_IS_OK(status)) {
3993 return status;
3996 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
3997 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
3998 smb_fname_str_dbg(smb_fname), (double)size,
3999 (unsigned int)set_owner, (unsigned int)set_grp,
4000 (int)raw_unixmode));
4002 sbuf = smb_fname->st;
4004 if (!VALID_STAT(sbuf)) {
4006 * The only valid use of this is to create character and block
4007 * devices, and named pipes. This is deprecated (IMHO) and
4008 * a new info level should be used for mknod. JRA.
4011 if (dirfsp == NULL) {
4012 return NT_STATUS_INVALID_PARAMETER;
4015 return smb_unix_mknod(conn,
4016 pdata,
4017 total_data,
4018 dirfsp,
4019 smb_fname);
4022 #if 1
4023 /* Horrible backwards compatibility hack as an old server bug
4024 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
4025 * */
4027 if (!size) {
4028 size = get_file_size_stat(&sbuf);
4030 #endif
4033 * Deal with the UNIX specific mode set.
4036 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
4037 int ret;
4039 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4040 DBG_WARNING("Can't set mode on symlink %s\n",
4041 smb_fname_str_dbg(smb_fname));
4042 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4045 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4046 "setting mode 0%o for file %s\n",
4047 (unsigned int)unixmode,
4048 smb_fname_str_dbg(smb_fname)));
4049 ret = SMB_VFS_FCHMOD(fsp, unixmode);
4050 if (ret != 0) {
4051 return map_nt_error_from_unix(errno);
4056 * Deal with the UNIX specific uid set.
4059 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
4060 (sbuf.st_ex_uid != set_owner)) {
4061 int ret;
4063 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4064 "changing owner %u for path %s\n",
4065 (unsigned int)set_owner,
4066 smb_fname_str_dbg(smb_fname)));
4068 if (fsp &&
4069 !fsp->fsp_flags.is_pathref &&
4070 fsp_get_io_fd(fsp) != -1)
4072 ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
4073 } else {
4075 * UNIX extensions calls must always operate
4076 * on symlinks.
4078 ret = SMB_VFS_LCHOWN(conn, smb_fname,
4079 set_owner, (gid_t)-1);
4082 if (ret != 0) {
4083 status = map_nt_error_from_unix(errno);
4084 return status;
4089 * Deal with the UNIX specific gid set.
4092 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
4093 (sbuf.st_ex_gid != set_grp)) {
4094 int ret;
4096 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
4097 "changing group %u for file %s\n",
4098 (unsigned int)set_grp,
4099 smb_fname_str_dbg(smb_fname)));
4100 if (fsp &&
4101 !fsp->fsp_flags.is_pathref &&
4102 fsp_get_io_fd(fsp) != -1)
4104 ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
4105 } else {
4107 * UNIX extensions calls must always operate
4108 * on symlinks.
4110 ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
4111 set_grp);
4113 if (ret != 0) {
4114 status = map_nt_error_from_unix(errno);
4115 return status;
4119 /* Deal with any size changes. */
4121 if (S_ISREG(sbuf.st_ex_mode)) {
4122 status = smb_set_file_size(conn, req,
4123 fsp,
4124 smb_fname,
4125 &sbuf,
4126 size,
4127 false);
4128 if (!NT_STATUS_IS_OK(status)) {
4129 return status;
4133 /* Deal with any time changes. */
4134 if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
4135 /* No change, don't cancel anything. */
4136 return status;
4139 id = vfs_file_id_from_sbuf(conn, &sbuf);
4140 for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
4141 all_fsps = file_find_di_next(all_fsps, true)) {
4143 * We're setting the time explicitly for UNIX.
4144 * Cancel any pending changes over all handles.
4146 all_fsps->fsp_flags.update_write_time_on_close = false;
4147 TALLOC_FREE(all_fsps->update_write_time_event);
4151 * Override the "setting_write_time"
4152 * parameter here as it almost does what
4153 * we need. Just remember if we modified
4154 * mtime and send the notify ourselves.
4156 if (is_omit_timespec(&ft.mtime)) {
4157 modify_mtime = false;
4160 status = smb_set_file_time(conn,
4161 fsp,
4162 smb_fname,
4163 &ft,
4164 false);
4165 if (modify_mtime) {
4166 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
4167 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
4169 return status;
4172 /****************************************************************************
4173 Deal with SMB_SET_FILE_UNIX_INFO2.
4174 ****************************************************************************/
4176 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
4177 struct smb_request *req,
4178 const char *pdata,
4179 int total_data,
4180 struct files_struct *dirfsp,
4181 files_struct *fsp,
4182 struct smb_filename *smb_fname)
4184 NTSTATUS status;
4185 uint32_t smb_fflags;
4186 uint32_t smb_fmask;
4188 if (!CAN_WRITE(conn)) {
4189 return NT_STATUS_DOS(ERRSRV, ERRaccess);
4192 if (total_data < 116) {
4193 return NT_STATUS_INVALID_PARAMETER;
4196 /* Start by setting all the fields that are common between UNIX_BASIC
4197 * and UNIX_INFO2.
4199 status = smb_set_file_unix_basic(conn,
4200 req,
4201 pdata,
4202 total_data,
4203 dirfsp,
4204 fsp,
4205 smb_fname);
4206 if (!NT_STATUS_IS_OK(status)) {
4207 return status;
4210 smb_fflags = IVAL(pdata, 108);
4211 smb_fmask = IVAL(pdata, 112);
4213 /* NB: We should only attempt to alter the file flags if the client
4214 * sends a non-zero mask.
4216 if (smb_fmask != 0) {
4217 int stat_fflags = 0;
4219 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
4220 smb_fmask, &stat_fflags)) {
4221 /* Client asked to alter a flag we don't understand. */
4222 return NT_STATUS_INVALID_PARAMETER;
4225 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
4226 DBG_WARNING("Can't change flags on symlink %s\n",
4227 smb_fname_str_dbg(smb_fname));
4228 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4230 if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
4231 return map_nt_error_from_unix(errno);
4235 /* XXX: need to add support for changing the create_time here. You
4236 * can do this for paths on Darwin with setattrlist(2). The right way
4237 * to hook this up is probably by extending the VFS utimes interface.
4240 return NT_STATUS_OK;
4243 /****************************************************************************
4244 Deal with SMB_SET_POSIX_ACL.
4245 ****************************************************************************/
4247 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
4248 struct smb_request *req,
4249 const char *pdata,
4250 int total_data_in,
4251 files_struct *fsp,
4252 struct smb_filename *smb_fname)
4254 #if !defined(HAVE_POSIX_ACLS)
4255 return NT_STATUS_INVALID_LEVEL;
4256 #else
4257 uint16_t posix_acl_version;
4258 uint16_t num_file_acls;
4259 uint16_t num_def_acls;
4260 bool valid_file_acls = true;
4261 bool valid_def_acls = true;
4262 NTSTATUS status;
4263 unsigned int size_needed;
4264 unsigned int total_data;
4265 bool close_fsp = false;
4267 if (total_data_in < 0) {
4268 status = NT_STATUS_INVALID_PARAMETER;
4269 goto out;
4272 total_data = total_data_in;
4274 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
4275 status = NT_STATUS_INVALID_PARAMETER;
4276 goto out;
4278 posix_acl_version = SVAL(pdata,0);
4279 num_file_acls = SVAL(pdata,2);
4280 num_def_acls = SVAL(pdata,4);
4282 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4283 valid_file_acls = false;
4284 num_file_acls = 0;
4287 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
4288 valid_def_acls = false;
4289 num_def_acls = 0;
4292 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
4293 status = NT_STATUS_INVALID_PARAMETER;
4294 goto out;
4297 /* Wrap checks. */
4298 if (num_file_acls + num_def_acls < num_file_acls) {
4299 status = NT_STATUS_INVALID_PARAMETER;
4300 goto out;
4303 size_needed = num_file_acls + num_def_acls;
4306 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
4307 * than UINT_MAX, so check by division.
4309 if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
4310 status = NT_STATUS_INVALID_PARAMETER;
4311 goto out;
4314 size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
4315 if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
4316 status = NT_STATUS_INVALID_PARAMETER;
4317 goto out;
4319 size_needed += SMB_POSIX_ACL_HEADER_SIZE;
4321 if (total_data < size_needed) {
4322 status = NT_STATUS_INVALID_PARAMETER;
4323 goto out;
4327 * Ensure we always operate on a file descriptor, not just
4328 * the filename.
4330 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
4331 uint32_t access_mask = SEC_STD_WRITE_OWNER|
4332 SEC_STD_WRITE_DAC|
4333 SEC_STD_READ_CONTROL|
4334 FILE_READ_ATTRIBUTES|
4335 FILE_WRITE_ATTRIBUTES;
4337 status = get_posix_fsp(conn,
4338 req,
4339 smb_fname,
4340 access_mask,
4341 &fsp);
4343 if (!NT_STATUS_IS_OK(status)) {
4344 goto out;
4346 close_fsp = true;
4349 /* Here we know fsp != NULL */
4350 SMB_ASSERT(fsp != NULL);
4352 status = refuse_symlink_fsp(fsp);
4353 if (!NT_STATUS_IS_OK(status)) {
4354 goto out;
4357 /* If we have a default acl, this *must* be a directory. */
4358 if (valid_def_acls && !fsp->fsp_flags.is_directory) {
4359 DBG_INFO("Can't set default acls on "
4360 "non-directory %s\n",
4361 fsp_str_dbg(fsp));
4362 return NT_STATUS_INVALID_HANDLE;
4365 DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
4366 "num_def_acls = %"PRIu16"\n",
4367 fsp_str_dbg(fsp),
4368 num_file_acls,
4369 num_def_acls);
4371 /* Move pdata to the start of the file ACL entries. */
4372 pdata += SMB_POSIX_ACL_HEADER_SIZE;
4374 if (valid_file_acls) {
4375 status = set_unix_posix_acl(conn,
4376 fsp,
4377 num_file_acls,
4378 pdata);
4379 if (!NT_STATUS_IS_OK(status)) {
4380 goto out;
4384 /* Move pdata to the start of the default ACL entries. */
4385 pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
4387 if (valid_def_acls) {
4388 status = set_unix_posix_default_acl(conn,
4389 fsp,
4390 num_def_acls,
4391 pdata);
4392 if (!NT_STATUS_IS_OK(status)) {
4393 goto out;
4397 status = NT_STATUS_OK;
4399 out:
4401 if (close_fsp) {
4402 (void)close_file_free(req, &fsp, NORMAL_CLOSE);
4404 return status;
4405 #endif
4408 static void call_trans2setpathinfo(
4409 connection_struct *conn,
4410 struct smb_request *req,
4411 char **pparams,
4412 int total_params,
4413 char **ppdata,
4414 int total_data,
4415 unsigned int max_data_bytes)
4417 uint16_t info_level;
4418 struct smb_filename *smb_fname = NULL;
4419 struct files_struct *dirfsp = NULL;
4420 struct files_struct *fsp = NULL;
4421 char *params = *pparams;
4422 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4423 NTTIME twrp = 0;
4424 char *fname = NULL;
4425 bool info_level_handled;
4426 int data_return_size = 0;
4427 NTSTATUS status;
4429 if (params == NULL) {
4430 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4431 return;
4434 /* set path info */
4435 if (total_params < 7) {
4436 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4437 return;
4440 info_level = SVAL(params,0);
4442 if (INFO_LEVEL_IS_UNIX(info_level)) {
4443 if (!lp_smb1_unix_extensions()) {
4444 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4445 return;
4447 if (!req->posix_pathnames) {
4448 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4449 return;
4453 if (req->posix_pathnames) {
4454 srvstr_get_path_posix(req,
4455 params,
4456 req->flags2,
4457 &fname,
4458 &params[6],
4459 total_params - 6,
4460 STR_TERMINATE,
4461 &status);
4462 } else {
4463 srvstr_get_path(req,
4464 params,
4465 req->flags2,
4466 &fname,
4467 &params[6],
4468 total_params - 6,
4469 STR_TERMINATE,
4470 &status);
4472 if (!NT_STATUS_IS_OK(status)) {
4473 reply_nterror(req, status);
4474 return;
4477 DBG_NOTICE("fname=%s info_level=%d totdata=%d\n",
4478 fname,
4479 info_level,
4480 total_data);
4482 if (ucf_flags & UCF_GMT_PATHNAME) {
4483 extract_snapshot_token(fname, &twrp);
4485 status = smb1_strip_dfs_path(req, &ucf_flags, &fname);
4486 if (!NT_STATUS_IS_OK(status)) {
4487 reply_nterror(req, status);
4488 return;
4490 status = filename_convert_dirfsp(req,
4491 conn,
4492 fname,
4493 ucf_flags,
4494 twrp,
4495 &dirfsp,
4496 &smb_fname);
4497 if (!NT_STATUS_IS_OK(status)) {
4498 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4499 reply_botherror(req,
4500 NT_STATUS_PATH_NOT_COVERED,
4501 ERRSRV, ERRbadpath);
4502 return;
4504 reply_nterror(req, status);
4505 return;
4508 info_level_handled = true; /* Untouched in switch cases below */
4510 switch (info_level) {
4512 default:
4513 info_level_handled = false;
4514 break;
4516 case SMB_POSIX_PATH_OPEN:
4517 status = smb_posix_open(conn,
4518 req,
4519 ppdata,
4520 total_data,
4521 dirfsp,
4522 smb_fname,
4523 &data_return_size);
4524 break;
4526 case SMB_POSIX_PATH_UNLINK:
4527 status = smb_posix_unlink(conn,
4528 req,
4529 *ppdata,
4530 total_data,
4531 dirfsp,
4532 smb_fname);
4533 break;
4535 case SMB_SET_FILE_UNIX_LINK:
4536 status = smb_set_file_unix_link(
4537 conn, req, *ppdata, total_data, dirfsp, smb_fname);
4538 break;
4540 case SMB_SET_FILE_UNIX_HLINK:
4541 status = smb_set_file_unix_hlink(
4542 conn, req, *ppdata, total_data, smb_fname);
4543 break;
4545 case SMB_SET_FILE_UNIX_BASIC:
4546 status = smb_set_file_unix_basic(conn,
4547 req,
4548 *ppdata,
4549 total_data,
4550 dirfsp,
4551 smb_fname->fsp,
4552 smb_fname);
4553 break;
4555 case SMB_SET_FILE_UNIX_INFO2:
4556 status = smb_set_file_unix_info2(conn,
4557 req,
4558 *ppdata,
4559 total_data,
4560 dirfsp,
4561 smb_fname->fsp,
4562 smb_fname);
4563 break;
4564 case SMB_SET_POSIX_ACL:
4565 status = smb_set_posix_acl(
4566 conn, req, *ppdata, total_data, NULL, smb_fname);
4567 break;
4570 if (info_level_handled) {
4571 handle_trans2setfilepathinfo_result(
4572 conn,
4573 req,
4574 info_level,
4575 status,
4576 *ppdata,
4577 data_return_size,
4578 max_data_bytes);
4579 return;
4583 * smb_fname->fsp may be NULL if smb_fname points at a symlink
4584 * and we're in POSIX context, so be careful when using fsp
4585 * below, it can still be NULL.
4587 fsp = smb_fname->fsp;
4589 status = smbd_do_setfilepathinfo(
4590 conn,
4591 req,
4592 req,
4593 info_level,
4594 fsp,
4595 smb_fname,
4596 ppdata,
4597 total_data,
4598 &data_return_size);
4600 handle_trans2setfilepathinfo_result(
4601 conn,
4602 req,
4603 info_level,
4604 status,
4605 *ppdata,
4606 data_return_size,
4607 max_data_bytes);
4610 static void call_trans2setfileinfo(
4611 connection_struct *conn,
4612 struct smb_request *req,
4613 char **pparams,
4614 int total_params,
4615 char **ppdata,
4616 int total_data,
4617 unsigned int max_data_bytes)
4619 char *pdata = *ppdata;
4620 uint16_t info_level;
4621 struct smb_filename *smb_fname = NULL;
4622 struct files_struct *fsp = NULL;
4623 char *params = *pparams;
4624 int data_return_size = 0;
4625 bool info_level_handled;
4626 NTSTATUS status;
4627 int ret;
4629 if (params == NULL) {
4630 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4631 return;
4633 if (total_params < 4) {
4634 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4635 return;
4638 fsp = file_fsp(req, SVAL(params,0));
4639 /* Basic check for non-null fsp. */
4640 if (!check_fsp_open(conn, req, fsp)) {
4641 return;
4643 info_level = SVAL(params,2);
4645 if (INFO_LEVEL_IS_UNIX(info_level)) {
4646 if (!lp_smb1_unix_extensions()) {
4647 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4648 return;
4650 if (!req->posix_pathnames) {
4651 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4652 return;
4656 smb_fname = fsp->fsp_name;
4658 DBG_NOTICE("fnum=%s fname=%s info_level=%d totdata=%d\n",
4659 fsp_fnum_dbg(fsp),
4660 fsp_str_dbg(fsp),
4661 info_level,
4662 total_data);
4664 if (fsp_get_pathref_fd(fsp) == -1) {
4666 * This is actually a SETFILEINFO on a directory
4667 * handle (returned from an NT SMB). NT5.0 seems
4668 * to do this call. JRA.
4670 ret = vfs_stat(conn, smb_fname);
4671 if (ret != 0) {
4672 DBG_NOTICE("vfs_stat of %s failed (%s)\n",
4673 smb_fname_str_dbg(smb_fname),
4674 strerror(errno));
4675 reply_nterror(req, map_nt_error_from_unix(errno));
4676 return;
4678 } else if (fsp->print_file) {
4680 * Doing a DELETE_ON_CLOSE should cancel a print job.
4682 if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) &&
4683 CVAL(pdata,0)) {
4685 fsp->fsp_flags.delete_on_close = true;
4687 DBG_NOTICE("Cancelling print job (%s)\n",
4688 fsp_str_dbg(fsp));
4690 SSVAL(params,0,0);
4691 send_trans2_replies(
4692 conn,
4693 req,
4694 NT_STATUS_OK,
4695 params,
4697 *ppdata, 0,
4698 max_data_bytes);
4699 return;
4700 } else {
4701 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
4702 return;
4704 } else {
4706 * Original code - this is an open file.
4708 status = vfs_stat_fsp(fsp);
4709 if (!NT_STATUS_IS_OK(status)) {
4710 DBG_NOTICE("fstat of %s failed (%s)\n",
4711 fsp_fnum_dbg(fsp),
4712 nt_errstr(status));
4713 reply_nterror(req, status);
4714 return;
4718 info_level_handled = true; /* Untouched in switch cases below */
4720 switch (info_level) {
4722 default:
4723 info_level_handled = false;
4724 break;
4726 case SMB_SET_FILE_UNIX_BASIC:
4727 status = smb_set_file_unix_basic(conn,
4728 req,
4729 pdata,
4730 total_data,
4731 NULL,
4732 fsp,
4733 smb_fname);
4734 break;
4736 case SMB_SET_FILE_UNIX_INFO2:
4737 status = smb_set_file_unix_info2(conn,
4738 req,
4739 pdata,
4740 total_data,
4741 NULL,
4742 fsp,
4743 smb_fname);
4744 break;
4746 case SMB_SET_POSIX_LOCK:
4747 status = smb_set_posix_lock(
4748 conn, req, *ppdata, total_data, fsp);
4749 break;
4752 if (info_level_handled) {
4753 handle_trans2setfilepathinfo_result(
4754 conn,
4755 req,
4756 info_level,
4757 status,
4758 *ppdata,
4759 data_return_size,
4760 max_data_bytes);
4761 return;
4764 status = smbd_do_setfilepathinfo(
4765 conn,
4766 req,
4767 req,
4768 info_level,
4769 fsp,
4770 smb_fname,
4771 ppdata,
4772 total_data,
4773 &data_return_size);
4775 handle_trans2setfilepathinfo_result(
4776 conn,
4777 req,
4778 info_level,
4779 status,
4780 *ppdata,
4781 data_return_size,
4782 max_data_bytes);
4785 /****************************************************************************
4786 Reply to a TRANS2_MKDIR (make directory with extended attributes).
4787 ****************************************************************************/
4789 static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
4790 char **pparams, int total_params,
4791 char **ppdata, int total_data,
4792 unsigned int max_data_bytes)
4794 struct files_struct *dirfsp = NULL;
4795 struct files_struct *fsp = NULL;
4796 struct smb_filename *smb_dname = NULL;
4797 char *params = *pparams;
4798 char *pdata = *ppdata;
4799 char *directory = NULL;
4800 NTSTATUS status = NT_STATUS_OK;
4801 struct ea_list *ea_list = NULL;
4802 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4803 NTTIME twrp = 0;
4804 TALLOC_CTX *ctx = talloc_tos();
4806 if (!CAN_WRITE(conn)) {
4807 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4808 return;
4811 if (total_params < 5) {
4812 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4813 return;
4816 if (req->posix_pathnames) {
4817 srvstr_get_path_posix(ctx,
4818 params,
4819 req->flags2,
4820 &directory,
4821 &params[4],
4822 total_params - 4,
4823 STR_TERMINATE,
4824 &status);
4825 } else {
4826 srvstr_get_path(ctx,
4827 params,
4828 req->flags2,
4829 &directory,
4830 &params[4],
4831 total_params - 4,
4832 STR_TERMINATE,
4833 &status);
4835 if (!NT_STATUS_IS_OK(status)) {
4836 reply_nterror(req, status);
4837 return;
4840 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
4842 if (ucf_flags & UCF_GMT_PATHNAME) {
4843 extract_snapshot_token(directory, &twrp);
4845 status = smb1_strip_dfs_path(ctx, &ucf_flags, &directory);
4846 if (!NT_STATUS_IS_OK(status)) {
4847 reply_nterror(req, status);
4848 goto out;
4850 status = filename_convert_dirfsp(ctx,
4851 conn,
4852 directory,
4853 ucf_flags,
4854 twrp,
4855 &dirfsp,
4856 &smb_dname);
4857 if (!NT_STATUS_IS_OK(status)) {
4858 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4859 reply_botherror(req,
4860 NT_STATUS_PATH_NOT_COVERED,
4861 ERRSRV, ERRbadpath);
4862 return;
4864 reply_nterror(req, status);
4865 return;
4869 * OS/2 workplace shell seems to send SET_EA requests of "null"
4870 * length (4 bytes containing IVAL 4).
4871 * They seem to have no effect. Bug #3212. JRA.
4874 if (total_data && (total_data != 4)) {
4875 /* Any data in this call is an EA list. */
4876 if (total_data < 10) {
4877 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4878 goto out;
4881 if (IVAL(pdata,0) > total_data) {
4882 DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
4883 IVAL(pdata,0), (unsigned int)total_data));
4884 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4885 goto out;
4888 ea_list = read_ea_list(talloc_tos(), pdata + 4,
4889 total_data - 4);
4890 if (!ea_list) {
4891 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4892 goto out;
4895 if (!lp_ea_support(SNUM(conn))) {
4896 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
4897 goto out;
4900 /* If total_data == 4 Windows doesn't care what values
4901 * are placed in that field, it just ignores them.
4902 * The System i QNTC IBM SMB client puts bad values here,
4903 * so ignore them. */
4905 status = SMB_VFS_CREATE_FILE(
4906 conn, /* conn */
4907 req, /* req */
4908 dirfsp, /* dirfsp */
4909 smb_dname, /* fname */
4910 MAXIMUM_ALLOWED_ACCESS, /* access_mask */
4911 FILE_SHARE_NONE, /* share_access */
4912 FILE_CREATE, /* create_disposition*/
4913 FILE_DIRECTORY_FILE, /* create_options */
4914 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
4915 0, /* oplock_request */
4916 NULL, /* lease */
4917 0, /* allocation_size */
4918 0, /* private_flags */
4919 NULL, /* sd */
4920 NULL, /* ea_list */
4921 &fsp, /* result */
4922 NULL, /* pinfo */
4923 NULL, NULL); /* create context */
4924 if (!NT_STATUS_IS_OK(status)) {
4925 reply_nterror(req, status);
4926 goto out;
4929 /* Try and set any given EA. */
4930 if (ea_list) {
4931 status = set_ea(conn, fsp, ea_list);
4932 if (!NT_STATUS_IS_OK(status)) {
4933 reply_nterror(req, status);
4934 goto out;
4938 /* Realloc the parameter and data sizes */
4939 *pparams = (char *)SMB_REALLOC(*pparams,2);
4940 if(*pparams == NULL) {
4941 reply_nterror(req, NT_STATUS_NO_MEMORY);
4942 goto out;
4944 params = *pparams;
4946 SSVAL(params,0,0);
4948 send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
4950 out:
4951 if (fsp != NULL) {
4952 close_file_free(NULL, &fsp, NORMAL_CLOSE);
4954 TALLOC_FREE(smb_dname);
4957 /****************************************************************************
4958 Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
4959 We don't actually do this - we just send a null response.
4960 ****************************************************************************/
4962 static void call_trans2findnotifyfirst(connection_struct *conn,
4963 struct smb_request *req,
4964 char **pparams, int total_params,
4965 char **ppdata, int total_data,
4966 unsigned int max_data_bytes)
4968 char *params = *pparams;
4969 uint16_t info_level;
4971 if (total_params < 6) {
4972 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4973 return;
4976 info_level = SVAL(params,4);
4977 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
4979 switch (info_level) {
4980 case 1:
4981 case 2:
4982 break;
4983 default:
4984 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4985 return;
4988 /* Realloc the parameter and data sizes */
4989 *pparams = (char *)SMB_REALLOC(*pparams,6);
4990 if (*pparams == NULL) {
4991 reply_nterror(req, NT_STATUS_NO_MEMORY);
4992 return;
4994 params = *pparams;
4996 SSVAL(params,0,fnf_handle);
4997 SSVAL(params,2,0); /* No changes */
4998 SSVAL(params,4,0); /* No EA errors */
5000 fnf_handle++;
5002 if(fnf_handle == 0)
5003 fnf_handle = 257;
5005 send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
5008 /****************************************************************************
5009 Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
5010 changes). Currently this does nothing.
5011 ****************************************************************************/
5013 static void call_trans2findnotifynext(connection_struct *conn,
5014 struct smb_request *req,
5015 char **pparams, int total_params,
5016 char **ppdata, int total_data,
5017 unsigned int max_data_bytes)
5019 char *params = *pparams;
5021 DEBUG(3,("call_trans2findnotifynext\n"));
5023 /* Realloc the parameter and data sizes */
5024 *pparams = (char *)SMB_REALLOC(*pparams,4);
5025 if (*pparams == NULL) {
5026 reply_nterror(req, NT_STATUS_NO_MEMORY);
5027 return;
5029 params = *pparams;
5031 SSVAL(params,0,0); /* No changes */
5032 SSVAL(params,2,0); /* No EA errors */
5034 send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
5037 /****************************************************************************
5038 Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
5039 ****************************************************************************/
5041 static void call_trans2getdfsreferral(connection_struct *conn,
5042 struct smb_request *req,
5043 char **pparams, int total_params,
5044 char **ppdata, int total_data,
5045 unsigned int max_data_bytes)
5047 char *params = *pparams;
5048 char *pathname = NULL;
5049 int reply_size = 0;
5050 int max_referral_level;
5051 NTSTATUS status = NT_STATUS_OK;
5052 TALLOC_CTX *ctx = talloc_tos();
5054 DEBUG(10,("call_trans2getdfsreferral\n"));
5056 if (!IS_IPC(conn)) {
5057 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5058 return;
5061 if (total_params < 3) {
5062 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5063 return;
5066 max_referral_level = SVAL(params,0);
5068 if(!lp_host_msdfs()) {
5069 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5070 return;
5073 srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
5074 total_params - 2, STR_TERMINATE);
5075 if (!pathname) {
5076 reply_nterror(req, NT_STATUS_NOT_FOUND);
5077 return;
5079 reply_size = setup_dfs_referral(
5080 conn, pathname, max_referral_level, ppdata, &status);
5081 if (reply_size < 0) {
5082 reply_nterror(req, status);
5083 return;
5086 SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
5087 SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
5088 send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
5091 #define LMCAT_SPL 0x53
5092 #define LMFUNC_GETJOBID 0x60
5094 /****************************************************************************
5095 Reply to a TRANS2_IOCTL - used for OS/2 printing.
5096 ****************************************************************************/
5098 static void call_trans2ioctl(connection_struct *conn,
5099 struct smb_request *req,
5100 char **pparams, int total_params,
5101 char **ppdata, int total_data,
5102 unsigned int max_data_bytes)
5104 const struct loadparm_substitution *lp_sub =
5105 loadparm_s3_global_substitution();
5106 char *pdata = *ppdata;
5107 files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
5108 NTSTATUS status;
5109 size_t len = 0;
5111 /* check for an invalid fid before proceeding */
5113 if (!fsp) {
5114 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5115 return;
5118 if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
5119 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5120 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
5121 if (*ppdata == NULL) {
5122 reply_nterror(req, NT_STATUS_NO_MEMORY);
5123 return;
5125 pdata = *ppdata;
5127 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
5128 CAN ACCEPT THIS IN UNICODE. JRA. */
5130 /* Job number */
5131 SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));
5133 status = srvstr_push(pdata, req->flags2, pdata + 2,
5134 lp_netbios_name(), 15,
5135 STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
5136 if (!NT_STATUS_IS_OK(status)) {
5137 reply_nterror(req, status);
5138 return;
5140 status = srvstr_push(pdata, req->flags2, pdata+18,
5141 lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13,
5142 STR_ASCII|STR_TERMINATE, &len); /* Service name */
5143 if (!NT_STATUS_IS_OK(status)) {
5144 reply_nterror(req, status);
5145 return;
5147 send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
5148 max_data_bytes);
5149 return;
5152 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
5153 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5156 static void handle_trans2(connection_struct *conn, struct smb_request *req,
5157 struct trans_state *state)
5159 struct smbXsrv_connection *xconn = req->xconn;
5161 if (xconn->protocol >= PROTOCOL_NT1) {
5162 req->flags2 |= 0x40; /* IS_LONG_NAME */
5163 SSVAL((discard_const_p(uint8_t, req->inbuf)),smb_flg2,req->flags2);
5166 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
5167 if (state->call != TRANSACT2_QFSINFO &&
5168 state->call != TRANSACT2_SETFSINFO) {
5169 DEBUG(0,("handle_trans2: encryption required "
5170 "with call 0x%x\n",
5171 (unsigned int)state->call));
5172 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5173 return;
5177 /* Now we must call the relevant TRANS2 function */
5178 switch(state->call) {
5179 case TRANSACT2_OPEN:
5181 START_PROFILE(Trans2_open);
5182 call_trans2open(conn, req,
5183 &state->param, state->total_param,
5184 &state->data, state->total_data,
5185 state->max_data_return);
5186 END_PROFILE(Trans2_open);
5187 break;
5190 case TRANSACT2_FINDFIRST:
5192 START_PROFILE(Trans2_findfirst);
5193 call_trans2findfirst(conn, req,
5194 &state->param, state->total_param,
5195 &state->data, state->total_data,
5196 state->max_data_return);
5197 END_PROFILE(Trans2_findfirst);
5198 break;
5201 case TRANSACT2_FINDNEXT:
5203 START_PROFILE(Trans2_findnext);
5204 call_trans2findnext(conn, req,
5205 &state->param, state->total_param,
5206 &state->data, state->total_data,
5207 state->max_data_return);
5208 END_PROFILE(Trans2_findnext);
5209 break;
5212 case TRANSACT2_QFSINFO:
5214 START_PROFILE(Trans2_qfsinfo);
5215 call_trans2qfsinfo(conn, req,
5216 &state->param, state->total_param,
5217 &state->data, state->total_data,
5218 state->max_data_return);
5219 END_PROFILE(Trans2_qfsinfo);
5220 break;
5223 case TRANSACT2_SETFSINFO:
5225 START_PROFILE(Trans2_setfsinfo);
5226 call_trans2setfsinfo(conn, req,
5227 &state->param, state->total_param,
5228 &state->data, state->total_data,
5229 state->max_data_return);
5230 END_PROFILE(Trans2_setfsinfo);
5231 break;
5234 case TRANSACT2_QPATHINFO:
5236 START_PROFILE(Trans2_qpathinfo);
5237 call_trans2qpathinfo(
5238 conn,
5239 req,
5240 &state->param,
5241 state->total_param,
5242 &state->data,
5243 state->total_data,
5244 state->max_data_return);
5245 END_PROFILE(Trans2_qpathinfo);
5246 break;
5249 case TRANSACT2_QFILEINFO:
5251 START_PROFILE(Trans2_qfileinfo);
5252 call_trans2qfileinfo(
5253 conn,
5254 req,
5255 &state->param,
5256 state->total_param,
5257 &state->data,
5258 state->total_data,
5259 state->max_data_return);
5260 END_PROFILE(Trans2_qfileinfo);
5261 break;
5264 case TRANSACT2_SETPATHINFO:
5266 START_PROFILE(Trans2_setpathinfo);
5267 call_trans2setpathinfo(
5268 conn,
5269 req,
5270 &state->param,
5271 state->total_param,
5272 &state->data,
5273 state->total_data,
5274 state->max_data_return);
5275 END_PROFILE(Trans2_setpathinfo);
5276 break;
5279 case TRANSACT2_SETFILEINFO:
5281 START_PROFILE(Trans2_setfileinfo);
5282 call_trans2setfileinfo(
5283 conn,
5284 req,
5285 &state->param,
5286 state->total_param,
5287 &state->data,
5288 state->total_data,
5289 state->max_data_return);
5290 END_PROFILE(Trans2_setfileinfo);
5291 break;
5294 case TRANSACT2_FINDNOTIFYFIRST:
5296 START_PROFILE(Trans2_findnotifyfirst);
5297 call_trans2findnotifyfirst(conn, req,
5298 &state->param, state->total_param,
5299 &state->data, state->total_data,
5300 state->max_data_return);
5301 END_PROFILE(Trans2_findnotifyfirst);
5302 break;
5305 case TRANSACT2_FINDNOTIFYNEXT:
5307 START_PROFILE(Trans2_findnotifynext);
5308 call_trans2findnotifynext(conn, req,
5309 &state->param, state->total_param,
5310 &state->data, state->total_data,
5311 state->max_data_return);
5312 END_PROFILE(Trans2_findnotifynext);
5313 break;
5316 case TRANSACT2_MKDIR:
5318 START_PROFILE(Trans2_mkdir);
5319 call_trans2mkdir(conn, req,
5320 &state->param, state->total_param,
5321 &state->data, state->total_data,
5322 state->max_data_return);
5323 END_PROFILE(Trans2_mkdir);
5324 break;
5327 case TRANSACT2_GET_DFS_REFERRAL:
5329 START_PROFILE(Trans2_get_dfs_referral);
5330 call_trans2getdfsreferral(conn, req,
5331 &state->param, state->total_param,
5332 &state->data, state->total_data,
5333 state->max_data_return);
5334 END_PROFILE(Trans2_get_dfs_referral);
5335 break;
5338 case TRANSACT2_IOCTL:
5340 START_PROFILE(Trans2_ioctl);
5341 call_trans2ioctl(conn, req,
5342 &state->param, state->total_param,
5343 &state->data, state->total_data,
5344 state->max_data_return);
5345 END_PROFILE(Trans2_ioctl);
5346 break;
5349 default:
5350 /* Error in request */
5351 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
5352 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
5356 /****************************************************************************
5357 Reply to a SMBtrans2.
5358 ****************************************************************************/
5360 void reply_trans2(struct smb_request *req)
5362 connection_struct *conn = req->conn;
5363 unsigned int dsoff;
5364 unsigned int dscnt;
5365 unsigned int psoff;
5366 unsigned int pscnt;
5367 unsigned int tran_call;
5368 struct trans_state *state;
5369 NTSTATUS result;
5371 START_PROFILE(SMBtrans2);
5373 if (req->wct < 14) {
5374 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5375 END_PROFILE(SMBtrans2);
5376 return;
5379 dsoff = SVAL(req->vwv+12, 0);
5380 dscnt = SVAL(req->vwv+11, 0);
5381 psoff = SVAL(req->vwv+10, 0);
5382 pscnt = SVAL(req->vwv+9, 0);
5383 tran_call = SVAL(req->vwv+14, 0);
5385 result = allow_new_trans(conn->pending_trans, req->mid);
5386 if (!NT_STATUS_IS_OK(result)) {
5387 DEBUG(2, ("Got invalid trans2 request: %s\n",
5388 nt_errstr(result)));
5389 reply_nterror(req, result);
5390 END_PROFILE(SMBtrans2);
5391 return;
5394 if (IS_IPC(conn)) {
5395 switch (tran_call) {
5396 /* List the allowed trans2 calls on IPC$ */
5397 case TRANSACT2_OPEN:
5398 case TRANSACT2_GET_DFS_REFERRAL:
5399 case TRANSACT2_QFILEINFO:
5400 case TRANSACT2_QFSINFO:
5401 case TRANSACT2_SETFSINFO:
5402 break;
5403 default:
5404 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5405 END_PROFILE(SMBtrans2);
5406 return;
5410 if ((state = talloc(conn, struct trans_state)) == NULL) {
5411 DEBUG(0, ("talloc failed\n"));
5412 reply_nterror(req, NT_STATUS_NO_MEMORY);
5413 END_PROFILE(SMBtrans2);
5414 return;
5417 state->cmd = SMBtrans2;
5419 state->mid = req->mid;
5420 state->vuid = req->vuid;
5421 state->setup_count = SVAL(req->vwv+13, 0);
5422 state->setup = NULL;
5423 state->total_param = SVAL(req->vwv+0, 0);
5424 state->param = NULL;
5425 state->total_data = SVAL(req->vwv+1, 0);
5426 state->data = NULL;
5427 state->max_param_return = SVAL(req->vwv+2, 0);
5428 state->max_data_return = SVAL(req->vwv+3, 0);
5429 state->max_setup_return = SVAL(req->vwv+4, 0);
5430 state->close_on_completion = BITSETW(req->vwv+5, 0);
5431 state->one_way = BITSETW(req->vwv+5, 1);
5433 state->call = tran_call;
5435 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
5436 is so as a sanity check */
5437 if (state->setup_count != 1) {
5439 * Need to have rc=0 for ioctl to get job id for OS/2.
5440 * Network printing will fail if function is not successful.
5441 * Similar function in reply.c will be used if protocol
5442 * is LANMAN1.0 instead of LM1.2X002.
5443 * Until DosPrintSetJobInfo with PRJINFO3 is supported,
5444 * outbuf doesn't have to be set(only job id is used).
5446 if ( (state->setup_count == 4)
5447 && (tran_call == TRANSACT2_IOCTL)
5448 && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
5449 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
5450 DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
5451 } else {
5452 DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
5453 DEBUG(2,("Transaction is %d\n",tran_call));
5454 TALLOC_FREE(state);
5455 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5456 END_PROFILE(SMBtrans2);
5457 return;
5461 if ((dscnt > state->total_data) || (pscnt > state->total_param))
5462 goto bad_param;
5464 if (state->total_data) {
5466 if (smb_buffer_oob(state->total_data, 0, dscnt)
5467 || smb_buffer_oob(smb_len(req->inbuf), dsoff, dscnt)) {
5468 goto bad_param;
5471 /* Can't use talloc here, the core routines do realloc on the
5472 * params and data. */
5473 state->data = (char *)SMB_MALLOC(state->total_data);
5474 if (state->data == NULL) {
5475 DEBUG(0,("reply_trans2: data malloc fail for %u "
5476 "bytes !\n", (unsigned int)state->total_data));
5477 TALLOC_FREE(state);
5478 reply_nterror(req, NT_STATUS_NO_MEMORY);
5479 END_PROFILE(SMBtrans2);
5480 return;
5483 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
5486 if (state->total_param) {
5488 if (smb_buffer_oob(state->total_param, 0, pscnt)
5489 || smb_buffer_oob(smb_len(req->inbuf), psoff, pscnt)) {
5490 goto bad_param;
5493 /* Can't use talloc here, the core routines do realloc on the
5494 * params and data. */
5495 state->param = (char *)SMB_MALLOC(state->total_param);
5496 if (state->param == NULL) {
5497 DEBUG(0,("reply_trans: param malloc fail for %u "
5498 "bytes !\n", (unsigned int)state->total_param));
5499 SAFE_FREE(state->data);
5500 TALLOC_FREE(state);
5501 reply_nterror(req, NT_STATUS_NO_MEMORY);
5502 END_PROFILE(SMBtrans2);
5503 return;
5506 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
5509 state->received_data = dscnt;
5510 state->received_param = pscnt;
5512 if ((state->received_param == state->total_param) &&
5513 (state->received_data == state->total_data)) {
5515 handle_trans2(conn, req, state);
5517 SAFE_FREE(state->data);
5518 SAFE_FREE(state->param);
5519 TALLOC_FREE(state);
5520 END_PROFILE(SMBtrans2);
5521 return;
5524 DLIST_ADD(conn->pending_trans, state);
5526 /* We need to send an interim response then receive the rest
5527 of the parameter/data bytes */
5528 reply_smb1_outbuf(req, 0, 0);
5529 show_msg((char *)req->outbuf);
5530 END_PROFILE(SMBtrans2);
5531 return;
5533 bad_param:
5535 DEBUG(0,("reply_trans2: invalid trans parameters\n"));
5536 SAFE_FREE(state->data);
5537 SAFE_FREE(state->param);
5538 TALLOC_FREE(state);
5539 END_PROFILE(SMBtrans2);
5540 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5543 /****************************************************************************
5544 Reply to a SMBtranss2
5545 ****************************************************************************/
5547 void reply_transs2(struct smb_request *req)
5549 connection_struct *conn = req->conn;
5550 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
5551 struct trans_state *state;
5553 START_PROFILE(SMBtranss2);
5555 show_msg((const char *)req->inbuf);
5557 /* Windows clients expect all replies to
5558 a transact secondary (SMBtranss2 0x33)
5559 to have a command code of transact
5560 (SMBtrans2 0x32). See bug #8989
5561 and also [MS-CIFS] section 2.2.4.47.2
5562 for details.
5564 req->cmd = SMBtrans2;
5566 if (req->wct < 8) {
5567 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5568 END_PROFILE(SMBtranss2);
5569 return;
5572 for (state = conn->pending_trans; state != NULL;
5573 state = state->next) {
5574 if (state->mid == req->mid) {
5575 break;
5579 if ((state == NULL) || (state->cmd != SMBtrans2)) {
5580 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5581 END_PROFILE(SMBtranss2);
5582 return;
5585 /* Revise state->total_param and state->total_data in case they have
5586 changed downwards */
5588 if (SVAL(req->vwv+0, 0) < state->total_param)
5589 state->total_param = SVAL(req->vwv+0, 0);
5590 if (SVAL(req->vwv+1, 0) < state->total_data)
5591 state->total_data = SVAL(req->vwv+1, 0);
5593 pcnt = SVAL(req->vwv+2, 0);
5594 poff = SVAL(req->vwv+3, 0);
5595 pdisp = SVAL(req->vwv+4, 0);
5597 dcnt = SVAL(req->vwv+5, 0);
5598 doff = SVAL(req->vwv+6, 0);
5599 ddisp = SVAL(req->vwv+7, 0);
5601 state->received_param += pcnt;
5602 state->received_data += dcnt;
5604 if ((state->received_data > state->total_data) ||
5605 (state->received_param > state->total_param))
5606 goto bad_param;
5608 if (pcnt) {
5609 if (smb_buffer_oob(state->total_param, pdisp, pcnt)
5610 || smb_buffer_oob(smb_len(req->inbuf), poff, pcnt)) {
5611 goto bad_param;
5613 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
5616 if (dcnt) {
5617 if (smb_buffer_oob(state->total_data, ddisp, dcnt)
5618 || smb_buffer_oob(smb_len(req->inbuf), doff, dcnt)) {
5619 goto bad_param;
5621 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
5624 if ((state->received_param < state->total_param) ||
5625 (state->received_data < state->total_data)) {
5626 END_PROFILE(SMBtranss2);
5627 return;
5630 handle_trans2(conn, req, state);
5632 DLIST_REMOVE(conn->pending_trans, state);
5633 SAFE_FREE(state->data);
5634 SAFE_FREE(state->param);
5635 TALLOC_FREE(state);
5637 END_PROFILE(SMBtranss2);
5638 return;
5640 bad_param:
5642 DEBUG(0,("reply_transs2: invalid trans parameters\n"));
5643 DLIST_REMOVE(conn->pending_trans, state);
5644 SAFE_FREE(state->data);
5645 SAFE_FREE(state->param);
5646 TALLOC_FREE(state);
5647 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5648 END_PROFILE(SMBtranss2);