Fix bug #6196 - Unable to serve files with colons to Linux CIFS/VFS client
[Samba.git] / source / smbd / reply.c
bloba374b65d55d263178795f799777c877091f1ce6a
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 unsigned int smb_echo_count = 0;
33 extern uint32 global_client_caps;
35 extern struct current_user current_user;
36 extern bool global_encrypted_passwords_negotiated;
38 /****************************************************************************
39 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
40 path or anything including wildcards.
41 We're assuming here that '/' is not the second byte in any multibyte char
42 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
43 set.
44 ****************************************************************************/
46 /* Custom version for processing POSIX paths. */
47 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
49 static NTSTATUS check_path_syntax_internal(char *path,
50 bool posix_path,
51 bool *p_last_component_contains_wcard)
53 char *d = path;
54 const char *s = path;
55 NTSTATUS ret = NT_STATUS_OK;
56 bool start_of_name_component = True;
57 bool stream_started = false;
59 *p_last_component_contains_wcard = False;
61 while (*s) {
62 if (stream_started) {
63 switch (*s) {
64 case '/':
65 case '\\':
66 return NT_STATUS_OBJECT_NAME_INVALID;
67 case ':':
68 if (s[1] == '\0') {
69 return NT_STATUS_OBJECT_NAME_INVALID;
71 if (strchr_m(&s[1], ':')) {
72 return NT_STATUS_OBJECT_NAME_INVALID;
74 if (StrCaseCmp(s, ":$DATA") != 0) {
75 return NT_STATUS_INVALID_PARAMETER;
77 break;
81 if (!posix_path && !stream_started && *s == ':') {
82 if (*p_last_component_contains_wcard) {
83 return NT_STATUS_OBJECT_NAME_INVALID;
85 /* Stream names allow more characters than file names.
86 We're overloading posix_path here to allow a wider
87 range of characters. If stream_started is true this
88 is still a Windows path even if posix_path is true.
89 JRA.
91 stream_started = true;
92 start_of_name_component = false;
93 posix_path = true;
95 if (s[1] == '\0') {
96 return NT_STATUS_OBJECT_NAME_INVALID;
100 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
102 * Safe to assume is not the second part of a mb char
103 * as this is handled below.
105 /* Eat multiple '/' or '\\' */
106 while (IS_PATH_SEP(*s,posix_path)) {
107 s++;
109 if ((d != path) && (*s != '\0')) {
110 /* We only care about non-leading or trailing '/' or '\\' */
111 *d++ = '/';
114 start_of_name_component = True;
115 /* New component. */
116 *p_last_component_contains_wcard = False;
117 continue;
120 if (start_of_name_component) {
121 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
122 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
125 * No mb char starts with '.' so we're safe checking the directory separator here.
128 /* If we just added a '/' - delete it */
129 if ((d > path) && (*(d-1) == '/')) {
130 *(d-1) = '\0';
131 d--;
134 /* Are we at the start ? Can't go back further if so. */
135 if (d <= path) {
136 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
137 break;
139 /* Go back one level... */
140 /* We know this is safe as '/' cannot be part of a mb sequence. */
141 /* NOTE - if this assumption is invalid we are not in good shape... */
142 /* Decrement d first as d points to the *next* char to write into. */
143 for (d--; d > path; d--) {
144 if (*d == '/')
145 break;
147 s += 2; /* Else go past the .. */
148 /* We're still at the start of a name component, just the previous one. */
149 continue;
151 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
152 if (posix_path) {
153 /* Eat the '.' */
154 s++;
155 continue;
161 if (!(*s & 0x80)) {
162 if (!posix_path) {
163 if (*s <= 0x1f || *s == '|') {
164 return NT_STATUS_OBJECT_NAME_INVALID;
166 switch (*s) {
167 case '*':
168 case '?':
169 case '<':
170 case '>':
171 case '"':
172 *p_last_component_contains_wcard = True;
173 break;
174 default:
175 break;
178 *d++ = *s++;
179 } else {
180 size_t siz;
181 /* Get the size of the next MB character. */
182 next_codepoint(s,&siz);
183 switch(siz) {
184 case 5:
185 *d++ = *s++;
186 /*fall through*/
187 case 4:
188 *d++ = *s++;
189 /*fall through*/
190 case 3:
191 *d++ = *s++;
192 /*fall through*/
193 case 2:
194 *d++ = *s++;
195 /*fall through*/
196 case 1:
197 *d++ = *s++;
198 break;
199 default:
200 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
201 *d = '\0';
202 return NT_STATUS_INVALID_PARAMETER;
205 start_of_name_component = False;
208 *d = '\0';
210 return ret;
213 /****************************************************************************
214 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
215 No wildcards allowed.
216 ****************************************************************************/
218 NTSTATUS check_path_syntax(char *path)
220 bool ignore;
221 return check_path_syntax_internal(path, False, &ignore);
224 /****************************************************************************
225 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
226 Wildcards allowed - p_contains_wcard returns true if the last component contained
227 a wildcard.
228 ****************************************************************************/
230 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
232 return check_path_syntax_internal(path, False, p_contains_wcard);
235 /****************************************************************************
236 Check the path for a POSIX client.
237 We're assuming here that '/' is not the second byte in any multibyte char
238 set (a safe assumption).
239 ****************************************************************************/
241 NTSTATUS check_path_syntax_posix(char *path)
243 bool ignore;
244 return check_path_syntax_internal(path, True, &ignore);
247 /****************************************************************************
248 Pull a string and check the path allowing a wilcard - provide for error return.
249 ****************************************************************************/
251 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
252 const char *inbuf,
253 uint16 smb_flags2,
254 char **pp_dest,
255 const char *src,
256 size_t src_len,
257 int flags,
258 NTSTATUS *err,
259 bool *contains_wcard)
261 size_t ret;
263 *pp_dest = NULL;
265 if (src_len == 0) {
266 ret = srvstr_pull_buf_talloc(ctx,
267 inbuf,
268 smb_flags2,
269 pp_dest,
270 src,
271 flags);
272 } else {
273 ret = srvstr_pull_talloc(ctx,
274 inbuf,
275 smb_flags2,
276 pp_dest,
277 src,
278 src_len,
279 flags);
282 if (!*pp_dest) {
283 *err = NT_STATUS_INVALID_PARAMETER;
284 return ret;
287 *contains_wcard = False;
289 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
291 * For a DFS path the function parse_dfs_path()
292 * will do the path processing, just make a copy.
294 *err = NT_STATUS_OK;
295 return ret;
298 if (lp_posix_pathnames()) {
299 *err = check_path_syntax_posix(*pp_dest);
300 } else {
301 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
304 return ret;
307 /****************************************************************************
308 Pull a string and check the path - provide for error return.
309 ****************************************************************************/
311 size_t srvstr_get_path(TALLOC_CTX *ctx,
312 const char *inbuf,
313 uint16 smb_flags2,
314 char **pp_dest,
315 const char *src,
316 size_t src_len,
317 int flags,
318 NTSTATUS *err)
320 size_t ret;
322 *pp_dest = NULL;
324 if (src_len == 0) {
325 ret = srvstr_pull_buf_talloc(ctx,
326 inbuf,
327 smb_flags2,
328 pp_dest,
329 src,
330 flags);
331 } else {
332 ret = srvstr_pull_talloc(ctx,
333 inbuf,
334 smb_flags2,
335 pp_dest,
336 src,
337 src_len,
338 flags);
341 if (!*pp_dest) {
342 *err = NT_STATUS_INVALID_PARAMETER;
343 return ret;
346 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
348 * For a DFS path the function parse_dfs_path()
349 * will do the path processing, just make a copy.
351 *err = NT_STATUS_OK;
352 return ret;
355 if (lp_posix_pathnames()) {
356 *err = check_path_syntax_posix(*pp_dest);
357 } else {
358 *err = check_path_syntax(*pp_dest);
361 return ret;
364 /****************************************************************************
365 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
366 ****************************************************************************/
368 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
369 files_struct *fsp, struct current_user *user)
371 if (!(fsp) || !(conn)) {
372 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
373 return False;
375 if (((conn) != (fsp)->conn) || user->vuid != (fsp)->vuid) {
376 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
377 return False;
379 return True;
382 /****************************************************************************
383 Check if we have a correct fsp pointing to a file. Replacement for the
384 CHECK_FSP macro.
385 ****************************************************************************/
387 bool check_fsp(connection_struct *conn, struct smb_request *req,
388 files_struct *fsp, struct current_user *user)
390 if (!check_fsp_open(conn, req, fsp, user)) {
391 return False;
393 if ((fsp)->is_directory) {
394 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
395 return False;
397 if ((fsp)->fh->fd == -1) {
398 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
399 return False;
401 (fsp)->num_smb_operations++;
402 return True;
405 /****************************************************************************
406 Check if we have a correct fsp. Replacement for the FSP_BELONGS_CONN macro
407 ****************************************************************************/
409 bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req,
410 files_struct *fsp, struct current_user *user)
412 if ((fsp) && (conn) && ((conn)==(fsp)->conn)
413 && (current_user.vuid==(fsp)->vuid)) {
414 return True;
417 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
418 return False;
421 /****************************************************************************
422 Reply to a (netbios-level) special message.
423 ****************************************************************************/
425 void reply_special(char *inbuf)
427 int msg_type = CVAL(inbuf,0);
428 int msg_flags = CVAL(inbuf,1);
429 fstring name1,name2;
430 char name_type = 0;
433 * We only really use 4 bytes of the outbuf, but for the smb_setlen
434 * calculation & friends (srv_send_smb uses that) we need the full smb
435 * header.
437 char outbuf[smb_size];
439 static bool already_got_session = False;
441 *name1 = *name2 = 0;
443 memset(outbuf, '\0', sizeof(outbuf));
445 smb_setlen(outbuf,0);
447 switch (msg_type) {
448 case 0x81: /* session request */
450 if (already_got_session) {
451 exit_server_cleanly("multiple session request not permitted");
454 SCVAL(outbuf,0,0x82);
455 SCVAL(outbuf,3,0);
456 if (name_len(inbuf+4) > 50 ||
457 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
458 DEBUG(0,("Invalid name length in session request\n"));
459 return;
461 name_extract(inbuf,4,name1);
462 name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
463 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
464 name1,name2));
466 set_local_machine_name(name1, True);
467 set_remote_machine_name(name2, True);
469 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
470 get_local_machine_name(), get_remote_machine_name(),
471 name_type));
473 if (name_type == 'R') {
474 /* We are being asked for a pathworks session ---
475 no thanks! */
476 SCVAL(outbuf, 0,0x83);
477 break;
480 /* only add the client's machine name to the list
481 of possibly valid usernames if we are operating
482 in share mode security */
483 if (lp_security() == SEC_SHARE) {
484 add_session_user(get_remote_machine_name());
487 reload_services(True);
488 reopen_logs();
490 already_got_session = True;
491 break;
493 case 0x89: /* session keepalive request
494 (some old clients produce this?) */
495 SCVAL(outbuf,0,SMBkeepalive);
496 SCVAL(outbuf,3,0);
497 break;
499 case 0x82: /* positive session response */
500 case 0x83: /* negative session response */
501 case 0x84: /* retarget session response */
502 DEBUG(0,("Unexpected session response\n"));
503 break;
505 case SMBkeepalive: /* session keepalive */
506 default:
507 return;
510 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
511 msg_type, msg_flags));
513 srv_send_smb(smbd_server_fd(), outbuf, false);
514 return;
517 /****************************************************************************
518 Reply to a tcon.
519 conn POINTER CAN BE NULL HERE !
520 ****************************************************************************/
522 void reply_tcon(struct smb_request *req)
524 connection_struct *conn = req->conn;
525 const char *service;
526 char *service_buf = NULL;
527 char *password = NULL;
528 char *dev = NULL;
529 int pwlen=0;
530 NTSTATUS nt_status;
531 char *p;
532 DATA_BLOB password_blob;
533 TALLOC_CTX *ctx = talloc_tos();
535 START_PROFILE(SMBtcon);
537 if (smb_buflen(req->inbuf) < 4) {
538 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
539 END_PROFILE(SMBtcon);
540 return;
543 p = smb_buf(req->inbuf)+1;
544 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
545 &service_buf, p, STR_TERMINATE) + 1;
546 pwlen = srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
547 &password, p, STR_TERMINATE) + 1;
548 p += pwlen;
549 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
550 &dev, p, STR_TERMINATE) + 1;
552 if (service_buf == NULL || password == NULL || dev == NULL) {
553 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
554 END_PROFILE(SMBtcon);
555 return;
557 p = strrchr_m(service_buf,'\\');
558 if (p) {
559 service = p+1;
560 } else {
561 service = service_buf;
564 password_blob = data_blob(password, pwlen+1);
566 conn = make_connection(service,password_blob,dev,req->vuid,&nt_status);
567 req->conn = conn;
569 data_blob_clear_free(&password_blob);
571 if (!conn) {
572 reply_nterror(req, nt_status);
573 END_PROFILE(SMBtcon);
574 return;
577 reply_outbuf(req, 2, 0);
578 SSVAL(req->outbuf,smb_vwv0,max_recv);
579 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
580 SSVAL(req->outbuf,smb_tid,conn->cnum);
582 DEBUG(3,("tcon service=%s cnum=%d\n",
583 service, conn->cnum));
585 END_PROFILE(SMBtcon);
586 return;
589 /****************************************************************************
590 Reply to a tcon and X.
591 conn POINTER CAN BE NULL HERE !
592 ****************************************************************************/
594 void reply_tcon_and_X(struct smb_request *req)
596 connection_struct *conn = req->conn;
597 char *service = NULL;
598 DATA_BLOB password;
599 TALLOC_CTX *ctx = talloc_tos();
600 /* what the cleint thinks the device is */
601 char *client_devicetype = NULL;
602 /* what the server tells the client the share represents */
603 const char *server_devicetype;
604 NTSTATUS nt_status;
605 int passlen;
606 char *path = NULL;
607 char *p, *q;
608 uint16 tcon_flags;
610 START_PROFILE(SMBtconX);
612 if (req->wct < 4) {
613 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
614 END_PROFILE(SMBtconX);
615 return;
618 passlen = SVAL(req->inbuf,smb_vwv3);
619 tcon_flags = SVAL(req->inbuf,smb_vwv2);
621 /* we might have to close an old one */
622 if ((tcon_flags & 0x1) && conn) {
623 close_cnum(conn,req->vuid);
624 req->conn = NULL;
625 conn = NULL;
628 if ((passlen > MAX_PASS_LEN) || (passlen >= smb_buflen(req->inbuf))) {
629 reply_doserror(req, ERRDOS, ERRbuftoosmall);
630 END_PROFILE(SMBtconX);
631 return;
634 if (global_encrypted_passwords_negotiated) {
635 password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
636 passlen);
637 if (lp_security() == SEC_SHARE) {
639 * Security = share always has a pad byte
640 * after the password.
642 p = smb_buf(req->inbuf) + passlen + 1;
643 } else {
644 p = smb_buf(req->inbuf) + passlen;
646 } else {
647 password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
648 passlen+1);
649 /* Ensure correct termination */
650 password.data[passlen]=0;
651 p = smb_buf(req->inbuf) + passlen + 1;
654 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2, &path, p,
655 STR_TERMINATE);
657 if (path == NULL) {
658 data_blob_clear_free(&password);
659 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
660 END_PROFILE(SMBtconX);
661 return;
665 * the service name can be either: \\server\share
666 * or share directly like on the DELL PowerVault 705
668 if (*path=='\\') {
669 q = strchr_m(path+2,'\\');
670 if (!q) {
671 data_blob_clear_free(&password);
672 reply_doserror(req, ERRDOS, ERRnosuchshare);
673 END_PROFILE(SMBtconX);
674 return;
676 service = q+1;
677 } else {
678 service = path;
681 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
682 &client_devicetype, p,
683 MIN(6,smb_bufrem(req->inbuf, p)), STR_ASCII);
685 if (client_devicetype == NULL) {
686 data_blob_clear_free(&password);
687 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
688 END_PROFILE(SMBtconX);
689 return;
692 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
694 conn = make_connection(service, password, client_devicetype,
695 req->vuid, &nt_status);
696 req->conn =conn;
698 data_blob_clear_free(&password);
700 if (!conn) {
701 reply_nterror(req, nt_status);
702 END_PROFILE(SMBtconX);
703 return;
706 if ( IS_IPC(conn) )
707 server_devicetype = "IPC";
708 else if ( IS_PRINT(conn) )
709 server_devicetype = "LPT1:";
710 else
711 server_devicetype = "A:";
713 if (Protocol < PROTOCOL_NT1) {
714 reply_outbuf(req, 2, 0);
715 if (message_push_string(&req->outbuf, server_devicetype,
716 STR_TERMINATE|STR_ASCII) == -1) {
717 reply_nterror(req, NT_STATUS_NO_MEMORY);
718 END_PROFILE(SMBtconX);
719 return;
721 } else {
722 /* NT sets the fstype of IPC$ to the null string */
723 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
725 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
726 /* Return permissions. */
727 uint32 perm1 = 0;
728 uint32 perm2 = 0;
730 reply_outbuf(req, 7, 0);
732 if (IS_IPC(conn)) {
733 perm1 = FILE_ALL_ACCESS;
734 perm2 = FILE_ALL_ACCESS;
735 } else {
736 perm1 = CAN_WRITE(conn) ?
737 SHARE_ALL_ACCESS :
738 SHARE_READ_ONLY;
741 SIVAL(req->outbuf, smb_vwv3, perm1);
742 SIVAL(req->outbuf, smb_vwv5, perm2);
743 } else {
744 reply_outbuf(req, 3, 0);
747 if ((message_push_string(&req->outbuf, server_devicetype,
748 STR_TERMINATE|STR_ASCII) == -1)
749 || (message_push_string(&req->outbuf, fstype,
750 STR_TERMINATE) == -1)) {
751 reply_nterror(req, NT_STATUS_NO_MEMORY);
752 END_PROFILE(SMBtconX);
753 return;
756 /* what does setting this bit do? It is set by NT4 and
757 may affect the ability to autorun mounted cdroms */
758 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
759 (lp_csc_policy(SNUM(conn)) << 2));
761 init_dfsroot(conn, req->inbuf, req->outbuf);
765 DEBUG(3,("tconX service=%s \n",
766 service));
768 /* set the incoming and outgoing tid to the just created one */
769 SSVAL(req->inbuf,smb_tid,conn->cnum);
770 SSVAL(req->outbuf,smb_tid,conn->cnum);
772 END_PROFILE(SMBtconX);
774 chain_reply(req);
775 return;
778 /****************************************************************************
779 Reply to an unknown type.
780 ****************************************************************************/
782 void reply_unknown_new(struct smb_request *req, uint8 type)
784 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
785 smb_fn_name(type), type, type));
786 reply_doserror(req, ERRSRV, ERRunknownsmb);
787 return;
790 /****************************************************************************
791 Reply to an ioctl.
792 conn POINTER CAN BE NULL HERE !
793 ****************************************************************************/
795 void reply_ioctl(struct smb_request *req)
797 connection_struct *conn = req->conn;
798 uint16 device;
799 uint16 function;
800 uint32 ioctl_code;
801 int replysize;
802 char *p;
804 START_PROFILE(SMBioctl);
806 if (req->wct < 3) {
807 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
808 END_PROFILE(SMBioctl);
809 return;
812 device = SVAL(req->inbuf,smb_vwv1);
813 function = SVAL(req->inbuf,smb_vwv2);
814 ioctl_code = (device << 16) + function;
816 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
818 switch (ioctl_code) {
819 case IOCTL_QUERY_JOB_INFO:
820 replysize = 32;
821 break;
822 default:
823 reply_doserror(req, ERRSRV, ERRnosupport);
824 END_PROFILE(SMBioctl);
825 return;
828 reply_outbuf(req, 8, replysize+1);
829 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
830 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
831 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
832 p = smb_buf(req->outbuf);
833 memset(p, '\0', replysize+1); /* valgrind-safe. */
834 p += 1; /* Allow for alignment */
836 switch (ioctl_code) {
837 case IOCTL_QUERY_JOB_INFO:
839 files_struct *fsp = file_fsp(SVAL(req->inbuf,
840 smb_vwv0));
841 if (!fsp) {
842 reply_doserror(req, ERRDOS, ERRbadfid);
843 END_PROFILE(SMBioctl);
844 return;
846 SSVAL(p,0,fsp->rap_print_jobid); /* Job number */
847 srvstr_push((char *)req->outbuf, req->flags2, p+2,
848 global_myname(), 15,
849 STR_TERMINATE|STR_ASCII);
850 if (conn) {
851 srvstr_push((char *)req->outbuf, req->flags2,
852 p+18, lp_servicename(SNUM(conn)),
853 13, STR_TERMINATE|STR_ASCII);
854 } else {
855 memset(p+18, 0, 13);
857 break;
861 END_PROFILE(SMBioctl);
862 return;
865 /****************************************************************************
866 Strange checkpath NTSTATUS mapping.
867 ****************************************************************************/
869 static NTSTATUS map_checkpath_error(const char *inbuf, NTSTATUS status)
871 /* Strange DOS error code semantics only for checkpath... */
872 if (!(SVAL(inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) {
873 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
874 /* We need to map to ERRbadpath */
875 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
878 return status;
881 /****************************************************************************
882 Reply to a checkpath.
883 ****************************************************************************/
885 void reply_checkpath(struct smb_request *req)
887 connection_struct *conn = req->conn;
888 char *name = NULL;
889 SMB_STRUCT_STAT sbuf;
890 NTSTATUS status;
891 TALLOC_CTX *ctx = talloc_tos();
893 START_PROFILE(SMBcheckpath);
895 srvstr_get_path(ctx,(char *)req->inbuf, req->flags2, &name,
896 smb_buf(req->inbuf) + 1, 0,
897 STR_TERMINATE, &status);
898 if (!NT_STATUS_IS_OK(status)) {
899 status = map_checkpath_error((char *)req->inbuf, status);
900 reply_nterror(req, status);
901 END_PROFILE(SMBcheckpath);
902 return;
905 status = resolve_dfspath(ctx, conn,
906 req->flags2 & FLAGS2_DFS_PATHNAMES,
907 name,
908 &name);
909 if (!NT_STATUS_IS_OK(status)) {
910 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
911 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
912 ERRSRV, ERRbadpath);
913 END_PROFILE(SMBcheckpath);
914 return;
916 goto path_err;
919 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->inbuf,smb_vwv0)));
921 status = unix_convert(ctx, conn, name, False, &name, NULL, &sbuf);
922 if (!NT_STATUS_IS_OK(status)) {
923 goto path_err;
926 status = check_name(conn, name);
927 if (!NT_STATUS_IS_OK(status)) {
928 DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status)));
929 goto path_err;
932 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) {
933 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno)));
934 status = map_nt_error_from_unix(errno);
935 goto path_err;
938 if (!S_ISDIR(sbuf.st_mode)) {
939 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
940 ERRDOS, ERRbadpath);
941 END_PROFILE(SMBcheckpath);
942 return;
945 reply_outbuf(req, 0, 0);
947 END_PROFILE(SMBcheckpath);
948 return;
950 path_err:
952 END_PROFILE(SMBcheckpath);
954 /* We special case this - as when a Windows machine
955 is parsing a path is steps through the components
956 one at a time - if a component fails it expects
957 ERRbadpath, not ERRbadfile.
959 status = map_checkpath_error((char *)req->inbuf, status);
960 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
962 * Windows returns different error codes if
963 * the parent directory is valid but not the
964 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
965 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
966 * if the path is invalid.
968 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
969 ERRDOS, ERRbadpath);
970 return;
973 reply_nterror(req, status);
976 /****************************************************************************
977 Reply to a getatr.
978 ****************************************************************************/
980 void reply_getatr(struct smb_request *req)
982 connection_struct *conn = req->conn;
983 char *fname = NULL;
984 SMB_STRUCT_STAT sbuf;
985 int mode=0;
986 SMB_OFF_T size=0;
987 time_t mtime=0;
988 char *p;
989 NTSTATUS status;
990 TALLOC_CTX *ctx = talloc_tos();
992 START_PROFILE(SMBgetatr);
994 p = smb_buf(req->inbuf) + 1;
995 p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
996 0, STR_TERMINATE, &status);
997 if (!NT_STATUS_IS_OK(status)) {
998 reply_nterror(req, status);
999 END_PROFILE(SMBgetatr);
1000 return;
1003 status = resolve_dfspath(ctx, conn,
1004 req->flags2 & FLAGS2_DFS_PATHNAMES,
1005 fname,
1006 &fname);
1007 if (!NT_STATUS_IS_OK(status)) {
1008 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1009 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1010 ERRSRV, ERRbadpath);
1011 END_PROFILE(SMBgetatr);
1012 return;
1014 reply_nterror(req, status);
1015 END_PROFILE(SMBgetatr);
1016 return;
1019 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1020 under WfWg - weird! */
1021 if (*fname == '\0') {
1022 mode = aHIDDEN | aDIR;
1023 if (!CAN_WRITE(conn)) {
1024 mode |= aRONLY;
1026 size = 0;
1027 mtime = 0;
1028 } else {
1029 status = unix_convert(ctx, conn, fname, False, &fname, NULL,&sbuf);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 reply_nterror(req, status);
1032 END_PROFILE(SMBgetatr);
1033 return;
1035 status = check_name(conn, fname);
1036 if (!NT_STATUS_IS_OK(status)) {
1037 DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status)));
1038 reply_nterror(req, status);
1039 END_PROFILE(SMBgetatr);
1040 return;
1042 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) {
1043 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
1044 reply_unixerror(req, ERRDOS,ERRbadfile);
1045 END_PROFILE(SMBgetatr);
1046 return;
1049 mode = dos_mode(conn,fname,&sbuf);
1050 size = sbuf.st_size;
1051 mtime = sbuf.st_mtime;
1052 if (mode & aDIR) {
1053 size = 0;
1057 reply_outbuf(req, 10, 0);
1059 SSVAL(req->outbuf,smb_vwv0,mode);
1060 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1061 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1062 } else {
1063 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1065 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1067 if (Protocol >= PROTOCOL_NT1) {
1068 SSVAL(req->outbuf, smb_flg2,
1069 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1072 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) );
1074 END_PROFILE(SMBgetatr);
1075 return;
1078 /****************************************************************************
1079 Reply to a setatr.
1080 ****************************************************************************/
1082 void reply_setatr(struct smb_request *req)
1084 struct timespec ts[2];
1085 connection_struct *conn = req->conn;
1086 char *fname = NULL;
1087 int mode;
1088 time_t mtime;
1089 SMB_STRUCT_STAT sbuf;
1090 char *p;
1091 NTSTATUS status;
1092 TALLOC_CTX *ctx = talloc_tos();
1094 START_PROFILE(SMBsetatr);
1096 ZERO_STRUCT(ts);
1098 if (req->wct < 2) {
1099 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1100 return;
1103 p = smb_buf(req->inbuf) + 1;
1104 p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
1105 0, STR_TERMINATE, &status);
1106 if (!NT_STATUS_IS_OK(status)) {
1107 reply_nterror(req, status);
1108 END_PROFILE(SMBsetatr);
1109 return;
1112 status = resolve_dfspath(ctx, conn,
1113 req->flags2 & FLAGS2_DFS_PATHNAMES,
1114 fname,
1115 &fname);
1116 if (!NT_STATUS_IS_OK(status)) {
1117 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1118 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1119 ERRSRV, ERRbadpath);
1120 END_PROFILE(SMBsetatr);
1121 return;
1123 reply_nterror(req, status);
1124 END_PROFILE(SMBsetatr);
1125 return;
1128 status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
1129 if (!NT_STATUS_IS_OK(status)) {
1130 reply_nterror(req, status);
1131 END_PROFILE(SMBsetatr);
1132 return;
1135 status = check_name(conn, fname);
1136 if (!NT_STATUS_IS_OK(status)) {
1137 reply_nterror(req, status);
1138 END_PROFILE(SMBsetatr);
1139 return;
1142 if (fname[0] == '.' && fname[1] == '\0') {
1144 * Not sure here is the right place to catch this
1145 * condition. Might be moved to somewhere else later -- vl
1147 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1148 END_PROFILE(SMBsetatr);
1149 return;
1152 mode = SVAL(req->inbuf,smb_vwv0);
1153 mtime = srv_make_unix_date3(req->inbuf+smb_vwv1);
1155 ts[1] = convert_time_t_to_timespec(mtime);
1156 status = smb_set_file_time(conn, NULL, fname,
1157 &sbuf, ts, true);
1158 if (!NT_STATUS_IS_OK(status)) {
1159 reply_unixerror(req, ERRDOS, ERRnoaccess);
1160 END_PROFILE(SMBsetatr);
1161 return;
1164 if (mode != FILE_ATTRIBUTE_NORMAL) {
1165 if (VALID_STAT_OF_DIR(sbuf))
1166 mode |= aDIR;
1167 else
1168 mode &= ~aDIR;
1170 if (file_set_dosmode(conn,fname,mode,&sbuf,NULL,false) != 0) {
1171 reply_unixerror(req, ERRDOS, ERRnoaccess);
1172 END_PROFILE(SMBsetatr);
1173 return;
1177 reply_outbuf(req, 0, 0);
1179 DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
1181 END_PROFILE(SMBsetatr);
1182 return;
1185 /****************************************************************************
1186 Reply to a dskattr.
1187 ****************************************************************************/
1189 void reply_dskattr(struct smb_request *req)
1191 connection_struct *conn = req->conn;
1192 SMB_BIG_UINT dfree,dsize,bsize;
1193 START_PROFILE(SMBdskattr);
1195 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
1196 reply_unixerror(req, ERRHRD, ERRgeneral);
1197 END_PROFILE(SMBdskattr);
1198 return;
1201 reply_outbuf(req, 5, 0);
1203 if (Protocol <= PROTOCOL_LANMAN2) {
1204 double total_space, free_space;
1205 /* we need to scale this to a number that DOS6 can handle. We
1206 use floating point so we can handle large drives on systems
1207 that don't have 64 bit integers
1209 we end up displaying a maximum of 2G to DOS systems
1211 total_space = dsize * (double)bsize;
1212 free_space = dfree * (double)bsize;
1214 dsize = (SMB_BIG_UINT)((total_space+63*512) / (64*512));
1215 dfree = (SMB_BIG_UINT)((free_space+63*512) / (64*512));
1217 if (dsize > 0xFFFF) dsize = 0xFFFF;
1218 if (dfree > 0xFFFF) dfree = 0xFFFF;
1220 SSVAL(req->outbuf,smb_vwv0,dsize);
1221 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1222 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1223 SSVAL(req->outbuf,smb_vwv3,dfree);
1224 } else {
1225 SSVAL(req->outbuf,smb_vwv0,dsize);
1226 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1227 SSVAL(req->outbuf,smb_vwv2,512);
1228 SSVAL(req->outbuf,smb_vwv3,dfree);
1231 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1233 END_PROFILE(SMBdskattr);
1234 return;
1237 /****************************************************************************
1238 Reply to a search.
1239 Can be called from SMBsearch, SMBffirst or SMBfunique.
1240 ****************************************************************************/
1242 void reply_search(struct smb_request *req)
1244 connection_struct *conn = req->conn;
1245 char *mask = NULL;
1246 char *directory = NULL;
1247 char *fname = NULL;
1248 SMB_OFF_T size;
1249 uint32 mode;
1250 time_t date;
1251 uint32 dirtype;
1252 unsigned int numentries = 0;
1253 unsigned int maxentries = 0;
1254 bool finished = False;
1255 char *p;
1256 int status_len;
1257 char *path = NULL;
1258 char status[21];
1259 int dptr_num= -1;
1260 bool check_descend = False;
1261 bool expect_close = False;
1262 NTSTATUS nt_status;
1263 bool mask_contains_wcard = False;
1264 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1265 TALLOC_CTX *ctx = talloc_tos();
1266 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1268 START_PROFILE(SMBsearch);
1270 if (req->wct < 2) {
1271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1272 END_PROFILE(SMBsearch);
1273 return;
1276 if (lp_posix_pathnames()) {
1277 reply_unknown_new(req, CVAL(req->inbuf, smb_com));
1278 END_PROFILE(SMBsearch);
1279 return;
1282 /* If we were called as SMBffirst then we must expect close. */
1283 if(CVAL(req->inbuf,smb_com) == SMBffirst) {
1284 expect_close = True;
1287 reply_outbuf(req, 1, 3);
1288 maxentries = SVAL(req->inbuf,smb_vwv0);
1289 dirtype = SVAL(req->inbuf,smb_vwv1);
1290 p = smb_buf(req->inbuf) + 1;
1291 p += srvstr_get_path_wcard(ctx,
1292 (char *)req->inbuf,
1293 req->flags2,
1294 &path,
1297 STR_TERMINATE,
1298 &nt_status,
1299 &mask_contains_wcard);
1300 if (!NT_STATUS_IS_OK(nt_status)) {
1301 reply_nterror(req, nt_status);
1302 END_PROFILE(SMBsearch);
1303 return;
1306 nt_status = resolve_dfspath_wcard(ctx, conn,
1307 req->flags2 & FLAGS2_DFS_PATHNAMES,
1308 path,
1309 &path,
1310 &mask_contains_wcard);
1311 if (!NT_STATUS_IS_OK(nt_status)) {
1312 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1313 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1314 ERRSRV, ERRbadpath);
1315 END_PROFILE(SMBsearch);
1316 return;
1318 reply_nterror(req, nt_status);
1319 END_PROFILE(SMBsearch);
1320 return;
1323 p++;
1324 status_len = SVAL(p, 0);
1325 p += 2;
1327 /* dirtype &= ~aDIR; */
1329 if (status_len == 0) {
1330 SMB_STRUCT_STAT sbuf;
1332 nt_status = unix_convert(ctx, conn, path, True,
1333 &directory, NULL, &sbuf);
1334 if (!NT_STATUS_IS_OK(nt_status)) {
1335 reply_nterror(req, nt_status);
1336 END_PROFILE(SMBsearch);
1337 return;
1340 nt_status = check_name(conn, directory);
1341 if (!NT_STATUS_IS_OK(nt_status)) {
1342 reply_nterror(req, nt_status);
1343 END_PROFILE(SMBsearch);
1344 return;
1347 p = strrchr_m(directory,'/');
1348 if (!p) {
1349 mask = directory;
1350 directory = talloc_strdup(ctx,".");
1351 if (!directory) {
1352 reply_nterror(req, NT_STATUS_NO_MEMORY);
1353 END_PROFILE(SMBsearch);
1354 return;
1356 } else {
1357 *p = 0;
1358 mask = p+1;
1361 if (*directory == '\0') {
1362 directory = talloc_strdup(ctx,".");
1363 if (!directory) {
1364 reply_nterror(req, NT_STATUS_NO_MEMORY);
1365 END_PROFILE(SMBsearch);
1366 return;
1369 memset((char *)status,'\0',21);
1370 SCVAL(status,0,(dirtype & 0x1F));
1372 nt_status = dptr_create(conn,
1373 directory,
1374 True,
1375 expect_close,
1376 req->smbpid,
1377 mask,
1378 mask_contains_wcard,
1379 dirtype,
1380 &conn->dirptr);
1381 if (!NT_STATUS_IS_OK(nt_status)) {
1382 reply_nterror(req, nt_status);
1383 END_PROFILE(SMBsearch);
1384 return;
1386 dptr_num = dptr_dnum(conn->dirptr);
1387 } else {
1388 int status_dirtype;
1390 memcpy(status,p,21);
1391 status_dirtype = CVAL(status,0) & 0x1F;
1392 if (status_dirtype != (dirtype & 0x1F)) {
1393 dirtype = status_dirtype;
1396 conn->dirptr = dptr_fetch(status+12,&dptr_num);
1397 if (!conn->dirptr) {
1398 goto SearchEmpty;
1400 string_set(&conn->dirpath,dptr_path(dptr_num));
1401 mask = dptr_wcard(dptr_num);
1402 if (!mask) {
1403 goto SearchEmpty;
1406 * For a 'continue' search we have no string. So
1407 * check from the initial saved string.
1409 mask_contains_wcard = ms_has_wild(mask);
1410 dirtype = dptr_attr(dptr_num);
1413 DEBUG(4,("dptr_num is %d\n",dptr_num));
1415 if ((dirtype&0x1F) == aVOLID) {
1416 char buf[DIR_STRUCT_SIZE];
1417 memcpy(buf,status,21);
1418 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1419 0,aVOLID,0,!allow_long_path_components)) {
1420 reply_nterror(req, NT_STATUS_NO_MEMORY);
1421 END_PROFILE(SMBsearch);
1422 return;
1424 dptr_fill(buf+12,dptr_num);
1425 if (dptr_zero(buf+12) && (status_len==0)) {
1426 numentries = 1;
1427 } else {
1428 numentries = 0;
1430 if (message_push_blob(&req->outbuf,
1431 data_blob_const(buf, sizeof(buf)))
1432 == -1) {
1433 reply_nterror(req, NT_STATUS_NO_MEMORY);
1434 END_PROFILE(SMBsearch);
1435 return;
1437 } else {
1438 unsigned int i;
1439 maxentries = MIN(
1440 maxentries,
1441 ((BUFFER_SIZE -
1442 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1443 /DIR_STRUCT_SIZE));
1445 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1446 conn->dirpath,lp_dontdescend(SNUM(conn))));
1447 if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True)) {
1448 check_descend = True;
1451 for (i=numentries;(i<maxentries) && !finished;i++) {
1452 finished = !get_dir_entry(ctx,
1453 conn,
1454 mask,
1455 dirtype,
1456 &fname,
1457 &size,
1458 &mode,
1459 &date,
1460 check_descend,
1461 ask_sharemode);
1462 if (!finished) {
1463 char buf[DIR_STRUCT_SIZE];
1464 memcpy(buf,status,21);
1465 if (!make_dir_struct(ctx,
1466 buf,
1467 mask,
1468 fname,
1469 size,
1470 mode,
1471 date,
1472 !allow_long_path_components)) {
1473 reply_nterror(req, NT_STATUS_NO_MEMORY);
1474 END_PROFILE(SMBsearch);
1475 return;
1477 if (!dptr_fill(buf+12,dptr_num)) {
1478 break;
1480 if (message_push_blob(&req->outbuf,
1481 data_blob_const(buf, sizeof(buf)))
1482 == -1) {
1483 reply_nterror(req, NT_STATUS_NO_MEMORY);
1484 END_PROFILE(SMBsearch);
1485 return;
1487 numentries++;
1492 SearchEmpty:
1494 /* If we were called as SMBffirst with smb_search_id == NULL
1495 and no entries were found then return error and close dirptr
1496 (X/Open spec) */
1498 if (numentries == 0) {
1499 dptr_close(&dptr_num);
1500 } else if(expect_close && status_len == 0) {
1501 /* Close the dptr - we know it's gone */
1502 dptr_close(&dptr_num);
1505 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1506 if(dptr_num >= 0 && CVAL(req->inbuf,smb_com) == SMBfunique) {
1507 dptr_close(&dptr_num);
1510 if ((numentries == 0) && !mask_contains_wcard) {
1511 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1512 END_PROFILE(SMBsearch);
1513 return;
1516 SSVAL(req->outbuf,smb_vwv0,numentries);
1517 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1518 SCVAL(smb_buf(req->outbuf),0,5);
1519 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1521 /* The replies here are never long name. */
1522 SSVAL(req->outbuf, smb_flg2,
1523 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1524 if (!allow_long_path_components) {
1525 SSVAL(req->outbuf, smb_flg2,
1526 SVAL(req->outbuf, smb_flg2)
1527 & (~FLAGS2_LONG_PATH_COMPONENTS));
1530 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1531 SSVAL(req->outbuf, smb_flg2,
1532 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1534 if (!directory) {
1535 directory = dptr_path(dptr_num);
1538 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1539 smb_fn_name(CVAL(req->inbuf,smb_com)),
1540 mask,
1541 directory ? directory : "./",
1542 dirtype,
1543 numentries,
1544 maxentries ));
1546 END_PROFILE(SMBsearch);
1547 return;
1550 /****************************************************************************
1551 Reply to a fclose (stop directory search).
1552 ****************************************************************************/
1554 void reply_fclose(struct smb_request *req)
1556 int status_len;
1557 char status[21];
1558 int dptr_num= -2;
1559 char *p;
1560 char *path = NULL;
1561 NTSTATUS err;
1562 bool path_contains_wcard = False;
1563 TALLOC_CTX *ctx = talloc_tos();
1565 START_PROFILE(SMBfclose);
1567 if (lp_posix_pathnames()) {
1568 reply_unknown_new(req, CVAL(req->inbuf, smb_com));
1569 END_PROFILE(SMBfclose);
1570 return;
1573 p = smb_buf(req->inbuf) + 1;
1574 p += srvstr_get_path_wcard(ctx,
1575 (char *)req->inbuf,
1576 req->flags2,
1577 &path,
1580 STR_TERMINATE,
1581 &err,
1582 &path_contains_wcard);
1583 if (!NT_STATUS_IS_OK(err)) {
1584 reply_nterror(req, err);
1585 END_PROFILE(SMBfclose);
1586 return;
1588 p++;
1589 status_len = SVAL(p,0);
1590 p += 2;
1592 if (status_len == 0) {
1593 reply_doserror(req, ERRSRV, ERRsrverror);
1594 END_PROFILE(SMBfclose);
1595 return;
1598 memcpy(status,p,21);
1600 if(dptr_fetch(status+12,&dptr_num)) {
1601 /* Close the dptr - we know it's gone */
1602 dptr_close(&dptr_num);
1605 reply_outbuf(req, 1, 0);
1606 SSVAL(req->outbuf,smb_vwv0,0);
1608 DEBUG(3,("search close\n"));
1610 END_PROFILE(SMBfclose);
1611 return;
1614 /****************************************************************************
1615 Reply to an open.
1616 ****************************************************************************/
1618 void reply_open(struct smb_request *req)
1620 connection_struct *conn = req->conn;
1621 char *fname = NULL;
1622 uint32 fattr=0;
1623 SMB_OFF_T size = 0;
1624 time_t mtime=0;
1625 int info;
1626 SMB_STRUCT_STAT sbuf;
1627 files_struct *fsp;
1628 int oplock_request;
1629 int deny_mode;
1630 uint32 dos_attr;
1631 uint32 access_mask;
1632 uint32 share_mode;
1633 uint32 create_disposition;
1634 uint32 create_options = 0;
1635 NTSTATUS status;
1636 TALLOC_CTX *ctx = talloc_tos();
1638 START_PROFILE(SMBopen);
1640 if (req->wct < 2) {
1641 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1642 END_PROFILE(SMBopen);
1643 return;
1646 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1647 deny_mode = SVAL(req->inbuf,smb_vwv0);
1648 dos_attr = SVAL(req->inbuf,smb_vwv1);
1650 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1651 smb_buf(req->inbuf)+1, 0,
1652 STR_TERMINATE, &status);
1653 if (!NT_STATUS_IS_OK(status)) {
1654 reply_nterror(req, status);
1655 END_PROFILE(SMBopen);
1656 return;
1659 if (!map_open_params_to_ntcreate(
1660 fname, deny_mode, OPENX_FILE_EXISTS_OPEN, &access_mask,
1661 &share_mode, &create_disposition, &create_options)) {
1662 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1663 END_PROFILE(SMBopen);
1664 return;
1667 status = create_file(conn, /* conn */
1668 req, /* req */
1669 0, /* root_dir_fid */
1670 fname, /* fname */
1671 access_mask, /* access_mask */
1672 share_mode, /* share_access */
1673 create_disposition, /* create_disposition*/
1674 create_options, /* create_options */
1675 dos_attr, /* file_attributes */
1676 oplock_request, /* oplock_request */
1677 0, /* allocation_size */
1678 NULL, /* sd */
1679 NULL, /* ea_list */
1680 &fsp, /* result */
1681 &info, /* pinfo */
1682 &sbuf); /* psbuf */
1684 if (!NT_STATUS_IS_OK(status)) {
1685 if (open_was_deferred(req->mid)) {
1686 /* We have re-scheduled this call. */
1687 END_PROFILE(SMBopen);
1688 return;
1690 reply_openerror(req, status);
1691 END_PROFILE(SMBopen);
1692 return;
1695 size = sbuf.st_size;
1696 fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
1697 mtime = sbuf.st_mtime;
1699 if (fattr & aDIR) {
1700 DEBUG(3,("attempt to open a directory %s\n",fsp->fsp_name));
1701 close_file(fsp,ERROR_CLOSE);
1702 reply_doserror(req, ERRDOS,ERRnoaccess);
1703 END_PROFILE(SMBopen);
1704 return;
1707 reply_outbuf(req, 7, 0);
1708 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1709 SSVAL(req->outbuf,smb_vwv1,fattr);
1710 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1711 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1712 } else {
1713 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1715 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1716 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1718 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1719 SCVAL(req->outbuf,smb_flg,
1720 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1723 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1724 SCVAL(req->outbuf,smb_flg,
1725 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1727 END_PROFILE(SMBopen);
1728 return;
1731 /****************************************************************************
1732 Reply to an open and X.
1733 ****************************************************************************/
1735 void reply_open_and_X(struct smb_request *req)
1737 connection_struct *conn = req->conn;
1738 char *fname = NULL;
1739 uint16 open_flags;
1740 int deny_mode;
1741 uint32 smb_attr;
1742 /* Breakout the oplock request bits so we can set the
1743 reply bits separately. */
1744 int ex_oplock_request;
1745 int core_oplock_request;
1746 int oplock_request;
1747 #if 0
1748 int smb_sattr = SVAL(req->inbuf,smb_vwv4);
1749 uint32 smb_time = make_unix_date3(req->inbuf+smb_vwv6);
1750 #endif
1751 int smb_ofun;
1752 uint32 fattr=0;
1753 int mtime=0;
1754 SMB_STRUCT_STAT sbuf;
1755 int smb_action = 0;
1756 files_struct *fsp;
1757 NTSTATUS status;
1758 SMB_BIG_UINT allocation_size;
1759 ssize_t retval = -1;
1760 uint32 access_mask;
1761 uint32 share_mode;
1762 uint32 create_disposition;
1763 uint32 create_options = 0;
1764 TALLOC_CTX *ctx = talloc_tos();
1766 START_PROFILE(SMBopenX);
1768 if (req->wct < 15) {
1769 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1770 END_PROFILE(SMBopenX);
1771 return;
1774 open_flags = SVAL(req->inbuf,smb_vwv2);
1775 deny_mode = SVAL(req->inbuf,smb_vwv3);
1776 smb_attr = SVAL(req->inbuf,smb_vwv5);
1777 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1778 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1779 oplock_request = ex_oplock_request | core_oplock_request;
1780 smb_ofun = SVAL(req->inbuf,smb_vwv8);
1781 allocation_size = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv9);
1783 /* If it's an IPC, pass off the pipe handler. */
1784 if (IS_IPC(conn)) {
1785 if (lp_nt_pipe_support()) {
1786 reply_open_pipe_and_X(conn, req);
1787 } else {
1788 reply_doserror(req, ERRSRV, ERRaccess);
1790 END_PROFILE(SMBopenX);
1791 return;
1794 /* XXXX we need to handle passed times, sattr and flags */
1795 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1796 smb_buf(req->inbuf), 0, STR_TERMINATE,
1797 &status);
1798 if (!NT_STATUS_IS_OK(status)) {
1799 reply_nterror(req, status);
1800 END_PROFILE(SMBopenX);
1801 return;
1804 if (!map_open_params_to_ntcreate(
1805 fname, deny_mode, smb_ofun, &access_mask,
1806 &share_mode, &create_disposition, &create_options)) {
1807 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1808 END_PROFILE(SMBopenX);
1809 return;
1812 status = create_file(conn, /* conn */
1813 req, /* req */
1814 0, /* root_dir_fid */
1815 fname, /* fname */
1816 access_mask, /* access_mask */
1817 share_mode, /* share_access */
1818 create_disposition, /* create_disposition*/
1819 create_options, /* create_options */
1820 smb_attr, /* file_attributes */
1821 oplock_request, /* oplock_request */
1822 0, /* allocation_size */
1823 NULL, /* sd */
1824 NULL, /* ea_list */
1825 &fsp, /* result */
1826 &smb_action, /* pinfo */
1827 &sbuf); /* psbuf */
1829 if (!NT_STATUS_IS_OK(status)) {
1830 END_PROFILE(SMBopenX);
1831 if (open_was_deferred(req->mid)) {
1832 /* We have re-scheduled this call. */
1833 return;
1835 reply_openerror(req, status);
1836 return;
1839 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1840 if the file is truncated or created. */
1841 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1842 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1843 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1844 close_file(fsp,ERROR_CLOSE);
1845 reply_nterror(req, NT_STATUS_DISK_FULL);
1846 END_PROFILE(SMBopenX);
1847 return;
1849 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1850 if (retval < 0) {
1851 close_file(fsp,ERROR_CLOSE);
1852 reply_nterror(req, NT_STATUS_DISK_FULL);
1853 END_PROFILE(SMBopenX);
1854 return;
1856 sbuf.st_size = get_allocation_size(conn,fsp,&sbuf);
1859 fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
1860 mtime = sbuf.st_mtime;
1861 if (fattr & aDIR) {
1862 close_file(fsp,ERROR_CLOSE);
1863 reply_doserror(req, ERRDOS, ERRnoaccess);
1864 END_PROFILE(SMBopenX);
1865 return;
1868 /* If the caller set the extended oplock request bit
1869 and we granted one (by whatever means) - set the
1870 correct bit for extended oplock reply.
1873 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1874 smb_action |= EXTENDED_OPLOCK_GRANTED;
1877 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1878 smb_action |= EXTENDED_OPLOCK_GRANTED;
1881 /* If the caller set the core oplock request bit
1882 and we granted one (by whatever means) - set the
1883 correct bit for core oplock reply.
1886 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1887 reply_outbuf(req, 19, 0);
1888 } else {
1889 reply_outbuf(req, 15, 0);
1892 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1893 SCVAL(req->outbuf, smb_flg,
1894 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1897 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1898 SCVAL(req->outbuf, smb_flg,
1899 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1902 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
1903 SSVAL(req->outbuf,smb_vwv3,fattr);
1904 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1905 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
1906 } else {
1907 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
1909 SIVAL(req->outbuf,smb_vwv6,(uint32)sbuf.st_size);
1910 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
1911 SSVAL(req->outbuf,smb_vwv11,smb_action);
1913 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1914 SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS);
1917 END_PROFILE(SMBopenX);
1918 chain_reply(req);
1919 return;
1922 /****************************************************************************
1923 Reply to a SMBulogoffX.
1924 ****************************************************************************/
1926 void reply_ulogoffX(struct smb_request *req)
1928 user_struct *vuser;
1930 START_PROFILE(SMBulogoffX);
1932 vuser = get_valid_user_struct(req->vuid);
1934 if(vuser == NULL) {
1935 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
1936 req->vuid));
1939 /* in user level security we are supposed to close any files
1940 open by this user */
1941 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
1942 file_close_user(req->vuid);
1945 invalidate_vuid(req->vuid);
1947 reply_outbuf(req, 2, 0);
1949 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
1951 END_PROFILE(SMBulogoffX);
1952 chain_reply(req);
1955 /****************************************************************************
1956 Reply to a mknew or a create.
1957 ****************************************************************************/
1959 void reply_mknew(struct smb_request *req)
1961 connection_struct *conn = req->conn;
1962 char *fname = NULL;
1963 int com;
1964 uint32 fattr = 0;
1965 struct timespec ts[2];
1966 files_struct *fsp;
1967 int oplock_request = 0;
1968 SMB_STRUCT_STAT sbuf;
1969 NTSTATUS status;
1970 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
1971 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
1972 uint32 create_disposition;
1973 uint32 create_options = 0;
1974 TALLOC_CTX *ctx = talloc_tos();
1976 START_PROFILE(SMBcreate);
1978 if (req->wct < 3) {
1979 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1980 END_PROFILE(SMBcreate);
1981 return;
1984 fattr = SVAL(req->inbuf,smb_vwv0);
1985 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1986 com = SVAL(req->inbuf,smb_com);
1988 ts[1] =convert_time_t_to_timespec(
1989 srv_make_unix_date3(req->inbuf + smb_vwv1));
1990 /* mtime. */
1992 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1993 smb_buf(req->inbuf) + 1, 0,
1994 STR_TERMINATE, &status);
1995 if (!NT_STATUS_IS_OK(status)) {
1996 reply_nterror(req, status);
1997 END_PROFILE(SMBcreate);
1998 return;
2001 if (fattr & aVOLID) {
2002 DEBUG(0,("Attempt to create file (%s) with volid set - "
2003 "please report this\n", fname));
2006 if(com == SMBmknew) {
2007 /* We should fail if file exists. */
2008 create_disposition = FILE_CREATE;
2009 } else {
2010 /* Create if file doesn't exist, truncate if it does. */
2011 create_disposition = FILE_OVERWRITE_IF;
2014 status = create_file(conn, /* conn */
2015 req, /* req */
2016 0, /* root_dir_fid */
2017 fname, /* fname */
2018 access_mask, /* access_mask */
2019 share_mode, /* share_access */
2020 create_disposition, /* create_disposition*/
2021 create_options, /* create_options */
2022 fattr, /* file_attributes */
2023 oplock_request, /* oplock_request */
2024 0, /* allocation_size */
2025 NULL, /* sd */
2026 NULL, /* ea_list */
2027 &fsp, /* result */
2028 NULL, /* pinfo */
2029 &sbuf); /* psbuf */
2031 if (!NT_STATUS_IS_OK(status)) {
2032 END_PROFILE(SMBcreate);
2033 if (open_was_deferred(req->mid)) {
2034 /* We have re-scheduled this call. */
2035 return;
2037 reply_openerror(req, status);
2038 return;
2041 ts[0] = get_atimespec(&sbuf); /* atime. */
2042 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, ts, true);
2043 if (!NT_STATUS_IS_OK(status)) {
2044 END_PROFILE(SMBcreate);
2045 reply_openerror(req, status);
2046 return;
2049 reply_outbuf(req, 1, 0);
2050 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2052 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2053 SCVAL(req->outbuf,smb_flg,
2054 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2057 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2058 SCVAL(req->outbuf,smb_flg,
2059 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2062 DEBUG( 2, ( "reply_mknew: file %s\n", fsp->fsp_name ) );
2063 DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n",
2064 fsp->fsp_name, fsp->fh->fd, (unsigned int)fattr ) );
2066 END_PROFILE(SMBcreate);
2067 return;
2070 /****************************************************************************
2071 Reply to a create temporary file.
2072 ****************************************************************************/
2074 void reply_ctemp(struct smb_request *req)
2076 connection_struct *conn = req->conn;
2077 char *fname = NULL;
2078 uint32 fattr;
2079 files_struct *fsp;
2080 int oplock_request;
2081 int tmpfd;
2082 SMB_STRUCT_STAT sbuf;
2083 char *s;
2084 NTSTATUS status;
2085 TALLOC_CTX *ctx = talloc_tos();
2087 START_PROFILE(SMBctemp);
2089 if (req->wct < 3) {
2090 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2091 END_PROFILE(SMBctemp);
2092 return;
2095 fattr = SVAL(req->inbuf,smb_vwv0);
2096 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2098 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
2099 smb_buf(req->inbuf)+1, 0, STR_TERMINATE,
2100 &status);
2101 if (!NT_STATUS_IS_OK(status)) {
2102 reply_nterror(req, status);
2103 END_PROFILE(SMBctemp);
2104 return;
2106 if (*fname) {
2107 fname = talloc_asprintf(ctx,
2108 "%s/TMXXXXXX",
2109 fname);
2110 } else {
2111 fname = talloc_strdup(ctx, "TMXXXXXX");
2114 if (!fname) {
2115 reply_nterror(req, NT_STATUS_NO_MEMORY);
2116 END_PROFILE(SMBctemp);
2117 return;
2120 status = resolve_dfspath(ctx, conn,
2121 req->flags2 & FLAGS2_DFS_PATHNAMES,
2122 fname,
2123 &fname);
2124 if (!NT_STATUS_IS_OK(status)) {
2125 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2126 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2127 ERRSRV, ERRbadpath);
2128 END_PROFILE(SMBctemp);
2129 return;
2131 reply_nterror(req, status);
2132 END_PROFILE(SMBctemp);
2133 return;
2136 status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
2137 if (!NT_STATUS_IS_OK(status)) {
2138 reply_nterror(req, status);
2139 END_PROFILE(SMBctemp);
2140 return;
2143 status = check_name(conn, CONST_DISCARD(char *,fname));
2144 if (!NT_STATUS_IS_OK(status)) {
2145 reply_nterror(req, status);
2146 END_PROFILE(SMBctemp);
2147 return;
2150 tmpfd = smb_mkstemp(fname);
2151 if (tmpfd == -1) {
2152 reply_unixerror(req, ERRDOS, ERRnoaccess);
2153 END_PROFILE(SMBctemp);
2154 return;
2157 SMB_VFS_STAT(conn,fname,&sbuf);
2159 /* We should fail if file does not exist. */
2160 status = open_file_ntcreate(conn, req, fname, &sbuf,
2161 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
2162 FILE_SHARE_READ|FILE_SHARE_WRITE,
2163 FILE_OPEN,
2165 fattr,
2166 oplock_request,
2167 NULL, &fsp);
2169 /* close fd from smb_mkstemp() */
2170 close(tmpfd);
2172 if (!NT_STATUS_IS_OK(status)) {
2173 if (open_was_deferred(req->mid)) {
2174 /* We have re-scheduled this call. */
2175 END_PROFILE(SMBctemp);
2176 return;
2178 reply_openerror(req, status);
2179 END_PROFILE(SMBctemp);
2180 return;
2183 reply_outbuf(req, 1, 0);
2184 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2186 /* the returned filename is relative to the directory */
2187 s = strrchr_m(fsp->fsp_name, '/');
2188 if (!s) {
2189 s = fsp->fsp_name;
2190 } else {
2191 s++;
2194 #if 0
2195 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2196 thing in the byte section. JRA */
2197 SSVALS(p, 0, -1); /* what is this? not in spec */
2198 #endif
2199 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2200 == -1) {
2201 reply_nterror(req, NT_STATUS_NO_MEMORY);
2202 END_PROFILE(SMBctemp);
2203 return;
2206 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2207 SCVAL(req->outbuf, smb_flg,
2208 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2211 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2212 SCVAL(req->outbuf, smb_flg,
2213 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2216 DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) );
2217 DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name,
2218 fsp->fh->fd, (unsigned int)sbuf.st_mode ) );
2220 END_PROFILE(SMBctemp);
2221 return;
2224 /*******************************************************************
2225 Check if a user is allowed to rename a file.
2226 ********************************************************************/
2228 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2229 uint16 dirtype, SMB_STRUCT_STAT *pst)
2231 uint32 fmode;
2233 if (!CAN_WRITE(conn)) {
2234 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2237 fmode = dos_mode(conn, fsp->fsp_name, pst);
2238 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2239 return NT_STATUS_NO_SUCH_FILE;
2242 if (S_ISDIR(pst->st_mode)) {
2243 return NT_STATUS_OK;
2246 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2247 return NT_STATUS_OK;
2250 return NT_STATUS_ACCESS_DENIED;
2253 /*******************************************************************
2254 * unlink a file with all relevant access checks
2255 *******************************************************************/
2257 static NTSTATUS do_unlink(connection_struct *conn,
2258 struct smb_request *req,
2259 const char *fname,
2260 uint32 dirtype)
2262 SMB_STRUCT_STAT sbuf;
2263 uint32 fattr;
2264 files_struct *fsp;
2265 uint32 dirtype_orig = dirtype;
2266 NTSTATUS status;
2268 DEBUG(10,("do_unlink: %s, dirtype = %d\n", fname, dirtype ));
2270 if (!CAN_WRITE(conn)) {
2271 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2274 if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) {
2275 return map_nt_error_from_unix(errno);
2278 fattr = dos_mode(conn,fname,&sbuf);
2280 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2281 dirtype = aDIR|aARCH|aRONLY;
2284 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2285 if (!dirtype) {
2286 return NT_STATUS_NO_SUCH_FILE;
2289 if (!dir_check_ftype(conn, fattr, dirtype)) {
2290 if (fattr & aDIR) {
2291 return NT_STATUS_FILE_IS_A_DIRECTORY;
2293 return NT_STATUS_NO_SUCH_FILE;
2296 if (dirtype_orig & 0x8000) {
2297 /* These will never be set for POSIX. */
2298 return NT_STATUS_NO_SUCH_FILE;
2301 #if 0
2302 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2303 return NT_STATUS_FILE_IS_A_DIRECTORY;
2306 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2307 return NT_STATUS_NO_SUCH_FILE;
2310 if (dirtype & 0xFF00) {
2311 /* These will never be set for POSIX. */
2312 return NT_STATUS_NO_SUCH_FILE;
2315 dirtype &= 0xFF;
2316 if (!dirtype) {
2317 return NT_STATUS_NO_SUCH_FILE;
2320 /* Can't delete a directory. */
2321 if (fattr & aDIR) {
2322 return NT_STATUS_FILE_IS_A_DIRECTORY;
2324 #endif
2326 #if 0 /* JRATEST */
2327 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2328 return NT_STATUS_OBJECT_NAME_INVALID;
2329 #endif /* JRATEST */
2331 /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com>
2333 On a Windows share, a file with read-only dosmode can be opened with
2334 DELETE_ACCESS. But on a Samba share (delete readonly = no), it
2335 fails with NT_STATUS_CANNOT_DELETE error.
2337 This semantic causes a problem that a user can not
2338 rename a file with read-only dosmode on a Samba share
2339 from a Windows command prompt (i.e. cmd.exe, but can rename
2340 from Windows Explorer).
2343 if (!lp_delete_readonly(SNUM(conn))) {
2344 if (fattr & aRONLY) {
2345 return NT_STATUS_CANNOT_DELETE;
2349 /* On open checks the open itself will check the share mode, so
2350 don't do it here as we'll get it wrong. */
2352 status = create_file_unixpath
2353 (conn, /* conn */
2354 req, /* req */
2355 fname, /* fname */
2356 DELETE_ACCESS, /* access_mask */
2357 FILE_SHARE_NONE, /* share_access */
2358 FILE_OPEN, /* create_disposition*/
2359 FILE_NON_DIRECTORY_FILE, /* create_options */
2360 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2361 0, /* oplock_request */
2362 0, /* allocation_size */
2363 NULL, /* sd */
2364 NULL, /* ea_list */
2365 &fsp, /* result */
2366 NULL, /* pinfo */
2367 &sbuf); /* psbuf */
2369 if (!NT_STATUS_IS_OK(status)) {
2370 DEBUG(10, ("create_file_unixpath failed: %s\n",
2371 nt_errstr(status)));
2372 return status;
2375 /* The set is across all open files on this dev/inode pair. */
2376 if (!set_delete_on_close(fsp, True, &current_user.ut)) {
2377 close_file(fsp, NORMAL_CLOSE);
2378 return NT_STATUS_ACCESS_DENIED;
2381 return close_file(fsp,NORMAL_CLOSE);
2384 /****************************************************************************
2385 The guts of the unlink command, split out so it may be called by the NT SMB
2386 code.
2387 ****************************************************************************/
2389 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2390 uint32 dirtype, const char *name_in, bool has_wild)
2392 const char *directory = NULL;
2393 char *mask = NULL;
2394 char *name = NULL;
2395 char *p = NULL;
2396 int count=0;
2397 NTSTATUS status = NT_STATUS_OK;
2398 SMB_STRUCT_STAT sbuf;
2399 TALLOC_CTX *ctx = talloc_tos();
2401 status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf);
2402 if (!NT_STATUS_IS_OK(status)) {
2403 return status;
2406 p = strrchr_m(name,'/');
2407 if (!p) {
2408 directory = talloc_strdup(ctx, ".");
2409 if (!directory) {
2410 return NT_STATUS_NO_MEMORY;
2412 mask = name;
2413 } else {
2414 *p = 0;
2415 directory = name;
2416 mask = p+1;
2420 * We should only check the mangled cache
2421 * here if unix_convert failed. This means
2422 * that the path in 'mask' doesn't exist
2423 * on the file system and so we need to look
2424 * for a possible mangle. This patch from
2425 * Tine Smukavec <valentin.smukavec@hermes.si>.
2428 if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) {
2429 char *new_mask = NULL;
2430 mangle_lookup_name_from_8_3(ctx,
2431 mask,
2432 &new_mask,
2433 conn->params );
2434 if (new_mask) {
2435 mask = new_mask;
2439 if (!has_wild) {
2440 directory = talloc_asprintf(ctx,
2441 "%s/%s",
2442 directory,
2443 mask);
2444 if (!directory) {
2445 return NT_STATUS_NO_MEMORY;
2447 if (dirtype == 0) {
2448 dirtype = FILE_ATTRIBUTE_NORMAL;
2451 status = check_name(conn, directory);
2452 if (!NT_STATUS_IS_OK(status)) {
2453 return status;
2456 status = do_unlink(conn, req, directory, dirtype);
2457 if (!NT_STATUS_IS_OK(status)) {
2458 return status;
2461 count++;
2462 } else {
2463 struct smb_Dir *dir_hnd = NULL;
2464 long offset = 0;
2465 const char *dname;
2467 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2468 return NT_STATUS_OBJECT_NAME_INVALID;
2471 if (strequal(mask,"????????.???")) {
2472 mask[0] = '*';
2473 mask[1] = '\0';
2476 status = check_name(conn, directory);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 return status;
2481 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask,
2482 dirtype);
2483 if (dir_hnd == NULL) {
2484 return map_nt_error_from_unix(errno);
2487 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2488 the pattern matches against the long name, otherwise the short name
2489 We don't implement this yet XXXX
2492 status = NT_STATUS_NO_SUCH_FILE;
2494 while ((dname = ReadDirName(dir_hnd, &offset))) {
2495 SMB_STRUCT_STAT st;
2496 char *fname = NULL;
2498 if (!is_visible_file(conn, directory, dname, &st, True)) {
2499 continue;
2502 /* Quick check for "." and ".." */
2503 if (ISDOT(dname) || ISDOTDOT(dname)) {
2504 continue;
2507 if(!mask_match(dname, mask, conn->case_sensitive)) {
2508 continue;
2511 fname = talloc_asprintf(ctx, "%s/%s",
2512 directory,
2513 dname);
2514 if (!fname) {
2515 return NT_STATUS_NO_MEMORY;
2518 status = check_name(conn, fname);
2519 if (!NT_STATUS_IS_OK(status)) {
2520 TALLOC_FREE(dir_hnd);
2521 return status;
2524 status = do_unlink(conn, req, fname, dirtype);
2525 if (!NT_STATUS_IS_OK(status)) {
2526 TALLOC_FREE(fname);
2527 continue;
2530 count++;
2531 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2532 fname));
2534 TALLOC_FREE(fname);
2536 TALLOC_FREE(dir_hnd);
2539 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2540 status = map_nt_error_from_unix(errno);
2543 return status;
2546 /****************************************************************************
2547 Reply to a unlink
2548 ****************************************************************************/
2550 void reply_unlink(struct smb_request *req)
2552 connection_struct *conn = req->conn;
2553 char *name = NULL;
2554 uint32 dirtype;
2555 NTSTATUS status;
2556 bool path_contains_wcard = False;
2557 TALLOC_CTX *ctx = talloc_tos();
2559 START_PROFILE(SMBunlink);
2561 if (req->wct < 1) {
2562 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2563 END_PROFILE(SMBunlink);
2564 return;
2567 dirtype = SVAL(req->inbuf,smb_vwv0);
2569 srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name,
2570 smb_buf(req->inbuf) + 1, 0,
2571 STR_TERMINATE, &status, &path_contains_wcard);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 reply_nterror(req, status);
2574 END_PROFILE(SMBunlink);
2575 return;
2578 status = resolve_dfspath_wcard(ctx, conn,
2579 req->flags2 & FLAGS2_DFS_PATHNAMES,
2580 name,
2581 &name,
2582 &path_contains_wcard);
2583 if (!NT_STATUS_IS_OK(status)) {
2584 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2585 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2586 ERRSRV, ERRbadpath);
2587 END_PROFILE(SMBunlink);
2588 return;
2590 reply_nterror(req, status);
2591 END_PROFILE(SMBunlink);
2592 return;
2595 DEBUG(3,("reply_unlink : %s\n",name));
2597 status = unlink_internals(conn, req, dirtype, name,
2598 path_contains_wcard);
2599 if (!NT_STATUS_IS_OK(status)) {
2600 if (open_was_deferred(req->mid)) {
2601 /* We have re-scheduled this call. */
2602 END_PROFILE(SMBunlink);
2603 return;
2605 reply_nterror(req, status);
2606 END_PROFILE(SMBunlink);
2607 return;
2610 reply_outbuf(req, 0, 0);
2611 END_PROFILE(SMBunlink);
2613 return;
2616 /****************************************************************************
2617 Fail for readbraw.
2618 ****************************************************************************/
2620 static void fail_readraw(void)
2622 const char *errstr = talloc_asprintf(talloc_tos(),
2623 "FAIL ! reply_readbraw: socket write fail (%s)",
2624 strerror(errno));
2625 if (!errstr) {
2626 errstr = "";
2628 exit_server_cleanly(errstr);
2631 /****************************************************************************
2632 Fake (read/write) sendfile. Returns -1 on read or write fail.
2633 ****************************************************************************/
2635 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
2636 size_t nread)
2638 size_t bufsize;
2639 size_t tosend = nread;
2640 char *buf;
2642 if (nread == 0) {
2643 return 0;
2646 bufsize = MIN(nread, 65536);
2648 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2649 return -1;
2652 while (tosend > 0) {
2653 ssize_t ret;
2654 size_t cur_read;
2656 if (tosend > bufsize) {
2657 cur_read = bufsize;
2658 } else {
2659 cur_read = tosend;
2661 ret = read_file(fsp,buf,startpos,cur_read);
2662 if (ret == -1) {
2663 SAFE_FREE(buf);
2664 return -1;
2667 /* If we had a short read, fill with zeros. */
2668 if (ret < cur_read) {
2669 memset(buf, '\0', cur_read - ret);
2672 if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
2673 SAFE_FREE(buf);
2674 return -1;
2676 tosend -= cur_read;
2677 startpos += cur_read;
2680 SAFE_FREE(buf);
2681 return (ssize_t)nread;
2684 /****************************************************************************
2685 Return a readbraw error (4 bytes of zero).
2686 ****************************************************************************/
2688 static void reply_readbraw_error(void)
2690 char header[4];
2691 SIVAL(header,0,0);
2692 if (write_data(smbd_server_fd(),header,4) != 4) {
2693 fail_readraw();
2697 /****************************************************************************
2698 Use sendfile in readbraw.
2699 ****************************************************************************/
2701 void send_file_readbraw(connection_struct *conn,
2702 files_struct *fsp,
2703 SMB_OFF_T startpos,
2704 size_t nread,
2705 ssize_t mincount)
2707 char *outbuf = NULL;
2708 ssize_t ret=0;
2710 #if defined(WITH_SENDFILE)
2712 * We can only use sendfile on a non-chained packet
2713 * but we can use on a non-oplocked file. tridge proved this
2714 * on a train in Germany :-). JRA.
2715 * reply_readbraw has already checked the length.
2718 if ( (chain_size == 0) && (nread > 0) && (fsp->base_fsp == NULL) &&
2719 (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) {
2720 char header[4];
2721 DATA_BLOB header_blob;
2723 _smb_setlen(header,nread);
2724 header_blob = data_blob_const(header, 4);
2726 if (SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
2727 &header_blob, startpos, nread) == -1) {
2728 /* Returning ENOSYS means no data at all was sent.
2729 * Do this as a normal read. */
2730 if (errno == ENOSYS) {
2731 goto normal_readbraw;
2735 * Special hack for broken Linux with no working sendfile. If we
2736 * return EINTR we sent the header but not the rest of the data.
2737 * Fake this up by doing read/write calls.
2739 if (errno == EINTR) {
2740 /* Ensure we don't do this again. */
2741 set_use_sendfile(SNUM(conn), False);
2742 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2744 if (fake_sendfile(fsp, startpos, nread) == -1) {
2745 DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
2746 fsp->fsp_name, strerror(errno) ));
2747 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2749 return;
2752 DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
2753 fsp->fsp_name, strerror(errno) ));
2754 exit_server_cleanly("send_file_readbraw sendfile failed");
2757 return;
2759 #endif
2761 normal_readbraw:
2763 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
2764 if (!outbuf) {
2765 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
2766 (unsigned)(nread+4)));
2767 reply_readbraw_error();
2768 return;
2771 if (nread > 0) {
2772 ret = read_file(fsp,outbuf+4,startpos,nread);
2773 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
2774 if (ret < mincount)
2775 ret = 0;
2776 #else
2777 if (ret < nread)
2778 ret = 0;
2779 #endif
2782 _smb_setlen(outbuf,ret);
2783 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
2784 fail_readraw();
2786 TALLOC_FREE(outbuf);
2789 /****************************************************************************
2790 Reply to a readbraw (core+ protocol).
2791 ****************************************************************************/
2793 void reply_readbraw(struct smb_request *req)
2795 connection_struct *conn = req->conn;
2796 ssize_t maxcount,mincount;
2797 size_t nread = 0;
2798 SMB_OFF_T startpos;
2799 files_struct *fsp;
2800 SMB_STRUCT_STAT st;
2801 SMB_OFF_T size = 0;
2803 START_PROFILE(SMBreadbraw);
2805 if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
2806 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
2807 "raw reads/writes are disallowed.");
2810 if (req->wct < 8) {
2811 reply_readbraw_error();
2812 END_PROFILE(SMBreadbraw);
2813 return;
2817 * Special check if an oplock break has been issued
2818 * and the readraw request croses on the wire, we must
2819 * return a zero length response here.
2822 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
2825 * We have to do a check_fsp by hand here, as
2826 * we must always return 4 zero bytes on error,
2827 * not a NTSTATUS.
2830 if (!fsp || !conn || conn != fsp->conn ||
2831 current_user.vuid != fsp->vuid ||
2832 fsp->is_directory || fsp->fh->fd == -1) {
2834 * fsp could be NULL here so use the value from the packet. JRA.
2836 DEBUG(3,("reply_readbraw: fnum %d not valid "
2837 "- cache prime?\n",
2838 (int)SVAL(req->inbuf,smb_vwv0)));
2839 reply_readbraw_error();
2840 END_PROFILE(SMBreadbraw);
2841 return;
2844 /* Do a "by hand" version of CHECK_READ. */
2845 if (!(fsp->can_read ||
2846 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
2847 (fsp->access_mask & FILE_EXECUTE)))) {
2848 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
2849 (int)SVAL(req->inbuf,smb_vwv0)));
2850 reply_readbraw_error();
2851 END_PROFILE(SMBreadbraw);
2852 return;
2855 flush_write_cache(fsp, READRAW_FLUSH);
2857 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv1);
2858 if(req->wct == 10) {
2860 * This is a large offset (64 bit) read.
2862 #ifdef LARGE_SMB_OFF_T
2864 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv8)) << 32);
2866 #else /* !LARGE_SMB_OFF_T */
2869 * Ensure we haven't been sent a >32 bit offset.
2872 if(IVAL(req->inbuf,smb_vwv8) != 0) {
2873 DEBUG(0,("reply_readbraw: large offset "
2874 "(%x << 32) used and we don't support "
2875 "64 bit offsets.\n",
2876 (unsigned int)IVAL(req->inbuf,smb_vwv8) ));
2877 reply_readbraw_error();
2878 END_PROFILE(SMBreadbraw);
2879 return;
2882 #endif /* LARGE_SMB_OFF_T */
2884 if(startpos < 0) {
2885 DEBUG(0,("reply_readbraw: negative 64 bit "
2886 "readraw offset (%.0f) !\n",
2887 (double)startpos ));
2888 reply_readbraw_error();
2889 END_PROFILE(SMBreadbraw);
2890 return;
2894 maxcount = (SVAL(req->inbuf,smb_vwv3) & 0xFFFF);
2895 mincount = (SVAL(req->inbuf,smb_vwv4) & 0xFFFF);
2897 /* ensure we don't overrun the packet size */
2898 maxcount = MIN(65535,maxcount);
2900 if (is_locked(fsp,(uint32)req->smbpid,
2901 (SMB_BIG_UINT)maxcount,
2902 (SMB_BIG_UINT)startpos,
2903 READ_LOCK)) {
2904 reply_readbraw_error();
2905 END_PROFILE(SMBreadbraw);
2906 return;
2909 if (SMB_VFS_FSTAT(fsp, &st) == 0) {
2910 size = st.st_size;
2913 if (startpos >= size) {
2914 nread = 0;
2915 } else {
2916 nread = MIN(maxcount,(size - startpos));
2919 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
2920 if (nread < mincount)
2921 nread = 0;
2922 #endif
2924 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
2925 "min=%lu nread=%lu\n",
2926 fsp->fnum, (double)startpos,
2927 (unsigned long)maxcount,
2928 (unsigned long)mincount,
2929 (unsigned long)nread ) );
2931 send_file_readbraw(conn, fsp, startpos, nread, mincount);
2933 DEBUG(5,("reply_readbraw finished\n"));
2934 END_PROFILE(SMBreadbraw);
2937 #undef DBGC_CLASS
2938 #define DBGC_CLASS DBGC_LOCKING
2940 /****************************************************************************
2941 Reply to a lockread (core+ protocol).
2942 ****************************************************************************/
2944 void reply_lockread(struct smb_request *req)
2946 connection_struct *conn = req->conn;
2947 ssize_t nread = -1;
2948 char *data;
2949 SMB_OFF_T startpos;
2950 size_t numtoread;
2951 NTSTATUS status;
2952 files_struct *fsp;
2953 struct byte_range_lock *br_lck = NULL;
2954 char *p = NULL;
2956 START_PROFILE(SMBlockread);
2958 if (req->wct < 5) {
2959 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2960 END_PROFILE(SMBlockread);
2961 return;
2964 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
2966 if (!check_fsp(conn, req, fsp, &current_user)) {
2967 END_PROFILE(SMBlockread);
2968 return;
2971 if (!CHECK_READ(fsp,req->inbuf)) {
2972 reply_doserror(req, ERRDOS, ERRbadaccess);
2973 END_PROFILE(SMBlockread);
2974 return;
2977 release_level_2_oplocks_on_change(fsp);
2979 numtoread = SVAL(req->inbuf,smb_vwv1);
2980 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
2982 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
2984 reply_outbuf(req, 5, numtoread + 3);
2986 data = smb_buf(req->outbuf) + 3;
2989 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
2990 * protocol request that predates the read/write lock concept.
2991 * Thus instead of asking for a read lock here we need to ask
2992 * for a write lock. JRA.
2993 * Note that the requested lock size is unaffected by max_recv.
2996 br_lck = do_lock(smbd_messaging_context(),
2997 fsp,
2998 req->smbpid,
2999 (SMB_BIG_UINT)numtoread,
3000 (SMB_BIG_UINT)startpos,
3001 WRITE_LOCK,
3002 WINDOWS_LOCK,
3003 False, /* Non-blocking lock. */
3004 &status,
3005 NULL);
3006 TALLOC_FREE(br_lck);
3008 if (NT_STATUS_V(status)) {
3009 reply_nterror(req, status);
3010 END_PROFILE(SMBlockread);
3011 return;
3015 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3018 if (numtoread > max_recv) {
3019 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3020 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3021 (unsigned int)numtoread, (unsigned int)max_recv ));
3022 numtoread = MIN(numtoread,max_recv);
3024 nread = read_file(fsp,data,startpos,numtoread);
3026 if (nread < 0) {
3027 reply_unixerror(req, ERRDOS, ERRnoaccess);
3028 END_PROFILE(SMBlockread);
3029 return;
3032 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3034 SSVAL(req->outbuf,smb_vwv0,nread);
3035 SSVAL(req->outbuf,smb_vwv5,nread+3);
3036 p = smb_buf(req->outbuf);
3037 SCVAL(p,0,0); /* pad byte. */
3038 SSVAL(p,1,nread);
3040 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3041 fsp->fnum, (int)numtoread, (int)nread));
3043 END_PROFILE(SMBlockread);
3044 return;
3047 #undef DBGC_CLASS
3048 #define DBGC_CLASS DBGC_ALL
3050 /****************************************************************************
3051 Reply to a read.
3052 ****************************************************************************/
3054 void reply_read(struct smb_request *req)
3056 connection_struct *conn = req->conn;
3057 size_t numtoread;
3058 ssize_t nread = 0;
3059 char *data;
3060 SMB_OFF_T startpos;
3061 int outsize = 0;
3062 files_struct *fsp;
3064 START_PROFILE(SMBread);
3066 if (req->wct < 3) {
3067 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3068 END_PROFILE(SMBread);
3069 return;
3072 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3074 if (!check_fsp(conn, req, fsp, &current_user)) {
3075 END_PROFILE(SMBread);
3076 return;
3079 if (!CHECK_READ(fsp,req->inbuf)) {
3080 reply_doserror(req, ERRDOS, ERRbadaccess);
3081 END_PROFILE(SMBread);
3082 return;
3085 numtoread = SVAL(req->inbuf,smb_vwv1);
3086 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3088 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3091 * The requested read size cannot be greater than max_recv. JRA.
3093 if (numtoread > max_recv) {
3094 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3095 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3096 (unsigned int)numtoread, (unsigned int)max_recv ));
3097 numtoread = MIN(numtoread,max_recv);
3100 reply_outbuf(req, 5, numtoread+3);
3102 data = smb_buf(req->outbuf) + 3;
3104 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtoread,
3105 (SMB_BIG_UINT)startpos, READ_LOCK)) {
3106 reply_doserror(req, ERRDOS,ERRlock);
3107 END_PROFILE(SMBread);
3108 return;
3111 if (numtoread > 0)
3112 nread = read_file(fsp,data,startpos,numtoread);
3114 if (nread < 0) {
3115 reply_unixerror(req, ERRDOS,ERRnoaccess);
3116 END_PROFILE(SMBread);
3117 return;
3120 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3122 SSVAL(req->outbuf,smb_vwv0,nread);
3123 SSVAL(req->outbuf,smb_vwv5,nread+3);
3124 SCVAL(smb_buf(req->outbuf),0,1);
3125 SSVAL(smb_buf(req->outbuf),1,nread);
3127 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3128 fsp->fnum, (int)numtoread, (int)nread ) );
3130 END_PROFILE(SMBread);
3131 return;
3134 /****************************************************************************
3135 Setup readX header.
3136 ****************************************************************************/
3138 static int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3140 int outsize;
3141 char *data;
3143 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3144 data = smb_buf(outbuf);
3146 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3148 SCVAL(outbuf,smb_vwv0,0xFF);
3149 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3150 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3151 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
3152 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3153 SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
3154 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3155 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3156 return outsize;
3159 /****************************************************************************
3160 Reply to a read and X - possibly using sendfile.
3161 ****************************************************************************/
3163 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3164 files_struct *fsp, SMB_OFF_T startpos,
3165 size_t smb_maxcnt)
3167 SMB_STRUCT_STAT sbuf;
3168 ssize_t nread = -1;
3170 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
3171 reply_unixerror(req, ERRDOS, ERRnoaccess);
3172 return;
3175 if (startpos > sbuf.st_size) {
3176 smb_maxcnt = 0;
3177 } else if (smb_maxcnt > (sbuf.st_size - startpos)) {
3178 smb_maxcnt = (sbuf.st_size - startpos);
3181 if (smb_maxcnt == 0) {
3182 goto normal_read;
3185 #if defined(WITH_SENDFILE)
3187 * We can only use sendfile on a non-chained packet
3188 * but we can use on a non-oplocked file. tridge proved this
3189 * on a train in Germany :-). JRA.
3192 if ((chain_size == 0) && (CVAL(req->inbuf,smb_vwv0) == 0xFF) &&
3193 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3194 lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
3195 uint8 headerbuf[smb_size + 12 * 2];
3196 DATA_BLOB header;
3199 * Set up the packet header before send. We
3200 * assume here the sendfile will work (get the
3201 * correct amount of data).
3204 header = data_blob_const(headerbuf, sizeof(headerbuf));
3206 construct_reply_common((char *)req->inbuf, (char *)headerbuf);
3207 setup_readX_header((char *)headerbuf, smb_maxcnt);
3209 if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
3210 /* Returning ENOSYS means no data at all was sent.
3211 Do this as a normal read. */
3212 if (errno == ENOSYS) {
3213 goto normal_read;
3217 * Special hack for broken Linux with no working sendfile. If we
3218 * return EINTR we sent the header but not the rest of the data.
3219 * Fake this up by doing read/write calls.
3222 if (errno == EINTR) {
3223 /* Ensure we don't do this again. */
3224 set_use_sendfile(SNUM(conn), False);
3225 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3226 nread = fake_sendfile(fsp, startpos,
3227 smb_maxcnt);
3228 if (nread == -1) {
3229 DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
3230 fsp->fsp_name, strerror(errno) ));
3231 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3233 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3234 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3235 /* No outbuf here means successful sendfile. */
3236 TALLOC_FREE(req->outbuf);
3237 return;
3240 DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
3241 fsp->fsp_name, strerror(errno) ));
3242 exit_server_cleanly("send_file_readX sendfile failed");
3245 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3246 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3247 /* No outbuf here means successful sendfile. */
3248 TALLOC_FREE(req->outbuf);
3249 return;
3251 #endif
3253 normal_read:
3255 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3256 uint8 headerbuf[smb_size + 2*12];
3258 construct_reply_common((char *)req->inbuf, (char *)headerbuf);
3259 setup_readX_header((char *)headerbuf, smb_maxcnt);
3261 /* Send out the header. */
3262 if (write_data(smbd_server_fd(), (char *)headerbuf,
3263 sizeof(headerbuf)) != sizeof(headerbuf)) {
3264 DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
3265 fsp->fsp_name, strerror(errno) ));
3266 exit_server_cleanly("send_file_readX sendfile failed");
3268 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3269 if (nread == -1) {
3270 DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
3271 fsp->fsp_name, strerror(errno) ));
3272 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3274 TALLOC_FREE(req->outbuf);
3275 return;
3276 } else {
3277 reply_outbuf(req, 12, smb_maxcnt);
3279 nread = read_file(fsp, smb_buf(req->outbuf), startpos,
3280 smb_maxcnt);
3281 if (nread < 0) {
3282 reply_unixerror(req, ERRDOS, ERRnoaccess);
3283 return;
3286 setup_readX_header((char *)req->outbuf, nread);
3288 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3289 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3291 chain_reply(req);
3293 return;
3297 /****************************************************************************
3298 Reply to a read and X.
3299 ****************************************************************************/
3301 void reply_read_and_X(struct smb_request *req)
3303 connection_struct *conn = req->conn;
3304 files_struct *fsp;
3305 SMB_OFF_T startpos;
3306 size_t smb_maxcnt;
3307 bool big_readX = False;
3308 #if 0
3309 size_t smb_mincnt = SVAL(req->inbuf,smb_vwv6);
3310 #endif
3312 START_PROFILE(SMBreadX);
3314 if ((req->wct != 10) && (req->wct != 12)) {
3315 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3316 return;
3319 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
3320 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
3321 smb_maxcnt = SVAL(req->inbuf,smb_vwv5);
3323 /* If it's an IPC, pass off the pipe handler. */
3324 if (IS_IPC(conn)) {
3325 reply_pipe_read_and_X(req);
3326 END_PROFILE(SMBreadX);
3327 return;
3330 if (!check_fsp(conn, req, fsp, &current_user)) {
3331 END_PROFILE(SMBreadX);
3332 return;
3335 if (!CHECK_READ(fsp,req->inbuf)) {
3336 reply_doserror(req, ERRDOS,ERRbadaccess);
3337 END_PROFILE(SMBreadX);
3338 return;
3341 if (global_client_caps & CAP_LARGE_READX) {
3342 size_t upper_size = SVAL(req->inbuf,smb_vwv7);
3343 smb_maxcnt |= (upper_size<<16);
3344 if (upper_size > 1) {
3345 /* Can't do this on a chained packet. */
3346 if ((CVAL(req->inbuf,smb_vwv0) != 0xFF)) {
3347 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3348 END_PROFILE(SMBreadX);
3349 return;
3351 /* We currently don't do this on signed or sealed data. */
3352 if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
3353 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3354 END_PROFILE(SMBreadX);
3355 return;
3357 /* Is there room in the reply for this data ? */
3358 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3359 reply_nterror(req,
3360 NT_STATUS_INVALID_PARAMETER);
3361 END_PROFILE(SMBreadX);
3362 return;
3364 big_readX = True;
3368 if (req->wct == 12) {
3369 #ifdef LARGE_SMB_OFF_T
3371 * This is a large offset (64 bit) read.
3373 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv10)) << 32);
3375 #else /* !LARGE_SMB_OFF_T */
3378 * Ensure we haven't been sent a >32 bit offset.
3381 if(IVAL(req->inbuf,smb_vwv10) != 0) {
3382 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3383 "used and we don't support 64 bit offsets.\n",
3384 (unsigned int)IVAL(req->inbuf,smb_vwv10) ));
3385 END_PROFILE(SMBreadX);
3386 reply_doserror(req, ERRDOS, ERRbadaccess);
3387 return;
3390 #endif /* LARGE_SMB_OFF_T */
3394 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)smb_maxcnt,
3395 (SMB_BIG_UINT)startpos, READ_LOCK)) {
3396 END_PROFILE(SMBreadX);
3397 reply_doserror(req, ERRDOS, ERRlock);
3398 return;
3401 if (!big_readX &&
3402 schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
3403 END_PROFILE(SMBreadX);
3404 return;
3407 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3409 END_PROFILE(SMBreadX);
3410 return;
3413 /****************************************************************************
3414 Error replies to writebraw must have smb_wct == 1. Fix this up.
3415 ****************************************************************************/
3417 void error_to_writebrawerr(struct smb_request *req)
3419 uint8 *old_outbuf = req->outbuf;
3421 reply_outbuf(req, 1, 0);
3423 memcpy(req->outbuf, old_outbuf, smb_size);
3424 TALLOC_FREE(old_outbuf);
3427 /****************************************************************************
3428 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3429 ****************************************************************************/
3431 void reply_writebraw(struct smb_request *req)
3433 connection_struct *conn = req->conn;
3434 char *buf = NULL;
3435 ssize_t nwritten=0;
3436 ssize_t total_written=0;
3437 size_t numtowrite=0;
3438 size_t tcount;
3439 SMB_OFF_T startpos;
3440 char *data=NULL;
3441 bool write_through;
3442 files_struct *fsp;
3443 NTSTATUS status;
3445 START_PROFILE(SMBwritebraw);
3448 * If we ever reply with an error, it must have the SMB command
3449 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3450 * we're finished.
3452 SCVAL(req->inbuf,smb_com,SMBwritec);
3454 if (srv_is_signing_active()) {
3455 END_PROFILE(SMBwritebraw);
3456 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3457 "raw reads/writes are disallowed.");
3460 if (req->wct < 12) {
3461 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3462 error_to_writebrawerr(req);
3463 END_PROFILE(SMBwritebraw);
3464 return;
3467 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3468 if (!check_fsp(conn, req, fsp, &current_user)) {
3469 error_to_writebrawerr(req);
3470 END_PROFILE(SMBwritebraw);
3471 return;
3474 if (!CHECK_WRITE(fsp)) {
3475 reply_doserror(req, ERRDOS, ERRbadaccess);
3476 error_to_writebrawerr(req);
3477 END_PROFILE(SMBwritebraw);
3478 return;
3481 tcount = IVAL(req->inbuf,smb_vwv1);
3482 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
3483 write_through = BITSETW(req->inbuf+smb_vwv7,0);
3485 /* We have to deal with slightly different formats depending
3486 on whether we are using the core+ or lanman1.0 protocol */
3488 if(Protocol <= PROTOCOL_COREPLUS) {
3489 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3490 data = smb_buf(req->inbuf);
3491 } else {
3492 numtowrite = SVAL(req->inbuf,smb_vwv10);
3493 data = smb_base(req->inbuf) + SVAL(req->inbuf, smb_vwv11);
3496 /* Ensure we don't write bytes past the end of this packet. */
3497 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3498 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3499 error_to_writebrawerr(req);
3500 END_PROFILE(SMBwritebraw);
3501 return;
3504 if (is_locked(fsp,(uint32)req->smbpid,(SMB_BIG_UINT)tcount,
3505 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3506 reply_doserror(req, ERRDOS, ERRlock);
3507 error_to_writebrawerr(req);
3508 END_PROFILE(SMBwritebraw);
3509 return;
3512 if (numtowrite>0) {
3513 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3516 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3517 "wrote=%d sync=%d\n",
3518 fsp->fnum, (double)startpos, (int)numtowrite,
3519 (int)nwritten, (int)write_through));
3521 if (nwritten < (ssize_t)numtowrite) {
3522 reply_unixerror(req, ERRHRD, ERRdiskfull);
3523 error_to_writebrawerr(req);
3524 END_PROFILE(SMBwritebraw);
3525 return;
3528 total_written = nwritten;
3530 /* Allocate a buffer of 64k + length. */
3531 buf = TALLOC_ARRAY(NULL, char, 65540);
3532 if (!buf) {
3533 reply_doserror(req, ERRDOS, ERRnomem);
3534 error_to_writebrawerr(req);
3535 END_PROFILE(SMBwritebraw);
3536 return;
3539 /* Return a SMBwritebraw message to the redirector to tell
3540 * it to send more bytes */
3542 memcpy(buf, req->inbuf, smb_size);
3543 srv_set_message(buf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
3544 SCVAL(buf,smb_com,SMBwritebraw);
3545 SSVALS(buf,smb_vwv0,0xFFFF);
3546 show_msg(buf);
3547 if (!srv_send_smb(smbd_server_fd(),
3548 buf,
3549 IS_CONN_ENCRYPTED(conn))) {
3550 exit_server_cleanly("reply_writebraw: srv_send_smb "
3551 "failed.");
3554 /* Now read the raw data into the buffer and write it */
3555 status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
3556 &numtowrite);
3557 if (!NT_STATUS_IS_OK(status)) {
3558 exit_server_cleanly("secondary writebraw failed");
3561 /* Set up outbuf to return the correct size */
3562 reply_outbuf(req, 1, 0);
3564 if (numtowrite != 0) {
3566 if (numtowrite > 0xFFFF) {
3567 DEBUG(0,("reply_writebraw: Oversize secondary write "
3568 "raw requested (%u). Terminating\n",
3569 (unsigned int)numtowrite ));
3570 exit_server_cleanly("secondary writebraw failed");
3573 if (tcount > nwritten+numtowrite) {
3574 DEBUG(3,("reply_writebraw: Client overestimated the "
3575 "write %d %d %d\n",
3576 (int)tcount,(int)nwritten,(int)numtowrite));
3579 status = read_data(smbd_server_fd(), buf+4, numtowrite);
3581 if (!NT_STATUS_IS_OK(status)) {
3582 DEBUG(0,("reply_writebraw: Oversize secondary write "
3583 "raw read failed (%s). Terminating\n",
3584 nt_errstr(status)));
3585 exit_server_cleanly("secondary writebraw failed");
3588 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
3589 if (nwritten == -1) {
3590 TALLOC_FREE(buf);
3591 reply_unixerror(req, ERRHRD, ERRdiskfull);
3592 error_to_writebrawerr(req);
3593 END_PROFILE(SMBwritebraw);
3594 return;
3597 if (nwritten < (ssize_t)numtowrite) {
3598 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3599 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3602 if (nwritten > 0) {
3603 total_written += nwritten;
3607 TALLOC_FREE(buf);
3608 SSVAL(req->outbuf,smb_vwv0,total_written);
3610 status = sync_file(conn, fsp, write_through);
3611 if (!NT_STATUS_IS_OK(status)) {
3612 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
3613 fsp->fsp_name, nt_errstr(status) ));
3614 reply_nterror(req, status);
3615 error_to_writebrawerr(req);
3616 END_PROFILE(SMBwritebraw);
3617 return;
3620 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
3621 "wrote=%d\n",
3622 fsp->fnum, (double)startpos, (int)numtowrite,
3623 (int)total_written));
3625 /* We won't return a status if write through is not selected - this
3626 * follows what WfWg does */
3627 END_PROFILE(SMBwritebraw);
3629 if (!write_through && total_written==tcount) {
3631 #if RABBIT_PELLET_FIX
3633 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
3634 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
3635 * JRA.
3637 if (!send_keepalive(smbd_server_fd())) {
3638 exit_server_cleanly("reply_writebraw: send of "
3639 "keepalive failed");
3641 #endif
3642 TALLOC_FREE(req->outbuf);
3644 return;
3647 #undef DBGC_CLASS
3648 #define DBGC_CLASS DBGC_LOCKING
3650 /****************************************************************************
3651 Reply to a writeunlock (core+).
3652 ****************************************************************************/
3654 void reply_writeunlock(struct smb_request *req)
3656 connection_struct *conn = req->conn;
3657 ssize_t nwritten = -1;
3658 size_t numtowrite;
3659 SMB_OFF_T startpos;
3660 char *data;
3661 NTSTATUS status = NT_STATUS_OK;
3662 files_struct *fsp;
3664 START_PROFILE(SMBwriteunlock);
3666 if (req->wct < 5) {
3667 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3668 END_PROFILE(SMBwriteunlock);
3669 return;
3672 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3674 if (!check_fsp(conn, req, fsp, &current_user)) {
3675 END_PROFILE(SMBwriteunlock);
3676 return;
3679 if (!CHECK_WRITE(fsp)) {
3680 reply_doserror(req, ERRDOS,ERRbadaccess);
3681 END_PROFILE(SMBwriteunlock);
3682 return;
3685 numtowrite = SVAL(req->inbuf,smb_vwv1);
3686 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3687 data = smb_buf(req->inbuf) + 3;
3689 if (numtowrite
3690 && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
3691 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3692 reply_doserror(req, ERRDOS, ERRlock);
3693 END_PROFILE(SMBwriteunlock);
3694 return;
3697 /* The special X/Open SMB protocol handling of
3698 zero length writes is *NOT* done for
3699 this call */
3700 if(numtowrite == 0) {
3701 nwritten = 0;
3702 } else {
3703 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3706 status = sync_file(conn, fsp, False /* write through */);
3707 if (!NT_STATUS_IS_OK(status)) {
3708 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
3709 fsp->fsp_name, nt_errstr(status) ));
3710 reply_nterror(req, status);
3711 END_PROFILE(SMBwriteunlock);
3712 return;
3715 if(((nwritten < numtowrite) && (numtowrite != 0))||(nwritten < 0)) {
3716 reply_unixerror(req, ERRHRD, ERRdiskfull);
3717 END_PROFILE(SMBwriteunlock);
3718 return;
3721 if (numtowrite) {
3722 status = do_unlock(smbd_messaging_context(),
3723 fsp,
3724 req->smbpid,
3725 (SMB_BIG_UINT)numtowrite,
3726 (SMB_BIG_UINT)startpos,
3727 WINDOWS_LOCK);
3729 if (NT_STATUS_V(status)) {
3730 reply_nterror(req, status);
3731 END_PROFILE(SMBwriteunlock);
3732 return;
3736 reply_outbuf(req, 1, 0);
3738 SSVAL(req->outbuf,smb_vwv0,nwritten);
3740 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
3741 fsp->fnum, (int)numtowrite, (int)nwritten));
3743 END_PROFILE(SMBwriteunlock);
3744 return;
3747 #undef DBGC_CLASS
3748 #define DBGC_CLASS DBGC_ALL
3750 /****************************************************************************
3751 Reply to a write.
3752 ****************************************************************************/
3754 void reply_write(struct smb_request *req)
3756 connection_struct *conn = req->conn;
3757 size_t numtowrite;
3758 ssize_t nwritten = -1;
3759 SMB_OFF_T startpos;
3760 char *data;
3761 files_struct *fsp;
3762 NTSTATUS status;
3764 START_PROFILE(SMBwrite);
3766 if (req->wct < 5) {
3767 END_PROFILE(SMBwrite);
3768 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3769 return;
3772 /* If it's an IPC, pass off the pipe handler. */
3773 if (IS_IPC(conn)) {
3774 reply_pipe_write(req);
3775 END_PROFILE(SMBwrite);
3776 return;
3779 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3781 if (!check_fsp(conn, req, fsp, &current_user)) {
3782 END_PROFILE(SMBwrite);
3783 return;
3786 if (!CHECK_WRITE(fsp)) {
3787 reply_doserror(req, ERRDOS, ERRbadaccess);
3788 END_PROFILE(SMBwrite);
3789 return;
3792 numtowrite = SVAL(req->inbuf,smb_vwv1);
3793 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3794 data = smb_buf(req->inbuf) + 3;
3796 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
3797 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3798 reply_doserror(req, ERRDOS, ERRlock);
3799 END_PROFILE(SMBwrite);
3800 return;
3804 * X/Open SMB protocol says that if smb_vwv1 is
3805 * zero then the file size should be extended or
3806 * truncated to the size given in smb_vwv[2-3].
3809 if(numtowrite == 0) {
3811 * This is actually an allocate call, and set EOF. JRA.
3813 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
3814 if (nwritten < 0) {
3815 reply_nterror(req, NT_STATUS_DISK_FULL);
3816 END_PROFILE(SMBwrite);
3817 return;
3819 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
3820 if (nwritten < 0) {
3821 reply_nterror(req, NT_STATUS_DISK_FULL);
3822 END_PROFILE(SMBwrite);
3823 return;
3825 trigger_write_time_update_immediate(fsp);
3826 } else {
3827 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3830 status = sync_file(conn, fsp, False);
3831 if (!NT_STATUS_IS_OK(status)) {
3832 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
3833 fsp->fsp_name, nt_errstr(status) ));
3834 reply_nterror(req, status);
3835 END_PROFILE(SMBwrite);
3836 return;
3839 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
3840 reply_unixerror(req, ERRHRD, ERRdiskfull);
3841 END_PROFILE(SMBwrite);
3842 return;
3845 reply_outbuf(req, 1, 0);
3847 SSVAL(req->outbuf,smb_vwv0,nwritten);
3849 if (nwritten < (ssize_t)numtowrite) {
3850 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3851 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3854 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
3856 END_PROFILE(SMBwrite);
3857 return;
3860 /****************************************************************************
3861 Ensure a buffer is a valid writeX for recvfile purposes.
3862 ****************************************************************************/
3864 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
3865 (2*14) + /* word count (including bcc) */ \
3866 1 /* pad byte */)
3868 bool is_valid_writeX_buffer(const uint8_t *inbuf)
3870 size_t numtowrite;
3871 connection_struct *conn = NULL;
3872 unsigned int doff = 0;
3873 size_t len = smb_len_large(inbuf);
3875 if (is_encrypted_packet(inbuf)) {
3876 /* Can't do this on encrypted
3877 * connections. */
3878 return false;
3881 if (CVAL(inbuf,smb_com) != SMBwriteX) {
3882 return false;
3885 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
3886 CVAL(inbuf,smb_wct) != 14) {
3887 DEBUG(10,("is_valid_writeX_buffer: chained or "
3888 "invalid word length.\n"));
3889 return false;
3892 conn = conn_find(SVAL(inbuf, smb_tid));
3893 if (conn == NULL) {
3894 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
3895 return false;
3897 if (IS_IPC(conn)) {
3898 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
3899 return false;
3901 if (IS_PRINT(conn)) {
3902 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
3903 return false;
3905 doff = SVAL(inbuf,smb_vwv11);
3907 numtowrite = SVAL(inbuf,smb_vwv10);
3909 if (len > doff && len - doff > 0xFFFF) {
3910 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
3913 if (numtowrite == 0) {
3914 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
3915 return false;
3918 /* Ensure the sizes match up. */
3919 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
3920 /* no pad byte...old smbclient :-( */
3921 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
3922 (unsigned int)doff,
3923 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
3924 return false;
3927 if (len - doff != numtowrite) {
3928 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
3929 "len = %u, doff = %u, numtowrite = %u\n",
3930 (unsigned int)len,
3931 (unsigned int)doff,
3932 (unsigned int)numtowrite ));
3933 return false;
3936 DEBUG(10,("is_valid_writeX_buffer: true "
3937 "len = %u, doff = %u, numtowrite = %u\n",
3938 (unsigned int)len,
3939 (unsigned int)doff,
3940 (unsigned int)numtowrite ));
3942 return true;
3945 /****************************************************************************
3946 Reply to a write and X.
3947 ****************************************************************************/
3949 void reply_write_and_X(struct smb_request *req)
3951 connection_struct *conn = req->conn;
3952 files_struct *fsp;
3953 SMB_OFF_T startpos;
3954 size_t numtowrite;
3955 bool write_through;
3956 ssize_t nwritten;
3957 unsigned int smb_doff;
3958 unsigned int smblen;
3959 char *data;
3960 NTSTATUS status;
3962 START_PROFILE(SMBwriteX);
3964 if ((req->wct != 12) && (req->wct != 14)) {
3965 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3966 END_PROFILE(SMBwriteX);
3967 return;
3970 numtowrite = SVAL(req->inbuf,smb_vwv10);
3971 smb_doff = SVAL(req->inbuf,smb_vwv11);
3972 smblen = smb_len(req->inbuf);
3974 if (req->unread_bytes > 0xFFFF ||
3975 (smblen > smb_doff &&
3976 smblen - smb_doff > 0xFFFF)) {
3977 numtowrite |= (((size_t)SVAL(req->inbuf,smb_vwv9))<<16);
3980 if (req->unread_bytes) {
3981 /* Can't do a recvfile write on IPC$ */
3982 if (IS_IPC(conn)) {
3983 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3984 END_PROFILE(SMBwriteX);
3985 return;
3987 if (numtowrite != req->unread_bytes) {
3988 reply_doserror(req, ERRDOS, ERRbadmem);
3989 END_PROFILE(SMBwriteX);
3990 return;
3992 } else {
3993 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
3994 smb_doff + numtowrite > smblen) {
3995 reply_doserror(req, ERRDOS, ERRbadmem);
3996 END_PROFILE(SMBwriteX);
3997 return;
4001 /* If it's an IPC, pass off the pipe handler. */
4002 if (IS_IPC(conn)) {
4003 if (req->unread_bytes) {
4004 reply_doserror(req, ERRDOS, ERRbadmem);
4005 END_PROFILE(SMBwriteX);
4006 return;
4008 reply_pipe_write_and_X(req);
4009 END_PROFILE(SMBwriteX);
4010 return;
4013 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
4014 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
4015 write_through = BITSETW(req->inbuf+smb_vwv7,0);
4017 if (!check_fsp(conn, req, fsp, &current_user)) {
4018 END_PROFILE(SMBwriteX);
4019 return;
4022 if (!CHECK_WRITE(fsp)) {
4023 reply_doserror(req, ERRDOS, ERRbadaccess);
4024 END_PROFILE(SMBwriteX);
4025 return;
4028 data = smb_base(req->inbuf) + smb_doff;
4030 if(req->wct == 14) {
4031 #ifdef LARGE_SMB_OFF_T
4033 * This is a large offset (64 bit) write.
4035 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv12)) << 32);
4037 #else /* !LARGE_SMB_OFF_T */
4040 * Ensure we haven't been sent a >32 bit offset.
4043 if(IVAL(req->inbuf,smb_vwv12) != 0) {
4044 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4045 "used and we don't support 64 bit offsets.\n",
4046 (unsigned int)IVAL(req->inbuf,smb_vwv12) ));
4047 reply_doserror(req, ERRDOS, ERRbadaccess);
4048 END_PROFILE(SMBwriteX);
4049 return;
4052 #endif /* LARGE_SMB_OFF_T */
4055 if (is_locked(fsp,(uint32)req->smbpid,
4056 (SMB_BIG_UINT)numtowrite,
4057 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
4058 reply_doserror(req, ERRDOS, ERRlock);
4059 END_PROFILE(SMBwriteX);
4060 return;
4063 /* X/Open SMB protocol says that, unlike SMBwrite
4064 if the length is zero then NO truncation is
4065 done, just a write of zero. To truncate a file,
4066 use SMBwrite. */
4068 if(numtowrite == 0) {
4069 nwritten = 0;
4070 } else {
4072 if ((req->unread_bytes == 0) &&
4073 schedule_aio_write_and_X(conn, req, fsp, data, startpos,
4074 numtowrite)) {
4075 END_PROFILE(SMBwriteX);
4076 return;
4079 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4082 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4083 reply_unixerror(req, ERRHRD, ERRdiskfull);
4084 END_PROFILE(SMBwriteX);
4085 return;
4088 reply_outbuf(req, 6, 0);
4089 SSVAL(req->outbuf,smb_vwv2,nwritten);
4090 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4092 if (nwritten < (ssize_t)numtowrite) {
4093 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4094 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4097 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4098 fsp->fnum, (int)numtowrite, (int)nwritten));
4100 status = sync_file(conn, fsp, write_through);
4101 if (!NT_STATUS_IS_OK(status)) {
4102 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4103 fsp->fsp_name, nt_errstr(status) ));
4104 reply_nterror(req, status);
4105 END_PROFILE(SMBwriteX);
4106 return;
4109 END_PROFILE(SMBwriteX);
4110 chain_reply(req);
4111 return;
4114 /****************************************************************************
4115 Reply to a lseek.
4116 ****************************************************************************/
4118 void reply_lseek(struct smb_request *req)
4120 connection_struct *conn = req->conn;
4121 SMB_OFF_T startpos;
4122 SMB_OFF_T res= -1;
4123 int mode,umode;
4124 files_struct *fsp;
4126 START_PROFILE(SMBlseek);
4128 if (req->wct < 4) {
4129 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4130 END_PROFILE(SMBlseek);
4131 return;
4134 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4136 if (!check_fsp(conn, req, fsp, &current_user)) {
4137 return;
4140 flush_write_cache(fsp, SEEK_FLUSH);
4142 mode = SVAL(req->inbuf,smb_vwv1) & 3;
4143 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4144 startpos = (SMB_OFF_T)IVALS(req->inbuf,smb_vwv2);
4146 switch (mode) {
4147 case 0:
4148 umode = SEEK_SET;
4149 res = startpos;
4150 break;
4151 case 1:
4152 umode = SEEK_CUR;
4153 res = fsp->fh->pos + startpos;
4154 break;
4155 case 2:
4156 umode = SEEK_END;
4157 break;
4158 default:
4159 umode = SEEK_SET;
4160 res = startpos;
4161 break;
4164 if (umode == SEEK_END) {
4165 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4166 if(errno == EINVAL) {
4167 SMB_OFF_T current_pos = startpos;
4168 SMB_STRUCT_STAT sbuf;
4170 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
4171 reply_unixerror(req, ERRDOS,
4172 ERRnoaccess);
4173 END_PROFILE(SMBlseek);
4174 return;
4177 current_pos += sbuf.st_size;
4178 if(current_pos < 0)
4179 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4183 if(res == -1) {
4184 reply_unixerror(req, ERRDOS, ERRnoaccess);
4185 END_PROFILE(SMBlseek);
4186 return;
4190 fsp->fh->pos = res;
4192 reply_outbuf(req, 2, 0);
4193 SIVAL(req->outbuf,smb_vwv0,res);
4195 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4196 fsp->fnum, (double)startpos, (double)res, mode));
4198 END_PROFILE(SMBlseek);
4199 return;
4202 /****************************************************************************
4203 Reply to a flush.
4204 ****************************************************************************/
4206 void reply_flush(struct smb_request *req)
4208 connection_struct *conn = req->conn;
4209 uint16 fnum;
4210 files_struct *fsp;
4212 START_PROFILE(SMBflush);
4214 if (req->wct < 1) {
4215 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4216 return;
4219 fnum = SVAL(req->inbuf,smb_vwv0);
4220 fsp = file_fsp(fnum);
4222 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp, &current_user)) {
4223 return;
4226 if (!fsp) {
4227 file_sync_all(conn);
4228 } else {
4229 NTSTATUS status = sync_file(conn, fsp, True);
4230 if (!NT_STATUS_IS_OK(status)) {
4231 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4232 fsp->fsp_name, nt_errstr(status) ));
4233 reply_nterror(req, status);
4234 END_PROFILE(SMBflush);
4235 return;
4239 reply_outbuf(req, 0, 0);
4241 DEBUG(3,("flush\n"));
4242 END_PROFILE(SMBflush);
4243 return;
4246 /****************************************************************************
4247 Reply to a exit.
4248 conn POINTER CAN BE NULL HERE !
4249 ****************************************************************************/
4251 void reply_exit(struct smb_request *req)
4253 START_PROFILE(SMBexit);
4255 file_close_pid(req->smbpid, req->vuid);
4257 reply_outbuf(req, 0, 0);
4259 DEBUG(3,("exit\n"));
4261 END_PROFILE(SMBexit);
4262 return;
4265 /****************************************************************************
4266 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4267 ****************************************************************************/
4269 void reply_close(struct smb_request *req)
4271 connection_struct *conn = req->conn;
4272 NTSTATUS status = NT_STATUS_OK;
4273 files_struct *fsp = NULL;
4274 START_PROFILE(SMBclose);
4276 if (req->wct < 3) {
4277 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4278 END_PROFILE(SMBclose);
4279 return;
4282 /* If it's an IPC, pass off to the pipe handler. */
4283 if (IS_IPC(conn)) {
4284 reply_pipe_close(conn, req);
4285 END_PROFILE(SMBclose);
4286 return;
4289 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4292 * We can only use CHECK_FSP if we know it's not a directory.
4295 if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) {
4296 reply_doserror(req, ERRDOS, ERRbadfid);
4297 END_PROFILE(SMBclose);
4298 return;
4301 if(fsp->is_directory) {
4303 * Special case - close NT SMB directory handle.
4305 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4306 status = close_file(fsp,NORMAL_CLOSE);
4307 } else {
4308 time_t t;
4310 * Close ordinary file.
4313 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4314 fsp->fh->fd, fsp->fnum,
4315 conn->num_files_open));
4318 * Take care of any time sent in the close.
4321 t = srv_make_unix_date3(req->inbuf+smb_vwv1);
4322 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4325 * close_file() returns the unix errno if an error
4326 * was detected on close - normally this is due to
4327 * a disk full error. If not then it was probably an I/O error.
4330 status = close_file(fsp,NORMAL_CLOSE);
4333 if (!NT_STATUS_IS_OK(status)) {
4334 reply_nterror(req, status);
4335 END_PROFILE(SMBclose);
4336 return;
4339 reply_outbuf(req, 0, 0);
4340 END_PROFILE(SMBclose);
4341 return;
4344 /****************************************************************************
4345 Reply to a writeclose (Core+ protocol).
4346 ****************************************************************************/
4348 void reply_writeclose(struct smb_request *req)
4350 connection_struct *conn = req->conn;
4351 size_t numtowrite;
4352 ssize_t nwritten = -1;
4353 NTSTATUS close_status = NT_STATUS_OK;
4354 SMB_OFF_T startpos;
4355 char *data;
4356 struct timespec mtime;
4357 files_struct *fsp;
4359 START_PROFILE(SMBwriteclose);
4361 if (req->wct < 6) {
4362 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4363 END_PROFILE(SMBwriteclose);
4364 return;
4367 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4369 if (!check_fsp(conn, req, fsp, &current_user)) {
4370 END_PROFILE(SMBwriteclose);
4371 return;
4373 if (!CHECK_WRITE(fsp)) {
4374 reply_doserror(req, ERRDOS,ERRbadaccess);
4375 END_PROFILE(SMBwriteclose);
4376 return;
4379 numtowrite = SVAL(req->inbuf,smb_vwv1);
4380 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
4381 mtime = convert_time_t_to_timespec(srv_make_unix_date3(
4382 req->inbuf+smb_vwv4));
4383 data = smb_buf(req->inbuf) + 1;
4385 if (numtowrite
4386 && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
4387 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
4388 reply_doserror(req, ERRDOS,ERRlock);
4389 END_PROFILE(SMBwriteclose);
4390 return;
4393 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4395 set_close_write_time(fsp, mtime);
4398 * More insanity. W2K only closes the file if writelen > 0.
4399 * JRA.
4402 if (numtowrite) {
4403 DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
4404 fsp->fsp_name ));
4405 close_status = close_file(fsp,NORMAL_CLOSE);
4408 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4409 fsp->fnum, (int)numtowrite, (int)nwritten,
4410 conn->num_files_open));
4412 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4413 reply_doserror(req, ERRHRD, ERRdiskfull);
4414 END_PROFILE(SMBwriteclose);
4415 return;
4418 if(!NT_STATUS_IS_OK(close_status)) {
4419 reply_nterror(req, close_status);
4420 END_PROFILE(SMBwriteclose);
4421 return;
4424 reply_outbuf(req, 1, 0);
4426 SSVAL(req->outbuf,smb_vwv0,nwritten);
4427 END_PROFILE(SMBwriteclose);
4428 return;
4431 #undef DBGC_CLASS
4432 #define DBGC_CLASS DBGC_LOCKING
4434 /****************************************************************************
4435 Reply to a lock.
4436 ****************************************************************************/
4438 void reply_lock(struct smb_request *req)
4440 connection_struct *conn = req->conn;
4441 SMB_BIG_UINT count,offset;
4442 NTSTATUS status;
4443 files_struct *fsp;
4444 struct byte_range_lock *br_lck = NULL;
4446 START_PROFILE(SMBlock);
4448 if (req->wct < 5) {
4449 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4450 END_PROFILE(SMBlock);
4451 return;
4454 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4456 if (!check_fsp(conn, req, fsp, &current_user)) {
4457 END_PROFILE(SMBlock);
4458 return;
4461 release_level_2_oplocks_on_change(fsp);
4463 count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
4464 offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
4466 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4467 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4469 br_lck = do_lock(smbd_messaging_context(),
4470 fsp,
4471 req->smbpid,
4472 count,
4473 offset,
4474 WRITE_LOCK,
4475 WINDOWS_LOCK,
4476 False, /* Non-blocking lock. */
4477 &status,
4478 NULL);
4480 TALLOC_FREE(br_lck);
4482 if (NT_STATUS_V(status)) {
4483 reply_nterror(req, status);
4484 END_PROFILE(SMBlock);
4485 return;
4488 reply_outbuf(req, 0, 0);
4490 END_PROFILE(SMBlock);
4491 return;
4494 /****************************************************************************
4495 Reply to a unlock.
4496 ****************************************************************************/
4498 void reply_unlock(struct smb_request *req)
4500 connection_struct *conn = req->conn;
4501 SMB_BIG_UINT count,offset;
4502 NTSTATUS status;
4503 files_struct *fsp;
4505 START_PROFILE(SMBunlock);
4507 if (req->wct < 5) {
4508 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4509 END_PROFILE(SMBunlock);
4510 return;
4513 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4515 if (!check_fsp(conn, req, fsp, &current_user)) {
4516 END_PROFILE(SMBunlock);
4517 return;
4520 count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
4521 offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
4523 status = do_unlock(smbd_messaging_context(),
4524 fsp,
4525 req->smbpid,
4526 count,
4527 offset,
4528 WINDOWS_LOCK);
4530 if (NT_STATUS_V(status)) {
4531 reply_nterror(req, status);
4532 END_PROFILE(SMBunlock);
4533 return;
4536 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4537 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
4539 reply_outbuf(req, 0, 0);
4541 END_PROFILE(SMBunlock);
4542 return;
4545 #undef DBGC_CLASS
4546 #define DBGC_CLASS DBGC_ALL
4548 /****************************************************************************
4549 Reply to a tdis.
4550 conn POINTER CAN BE NULL HERE !
4551 ****************************************************************************/
4553 void reply_tdis(struct smb_request *req)
4555 connection_struct *conn = req->conn;
4556 START_PROFILE(SMBtdis);
4558 if (!conn) {
4559 DEBUG(4,("Invalid connection in tdis\n"));
4560 reply_doserror(req, ERRSRV, ERRinvnid);
4561 END_PROFILE(SMBtdis);
4562 return;
4565 conn->used = False;
4567 close_cnum(conn,req->vuid);
4568 req->conn = NULL;
4570 reply_outbuf(req, 0, 0);
4571 END_PROFILE(SMBtdis);
4572 return;
4575 /****************************************************************************
4576 Reply to a echo.
4577 conn POINTER CAN BE NULL HERE !
4578 ****************************************************************************/
4580 void reply_echo(struct smb_request *req)
4582 connection_struct *conn = req->conn;
4583 int smb_reverb;
4584 int seq_num;
4585 unsigned int data_len = smb_buflen(req->inbuf);
4587 START_PROFILE(SMBecho);
4589 if (req->wct < 1) {
4590 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4591 END_PROFILE(SMBecho);
4592 return;
4595 if (data_len > BUFFER_SIZE) {
4596 DEBUG(0,("reply_echo: data_len too large.\n"));
4597 reply_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
4598 END_PROFILE(SMBecho);
4599 return;
4602 smb_reverb = SVAL(req->inbuf,smb_vwv0);
4604 reply_outbuf(req, 1, data_len);
4606 /* copy any incoming data back out */
4607 if (data_len > 0) {
4608 memcpy(smb_buf(req->outbuf),smb_buf(req->inbuf),data_len);
4611 if (smb_reverb > 100) {
4612 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
4613 smb_reverb = 100;
4616 for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
4617 SSVAL(req->outbuf,smb_vwv0,seq_num);
4619 show_msg((char *)req->outbuf);
4620 if (!srv_send_smb(smbd_server_fd(),
4621 (char *)req->outbuf,
4622 IS_CONN_ENCRYPTED(conn)||req->encrypted))
4623 exit_server_cleanly("reply_echo: srv_send_smb failed.");
4626 DEBUG(3,("echo %d times\n", smb_reverb));
4628 TALLOC_FREE(req->outbuf);
4630 smb_echo_count++;
4632 END_PROFILE(SMBecho);
4633 return;
4636 /****************************************************************************
4637 Reply to a printopen.
4638 ****************************************************************************/
4640 void reply_printopen(struct smb_request *req)
4642 connection_struct *conn = req->conn;
4643 files_struct *fsp;
4644 NTSTATUS status;
4645 SMB_STRUCT_STAT sbuf;
4647 START_PROFILE(SMBsplopen);
4649 if (req->wct < 2) {
4650 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4651 END_PROFILE(SMBsplopen);
4652 return;
4655 if (!CAN_PRINT(conn)) {
4656 reply_doserror(req, ERRDOS, ERRnoaccess);
4657 END_PROFILE(SMBsplopen);
4658 return;
4661 status = file_new(conn, &fsp);
4662 if(!NT_STATUS_IS_OK(status)) {
4663 reply_nterror(req, status);
4664 END_PROFILE(SMBsplopen);
4665 return;
4668 /* Open for exclusive use, write only. */
4669 status = print_fsp_open(conn, NULL, fsp, &sbuf);
4671 if (!NT_STATUS_IS_OK(status)) {
4672 file_free(fsp);
4673 reply_nterror(req, status);
4674 END_PROFILE(SMBsplopen);
4675 return;
4678 reply_outbuf(req, 1, 0);
4679 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
4681 DEBUG(3,("openprint fd=%d fnum=%d\n",
4682 fsp->fh->fd, fsp->fnum));
4684 END_PROFILE(SMBsplopen);
4685 return;
4688 /****************************************************************************
4689 Reply to a printclose.
4690 ****************************************************************************/
4692 void reply_printclose(struct smb_request *req)
4694 connection_struct *conn = req->conn;
4695 files_struct *fsp;
4696 NTSTATUS status;
4698 START_PROFILE(SMBsplclose);
4700 if (req->wct < 1) {
4701 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4702 END_PROFILE(SMBsplclose);
4703 return;
4706 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4708 if (!check_fsp(conn, req, fsp, &current_user)) {
4709 END_PROFILE(SMBsplclose);
4710 return;
4713 if (!CAN_PRINT(conn)) {
4714 reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
4715 END_PROFILE(SMBsplclose);
4716 return;
4719 DEBUG(3,("printclose fd=%d fnum=%d\n",
4720 fsp->fh->fd,fsp->fnum));
4722 status = close_file(fsp,NORMAL_CLOSE);
4724 if(!NT_STATUS_IS_OK(status)) {
4725 reply_nterror(req, status);
4726 END_PROFILE(SMBsplclose);
4727 return;
4730 reply_outbuf(req, 0, 0);
4732 END_PROFILE(SMBsplclose);
4733 return;
4736 /****************************************************************************
4737 Reply to a printqueue.
4738 ****************************************************************************/
4740 void reply_printqueue(struct smb_request *req)
4742 connection_struct *conn = req->conn;
4743 int max_count;
4744 int start_index;
4746 START_PROFILE(SMBsplretq);
4748 if (req->wct < 2) {
4749 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4750 END_PROFILE(SMBsplretq);
4751 return;
4754 max_count = SVAL(req->inbuf,smb_vwv0);
4755 start_index = SVAL(req->inbuf,smb_vwv1);
4757 /* we used to allow the client to get the cnum wrong, but that
4758 is really quite gross and only worked when there was only
4759 one printer - I think we should now only accept it if they
4760 get it right (tridge) */
4761 if (!CAN_PRINT(conn)) {
4762 reply_doserror(req, ERRDOS, ERRnoaccess);
4763 END_PROFILE(SMBsplretq);
4764 return;
4767 reply_outbuf(req, 2, 3);
4768 SSVAL(req->outbuf,smb_vwv0,0);
4769 SSVAL(req->outbuf,smb_vwv1,0);
4770 SCVAL(smb_buf(req->outbuf),0,1);
4771 SSVAL(smb_buf(req->outbuf),1,0);
4773 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
4774 start_index, max_count));
4777 print_queue_struct *queue = NULL;
4778 print_status_struct status;
4779 int count = print_queue_status(SNUM(conn), &queue, &status);
4780 int num_to_get = ABS(max_count);
4781 int first = (max_count>0?start_index:start_index+max_count+1);
4782 int i;
4784 if (first >= count)
4785 num_to_get = 0;
4786 else
4787 num_to_get = MIN(num_to_get,count-first);
4790 for (i=first;i<first+num_to_get;i++) {
4791 char blob[28];
4792 char *p = blob;
4794 srv_put_dos_date2(p,0,queue[i].time);
4795 SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
4796 SSVAL(p,5, queue[i].job);
4797 SIVAL(p,7,queue[i].size);
4798 SCVAL(p,11,0);
4799 srvstr_push(blob, req->flags2, p+12,
4800 queue[i].fs_user, 16, STR_ASCII);
4802 if (message_push_blob(
4803 &req->outbuf,
4804 data_blob_const(
4805 blob, sizeof(blob))) == -1) {
4806 reply_nterror(req, NT_STATUS_NO_MEMORY);
4807 END_PROFILE(SMBsplretq);
4808 return;
4812 if (count > 0) {
4813 SSVAL(req->outbuf,smb_vwv0,count);
4814 SSVAL(req->outbuf,smb_vwv1,
4815 (max_count>0?first+count:first-1));
4816 SCVAL(smb_buf(req->outbuf),0,1);
4817 SSVAL(smb_buf(req->outbuf),1,28*count);
4820 SAFE_FREE(queue);
4822 DEBUG(3,("%d entries returned in queue\n",count));
4825 END_PROFILE(SMBsplretq);
4826 return;
4829 /****************************************************************************
4830 Reply to a printwrite.
4831 ****************************************************************************/
4833 void reply_printwrite(struct smb_request *req)
4835 connection_struct *conn = req->conn;
4836 int numtowrite;
4837 char *data;
4838 files_struct *fsp;
4840 START_PROFILE(SMBsplwr);
4842 if (req->wct < 1) {
4843 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4844 END_PROFILE(SMBsplwr);
4845 return;
4848 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4850 if (!check_fsp(conn, req, fsp, &current_user)) {
4851 END_PROFILE(SMBsplwr);
4852 return;
4855 if (!CAN_PRINT(conn)) {
4856 reply_doserror(req, ERRDOS, ERRnoaccess);
4857 END_PROFILE(SMBsplwr);
4858 return;
4861 if (!CHECK_WRITE(fsp)) {
4862 reply_doserror(req, ERRDOS, ERRbadaccess);
4863 END_PROFILE(SMBsplwr);
4864 return;
4867 numtowrite = SVAL(smb_buf(req->inbuf),1);
4869 if (smb_buflen(req->inbuf) < numtowrite + 3) {
4870 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4871 END_PROFILE(SMBsplwr);
4872 return;
4875 data = smb_buf(req->inbuf) + 3;
4877 if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) {
4878 reply_unixerror(req, ERRHRD, ERRdiskfull);
4879 END_PROFILE(SMBsplwr);
4880 return;
4883 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
4885 END_PROFILE(SMBsplwr);
4886 return;
4889 /****************************************************************************
4890 Reply to a mkdir.
4891 ****************************************************************************/
4893 void reply_mkdir(struct smb_request *req)
4895 connection_struct *conn = req->conn;
4896 char *directory = NULL;
4897 NTSTATUS status;
4898 SMB_STRUCT_STAT sbuf;
4899 TALLOC_CTX *ctx = talloc_tos();
4901 START_PROFILE(SMBmkdir);
4903 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
4904 smb_buf(req->inbuf) + 1, 0,
4905 STR_TERMINATE, &status);
4906 if (!NT_STATUS_IS_OK(status)) {
4907 reply_nterror(req, status);
4908 END_PROFILE(SMBmkdir);
4909 return;
4912 status = resolve_dfspath(ctx, conn,
4913 req->flags2 & FLAGS2_DFS_PATHNAMES,
4914 directory,
4915 &directory);
4916 if (!NT_STATUS_IS_OK(status)) {
4917 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4918 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
4919 ERRSRV, ERRbadpath);
4920 END_PROFILE(SMBmkdir);
4921 return;
4923 reply_nterror(req, status);
4924 END_PROFILE(SMBmkdir);
4925 return;
4928 status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
4929 if (!NT_STATUS_IS_OK(status)) {
4930 reply_nterror(req, status);
4931 END_PROFILE(SMBmkdir);
4932 return;
4935 status = check_name(conn, directory);
4936 if (!NT_STATUS_IS_OK(status)) {
4937 reply_nterror(req, status);
4938 END_PROFILE(SMBmkdir);
4939 return;
4942 status = create_directory(conn, req, directory);
4944 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
4946 if (!NT_STATUS_IS_OK(status)) {
4948 if (!use_nt_status()
4949 && NT_STATUS_EQUAL(status,
4950 NT_STATUS_OBJECT_NAME_COLLISION)) {
4952 * Yes, in the DOS error code case we get a
4953 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
4954 * samba4 torture test.
4956 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
4959 reply_nterror(req, status);
4960 END_PROFILE(SMBmkdir);
4961 return;
4964 reply_outbuf(req, 0, 0);
4966 DEBUG( 3, ( "mkdir %s\n", directory ) );
4968 END_PROFILE(SMBmkdir);
4969 return;
4972 /****************************************************************************
4973 Static function used by reply_rmdir to delete an entire directory
4974 tree recursively. Return True on ok, False on fail.
4975 ****************************************************************************/
4977 static bool recursive_rmdir(TALLOC_CTX *ctx,
4978 connection_struct *conn,
4979 char *directory)
4981 const char *dname = NULL;
4982 bool ret = True;
4983 long offset = 0;
4984 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, directory,
4985 NULL, 0);
4987 if(dir_hnd == NULL)
4988 return False;
4990 while((dname = ReadDirName(dir_hnd, &offset))) {
4991 char *fullname = NULL;
4992 SMB_STRUCT_STAT st;
4994 if (ISDOT(dname) || ISDOTDOT(dname)) {
4995 continue;
4998 if (!is_visible_file(conn, directory, dname, &st, False)) {
4999 continue;
5002 /* Construct the full name. */
5003 fullname = talloc_asprintf(ctx,
5004 "%s/%s",
5005 directory,
5006 dname);
5007 if (!fullname) {
5008 errno = ENOMEM;
5009 ret = False;
5010 break;
5013 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
5014 ret = False;
5015 break;
5018 if(st.st_mode & S_IFDIR) {
5019 if(!recursive_rmdir(ctx, conn, fullname)) {
5020 ret = False;
5021 break;
5023 if(SMB_VFS_RMDIR(conn,fullname) != 0) {
5024 ret = False;
5025 break;
5027 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
5028 ret = False;
5029 break;
5031 TALLOC_FREE(fullname);
5033 TALLOC_FREE(dir_hnd);
5034 return ret;
5037 /****************************************************************************
5038 The internals of the rmdir code - called elsewhere.
5039 ****************************************************************************/
5041 NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
5042 connection_struct *conn,
5043 const char *directory)
5045 int ret;
5046 SMB_STRUCT_STAT st;
5048 /* Might be a symlink. */
5049 if(SMB_VFS_LSTAT(conn, directory, &st) != 0) {
5050 return map_nt_error_from_unix(errno);
5053 if (S_ISLNK(st.st_mode)) {
5054 /* Is what it points to a directory ? */
5055 if(SMB_VFS_STAT(conn, directory, &st) != 0) {
5056 return map_nt_error_from_unix(errno);
5058 if (!(S_ISDIR(st.st_mode))) {
5059 return NT_STATUS_NOT_A_DIRECTORY;
5061 ret = SMB_VFS_UNLINK(conn,directory);
5062 } else {
5063 ret = SMB_VFS_RMDIR(conn,directory);
5065 if (ret == 0) {
5066 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5067 FILE_NOTIFY_CHANGE_DIR_NAME,
5068 directory);
5069 return NT_STATUS_OK;
5072 if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
5074 * Check to see if the only thing in this directory are
5075 * vetoed files/directories. If so then delete them and
5076 * retry. If we fail to delete any of them (and we *don't*
5077 * do a recursive delete) then fail the rmdir.
5079 const char *dname;
5080 long dirpos = 0;
5081 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
5082 directory, NULL, 0);
5084 if(dir_hnd == NULL) {
5085 errno = ENOTEMPTY;
5086 goto err;
5089 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
5090 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
5091 continue;
5092 if (!is_visible_file(conn, directory, dname, &st, False))
5093 continue;
5094 if(!IS_VETO_PATH(conn, dname)) {
5095 TALLOC_FREE(dir_hnd);
5096 errno = ENOTEMPTY;
5097 goto err;
5101 /* We only have veto files/directories.
5102 * Are we allowed to delete them ? */
5104 if(!lp_recursive_veto_delete(SNUM(conn))) {
5105 TALLOC_FREE(dir_hnd);
5106 errno = ENOTEMPTY;
5107 goto err;
5110 /* Do a recursive delete. */
5111 RewindDir(dir_hnd,&dirpos);
5112 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
5113 char *fullname = NULL;
5115 if (ISDOT(dname) || ISDOTDOT(dname)) {
5116 continue;
5118 if (!is_visible_file(conn, directory, dname, &st, False)) {
5119 continue;
5122 fullname = talloc_asprintf(ctx,
5123 "%s/%s",
5124 directory,
5125 dname);
5127 if(!fullname) {
5128 errno = ENOMEM;
5129 break;
5132 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
5133 break;
5135 if(st.st_mode & S_IFDIR) {
5136 if(!recursive_rmdir(ctx, conn, fullname)) {
5137 break;
5139 if(SMB_VFS_RMDIR(conn,fullname) != 0) {
5140 break;
5142 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
5143 break;
5145 TALLOC_FREE(fullname);
5147 TALLOC_FREE(dir_hnd);
5148 /* Retry the rmdir */
5149 ret = SMB_VFS_RMDIR(conn,directory);
5152 err:
5154 if (ret != 0) {
5155 DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
5156 "%s\n", directory,strerror(errno)));
5157 return map_nt_error_from_unix(errno);
5160 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5161 FILE_NOTIFY_CHANGE_DIR_NAME,
5162 directory);
5164 return NT_STATUS_OK;
5167 /****************************************************************************
5168 Reply to a rmdir.
5169 ****************************************************************************/
5171 void reply_rmdir(struct smb_request *req)
5173 connection_struct *conn = req->conn;
5174 char *directory = NULL;
5175 SMB_STRUCT_STAT sbuf;
5176 NTSTATUS status;
5177 TALLOC_CTX *ctx = talloc_tos();
5179 START_PROFILE(SMBrmdir);
5181 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
5182 smb_buf(req->inbuf) + 1, 0,
5183 STR_TERMINATE, &status);
5184 if (!NT_STATUS_IS_OK(status)) {
5185 reply_nterror(req, status);
5186 END_PROFILE(SMBrmdir);
5187 return;
5190 status = resolve_dfspath(ctx, conn,
5191 req->flags2 & FLAGS2_DFS_PATHNAMES,
5192 directory,
5193 &directory);
5194 if (!NT_STATUS_IS_OK(status)) {
5195 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5196 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5197 ERRSRV, ERRbadpath);
5198 END_PROFILE(SMBrmdir);
5199 return;
5201 reply_nterror(req, status);
5202 END_PROFILE(SMBrmdir);
5203 return;
5206 status = unix_convert(ctx, conn, directory, False, &directory,
5207 NULL, &sbuf);
5208 if (!NT_STATUS_IS_OK(status)) {
5209 reply_nterror(req, status);
5210 END_PROFILE(SMBrmdir);
5211 return;
5214 status = check_name(conn, directory);
5215 if (!NT_STATUS_IS_OK(status)) {
5216 reply_nterror(req, status);
5217 END_PROFILE(SMBrmdir);
5218 return;
5221 dptr_closepath(directory, req->smbpid);
5222 status = rmdir_internals(ctx, conn, directory);
5223 if (!NT_STATUS_IS_OK(status)) {
5224 reply_nterror(req, status);
5225 END_PROFILE(SMBrmdir);
5226 return;
5229 reply_outbuf(req, 0, 0);
5231 DEBUG( 3, ( "rmdir %s\n", directory ) );
5233 END_PROFILE(SMBrmdir);
5234 return;
5237 /*******************************************************************
5238 Resolve wildcards in a filename rename.
5239 ********************************************************************/
5241 static bool resolve_wildcards(TALLOC_CTX *ctx,
5242 const char *name1,
5243 const char *name2,
5244 char **pp_newname)
5246 char *name2_copy = NULL;
5247 char *root1 = NULL;
5248 char *root2 = NULL;
5249 char *ext1 = NULL;
5250 char *ext2 = NULL;
5251 char *p,*p2, *pname1, *pname2;
5253 name2_copy = talloc_strdup(ctx, name2);
5254 if (!name2_copy) {
5255 return False;
5258 pname1 = strrchr_m(name1,'/');
5259 pname2 = strrchr_m(name2_copy,'/');
5261 if (!pname1 || !pname2) {
5262 return False;
5265 /* Truncate the copy of name2 at the last '/' */
5266 *pname2 = '\0';
5268 /* Now go past the '/' */
5269 pname1++;
5270 pname2++;
5272 root1 = talloc_strdup(ctx, pname1);
5273 root2 = talloc_strdup(ctx, pname2);
5275 if (!root1 || !root2) {
5276 return False;
5279 p = strrchr_m(root1,'.');
5280 if (p) {
5281 *p = 0;
5282 ext1 = talloc_strdup(ctx, p+1);
5283 } else {
5284 ext1 = talloc_strdup(ctx, "");
5286 p = strrchr_m(root2,'.');
5287 if (p) {
5288 *p = 0;
5289 ext2 = talloc_strdup(ctx, p+1);
5290 } else {
5291 ext2 = talloc_strdup(ctx, "");
5294 if (!ext1 || !ext2) {
5295 return False;
5298 p = root1;
5299 p2 = root2;
5300 while (*p2) {
5301 if (*p2 == '?') {
5302 /* Hmmm. Should this be mb-aware ? */
5303 *p2 = *p;
5304 p2++;
5305 } else if (*p2 == '*') {
5306 *p2 = '\0';
5307 root2 = talloc_asprintf(ctx, "%s%s",
5308 root2,
5310 if (!root2) {
5311 return False;
5313 break;
5314 } else {
5315 p2++;
5317 if (*p) {
5318 p++;
5322 p = ext1;
5323 p2 = ext2;
5324 while (*p2) {
5325 if (*p2 == '?') {
5326 /* Hmmm. Should this be mb-aware ? */
5327 *p2 = *p;
5328 p2++;
5329 } else if (*p2 == '*') {
5330 *p2 = '\0';
5331 ext2 = talloc_asprintf(ctx, "%s%s",
5332 ext2,
5334 if (!ext2) {
5335 return False;
5337 break;
5338 } else {
5339 p2++;
5341 if (*p) {
5342 p++;
5346 if (*ext2) {
5347 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5348 name2_copy,
5349 root2,
5350 ext2);
5351 } else {
5352 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5353 name2_copy,
5354 root2);
5357 if (!*pp_newname) {
5358 return False;
5361 return True;
5364 /****************************************************************************
5365 Ensure open files have their names updated. Updated to notify other smbd's
5366 asynchronously.
5367 ****************************************************************************/
5369 static void rename_open_files(connection_struct *conn,
5370 struct share_mode_lock *lck,
5371 const char *newname)
5373 files_struct *fsp;
5374 bool did_rename = False;
5376 for(fsp = file_find_di_first(lck->id); fsp;
5377 fsp = file_find_di_next(fsp)) {
5378 /* fsp_name is a relative path under the fsp. To change this for other
5379 sharepaths we need to manipulate relative paths. */
5380 /* TODO - create the absolute path and manipulate the newname
5381 relative to the sharepath. */
5382 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5383 continue;
5385 DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n",
5386 fsp->fnum, file_id_string_tos(&fsp->file_id),
5387 fsp->fsp_name, newname ));
5388 string_set(&fsp->fsp_name, newname);
5389 did_rename = True;
5392 if (!did_rename) {
5393 DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n",
5394 file_id_string_tos(&lck->id), newname ));
5397 /* Send messages to all smbd's (not ourself) that the name has changed. */
5398 rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
5399 newname);
5402 /****************************************************************************
5403 We need to check if the source path is a parent directory of the destination
5404 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5405 refuse the rename with a sharing violation. Under UNIX the above call can
5406 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5407 probably need to check that the client is a Windows one before disallowing
5408 this as a UNIX client (one with UNIX extensions) can know the source is a
5409 symlink and make this decision intelligently. Found by an excellent bug
5410 report from <AndyLiebman@aol.com>.
5411 ****************************************************************************/
5413 static bool rename_path_prefix_equal(const char *src, const char *dest)
5415 const char *psrc = src;
5416 const char *pdst = dest;
5417 size_t slen;
5419 if (psrc[0] == '.' && psrc[1] == '/') {
5420 psrc += 2;
5422 if (pdst[0] == '.' && pdst[1] == '/') {
5423 pdst += 2;
5425 if ((slen = strlen(psrc)) > strlen(pdst)) {
5426 return False;
5428 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5432 * Do the notify calls from a rename
5435 static void notify_rename(connection_struct *conn, bool is_dir,
5436 const char *oldpath, const char *newpath)
5438 char *olddir, *newdir;
5439 const char *oldname, *newname;
5440 uint32 mask;
5442 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5443 : FILE_NOTIFY_CHANGE_FILE_NAME;
5445 if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
5446 || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
5447 TALLOC_FREE(olddir);
5448 return;
5451 if (strcmp(olddir, newdir) == 0) {
5452 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
5453 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
5455 else {
5456 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
5457 notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
5459 TALLOC_FREE(olddir);
5460 TALLOC_FREE(newdir);
5462 /* this is a strange one. w2k3 gives an additional event for
5463 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5464 files, but not directories */
5465 if (!is_dir) {
5466 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5467 FILE_NOTIFY_CHANGE_ATTRIBUTES
5468 |FILE_NOTIFY_CHANGE_CREATION,
5469 newpath);
5473 /****************************************************************************
5474 Rename an open file - given an fsp.
5475 ****************************************************************************/
5477 NTSTATUS rename_internals_fsp(connection_struct *conn,
5478 files_struct *fsp,
5479 char *newname,
5480 const char *newname_last_component,
5481 uint32 attrs,
5482 bool replace_if_exists)
5484 TALLOC_CTX *ctx = talloc_tos();
5485 SMB_STRUCT_STAT sbuf, sbuf1;
5486 NTSTATUS status = NT_STATUS_OK;
5487 struct share_mode_lock *lck = NULL;
5488 bool dst_exists, old_is_stream, new_is_stream;
5490 ZERO_STRUCT(sbuf);
5492 status = check_name(conn, newname);
5493 if (!NT_STATUS_IS_OK(status)) {
5494 return status;
5497 /* Ensure newname contains a '/' */
5498 if(strrchr_m(newname,'/') == 0) {
5499 newname = talloc_asprintf(ctx,
5500 "./%s",
5501 newname);
5502 if (!newname) {
5503 return NT_STATUS_NO_MEMORY;
5508 * Check for special case with case preserving and not
5509 * case sensitive. If the old last component differs from the original
5510 * last component only by case, then we should allow
5511 * the rename (user is trying to change the case of the
5512 * filename).
5515 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5516 strequal(newname, fsp->fsp_name)) {
5517 char *p;
5518 char *newname_modified_last_component = NULL;
5521 * Get the last component of the modified name.
5522 * Note that we guarantee that newname contains a '/'
5523 * character above.
5525 p = strrchr_m(newname,'/');
5526 newname_modified_last_component = talloc_strdup(ctx,
5527 p+1);
5528 if (!newname_modified_last_component) {
5529 return NT_STATUS_NO_MEMORY;
5532 if(strcsequal(newname_modified_last_component,
5533 newname_last_component) == False) {
5535 * Replace the modified last component with
5536 * the original.
5538 *p = '\0'; /* Truncate at the '/' */
5539 newname = talloc_asprintf(ctx,
5540 "%s/%s",
5541 newname,
5542 newname_last_component);
5547 * If the src and dest names are identical - including case,
5548 * don't do the rename, just return success.
5551 if (strcsequal(fsp->fsp_name, newname)) {
5552 DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n",
5553 newname));
5554 return NT_STATUS_OK;
5557 old_is_stream = is_ntfs_stream_name(fsp->fsp_name);
5558 new_is_stream = is_ntfs_stream_name(newname);
5560 /* Return the correct error code if both names aren't streams. */
5561 if (!old_is_stream && new_is_stream) {
5562 return NT_STATUS_OBJECT_NAME_INVALID;
5565 if (old_is_stream && !new_is_stream) {
5566 return NT_STATUS_INVALID_PARAMETER;
5570 * Have vfs_object_exist also fill sbuf1
5572 dst_exists = vfs_object_exist(conn, newname, &sbuf1);
5574 if(!replace_if_exists && dst_exists) {
5575 DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
5576 fsp->fsp_name,newname));
5577 return NT_STATUS_OBJECT_NAME_COLLISION;
5580 if (dst_exists) {
5581 struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf1);
5582 files_struct *dst_fsp = file_find_di_first(fileid);
5583 /* The file can be open when renaming a stream */
5584 if (dst_fsp && !new_is_stream) {
5585 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
5586 return NT_STATUS_ACCESS_DENIED;
5590 /* Ensure we have a valid stat struct for the source. */
5591 if (fsp->fh->fd != -1) {
5592 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
5593 return map_nt_error_from_unix(errno);
5595 } else {
5596 if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
5597 return map_nt_error_from_unix(errno);
5601 status = can_rename(conn, fsp, attrs, &sbuf);
5603 if (!NT_STATUS_IS_OK(status)) {
5604 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
5605 nt_errstr(status), fsp->fsp_name,newname));
5606 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
5607 status = NT_STATUS_ACCESS_DENIED;
5608 return status;
5611 if (rename_path_prefix_equal(fsp->fsp_name, newname)) {
5612 return NT_STATUS_ACCESS_DENIED;
5615 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
5616 NULL);
5619 * We have the file open ourselves, so not being able to get the
5620 * corresponding share mode lock is a fatal error.
5623 SMB_ASSERT(lck != NULL);
5625 if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
5626 uint32 create_options = fsp->fh->private_options;
5628 DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
5629 fsp->fsp_name,newname));
5631 notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname);
5633 rename_open_files(conn, lck, newname);
5636 * A rename acts as a new file create w.r.t. allowing an initial delete
5637 * on close, probably because in Windows there is a new handle to the
5638 * new file. If initial delete on close was requested but not
5639 * originally set, we need to set it here. This is probably not 100% correct,
5640 * but will work for the CIFSFS client which in non-posix mode
5641 * depends on these semantics. JRA.
5644 if (create_options & FILE_DELETE_ON_CLOSE) {
5645 status = can_set_delete_on_close(fsp, True, 0);
5647 if (NT_STATUS_IS_OK(status)) {
5648 /* Note that here we set the *inital* delete on close flag,
5649 * not the regular one. The magic gets handled in close. */
5650 fsp->initial_delete_on_close = True;
5653 TALLOC_FREE(lck);
5654 return NT_STATUS_OK;
5657 TALLOC_FREE(lck);
5659 if (errno == ENOTDIR || errno == EISDIR) {
5660 status = NT_STATUS_OBJECT_NAME_COLLISION;
5661 } else {
5662 status = map_nt_error_from_unix(errno);
5665 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
5666 nt_errstr(status), fsp->fsp_name,newname));
5668 return status;
5671 /****************************************************************************
5672 The guts of the rename command, split out so it may be called by the NT SMB
5673 code.
5674 ****************************************************************************/
5676 NTSTATUS rename_internals(TALLOC_CTX *ctx,
5677 connection_struct *conn,
5678 struct smb_request *req,
5679 const char *name_in,
5680 const char *newname_in,
5681 uint32 attrs,
5682 bool replace_if_exists,
5683 bool src_has_wild,
5684 bool dest_has_wild,
5685 uint32_t access_mask)
5687 char *directory = NULL;
5688 char *mask = NULL;
5689 char *last_component_src = NULL;
5690 char *last_component_dest = NULL;
5691 char *name = NULL;
5692 char *newname = NULL;
5693 char *p;
5694 int count=0;
5695 NTSTATUS status = NT_STATUS_OK;
5696 SMB_STRUCT_STAT sbuf1, sbuf2;
5697 struct smb_Dir *dir_hnd = NULL;
5698 const char *dname;
5699 long offset = 0;
5701 ZERO_STRUCT(sbuf1);
5702 ZERO_STRUCT(sbuf2);
5704 status = unix_convert(ctx, conn, name_in, src_has_wild, &name,
5705 &last_component_src, &sbuf1);
5706 if (!NT_STATUS_IS_OK(status)) {
5707 return status;
5710 status = unix_convert(ctx, conn, newname_in, dest_has_wild, &newname,
5711 &last_component_dest, &sbuf2);
5712 if (!NT_STATUS_IS_OK(status)) {
5713 return status;
5717 * Split the old name into directory and last component
5718 * strings. Note that unix_convert may have stripped off a
5719 * leading ./ from both name and newname if the rename is
5720 * at the root of the share. We need to make sure either both
5721 * name and newname contain a / character or neither of them do
5722 * as this is checked in resolve_wildcards().
5725 p = strrchr_m(name,'/');
5726 if (!p) {
5727 directory = talloc_strdup(ctx, ".");
5728 if (!directory) {
5729 return NT_STATUS_NO_MEMORY;
5731 mask = name;
5732 } else {
5733 *p = 0;
5734 directory = talloc_strdup(ctx, name);
5735 if (!directory) {
5736 return NT_STATUS_NO_MEMORY;
5738 mask = p+1;
5739 *p = '/'; /* Replace needed for exceptional test below. */
5743 * We should only check the mangled cache
5744 * here if unix_convert failed. This means
5745 * that the path in 'mask' doesn't exist
5746 * on the file system and so we need to look
5747 * for a possible mangle. This patch from
5748 * Tine Smukavec <valentin.smukavec@hermes.si>.
5751 if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
5752 char *new_mask = NULL;
5753 mangle_lookup_name_from_8_3(ctx,
5754 mask,
5755 &new_mask,
5756 conn->params );
5757 if (new_mask) {
5758 mask = new_mask;
5762 if (!src_has_wild) {
5763 files_struct *fsp;
5766 * No wildcards - just process the one file.
5768 bool is_short_name = mangle_is_8_3(name, True, conn->params);
5770 /* Add a terminating '/' to the directory name. */
5771 directory = talloc_asprintf_append(directory,
5772 "/%s",
5773 mask);
5774 if (!directory) {
5775 return NT_STATUS_NO_MEMORY;
5778 /* Ensure newname contains a '/' also */
5779 if(strrchr_m(newname,'/') == 0) {
5780 newname = talloc_asprintf(ctx,
5781 "./%s",
5782 newname);
5783 if (!newname) {
5784 return NT_STATUS_NO_MEMORY;
5788 DEBUG(3, ("rename_internals: case_sensitive = %d, "
5789 "case_preserve = %d, short case preserve = %d, "
5790 "directory = %s, newname = %s, "
5791 "last_component_dest = %s, is_8_3 = %d\n",
5792 conn->case_sensitive, conn->case_preserve,
5793 conn->short_case_preserve, directory,
5794 newname, last_component_dest, is_short_name));
5796 /* The dest name still may have wildcards. */
5797 if (dest_has_wild) {
5798 char *mod_newname = NULL;
5799 if (!resolve_wildcards(ctx,
5800 directory,newname,&mod_newname)) {
5801 DEBUG(6, ("rename_internals: resolve_wildcards "
5802 "%s %s failed\n",
5803 directory,
5804 newname));
5805 return NT_STATUS_NO_MEMORY;
5807 newname = mod_newname;
5810 ZERO_STRUCT(sbuf1);
5811 SMB_VFS_STAT(conn, directory, &sbuf1);
5813 status = S_ISDIR(sbuf1.st_mode) ?
5814 open_directory(conn, req, directory, &sbuf1,
5815 access_mask,
5816 FILE_SHARE_READ|FILE_SHARE_WRITE,
5817 FILE_OPEN, 0, 0, NULL,
5818 &fsp)
5819 : open_file_ntcreate(conn, req, directory, &sbuf1,
5820 access_mask,
5821 FILE_SHARE_READ|FILE_SHARE_WRITE,
5822 FILE_OPEN, 0, 0, 0, NULL,
5823 &fsp);
5825 if (!NT_STATUS_IS_OK(status)) {
5826 DEBUG(3, ("Could not open rename source %s: %s\n",
5827 directory, nt_errstr(status)));
5828 return status;
5831 status = rename_internals_fsp(conn, fsp, newname,
5832 last_component_dest,
5833 attrs, replace_if_exists);
5835 close_file(fsp, NORMAL_CLOSE);
5837 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
5838 nt_errstr(status), directory,newname));
5840 return status;
5844 * Wildcards - process each file that matches.
5846 if (strequal(mask,"????????.???")) {
5847 mask[0] = '*';
5848 mask[1] = '\0';
5851 status = check_name(conn, directory);
5852 if (!NT_STATUS_IS_OK(status)) {
5853 return status;
5856 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs);
5857 if (dir_hnd == NULL) {
5858 return map_nt_error_from_unix(errno);
5861 status = NT_STATUS_NO_SUCH_FILE;
5863 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
5864 * - gentest fix. JRA
5867 while ((dname = ReadDirName(dir_hnd, &offset))) {
5868 files_struct *fsp = NULL;
5869 char *fname = NULL;
5870 char *destname = NULL;
5871 bool sysdir_entry = False;
5873 /* Quick check for "." and ".." */
5874 if (ISDOT(dname) || ISDOTDOT(dname)) {
5875 if (attrs & aDIR) {
5876 sysdir_entry = True;
5877 } else {
5878 continue;
5882 if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
5883 continue;
5886 if(!mask_match(dname, mask, conn->case_sensitive)) {
5887 continue;
5890 if (sysdir_entry) {
5891 status = NT_STATUS_OBJECT_NAME_INVALID;
5892 break;
5895 fname = talloc_asprintf(ctx,
5896 "%s/%s",
5897 directory,
5898 dname);
5899 if (!fname) {
5900 return NT_STATUS_NO_MEMORY;
5903 if (!resolve_wildcards(ctx,
5904 fname,newname,&destname)) {
5905 DEBUG(6, ("resolve_wildcards %s %s failed\n",
5906 fname, destname));
5907 TALLOC_FREE(fname);
5908 continue;
5910 if (!destname) {
5911 return NT_STATUS_NO_MEMORY;
5914 ZERO_STRUCT(sbuf1);
5915 SMB_VFS_STAT(conn, fname, &sbuf1);
5917 status = S_ISDIR(sbuf1.st_mode) ?
5918 open_directory(conn, req, fname, &sbuf1,
5919 access_mask,
5920 FILE_SHARE_READ|FILE_SHARE_WRITE,
5921 FILE_OPEN, 0, 0, NULL,
5922 &fsp)
5923 : open_file_ntcreate(conn, req, fname, &sbuf1,
5924 access_mask,
5925 FILE_SHARE_READ|FILE_SHARE_WRITE,
5926 FILE_OPEN, 0, 0, 0, NULL,
5927 &fsp);
5929 if (!NT_STATUS_IS_OK(status)) {
5930 DEBUG(3,("rename_internals: open_file_ntcreate "
5931 "returned %s rename %s -> %s\n",
5932 nt_errstr(status), directory, newname));
5933 break;
5936 status = rename_internals_fsp(conn, fsp, destname, dname,
5937 attrs, replace_if_exists);
5939 close_file(fsp, NORMAL_CLOSE);
5941 if (!NT_STATUS_IS_OK(status)) {
5942 DEBUG(3, ("rename_internals_fsp returned %s for "
5943 "rename %s -> %s\n", nt_errstr(status),
5944 directory, newname));
5945 break;
5948 count++;
5950 DEBUG(3,("rename_internals: doing rename on %s -> "
5951 "%s\n",fname,destname));
5953 TALLOC_FREE(fname);
5954 TALLOC_FREE(destname);
5956 TALLOC_FREE(dir_hnd);
5958 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
5959 status = map_nt_error_from_unix(errno);
5962 return status;
5965 /****************************************************************************
5966 Reply to a mv.
5967 ****************************************************************************/
5969 void reply_mv(struct smb_request *req)
5971 connection_struct *conn = req->conn;
5972 char *name = NULL;
5973 char *newname = NULL;
5974 char *p;
5975 uint32 attrs;
5976 NTSTATUS status;
5977 bool src_has_wcard = False;
5978 bool dest_has_wcard = False;
5979 TALLOC_CTX *ctx = talloc_tos();
5981 START_PROFILE(SMBmv);
5983 if (req->wct < 1) {
5984 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5985 END_PROFILE(SMBmv);
5986 return;
5989 attrs = SVAL(req->inbuf,smb_vwv0);
5991 p = smb_buf(req->inbuf) + 1;
5992 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
5993 0, STR_TERMINATE, &status,
5994 &src_has_wcard);
5995 if (!NT_STATUS_IS_OK(status)) {
5996 reply_nterror(req, status);
5997 END_PROFILE(SMBmv);
5998 return;
6000 p++;
6001 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
6002 0, STR_TERMINATE, &status,
6003 &dest_has_wcard);
6004 if (!NT_STATUS_IS_OK(status)) {
6005 reply_nterror(req, status);
6006 END_PROFILE(SMBmv);
6007 return;
6010 status = resolve_dfspath_wcard(ctx, conn,
6011 req->flags2 & FLAGS2_DFS_PATHNAMES,
6012 name,
6013 &name,
6014 &src_has_wcard);
6015 if (!NT_STATUS_IS_OK(status)) {
6016 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6017 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6018 ERRSRV, ERRbadpath);
6019 END_PROFILE(SMBmv);
6020 return;
6022 reply_nterror(req, status);
6023 END_PROFILE(SMBmv);
6024 return;
6027 status = resolve_dfspath_wcard(ctx, conn,
6028 req->flags2 & FLAGS2_DFS_PATHNAMES,
6029 newname,
6030 &newname,
6031 &dest_has_wcard);
6032 if (!NT_STATUS_IS_OK(status)) {
6033 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6034 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6035 ERRSRV, ERRbadpath);
6036 END_PROFILE(SMBmv);
6037 return;
6039 reply_nterror(req, status);
6040 END_PROFILE(SMBmv);
6041 return;
6044 DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
6046 status = rename_internals(ctx, conn, req, name, newname, attrs, False,
6047 src_has_wcard, dest_has_wcard, DELETE_ACCESS);
6048 if (!NT_STATUS_IS_OK(status)) {
6049 if (open_was_deferred(req->mid)) {
6050 /* We have re-scheduled this call. */
6051 END_PROFILE(SMBmv);
6052 return;
6054 reply_nterror(req, status);
6055 END_PROFILE(SMBmv);
6056 return;
6059 reply_outbuf(req, 0, 0);
6061 END_PROFILE(SMBmv);
6062 return;
6065 /*******************************************************************
6066 Copy a file as part of a reply_copy.
6067 ******************************************************************/
6070 * TODO: check error codes on all callers
6073 NTSTATUS copy_file(TALLOC_CTX *ctx,
6074 connection_struct *conn,
6075 const char *src,
6076 const char *dest1,
6077 int ofun,
6078 int count,
6079 bool target_is_directory)
6081 SMB_STRUCT_STAT src_sbuf, sbuf2;
6082 SMB_OFF_T ret=-1;
6083 files_struct *fsp1,*fsp2;
6084 char *dest = NULL;
6085 uint32 dosattrs;
6086 uint32 new_create_disposition;
6087 NTSTATUS status;
6089 dest = talloc_strdup(ctx, dest1);
6090 if (!dest) {
6091 return NT_STATUS_NO_MEMORY;
6093 if (target_is_directory) {
6094 const char *p = strrchr_m(src,'/');
6095 if (p) {
6096 p++;
6097 } else {
6098 p = src;
6100 dest = talloc_asprintf_append(dest,
6101 "/%s",
6103 if (!dest) {
6104 return NT_STATUS_NO_MEMORY;
6108 if (!vfs_file_exist(conn,src,&src_sbuf)) {
6109 TALLOC_FREE(dest);
6110 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6113 if (!target_is_directory && count) {
6114 new_create_disposition = FILE_OPEN;
6115 } else {
6116 if (!map_open_params_to_ntcreate(dest1,0,ofun,
6117 NULL, NULL, &new_create_disposition, NULL)) {
6118 TALLOC_FREE(dest);
6119 return NT_STATUS_INVALID_PARAMETER;
6123 status = open_file_ntcreate(conn, NULL, src, &src_sbuf,
6124 FILE_GENERIC_READ,
6125 FILE_SHARE_READ|FILE_SHARE_WRITE,
6126 FILE_OPEN,
6128 FILE_ATTRIBUTE_NORMAL,
6129 INTERNAL_OPEN_ONLY,
6130 NULL, &fsp1);
6132 if (!NT_STATUS_IS_OK(status)) {
6133 TALLOC_FREE(dest);
6134 return status;
6137 dosattrs = dos_mode(conn, src, &src_sbuf);
6138 if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) {
6139 ZERO_STRUCTP(&sbuf2);
6142 status = open_file_ntcreate(conn, NULL, dest, &sbuf2,
6143 FILE_GENERIC_WRITE,
6144 FILE_SHARE_READ|FILE_SHARE_WRITE,
6145 new_create_disposition,
6147 dosattrs,
6148 INTERNAL_OPEN_ONLY,
6149 NULL, &fsp2);
6151 TALLOC_FREE(dest);
6153 if (!NT_STATUS_IS_OK(status)) {
6154 close_file(fsp1,ERROR_CLOSE);
6155 return status;
6158 if ((ofun&3) == 1) {
6159 if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
6160 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
6162 * Stop the copy from occurring.
6164 ret = -1;
6165 src_sbuf.st_size = 0;
6169 if (src_sbuf.st_size) {
6170 ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
6173 close_file(fsp1,NORMAL_CLOSE);
6175 /* Ensure the modtime is set correctly on the destination file. */
6176 set_close_write_time(fsp2, get_mtimespec(&src_sbuf));
6179 * As we are opening fsp1 read-only we only expect
6180 * an error on close on fsp2 if we are out of space.
6181 * Thus we don't look at the error return from the
6182 * close of fsp1.
6184 status = close_file(fsp2,NORMAL_CLOSE);
6186 if (!NT_STATUS_IS_OK(status)) {
6187 return status;
6190 if (ret != (SMB_OFF_T)src_sbuf.st_size) {
6191 return NT_STATUS_DISK_FULL;
6194 return NT_STATUS_OK;
6197 /****************************************************************************
6198 Reply to a file copy.
6199 ****************************************************************************/
6201 void reply_copy(struct smb_request *req)
6203 connection_struct *conn = req->conn;
6204 char *name = NULL;
6205 char *newname = NULL;
6206 char *directory = NULL;
6207 char *mask = NULL;
6208 char *p;
6209 int count=0;
6210 int error = ERRnoaccess;
6211 int err = 0;
6212 int tid2;
6213 int ofun;
6214 int flags;
6215 bool target_is_directory=False;
6216 bool source_has_wild = False;
6217 bool dest_has_wild = False;
6218 SMB_STRUCT_STAT sbuf1, sbuf2;
6219 NTSTATUS status;
6220 TALLOC_CTX *ctx = talloc_tos();
6222 START_PROFILE(SMBcopy);
6224 if (req->wct < 3) {
6225 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6226 END_PROFILE(SMBcopy);
6227 return;
6230 tid2 = SVAL(req->inbuf,smb_vwv0);
6231 ofun = SVAL(req->inbuf,smb_vwv1);
6232 flags = SVAL(req->inbuf,smb_vwv2);
6234 p = smb_buf(req->inbuf);
6235 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
6236 0, STR_TERMINATE, &status,
6237 &source_has_wild);
6238 if (!NT_STATUS_IS_OK(status)) {
6239 reply_nterror(req, status);
6240 END_PROFILE(SMBcopy);
6241 return;
6243 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
6244 0, STR_TERMINATE, &status,
6245 &dest_has_wild);
6246 if (!NT_STATUS_IS_OK(status)) {
6247 reply_nterror(req, status);
6248 END_PROFILE(SMBcopy);
6249 return;
6252 DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
6254 if (tid2 != conn->cnum) {
6255 /* can't currently handle inter share copies XXXX */
6256 DEBUG(3,("Rejecting inter-share copy\n"));
6257 reply_doserror(req, ERRSRV, ERRinvdevice);
6258 END_PROFILE(SMBcopy);
6259 return;
6262 status = resolve_dfspath_wcard(ctx, conn,
6263 req->flags2 & FLAGS2_DFS_PATHNAMES,
6264 name,
6265 &name,
6266 &source_has_wild);
6267 if (!NT_STATUS_IS_OK(status)) {
6268 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6269 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6270 ERRSRV, ERRbadpath);
6271 END_PROFILE(SMBcopy);
6272 return;
6274 reply_nterror(req, status);
6275 END_PROFILE(SMBcopy);
6276 return;
6279 status = resolve_dfspath_wcard(ctx, conn,
6280 req->flags2 & FLAGS2_DFS_PATHNAMES,
6281 newname,
6282 &newname,
6283 &dest_has_wild);
6284 if (!NT_STATUS_IS_OK(status)) {
6285 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6286 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6287 ERRSRV, ERRbadpath);
6288 END_PROFILE(SMBcopy);
6289 return;
6291 reply_nterror(req, status);
6292 END_PROFILE(SMBcopy);
6293 return;
6296 status = unix_convert(ctx, conn, name, source_has_wild,
6297 &name, NULL, &sbuf1);
6298 if (!NT_STATUS_IS_OK(status)) {
6299 reply_nterror(req, status);
6300 END_PROFILE(SMBcopy);
6301 return;
6304 status = unix_convert(ctx, conn, newname, dest_has_wild,
6305 &newname, NULL, &sbuf2);
6306 if (!NT_STATUS_IS_OK(status)) {
6307 reply_nterror(req, status);
6308 END_PROFILE(SMBcopy);
6309 return;
6312 target_is_directory = VALID_STAT_OF_DIR(sbuf2);
6314 if ((flags&1) && target_is_directory) {
6315 reply_doserror(req, ERRDOS, ERRbadfile);
6316 END_PROFILE(SMBcopy);
6317 return;
6320 if ((flags&2) && !target_is_directory) {
6321 reply_doserror(req, ERRDOS, ERRbadpath);
6322 END_PROFILE(SMBcopy);
6323 return;
6326 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
6327 /* wants a tree copy! XXXX */
6328 DEBUG(3,("Rejecting tree copy\n"));
6329 reply_doserror(req, ERRSRV, ERRerror);
6330 END_PROFILE(SMBcopy);
6331 return;
6334 p = strrchr_m(name,'/');
6335 if (!p) {
6336 directory = talloc_strdup(ctx, "./");
6337 if (!directory) {
6338 reply_nterror(req, NT_STATUS_NO_MEMORY);
6339 END_PROFILE(SMBcopy);
6340 return;
6342 mask = name;
6343 } else {
6344 *p = 0;
6345 directory = talloc_strdup(ctx, name);
6346 if (!directory) {
6347 reply_nterror(req, NT_STATUS_NO_MEMORY);
6348 END_PROFILE(SMBcopy);
6349 return;
6351 mask = p+1;
6355 * We should only check the mangled cache
6356 * here if unix_convert failed. This means
6357 * that the path in 'mask' doesn't exist
6358 * on the file system and so we need to look
6359 * for a possible mangle. This patch from
6360 * Tine Smukavec <valentin.smukavec@hermes.si>.
6363 if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
6364 char *new_mask = NULL;
6365 mangle_lookup_name_from_8_3(ctx,
6366 mask,
6367 &new_mask,
6368 conn->params );
6369 if (new_mask) {
6370 mask = new_mask;
6374 if (!source_has_wild) {
6375 directory = talloc_asprintf_append(directory,
6376 "/%s",
6377 mask);
6378 if (dest_has_wild) {
6379 char *mod_newname = NULL;
6380 if (!resolve_wildcards(ctx,
6381 directory,newname,&mod_newname)) {
6382 reply_nterror(req, NT_STATUS_NO_MEMORY);
6383 END_PROFILE(SMBcopy);
6384 return;
6386 newname = mod_newname;
6389 status = check_name(conn, directory);
6390 if (!NT_STATUS_IS_OK(status)) {
6391 reply_nterror(req, status);
6392 END_PROFILE(SMBcopy);
6393 return;
6396 status = check_name(conn, newname);
6397 if (!NT_STATUS_IS_OK(status)) {
6398 reply_nterror(req, status);
6399 END_PROFILE(SMBcopy);
6400 return;
6403 status = copy_file(ctx,conn,directory,newname,ofun,
6404 count,target_is_directory);
6406 if(!NT_STATUS_IS_OK(status)) {
6407 reply_nterror(req, status);
6408 END_PROFILE(SMBcopy);
6409 return;
6410 } else {
6411 count++;
6413 } else {
6414 struct smb_Dir *dir_hnd = NULL;
6415 const char *dname = NULL;
6416 long offset = 0;
6418 if (strequal(mask,"????????.???")) {
6419 mask[0] = '*';
6420 mask[1] = '\0';
6423 status = check_name(conn, directory);
6424 if (!NT_STATUS_IS_OK(status)) {
6425 reply_nterror(req, status);
6426 END_PROFILE(SMBcopy);
6427 return;
6430 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0);
6431 if (dir_hnd == NULL) {
6432 status = map_nt_error_from_unix(errno);
6433 reply_nterror(req, status);
6434 END_PROFILE(SMBcopy);
6435 return;
6438 error = ERRbadfile;
6440 while ((dname = ReadDirName(dir_hnd, &offset))) {
6441 char *destname = NULL;
6442 char *fname = NULL;
6444 if (ISDOT(dname) || ISDOTDOT(dname)) {
6445 continue;
6448 if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
6449 continue;
6452 if(!mask_match(dname, mask, conn->case_sensitive)) {
6453 continue;
6456 error = ERRnoaccess;
6457 fname = talloc_asprintf(ctx,
6458 "%s/%s",
6459 directory,
6460 dname);
6461 if (!fname) {
6462 TALLOC_FREE(dir_hnd);
6463 reply_nterror(req, NT_STATUS_NO_MEMORY);
6464 END_PROFILE(SMBcopy);
6465 return;
6468 if (!resolve_wildcards(ctx,
6469 fname,newname,&destname)) {
6470 continue;
6472 if (!destname) {
6473 TALLOC_FREE(dir_hnd);
6474 reply_nterror(req, NT_STATUS_NO_MEMORY);
6475 END_PROFILE(SMBcopy);
6476 return;
6479 status = check_name(conn, fname);
6480 if (!NT_STATUS_IS_OK(status)) {
6481 TALLOC_FREE(dir_hnd);
6482 reply_nterror(req, status);
6483 END_PROFILE(SMBcopy);
6484 return;
6487 status = check_name(conn, destname);
6488 if (!NT_STATUS_IS_OK(status)) {
6489 TALLOC_FREE(dir_hnd);
6490 reply_nterror(req, status);
6491 END_PROFILE(SMBcopy);
6492 return;
6495 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
6497 status = copy_file(ctx,conn,fname,destname,ofun,
6498 count,target_is_directory);
6499 if (NT_STATUS_IS_OK(status)) {
6500 count++;
6502 TALLOC_FREE(fname);
6503 TALLOC_FREE(destname);
6505 TALLOC_FREE(dir_hnd);
6508 if (count == 0) {
6509 if(err) {
6510 /* Error on close... */
6511 errno = err;
6512 reply_unixerror(req, ERRHRD, ERRgeneral);
6513 END_PROFILE(SMBcopy);
6514 return;
6517 reply_doserror(req, ERRDOS, error);
6518 END_PROFILE(SMBcopy);
6519 return;
6522 reply_outbuf(req, 1, 0);
6523 SSVAL(req->outbuf,smb_vwv0,count);
6525 END_PROFILE(SMBcopy);
6526 return;
6529 #undef DBGC_CLASS
6530 #define DBGC_CLASS DBGC_LOCKING
6532 /****************************************************************************
6533 Get a lock pid, dealing with large count requests.
6534 ****************************************************************************/
6536 uint32 get_lock_pid( char *data, int data_offset, bool large_file_format)
6538 if(!large_file_format)
6539 return (uint32)SVAL(data,SMB_LPID_OFFSET(data_offset));
6540 else
6541 return (uint32)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
6544 /****************************************************************************
6545 Get a lock count, dealing with large count requests.
6546 ****************************************************************************/
6548 SMB_BIG_UINT get_lock_count( char *data, int data_offset, bool large_file_format)
6550 SMB_BIG_UINT count = 0;
6552 if(!large_file_format) {
6553 count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
6554 } else {
6556 #if defined(HAVE_LONGLONG)
6557 count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
6558 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
6559 #else /* HAVE_LONGLONG */
6562 * NT4.x seems to be broken in that it sends large file (64 bit)
6563 * lockingX calls even if the CAP_LARGE_FILES was *not*
6564 * negotiated. For boxes without large unsigned ints truncate the
6565 * lock count by dropping the top 32 bits.
6568 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
6569 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
6570 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
6571 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
6572 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
6575 count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
6576 #endif /* HAVE_LONGLONG */
6579 return count;
6582 #if !defined(HAVE_LONGLONG)
6583 /****************************************************************************
6584 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
6585 ****************************************************************************/
6587 static uint32 map_lock_offset(uint32 high, uint32 low)
6589 unsigned int i;
6590 uint32 mask = 0;
6591 uint32 highcopy = high;
6594 * Try and find out how many significant bits there are in high.
6597 for(i = 0; highcopy; i++)
6598 highcopy >>= 1;
6601 * We use 31 bits not 32 here as POSIX
6602 * lock offsets may not be negative.
6605 mask = (~0) << (31 - i);
6607 if(low & mask)
6608 return 0; /* Fail. */
6610 high <<= (31 - i);
6612 return (high|low);
6614 #endif /* !defined(HAVE_LONGLONG) */
6616 /****************************************************************************
6617 Get a lock offset, dealing with large offset requests.
6618 ****************************************************************************/
6620 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, bool large_file_format, bool *err)
6622 SMB_BIG_UINT offset = 0;
6624 *err = False;
6626 if(!large_file_format) {
6627 offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
6628 } else {
6630 #if defined(HAVE_LONGLONG)
6631 offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
6632 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
6633 #else /* HAVE_LONGLONG */
6636 * NT4.x seems to be broken in that it sends large file (64 bit)
6637 * lockingX calls even if the CAP_LARGE_FILES was *not*
6638 * negotiated. For boxes without large unsigned ints mangle the
6639 * lock offset by mapping the top 32 bits onto the lower 32.
6642 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
6643 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
6644 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
6645 uint32 new_low = 0;
6647 if((new_low = map_lock_offset(high, low)) == 0) {
6648 *err = True;
6649 return (SMB_BIG_UINT)-1;
6652 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
6653 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
6654 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
6655 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
6658 offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
6659 #endif /* HAVE_LONGLONG */
6662 return offset;
6665 /****************************************************************************
6666 Reply to a lockingX request.
6667 ****************************************************************************/
6669 void reply_lockingX(struct smb_request *req)
6671 connection_struct *conn = req->conn;
6672 files_struct *fsp;
6673 unsigned char locktype;
6674 unsigned char oplocklevel;
6675 uint16 num_ulocks;
6676 uint16 num_locks;
6677 SMB_BIG_UINT count = 0, offset = 0;
6678 uint32 lock_pid;
6679 int32 lock_timeout;
6680 int i;
6681 char *data;
6682 bool large_file_format;
6683 bool err;
6684 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
6686 START_PROFILE(SMBlockingX);
6688 if (req->wct < 8) {
6689 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6690 END_PROFILE(SMBlockingX);
6691 return;
6694 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
6695 locktype = CVAL(req->inbuf,smb_vwv3);
6696 oplocklevel = CVAL(req->inbuf,smb_vwv3+1);
6697 num_ulocks = SVAL(req->inbuf,smb_vwv6);
6698 num_locks = SVAL(req->inbuf,smb_vwv7);
6699 lock_timeout = IVAL(req->inbuf,smb_vwv4);
6700 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
6702 if (!check_fsp(conn, req, fsp, &current_user)) {
6703 END_PROFILE(SMBlockingX);
6704 return;
6707 data = smb_buf(req->inbuf);
6709 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6710 /* we don't support these - and CANCEL_LOCK makes w2k
6711 and XP reboot so I don't really want to be
6712 compatible! (tridge) */
6713 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
6714 END_PROFILE(SMBlockingX);
6715 return;
6718 /* Check if this is an oplock break on a file
6719 we have granted an oplock on.
6721 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
6722 /* Client can insist on breaking to none. */
6723 bool break_to_none = (oplocklevel == 0);
6724 bool result;
6726 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
6727 "for fnum = %d\n", (unsigned int)oplocklevel,
6728 fsp->fnum ));
6731 * Make sure we have granted an exclusive or batch oplock on
6732 * this file.
6735 if (fsp->oplock_type == 0) {
6737 /* The Samba4 nbench simulator doesn't understand
6738 the difference between break to level2 and break
6739 to none from level2 - it sends oplock break
6740 replies in both cases. Don't keep logging an error
6741 message here - just ignore it. JRA. */
6743 DEBUG(5,("reply_lockingX: Error : oplock break from "
6744 "client for fnum = %d (oplock=%d) and no "
6745 "oplock granted on this file (%s).\n",
6746 fsp->fnum, fsp->oplock_type, fsp->fsp_name));
6748 /* if this is a pure oplock break request then don't
6749 * send a reply */
6750 if (num_locks == 0 && num_ulocks == 0) {
6751 END_PROFILE(SMBlockingX);
6752 return;
6753 } else {
6754 END_PROFILE(SMBlockingX);
6755 reply_doserror(req, ERRDOS, ERRlock);
6756 return;
6760 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
6761 (break_to_none)) {
6762 result = remove_oplock(fsp);
6763 } else {
6764 result = downgrade_oplock(fsp);
6767 if (!result) {
6768 DEBUG(0, ("reply_lockingX: error in removing "
6769 "oplock on file %s\n", fsp->fsp_name));
6770 /* Hmmm. Is this panic justified? */
6771 smb_panic("internal tdb error");
6774 reply_to_oplock_break_requests(fsp);
6776 /* if this is a pure oplock break request then don't send a
6777 * reply */
6778 if (num_locks == 0 && num_ulocks == 0) {
6779 /* Sanity check - ensure a pure oplock break is not a
6780 chained request. */
6781 if(CVAL(req->inbuf,smb_vwv0) != 0xff)
6782 DEBUG(0,("reply_lockingX: Error : pure oplock "
6783 "break is a chained %d request !\n",
6784 (unsigned int)CVAL(req->inbuf,
6785 smb_vwv0) ));
6786 END_PROFILE(SMBlockingX);
6787 return;
6792 * We do this check *after* we have checked this is not a oplock break
6793 * response message. JRA.
6796 release_level_2_oplocks_on_change(fsp);
6798 if (smb_buflen(req->inbuf) <
6799 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
6800 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6801 END_PROFILE(SMBlockingX);
6802 return;
6805 /* Data now points at the beginning of the list
6806 of smb_unlkrng structs */
6807 for(i = 0; i < (int)num_ulocks; i++) {
6808 lock_pid = get_lock_pid( data, i, large_file_format);
6809 count = get_lock_count( data, i, large_file_format);
6810 offset = get_lock_offset( data, i, large_file_format, &err);
6813 * There is no error code marked "stupid client bug".... :-).
6815 if(err) {
6816 END_PROFILE(SMBlockingX);
6817 reply_doserror(req, ERRDOS, ERRnoaccess);
6818 return;
6821 DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for "
6822 "pid %u, file %s\n", (double)offset, (double)count,
6823 (unsigned int)lock_pid, fsp->fsp_name ));
6825 status = do_unlock(smbd_messaging_context(),
6826 fsp,
6827 lock_pid,
6828 count,
6829 offset,
6830 WINDOWS_LOCK);
6832 if (NT_STATUS_V(status)) {
6833 END_PROFILE(SMBlockingX);
6834 reply_nterror(req, status);
6835 return;
6839 /* Setup the timeout in seconds. */
6841 if (!lp_blocking_locks(SNUM(conn))) {
6842 lock_timeout = 0;
6845 /* Now do any requested locks */
6846 data += ((large_file_format ? 20 : 10)*num_ulocks);
6848 /* Data now points at the beginning of the list
6849 of smb_lkrng structs */
6851 for(i = 0; i < (int)num_locks; i++) {
6852 enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
6853 READ_LOCK:WRITE_LOCK);
6854 lock_pid = get_lock_pid( data, i, large_file_format);
6855 count = get_lock_count( data, i, large_file_format);
6856 offset = get_lock_offset( data, i, large_file_format, &err);
6859 * There is no error code marked "stupid client bug".... :-).
6861 if(err) {
6862 END_PROFILE(SMBlockingX);
6863 reply_doserror(req, ERRDOS, ERRnoaccess);
6864 return;
6867 DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid "
6868 "%u, file %s timeout = %d\n", (double)offset,
6869 (double)count, (unsigned int)lock_pid,
6870 fsp->fsp_name, (int)lock_timeout ));
6872 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
6873 if (lp_blocking_locks(SNUM(conn))) {
6875 /* Schedule a message to ourselves to
6876 remove the blocking lock record and
6877 return the right error. */
6879 if (!blocking_lock_cancel(fsp,
6880 lock_pid,
6881 offset,
6882 count,
6883 WINDOWS_LOCK,
6884 locktype,
6885 NT_STATUS_FILE_LOCK_CONFLICT)) {
6886 END_PROFILE(SMBlockingX);
6887 reply_nterror(
6888 req,
6889 NT_STATUS_DOS(
6890 ERRDOS,
6891 ERRcancelviolation));
6892 return;
6895 /* Remove a matching pending lock. */
6896 status = do_lock_cancel(fsp,
6897 lock_pid,
6898 count,
6899 offset,
6900 WINDOWS_LOCK);
6901 } else {
6902 bool blocking_lock = lock_timeout ? True : False;
6903 bool defer_lock = False;
6904 struct byte_range_lock *br_lck;
6905 uint32 block_smbpid;
6907 br_lck = do_lock(smbd_messaging_context(),
6908 fsp,
6909 lock_pid,
6910 count,
6911 offset,
6912 lock_type,
6913 WINDOWS_LOCK,
6914 blocking_lock,
6915 &status,
6916 &block_smbpid);
6918 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6919 /* Windows internal resolution for blocking locks seems
6920 to be about 200ms... Don't wait for less than that. JRA. */
6921 if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) {
6922 lock_timeout = lp_lock_spin_time();
6924 defer_lock = True;
6927 /* This heuristic seems to match W2K3 very well. If a
6928 lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
6929 it pretends we asked for a timeout of between 150 - 300 milliseconds as
6930 far as I can tell. Replacement for do_lock_spin(). JRA. */
6932 if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
6933 NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
6934 defer_lock = True;
6935 lock_timeout = lp_lock_spin_time();
6938 if (br_lck && defer_lock) {
6940 * A blocking lock was requested. Package up
6941 * this smb into a queued request and push it
6942 * onto the blocking lock queue.
6944 if(push_blocking_lock_request(br_lck,
6945 req,
6946 fsp,
6947 lock_timeout,
6949 lock_pid,
6950 lock_type,
6951 WINDOWS_LOCK,
6952 offset,
6953 count,
6954 block_smbpid)) {
6955 TALLOC_FREE(br_lck);
6956 END_PROFILE(SMBlockingX);
6957 return;
6961 TALLOC_FREE(br_lck);
6964 if (NT_STATUS_V(status)) {
6965 END_PROFILE(SMBlockingX);
6966 reply_nterror(req, status);
6967 return;
6971 /* If any of the above locks failed, then we must unlock
6972 all of the previous locks (X/Open spec). */
6974 if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) &&
6975 (i != num_locks) &&
6976 (num_locks != 0)) {
6978 * Ensure we don't do a remove on the lock that just failed,
6979 * as under POSIX rules, if we have a lock already there, we
6980 * will delete it (and we shouldn't) .....
6982 for(i--; i >= 0; i--) {
6983 lock_pid = get_lock_pid( data, i, large_file_format);
6984 count = get_lock_count( data, i, large_file_format);
6985 offset = get_lock_offset( data, i, large_file_format,
6986 &err);
6989 * There is no error code marked "stupid client
6990 * bug".... :-).
6992 if(err) {
6993 END_PROFILE(SMBlockingX);
6994 reply_doserror(req, ERRDOS, ERRnoaccess);
6995 return;
6998 do_unlock(smbd_messaging_context(),
6999 fsp,
7000 lock_pid,
7001 count,
7002 offset,
7003 WINDOWS_LOCK);
7005 END_PROFILE(SMBlockingX);
7006 reply_nterror(req, status);
7007 return;
7010 reply_outbuf(req, 2, 0);
7012 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7013 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7015 END_PROFILE(SMBlockingX);
7016 chain_reply(req);
7019 #undef DBGC_CLASS
7020 #define DBGC_CLASS DBGC_ALL
7022 /****************************************************************************
7023 Reply to a SMBreadbmpx (read block multiplex) request.
7024 Always reply with an error, if someone has a platform really needs this,
7025 please contact vl@samba.org
7026 ****************************************************************************/
7028 void reply_readbmpx(struct smb_request *req)
7030 START_PROFILE(SMBreadBmpx);
7031 reply_doserror(req, ERRSRV, ERRuseSTD);
7032 END_PROFILE(SMBreadBmpx);
7033 return;
7036 /****************************************************************************
7037 Reply to a SMBreadbs (read block multiplex secondary) request.
7038 Always reply with an error, if someone has a platform really needs this,
7039 please contact vl@samba.org
7040 ****************************************************************************/
7042 void reply_readbs(struct smb_request *req)
7044 START_PROFILE(SMBreadBs);
7045 reply_doserror(req, ERRSRV, ERRuseSTD);
7046 END_PROFILE(SMBreadBs);
7047 return;
7050 /****************************************************************************
7051 Reply to a SMBsetattrE.
7052 ****************************************************************************/
7054 void reply_setattrE(struct smb_request *req)
7056 connection_struct *conn = req->conn;
7057 struct timespec ts[2];
7058 files_struct *fsp;
7059 SMB_STRUCT_STAT sbuf;
7060 NTSTATUS status;
7062 START_PROFILE(SMBsetattrE);
7064 if (req->wct < 7) {
7065 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7066 END_PROFILE(SMBsetattrE);
7067 return;
7070 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
7072 if(!fsp || (fsp->conn != conn)) {
7073 reply_doserror(req, ERRDOS, ERRbadfid);
7074 END_PROFILE(SMBsetattrE);
7075 return;
7080 * Convert the DOS times into unix times. Ignore create
7081 * time as UNIX can't set this.
7084 ts[0] = convert_time_t_to_timespec(
7085 srv_make_unix_date2(req->inbuf+smb_vwv3)); /* atime. */
7086 ts[1] = convert_time_t_to_timespec(
7087 srv_make_unix_date2(req->inbuf+smb_vwv5)); /* mtime. */
7089 reply_outbuf(req, 0, 0);
7092 * Patch from Ray Frush <frush@engr.colostate.edu>
7093 * Sometimes times are sent as zero - ignore them.
7096 /* Ensure we have a valid stat struct for the source. */
7097 if (fsp->fh->fd != -1) {
7098 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
7099 status = map_nt_error_from_unix(errno);
7100 reply_nterror(req, status);
7101 END_PROFILE(SMBsetattrE);
7102 return;
7104 } else {
7105 if (SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf) == -1) {
7106 status = map_nt_error_from_unix(errno);
7107 reply_nterror(req, status);
7108 END_PROFILE(SMBsetattrE);
7109 return;
7113 status = smb_set_file_time(conn, fsp, fsp->fsp_name,
7114 &sbuf, ts, true);
7115 if (!NT_STATUS_IS_OK(status)) {
7116 reply_doserror(req, ERRDOS, ERRnoaccess);
7117 END_PROFILE(SMBsetattrE);
7118 return;
7121 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
7122 fsp->fnum,
7123 (unsigned int)ts[0].tv_sec,
7124 (unsigned int)ts[1].tv_sec));
7126 END_PROFILE(SMBsetattrE);
7127 return;
7131 /* Back from the dead for OS/2..... JRA. */
7133 /****************************************************************************
7134 Reply to a SMBwritebmpx (write block multiplex primary) request.
7135 Always reply with an error, if someone has a platform really needs this,
7136 please contact vl@samba.org
7137 ****************************************************************************/
7139 void reply_writebmpx(struct smb_request *req)
7141 START_PROFILE(SMBwriteBmpx);
7142 reply_doserror(req, ERRSRV, ERRuseSTD);
7143 END_PROFILE(SMBwriteBmpx);
7144 return;
7147 /****************************************************************************
7148 Reply to a SMBwritebs (write block multiplex secondary) request.
7149 Always reply with an error, if someone has a platform really needs this,
7150 please contact vl@samba.org
7151 ****************************************************************************/
7153 void reply_writebs(struct smb_request *req)
7155 START_PROFILE(SMBwriteBs);
7156 reply_doserror(req, ERRSRV, ERRuseSTD);
7157 END_PROFILE(SMBwriteBs);
7158 return;
7161 /****************************************************************************
7162 Reply to a SMBgetattrE.
7163 ****************************************************************************/
7165 void reply_getattrE(struct smb_request *req)
7167 connection_struct *conn = req->conn;
7168 SMB_STRUCT_STAT sbuf;
7169 int mode;
7170 files_struct *fsp;
7171 struct timespec create_ts;
7173 START_PROFILE(SMBgetattrE);
7175 if (req->wct < 1) {
7176 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7177 END_PROFILE(SMBgetattrE);
7178 return;
7181 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
7183 if(!fsp || (fsp->conn != conn)) {
7184 reply_doserror(req, ERRDOS, ERRbadfid);
7185 END_PROFILE(SMBgetattrE);
7186 return;
7189 /* Do an fstat on this file */
7190 if(fsp_stat(fsp, &sbuf)) {
7191 reply_unixerror(req, ERRDOS, ERRnoaccess);
7192 END_PROFILE(SMBgetattrE);
7193 return;
7196 mode = dos_mode(conn,fsp->fsp_name,&sbuf);
7199 * Convert the times into dos times. Set create
7200 * date to be last modify date as UNIX doesn't save
7201 * this.
7204 reply_outbuf(req, 11, 0);
7206 create_ts = get_create_timespec(&sbuf,
7207 lp_fake_dir_create_times(SNUM(conn)));
7208 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7209 srv_put_dos_date2((char *)req->outbuf, smb_vwv2, sbuf.st_atime);
7210 /* Should we check pending modtime here ? JRA */
7211 srv_put_dos_date2((char *)req->outbuf, smb_vwv4, sbuf.st_mtime);
7213 if (mode & aDIR) {
7214 SIVAL(req->outbuf, smb_vwv6, 0);
7215 SIVAL(req->outbuf, smb_vwv8, 0);
7216 } else {
7217 uint32 allocation_size = get_allocation_size(conn,fsp, &sbuf);
7218 SIVAL(req->outbuf, smb_vwv6, (uint32)sbuf.st_size);
7219 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7221 SSVAL(req->outbuf,smb_vwv10, mode);
7223 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7225 END_PROFILE(SMBgetattrE);
7226 return;