s3-lsa: Fix _lsa_LookupNames2() server implementation which always returned a NULL...
[Samba.git] / source / smbd / reply.c
blob46653cd9c5ebd3e08608a7337c6924353b78ad93
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
29 /* look in server.c for some explanation of these variables */
30 extern enum protocol_types Protocol;
31 extern int max_recv;
32 extern uint32 global_client_caps;
34 extern bool global_encrypted_passwords_negotiated;
36 /****************************************************************************
37 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
38 path or anything including wildcards.
39 We're assuming here that '/' is not the second byte in any multibyte char
40 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
41 set.
42 ****************************************************************************/
44 /* Custom version for processing POSIX paths. */
45 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
47 static NTSTATUS check_path_syntax_internal(char *path,
48 bool posix_path,
49 bool *p_last_component_contains_wcard)
51 char *d = path;
52 const char *s = path;
53 NTSTATUS ret = NT_STATUS_OK;
54 bool start_of_name_component = True;
55 bool stream_started = false;
57 *p_last_component_contains_wcard = False;
59 while (*s) {
60 if (stream_started) {
61 switch (*s) {
62 case '/':
63 case '\\':
64 return NT_STATUS_OBJECT_NAME_INVALID;
65 case ':':
66 if (s[1] == '\0') {
67 return NT_STATUS_OBJECT_NAME_INVALID;
69 if (strchr_m(&s[1], ':')) {
70 return NT_STATUS_OBJECT_NAME_INVALID;
72 if (StrCaseCmp(s, ":$DATA") != 0) {
73 return NT_STATUS_INVALID_PARAMETER;
75 break;
79 if (!posix_path && !stream_started && *s == ':') {
80 if (*p_last_component_contains_wcard) {
81 return NT_STATUS_OBJECT_NAME_INVALID;
83 /* Stream names allow more characters than file names.
84 We're overloading posix_path here to allow a wider
85 range of characters. If stream_started is true this
86 is still a Windows path even if posix_path is true.
87 JRA.
89 stream_started = true;
90 start_of_name_component = false;
91 posix_path = true;
93 if (s[1] == '\0') {
94 return NT_STATUS_OBJECT_NAME_INVALID;
98 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
100 * Safe to assume is not the second part of a mb char
101 * as this is handled below.
103 /* Eat multiple '/' or '\\' */
104 while (IS_PATH_SEP(*s,posix_path)) {
105 s++;
107 if ((d != path) && (*s != '\0')) {
108 /* We only care about non-leading or trailing '/' or '\\' */
109 *d++ = '/';
112 start_of_name_component = True;
113 /* New component. */
114 *p_last_component_contains_wcard = False;
115 continue;
118 if (start_of_name_component) {
119 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
120 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
123 * No mb char starts with '.' so we're safe checking the directory separator here.
126 /* If we just added a '/' - delete it */
127 if ((d > path) && (*(d-1) == '/')) {
128 *(d-1) = '\0';
129 d--;
132 /* Are we at the start ? Can't go back further if so. */
133 if (d <= path) {
134 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
135 break;
137 /* Go back one level... */
138 /* We know this is safe as '/' cannot be part of a mb sequence. */
139 /* NOTE - if this assumption is invalid we are not in good shape... */
140 /* Decrement d first as d points to the *next* char to write into. */
141 for (d--; d > path; d--) {
142 if (*d == '/')
143 break;
145 s += 2; /* Else go past the .. */
146 /* We're still at the start of a name component, just the previous one. */
147 continue;
149 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
150 if (posix_path) {
151 /* Eat the '.' */
152 s++;
153 continue;
159 if (!(*s & 0x80)) {
160 if (!posix_path) {
161 if (*s <= 0x1f || *s == '|') {
162 return NT_STATUS_OBJECT_NAME_INVALID;
164 switch (*s) {
165 case '*':
166 case '?':
167 case '<':
168 case '>':
169 case '"':
170 *p_last_component_contains_wcard = True;
171 break;
172 default:
173 break;
176 *d++ = *s++;
177 } else {
178 size_t siz;
179 /* Get the size of the next MB character. */
180 next_codepoint(s,&siz);
181 switch(siz) {
182 case 5:
183 *d++ = *s++;
184 /*fall through*/
185 case 4:
186 *d++ = *s++;
187 /*fall through*/
188 case 3:
189 *d++ = *s++;
190 /*fall through*/
191 case 2:
192 *d++ = *s++;
193 /*fall through*/
194 case 1:
195 *d++ = *s++;
196 break;
197 default:
198 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
199 *d = '\0';
200 return NT_STATUS_INVALID_PARAMETER;
203 start_of_name_component = False;
206 *d = '\0';
208 return ret;
211 /****************************************************************************
212 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
213 No wildcards allowed.
214 ****************************************************************************/
216 NTSTATUS check_path_syntax(char *path)
218 bool ignore;
219 return check_path_syntax_internal(path, False, &ignore);
222 /****************************************************************************
223 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
224 Wildcards allowed - p_contains_wcard returns true if the last component contained
225 a wildcard.
226 ****************************************************************************/
228 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
230 return check_path_syntax_internal(path, False, p_contains_wcard);
233 /****************************************************************************
234 Check the path for a POSIX client.
235 We're assuming here that '/' is not the second byte in any multibyte char
236 set (a safe assumption).
237 ****************************************************************************/
239 NTSTATUS check_path_syntax_posix(char *path)
241 bool ignore;
242 return check_path_syntax_internal(path, True, &ignore);
245 /****************************************************************************
246 Pull a string and check the path allowing a wilcard - provide for error return.
247 ****************************************************************************/
249 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
250 const char *inbuf,
251 uint16 smb_flags2,
252 char **pp_dest,
253 const char *src,
254 size_t src_len,
255 int flags,
256 NTSTATUS *err,
257 bool *contains_wcard)
259 size_t ret;
261 *pp_dest = NULL;
263 if (src_len == 0) {
264 ret = srvstr_pull_buf_talloc(ctx,
265 inbuf,
266 smb_flags2,
267 pp_dest,
268 src,
269 flags);
270 } else {
271 ret = srvstr_pull_talloc(ctx,
272 inbuf,
273 smb_flags2,
274 pp_dest,
275 src,
276 src_len,
277 flags);
280 if (!*pp_dest) {
281 *err = NT_STATUS_INVALID_PARAMETER;
282 return ret;
285 *contains_wcard = False;
287 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
289 * For a DFS path the function parse_dfs_path()
290 * will do the path processing, just make a copy.
292 *err = NT_STATUS_OK;
293 return ret;
296 if (lp_posix_pathnames()) {
297 *err = check_path_syntax_posix(*pp_dest);
298 } else {
299 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
302 return ret;
305 /****************************************************************************
306 Pull a string and check the path - provide for error return.
307 ****************************************************************************/
309 size_t srvstr_get_path(TALLOC_CTX *ctx,
310 const char *inbuf,
311 uint16 smb_flags2,
312 char **pp_dest,
313 const char *src,
314 size_t src_len,
315 int flags,
316 NTSTATUS *err)
318 size_t ret;
320 *pp_dest = NULL;
322 if (src_len == 0) {
323 ret = srvstr_pull_buf_talloc(ctx,
324 inbuf,
325 smb_flags2,
326 pp_dest,
327 src,
328 flags);
329 } else {
330 ret = srvstr_pull_talloc(ctx,
331 inbuf,
332 smb_flags2,
333 pp_dest,
334 src,
335 src_len,
336 flags);
339 if (!*pp_dest) {
340 *err = NT_STATUS_INVALID_PARAMETER;
341 return ret;
344 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
346 * For a DFS path the function parse_dfs_path()
347 * will do the path processing, just make a copy.
349 *err = NT_STATUS_OK;
350 return ret;
353 if (lp_posix_pathnames()) {
354 *err = check_path_syntax_posix(*pp_dest);
355 } else {
356 *err = check_path_syntax(*pp_dest);
359 return ret;
362 /****************************************************************************
363 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
364 ****************************************************************************/
366 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
367 files_struct *fsp)
369 if (!(fsp) || !(conn)) {
370 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
371 return False;
373 if (((conn) != (fsp)->conn) || req->vuid != (fsp)->vuid) {
374 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
375 return False;
377 return True;
380 /****************************************************************************
381 Check if we have a correct fsp pointing to a file.
382 ****************************************************************************/
384 bool check_fsp(connection_struct *conn, struct smb_request *req,
385 files_struct *fsp)
387 if (!check_fsp_open(conn, req, fsp)) {
388 return False;
390 if ((fsp)->is_directory) {
391 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
392 return False;
394 if ((fsp)->fh->fd == -1) {
395 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
396 return False;
398 (fsp)->num_smb_operations++;
399 return True;
402 /****************************************************************************
403 Check if we have a correct fsp pointing to a quota fake file. Replacement for
404 the CHECK_NTQUOTA_HANDLE_OK macro.
405 ****************************************************************************/
407 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
408 files_struct *fsp)
410 if (!check_fsp_open(conn, req, fsp)) {
411 return false;
414 if (fsp->is_directory) {
415 return false;
418 if (fsp->fake_file_handle == NULL) {
419 return false;
422 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
423 return false;
426 if (fsp->fake_file_handle->private_data == NULL) {
427 return false;
430 return true;
433 /****************************************************************************
434 Check if we have a correct fsp. Replacement for the FSP_BELONGS_CONN macro
435 ****************************************************************************/
437 bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req,
438 files_struct *fsp)
440 if ((fsp) && (conn) && ((conn)==(fsp)->conn)
441 && (req->vuid == (fsp)->vuid)) {
442 return True;
445 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
446 return False;
449 /****************************************************************************
450 Reply to a (netbios-level) special message.
451 ****************************************************************************/
453 void reply_special(char *inbuf)
455 int msg_type = CVAL(inbuf,0);
456 int msg_flags = CVAL(inbuf,1);
457 fstring name1,name2;
458 char name_type = 0;
461 * We only really use 4 bytes of the outbuf, but for the smb_setlen
462 * calculation & friends (srv_send_smb uses that) we need the full smb
463 * header.
465 char outbuf[smb_size];
467 static bool already_got_session = False;
469 *name1 = *name2 = 0;
471 memset(outbuf, '\0', sizeof(outbuf));
473 smb_setlen(outbuf,0);
475 switch (msg_type) {
476 case 0x81: /* session request */
478 if (already_got_session) {
479 exit_server_cleanly("multiple session request not permitted");
482 SCVAL(outbuf,0,0x82);
483 SCVAL(outbuf,3,0);
484 if (name_len(inbuf+4) > 50 ||
485 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
486 DEBUG(0,("Invalid name length in session request\n"));
487 return;
489 name_extract(inbuf,4,name1);
490 name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
491 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
492 name1,name2));
494 set_local_machine_name(name1, True);
495 set_remote_machine_name(name2, True);
497 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
498 get_local_machine_name(), get_remote_machine_name(),
499 name_type));
501 if (name_type == 'R') {
502 /* We are being asked for a pathworks session ---
503 no thanks! */
504 SCVAL(outbuf, 0,0x83);
505 break;
508 /* only add the client's machine name to the list
509 of possibly valid usernames if we are operating
510 in share mode security */
511 if (lp_security() == SEC_SHARE) {
512 add_session_user(get_remote_machine_name());
515 reload_services(True);
516 reopen_logs();
518 already_got_session = True;
519 break;
521 case 0x89: /* session keepalive request
522 (some old clients produce this?) */
523 SCVAL(outbuf,0,SMBkeepalive);
524 SCVAL(outbuf,3,0);
525 break;
527 case 0x82: /* positive session response */
528 case 0x83: /* negative session response */
529 case 0x84: /* retarget session response */
530 DEBUG(0,("Unexpected session response\n"));
531 break;
533 case SMBkeepalive: /* session keepalive */
534 default:
535 return;
538 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
539 msg_type, msg_flags));
541 srv_send_smb(smbd_server_fd(), outbuf, false);
542 return;
545 /****************************************************************************
546 Reply to a tcon.
547 conn POINTER CAN BE NULL HERE !
548 ****************************************************************************/
550 void reply_tcon(struct smb_request *req)
552 connection_struct *conn = req->conn;
553 const char *service;
554 char *service_buf = NULL;
555 char *password = NULL;
556 char *dev = NULL;
557 int pwlen=0;
558 NTSTATUS nt_status;
559 char *p;
560 DATA_BLOB password_blob;
561 TALLOC_CTX *ctx = talloc_tos();
563 START_PROFILE(SMBtcon);
565 if (smb_buflen(req->inbuf) < 4) {
566 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
567 END_PROFILE(SMBtcon);
568 return;
571 p = smb_buf(req->inbuf)+1;
572 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
573 &service_buf, p, STR_TERMINATE) + 1;
574 pwlen = srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
575 &password, p, STR_TERMINATE) + 1;
576 p += pwlen;
577 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
578 &dev, p, STR_TERMINATE) + 1;
580 if (service_buf == NULL || password == NULL || dev == NULL) {
581 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
582 END_PROFILE(SMBtcon);
583 return;
585 p = strrchr_m(service_buf,'\\');
586 if (p) {
587 service = p+1;
588 } else {
589 service = service_buf;
592 password_blob = data_blob(password, pwlen+1);
594 conn = make_connection(service,password_blob,dev,req->vuid,&nt_status);
595 req->conn = conn;
597 data_blob_clear_free(&password_blob);
599 if (!conn) {
600 reply_nterror(req, nt_status);
601 END_PROFILE(SMBtcon);
602 return;
605 reply_outbuf(req, 2, 0);
606 SSVAL(req->outbuf,smb_vwv0,max_recv);
607 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
608 SSVAL(req->outbuf,smb_tid,conn->cnum);
610 DEBUG(3,("tcon service=%s cnum=%d\n",
611 service, conn->cnum));
613 END_PROFILE(SMBtcon);
614 return;
617 /****************************************************************************
618 Reply to a tcon and X.
619 conn POINTER CAN BE NULL HERE !
620 ****************************************************************************/
622 void reply_tcon_and_X(struct smb_request *req)
624 connection_struct *conn = req->conn;
625 char *service = NULL;
626 DATA_BLOB password;
627 TALLOC_CTX *ctx = talloc_tos();
628 /* what the cleint thinks the device is */
629 char *client_devicetype = NULL;
630 /* what the server tells the client the share represents */
631 const char *server_devicetype;
632 NTSTATUS nt_status;
633 int passlen;
634 char *path = NULL;
635 char *p, *q;
636 uint16 tcon_flags;
638 START_PROFILE(SMBtconX);
640 if (req->wct < 4) {
641 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
642 END_PROFILE(SMBtconX);
643 return;
646 passlen = SVAL(req->inbuf,smb_vwv3);
647 tcon_flags = SVAL(req->inbuf,smb_vwv2);
649 /* we might have to close an old one */
650 if ((tcon_flags & 0x1) && conn) {
651 close_cnum(conn,req->vuid);
652 req->conn = NULL;
653 conn = NULL;
656 if ((passlen > MAX_PASS_LEN) || (passlen >= smb_buflen(req->inbuf))) {
657 reply_doserror(req, ERRDOS, ERRbuftoosmall);
658 END_PROFILE(SMBtconX);
659 return;
662 if (global_encrypted_passwords_negotiated) {
663 password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
664 passlen);
665 if (lp_security() == SEC_SHARE) {
667 * Security = share always has a pad byte
668 * after the password.
670 p = smb_buf(req->inbuf) + passlen + 1;
671 } else {
672 p = smb_buf(req->inbuf) + passlen;
674 } else {
675 password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
676 passlen+1);
677 /* Ensure correct termination */
678 password.data[passlen]=0;
679 p = smb_buf(req->inbuf) + passlen + 1;
682 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2, &path, p,
683 STR_TERMINATE);
685 if (path == NULL) {
686 data_blob_clear_free(&password);
687 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
688 END_PROFILE(SMBtconX);
689 return;
693 * the service name can be either: \\server\share
694 * or share directly like on the DELL PowerVault 705
696 if (*path=='\\') {
697 q = strchr_m(path+2,'\\');
698 if (!q) {
699 data_blob_clear_free(&password);
700 reply_doserror(req, ERRDOS, ERRnosuchshare);
701 END_PROFILE(SMBtconX);
702 return;
704 service = q+1;
705 } else {
706 service = path;
709 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
710 &client_devicetype, p,
711 MIN(6,smb_bufrem(req->inbuf, p)), STR_ASCII);
713 if (client_devicetype == NULL) {
714 data_blob_clear_free(&password);
715 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
716 END_PROFILE(SMBtconX);
717 return;
720 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
722 conn = make_connection(service, password, client_devicetype,
723 req->vuid, &nt_status);
724 req->conn =conn;
726 data_blob_clear_free(&password);
728 if (!conn) {
729 reply_nterror(req, nt_status);
730 END_PROFILE(SMBtconX);
731 return;
734 if ( IS_IPC(conn) )
735 server_devicetype = "IPC";
736 else if ( IS_PRINT(conn) )
737 server_devicetype = "LPT1:";
738 else
739 server_devicetype = "A:";
741 if (Protocol < PROTOCOL_NT1) {
742 reply_outbuf(req, 2, 0);
743 if (message_push_string(&req->outbuf, server_devicetype,
744 STR_TERMINATE|STR_ASCII) == -1) {
745 reply_nterror(req, NT_STATUS_NO_MEMORY);
746 END_PROFILE(SMBtconX);
747 return;
749 } else {
750 /* NT sets the fstype of IPC$ to the null string */
751 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
753 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
754 /* Return permissions. */
755 uint32 perm1 = 0;
756 uint32 perm2 = 0;
758 reply_outbuf(req, 7, 0);
760 if (IS_IPC(conn)) {
761 perm1 = FILE_ALL_ACCESS;
762 perm2 = FILE_ALL_ACCESS;
763 } else {
764 perm1 = CAN_WRITE(conn) ?
765 SHARE_ALL_ACCESS :
766 SHARE_READ_ONLY;
769 SIVAL(req->outbuf, smb_vwv3, perm1);
770 SIVAL(req->outbuf, smb_vwv5, perm2);
771 } else {
772 reply_outbuf(req, 3, 0);
775 if ((message_push_string(&req->outbuf, server_devicetype,
776 STR_TERMINATE|STR_ASCII) == -1)
777 || (message_push_string(&req->outbuf, fstype,
778 STR_TERMINATE) == -1)) {
779 reply_nterror(req, NT_STATUS_NO_MEMORY);
780 END_PROFILE(SMBtconX);
781 return;
784 /* what does setting this bit do? It is set by NT4 and
785 may affect the ability to autorun mounted cdroms */
786 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
787 (lp_csc_policy(SNUM(conn)) << 2));
789 init_dfsroot(conn, req->inbuf, req->outbuf);
793 DEBUG(3,("tconX service=%s \n",
794 service));
796 /* set the incoming and outgoing tid to the just created one */
797 SSVAL(req->inbuf,smb_tid,conn->cnum);
798 SSVAL(req->outbuf,smb_tid,conn->cnum);
800 END_PROFILE(SMBtconX);
802 chain_reply(req);
803 return;
806 /****************************************************************************
807 Reply to an unknown type.
808 ****************************************************************************/
810 void reply_unknown_new(struct smb_request *req, uint8 type)
812 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
813 smb_fn_name(type), type, type));
814 reply_doserror(req, ERRSRV, ERRunknownsmb);
815 return;
818 /****************************************************************************
819 Reply to an ioctl.
820 conn POINTER CAN BE NULL HERE !
821 ****************************************************************************/
823 void reply_ioctl(struct smb_request *req)
825 connection_struct *conn = req->conn;
826 uint16 device;
827 uint16 function;
828 uint32 ioctl_code;
829 int replysize;
830 char *p;
832 START_PROFILE(SMBioctl);
834 if (req->wct < 3) {
835 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
836 END_PROFILE(SMBioctl);
837 return;
840 device = SVAL(req->inbuf,smb_vwv1);
841 function = SVAL(req->inbuf,smb_vwv2);
842 ioctl_code = (device << 16) + function;
844 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
846 switch (ioctl_code) {
847 case IOCTL_QUERY_JOB_INFO:
848 replysize = 32;
849 break;
850 default:
851 reply_doserror(req, ERRSRV, ERRnosupport);
852 END_PROFILE(SMBioctl);
853 return;
856 reply_outbuf(req, 8, replysize+1);
857 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
858 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
859 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
860 p = smb_buf(req->outbuf);
861 memset(p, '\0', replysize+1); /* valgrind-safe. */
862 p += 1; /* Allow for alignment */
864 switch (ioctl_code) {
865 case IOCTL_QUERY_JOB_INFO:
867 files_struct *fsp = file_fsp(SVAL(req->inbuf,
868 smb_vwv0));
869 if (!fsp) {
870 reply_doserror(req, ERRDOS, ERRbadfid);
871 END_PROFILE(SMBioctl);
872 return;
874 SSVAL(p,0,fsp->rap_print_jobid); /* Job number */
875 srvstr_push((char *)req->outbuf, req->flags2, p+2,
876 global_myname(), 15,
877 STR_TERMINATE|STR_ASCII);
878 if (conn) {
879 srvstr_push((char *)req->outbuf, req->flags2,
880 p+18, lp_servicename(SNUM(conn)),
881 13, STR_TERMINATE|STR_ASCII);
882 } else {
883 memset(p+18, 0, 13);
885 break;
889 END_PROFILE(SMBioctl);
890 return;
893 /****************************************************************************
894 Strange checkpath NTSTATUS mapping.
895 ****************************************************************************/
897 static NTSTATUS map_checkpath_error(const char *inbuf, NTSTATUS status)
899 /* Strange DOS error code semantics only for checkpath... */
900 if (!(SVAL(inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) {
901 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
902 /* We need to map to ERRbadpath */
903 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
906 return status;
909 /****************************************************************************
910 Reply to a checkpath.
911 ****************************************************************************/
913 void reply_checkpath(struct smb_request *req)
915 connection_struct *conn = req->conn;
916 char *name = NULL;
917 SMB_STRUCT_STAT sbuf;
918 NTSTATUS status;
919 TALLOC_CTX *ctx = talloc_tos();
921 START_PROFILE(SMBcheckpath);
923 srvstr_get_path(ctx,(char *)req->inbuf, req->flags2, &name,
924 smb_buf(req->inbuf) + 1, 0,
925 STR_TERMINATE, &status);
926 if (!NT_STATUS_IS_OK(status)) {
927 status = map_checkpath_error((char *)req->inbuf, status);
928 reply_nterror(req, status);
929 END_PROFILE(SMBcheckpath);
930 return;
933 status = resolve_dfspath(ctx, conn,
934 req->flags2 & FLAGS2_DFS_PATHNAMES,
935 name,
936 &name);
937 if (!NT_STATUS_IS_OK(status)) {
938 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
939 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
940 ERRSRV, ERRbadpath);
941 END_PROFILE(SMBcheckpath);
942 return;
944 goto path_err;
947 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->inbuf,smb_vwv0)));
949 status = unix_convert(ctx, conn, name, False, &name, NULL, &sbuf);
950 if (!NT_STATUS_IS_OK(status)) {
951 goto path_err;
954 status = check_name(conn, name);
955 if (!NT_STATUS_IS_OK(status)) {
956 DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status)));
957 goto path_err;
960 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) {
961 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno)));
962 status = map_nt_error_from_unix(errno);
963 goto path_err;
966 if (!S_ISDIR(sbuf.st_mode)) {
967 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
968 ERRDOS, ERRbadpath);
969 END_PROFILE(SMBcheckpath);
970 return;
973 reply_outbuf(req, 0, 0);
975 END_PROFILE(SMBcheckpath);
976 return;
978 path_err:
980 END_PROFILE(SMBcheckpath);
982 /* We special case this - as when a Windows machine
983 is parsing a path is steps through the components
984 one at a time - if a component fails it expects
985 ERRbadpath, not ERRbadfile.
987 status = map_checkpath_error((char *)req->inbuf, status);
988 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
990 * Windows returns different error codes if
991 * the parent directory is valid but not the
992 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
993 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
994 * if the path is invalid.
996 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
997 ERRDOS, ERRbadpath);
998 return;
1001 reply_nterror(req, status);
1004 /****************************************************************************
1005 Reply to a getatr.
1006 ****************************************************************************/
1008 void reply_getatr(struct smb_request *req)
1010 connection_struct *conn = req->conn;
1011 char *fname = NULL;
1012 SMB_STRUCT_STAT sbuf;
1013 int mode=0;
1014 SMB_OFF_T size=0;
1015 time_t mtime=0;
1016 char *p;
1017 NTSTATUS status;
1018 TALLOC_CTX *ctx = talloc_tos();
1020 START_PROFILE(SMBgetatr);
1022 p = smb_buf(req->inbuf) + 1;
1023 p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
1024 0, STR_TERMINATE, &status);
1025 if (!NT_STATUS_IS_OK(status)) {
1026 reply_nterror(req, status);
1027 END_PROFILE(SMBgetatr);
1028 return;
1031 status = resolve_dfspath(ctx, conn,
1032 req->flags2 & FLAGS2_DFS_PATHNAMES,
1033 fname,
1034 &fname);
1035 if (!NT_STATUS_IS_OK(status)) {
1036 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1037 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1038 ERRSRV, ERRbadpath);
1039 END_PROFILE(SMBgetatr);
1040 return;
1042 reply_nterror(req, status);
1043 END_PROFILE(SMBgetatr);
1044 return;
1047 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1048 under WfWg - weird! */
1049 if (*fname == '\0') {
1050 mode = aHIDDEN | aDIR;
1051 if (!CAN_WRITE(conn)) {
1052 mode |= aRONLY;
1054 size = 0;
1055 mtime = 0;
1056 } else {
1057 status = unix_convert(ctx, conn, fname, False, &fname, NULL,&sbuf);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 reply_nterror(req, status);
1060 END_PROFILE(SMBgetatr);
1061 return;
1063 status = check_name(conn, fname);
1064 if (!NT_STATUS_IS_OK(status)) {
1065 DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status)));
1066 reply_nterror(req, status);
1067 END_PROFILE(SMBgetatr);
1068 return;
1070 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) {
1071 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
1072 reply_unixerror(req, ERRDOS,ERRbadfile);
1073 END_PROFILE(SMBgetatr);
1074 return;
1077 mode = dos_mode(conn,fname,&sbuf);
1078 size = sbuf.st_size;
1079 mtime = sbuf.st_mtime;
1080 if (mode & aDIR) {
1081 size = 0;
1085 reply_outbuf(req, 10, 0);
1087 SSVAL(req->outbuf,smb_vwv0,mode);
1088 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1089 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1090 } else {
1091 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1093 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1095 if (Protocol >= PROTOCOL_NT1) {
1096 SSVAL(req->outbuf, smb_flg2,
1097 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1100 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) );
1102 END_PROFILE(SMBgetatr);
1103 return;
1106 /****************************************************************************
1107 Reply to a setatr.
1108 ****************************************************************************/
1110 void reply_setatr(struct smb_request *req)
1112 struct timespec ts[2];
1113 connection_struct *conn = req->conn;
1114 char *fname = NULL;
1115 int mode;
1116 time_t mtime;
1117 SMB_STRUCT_STAT sbuf;
1118 char *p;
1119 NTSTATUS status;
1120 TALLOC_CTX *ctx = talloc_tos();
1122 START_PROFILE(SMBsetatr);
1124 ZERO_STRUCT(ts);
1126 if (req->wct < 2) {
1127 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1128 return;
1131 p = smb_buf(req->inbuf) + 1;
1132 p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
1133 0, STR_TERMINATE, &status);
1134 if (!NT_STATUS_IS_OK(status)) {
1135 reply_nterror(req, status);
1136 END_PROFILE(SMBsetatr);
1137 return;
1140 status = resolve_dfspath(ctx, conn,
1141 req->flags2 & FLAGS2_DFS_PATHNAMES,
1142 fname,
1143 &fname);
1144 if (!NT_STATUS_IS_OK(status)) {
1145 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1146 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1147 ERRSRV, ERRbadpath);
1148 END_PROFILE(SMBsetatr);
1149 return;
1151 reply_nterror(req, status);
1152 END_PROFILE(SMBsetatr);
1153 return;
1156 status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
1157 if (!NT_STATUS_IS_OK(status)) {
1158 reply_nterror(req, status);
1159 END_PROFILE(SMBsetatr);
1160 return;
1163 status = check_name(conn, fname);
1164 if (!NT_STATUS_IS_OK(status)) {
1165 reply_nterror(req, status);
1166 END_PROFILE(SMBsetatr);
1167 return;
1170 if (fname[0] == '.' && fname[1] == '\0') {
1172 * Not sure here is the right place to catch this
1173 * condition. Might be moved to somewhere else later -- vl
1175 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1176 END_PROFILE(SMBsetatr);
1177 return;
1180 mode = SVAL(req->inbuf,smb_vwv0);
1181 mtime = srv_make_unix_date3(req->inbuf+smb_vwv1);
1183 ts[1] = convert_time_t_to_timespec(mtime);
1184 status = smb_set_file_time(conn, NULL, fname,
1185 &sbuf, ts, true);
1186 if (!NT_STATUS_IS_OK(status)) {
1187 reply_unixerror(req, ERRDOS, ERRnoaccess);
1188 END_PROFILE(SMBsetatr);
1189 return;
1192 if (mode != FILE_ATTRIBUTE_NORMAL) {
1193 if (VALID_STAT_OF_DIR(sbuf))
1194 mode |= aDIR;
1195 else
1196 mode &= ~aDIR;
1198 if (file_set_dosmode(conn,fname,mode,&sbuf,NULL,false) != 0) {
1199 reply_unixerror(req, ERRDOS, ERRnoaccess);
1200 END_PROFILE(SMBsetatr);
1201 return;
1205 reply_outbuf(req, 0, 0);
1207 DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
1209 END_PROFILE(SMBsetatr);
1210 return;
1213 /****************************************************************************
1214 Reply to a dskattr.
1215 ****************************************************************************/
1217 void reply_dskattr(struct smb_request *req)
1219 connection_struct *conn = req->conn;
1220 SMB_BIG_UINT dfree,dsize,bsize;
1221 START_PROFILE(SMBdskattr);
1223 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
1224 reply_unixerror(req, ERRHRD, ERRgeneral);
1225 END_PROFILE(SMBdskattr);
1226 return;
1229 reply_outbuf(req, 5, 0);
1231 if (Protocol <= PROTOCOL_LANMAN2) {
1232 double total_space, free_space;
1233 /* we need to scale this to a number that DOS6 can handle. We
1234 use floating point so we can handle large drives on systems
1235 that don't have 64 bit integers
1237 we end up displaying a maximum of 2G to DOS systems
1239 total_space = dsize * (double)bsize;
1240 free_space = dfree * (double)bsize;
1242 dsize = (SMB_BIG_UINT)((total_space+63*512) / (64*512));
1243 dfree = (SMB_BIG_UINT)((free_space+63*512) / (64*512));
1245 if (dsize > 0xFFFF) dsize = 0xFFFF;
1246 if (dfree > 0xFFFF) dfree = 0xFFFF;
1248 SSVAL(req->outbuf,smb_vwv0,dsize);
1249 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1250 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1251 SSVAL(req->outbuf,smb_vwv3,dfree);
1252 } else {
1253 SSVAL(req->outbuf,smb_vwv0,dsize);
1254 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1255 SSVAL(req->outbuf,smb_vwv2,512);
1256 SSVAL(req->outbuf,smb_vwv3,dfree);
1259 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1261 END_PROFILE(SMBdskattr);
1262 return;
1265 /****************************************************************************
1266 Reply to a search.
1267 Can be called from SMBsearch, SMBffirst or SMBfunique.
1268 ****************************************************************************/
1270 void reply_search(struct smb_request *req)
1272 connection_struct *conn = req->conn;
1273 char *mask = NULL;
1274 char *directory = NULL;
1275 char *fname = NULL;
1276 SMB_OFF_T size;
1277 uint32 mode;
1278 time_t date;
1279 uint32 dirtype;
1280 unsigned int numentries = 0;
1281 unsigned int maxentries = 0;
1282 bool finished = False;
1283 char *p;
1284 int status_len;
1285 char *path = NULL;
1286 char status[21];
1287 int dptr_num= -1;
1288 bool check_descend = False;
1289 bool expect_close = False;
1290 NTSTATUS nt_status;
1291 bool mask_contains_wcard = False;
1292 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1293 TALLOC_CTX *ctx = talloc_tos();
1294 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1296 START_PROFILE(SMBsearch);
1298 if (req->wct < 2) {
1299 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1300 END_PROFILE(SMBsearch);
1301 return;
1304 if (lp_posix_pathnames()) {
1305 reply_unknown_new(req, CVAL(req->inbuf, smb_com));
1306 END_PROFILE(SMBsearch);
1307 return;
1310 /* If we were called as SMBffirst then we must expect close. */
1311 if(CVAL(req->inbuf,smb_com) == SMBffirst) {
1312 expect_close = True;
1315 reply_outbuf(req, 1, 3);
1316 maxentries = SVAL(req->inbuf,smb_vwv0);
1317 dirtype = SVAL(req->inbuf,smb_vwv1);
1318 p = smb_buf(req->inbuf) + 1;
1319 p += srvstr_get_path_wcard(ctx,
1320 (char *)req->inbuf,
1321 req->flags2,
1322 &path,
1325 STR_TERMINATE,
1326 &nt_status,
1327 &mask_contains_wcard);
1328 if (!NT_STATUS_IS_OK(nt_status)) {
1329 reply_nterror(req, nt_status);
1330 END_PROFILE(SMBsearch);
1331 return;
1334 nt_status = resolve_dfspath_wcard(ctx, conn,
1335 req->flags2 & FLAGS2_DFS_PATHNAMES,
1336 path,
1337 &path,
1338 &mask_contains_wcard);
1339 if (!NT_STATUS_IS_OK(nt_status)) {
1340 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1341 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1342 ERRSRV, ERRbadpath);
1343 END_PROFILE(SMBsearch);
1344 return;
1346 reply_nterror(req, nt_status);
1347 END_PROFILE(SMBsearch);
1348 return;
1351 p++;
1352 status_len = SVAL(p, 0);
1353 p += 2;
1355 /* dirtype &= ~aDIR; */
1357 if (status_len == 0) {
1358 SMB_STRUCT_STAT sbuf;
1360 nt_status = unix_convert(ctx, conn, path, True,
1361 &directory, NULL, &sbuf);
1362 if (!NT_STATUS_IS_OK(nt_status)) {
1363 reply_nterror(req, nt_status);
1364 END_PROFILE(SMBsearch);
1365 return;
1368 nt_status = check_name(conn, directory);
1369 if (!NT_STATUS_IS_OK(nt_status)) {
1370 reply_nterror(req, nt_status);
1371 END_PROFILE(SMBsearch);
1372 return;
1375 p = strrchr_m(directory,'/');
1376 if (!p) {
1377 mask = directory;
1378 directory = talloc_strdup(ctx,".");
1379 if (!directory) {
1380 reply_nterror(req, NT_STATUS_NO_MEMORY);
1381 END_PROFILE(SMBsearch);
1382 return;
1384 } else {
1385 *p = 0;
1386 mask = p+1;
1389 if (*directory == '\0') {
1390 directory = talloc_strdup(ctx,".");
1391 if (!directory) {
1392 reply_nterror(req, NT_STATUS_NO_MEMORY);
1393 END_PROFILE(SMBsearch);
1394 return;
1397 memset((char *)status,'\0',21);
1398 SCVAL(status,0,(dirtype & 0x1F));
1400 nt_status = dptr_create(conn,
1401 directory,
1402 True,
1403 expect_close,
1404 req->smbpid,
1405 mask,
1406 mask_contains_wcard,
1407 dirtype,
1408 &conn->dirptr);
1409 if (!NT_STATUS_IS_OK(nt_status)) {
1410 reply_nterror(req, nt_status);
1411 END_PROFILE(SMBsearch);
1412 return;
1414 dptr_num = dptr_dnum(conn->dirptr);
1415 } else {
1416 int status_dirtype;
1418 memcpy(status,p,21);
1419 status_dirtype = CVAL(status,0) & 0x1F;
1420 if (status_dirtype != (dirtype & 0x1F)) {
1421 dirtype = status_dirtype;
1424 conn->dirptr = dptr_fetch(status+12,&dptr_num);
1425 if (!conn->dirptr) {
1426 goto SearchEmpty;
1428 string_set(&conn->dirpath,dptr_path(dptr_num));
1429 mask = dptr_wcard(dptr_num);
1430 if (!mask) {
1431 goto SearchEmpty;
1434 * For a 'continue' search we have no string. So
1435 * check from the initial saved string.
1437 mask_contains_wcard = ms_has_wild(mask);
1438 dirtype = dptr_attr(dptr_num);
1441 DEBUG(4,("dptr_num is %d\n",dptr_num));
1443 if ((dirtype&0x1F) == aVOLID) {
1444 char buf[DIR_STRUCT_SIZE];
1445 memcpy(buf,status,21);
1446 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1447 0,aVOLID,0,!allow_long_path_components)) {
1448 reply_nterror(req, NT_STATUS_NO_MEMORY);
1449 END_PROFILE(SMBsearch);
1450 return;
1452 dptr_fill(buf+12,dptr_num);
1453 if (dptr_zero(buf+12) && (status_len==0)) {
1454 numentries = 1;
1455 } else {
1456 numentries = 0;
1458 if (message_push_blob(&req->outbuf,
1459 data_blob_const(buf, sizeof(buf)))
1460 == -1) {
1461 reply_nterror(req, NT_STATUS_NO_MEMORY);
1462 END_PROFILE(SMBsearch);
1463 return;
1465 } else {
1466 unsigned int i;
1467 maxentries = MIN(
1468 maxentries,
1469 ((BUFFER_SIZE -
1470 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1471 /DIR_STRUCT_SIZE));
1473 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1474 conn->dirpath,lp_dontdescend(SNUM(conn))));
1475 if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True)) {
1476 check_descend = True;
1479 for (i=numentries;(i<maxentries) && !finished;i++) {
1480 finished = !get_dir_entry(ctx,
1481 conn,
1482 mask,
1483 dirtype,
1484 &fname,
1485 &size,
1486 &mode,
1487 &date,
1488 check_descend,
1489 ask_sharemode);
1490 if (!finished) {
1491 char buf[DIR_STRUCT_SIZE];
1492 memcpy(buf,status,21);
1493 if (!make_dir_struct(ctx,
1494 buf,
1495 mask,
1496 fname,
1497 size,
1498 mode,
1499 date,
1500 !allow_long_path_components)) {
1501 reply_nterror(req, NT_STATUS_NO_MEMORY);
1502 END_PROFILE(SMBsearch);
1503 return;
1505 if (!dptr_fill(buf+12,dptr_num)) {
1506 break;
1508 if (message_push_blob(&req->outbuf,
1509 data_blob_const(buf, sizeof(buf)))
1510 == -1) {
1511 reply_nterror(req, NT_STATUS_NO_MEMORY);
1512 END_PROFILE(SMBsearch);
1513 return;
1515 numentries++;
1520 SearchEmpty:
1522 /* If we were called as SMBffirst with smb_search_id == NULL
1523 and no entries were found then return error and close dirptr
1524 (X/Open spec) */
1526 if (numentries == 0) {
1527 dptr_close(&dptr_num);
1528 } else if(expect_close && status_len == 0) {
1529 /* Close the dptr - we know it's gone */
1530 dptr_close(&dptr_num);
1533 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1534 if(dptr_num >= 0 && CVAL(req->inbuf,smb_com) == SMBfunique) {
1535 dptr_close(&dptr_num);
1538 if ((numentries == 0) && !mask_contains_wcard) {
1539 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1540 END_PROFILE(SMBsearch);
1541 return;
1544 SSVAL(req->outbuf,smb_vwv0,numentries);
1545 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1546 SCVAL(smb_buf(req->outbuf),0,5);
1547 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1549 /* The replies here are never long name. */
1550 SSVAL(req->outbuf, smb_flg2,
1551 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1552 if (!allow_long_path_components) {
1553 SSVAL(req->outbuf, smb_flg2,
1554 SVAL(req->outbuf, smb_flg2)
1555 & (~FLAGS2_LONG_PATH_COMPONENTS));
1558 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1559 SSVAL(req->outbuf, smb_flg2,
1560 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1562 if (!directory) {
1563 directory = dptr_path(dptr_num);
1566 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1567 smb_fn_name(CVAL(req->inbuf,smb_com)),
1568 mask,
1569 directory ? directory : "./",
1570 dirtype,
1571 numentries,
1572 maxentries ));
1574 END_PROFILE(SMBsearch);
1575 return;
1578 /****************************************************************************
1579 Reply to a fclose (stop directory search).
1580 ****************************************************************************/
1582 void reply_fclose(struct smb_request *req)
1584 int status_len;
1585 char status[21];
1586 int dptr_num= -2;
1587 char *p;
1588 char *path = NULL;
1589 NTSTATUS err;
1590 bool path_contains_wcard = False;
1591 TALLOC_CTX *ctx = talloc_tos();
1593 START_PROFILE(SMBfclose);
1595 if (lp_posix_pathnames()) {
1596 reply_unknown_new(req, CVAL(req->inbuf, smb_com));
1597 END_PROFILE(SMBfclose);
1598 return;
1601 p = smb_buf(req->inbuf) + 1;
1602 p += srvstr_get_path_wcard(ctx,
1603 (char *)req->inbuf,
1604 req->flags2,
1605 &path,
1608 STR_TERMINATE,
1609 &err,
1610 &path_contains_wcard);
1611 if (!NT_STATUS_IS_OK(err)) {
1612 reply_nterror(req, err);
1613 END_PROFILE(SMBfclose);
1614 return;
1616 p++;
1617 status_len = SVAL(p,0);
1618 p += 2;
1620 if (status_len == 0) {
1621 reply_doserror(req, ERRSRV, ERRsrverror);
1622 END_PROFILE(SMBfclose);
1623 return;
1626 memcpy(status,p,21);
1628 if(dptr_fetch(status+12,&dptr_num)) {
1629 /* Close the dptr - we know it's gone */
1630 dptr_close(&dptr_num);
1633 reply_outbuf(req, 1, 0);
1634 SSVAL(req->outbuf,smb_vwv0,0);
1636 DEBUG(3,("search close\n"));
1638 END_PROFILE(SMBfclose);
1639 return;
1642 /****************************************************************************
1643 Reply to an open.
1644 ****************************************************************************/
1646 void reply_open(struct smb_request *req)
1648 connection_struct *conn = req->conn;
1649 char *fname = NULL;
1650 uint32 fattr=0;
1651 SMB_OFF_T size = 0;
1652 time_t mtime=0;
1653 int info;
1654 SMB_STRUCT_STAT sbuf;
1655 files_struct *fsp;
1656 int oplock_request;
1657 int deny_mode;
1658 uint32 dos_attr;
1659 uint32 access_mask;
1660 uint32 share_mode;
1661 uint32 create_disposition;
1662 uint32 create_options = 0;
1663 NTSTATUS status;
1664 TALLOC_CTX *ctx = talloc_tos();
1666 START_PROFILE(SMBopen);
1668 if (req->wct < 2) {
1669 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1670 END_PROFILE(SMBopen);
1671 return;
1674 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1675 deny_mode = SVAL(req->inbuf,smb_vwv0);
1676 dos_attr = SVAL(req->inbuf,smb_vwv1);
1678 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1679 smb_buf(req->inbuf)+1, 0,
1680 STR_TERMINATE, &status);
1681 if (!NT_STATUS_IS_OK(status)) {
1682 reply_nterror(req, status);
1683 END_PROFILE(SMBopen);
1684 return;
1687 if (!map_open_params_to_ntcreate(
1688 fname, deny_mode, OPENX_FILE_EXISTS_OPEN, &access_mask,
1689 &share_mode, &create_disposition, &create_options)) {
1690 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1691 END_PROFILE(SMBopen);
1692 return;
1695 status = create_file(conn, /* conn */
1696 req, /* req */
1697 0, /* root_dir_fid */
1698 fname, /* fname */
1699 access_mask, /* access_mask */
1700 share_mode, /* share_access */
1701 create_disposition, /* create_disposition*/
1702 create_options, /* create_options */
1703 dos_attr, /* file_attributes */
1704 oplock_request, /* oplock_request */
1705 0, /* allocation_size */
1706 NULL, /* sd */
1707 NULL, /* ea_list */
1708 &fsp, /* result */
1709 &info, /* pinfo */
1710 &sbuf); /* psbuf */
1712 if (!NT_STATUS_IS_OK(status)) {
1713 if (open_was_deferred(req->mid)) {
1714 /* We have re-scheduled this call. */
1715 END_PROFILE(SMBopen);
1716 return;
1718 reply_openerror(req, status);
1719 END_PROFILE(SMBopen);
1720 return;
1723 size = sbuf.st_size;
1724 fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
1725 mtime = sbuf.st_mtime;
1727 if (fattr & aDIR) {
1728 DEBUG(3,("attempt to open a directory %s\n",fsp->fsp_name));
1729 close_file(fsp,ERROR_CLOSE);
1730 reply_doserror(req, ERRDOS,ERRnoaccess);
1731 END_PROFILE(SMBopen);
1732 return;
1735 reply_outbuf(req, 7, 0);
1736 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1737 SSVAL(req->outbuf,smb_vwv1,fattr);
1738 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1739 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1740 } else {
1741 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1743 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1744 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1746 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1747 SCVAL(req->outbuf,smb_flg,
1748 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1751 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1752 SCVAL(req->outbuf,smb_flg,
1753 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1755 END_PROFILE(SMBopen);
1756 return;
1759 /****************************************************************************
1760 Reply to an open and X.
1761 ****************************************************************************/
1763 void reply_open_and_X(struct smb_request *req)
1765 connection_struct *conn = req->conn;
1766 char *fname = NULL;
1767 uint16 open_flags;
1768 int deny_mode;
1769 uint32 smb_attr;
1770 /* Breakout the oplock request bits so we can set the
1771 reply bits separately. */
1772 int ex_oplock_request;
1773 int core_oplock_request;
1774 int oplock_request;
1775 #if 0
1776 int smb_sattr = SVAL(req->inbuf,smb_vwv4);
1777 uint32 smb_time = make_unix_date3(req->inbuf+smb_vwv6);
1778 #endif
1779 int smb_ofun;
1780 uint32 fattr=0;
1781 int mtime=0;
1782 SMB_STRUCT_STAT sbuf;
1783 int smb_action = 0;
1784 files_struct *fsp;
1785 NTSTATUS status;
1786 SMB_BIG_UINT allocation_size;
1787 ssize_t retval = -1;
1788 uint32 access_mask;
1789 uint32 share_mode;
1790 uint32 create_disposition;
1791 uint32 create_options = 0;
1792 TALLOC_CTX *ctx = talloc_tos();
1794 START_PROFILE(SMBopenX);
1796 if (req->wct < 15) {
1797 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1798 END_PROFILE(SMBopenX);
1799 return;
1802 open_flags = SVAL(req->inbuf,smb_vwv2);
1803 deny_mode = SVAL(req->inbuf,smb_vwv3);
1804 smb_attr = SVAL(req->inbuf,smb_vwv5);
1805 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1806 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1807 oplock_request = ex_oplock_request | core_oplock_request;
1808 smb_ofun = SVAL(req->inbuf,smb_vwv8);
1809 allocation_size = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv9);
1811 /* If it's an IPC, pass off the pipe handler. */
1812 if (IS_IPC(conn)) {
1813 if (lp_nt_pipe_support()) {
1814 reply_open_pipe_and_X(conn, req);
1815 } else {
1816 reply_doserror(req, ERRSRV, ERRaccess);
1818 END_PROFILE(SMBopenX);
1819 return;
1822 /* XXXX we need to handle passed times, sattr and flags */
1823 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1824 smb_buf(req->inbuf), 0, STR_TERMINATE,
1825 &status);
1826 if (!NT_STATUS_IS_OK(status)) {
1827 reply_nterror(req, status);
1828 END_PROFILE(SMBopenX);
1829 return;
1832 if (!map_open_params_to_ntcreate(
1833 fname, deny_mode, smb_ofun, &access_mask,
1834 &share_mode, &create_disposition, &create_options)) {
1835 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1836 END_PROFILE(SMBopenX);
1837 return;
1840 status = create_file(conn, /* conn */
1841 req, /* req */
1842 0, /* root_dir_fid */
1843 fname, /* fname */
1844 access_mask, /* access_mask */
1845 share_mode, /* share_access */
1846 create_disposition, /* create_disposition*/
1847 create_options, /* create_options */
1848 smb_attr, /* file_attributes */
1849 oplock_request, /* oplock_request */
1850 0, /* allocation_size */
1851 NULL, /* sd */
1852 NULL, /* ea_list */
1853 &fsp, /* result */
1854 &smb_action, /* pinfo */
1855 &sbuf); /* psbuf */
1857 if (!NT_STATUS_IS_OK(status)) {
1858 END_PROFILE(SMBopenX);
1859 if (open_was_deferred(req->mid)) {
1860 /* We have re-scheduled this call. */
1861 return;
1863 reply_openerror(req, status);
1864 return;
1867 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1868 if the file is truncated or created. */
1869 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1870 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1871 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1872 close_file(fsp,ERROR_CLOSE);
1873 reply_nterror(req, NT_STATUS_DISK_FULL);
1874 END_PROFILE(SMBopenX);
1875 return;
1877 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1878 if (retval < 0) {
1879 close_file(fsp,ERROR_CLOSE);
1880 reply_nterror(req, NT_STATUS_DISK_FULL);
1881 END_PROFILE(SMBopenX);
1882 return;
1884 sbuf.st_size = get_allocation_size(conn,fsp,&sbuf);
1887 fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
1888 mtime = sbuf.st_mtime;
1889 if (fattr & aDIR) {
1890 close_file(fsp,ERROR_CLOSE);
1891 reply_doserror(req, ERRDOS, ERRnoaccess);
1892 END_PROFILE(SMBopenX);
1893 return;
1896 /* If the caller set the extended oplock request bit
1897 and we granted one (by whatever means) - set the
1898 correct bit for extended oplock reply.
1901 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1902 smb_action |= EXTENDED_OPLOCK_GRANTED;
1905 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1906 smb_action |= EXTENDED_OPLOCK_GRANTED;
1909 /* If the caller set the core oplock request bit
1910 and we granted one (by whatever means) - set the
1911 correct bit for core oplock reply.
1914 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1915 reply_outbuf(req, 19, 0);
1916 } else {
1917 reply_outbuf(req, 15, 0);
1920 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1921 SCVAL(req->outbuf, smb_flg,
1922 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1925 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1926 SCVAL(req->outbuf, smb_flg,
1927 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1930 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
1931 SSVAL(req->outbuf,smb_vwv3,fattr);
1932 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1933 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
1934 } else {
1935 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
1937 SIVAL(req->outbuf,smb_vwv6,(uint32)sbuf.st_size);
1938 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
1939 SSVAL(req->outbuf,smb_vwv11,smb_action);
1941 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1942 SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS);
1945 END_PROFILE(SMBopenX);
1946 chain_reply(req);
1947 return;
1950 /****************************************************************************
1951 Reply to a SMBulogoffX.
1952 ****************************************************************************/
1954 void reply_ulogoffX(struct smb_request *req)
1956 user_struct *vuser;
1958 START_PROFILE(SMBulogoffX);
1960 vuser = get_valid_user_struct(req->vuid);
1962 if(vuser == NULL) {
1963 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
1964 req->vuid));
1967 /* in user level security we are supposed to close any files
1968 open by this user */
1969 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
1970 file_close_user(req->vuid);
1973 invalidate_vuid(req->vuid);
1975 reply_outbuf(req, 2, 0);
1977 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
1979 END_PROFILE(SMBulogoffX);
1980 chain_reply(req);
1983 /****************************************************************************
1984 Reply to a mknew or a create.
1985 ****************************************************************************/
1987 void reply_mknew(struct smb_request *req)
1989 connection_struct *conn = req->conn;
1990 char *fname = NULL;
1991 int com;
1992 uint32 fattr = 0;
1993 struct timespec ts[2];
1994 files_struct *fsp;
1995 int oplock_request = 0;
1996 SMB_STRUCT_STAT sbuf;
1997 NTSTATUS status;
1998 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
1999 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2000 uint32 create_disposition;
2001 uint32 create_options = 0;
2002 TALLOC_CTX *ctx = talloc_tos();
2004 START_PROFILE(SMBcreate);
2006 if (req->wct < 3) {
2007 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2008 END_PROFILE(SMBcreate);
2009 return;
2012 fattr = SVAL(req->inbuf,smb_vwv0);
2013 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2014 com = SVAL(req->inbuf,smb_com);
2016 ts[1] =convert_time_t_to_timespec(
2017 srv_make_unix_date3(req->inbuf + smb_vwv1));
2018 /* mtime. */
2020 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
2021 smb_buf(req->inbuf) + 1, 0,
2022 STR_TERMINATE, &status);
2023 if (!NT_STATUS_IS_OK(status)) {
2024 reply_nterror(req, status);
2025 END_PROFILE(SMBcreate);
2026 return;
2029 if (fattr & aVOLID) {
2030 DEBUG(0,("Attempt to create file (%s) with volid set - "
2031 "please report this\n", fname));
2034 if(com == SMBmknew) {
2035 /* We should fail if file exists. */
2036 create_disposition = FILE_CREATE;
2037 } else {
2038 /* Create if file doesn't exist, truncate if it does. */
2039 create_disposition = FILE_OVERWRITE_IF;
2042 status = create_file(conn, /* conn */
2043 req, /* req */
2044 0, /* root_dir_fid */
2045 fname, /* fname */
2046 access_mask, /* access_mask */
2047 share_mode, /* share_access */
2048 create_disposition, /* create_disposition*/
2049 create_options, /* create_options */
2050 fattr, /* file_attributes */
2051 oplock_request, /* oplock_request */
2052 0, /* allocation_size */
2053 NULL, /* sd */
2054 NULL, /* ea_list */
2055 &fsp, /* result */
2056 NULL, /* pinfo */
2057 &sbuf); /* psbuf */
2059 if (!NT_STATUS_IS_OK(status)) {
2060 END_PROFILE(SMBcreate);
2061 if (open_was_deferred(req->mid)) {
2062 /* We have re-scheduled this call. */
2063 return;
2065 reply_openerror(req, status);
2066 return;
2069 ts[0] = get_atimespec(&sbuf); /* atime. */
2070 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, ts, true);
2071 if (!NT_STATUS_IS_OK(status)) {
2072 END_PROFILE(SMBcreate);
2073 reply_openerror(req, status);
2074 return;
2077 reply_outbuf(req, 1, 0);
2078 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2080 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2081 SCVAL(req->outbuf,smb_flg,
2082 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2085 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2086 SCVAL(req->outbuf,smb_flg,
2087 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2090 DEBUG( 2, ( "reply_mknew: file %s\n", fsp->fsp_name ) );
2091 DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n",
2092 fsp->fsp_name, fsp->fh->fd, (unsigned int)fattr ) );
2094 END_PROFILE(SMBcreate);
2095 return;
2098 /****************************************************************************
2099 Reply to a create temporary file.
2100 ****************************************************************************/
2102 void reply_ctemp(struct smb_request *req)
2104 connection_struct *conn = req->conn;
2105 char *fname = NULL;
2106 uint32 fattr;
2107 files_struct *fsp;
2108 int oplock_request;
2109 int tmpfd;
2110 SMB_STRUCT_STAT sbuf;
2111 char *s;
2112 NTSTATUS status;
2113 TALLOC_CTX *ctx = talloc_tos();
2115 START_PROFILE(SMBctemp);
2117 if (req->wct < 3) {
2118 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2119 END_PROFILE(SMBctemp);
2120 return;
2123 fattr = SVAL(req->inbuf,smb_vwv0);
2124 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2126 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
2127 smb_buf(req->inbuf)+1, 0, STR_TERMINATE,
2128 &status);
2129 if (!NT_STATUS_IS_OK(status)) {
2130 reply_nterror(req, status);
2131 END_PROFILE(SMBctemp);
2132 return;
2134 if (*fname) {
2135 fname = talloc_asprintf(ctx,
2136 "%s/TMXXXXXX",
2137 fname);
2138 } else {
2139 fname = talloc_strdup(ctx, "TMXXXXXX");
2142 if (!fname) {
2143 reply_nterror(req, NT_STATUS_NO_MEMORY);
2144 END_PROFILE(SMBctemp);
2145 return;
2148 status = resolve_dfspath(ctx, conn,
2149 req->flags2 & FLAGS2_DFS_PATHNAMES,
2150 fname,
2151 &fname);
2152 if (!NT_STATUS_IS_OK(status)) {
2153 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2154 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2155 ERRSRV, ERRbadpath);
2156 END_PROFILE(SMBctemp);
2157 return;
2159 reply_nterror(req, status);
2160 END_PROFILE(SMBctemp);
2161 return;
2164 status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
2165 if (!NT_STATUS_IS_OK(status)) {
2166 reply_nterror(req, status);
2167 END_PROFILE(SMBctemp);
2168 return;
2171 status = check_name(conn, fname);
2172 if (!NT_STATUS_IS_OK(status)) {
2173 reply_nterror(req, status);
2174 END_PROFILE(SMBctemp);
2175 return;
2178 tmpfd = smb_mkstemp(fname);
2179 if (tmpfd == -1) {
2180 reply_unixerror(req, ERRDOS, ERRnoaccess);
2181 END_PROFILE(SMBctemp);
2182 return;
2185 SMB_VFS_STAT(conn,fname,&sbuf);
2187 /* We should fail if file does not exist. */
2188 status = open_file_ntcreate(conn, req, fname, &sbuf,
2189 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
2190 FILE_SHARE_READ|FILE_SHARE_WRITE,
2191 FILE_OPEN,
2193 fattr,
2194 oplock_request,
2195 NULL, &fsp);
2197 /* close fd from smb_mkstemp() */
2198 close(tmpfd);
2200 if (!NT_STATUS_IS_OK(status)) {
2201 if (open_was_deferred(req->mid)) {
2202 /* We have re-scheduled this call. */
2203 END_PROFILE(SMBctemp);
2204 return;
2206 reply_openerror(req, status);
2207 END_PROFILE(SMBctemp);
2208 return;
2211 reply_outbuf(req, 1, 0);
2212 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2214 /* the returned filename is relative to the directory */
2215 s = strrchr_m(fsp->fsp_name, '/');
2216 if (!s) {
2217 s = fsp->fsp_name;
2218 } else {
2219 s++;
2222 #if 0
2223 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2224 thing in the byte section. JRA */
2225 SSVALS(p, 0, -1); /* what is this? not in spec */
2226 #endif
2227 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2228 == -1) {
2229 reply_nterror(req, NT_STATUS_NO_MEMORY);
2230 END_PROFILE(SMBctemp);
2231 return;
2234 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2235 SCVAL(req->outbuf, smb_flg,
2236 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2239 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2240 SCVAL(req->outbuf, smb_flg,
2241 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2244 DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) );
2245 DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name,
2246 fsp->fh->fd, (unsigned int)sbuf.st_mode ) );
2248 END_PROFILE(SMBctemp);
2249 return;
2252 /*******************************************************************
2253 Check if a user is allowed to rename a file.
2254 ********************************************************************/
2256 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2257 uint16 dirtype, SMB_STRUCT_STAT *pst)
2259 uint32 fmode;
2261 if (!CAN_WRITE(conn)) {
2262 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2265 fmode = dos_mode(conn, fsp->fsp_name, pst);
2266 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2267 return NT_STATUS_NO_SUCH_FILE;
2270 if (S_ISDIR(pst->st_mode)) {
2271 if (fsp->posix_open) {
2272 return NT_STATUS_OK;
2275 /* If no pathnames are open below this
2276 directory, allow the rename. */
2278 if (file_find_subpath(fsp)) {
2279 return NT_STATUS_ACCESS_DENIED;
2281 return NT_STATUS_OK;
2284 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2285 return NT_STATUS_OK;
2288 return NT_STATUS_ACCESS_DENIED;
2291 /*******************************************************************
2292 * unlink a file with all relevant access checks
2293 *******************************************************************/
2295 static NTSTATUS do_unlink(connection_struct *conn,
2296 struct smb_request *req,
2297 const char *fname,
2298 uint32 dirtype)
2300 SMB_STRUCT_STAT sbuf;
2301 uint32 fattr;
2302 files_struct *fsp;
2303 uint32 dirtype_orig = dirtype;
2304 NTSTATUS status;
2306 DEBUG(10,("do_unlink: %s, dirtype = %d\n", fname, dirtype ));
2308 if (!CAN_WRITE(conn)) {
2309 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2312 if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) {
2313 return map_nt_error_from_unix(errno);
2316 fattr = dos_mode(conn,fname,&sbuf);
2318 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2319 dirtype = aDIR|aARCH|aRONLY;
2322 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2323 if (!dirtype) {
2324 return NT_STATUS_NO_SUCH_FILE;
2327 if (!dir_check_ftype(conn, fattr, dirtype)) {
2328 if (fattr & aDIR) {
2329 return NT_STATUS_FILE_IS_A_DIRECTORY;
2331 return NT_STATUS_NO_SUCH_FILE;
2334 if (dirtype_orig & 0x8000) {
2335 /* These will never be set for POSIX. */
2336 return NT_STATUS_NO_SUCH_FILE;
2339 #if 0
2340 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2341 return NT_STATUS_FILE_IS_A_DIRECTORY;
2344 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2345 return NT_STATUS_NO_SUCH_FILE;
2348 if (dirtype & 0xFF00) {
2349 /* These will never be set for POSIX. */
2350 return NT_STATUS_NO_SUCH_FILE;
2353 dirtype &= 0xFF;
2354 if (!dirtype) {
2355 return NT_STATUS_NO_SUCH_FILE;
2358 /* Can't delete a directory. */
2359 if (fattr & aDIR) {
2360 return NT_STATUS_FILE_IS_A_DIRECTORY;
2362 #endif
2364 #if 0 /* JRATEST */
2365 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2366 return NT_STATUS_OBJECT_NAME_INVALID;
2367 #endif /* JRATEST */
2369 /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com>
2371 On a Windows share, a file with read-only dosmode can be opened with
2372 DELETE_ACCESS. But on a Samba share (delete readonly = no), it
2373 fails with NT_STATUS_CANNOT_DELETE error.
2375 This semantic causes a problem that a user can not
2376 rename a file with read-only dosmode on a Samba share
2377 from a Windows command prompt (i.e. cmd.exe, but can rename
2378 from Windows Explorer).
2381 if (!lp_delete_readonly(SNUM(conn))) {
2382 if (fattr & aRONLY) {
2383 return NT_STATUS_CANNOT_DELETE;
2387 /* On open checks the open itself will check the share mode, so
2388 don't do it here as we'll get it wrong. */
2390 status = create_file_unixpath
2391 (conn, /* conn */
2392 req, /* req */
2393 fname, /* fname */
2394 DELETE_ACCESS, /* access_mask */
2395 FILE_SHARE_NONE, /* share_access */
2396 FILE_OPEN, /* create_disposition*/
2397 FILE_NON_DIRECTORY_FILE, /* create_options */
2398 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2399 0, /* oplock_request */
2400 0, /* allocation_size */
2401 NULL, /* sd */
2402 NULL, /* ea_list */
2403 &fsp, /* result */
2404 NULL, /* pinfo */
2405 &sbuf); /* psbuf */
2407 if (!NT_STATUS_IS_OK(status)) {
2408 DEBUG(10, ("create_file_unixpath failed: %s\n",
2409 nt_errstr(status)));
2410 return status;
2413 /* The set is across all open files on this dev/inode pair. */
2414 if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) {
2415 close_file(fsp, NORMAL_CLOSE);
2416 return NT_STATUS_ACCESS_DENIED;
2419 return close_file(fsp,NORMAL_CLOSE);
2422 /****************************************************************************
2423 The guts of the unlink command, split out so it may be called by the NT SMB
2424 code.
2425 ****************************************************************************/
2427 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2428 uint32 dirtype, const char *name_in, bool has_wild)
2430 const char *directory = NULL;
2431 char *mask = NULL;
2432 char *name = NULL;
2433 char *p = NULL;
2434 int count=0;
2435 NTSTATUS status = NT_STATUS_OK;
2436 SMB_STRUCT_STAT sbuf;
2437 TALLOC_CTX *ctx = talloc_tos();
2439 status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf);
2440 if (!NT_STATUS_IS_OK(status)) {
2441 return status;
2444 p = strrchr_m(name,'/');
2445 if (!p) {
2446 directory = talloc_strdup(ctx, ".");
2447 if (!directory) {
2448 return NT_STATUS_NO_MEMORY;
2450 mask = name;
2451 } else {
2452 *p = 0;
2453 directory = name;
2454 mask = p+1;
2458 * We should only check the mangled cache
2459 * here if unix_convert failed. This means
2460 * that the path in 'mask' doesn't exist
2461 * on the file system and so we need to look
2462 * for a possible mangle. This patch from
2463 * Tine Smukavec <valentin.smukavec@hermes.si>.
2466 if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) {
2467 char *new_mask = NULL;
2468 mangle_lookup_name_from_8_3(ctx,
2469 mask,
2470 &new_mask,
2471 conn->params );
2472 if (new_mask) {
2473 mask = new_mask;
2477 if (!has_wild) {
2478 directory = talloc_asprintf(ctx,
2479 "%s/%s",
2480 directory,
2481 mask);
2482 if (!directory) {
2483 return NT_STATUS_NO_MEMORY;
2485 if (dirtype == 0) {
2486 dirtype = FILE_ATTRIBUTE_NORMAL;
2489 status = check_name(conn, directory);
2490 if (!NT_STATUS_IS_OK(status)) {
2491 return status;
2494 status = do_unlink(conn, req, directory, dirtype);
2495 if (!NT_STATUS_IS_OK(status)) {
2496 return status;
2499 count++;
2500 } else {
2501 struct smb_Dir *dir_hnd = NULL;
2502 long offset = 0;
2503 const char *dname;
2505 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2506 return NT_STATUS_OBJECT_NAME_INVALID;
2509 if (strequal(mask,"????????.???")) {
2510 mask[0] = '*';
2511 mask[1] = '\0';
2514 status = check_name(conn, directory);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 return status;
2519 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask,
2520 dirtype);
2521 if (dir_hnd == NULL) {
2522 return map_nt_error_from_unix(errno);
2525 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2526 the pattern matches against the long name, otherwise the short name
2527 We don't implement this yet XXXX
2530 status = NT_STATUS_NO_SUCH_FILE;
2532 while ((dname = ReadDirName(dir_hnd, &offset))) {
2533 SMB_STRUCT_STAT st;
2534 char *fname = NULL;
2536 if (!is_visible_file(conn, directory, dname, &st, True)) {
2537 continue;
2540 /* Quick check for "." and ".." */
2541 if (ISDOT(dname) || ISDOTDOT(dname)) {
2542 continue;
2545 if(!mask_match(dname, mask, conn->case_sensitive)) {
2546 continue;
2549 fname = talloc_asprintf(ctx, "%s/%s",
2550 directory,
2551 dname);
2552 if (!fname) {
2553 return NT_STATUS_NO_MEMORY;
2556 status = check_name(conn, fname);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 TALLOC_FREE(dir_hnd);
2559 return status;
2562 status = do_unlink(conn, req, fname, dirtype);
2563 if (!NT_STATUS_IS_OK(status)) {
2564 TALLOC_FREE(fname);
2565 continue;
2568 count++;
2569 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2570 fname));
2572 TALLOC_FREE(fname);
2574 TALLOC_FREE(dir_hnd);
2577 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2578 status = map_nt_error_from_unix(errno);
2581 return status;
2584 /****************************************************************************
2585 Reply to a unlink
2586 ****************************************************************************/
2588 void reply_unlink(struct smb_request *req)
2590 connection_struct *conn = req->conn;
2591 char *name = NULL;
2592 uint32 dirtype;
2593 NTSTATUS status;
2594 bool path_contains_wcard = False;
2595 TALLOC_CTX *ctx = talloc_tos();
2597 START_PROFILE(SMBunlink);
2599 if (req->wct < 1) {
2600 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2601 END_PROFILE(SMBunlink);
2602 return;
2605 dirtype = SVAL(req->inbuf,smb_vwv0);
2607 srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name,
2608 smb_buf(req->inbuf) + 1, 0,
2609 STR_TERMINATE, &status, &path_contains_wcard);
2610 if (!NT_STATUS_IS_OK(status)) {
2611 reply_nterror(req, status);
2612 END_PROFILE(SMBunlink);
2613 return;
2616 status = resolve_dfspath_wcard(ctx, conn,
2617 req->flags2 & FLAGS2_DFS_PATHNAMES,
2618 name,
2619 &name,
2620 &path_contains_wcard);
2621 if (!NT_STATUS_IS_OK(status)) {
2622 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2623 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2624 ERRSRV, ERRbadpath);
2625 END_PROFILE(SMBunlink);
2626 return;
2628 reply_nterror(req, status);
2629 END_PROFILE(SMBunlink);
2630 return;
2633 DEBUG(3,("reply_unlink : %s\n",name));
2635 status = unlink_internals(conn, req, dirtype, name,
2636 path_contains_wcard);
2637 if (!NT_STATUS_IS_OK(status)) {
2638 if (open_was_deferred(req->mid)) {
2639 /* We have re-scheduled this call. */
2640 END_PROFILE(SMBunlink);
2641 return;
2643 reply_nterror(req, status);
2644 END_PROFILE(SMBunlink);
2645 return;
2648 reply_outbuf(req, 0, 0);
2649 END_PROFILE(SMBunlink);
2651 return;
2654 /****************************************************************************
2655 Fail for readbraw.
2656 ****************************************************************************/
2658 static void fail_readraw(void)
2660 const char *errstr = talloc_asprintf(talloc_tos(),
2661 "FAIL ! reply_readbraw: socket write fail (%s)",
2662 strerror(errno));
2663 if (!errstr) {
2664 errstr = "";
2666 exit_server_cleanly(errstr);
2669 /****************************************************************************
2670 Fake (read/write) sendfile. Returns -1 on read or write fail.
2671 ****************************************************************************/
2673 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
2674 size_t nread)
2676 size_t bufsize;
2677 size_t tosend = nread;
2678 char *buf;
2680 if (nread == 0) {
2681 return 0;
2684 bufsize = MIN(nread, 65536);
2686 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2687 return -1;
2690 while (tosend > 0) {
2691 ssize_t ret;
2692 size_t cur_read;
2694 if (tosend > bufsize) {
2695 cur_read = bufsize;
2696 } else {
2697 cur_read = tosend;
2699 ret = read_file(fsp,buf,startpos,cur_read);
2700 if (ret == -1) {
2701 SAFE_FREE(buf);
2702 return -1;
2705 /* If we had a short read, fill with zeros. */
2706 if (ret < cur_read) {
2707 memset(buf, '\0', cur_read - ret);
2710 if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
2711 SAFE_FREE(buf);
2712 return -1;
2714 tosend -= cur_read;
2715 startpos += cur_read;
2718 SAFE_FREE(buf);
2719 return (ssize_t)nread;
2722 /****************************************************************************
2723 Return a readbraw error (4 bytes of zero).
2724 ****************************************************************************/
2726 static void reply_readbraw_error(void)
2728 char header[4];
2729 SIVAL(header,0,0);
2730 if (write_data(smbd_server_fd(),header,4) != 4) {
2731 fail_readraw();
2735 /****************************************************************************
2736 Use sendfile in readbraw.
2737 ****************************************************************************/
2739 void send_file_readbraw(connection_struct *conn,
2740 files_struct *fsp,
2741 SMB_OFF_T startpos,
2742 size_t nread,
2743 ssize_t mincount)
2745 char *outbuf = NULL;
2746 ssize_t ret=0;
2748 #if defined(WITH_SENDFILE)
2750 * We can only use sendfile on a non-chained packet
2751 * but we can use on a non-oplocked file. tridge proved this
2752 * on a train in Germany :-). JRA.
2753 * reply_readbraw has already checked the length.
2756 if ( (chain_size == 0) && (nread > 0) && (fsp->base_fsp == NULL) &&
2757 (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) {
2758 char header[4];
2759 DATA_BLOB header_blob;
2761 _smb_setlen(header,nread);
2762 header_blob = data_blob_const(header, 4);
2764 if (SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
2765 &header_blob, startpos, nread) == -1) {
2766 /* Returning ENOSYS means no data at all was sent.
2767 * Do this as a normal read. */
2768 if (errno == ENOSYS) {
2769 goto normal_readbraw;
2773 * Special hack for broken Linux with no working sendfile. If we
2774 * return EINTR we sent the header but not the rest of the data.
2775 * Fake this up by doing read/write calls.
2777 if (errno == EINTR) {
2778 /* Ensure we don't do this again. */
2779 set_use_sendfile(SNUM(conn), False);
2780 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2782 if (fake_sendfile(fsp, startpos, nread) == -1) {
2783 DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
2784 fsp->fsp_name, strerror(errno) ));
2785 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2787 return;
2790 DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
2791 fsp->fsp_name, strerror(errno) ));
2792 exit_server_cleanly("send_file_readbraw sendfile failed");
2795 return;
2798 normal_readbraw:
2799 #endif
2801 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
2802 if (!outbuf) {
2803 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
2804 (unsigned)(nread+4)));
2805 reply_readbraw_error();
2806 return;
2809 if (nread > 0) {
2810 ret = read_file(fsp,outbuf+4,startpos,nread);
2811 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
2812 if (ret < mincount)
2813 ret = 0;
2814 #else
2815 if (ret < nread)
2816 ret = 0;
2817 #endif
2820 _smb_setlen(outbuf,ret);
2821 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
2822 fail_readraw();
2824 TALLOC_FREE(outbuf);
2827 /****************************************************************************
2828 Reply to a readbraw (core+ protocol).
2829 ****************************************************************************/
2831 void reply_readbraw(struct smb_request *req)
2833 connection_struct *conn = req->conn;
2834 ssize_t maxcount,mincount;
2835 size_t nread = 0;
2836 SMB_OFF_T startpos;
2837 files_struct *fsp;
2838 SMB_STRUCT_STAT st;
2839 SMB_OFF_T size = 0;
2841 START_PROFILE(SMBreadbraw);
2843 if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
2844 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
2845 "raw reads/writes are disallowed.");
2848 if (req->wct < 8) {
2849 reply_readbraw_error();
2850 END_PROFILE(SMBreadbraw);
2851 return;
2855 * Special check if an oplock break has been issued
2856 * and the readraw request croses on the wire, we must
2857 * return a zero length response here.
2860 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
2863 * We have to do a check_fsp by hand here, as
2864 * we must always return 4 zero bytes on error,
2865 * not a NTSTATUS.
2868 if (!fsp || !conn || conn != fsp->conn ||
2869 req->vuid != fsp->vuid ||
2870 fsp->is_directory || fsp->fh->fd == -1) {
2872 * fsp could be NULL here so use the value from the packet. JRA.
2874 DEBUG(3,("reply_readbraw: fnum %d not valid "
2875 "- cache prime?\n",
2876 (int)SVAL(req->inbuf,smb_vwv0)));
2877 reply_readbraw_error();
2878 END_PROFILE(SMBreadbraw);
2879 return;
2882 /* Do a "by hand" version of CHECK_READ. */
2883 if (!(fsp->can_read ||
2884 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
2885 (fsp->access_mask & FILE_EXECUTE)))) {
2886 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
2887 (int)SVAL(req->inbuf,smb_vwv0)));
2888 reply_readbraw_error();
2889 END_PROFILE(SMBreadbraw);
2890 return;
2893 flush_write_cache(fsp, READRAW_FLUSH);
2895 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv1);
2896 if(req->wct == 10) {
2898 * This is a large offset (64 bit) read.
2900 #ifdef LARGE_SMB_OFF_T
2902 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv8)) << 32);
2904 #else /* !LARGE_SMB_OFF_T */
2907 * Ensure we haven't been sent a >32 bit offset.
2910 if(IVAL(req->inbuf,smb_vwv8) != 0) {
2911 DEBUG(0,("reply_readbraw: large offset "
2912 "(%x << 32) used and we don't support "
2913 "64 bit offsets.\n",
2914 (unsigned int)IVAL(req->inbuf,smb_vwv8) ));
2915 reply_readbraw_error();
2916 END_PROFILE(SMBreadbraw);
2917 return;
2920 #endif /* LARGE_SMB_OFF_T */
2922 if(startpos < 0) {
2923 DEBUG(0,("reply_readbraw: negative 64 bit "
2924 "readraw offset (%.0f) !\n",
2925 (double)startpos ));
2926 reply_readbraw_error();
2927 END_PROFILE(SMBreadbraw);
2928 return;
2932 maxcount = (SVAL(req->inbuf,smb_vwv3) & 0xFFFF);
2933 mincount = (SVAL(req->inbuf,smb_vwv4) & 0xFFFF);
2935 /* ensure we don't overrun the packet size */
2936 maxcount = MIN(65535,maxcount);
2938 if (is_locked(fsp,(uint32)req->smbpid,
2939 (SMB_BIG_UINT)maxcount,
2940 (SMB_BIG_UINT)startpos,
2941 READ_LOCK)) {
2942 reply_readbraw_error();
2943 END_PROFILE(SMBreadbraw);
2944 return;
2947 if (SMB_VFS_FSTAT(fsp, &st) == 0) {
2948 size = st.st_size;
2951 if (startpos >= size) {
2952 nread = 0;
2953 } else {
2954 nread = MIN(maxcount,(size - startpos));
2957 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
2958 if (nread < mincount)
2959 nread = 0;
2960 #endif
2962 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
2963 "min=%lu nread=%lu\n",
2964 fsp->fnum, (double)startpos,
2965 (unsigned long)maxcount,
2966 (unsigned long)mincount,
2967 (unsigned long)nread ) );
2969 send_file_readbraw(conn, fsp, startpos, nread, mincount);
2971 DEBUG(5,("reply_readbraw finished\n"));
2972 END_PROFILE(SMBreadbraw);
2975 #undef DBGC_CLASS
2976 #define DBGC_CLASS DBGC_LOCKING
2978 /****************************************************************************
2979 Reply to a lockread (core+ protocol).
2980 ****************************************************************************/
2982 void reply_lockread(struct smb_request *req)
2984 connection_struct *conn = req->conn;
2985 ssize_t nread = -1;
2986 char *data;
2987 SMB_OFF_T startpos;
2988 size_t numtoread;
2989 NTSTATUS status;
2990 files_struct *fsp;
2991 struct byte_range_lock *br_lck = NULL;
2992 char *p = NULL;
2994 START_PROFILE(SMBlockread);
2996 if (req->wct < 5) {
2997 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2998 END_PROFILE(SMBlockread);
2999 return;
3002 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3004 if (!check_fsp(conn, req, fsp)) {
3005 END_PROFILE(SMBlockread);
3006 return;
3009 if (!CHECK_READ(fsp,req->inbuf)) {
3010 reply_doserror(req, ERRDOS, ERRbadaccess);
3011 END_PROFILE(SMBlockread);
3012 return;
3015 release_level_2_oplocks_on_change(fsp);
3017 numtoread = SVAL(req->inbuf,smb_vwv1);
3018 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3020 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3022 reply_outbuf(req, 5, numtoread + 3);
3024 data = smb_buf(req->outbuf) + 3;
3027 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3028 * protocol request that predates the read/write lock concept.
3029 * Thus instead of asking for a read lock here we need to ask
3030 * for a write lock. JRA.
3031 * Note that the requested lock size is unaffected by max_recv.
3034 br_lck = do_lock(smbd_messaging_context(),
3035 fsp,
3036 req->smbpid,
3037 (SMB_BIG_UINT)numtoread,
3038 (SMB_BIG_UINT)startpos,
3039 WRITE_LOCK,
3040 WINDOWS_LOCK,
3041 False, /* Non-blocking lock. */
3042 &status,
3043 NULL);
3044 TALLOC_FREE(br_lck);
3046 if (NT_STATUS_V(status)) {
3047 reply_nterror(req, status);
3048 END_PROFILE(SMBlockread);
3049 return;
3053 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3056 if (numtoread > max_recv) {
3057 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3058 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3059 (unsigned int)numtoread, (unsigned int)max_recv ));
3060 numtoread = MIN(numtoread,max_recv);
3062 nread = read_file(fsp,data,startpos,numtoread);
3064 if (nread < 0) {
3065 reply_unixerror(req, ERRDOS, ERRnoaccess);
3066 END_PROFILE(SMBlockread);
3067 return;
3070 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3072 SSVAL(req->outbuf,smb_vwv0,nread);
3073 SSVAL(req->outbuf,smb_vwv5,nread+3);
3074 p = smb_buf(req->outbuf);
3075 SCVAL(p,0,0); /* pad byte. */
3076 SSVAL(p,1,nread);
3078 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3079 fsp->fnum, (int)numtoread, (int)nread));
3081 END_PROFILE(SMBlockread);
3082 return;
3085 #undef DBGC_CLASS
3086 #define DBGC_CLASS DBGC_ALL
3088 /****************************************************************************
3089 Reply to a read.
3090 ****************************************************************************/
3092 void reply_read(struct smb_request *req)
3094 connection_struct *conn = req->conn;
3095 size_t numtoread;
3096 ssize_t nread = 0;
3097 char *data;
3098 SMB_OFF_T startpos;
3099 int outsize = 0;
3100 files_struct *fsp;
3102 START_PROFILE(SMBread);
3104 if (req->wct < 3) {
3105 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3106 END_PROFILE(SMBread);
3107 return;
3110 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3112 if (!check_fsp(conn, req, fsp)) {
3113 END_PROFILE(SMBread);
3114 return;
3117 if (!CHECK_READ(fsp,req->inbuf)) {
3118 reply_doserror(req, ERRDOS, ERRbadaccess);
3119 END_PROFILE(SMBread);
3120 return;
3123 numtoread = SVAL(req->inbuf,smb_vwv1);
3124 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3126 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3129 * The requested read size cannot be greater than max_recv. JRA.
3131 if (numtoread > max_recv) {
3132 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3133 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3134 (unsigned int)numtoread, (unsigned int)max_recv ));
3135 numtoread = MIN(numtoread,max_recv);
3138 reply_outbuf(req, 5, numtoread+3);
3140 data = smb_buf(req->outbuf) + 3;
3142 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtoread,
3143 (SMB_BIG_UINT)startpos, READ_LOCK)) {
3144 reply_doserror(req, ERRDOS,ERRlock);
3145 END_PROFILE(SMBread);
3146 return;
3149 if (numtoread > 0)
3150 nread = read_file(fsp,data,startpos,numtoread);
3152 if (nread < 0) {
3153 reply_unixerror(req, ERRDOS,ERRnoaccess);
3154 END_PROFILE(SMBread);
3155 return;
3158 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3160 SSVAL(req->outbuf,smb_vwv0,nread);
3161 SSVAL(req->outbuf,smb_vwv5,nread+3);
3162 SCVAL(smb_buf(req->outbuf),0,1);
3163 SSVAL(smb_buf(req->outbuf),1,nread);
3165 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3166 fsp->fnum, (int)numtoread, (int)nread ) );
3168 END_PROFILE(SMBread);
3169 return;
3172 /****************************************************************************
3173 Setup readX header.
3174 ****************************************************************************/
3176 static int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3178 int outsize;
3179 char *data;
3181 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3182 data = smb_buf(outbuf);
3184 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3186 SCVAL(outbuf,smb_vwv0,0xFF);
3187 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3188 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3189 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
3190 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3191 SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
3192 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3193 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3194 return outsize;
3197 /****************************************************************************
3198 Reply to a read and X - possibly using sendfile.
3199 ****************************************************************************/
3201 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3202 files_struct *fsp, SMB_OFF_T startpos,
3203 size_t smb_maxcnt)
3205 SMB_STRUCT_STAT sbuf;
3206 ssize_t nread = -1;
3208 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
3209 reply_unixerror(req, ERRDOS, ERRnoaccess);
3210 return;
3213 if (startpos > sbuf.st_size) {
3214 smb_maxcnt = 0;
3215 } else if (smb_maxcnt > (sbuf.st_size - startpos)) {
3216 smb_maxcnt = (sbuf.st_size - startpos);
3219 if (smb_maxcnt == 0) {
3220 goto normal_read;
3223 #if defined(WITH_SENDFILE)
3225 * We can only use sendfile on a non-chained packet
3226 * but we can use on a non-oplocked file. tridge proved this
3227 * on a train in Germany :-). JRA.
3230 if ((chain_size == 0) && (CVAL(req->inbuf,smb_vwv0) == 0xFF) &&
3231 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3232 lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
3233 uint8 headerbuf[smb_size + 12 * 2];
3234 DATA_BLOB header;
3237 * Set up the packet header before send. We
3238 * assume here the sendfile will work (get the
3239 * correct amount of data).
3242 header = data_blob_const(headerbuf, sizeof(headerbuf));
3244 construct_reply_common((char *)req->inbuf, (char *)headerbuf);
3245 setup_readX_header((char *)headerbuf, smb_maxcnt);
3247 if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
3248 /* Returning ENOSYS means no data at all was sent.
3249 Do this as a normal read. */
3250 if (errno == ENOSYS) {
3251 goto normal_read;
3255 * Special hack for broken Linux with no working sendfile. If we
3256 * return EINTR we sent the header but not the rest of the data.
3257 * Fake this up by doing read/write calls.
3260 if (errno == EINTR) {
3261 /* Ensure we don't do this again. */
3262 set_use_sendfile(SNUM(conn), False);
3263 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3264 nread = fake_sendfile(fsp, startpos,
3265 smb_maxcnt);
3266 if (nread == -1) {
3267 DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
3268 fsp->fsp_name, strerror(errno) ));
3269 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3271 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3272 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3273 /* No outbuf here means successful sendfile. */
3274 TALLOC_FREE(req->outbuf);
3275 return;
3278 DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
3279 fsp->fsp_name, strerror(errno) ));
3280 exit_server_cleanly("send_file_readX sendfile failed");
3283 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3284 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3285 /* No outbuf here means successful sendfile. */
3286 TALLOC_FREE(req->outbuf);
3287 return;
3289 #endif
3291 normal_read:
3293 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3294 uint8 headerbuf[smb_size + 2*12];
3296 construct_reply_common((char *)req->inbuf, (char *)headerbuf);
3297 setup_readX_header((char *)headerbuf, smb_maxcnt);
3299 /* Send out the header. */
3300 if (write_data(smbd_server_fd(), (char *)headerbuf,
3301 sizeof(headerbuf)) != sizeof(headerbuf)) {
3302 DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
3303 fsp->fsp_name, strerror(errno) ));
3304 exit_server_cleanly("send_file_readX sendfile failed");
3306 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3307 if (nread == -1) {
3308 DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
3309 fsp->fsp_name, strerror(errno) ));
3310 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3312 TALLOC_FREE(req->outbuf);
3313 return;
3314 } else {
3315 reply_outbuf(req, 12, smb_maxcnt);
3317 nread = read_file(fsp, smb_buf(req->outbuf), startpos,
3318 smb_maxcnt);
3319 if (nread < 0) {
3320 reply_unixerror(req, ERRDOS, ERRnoaccess);
3321 return;
3324 setup_readX_header((char *)req->outbuf, nread);
3326 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3327 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3329 chain_reply(req);
3331 return;
3335 /****************************************************************************
3336 Reply to a read and X.
3337 ****************************************************************************/
3339 void reply_read_and_X(struct smb_request *req)
3341 connection_struct *conn = req->conn;
3342 files_struct *fsp;
3343 SMB_OFF_T startpos;
3344 size_t smb_maxcnt;
3345 bool big_readX = False;
3346 #if 0
3347 size_t smb_mincnt = SVAL(req->inbuf,smb_vwv6);
3348 #endif
3350 START_PROFILE(SMBreadX);
3352 if ((req->wct != 10) && (req->wct != 12)) {
3353 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3354 return;
3357 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
3358 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
3359 smb_maxcnt = SVAL(req->inbuf,smb_vwv5);
3361 /* If it's an IPC, pass off the pipe handler. */
3362 if (IS_IPC(conn)) {
3363 reply_pipe_read_and_X(req);
3364 END_PROFILE(SMBreadX);
3365 return;
3368 if (!check_fsp(conn, req, fsp)) {
3369 END_PROFILE(SMBreadX);
3370 return;
3373 if (!CHECK_READ(fsp,req->inbuf)) {
3374 reply_doserror(req, ERRDOS,ERRbadaccess);
3375 END_PROFILE(SMBreadX);
3376 return;
3379 if (global_client_caps & CAP_LARGE_READX) {
3380 size_t upper_size = SVAL(req->inbuf,smb_vwv7);
3381 smb_maxcnt |= (upper_size<<16);
3382 if (upper_size > 1) {
3383 /* Can't do this on a chained packet. */
3384 if ((CVAL(req->inbuf,smb_vwv0) != 0xFF)) {
3385 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3386 END_PROFILE(SMBreadX);
3387 return;
3389 /* We currently don't do this on signed or sealed data. */
3390 if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
3391 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3392 END_PROFILE(SMBreadX);
3393 return;
3395 /* Is there room in the reply for this data ? */
3396 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3397 reply_nterror(req,
3398 NT_STATUS_INVALID_PARAMETER);
3399 END_PROFILE(SMBreadX);
3400 return;
3402 big_readX = True;
3406 if (req->wct == 12) {
3407 #ifdef LARGE_SMB_OFF_T
3409 * This is a large offset (64 bit) read.
3411 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv10)) << 32);
3413 #else /* !LARGE_SMB_OFF_T */
3416 * Ensure we haven't been sent a >32 bit offset.
3419 if(IVAL(req->inbuf,smb_vwv10) != 0) {
3420 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3421 "used and we don't support 64 bit offsets.\n",
3422 (unsigned int)IVAL(req->inbuf,smb_vwv10) ));
3423 END_PROFILE(SMBreadX);
3424 reply_doserror(req, ERRDOS, ERRbadaccess);
3425 return;
3428 #endif /* LARGE_SMB_OFF_T */
3432 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)smb_maxcnt,
3433 (SMB_BIG_UINT)startpos, READ_LOCK)) {
3434 END_PROFILE(SMBreadX);
3435 reply_doserror(req, ERRDOS, ERRlock);
3436 return;
3439 if (!big_readX &&
3440 schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
3441 END_PROFILE(SMBreadX);
3442 return;
3445 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3447 END_PROFILE(SMBreadX);
3448 return;
3451 /****************************************************************************
3452 Error replies to writebraw must have smb_wct == 1. Fix this up.
3453 ****************************************************************************/
3455 void error_to_writebrawerr(struct smb_request *req)
3457 uint8 *old_outbuf = req->outbuf;
3459 reply_outbuf(req, 1, 0);
3461 memcpy(req->outbuf, old_outbuf, smb_size);
3462 TALLOC_FREE(old_outbuf);
3465 /****************************************************************************
3466 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3467 ****************************************************************************/
3469 void reply_writebraw(struct smb_request *req)
3471 connection_struct *conn = req->conn;
3472 char *buf = NULL;
3473 ssize_t nwritten=0;
3474 ssize_t total_written=0;
3475 size_t numtowrite=0;
3476 size_t tcount;
3477 SMB_OFF_T startpos;
3478 char *data=NULL;
3479 bool write_through;
3480 files_struct *fsp;
3481 NTSTATUS status;
3483 START_PROFILE(SMBwritebraw);
3486 * If we ever reply with an error, it must have the SMB command
3487 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3488 * we're finished.
3490 SCVAL(req->inbuf,smb_com,SMBwritec);
3492 if (srv_is_signing_active()) {
3493 END_PROFILE(SMBwritebraw);
3494 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3495 "raw reads/writes are disallowed.");
3498 if (req->wct < 12) {
3499 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3500 error_to_writebrawerr(req);
3501 END_PROFILE(SMBwritebraw);
3502 return;
3505 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3506 if (!check_fsp(conn, req, fsp)) {
3507 error_to_writebrawerr(req);
3508 END_PROFILE(SMBwritebraw);
3509 return;
3512 if (!CHECK_WRITE(fsp)) {
3513 reply_doserror(req, ERRDOS, ERRbadaccess);
3514 error_to_writebrawerr(req);
3515 END_PROFILE(SMBwritebraw);
3516 return;
3519 tcount = IVAL(req->inbuf,smb_vwv1);
3520 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
3521 write_through = BITSETW(req->inbuf+smb_vwv7,0);
3523 /* We have to deal with slightly different formats depending
3524 on whether we are using the core+ or lanman1.0 protocol */
3526 if(Protocol <= PROTOCOL_COREPLUS) {
3527 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3528 data = smb_buf(req->inbuf);
3529 } else {
3530 numtowrite = SVAL(req->inbuf,smb_vwv10);
3531 data = smb_base(req->inbuf) + SVAL(req->inbuf, smb_vwv11);
3534 /* Ensure we don't write bytes past the end of this packet. */
3535 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3536 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3537 error_to_writebrawerr(req);
3538 END_PROFILE(SMBwritebraw);
3539 return;
3542 if (is_locked(fsp,(uint32)req->smbpid,(SMB_BIG_UINT)tcount,
3543 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3544 reply_doserror(req, ERRDOS, ERRlock);
3545 error_to_writebrawerr(req);
3546 END_PROFILE(SMBwritebraw);
3547 return;
3550 if (numtowrite>0) {
3551 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3554 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3555 "wrote=%d sync=%d\n",
3556 fsp->fnum, (double)startpos, (int)numtowrite,
3557 (int)nwritten, (int)write_through));
3559 if (nwritten < (ssize_t)numtowrite) {
3560 reply_unixerror(req, ERRHRD, ERRdiskfull);
3561 error_to_writebrawerr(req);
3562 END_PROFILE(SMBwritebraw);
3563 return;
3566 total_written = nwritten;
3568 /* Allocate a buffer of 64k + length. */
3569 buf = TALLOC_ARRAY(NULL, char, 65540);
3570 if (!buf) {
3571 reply_doserror(req, ERRDOS, ERRnomem);
3572 error_to_writebrawerr(req);
3573 END_PROFILE(SMBwritebraw);
3574 return;
3577 /* Return a SMBwritebraw message to the redirector to tell
3578 * it to send more bytes */
3580 memcpy(buf, req->inbuf, smb_size);
3581 srv_set_message(buf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
3582 SCVAL(buf,smb_com,SMBwritebraw);
3583 SSVALS(buf,smb_vwv0,0xFFFF);
3584 show_msg(buf);
3585 if (!srv_send_smb(smbd_server_fd(),
3586 buf,
3587 IS_CONN_ENCRYPTED(conn))) {
3588 exit_server_cleanly("reply_writebraw: srv_send_smb "
3589 "failed.");
3592 /* Now read the raw data into the buffer and write it */
3593 status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
3594 &numtowrite);
3595 if (!NT_STATUS_IS_OK(status)) {
3596 exit_server_cleanly("secondary writebraw failed");
3599 /* Set up outbuf to return the correct size */
3600 reply_outbuf(req, 1, 0);
3602 if (numtowrite != 0) {
3604 if (numtowrite > 0xFFFF) {
3605 DEBUG(0,("reply_writebraw: Oversize secondary write "
3606 "raw requested (%u). Terminating\n",
3607 (unsigned int)numtowrite ));
3608 exit_server_cleanly("secondary writebraw failed");
3611 if (tcount > nwritten+numtowrite) {
3612 DEBUG(3,("reply_writebraw: Client overestimated the "
3613 "write %d %d %d\n",
3614 (int)tcount,(int)nwritten,(int)numtowrite));
3617 status = read_data(smbd_server_fd(), buf+4, numtowrite);
3619 if (!NT_STATUS_IS_OK(status)) {
3620 DEBUG(0,("reply_writebraw: Oversize secondary write "
3621 "raw read failed (%s). Terminating\n",
3622 nt_errstr(status)));
3623 exit_server_cleanly("secondary writebraw failed");
3626 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
3627 if (nwritten == -1) {
3628 TALLOC_FREE(buf);
3629 reply_unixerror(req, ERRHRD, ERRdiskfull);
3630 error_to_writebrawerr(req);
3631 END_PROFILE(SMBwritebraw);
3632 return;
3635 if (nwritten < (ssize_t)numtowrite) {
3636 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3637 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3640 if (nwritten > 0) {
3641 total_written += nwritten;
3645 TALLOC_FREE(buf);
3646 SSVAL(req->outbuf,smb_vwv0,total_written);
3648 status = sync_file(conn, fsp, write_through);
3649 if (!NT_STATUS_IS_OK(status)) {
3650 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
3651 fsp->fsp_name, nt_errstr(status) ));
3652 reply_nterror(req, status);
3653 error_to_writebrawerr(req);
3654 END_PROFILE(SMBwritebraw);
3655 return;
3658 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
3659 "wrote=%d\n",
3660 fsp->fnum, (double)startpos, (int)numtowrite,
3661 (int)total_written));
3663 /* We won't return a status if write through is not selected - this
3664 * follows what WfWg does */
3665 END_PROFILE(SMBwritebraw);
3667 if (!write_through && total_written==tcount) {
3669 #if RABBIT_PELLET_FIX
3671 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
3672 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
3673 * JRA.
3675 if (!send_keepalive(smbd_server_fd())) {
3676 exit_server_cleanly("reply_writebraw: send of "
3677 "keepalive failed");
3679 #endif
3680 TALLOC_FREE(req->outbuf);
3682 return;
3685 #undef DBGC_CLASS
3686 #define DBGC_CLASS DBGC_LOCKING
3688 /****************************************************************************
3689 Reply to a writeunlock (core+).
3690 ****************************************************************************/
3692 void reply_writeunlock(struct smb_request *req)
3694 connection_struct *conn = req->conn;
3695 ssize_t nwritten = -1;
3696 size_t numtowrite;
3697 SMB_OFF_T startpos;
3698 char *data;
3699 NTSTATUS status = NT_STATUS_OK;
3700 files_struct *fsp;
3702 START_PROFILE(SMBwriteunlock);
3704 if (req->wct < 5) {
3705 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3706 END_PROFILE(SMBwriteunlock);
3707 return;
3710 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3712 if (!check_fsp(conn, req, fsp)) {
3713 END_PROFILE(SMBwriteunlock);
3714 return;
3717 if (!CHECK_WRITE(fsp)) {
3718 reply_doserror(req, ERRDOS,ERRbadaccess);
3719 END_PROFILE(SMBwriteunlock);
3720 return;
3723 numtowrite = SVAL(req->inbuf,smb_vwv1);
3724 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3725 data = smb_buf(req->inbuf) + 3;
3727 if (numtowrite
3728 && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
3729 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3730 reply_doserror(req, ERRDOS, ERRlock);
3731 END_PROFILE(SMBwriteunlock);
3732 return;
3735 /* The special X/Open SMB protocol handling of
3736 zero length writes is *NOT* done for
3737 this call */
3738 if(numtowrite == 0) {
3739 nwritten = 0;
3740 } else {
3741 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3744 status = sync_file(conn, fsp, False /* write through */);
3745 if (!NT_STATUS_IS_OK(status)) {
3746 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
3747 fsp->fsp_name, nt_errstr(status) ));
3748 reply_nterror(req, status);
3749 END_PROFILE(SMBwriteunlock);
3750 return;
3753 if(((nwritten < numtowrite) && (numtowrite != 0))||(nwritten < 0)) {
3754 reply_unixerror(req, ERRHRD, ERRdiskfull);
3755 END_PROFILE(SMBwriteunlock);
3756 return;
3759 if (numtowrite) {
3760 status = do_unlock(smbd_messaging_context(),
3761 fsp,
3762 req->smbpid,
3763 (SMB_BIG_UINT)numtowrite,
3764 (SMB_BIG_UINT)startpos,
3765 WINDOWS_LOCK);
3767 if (NT_STATUS_V(status)) {
3768 reply_nterror(req, status);
3769 END_PROFILE(SMBwriteunlock);
3770 return;
3774 reply_outbuf(req, 1, 0);
3776 SSVAL(req->outbuf,smb_vwv0,nwritten);
3778 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
3779 fsp->fnum, (int)numtowrite, (int)nwritten));
3781 END_PROFILE(SMBwriteunlock);
3782 return;
3785 #undef DBGC_CLASS
3786 #define DBGC_CLASS DBGC_ALL
3788 /****************************************************************************
3789 Reply to a write.
3790 ****************************************************************************/
3792 void reply_write(struct smb_request *req)
3794 connection_struct *conn = req->conn;
3795 size_t numtowrite;
3796 ssize_t nwritten = -1;
3797 SMB_OFF_T startpos;
3798 char *data;
3799 files_struct *fsp;
3800 NTSTATUS status;
3802 START_PROFILE(SMBwrite);
3804 if (req->wct < 5) {
3805 END_PROFILE(SMBwrite);
3806 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3807 return;
3810 /* If it's an IPC, pass off the pipe handler. */
3811 if (IS_IPC(conn)) {
3812 reply_pipe_write(req);
3813 END_PROFILE(SMBwrite);
3814 return;
3817 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3819 if (!check_fsp(conn, req, fsp)) {
3820 END_PROFILE(SMBwrite);
3821 return;
3824 if (!CHECK_WRITE(fsp)) {
3825 reply_doserror(req, ERRDOS, ERRbadaccess);
3826 END_PROFILE(SMBwrite);
3827 return;
3830 numtowrite = SVAL(req->inbuf,smb_vwv1);
3831 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3832 data = smb_buf(req->inbuf) + 3;
3834 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
3835 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3836 reply_doserror(req, ERRDOS, ERRlock);
3837 END_PROFILE(SMBwrite);
3838 return;
3842 * X/Open SMB protocol says that if smb_vwv1 is
3843 * zero then the file size should be extended or
3844 * truncated to the size given in smb_vwv[2-3].
3847 if(numtowrite == 0) {
3849 * This is actually an allocate call, and set EOF. JRA.
3851 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
3852 if (nwritten < 0) {
3853 reply_nterror(req, NT_STATUS_DISK_FULL);
3854 END_PROFILE(SMBwrite);
3855 return;
3857 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
3858 if (nwritten < 0) {
3859 reply_nterror(req, NT_STATUS_DISK_FULL);
3860 END_PROFILE(SMBwrite);
3861 return;
3863 trigger_write_time_update_immediate(fsp);
3864 } else {
3865 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3868 status = sync_file(conn, fsp, False);
3869 if (!NT_STATUS_IS_OK(status)) {
3870 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
3871 fsp->fsp_name, nt_errstr(status) ));
3872 reply_nterror(req, status);
3873 END_PROFILE(SMBwrite);
3874 return;
3877 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
3878 reply_unixerror(req, ERRHRD, ERRdiskfull);
3879 END_PROFILE(SMBwrite);
3880 return;
3883 reply_outbuf(req, 1, 0);
3885 SSVAL(req->outbuf,smb_vwv0,nwritten);
3887 if (nwritten < (ssize_t)numtowrite) {
3888 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3889 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3892 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
3894 END_PROFILE(SMBwrite);
3895 return;
3898 /****************************************************************************
3899 Ensure a buffer is a valid writeX for recvfile purposes.
3900 ****************************************************************************/
3902 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
3903 (2*14) + /* word count (including bcc) */ \
3904 1 /* pad byte */)
3906 bool is_valid_writeX_buffer(const uint8_t *inbuf)
3908 size_t numtowrite;
3909 connection_struct *conn = NULL;
3910 unsigned int doff = 0;
3911 size_t len = smb_len_large(inbuf);
3913 if (is_encrypted_packet(inbuf)) {
3914 /* Can't do this on encrypted
3915 * connections. */
3916 return false;
3919 if (CVAL(inbuf,smb_com) != SMBwriteX) {
3920 return false;
3923 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
3924 CVAL(inbuf,smb_wct) != 14) {
3925 DEBUG(10,("is_valid_writeX_buffer: chained or "
3926 "invalid word length.\n"));
3927 return false;
3930 conn = conn_find(SVAL(inbuf, smb_tid));
3931 if (conn == NULL) {
3932 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
3933 return false;
3935 if (IS_IPC(conn)) {
3936 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
3937 return false;
3939 if (IS_PRINT(conn)) {
3940 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
3941 return false;
3943 doff = SVAL(inbuf,smb_vwv11);
3945 numtowrite = SVAL(inbuf,smb_vwv10);
3947 if (len > doff && len - doff > 0xFFFF) {
3948 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
3951 if (numtowrite == 0) {
3952 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
3953 return false;
3956 /* Ensure the sizes match up. */
3957 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
3958 /* no pad byte...old smbclient :-( */
3959 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
3960 (unsigned int)doff,
3961 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
3962 return false;
3965 if (len - doff != numtowrite) {
3966 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
3967 "len = %u, doff = %u, numtowrite = %u\n",
3968 (unsigned int)len,
3969 (unsigned int)doff,
3970 (unsigned int)numtowrite ));
3971 return false;
3974 DEBUG(10,("is_valid_writeX_buffer: true "
3975 "len = %u, doff = %u, numtowrite = %u\n",
3976 (unsigned int)len,
3977 (unsigned int)doff,
3978 (unsigned int)numtowrite ));
3980 return true;
3983 /****************************************************************************
3984 Reply to a write and X.
3985 ****************************************************************************/
3987 void reply_write_and_X(struct smb_request *req)
3989 connection_struct *conn = req->conn;
3990 files_struct *fsp;
3991 SMB_OFF_T startpos;
3992 size_t numtowrite;
3993 bool write_through;
3994 ssize_t nwritten;
3995 unsigned int smb_doff;
3996 unsigned int smblen;
3997 char *data;
3998 NTSTATUS status;
4000 START_PROFILE(SMBwriteX);
4002 if ((req->wct != 12) && (req->wct != 14)) {
4003 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4004 END_PROFILE(SMBwriteX);
4005 return;
4008 numtowrite = SVAL(req->inbuf,smb_vwv10);
4009 smb_doff = SVAL(req->inbuf,smb_vwv11);
4010 smblen = smb_len(req->inbuf);
4012 if (req->unread_bytes > 0xFFFF ||
4013 (smblen > smb_doff &&
4014 smblen - smb_doff > 0xFFFF)) {
4015 numtowrite |= (((size_t)SVAL(req->inbuf,smb_vwv9))<<16);
4018 if (req->unread_bytes) {
4019 /* Can't do a recvfile write on IPC$ */
4020 if (IS_IPC(conn)) {
4021 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4022 END_PROFILE(SMBwriteX);
4023 return;
4025 if (numtowrite != req->unread_bytes) {
4026 reply_doserror(req, ERRDOS, ERRbadmem);
4027 END_PROFILE(SMBwriteX);
4028 return;
4030 } else {
4031 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4032 smb_doff + numtowrite > smblen) {
4033 reply_doserror(req, ERRDOS, ERRbadmem);
4034 END_PROFILE(SMBwriteX);
4035 return;
4039 /* If it's an IPC, pass off the pipe handler. */
4040 if (IS_IPC(conn)) {
4041 if (req->unread_bytes) {
4042 reply_doserror(req, ERRDOS, ERRbadmem);
4043 END_PROFILE(SMBwriteX);
4044 return;
4046 reply_pipe_write_and_X(req);
4047 END_PROFILE(SMBwriteX);
4048 return;
4051 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
4052 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
4053 write_through = BITSETW(req->inbuf+smb_vwv7,0);
4055 if (!check_fsp(conn, req, fsp)) {
4056 END_PROFILE(SMBwriteX);
4057 return;
4060 if (!CHECK_WRITE(fsp)) {
4061 reply_doserror(req, ERRDOS, ERRbadaccess);
4062 END_PROFILE(SMBwriteX);
4063 return;
4066 data = smb_base(req->inbuf) + smb_doff;
4068 if(req->wct == 14) {
4069 #ifdef LARGE_SMB_OFF_T
4071 * This is a large offset (64 bit) write.
4073 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv12)) << 32);
4075 #else /* !LARGE_SMB_OFF_T */
4078 * Ensure we haven't been sent a >32 bit offset.
4081 if(IVAL(req->inbuf,smb_vwv12) != 0) {
4082 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4083 "used and we don't support 64 bit offsets.\n",
4084 (unsigned int)IVAL(req->inbuf,smb_vwv12) ));
4085 reply_doserror(req, ERRDOS, ERRbadaccess);
4086 END_PROFILE(SMBwriteX);
4087 return;
4090 #endif /* LARGE_SMB_OFF_T */
4093 if (is_locked(fsp,(uint32)req->smbpid,
4094 (SMB_BIG_UINT)numtowrite,
4095 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
4096 reply_doserror(req, ERRDOS, ERRlock);
4097 END_PROFILE(SMBwriteX);
4098 return;
4101 /* X/Open SMB protocol says that, unlike SMBwrite
4102 if the length is zero then NO truncation is
4103 done, just a write of zero. To truncate a file,
4104 use SMBwrite. */
4106 if(numtowrite == 0) {
4107 nwritten = 0;
4108 } else {
4110 if ((req->unread_bytes == 0) &&
4111 schedule_aio_write_and_X(conn, req, fsp, data, startpos,
4112 numtowrite)) {
4113 END_PROFILE(SMBwriteX);
4114 return;
4117 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4120 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4121 reply_unixerror(req, ERRHRD, ERRdiskfull);
4122 END_PROFILE(SMBwriteX);
4123 return;
4126 reply_outbuf(req, 6, 0);
4127 SSVAL(req->outbuf,smb_vwv2,nwritten);
4128 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4130 if (nwritten < (ssize_t)numtowrite) {
4131 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4132 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4135 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4136 fsp->fnum, (int)numtowrite, (int)nwritten));
4138 status = sync_file(conn, fsp, write_through);
4139 if (!NT_STATUS_IS_OK(status)) {
4140 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4141 fsp->fsp_name, nt_errstr(status) ));
4142 reply_nterror(req, status);
4143 END_PROFILE(SMBwriteX);
4144 return;
4147 END_PROFILE(SMBwriteX);
4148 chain_reply(req);
4149 return;
4152 /****************************************************************************
4153 Reply to a lseek.
4154 ****************************************************************************/
4156 void reply_lseek(struct smb_request *req)
4158 connection_struct *conn = req->conn;
4159 SMB_OFF_T startpos;
4160 SMB_OFF_T res= -1;
4161 int mode,umode;
4162 files_struct *fsp;
4164 START_PROFILE(SMBlseek);
4166 if (req->wct < 4) {
4167 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4168 END_PROFILE(SMBlseek);
4169 return;
4172 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4174 if (!check_fsp(conn, req, fsp)) {
4175 return;
4178 flush_write_cache(fsp, SEEK_FLUSH);
4180 mode = SVAL(req->inbuf,smb_vwv1) & 3;
4181 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4182 startpos = (SMB_OFF_T)IVALS(req->inbuf,smb_vwv2);
4184 switch (mode) {
4185 case 0:
4186 umode = SEEK_SET;
4187 res = startpos;
4188 break;
4189 case 1:
4190 umode = SEEK_CUR;
4191 res = fsp->fh->pos + startpos;
4192 break;
4193 case 2:
4194 umode = SEEK_END;
4195 break;
4196 default:
4197 umode = SEEK_SET;
4198 res = startpos;
4199 break;
4202 if (umode == SEEK_END) {
4203 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4204 if(errno == EINVAL) {
4205 SMB_OFF_T current_pos = startpos;
4206 SMB_STRUCT_STAT sbuf;
4208 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
4209 reply_unixerror(req, ERRDOS,
4210 ERRnoaccess);
4211 END_PROFILE(SMBlseek);
4212 return;
4215 current_pos += sbuf.st_size;
4216 if(current_pos < 0)
4217 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4221 if(res == -1) {
4222 reply_unixerror(req, ERRDOS, ERRnoaccess);
4223 END_PROFILE(SMBlseek);
4224 return;
4228 fsp->fh->pos = res;
4230 reply_outbuf(req, 2, 0);
4231 SIVAL(req->outbuf,smb_vwv0,res);
4233 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4234 fsp->fnum, (double)startpos, (double)res, mode));
4236 END_PROFILE(SMBlseek);
4237 return;
4240 /****************************************************************************
4241 Reply to a flush.
4242 ****************************************************************************/
4244 void reply_flush(struct smb_request *req)
4246 connection_struct *conn = req->conn;
4247 uint16 fnum;
4248 files_struct *fsp;
4250 START_PROFILE(SMBflush);
4252 if (req->wct < 1) {
4253 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4254 return;
4257 fnum = SVAL(req->inbuf,smb_vwv0);
4258 fsp = file_fsp(fnum);
4260 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4261 return;
4264 if (!fsp) {
4265 file_sync_all(conn);
4266 } else {
4267 NTSTATUS status = sync_file(conn, fsp, True);
4268 if (!NT_STATUS_IS_OK(status)) {
4269 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4270 fsp->fsp_name, nt_errstr(status) ));
4271 reply_nterror(req, status);
4272 END_PROFILE(SMBflush);
4273 return;
4277 reply_outbuf(req, 0, 0);
4279 DEBUG(3,("flush\n"));
4280 END_PROFILE(SMBflush);
4281 return;
4284 /****************************************************************************
4285 Reply to a exit.
4286 conn POINTER CAN BE NULL HERE !
4287 ****************************************************************************/
4289 void reply_exit(struct smb_request *req)
4291 START_PROFILE(SMBexit);
4293 file_close_pid(req->smbpid, req->vuid);
4295 reply_outbuf(req, 0, 0);
4297 DEBUG(3,("exit\n"));
4299 END_PROFILE(SMBexit);
4300 return;
4303 /****************************************************************************
4304 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4305 ****************************************************************************/
4307 void reply_close(struct smb_request *req)
4309 connection_struct *conn = req->conn;
4310 NTSTATUS status = NT_STATUS_OK;
4311 files_struct *fsp = NULL;
4312 START_PROFILE(SMBclose);
4314 if (req->wct < 3) {
4315 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4316 END_PROFILE(SMBclose);
4317 return;
4320 /* If it's an IPC, pass off to the pipe handler. */
4321 if (IS_IPC(conn)) {
4322 reply_pipe_close(conn, req);
4323 END_PROFILE(SMBclose);
4324 return;
4327 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4330 * We can only use check_fsp if we know it's not a directory.
4333 if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
4334 reply_doserror(req, ERRDOS, ERRbadfid);
4335 END_PROFILE(SMBclose);
4336 return;
4339 if(fsp->is_directory) {
4341 * Special case - close NT SMB directory handle.
4343 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4344 status = close_file(fsp,NORMAL_CLOSE);
4345 } else {
4346 time_t t;
4348 * Close ordinary file.
4351 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4352 fsp->fh->fd, fsp->fnum,
4353 conn->num_files_open));
4356 * Take care of any time sent in the close.
4359 t = srv_make_unix_date3(req->inbuf+smb_vwv1);
4360 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4363 * close_file() returns the unix errno if an error
4364 * was detected on close - normally this is due to
4365 * a disk full error. If not then it was probably an I/O error.
4368 status = close_file(fsp,NORMAL_CLOSE);
4371 if (!NT_STATUS_IS_OK(status)) {
4372 reply_nterror(req, status);
4373 END_PROFILE(SMBclose);
4374 return;
4377 reply_outbuf(req, 0, 0);
4378 END_PROFILE(SMBclose);
4379 return;
4382 /****************************************************************************
4383 Reply to a writeclose (Core+ protocol).
4384 ****************************************************************************/
4386 void reply_writeclose(struct smb_request *req)
4388 connection_struct *conn = req->conn;
4389 size_t numtowrite;
4390 ssize_t nwritten = -1;
4391 NTSTATUS close_status = NT_STATUS_OK;
4392 SMB_OFF_T startpos;
4393 char *data;
4394 struct timespec mtime;
4395 files_struct *fsp;
4397 START_PROFILE(SMBwriteclose);
4399 if (req->wct < 6) {
4400 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4401 END_PROFILE(SMBwriteclose);
4402 return;
4405 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4407 if (!check_fsp(conn, req, fsp)) {
4408 END_PROFILE(SMBwriteclose);
4409 return;
4411 if (!CHECK_WRITE(fsp)) {
4412 reply_doserror(req, ERRDOS,ERRbadaccess);
4413 END_PROFILE(SMBwriteclose);
4414 return;
4417 numtowrite = SVAL(req->inbuf,smb_vwv1);
4418 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
4419 mtime = convert_time_t_to_timespec(srv_make_unix_date3(
4420 req->inbuf+smb_vwv4));
4421 data = smb_buf(req->inbuf) + 1;
4423 if (numtowrite
4424 && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
4425 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
4426 reply_doserror(req, ERRDOS,ERRlock);
4427 END_PROFILE(SMBwriteclose);
4428 return;
4431 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4433 set_close_write_time(fsp, mtime);
4436 * More insanity. W2K only closes the file if writelen > 0.
4437 * JRA.
4440 if (numtowrite) {
4441 DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
4442 fsp->fsp_name ));
4443 close_status = close_file(fsp,NORMAL_CLOSE);
4446 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4447 fsp->fnum, (int)numtowrite, (int)nwritten,
4448 conn->num_files_open));
4450 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4451 reply_doserror(req, ERRHRD, ERRdiskfull);
4452 END_PROFILE(SMBwriteclose);
4453 return;
4456 if(!NT_STATUS_IS_OK(close_status)) {
4457 reply_nterror(req, close_status);
4458 END_PROFILE(SMBwriteclose);
4459 return;
4462 reply_outbuf(req, 1, 0);
4464 SSVAL(req->outbuf,smb_vwv0,nwritten);
4465 END_PROFILE(SMBwriteclose);
4466 return;
4469 #undef DBGC_CLASS
4470 #define DBGC_CLASS DBGC_LOCKING
4472 /****************************************************************************
4473 Reply to a lock.
4474 ****************************************************************************/
4476 void reply_lock(struct smb_request *req)
4478 connection_struct *conn = req->conn;
4479 SMB_BIG_UINT count,offset;
4480 NTSTATUS status;
4481 files_struct *fsp;
4482 struct byte_range_lock *br_lck = NULL;
4484 START_PROFILE(SMBlock);
4486 if (req->wct < 5) {
4487 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4488 END_PROFILE(SMBlock);
4489 return;
4492 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4494 if (!check_fsp(conn, req, fsp)) {
4495 END_PROFILE(SMBlock);
4496 return;
4499 release_level_2_oplocks_on_change(fsp);
4501 count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
4502 offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
4504 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4505 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4507 br_lck = do_lock(smbd_messaging_context(),
4508 fsp,
4509 req->smbpid,
4510 count,
4511 offset,
4512 WRITE_LOCK,
4513 WINDOWS_LOCK,
4514 False, /* Non-blocking lock. */
4515 &status,
4516 NULL);
4518 TALLOC_FREE(br_lck);
4520 if (NT_STATUS_V(status)) {
4521 reply_nterror(req, status);
4522 END_PROFILE(SMBlock);
4523 return;
4526 reply_outbuf(req, 0, 0);
4528 END_PROFILE(SMBlock);
4529 return;
4532 /****************************************************************************
4533 Reply to a unlock.
4534 ****************************************************************************/
4536 void reply_unlock(struct smb_request *req)
4538 connection_struct *conn = req->conn;
4539 SMB_BIG_UINT count,offset;
4540 NTSTATUS status;
4541 files_struct *fsp;
4543 START_PROFILE(SMBunlock);
4545 if (req->wct < 5) {
4546 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4547 END_PROFILE(SMBunlock);
4548 return;
4551 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4553 if (!check_fsp(conn, req, fsp)) {
4554 END_PROFILE(SMBunlock);
4555 return;
4558 count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
4559 offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
4561 status = do_unlock(smbd_messaging_context(),
4562 fsp,
4563 req->smbpid,
4564 count,
4565 offset,
4566 WINDOWS_LOCK);
4568 if (NT_STATUS_V(status)) {
4569 reply_nterror(req, status);
4570 END_PROFILE(SMBunlock);
4571 return;
4574 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4575 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
4577 reply_outbuf(req, 0, 0);
4579 END_PROFILE(SMBunlock);
4580 return;
4583 #undef DBGC_CLASS
4584 #define DBGC_CLASS DBGC_ALL
4586 /****************************************************************************
4587 Reply to a tdis.
4588 conn POINTER CAN BE NULL HERE !
4589 ****************************************************************************/
4591 void reply_tdis(struct smb_request *req)
4593 connection_struct *conn = req->conn;
4594 START_PROFILE(SMBtdis);
4596 if (!conn) {
4597 DEBUG(4,("Invalid connection in tdis\n"));
4598 reply_doserror(req, ERRSRV, ERRinvnid);
4599 END_PROFILE(SMBtdis);
4600 return;
4603 conn->used = False;
4605 close_cnum(conn,req->vuid);
4606 req->conn = NULL;
4608 reply_outbuf(req, 0, 0);
4609 END_PROFILE(SMBtdis);
4610 return;
4613 /****************************************************************************
4614 Reply to a echo.
4615 conn POINTER CAN BE NULL HERE !
4616 ****************************************************************************/
4618 void reply_echo(struct smb_request *req)
4620 connection_struct *conn = req->conn;
4621 int smb_reverb;
4622 int seq_num;
4623 unsigned int data_len = smb_buflen(req->inbuf);
4625 START_PROFILE(SMBecho);
4627 if (req->wct < 1) {
4628 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4629 END_PROFILE(SMBecho);
4630 return;
4633 if (data_len > BUFFER_SIZE) {
4634 DEBUG(0,("reply_echo: data_len too large.\n"));
4635 reply_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
4636 END_PROFILE(SMBecho);
4637 return;
4640 smb_reverb = SVAL(req->inbuf,smb_vwv0);
4642 reply_outbuf(req, 1, data_len);
4644 /* copy any incoming data back out */
4645 if (data_len > 0) {
4646 memcpy(smb_buf(req->outbuf),smb_buf(req->inbuf),data_len);
4649 if (smb_reverb > 100) {
4650 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
4651 smb_reverb = 100;
4654 for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
4655 SSVAL(req->outbuf,smb_vwv0,seq_num);
4657 show_msg((char *)req->outbuf);
4658 if (!srv_send_smb(smbd_server_fd(),
4659 (char *)req->outbuf,
4660 IS_CONN_ENCRYPTED(conn)||req->encrypted))
4661 exit_server_cleanly("reply_echo: srv_send_smb failed.");
4664 DEBUG(3,("echo %d times\n", smb_reverb));
4666 TALLOC_FREE(req->outbuf);
4668 END_PROFILE(SMBecho);
4669 return;
4672 /****************************************************************************
4673 Reply to a printopen.
4674 ****************************************************************************/
4676 void reply_printopen(struct smb_request *req)
4678 connection_struct *conn = req->conn;
4679 files_struct *fsp;
4680 SMB_STRUCT_STAT sbuf;
4681 NTSTATUS status;
4683 START_PROFILE(SMBsplopen);
4685 if (req->wct < 2) {
4686 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4687 END_PROFILE(SMBsplopen);
4688 return;
4691 if (!CAN_PRINT(conn)) {
4692 reply_doserror(req, ERRDOS, ERRnoaccess);
4693 END_PROFILE(SMBsplopen);
4694 return;
4697 status = file_new(conn, &fsp);
4698 if(!NT_STATUS_IS_OK(status)) {
4699 reply_nterror(req, status);
4700 END_PROFILE(SMBsplopen);
4701 return;
4704 /* Open for exclusive use, write only. */
4705 status = print_fsp_open(conn, NULL, req->vuid, fsp, &sbuf);
4707 if (!NT_STATUS_IS_OK(status)) {
4708 file_free(fsp);
4709 reply_nterror(req, status);
4710 END_PROFILE(SMBsplopen);
4711 return;
4714 reply_outbuf(req, 1, 0);
4715 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
4717 DEBUG(3,("openprint fd=%d fnum=%d\n",
4718 fsp->fh->fd, fsp->fnum));
4720 END_PROFILE(SMBsplopen);
4721 return;
4724 /****************************************************************************
4725 Reply to a printclose.
4726 ****************************************************************************/
4728 void reply_printclose(struct smb_request *req)
4730 connection_struct *conn = req->conn;
4731 files_struct *fsp;
4732 NTSTATUS status;
4734 START_PROFILE(SMBsplclose);
4736 if (req->wct < 1) {
4737 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4738 END_PROFILE(SMBsplclose);
4739 return;
4742 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4744 if (!check_fsp(conn, req, fsp)) {
4745 END_PROFILE(SMBsplclose);
4746 return;
4749 if (!CAN_PRINT(conn)) {
4750 reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
4751 END_PROFILE(SMBsplclose);
4752 return;
4755 DEBUG(3,("printclose fd=%d fnum=%d\n",
4756 fsp->fh->fd,fsp->fnum));
4758 status = close_file(fsp,NORMAL_CLOSE);
4760 if(!NT_STATUS_IS_OK(status)) {
4761 reply_nterror(req, status);
4762 END_PROFILE(SMBsplclose);
4763 return;
4766 reply_outbuf(req, 0, 0);
4768 END_PROFILE(SMBsplclose);
4769 return;
4772 /****************************************************************************
4773 Reply to a printqueue.
4774 ****************************************************************************/
4776 void reply_printqueue(struct smb_request *req)
4778 connection_struct *conn = req->conn;
4779 int max_count;
4780 int start_index;
4782 START_PROFILE(SMBsplretq);
4784 if (req->wct < 2) {
4785 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4786 END_PROFILE(SMBsplretq);
4787 return;
4790 max_count = SVAL(req->inbuf,smb_vwv0);
4791 start_index = SVAL(req->inbuf,smb_vwv1);
4793 /* we used to allow the client to get the cnum wrong, but that
4794 is really quite gross and only worked when there was only
4795 one printer - I think we should now only accept it if they
4796 get it right (tridge) */
4797 if (!CAN_PRINT(conn)) {
4798 reply_doserror(req, ERRDOS, ERRnoaccess);
4799 END_PROFILE(SMBsplretq);
4800 return;
4803 reply_outbuf(req, 2, 3);
4804 SSVAL(req->outbuf,smb_vwv0,0);
4805 SSVAL(req->outbuf,smb_vwv1,0);
4806 SCVAL(smb_buf(req->outbuf),0,1);
4807 SSVAL(smb_buf(req->outbuf),1,0);
4809 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
4810 start_index, max_count));
4813 print_queue_struct *queue = NULL;
4814 print_status_struct status;
4815 int count = print_queue_status(SNUM(conn), &queue, &status);
4816 int num_to_get = ABS(max_count);
4817 int first = (max_count>0?start_index:start_index+max_count+1);
4818 int i;
4820 if (first >= count)
4821 num_to_get = 0;
4822 else
4823 num_to_get = MIN(num_to_get,count-first);
4826 for (i=first;i<first+num_to_get;i++) {
4827 char blob[28];
4828 char *p = blob;
4830 srv_put_dos_date2(p,0,queue[i].time);
4831 SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
4832 SSVAL(p,5, queue[i].job);
4833 SIVAL(p,7,queue[i].size);
4834 SCVAL(p,11,0);
4835 srvstr_push(blob, req->flags2, p+12,
4836 queue[i].fs_user, 16, STR_ASCII);
4838 if (message_push_blob(
4839 &req->outbuf,
4840 data_blob_const(
4841 blob, sizeof(blob))) == -1) {
4842 reply_nterror(req, NT_STATUS_NO_MEMORY);
4843 END_PROFILE(SMBsplretq);
4844 return;
4848 if (count > 0) {
4849 SSVAL(req->outbuf,smb_vwv0,count);
4850 SSVAL(req->outbuf,smb_vwv1,
4851 (max_count>0?first+count:first-1));
4852 SCVAL(smb_buf(req->outbuf),0,1);
4853 SSVAL(smb_buf(req->outbuf),1,28*count);
4856 SAFE_FREE(queue);
4858 DEBUG(3,("%d entries returned in queue\n",count));
4861 END_PROFILE(SMBsplretq);
4862 return;
4865 /****************************************************************************
4866 Reply to a printwrite.
4867 ****************************************************************************/
4869 void reply_printwrite(struct smb_request *req)
4871 connection_struct *conn = req->conn;
4872 int numtowrite;
4873 char *data;
4874 files_struct *fsp;
4876 START_PROFILE(SMBsplwr);
4878 if (req->wct < 1) {
4879 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4880 END_PROFILE(SMBsplwr);
4881 return;
4884 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4886 if (!check_fsp(conn, req, fsp)) {
4887 END_PROFILE(SMBsplwr);
4888 return;
4891 if (!CAN_PRINT(conn)) {
4892 reply_doserror(req, ERRDOS, ERRnoaccess);
4893 END_PROFILE(SMBsplwr);
4894 return;
4897 if (!CHECK_WRITE(fsp)) {
4898 reply_doserror(req, ERRDOS, ERRbadaccess);
4899 END_PROFILE(SMBsplwr);
4900 return;
4903 numtowrite = SVAL(smb_buf(req->inbuf),1);
4905 if (smb_buflen(req->inbuf) < numtowrite + 3) {
4906 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4907 END_PROFILE(SMBsplwr);
4908 return;
4911 data = smb_buf(req->inbuf) + 3;
4913 if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) {
4914 reply_unixerror(req, ERRHRD, ERRdiskfull);
4915 END_PROFILE(SMBsplwr);
4916 return;
4919 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
4921 END_PROFILE(SMBsplwr);
4922 return;
4925 /****************************************************************************
4926 Reply to a mkdir.
4927 ****************************************************************************/
4929 void reply_mkdir(struct smb_request *req)
4931 connection_struct *conn = req->conn;
4932 char *directory = NULL;
4933 NTSTATUS status;
4934 SMB_STRUCT_STAT sbuf;
4935 TALLOC_CTX *ctx = talloc_tos();
4937 START_PROFILE(SMBmkdir);
4939 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
4940 smb_buf(req->inbuf) + 1, 0,
4941 STR_TERMINATE, &status);
4942 if (!NT_STATUS_IS_OK(status)) {
4943 reply_nterror(req, status);
4944 END_PROFILE(SMBmkdir);
4945 return;
4948 status = resolve_dfspath(ctx, conn,
4949 req->flags2 & FLAGS2_DFS_PATHNAMES,
4950 directory,
4951 &directory);
4952 if (!NT_STATUS_IS_OK(status)) {
4953 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4954 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
4955 ERRSRV, ERRbadpath);
4956 END_PROFILE(SMBmkdir);
4957 return;
4959 reply_nterror(req, status);
4960 END_PROFILE(SMBmkdir);
4961 return;
4964 status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
4965 if (!NT_STATUS_IS_OK(status)) {
4966 reply_nterror(req, status);
4967 END_PROFILE(SMBmkdir);
4968 return;
4971 status = check_name(conn, directory);
4972 if (!NT_STATUS_IS_OK(status)) {
4973 reply_nterror(req, status);
4974 END_PROFILE(SMBmkdir);
4975 return;
4978 status = create_directory(conn, req, directory);
4980 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
4982 if (!NT_STATUS_IS_OK(status)) {
4984 if (!use_nt_status()
4985 && NT_STATUS_EQUAL(status,
4986 NT_STATUS_OBJECT_NAME_COLLISION)) {
4988 * Yes, in the DOS error code case we get a
4989 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
4990 * samba4 torture test.
4992 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
4995 reply_nterror(req, status);
4996 END_PROFILE(SMBmkdir);
4997 return;
5000 reply_outbuf(req, 0, 0);
5002 DEBUG( 3, ( "mkdir %s\n", directory ) );
5004 END_PROFILE(SMBmkdir);
5005 return;
5008 /****************************************************************************
5009 Static function used by reply_rmdir to delete an entire directory
5010 tree recursively. Return True on ok, False on fail.
5011 ****************************************************************************/
5013 static bool recursive_rmdir(TALLOC_CTX *ctx,
5014 connection_struct *conn,
5015 char *directory)
5017 const char *dname = NULL;
5018 bool ret = True;
5019 long offset = 0;
5020 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, directory,
5021 NULL, 0);
5023 if(dir_hnd == NULL)
5024 return False;
5026 while((dname = ReadDirName(dir_hnd, &offset))) {
5027 char *fullname = NULL;
5028 SMB_STRUCT_STAT st;
5030 if (ISDOT(dname) || ISDOTDOT(dname)) {
5031 continue;
5034 if (!is_visible_file(conn, directory, dname, &st, False)) {
5035 continue;
5038 /* Construct the full name. */
5039 fullname = talloc_asprintf(ctx,
5040 "%s/%s",
5041 directory,
5042 dname);
5043 if (!fullname) {
5044 errno = ENOMEM;
5045 ret = False;
5046 break;
5049 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
5050 ret = False;
5051 break;
5054 if(st.st_mode & S_IFDIR) {
5055 if(!recursive_rmdir(ctx, conn, fullname)) {
5056 ret = False;
5057 break;
5059 if(SMB_VFS_RMDIR(conn,fullname) != 0) {
5060 ret = False;
5061 break;
5063 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
5064 ret = False;
5065 break;
5067 TALLOC_FREE(fullname);
5069 TALLOC_FREE(dir_hnd);
5070 return ret;
5073 /****************************************************************************
5074 The internals of the rmdir code - called elsewhere.
5075 ****************************************************************************/
5077 NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
5078 connection_struct *conn,
5079 const char *directory)
5081 int ret;
5082 SMB_STRUCT_STAT st;
5084 /* Might be a symlink. */
5085 if(SMB_VFS_LSTAT(conn, directory, &st) != 0) {
5086 return map_nt_error_from_unix(errno);
5089 if (S_ISLNK(st.st_mode)) {
5090 /* Is what it points to a directory ? */
5091 if(SMB_VFS_STAT(conn, directory, &st) != 0) {
5092 return map_nt_error_from_unix(errno);
5094 if (!(S_ISDIR(st.st_mode))) {
5095 return NT_STATUS_NOT_A_DIRECTORY;
5097 ret = SMB_VFS_UNLINK(conn,directory);
5098 } else {
5099 ret = SMB_VFS_RMDIR(conn,directory);
5101 if (ret == 0) {
5102 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5103 FILE_NOTIFY_CHANGE_DIR_NAME,
5104 directory);
5105 return NT_STATUS_OK;
5108 if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
5110 * Check to see if the only thing in this directory are
5111 * vetoed files/directories. If so then delete them and
5112 * retry. If we fail to delete any of them (and we *don't*
5113 * do a recursive delete) then fail the rmdir.
5115 const char *dname;
5116 long dirpos = 0;
5117 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
5118 directory, NULL, 0);
5120 if(dir_hnd == NULL) {
5121 errno = ENOTEMPTY;
5122 goto err;
5125 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
5126 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
5127 continue;
5128 if (!is_visible_file(conn, directory, dname, &st, False))
5129 continue;
5130 if(!IS_VETO_PATH(conn, dname)) {
5131 TALLOC_FREE(dir_hnd);
5132 errno = ENOTEMPTY;
5133 goto err;
5137 /* We only have veto files/directories.
5138 * Are we allowed to delete them ? */
5140 if(!lp_recursive_veto_delete(SNUM(conn))) {
5141 TALLOC_FREE(dir_hnd);
5142 errno = ENOTEMPTY;
5143 goto err;
5146 /* Do a recursive delete. */
5147 RewindDir(dir_hnd,&dirpos);
5148 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
5149 char *fullname = NULL;
5151 if (ISDOT(dname) || ISDOTDOT(dname)) {
5152 continue;
5154 if (!is_visible_file(conn, directory, dname, &st, False)) {
5155 continue;
5158 fullname = talloc_asprintf(ctx,
5159 "%s/%s",
5160 directory,
5161 dname);
5163 if(!fullname) {
5164 errno = ENOMEM;
5165 break;
5168 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
5169 break;
5171 if(st.st_mode & S_IFDIR) {
5172 if(!recursive_rmdir(ctx, conn, fullname)) {
5173 break;
5175 if(SMB_VFS_RMDIR(conn,fullname) != 0) {
5176 break;
5178 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
5179 break;
5181 TALLOC_FREE(fullname);
5183 TALLOC_FREE(dir_hnd);
5184 /* Retry the rmdir */
5185 ret = SMB_VFS_RMDIR(conn,directory);
5188 err:
5190 if (ret != 0) {
5191 DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
5192 "%s\n", directory,strerror(errno)));
5193 return map_nt_error_from_unix(errno);
5196 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5197 FILE_NOTIFY_CHANGE_DIR_NAME,
5198 directory);
5200 return NT_STATUS_OK;
5203 /****************************************************************************
5204 Reply to a rmdir.
5205 ****************************************************************************/
5207 void reply_rmdir(struct smb_request *req)
5209 connection_struct *conn = req->conn;
5210 char *directory = NULL;
5211 SMB_STRUCT_STAT sbuf;
5212 NTSTATUS status;
5213 TALLOC_CTX *ctx = talloc_tos();
5215 START_PROFILE(SMBrmdir);
5217 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
5218 smb_buf(req->inbuf) + 1, 0,
5219 STR_TERMINATE, &status);
5220 if (!NT_STATUS_IS_OK(status)) {
5221 reply_nterror(req, status);
5222 END_PROFILE(SMBrmdir);
5223 return;
5226 status = resolve_dfspath(ctx, conn,
5227 req->flags2 & FLAGS2_DFS_PATHNAMES,
5228 directory,
5229 &directory);
5230 if (!NT_STATUS_IS_OK(status)) {
5231 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5232 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5233 ERRSRV, ERRbadpath);
5234 END_PROFILE(SMBrmdir);
5235 return;
5237 reply_nterror(req, status);
5238 END_PROFILE(SMBrmdir);
5239 return;
5242 status = unix_convert(ctx, conn, directory, False, &directory,
5243 NULL, &sbuf);
5244 if (!NT_STATUS_IS_OK(status)) {
5245 reply_nterror(req, status);
5246 END_PROFILE(SMBrmdir);
5247 return;
5250 status = check_name(conn, directory);
5251 if (!NT_STATUS_IS_OK(status)) {
5252 reply_nterror(req, status);
5253 END_PROFILE(SMBrmdir);
5254 return;
5257 dptr_closepath(directory, req->smbpid);
5258 status = rmdir_internals(ctx, conn, directory);
5259 if (!NT_STATUS_IS_OK(status)) {
5260 reply_nterror(req, status);
5261 END_PROFILE(SMBrmdir);
5262 return;
5265 reply_outbuf(req, 0, 0);
5267 DEBUG( 3, ( "rmdir %s\n", directory ) );
5269 END_PROFILE(SMBrmdir);
5270 return;
5273 /*******************************************************************
5274 Resolve wildcards in a filename rename.
5275 ********************************************************************/
5277 static bool resolve_wildcards(TALLOC_CTX *ctx,
5278 const char *name1,
5279 const char *name2,
5280 char **pp_newname)
5282 char *name2_copy = NULL;
5283 char *root1 = NULL;
5284 char *root2 = NULL;
5285 char *ext1 = NULL;
5286 char *ext2 = NULL;
5287 char *p,*p2, *pname1, *pname2;
5289 name2_copy = talloc_strdup(ctx, name2);
5290 if (!name2_copy) {
5291 return False;
5294 pname1 = strrchr_m(name1,'/');
5295 pname2 = strrchr_m(name2_copy,'/');
5297 if (!pname1 || !pname2) {
5298 return False;
5301 /* Truncate the copy of name2 at the last '/' */
5302 *pname2 = '\0';
5304 /* Now go past the '/' */
5305 pname1++;
5306 pname2++;
5308 root1 = talloc_strdup(ctx, pname1);
5309 root2 = talloc_strdup(ctx, pname2);
5311 if (!root1 || !root2) {
5312 return False;
5315 p = strrchr_m(root1,'.');
5316 if (p) {
5317 *p = 0;
5318 ext1 = talloc_strdup(ctx, p+1);
5319 } else {
5320 ext1 = talloc_strdup(ctx, "");
5322 p = strrchr_m(root2,'.');
5323 if (p) {
5324 *p = 0;
5325 ext2 = talloc_strdup(ctx, p+1);
5326 } else {
5327 ext2 = talloc_strdup(ctx, "");
5330 if (!ext1 || !ext2) {
5331 return False;
5334 p = root1;
5335 p2 = root2;
5336 while (*p2) {
5337 if (*p2 == '?') {
5338 /* Hmmm. Should this be mb-aware ? */
5339 *p2 = *p;
5340 p2++;
5341 } else if (*p2 == '*') {
5342 *p2 = '\0';
5343 root2 = talloc_asprintf(ctx, "%s%s",
5344 root2,
5346 if (!root2) {
5347 return False;
5349 break;
5350 } else {
5351 p2++;
5353 if (*p) {
5354 p++;
5358 p = ext1;
5359 p2 = ext2;
5360 while (*p2) {
5361 if (*p2 == '?') {
5362 /* Hmmm. Should this be mb-aware ? */
5363 *p2 = *p;
5364 p2++;
5365 } else if (*p2 == '*') {
5366 *p2 = '\0';
5367 ext2 = talloc_asprintf(ctx, "%s%s",
5368 ext2,
5370 if (!ext2) {
5371 return False;
5373 break;
5374 } else {
5375 p2++;
5377 if (*p) {
5378 p++;
5382 if (*ext2) {
5383 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5384 name2_copy,
5385 root2,
5386 ext2);
5387 } else {
5388 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5389 name2_copy,
5390 root2);
5393 if (!*pp_newname) {
5394 return False;
5397 return True;
5400 /****************************************************************************
5401 Ensure open files have their names updated. Updated to notify other smbd's
5402 asynchronously.
5403 ****************************************************************************/
5405 static void rename_open_files(connection_struct *conn,
5406 struct share_mode_lock *lck,
5407 const char *newname)
5409 files_struct *fsp;
5410 bool did_rename = False;
5412 for(fsp = file_find_di_first(lck->id); fsp;
5413 fsp = file_find_di_next(fsp)) {
5414 /* fsp_name is a relative path under the fsp. To change this for other
5415 sharepaths we need to manipulate relative paths. */
5416 /* TODO - create the absolute path and manipulate the newname
5417 relative to the sharepath. */
5418 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5419 continue;
5421 DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n",
5422 fsp->fnum, file_id_string_tos(&fsp->file_id),
5423 fsp->fsp_name, newname ));
5424 string_set(&fsp->fsp_name, newname);
5425 did_rename = True;
5428 if (!did_rename) {
5429 DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n",
5430 file_id_string_tos(&lck->id), newname ));
5433 /* Send messages to all smbd's (not ourself) that the name has changed. */
5434 rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
5435 newname);
5438 /****************************************************************************
5439 We need to check if the source path is a parent directory of the destination
5440 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5441 refuse the rename with a sharing violation. Under UNIX the above call can
5442 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5443 probably need to check that the client is a Windows one before disallowing
5444 this as a UNIX client (one with UNIX extensions) can know the source is a
5445 symlink and make this decision intelligently. Found by an excellent bug
5446 report from <AndyLiebman@aol.com>.
5447 ****************************************************************************/
5449 static bool rename_path_prefix_equal(const char *src, const char *dest)
5451 const char *psrc = src;
5452 const char *pdst = dest;
5453 size_t slen;
5455 if (psrc[0] == '.' && psrc[1] == '/') {
5456 psrc += 2;
5458 if (pdst[0] == '.' && pdst[1] == '/') {
5459 pdst += 2;
5461 if ((slen = strlen(psrc)) > strlen(pdst)) {
5462 return False;
5464 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5468 * Do the notify calls from a rename
5471 static void notify_rename(connection_struct *conn, bool is_dir,
5472 const char *oldpath, const char *newpath)
5474 char *olddir, *newdir;
5475 const char *oldname, *newname;
5476 uint32 mask;
5478 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5479 : FILE_NOTIFY_CHANGE_FILE_NAME;
5481 if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
5482 || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
5483 TALLOC_FREE(olddir);
5484 return;
5487 if (strcmp(olddir, newdir) == 0) {
5488 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
5489 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
5491 else {
5492 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
5493 notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
5495 TALLOC_FREE(olddir);
5496 TALLOC_FREE(newdir);
5498 /* this is a strange one. w2k3 gives an additional event for
5499 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5500 files, but not directories */
5501 if (!is_dir) {
5502 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5503 FILE_NOTIFY_CHANGE_ATTRIBUTES
5504 |FILE_NOTIFY_CHANGE_CREATION,
5505 newpath);
5509 /****************************************************************************
5510 Rename an open file - given an fsp.
5511 ****************************************************************************/
5513 NTSTATUS rename_internals_fsp(connection_struct *conn,
5514 files_struct *fsp,
5515 char *newname,
5516 const char *newname_last_component,
5517 uint32 attrs,
5518 bool replace_if_exists)
5520 TALLOC_CTX *ctx = talloc_tos();
5521 SMB_STRUCT_STAT sbuf, sbuf1;
5522 NTSTATUS status = NT_STATUS_OK;
5523 struct share_mode_lock *lck = NULL;
5524 bool dst_exists, old_is_stream, new_is_stream;
5526 ZERO_STRUCT(sbuf);
5528 status = check_name(conn, newname);
5529 if (!NT_STATUS_IS_OK(status)) {
5530 return status;
5533 /* Ensure newname contains a '/' */
5534 if(strrchr_m(newname,'/') == 0) {
5535 newname = talloc_asprintf(ctx,
5536 "./%s",
5537 newname);
5538 if (!newname) {
5539 return NT_STATUS_NO_MEMORY;
5544 * Check for special case with case preserving and not
5545 * case sensitive. If the old last component differs from the original
5546 * last component only by case, then we should allow
5547 * the rename (user is trying to change the case of the
5548 * filename).
5551 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5552 strequal(newname, fsp->fsp_name)) {
5553 char *p;
5554 char *newname_modified_last_component = NULL;
5557 * Get the last component of the modified name.
5558 * Note that we guarantee that newname contains a '/'
5559 * character above.
5561 p = strrchr_m(newname,'/');
5562 newname_modified_last_component = talloc_strdup(ctx,
5563 p+1);
5564 if (!newname_modified_last_component) {
5565 return NT_STATUS_NO_MEMORY;
5568 if(strcsequal(newname_modified_last_component,
5569 newname_last_component) == False) {
5571 * Replace the modified last component with
5572 * the original.
5574 *p = '\0'; /* Truncate at the '/' */
5575 newname = talloc_asprintf(ctx,
5576 "%s/%s",
5577 newname,
5578 newname_last_component);
5583 * If the src and dest names are identical - including case,
5584 * don't do the rename, just return success.
5587 if (strcsequal(fsp->fsp_name, newname)) {
5588 DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n",
5589 newname));
5590 return NT_STATUS_OK;
5593 old_is_stream = is_ntfs_stream_name(fsp->fsp_name);
5594 new_is_stream = is_ntfs_stream_name(newname);
5596 /* Return the correct error code if both names aren't streams. */
5597 if (!old_is_stream && new_is_stream) {
5598 return NT_STATUS_OBJECT_NAME_INVALID;
5601 if (old_is_stream && !new_is_stream) {
5602 return NT_STATUS_INVALID_PARAMETER;
5606 * Have vfs_object_exist also fill sbuf1
5608 dst_exists = vfs_object_exist(conn, newname, &sbuf1);
5610 if(!replace_if_exists && dst_exists) {
5611 DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
5612 fsp->fsp_name,newname));
5613 return NT_STATUS_OBJECT_NAME_COLLISION;
5616 if (dst_exists) {
5617 struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf1);
5618 files_struct *dst_fsp = file_find_di_first(fileid);
5619 /* The file can be open when renaming a stream */
5620 if (dst_fsp && !new_is_stream) {
5621 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
5622 return NT_STATUS_ACCESS_DENIED;
5626 /* Ensure we have a valid stat struct for the source. */
5627 if (fsp->fh->fd != -1) {
5628 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
5629 return map_nt_error_from_unix(errno);
5631 } else {
5632 int ret = -1;
5633 if (fsp->posix_open) {
5634 ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf);
5635 } else {
5636 ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf);
5638 if (ret == -1) {
5639 return map_nt_error_from_unix(errno);
5643 status = can_rename(conn, fsp, attrs, &sbuf);
5645 if (!NT_STATUS_IS_OK(status)) {
5646 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
5647 nt_errstr(status), fsp->fsp_name,newname));
5648 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
5649 status = NT_STATUS_ACCESS_DENIED;
5650 return status;
5653 if (rename_path_prefix_equal(fsp->fsp_name, newname)) {
5654 return NT_STATUS_ACCESS_DENIED;
5657 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
5658 NULL);
5661 * We have the file open ourselves, so not being able to get the
5662 * corresponding share mode lock is a fatal error.
5665 SMB_ASSERT(lck != NULL);
5667 if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
5668 uint32 create_options = fsp->fh->private_options;
5670 DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
5671 fsp->fsp_name,newname));
5673 notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname);
5675 rename_open_files(conn, lck, newname);
5678 * A rename acts as a new file create w.r.t. allowing an initial delete
5679 * on close, probably because in Windows there is a new handle to the
5680 * new file. If initial delete on close was requested but not
5681 * originally set, we need to set it here. This is probably not 100% correct,
5682 * but will work for the CIFSFS client which in non-posix mode
5683 * depends on these semantics. JRA.
5686 if (create_options & FILE_DELETE_ON_CLOSE) {
5687 status = can_set_delete_on_close(fsp, True, 0);
5689 if (NT_STATUS_IS_OK(status)) {
5690 /* Note that here we set the *inital* delete on close flag,
5691 * not the regular one. The magic gets handled in close. */
5692 fsp->initial_delete_on_close = True;
5695 TALLOC_FREE(lck);
5696 return NT_STATUS_OK;
5699 TALLOC_FREE(lck);
5701 if (errno == ENOTDIR || errno == EISDIR) {
5702 status = NT_STATUS_OBJECT_NAME_COLLISION;
5703 } else {
5704 status = map_nt_error_from_unix(errno);
5707 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
5708 nt_errstr(status), fsp->fsp_name,newname));
5710 return status;
5713 /****************************************************************************
5714 The guts of the rename command, split out so it may be called by the NT SMB
5715 code.
5716 ****************************************************************************/
5718 NTSTATUS rename_internals(TALLOC_CTX *ctx,
5719 connection_struct *conn,
5720 struct smb_request *req,
5721 const char *name_in,
5722 const char *newname_in,
5723 uint32 attrs,
5724 bool replace_if_exists,
5725 bool src_has_wild,
5726 bool dest_has_wild,
5727 uint32_t access_mask)
5729 char *directory = NULL;
5730 char *mask = NULL;
5731 char *last_component_src = NULL;
5732 char *last_component_dest = NULL;
5733 char *name = NULL;
5734 char *newname = NULL;
5735 char *p;
5736 int count=0;
5737 NTSTATUS status = NT_STATUS_OK;
5738 SMB_STRUCT_STAT sbuf1, sbuf2;
5739 struct smb_Dir *dir_hnd = NULL;
5740 const char *dname;
5741 long offset = 0;
5742 bool posix_pathnames = lp_posix_pathnames();
5744 ZERO_STRUCT(sbuf1);
5745 ZERO_STRUCT(sbuf2);
5747 status = unix_convert(ctx, conn, name_in, src_has_wild, &name,
5748 &last_component_src, &sbuf1);
5749 if (!NT_STATUS_IS_OK(status)) {
5750 return status;
5753 status = unix_convert(ctx, conn, newname_in, dest_has_wild, &newname,
5754 &last_component_dest, &sbuf2);
5755 if (!NT_STATUS_IS_OK(status)) {
5756 return status;
5760 * Split the old name into directory and last component
5761 * strings. Note that unix_convert may have stripped off a
5762 * leading ./ from both name and newname if the rename is
5763 * at the root of the share. We need to make sure either both
5764 * name and newname contain a / character or neither of them do
5765 * as this is checked in resolve_wildcards().
5768 p = strrchr_m(name,'/');
5769 if (!p) {
5770 directory = talloc_strdup(ctx, ".");
5771 if (!directory) {
5772 return NT_STATUS_NO_MEMORY;
5774 mask = name;
5775 } else {
5776 *p = 0;
5777 directory = talloc_strdup(ctx, name);
5778 if (!directory) {
5779 return NT_STATUS_NO_MEMORY;
5781 mask = p+1;
5782 *p = '/'; /* Replace needed for exceptional test below. */
5786 * We should only check the mangled cache
5787 * here if unix_convert failed. This means
5788 * that the path in 'mask' doesn't exist
5789 * on the file system and so we need to look
5790 * for a possible mangle. This patch from
5791 * Tine Smukavec <valentin.smukavec@hermes.si>.
5794 if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
5795 char *new_mask = NULL;
5796 mangle_lookup_name_from_8_3(ctx,
5797 mask,
5798 &new_mask,
5799 conn->params );
5800 if (new_mask) {
5801 mask = new_mask;
5805 if (!src_has_wild) {
5806 files_struct *fsp;
5809 * No wildcards - just process the one file.
5811 bool is_short_name = mangle_is_8_3(name, True, conn->params);
5813 /* Add a terminating '/' to the directory name. */
5814 directory = talloc_asprintf_append(directory,
5815 "/%s",
5816 mask);
5817 if (!directory) {
5818 return NT_STATUS_NO_MEMORY;
5821 /* Ensure newname contains a '/' also */
5822 if(strrchr_m(newname,'/') == 0) {
5823 newname = talloc_asprintf(ctx,
5824 "./%s",
5825 newname);
5826 if (!newname) {
5827 return NT_STATUS_NO_MEMORY;
5831 DEBUG(3, ("rename_internals: case_sensitive = %d, "
5832 "case_preserve = %d, short case preserve = %d, "
5833 "directory = %s, newname = %s, "
5834 "last_component_dest = %s, is_8_3 = %d\n",
5835 conn->case_sensitive, conn->case_preserve,
5836 conn->short_case_preserve, directory,
5837 newname, last_component_dest, is_short_name));
5839 /* The dest name still may have wildcards. */
5840 if (dest_has_wild) {
5841 char *mod_newname = NULL;
5842 if (!resolve_wildcards(ctx,
5843 directory,newname,&mod_newname)) {
5844 DEBUG(6, ("rename_internals: resolve_wildcards "
5845 "%s %s failed\n",
5846 directory,
5847 newname));
5848 return NT_STATUS_NO_MEMORY;
5850 newname = mod_newname;
5853 ZERO_STRUCT(sbuf1);
5854 if (posix_pathnames) {
5855 SMB_VFS_LSTAT(conn, directory, &sbuf1);
5856 } else {
5857 SMB_VFS_STAT(conn, directory, &sbuf1);
5860 status = S_ISDIR(sbuf1.st_mode) ?
5861 open_directory(conn, req, directory, &sbuf1,
5862 access_mask,
5863 FILE_SHARE_READ|FILE_SHARE_WRITE,
5864 FILE_OPEN,
5866 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
5867 NULL,
5868 &fsp)
5869 : open_file_ntcreate(conn, req, directory, &sbuf1,
5870 access_mask,
5871 FILE_SHARE_READ|FILE_SHARE_WRITE,
5872 FILE_OPEN,
5874 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
5876 NULL,
5877 &fsp);
5879 if (!NT_STATUS_IS_OK(status)) {
5880 DEBUG(3, ("Could not open rename source %s: %s\n",
5881 directory, nt_errstr(status)));
5882 return status;
5885 status = rename_internals_fsp(conn, fsp, newname,
5886 last_component_dest,
5887 attrs, replace_if_exists);
5889 close_file(fsp, NORMAL_CLOSE);
5891 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
5892 nt_errstr(status), directory,newname));
5894 return status;
5898 * Wildcards - process each file that matches.
5900 if (strequal(mask,"????????.???")) {
5901 mask[0] = '*';
5902 mask[1] = '\0';
5905 status = check_name(conn, directory);
5906 if (!NT_STATUS_IS_OK(status)) {
5907 return status;
5910 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs);
5911 if (dir_hnd == NULL) {
5912 return map_nt_error_from_unix(errno);
5915 status = NT_STATUS_NO_SUCH_FILE;
5917 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
5918 * - gentest fix. JRA
5921 while ((dname = ReadDirName(dir_hnd, &offset))) {
5922 files_struct *fsp = NULL;
5923 char *fname = NULL;
5924 char *destname = NULL;
5925 bool sysdir_entry = False;
5927 /* Quick check for "." and ".." */
5928 if (ISDOT(dname) || ISDOTDOT(dname)) {
5929 if (attrs & aDIR) {
5930 sysdir_entry = True;
5931 } else {
5932 continue;
5936 if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
5937 continue;
5940 if(!mask_match(dname, mask, conn->case_sensitive)) {
5941 continue;
5944 if (sysdir_entry) {
5945 status = NT_STATUS_OBJECT_NAME_INVALID;
5946 break;
5949 fname = talloc_asprintf(ctx,
5950 "%s/%s",
5951 directory,
5952 dname);
5953 if (!fname) {
5954 return NT_STATUS_NO_MEMORY;
5957 if (!resolve_wildcards(ctx,
5958 fname,newname,&destname)) {
5959 DEBUG(6, ("resolve_wildcards %s %s failed\n",
5960 fname, destname));
5961 TALLOC_FREE(fname);
5962 continue;
5964 if (!destname) {
5965 return NT_STATUS_NO_MEMORY;
5968 ZERO_STRUCT(sbuf1);
5969 if (posix_pathnames) {
5970 SMB_VFS_LSTAT(conn, fname, &sbuf1);
5971 } else {
5972 SMB_VFS_STAT(conn, fname, &sbuf1);
5975 status = S_ISDIR(sbuf1.st_mode) ?
5976 open_directory(conn, req, fname, &sbuf1,
5977 access_mask,
5978 FILE_SHARE_READ|FILE_SHARE_WRITE,
5979 FILE_OPEN,
5981 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
5982 NULL,
5983 &fsp)
5984 : open_file_ntcreate(conn, req, fname, &sbuf1,
5985 access_mask,
5986 FILE_SHARE_READ|FILE_SHARE_WRITE,
5987 FILE_OPEN,
5989 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0,
5991 NULL,
5992 &fsp);
5994 if (!NT_STATUS_IS_OK(status)) {
5995 DEBUG(3,("rename_internals: open_file_ntcreate "
5996 "returned %s rename %s -> %s\n",
5997 nt_errstr(status), directory, newname));
5998 break;
6001 status = rename_internals_fsp(conn, fsp, destname, dname,
6002 attrs, replace_if_exists);
6004 close_file(fsp, NORMAL_CLOSE);
6006 if (!NT_STATUS_IS_OK(status)) {
6007 DEBUG(3, ("rename_internals_fsp returned %s for "
6008 "rename %s -> %s\n", nt_errstr(status),
6009 directory, newname));
6010 break;
6013 count++;
6015 DEBUG(3,("rename_internals: doing rename on %s -> "
6016 "%s\n",fname,destname));
6018 TALLOC_FREE(fname);
6019 TALLOC_FREE(destname);
6021 TALLOC_FREE(dir_hnd);
6023 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6024 status = map_nt_error_from_unix(errno);
6027 return status;
6030 /****************************************************************************
6031 Reply to a mv.
6032 ****************************************************************************/
6034 void reply_mv(struct smb_request *req)
6036 connection_struct *conn = req->conn;
6037 char *name = NULL;
6038 char *newname = NULL;
6039 char *p;
6040 uint32 attrs;
6041 NTSTATUS status;
6042 bool src_has_wcard = False;
6043 bool dest_has_wcard = False;
6044 TALLOC_CTX *ctx = talloc_tos();
6046 START_PROFILE(SMBmv);
6048 if (req->wct < 1) {
6049 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6050 END_PROFILE(SMBmv);
6051 return;
6054 attrs = SVAL(req->inbuf,smb_vwv0);
6056 p = smb_buf(req->inbuf) + 1;
6057 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
6058 0, STR_TERMINATE, &status,
6059 &src_has_wcard);
6060 if (!NT_STATUS_IS_OK(status)) {
6061 reply_nterror(req, status);
6062 END_PROFILE(SMBmv);
6063 return;
6065 p++;
6066 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
6067 0, STR_TERMINATE, &status,
6068 &dest_has_wcard);
6069 if (!NT_STATUS_IS_OK(status)) {
6070 reply_nterror(req, status);
6071 END_PROFILE(SMBmv);
6072 return;
6075 status = resolve_dfspath_wcard(ctx, conn,
6076 req->flags2 & FLAGS2_DFS_PATHNAMES,
6077 name,
6078 &name,
6079 &src_has_wcard);
6080 if (!NT_STATUS_IS_OK(status)) {
6081 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6082 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6083 ERRSRV, ERRbadpath);
6084 END_PROFILE(SMBmv);
6085 return;
6087 reply_nterror(req, status);
6088 END_PROFILE(SMBmv);
6089 return;
6092 status = resolve_dfspath_wcard(ctx, conn,
6093 req->flags2 & FLAGS2_DFS_PATHNAMES,
6094 newname,
6095 &newname,
6096 &dest_has_wcard);
6097 if (!NT_STATUS_IS_OK(status)) {
6098 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6099 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6100 ERRSRV, ERRbadpath);
6101 END_PROFILE(SMBmv);
6102 return;
6104 reply_nterror(req, status);
6105 END_PROFILE(SMBmv);
6106 return;
6109 DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
6111 status = rename_internals(ctx, conn, req, name, newname, attrs, False,
6112 src_has_wcard, dest_has_wcard, DELETE_ACCESS);
6113 if (!NT_STATUS_IS_OK(status)) {
6114 if (open_was_deferred(req->mid)) {
6115 /* We have re-scheduled this call. */
6116 END_PROFILE(SMBmv);
6117 return;
6119 reply_nterror(req, status);
6120 END_PROFILE(SMBmv);
6121 return;
6124 reply_outbuf(req, 0, 0);
6126 END_PROFILE(SMBmv);
6127 return;
6130 /*******************************************************************
6131 Copy a file as part of a reply_copy.
6132 ******************************************************************/
6135 * TODO: check error codes on all callers
6138 NTSTATUS copy_file(TALLOC_CTX *ctx,
6139 connection_struct *conn,
6140 const char *src,
6141 const char *dest1,
6142 int ofun,
6143 int count,
6144 bool target_is_directory)
6146 SMB_STRUCT_STAT src_sbuf, sbuf2;
6147 SMB_OFF_T ret=-1;
6148 files_struct *fsp1,*fsp2;
6149 char *dest = NULL;
6150 uint32 dosattrs;
6151 uint32 new_create_disposition;
6152 NTSTATUS status;
6154 dest = talloc_strdup(ctx, dest1);
6155 if (!dest) {
6156 return NT_STATUS_NO_MEMORY;
6158 if (target_is_directory) {
6159 const char *p = strrchr_m(src,'/');
6160 if (p) {
6161 p++;
6162 } else {
6163 p = src;
6165 dest = talloc_asprintf_append(dest,
6166 "/%s",
6168 if (!dest) {
6169 return NT_STATUS_NO_MEMORY;
6173 if (!vfs_file_exist(conn,src,&src_sbuf)) {
6174 TALLOC_FREE(dest);
6175 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6178 if (!target_is_directory && count) {
6179 new_create_disposition = FILE_OPEN;
6180 } else {
6181 if (!map_open_params_to_ntcreate(dest1,0,ofun,
6182 NULL, NULL, &new_create_disposition, NULL)) {
6183 TALLOC_FREE(dest);
6184 return NT_STATUS_INVALID_PARAMETER;
6188 status = open_file_ntcreate(conn, NULL, src, &src_sbuf,
6189 FILE_GENERIC_READ,
6190 FILE_SHARE_READ|FILE_SHARE_WRITE,
6191 FILE_OPEN,
6193 FILE_ATTRIBUTE_NORMAL,
6194 INTERNAL_OPEN_ONLY,
6195 NULL, &fsp1);
6197 if (!NT_STATUS_IS_OK(status)) {
6198 TALLOC_FREE(dest);
6199 return status;
6202 dosattrs = dos_mode(conn, src, &src_sbuf);
6203 if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) {
6204 ZERO_STRUCTP(&sbuf2);
6207 status = open_file_ntcreate(conn, NULL, dest, &sbuf2,
6208 FILE_GENERIC_WRITE,
6209 FILE_SHARE_READ|FILE_SHARE_WRITE,
6210 new_create_disposition,
6212 dosattrs,
6213 INTERNAL_OPEN_ONLY,
6214 NULL, &fsp2);
6216 TALLOC_FREE(dest);
6218 if (!NT_STATUS_IS_OK(status)) {
6219 close_file(fsp1,ERROR_CLOSE);
6220 return status;
6223 if ((ofun&3) == 1) {
6224 if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
6225 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
6227 * Stop the copy from occurring.
6229 ret = -1;
6230 src_sbuf.st_size = 0;
6234 if (src_sbuf.st_size) {
6235 ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
6238 close_file(fsp1,NORMAL_CLOSE);
6240 /* Ensure the modtime is set correctly on the destination file. */
6241 set_close_write_time(fsp2, get_mtimespec(&src_sbuf));
6244 * As we are opening fsp1 read-only we only expect
6245 * an error on close on fsp2 if we are out of space.
6246 * Thus we don't look at the error return from the
6247 * close of fsp1.
6249 status = close_file(fsp2,NORMAL_CLOSE);
6251 if (!NT_STATUS_IS_OK(status)) {
6252 return status;
6255 if (ret != (SMB_OFF_T)src_sbuf.st_size) {
6256 return NT_STATUS_DISK_FULL;
6259 return NT_STATUS_OK;
6262 /****************************************************************************
6263 Reply to a file copy.
6264 ****************************************************************************/
6266 void reply_copy(struct smb_request *req)
6268 connection_struct *conn = req->conn;
6269 char *name = NULL;
6270 char *newname = NULL;
6271 char *directory = NULL;
6272 char *mask = NULL;
6273 char *p;
6274 int count=0;
6275 int error = ERRnoaccess;
6276 int err = 0;
6277 int tid2;
6278 int ofun;
6279 int flags;
6280 bool target_is_directory=False;
6281 bool source_has_wild = False;
6282 bool dest_has_wild = False;
6283 SMB_STRUCT_STAT sbuf1, sbuf2;
6284 NTSTATUS status;
6285 TALLOC_CTX *ctx = talloc_tos();
6287 START_PROFILE(SMBcopy);
6289 if (req->wct < 3) {
6290 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6291 END_PROFILE(SMBcopy);
6292 return;
6295 tid2 = SVAL(req->inbuf,smb_vwv0);
6296 ofun = SVAL(req->inbuf,smb_vwv1);
6297 flags = SVAL(req->inbuf,smb_vwv2);
6299 p = smb_buf(req->inbuf);
6300 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
6301 0, STR_TERMINATE, &status,
6302 &source_has_wild);
6303 if (!NT_STATUS_IS_OK(status)) {
6304 reply_nterror(req, status);
6305 END_PROFILE(SMBcopy);
6306 return;
6308 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
6309 0, STR_TERMINATE, &status,
6310 &dest_has_wild);
6311 if (!NT_STATUS_IS_OK(status)) {
6312 reply_nterror(req, status);
6313 END_PROFILE(SMBcopy);
6314 return;
6317 DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
6319 if (tid2 != conn->cnum) {
6320 /* can't currently handle inter share copies XXXX */
6321 DEBUG(3,("Rejecting inter-share copy\n"));
6322 reply_doserror(req, ERRSRV, ERRinvdevice);
6323 END_PROFILE(SMBcopy);
6324 return;
6327 status = resolve_dfspath_wcard(ctx, conn,
6328 req->flags2 & FLAGS2_DFS_PATHNAMES,
6329 name,
6330 &name,
6331 &source_has_wild);
6332 if (!NT_STATUS_IS_OK(status)) {
6333 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6334 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6335 ERRSRV, ERRbadpath);
6336 END_PROFILE(SMBcopy);
6337 return;
6339 reply_nterror(req, status);
6340 END_PROFILE(SMBcopy);
6341 return;
6344 status = resolve_dfspath_wcard(ctx, conn,
6345 req->flags2 & FLAGS2_DFS_PATHNAMES,
6346 newname,
6347 &newname,
6348 &dest_has_wild);
6349 if (!NT_STATUS_IS_OK(status)) {
6350 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6351 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6352 ERRSRV, ERRbadpath);
6353 END_PROFILE(SMBcopy);
6354 return;
6356 reply_nterror(req, status);
6357 END_PROFILE(SMBcopy);
6358 return;
6361 status = unix_convert(ctx, conn, name, source_has_wild,
6362 &name, NULL, &sbuf1);
6363 if (!NT_STATUS_IS_OK(status)) {
6364 reply_nterror(req, status);
6365 END_PROFILE(SMBcopy);
6366 return;
6369 status = unix_convert(ctx, conn, newname, dest_has_wild,
6370 &newname, NULL, &sbuf2);
6371 if (!NT_STATUS_IS_OK(status)) {
6372 reply_nterror(req, status);
6373 END_PROFILE(SMBcopy);
6374 return;
6377 target_is_directory = VALID_STAT_OF_DIR(sbuf2);
6379 if ((flags&1) && target_is_directory) {
6380 reply_doserror(req, ERRDOS, ERRbadfile);
6381 END_PROFILE(SMBcopy);
6382 return;
6385 if ((flags&2) && !target_is_directory) {
6386 reply_doserror(req, ERRDOS, ERRbadpath);
6387 END_PROFILE(SMBcopy);
6388 return;
6391 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
6392 /* wants a tree copy! XXXX */
6393 DEBUG(3,("Rejecting tree copy\n"));
6394 reply_doserror(req, ERRSRV, ERRerror);
6395 END_PROFILE(SMBcopy);
6396 return;
6399 p = strrchr_m(name,'/');
6400 if (!p) {
6401 directory = talloc_strdup(ctx, "./");
6402 if (!directory) {
6403 reply_nterror(req, NT_STATUS_NO_MEMORY);
6404 END_PROFILE(SMBcopy);
6405 return;
6407 mask = name;
6408 } else {
6409 *p = 0;
6410 directory = talloc_strdup(ctx, name);
6411 if (!directory) {
6412 reply_nterror(req, NT_STATUS_NO_MEMORY);
6413 END_PROFILE(SMBcopy);
6414 return;
6416 mask = p+1;
6420 * We should only check the mangled cache
6421 * here if unix_convert failed. This means
6422 * that the path in 'mask' doesn't exist
6423 * on the file system and so we need to look
6424 * for a possible mangle. This patch from
6425 * Tine Smukavec <valentin.smukavec@hermes.si>.
6428 if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
6429 char *new_mask = NULL;
6430 mangle_lookup_name_from_8_3(ctx,
6431 mask,
6432 &new_mask,
6433 conn->params );
6434 if (new_mask) {
6435 mask = new_mask;
6439 if (!source_has_wild) {
6440 directory = talloc_asprintf_append(directory,
6441 "/%s",
6442 mask);
6443 if (dest_has_wild) {
6444 char *mod_newname = NULL;
6445 if (!resolve_wildcards(ctx,
6446 directory,newname,&mod_newname)) {
6447 reply_nterror(req, NT_STATUS_NO_MEMORY);
6448 END_PROFILE(SMBcopy);
6449 return;
6451 newname = mod_newname;
6454 status = check_name(conn, directory);
6455 if (!NT_STATUS_IS_OK(status)) {
6456 reply_nterror(req, status);
6457 END_PROFILE(SMBcopy);
6458 return;
6461 status = check_name(conn, newname);
6462 if (!NT_STATUS_IS_OK(status)) {
6463 reply_nterror(req, status);
6464 END_PROFILE(SMBcopy);
6465 return;
6468 status = copy_file(ctx,conn,directory,newname,ofun,
6469 count,target_is_directory);
6471 if(!NT_STATUS_IS_OK(status)) {
6472 reply_nterror(req, status);
6473 END_PROFILE(SMBcopy);
6474 return;
6475 } else {
6476 count++;
6478 } else {
6479 struct smb_Dir *dir_hnd = NULL;
6480 const char *dname = NULL;
6481 long offset = 0;
6483 if (strequal(mask,"????????.???")) {
6484 mask[0] = '*';
6485 mask[1] = '\0';
6488 status = check_name(conn, directory);
6489 if (!NT_STATUS_IS_OK(status)) {
6490 reply_nterror(req, status);
6491 END_PROFILE(SMBcopy);
6492 return;
6495 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0);
6496 if (dir_hnd == NULL) {
6497 status = map_nt_error_from_unix(errno);
6498 reply_nterror(req, status);
6499 END_PROFILE(SMBcopy);
6500 return;
6503 error = ERRbadfile;
6505 while ((dname = ReadDirName(dir_hnd, &offset))) {
6506 char *destname = NULL;
6507 char *fname = NULL;
6509 if (ISDOT(dname) || ISDOTDOT(dname)) {
6510 continue;
6513 if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
6514 continue;
6517 if(!mask_match(dname, mask, conn->case_sensitive)) {
6518 continue;
6521 error = ERRnoaccess;
6522 fname = talloc_asprintf(ctx,
6523 "%s/%s",
6524 directory,
6525 dname);
6526 if (!fname) {
6527 TALLOC_FREE(dir_hnd);
6528 reply_nterror(req, NT_STATUS_NO_MEMORY);
6529 END_PROFILE(SMBcopy);
6530 return;
6533 if (!resolve_wildcards(ctx,
6534 fname,newname,&destname)) {
6535 continue;
6537 if (!destname) {
6538 TALLOC_FREE(dir_hnd);
6539 reply_nterror(req, NT_STATUS_NO_MEMORY);
6540 END_PROFILE(SMBcopy);
6541 return;
6544 status = check_name(conn, fname);
6545 if (!NT_STATUS_IS_OK(status)) {
6546 TALLOC_FREE(dir_hnd);
6547 reply_nterror(req, status);
6548 END_PROFILE(SMBcopy);
6549 return;
6552 status = check_name(conn, destname);
6553 if (!NT_STATUS_IS_OK(status)) {
6554 TALLOC_FREE(dir_hnd);
6555 reply_nterror(req, status);
6556 END_PROFILE(SMBcopy);
6557 return;
6560 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
6562 status = copy_file(ctx,conn,fname,destname,ofun,
6563 count,target_is_directory);
6564 if (NT_STATUS_IS_OK(status)) {
6565 count++;
6567 TALLOC_FREE(fname);
6568 TALLOC_FREE(destname);
6570 TALLOC_FREE(dir_hnd);
6573 if (count == 0) {
6574 if(err) {
6575 /* Error on close... */
6576 errno = err;
6577 reply_unixerror(req, ERRHRD, ERRgeneral);
6578 END_PROFILE(SMBcopy);
6579 return;
6582 reply_doserror(req, ERRDOS, error);
6583 END_PROFILE(SMBcopy);
6584 return;
6587 reply_outbuf(req, 1, 0);
6588 SSVAL(req->outbuf,smb_vwv0,count);
6590 END_PROFILE(SMBcopy);
6591 return;
6594 #undef DBGC_CLASS
6595 #define DBGC_CLASS DBGC_LOCKING
6597 /****************************************************************************
6598 Get a lock pid, dealing with large count requests.
6599 ****************************************************************************/
6601 uint32 get_lock_pid( char *data, int data_offset, bool large_file_format)
6603 if(!large_file_format)
6604 return (uint32)SVAL(data,SMB_LPID_OFFSET(data_offset));
6605 else
6606 return (uint32)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
6609 /****************************************************************************
6610 Get a lock count, dealing with large count requests.
6611 ****************************************************************************/
6613 SMB_BIG_UINT get_lock_count( char *data, int data_offset, bool large_file_format)
6615 SMB_BIG_UINT count = 0;
6617 if(!large_file_format) {
6618 count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
6619 } else {
6621 #if defined(HAVE_LONGLONG)
6622 count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
6623 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
6624 #else /* HAVE_LONGLONG */
6627 * NT4.x seems to be broken in that it sends large file (64 bit)
6628 * lockingX calls even if the CAP_LARGE_FILES was *not*
6629 * negotiated. For boxes without large unsigned ints truncate the
6630 * lock count by dropping the top 32 bits.
6633 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
6634 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
6635 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
6636 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
6637 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
6640 count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
6641 #endif /* HAVE_LONGLONG */
6644 return count;
6647 #if !defined(HAVE_LONGLONG)
6648 /****************************************************************************
6649 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
6650 ****************************************************************************/
6652 static uint32 map_lock_offset(uint32 high, uint32 low)
6654 unsigned int i;
6655 uint32 mask = 0;
6656 uint32 highcopy = high;
6659 * Try and find out how many significant bits there are in high.
6662 for(i = 0; highcopy; i++)
6663 highcopy >>= 1;
6666 * We use 31 bits not 32 here as POSIX
6667 * lock offsets may not be negative.
6670 mask = (~0) << (31 - i);
6672 if(low & mask)
6673 return 0; /* Fail. */
6675 high <<= (31 - i);
6677 return (high|low);
6679 #endif /* !defined(HAVE_LONGLONG) */
6681 /****************************************************************************
6682 Get a lock offset, dealing with large offset requests.
6683 ****************************************************************************/
6685 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, bool large_file_format, bool *err)
6687 SMB_BIG_UINT offset = 0;
6689 *err = False;
6691 if(!large_file_format) {
6692 offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
6693 } else {
6695 #if defined(HAVE_LONGLONG)
6696 offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
6697 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
6698 #else /* HAVE_LONGLONG */
6701 * NT4.x seems to be broken in that it sends large file (64 bit)
6702 * lockingX calls even if the CAP_LARGE_FILES was *not*
6703 * negotiated. For boxes without large unsigned ints mangle the
6704 * lock offset by mapping the top 32 bits onto the lower 32.
6707 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
6708 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
6709 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
6710 uint32 new_low = 0;
6712 if((new_low = map_lock_offset(high, low)) == 0) {
6713 *err = True;
6714 return (SMB_BIG_UINT)-1;
6717 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
6718 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
6719 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
6720 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
6723 offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
6724 #endif /* HAVE_LONGLONG */
6727 return offset;
6730 /****************************************************************************
6731 Reply to a lockingX request.
6732 ****************************************************************************/
6734 void reply_lockingX(struct smb_request *req)
6736 connection_struct *conn = req->conn;
6737 files_struct *fsp;
6738 unsigned char locktype;
6739 unsigned char oplocklevel;
6740 uint16 num_ulocks;
6741 uint16 num_locks;
6742 SMB_BIG_UINT count = 0, offset = 0;
6743 uint32 lock_pid;
6744 int32 lock_timeout;
6745 int i;
6746 char *data;
6747 bool large_file_format;
6748 bool err;
6749 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
6751 START_PROFILE(SMBlockingX);
6753 if (req->wct < 8) {
6754 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6755 END_PROFILE(SMBlockingX);
6756 return;
6759 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
6760 locktype = CVAL(req->inbuf,smb_vwv3);
6761 oplocklevel = CVAL(req->inbuf,smb_vwv3+1);
6762 num_ulocks = SVAL(req->inbuf,smb_vwv6);
6763 num_locks = SVAL(req->inbuf,smb_vwv7);
6764 lock_timeout = IVAL(req->inbuf,smb_vwv4);
6765 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
6767 if (!check_fsp(conn, req, fsp)) {
6768 END_PROFILE(SMBlockingX);
6769 return;
6772 data = smb_buf(req->inbuf);
6774 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6775 /* we don't support these - and CANCEL_LOCK makes w2k
6776 and XP reboot so I don't really want to be
6777 compatible! (tridge) */
6778 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
6779 END_PROFILE(SMBlockingX);
6780 return;
6783 /* Check if this is an oplock break on a file
6784 we have granted an oplock on.
6786 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
6787 /* Client can insist on breaking to none. */
6788 bool break_to_none = (oplocklevel == 0);
6789 bool result;
6791 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
6792 "for fnum = %d\n", (unsigned int)oplocklevel,
6793 fsp->fnum ));
6796 * Make sure we have granted an exclusive or batch oplock on
6797 * this file.
6800 if (fsp->oplock_type == 0) {
6802 /* The Samba4 nbench simulator doesn't understand
6803 the difference between break to level2 and break
6804 to none from level2 - it sends oplock break
6805 replies in both cases. Don't keep logging an error
6806 message here - just ignore it. JRA. */
6808 DEBUG(5,("reply_lockingX: Error : oplock break from "
6809 "client for fnum = %d (oplock=%d) and no "
6810 "oplock granted on this file (%s).\n",
6811 fsp->fnum, fsp->oplock_type, fsp->fsp_name));
6813 /* if this is a pure oplock break request then don't
6814 * send a reply */
6815 if (num_locks == 0 && num_ulocks == 0) {
6816 END_PROFILE(SMBlockingX);
6817 return;
6818 } else {
6819 END_PROFILE(SMBlockingX);
6820 reply_doserror(req, ERRDOS, ERRlock);
6821 return;
6825 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
6826 (break_to_none)) {
6827 result = remove_oplock(fsp);
6828 } else {
6829 result = downgrade_oplock(fsp);
6832 if (!result) {
6833 DEBUG(0, ("reply_lockingX: error in removing "
6834 "oplock on file %s\n", fsp->fsp_name));
6835 /* Hmmm. Is this panic justified? */
6836 smb_panic("internal tdb error");
6839 reply_to_oplock_break_requests(fsp);
6841 /* if this is a pure oplock break request then don't send a
6842 * reply */
6843 if (num_locks == 0 && num_ulocks == 0) {
6844 /* Sanity check - ensure a pure oplock break is not a
6845 chained request. */
6846 if(CVAL(req->inbuf,smb_vwv0) != 0xff)
6847 DEBUG(0,("reply_lockingX: Error : pure oplock "
6848 "break is a chained %d request !\n",
6849 (unsigned int)CVAL(req->inbuf,
6850 smb_vwv0) ));
6851 END_PROFILE(SMBlockingX);
6852 return;
6857 * We do this check *after* we have checked this is not a oplock break
6858 * response message. JRA.
6861 release_level_2_oplocks_on_change(fsp);
6863 if (smb_buflen(req->inbuf) <
6864 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
6865 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6866 END_PROFILE(SMBlockingX);
6867 return;
6870 /* Data now points at the beginning of the list
6871 of smb_unlkrng structs */
6872 for(i = 0; i < (int)num_ulocks; i++) {
6873 lock_pid = get_lock_pid( data, i, large_file_format);
6874 count = get_lock_count( data, i, large_file_format);
6875 offset = get_lock_offset( data, i, large_file_format, &err);
6878 * There is no error code marked "stupid client bug".... :-).
6880 if(err) {
6881 END_PROFILE(SMBlockingX);
6882 reply_doserror(req, ERRDOS, ERRnoaccess);
6883 return;
6886 DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for "
6887 "pid %u, file %s\n", (double)offset, (double)count,
6888 (unsigned int)lock_pid, fsp->fsp_name ));
6890 status = do_unlock(smbd_messaging_context(),
6891 fsp,
6892 lock_pid,
6893 count,
6894 offset,
6895 WINDOWS_LOCK);
6897 if (NT_STATUS_V(status)) {
6898 END_PROFILE(SMBlockingX);
6899 reply_nterror(req, status);
6900 return;
6904 /* Setup the timeout in seconds. */
6906 if (!lp_blocking_locks(SNUM(conn))) {
6907 lock_timeout = 0;
6910 /* Now do any requested locks */
6911 data += ((large_file_format ? 20 : 10)*num_ulocks);
6913 /* Data now points at the beginning of the list
6914 of smb_lkrng structs */
6916 for(i = 0; i < (int)num_locks; i++) {
6917 enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
6918 READ_LOCK:WRITE_LOCK);
6919 lock_pid = get_lock_pid( data, i, large_file_format);
6920 count = get_lock_count( data, i, large_file_format);
6921 offset = get_lock_offset( data, i, large_file_format, &err);
6924 * There is no error code marked "stupid client bug".... :-).
6926 if(err) {
6927 END_PROFILE(SMBlockingX);
6928 reply_doserror(req, ERRDOS, ERRnoaccess);
6929 return;
6932 DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid "
6933 "%u, file %s timeout = %d\n", (double)offset,
6934 (double)count, (unsigned int)lock_pid,
6935 fsp->fsp_name, (int)lock_timeout ));
6937 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
6938 if (lp_blocking_locks(SNUM(conn))) {
6940 /* Schedule a message to ourselves to
6941 remove the blocking lock record and
6942 return the right error. */
6944 if (!blocking_lock_cancel(fsp,
6945 lock_pid,
6946 offset,
6947 count,
6948 WINDOWS_LOCK,
6949 locktype,
6950 NT_STATUS_FILE_LOCK_CONFLICT)) {
6951 END_PROFILE(SMBlockingX);
6952 reply_nterror(
6953 req,
6954 NT_STATUS_DOS(
6955 ERRDOS,
6956 ERRcancelviolation));
6957 return;
6960 /* Remove a matching pending lock. */
6961 status = do_lock_cancel(fsp,
6962 lock_pid,
6963 count,
6964 offset,
6965 WINDOWS_LOCK);
6966 } else {
6967 bool blocking_lock = lock_timeout ? True : False;
6968 bool defer_lock = False;
6969 struct byte_range_lock *br_lck;
6970 uint32 block_smbpid;
6972 br_lck = do_lock(smbd_messaging_context(),
6973 fsp,
6974 lock_pid,
6975 count,
6976 offset,
6977 lock_type,
6978 WINDOWS_LOCK,
6979 blocking_lock,
6980 &status,
6981 &block_smbpid);
6983 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6984 /* Windows internal resolution for blocking locks seems
6985 to be about 200ms... Don't wait for less than that. JRA. */
6986 if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) {
6987 lock_timeout = lp_lock_spin_time();
6989 defer_lock = True;
6992 /* This heuristic seems to match W2K3 very well. If a
6993 lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
6994 it pretends we asked for a timeout of between 150 - 300 milliseconds as
6995 far as I can tell. Replacement for do_lock_spin(). JRA. */
6997 if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
6998 NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
6999 defer_lock = True;
7000 lock_timeout = lp_lock_spin_time();
7003 if (br_lck && defer_lock) {
7005 * A blocking lock was requested. Package up
7006 * this smb into a queued request and push it
7007 * onto the blocking lock queue.
7009 if(push_blocking_lock_request(br_lck,
7010 req,
7011 fsp,
7012 lock_timeout,
7014 lock_pid,
7015 lock_type,
7016 WINDOWS_LOCK,
7017 offset,
7018 count,
7019 block_smbpid)) {
7020 TALLOC_FREE(br_lck);
7021 END_PROFILE(SMBlockingX);
7022 return;
7026 TALLOC_FREE(br_lck);
7029 if (NT_STATUS_V(status)) {
7030 END_PROFILE(SMBlockingX);
7031 reply_nterror(req, status);
7032 return;
7036 /* If any of the above locks failed, then we must unlock
7037 all of the previous locks (X/Open spec). */
7039 if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) &&
7040 (i != num_locks) &&
7041 (num_locks != 0)) {
7043 * Ensure we don't do a remove on the lock that just failed,
7044 * as under POSIX rules, if we have a lock already there, we
7045 * will delete it (and we shouldn't) .....
7047 for(i--; i >= 0; i--) {
7048 lock_pid = get_lock_pid( data, i, large_file_format);
7049 count = get_lock_count( data, i, large_file_format);
7050 offset = get_lock_offset( data, i, large_file_format,
7051 &err);
7054 * There is no error code marked "stupid client
7055 * bug".... :-).
7057 if(err) {
7058 END_PROFILE(SMBlockingX);
7059 reply_doserror(req, ERRDOS, ERRnoaccess);
7060 return;
7063 do_unlock(smbd_messaging_context(),
7064 fsp,
7065 lock_pid,
7066 count,
7067 offset,
7068 WINDOWS_LOCK);
7070 END_PROFILE(SMBlockingX);
7071 reply_nterror(req, status);
7072 return;
7075 reply_outbuf(req, 2, 0);
7077 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7078 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7080 END_PROFILE(SMBlockingX);
7081 chain_reply(req);
7084 #undef DBGC_CLASS
7085 #define DBGC_CLASS DBGC_ALL
7087 /****************************************************************************
7088 Reply to a SMBreadbmpx (read block multiplex) request.
7089 Always reply with an error, if someone has a platform really needs this,
7090 please contact vl@samba.org
7091 ****************************************************************************/
7093 void reply_readbmpx(struct smb_request *req)
7095 START_PROFILE(SMBreadBmpx);
7096 reply_doserror(req, ERRSRV, ERRuseSTD);
7097 END_PROFILE(SMBreadBmpx);
7098 return;
7101 /****************************************************************************
7102 Reply to a SMBreadbs (read block multiplex secondary) request.
7103 Always reply with an error, if someone has a platform really needs this,
7104 please contact vl@samba.org
7105 ****************************************************************************/
7107 void reply_readbs(struct smb_request *req)
7109 START_PROFILE(SMBreadBs);
7110 reply_doserror(req, ERRSRV, ERRuseSTD);
7111 END_PROFILE(SMBreadBs);
7112 return;
7115 /****************************************************************************
7116 Reply to a SMBsetattrE.
7117 ****************************************************************************/
7119 void reply_setattrE(struct smb_request *req)
7121 connection_struct *conn = req->conn;
7122 struct timespec ts[2];
7123 files_struct *fsp;
7124 SMB_STRUCT_STAT sbuf;
7125 NTSTATUS status;
7127 START_PROFILE(SMBsetattrE);
7129 if (req->wct < 7) {
7130 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7131 END_PROFILE(SMBsetattrE);
7132 return;
7135 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
7137 if(!fsp || (fsp->conn != conn)) {
7138 reply_doserror(req, ERRDOS, ERRbadfid);
7139 END_PROFILE(SMBsetattrE);
7140 return;
7145 * Convert the DOS times into unix times. Ignore create
7146 * time as UNIX can't set this.
7149 ts[0] = convert_time_t_to_timespec(
7150 srv_make_unix_date2(req->inbuf+smb_vwv3)); /* atime. */
7151 ts[1] = convert_time_t_to_timespec(
7152 srv_make_unix_date2(req->inbuf+smb_vwv5)); /* mtime. */
7154 reply_outbuf(req, 0, 0);
7157 * Patch from Ray Frush <frush@engr.colostate.edu>
7158 * Sometimes times are sent as zero - ignore them.
7161 /* Ensure we have a valid stat struct for the source. */
7162 if (fsp->fh->fd != -1) {
7163 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
7164 status = map_nt_error_from_unix(errno);
7165 reply_nterror(req, status);
7166 END_PROFILE(SMBsetattrE);
7167 return;
7169 } else {
7170 int ret = -1;
7172 if (fsp->posix_open) {
7173 ret = SMB_VFS_LSTAT(conn, fsp->fsp_name, &sbuf);
7174 } else {
7175 ret = SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf);
7177 if (ret == -1) {
7178 status = map_nt_error_from_unix(errno);
7179 reply_nterror(req, status);
7180 END_PROFILE(SMBsetattrE);
7181 return;
7185 status = smb_set_file_time(conn, fsp, fsp->fsp_name,
7186 &sbuf, ts, true);
7187 if (!NT_STATUS_IS_OK(status)) {
7188 reply_doserror(req, ERRDOS, ERRnoaccess);
7189 END_PROFILE(SMBsetattrE);
7190 return;
7193 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
7194 fsp->fnum,
7195 (unsigned int)ts[0].tv_sec,
7196 (unsigned int)ts[1].tv_sec));
7198 END_PROFILE(SMBsetattrE);
7199 return;
7203 /* Back from the dead for OS/2..... JRA. */
7205 /****************************************************************************
7206 Reply to a SMBwritebmpx (write block multiplex primary) request.
7207 Always reply with an error, if someone has a platform really needs this,
7208 please contact vl@samba.org
7209 ****************************************************************************/
7211 void reply_writebmpx(struct smb_request *req)
7213 START_PROFILE(SMBwriteBmpx);
7214 reply_doserror(req, ERRSRV, ERRuseSTD);
7215 END_PROFILE(SMBwriteBmpx);
7216 return;
7219 /****************************************************************************
7220 Reply to a SMBwritebs (write block multiplex secondary) request.
7221 Always reply with an error, if someone has a platform really needs this,
7222 please contact vl@samba.org
7223 ****************************************************************************/
7225 void reply_writebs(struct smb_request *req)
7227 START_PROFILE(SMBwriteBs);
7228 reply_doserror(req, ERRSRV, ERRuseSTD);
7229 END_PROFILE(SMBwriteBs);
7230 return;
7233 /****************************************************************************
7234 Reply to a SMBgetattrE.
7235 ****************************************************************************/
7237 void reply_getattrE(struct smb_request *req)
7239 connection_struct *conn = req->conn;
7240 SMB_STRUCT_STAT sbuf;
7241 int mode;
7242 files_struct *fsp;
7243 struct timespec create_ts;
7245 START_PROFILE(SMBgetattrE);
7247 if (req->wct < 1) {
7248 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7249 END_PROFILE(SMBgetattrE);
7250 return;
7253 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
7255 if(!fsp || (fsp->conn != conn)) {
7256 reply_doserror(req, ERRDOS, ERRbadfid);
7257 END_PROFILE(SMBgetattrE);
7258 return;
7261 /* Do an fstat on this file */
7262 if(fsp_stat(fsp, &sbuf)) {
7263 reply_unixerror(req, ERRDOS, ERRnoaccess);
7264 END_PROFILE(SMBgetattrE);
7265 return;
7268 mode = dos_mode(conn,fsp->fsp_name,&sbuf);
7271 * Convert the times into dos times. Set create
7272 * date to be last modify date as UNIX doesn't save
7273 * this.
7276 reply_outbuf(req, 11, 0);
7278 create_ts = get_create_timespec(&sbuf,
7279 lp_fake_dir_create_times(SNUM(conn)));
7280 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7281 srv_put_dos_date2((char *)req->outbuf, smb_vwv2, sbuf.st_atime);
7282 /* Should we check pending modtime here ? JRA */
7283 srv_put_dos_date2((char *)req->outbuf, smb_vwv4, sbuf.st_mtime);
7285 if (mode & aDIR) {
7286 SIVAL(req->outbuf, smb_vwv6, 0);
7287 SIVAL(req->outbuf, smb_vwv8, 0);
7288 } else {
7289 uint32 allocation_size = get_allocation_size(conn,fsp, &sbuf);
7290 SIVAL(req->outbuf, smb_vwv6, (uint32)sbuf.st_size);
7291 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7293 SSVAL(req->outbuf,smb_vwv10, mode);
7295 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7297 END_PROFILE(SMBgetattrE);
7298 return;