Revert commit "0551284dc08eb93ef7b2b2227a45e5ec21d482fb" - simplify
[Samba/fernandojvsilva.git] / source3 / smbd / reply.c
blob37634acc2ce4b5ac35169939b796b8124dc2e87d
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"
28 #include "smbd/globals.h"
30 /****************************************************************************
31 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
32 path or anything including wildcards.
33 We're assuming here that '/' is not the second byte in any multibyte char
34 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
35 set.
36 ****************************************************************************/
38 /* Custom version for processing POSIX paths. */
39 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
41 static NTSTATUS check_path_syntax_internal(char *path,
42 bool posix_path,
43 bool *p_last_component_contains_wcard)
45 char *d = path;
46 const char *s = path;
47 NTSTATUS ret = NT_STATUS_OK;
48 bool start_of_name_component = True;
49 bool stream_started = false;
51 *p_last_component_contains_wcard = False;
53 while (*s) {
54 if (stream_started) {
55 switch (*s) {
56 case '/':
57 case '\\':
58 return NT_STATUS_OBJECT_NAME_INVALID;
59 case ':':
60 if (s[1] == '\0') {
61 return NT_STATUS_OBJECT_NAME_INVALID;
63 if (strchr_m(&s[1], ':')) {
64 return NT_STATUS_OBJECT_NAME_INVALID;
66 break;
70 if (!posix_path && !stream_started && *s == ':') {
71 if (*p_last_component_contains_wcard) {
72 return NT_STATUS_OBJECT_NAME_INVALID;
74 /* Stream names allow more characters than file names.
75 We're overloading posix_path here to allow a wider
76 range of characters. If stream_started is true this
77 is still a Windows path even if posix_path is true.
78 JRA.
80 stream_started = true;
81 start_of_name_component = false;
82 posix_path = true;
84 if (s[1] == '\0') {
85 return NT_STATUS_OBJECT_NAME_INVALID;
89 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
91 * Safe to assume is not the second part of a mb char
92 * as this is handled below.
94 /* Eat multiple '/' or '\\' */
95 while (IS_PATH_SEP(*s,posix_path)) {
96 s++;
98 if ((d != path) && (*s != '\0')) {
99 /* We only care about non-leading or trailing '/' or '\\' */
100 *d++ = '/';
103 start_of_name_component = True;
104 /* New component. */
105 *p_last_component_contains_wcard = False;
106 continue;
109 if (start_of_name_component) {
110 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
111 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
114 * No mb char starts with '.' so we're safe checking the directory separator here.
117 /* If we just added a '/' - delete it */
118 if ((d > path) && (*(d-1) == '/')) {
119 *(d-1) = '\0';
120 d--;
123 /* Are we at the start ? Can't go back further if so. */
124 if (d <= path) {
125 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
126 break;
128 /* Go back one level... */
129 /* We know this is safe as '/' cannot be part of a mb sequence. */
130 /* NOTE - if this assumption is invalid we are not in good shape... */
131 /* Decrement d first as d points to the *next* char to write into. */
132 for (d--; d > path; d--) {
133 if (*d == '/')
134 break;
136 s += 2; /* Else go past the .. */
137 /* We're still at the start of a name component, just the previous one. */
138 continue;
140 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
141 if (posix_path) {
142 /* Eat the '.' */
143 s++;
144 continue;
150 if (!(*s & 0x80)) {
151 if (!posix_path) {
152 if (*s <= 0x1f || *s == '|') {
153 return NT_STATUS_OBJECT_NAME_INVALID;
155 switch (*s) {
156 case '*':
157 case '?':
158 case '<':
159 case '>':
160 case '"':
161 *p_last_component_contains_wcard = True;
162 break;
163 default:
164 break;
167 *d++ = *s++;
168 } else {
169 size_t siz;
170 /* Get the size of the next MB character. */
171 next_codepoint(s,&siz);
172 switch(siz) {
173 case 5:
174 *d++ = *s++;
175 /*fall through*/
176 case 4:
177 *d++ = *s++;
178 /*fall through*/
179 case 3:
180 *d++ = *s++;
181 /*fall through*/
182 case 2:
183 *d++ = *s++;
184 /*fall through*/
185 case 1:
186 *d++ = *s++;
187 break;
188 default:
189 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
190 *d = '\0';
191 return NT_STATUS_INVALID_PARAMETER;
194 start_of_name_component = False;
197 *d = '\0';
199 return ret;
202 /****************************************************************************
203 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
204 No wildcards allowed.
205 ****************************************************************************/
207 NTSTATUS check_path_syntax(char *path)
209 bool ignore;
210 return check_path_syntax_internal(path, False, &ignore);
213 /****************************************************************************
214 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
215 Wildcards allowed - p_contains_wcard returns true if the last component contained
216 a wildcard.
217 ****************************************************************************/
219 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
221 return check_path_syntax_internal(path, False, p_contains_wcard);
224 /****************************************************************************
225 Check the path for a POSIX client.
226 We're assuming here that '/' is not the second byte in any multibyte char
227 set (a safe assumption).
228 ****************************************************************************/
230 NTSTATUS check_path_syntax_posix(char *path)
232 bool ignore;
233 return check_path_syntax_internal(path, True, &ignore);
236 /****************************************************************************
237 Pull a string and check the path allowing a wilcard - provide for error return.
238 ****************************************************************************/
240 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
241 const char *base_ptr,
242 uint16 smb_flags2,
243 char **pp_dest,
244 const char *src,
245 size_t src_len,
246 int flags,
247 NTSTATUS *err,
248 bool *contains_wcard)
250 size_t ret;
252 *pp_dest = NULL;
254 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
255 src_len, flags);
257 if (!*pp_dest) {
258 *err = NT_STATUS_INVALID_PARAMETER;
259 return ret;
262 *contains_wcard = False;
264 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
266 * For a DFS path the function parse_dfs_path()
267 * will do the path processing, just make a copy.
269 *err = NT_STATUS_OK;
270 return ret;
273 if (lp_posix_pathnames()) {
274 *err = check_path_syntax_posix(*pp_dest);
275 } else {
276 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
279 return ret;
282 /****************************************************************************
283 Pull a string and check the path - provide for error return.
284 ****************************************************************************/
286 size_t srvstr_get_path(TALLOC_CTX *ctx,
287 const char *base_ptr,
288 uint16 smb_flags2,
289 char **pp_dest,
290 const char *src,
291 size_t src_len,
292 int flags,
293 NTSTATUS *err)
295 bool ignore;
296 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
297 src_len, flags, err, &ignore);
300 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
301 char **pp_dest, const char *src, int flags,
302 NTSTATUS *err, bool *contains_wcard)
304 return srvstr_get_path_wcard(mem_ctx, (char *)req->inbuf, req->flags2,
305 pp_dest, src, smbreq_bufrem(req, src),
306 flags, err, contains_wcard);
309 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
310 char **pp_dest, const char *src, int flags,
311 NTSTATUS *err)
313 bool ignore;
314 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
315 flags, err, &ignore);
318 /****************************************************************************
319 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
320 ****************************************************************************/
322 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
323 files_struct *fsp)
325 if (!(fsp) || !(conn)) {
326 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
327 return False;
329 if (((conn) != (fsp)->conn) || req->vuid != (fsp)->vuid) {
330 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
331 return False;
333 return True;
336 /****************************************************************************
337 Check if we have a correct fsp pointing to a file.
338 ****************************************************************************/
340 bool check_fsp(connection_struct *conn, struct smb_request *req,
341 files_struct *fsp)
343 if (!check_fsp_open(conn, req, fsp)) {
344 return False;
346 if ((fsp)->is_directory) {
347 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
348 return False;
350 if ((fsp)->fh->fd == -1) {
351 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
352 return False;
354 (fsp)->num_smb_operations++;
355 return True;
358 /****************************************************************************
359 Check if we have a correct fsp pointing to a quota fake file. Replacement for
360 the CHECK_NTQUOTA_HANDLE_OK macro.
361 ****************************************************************************/
363 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
364 files_struct *fsp)
366 if (!check_fsp_open(conn, req, fsp)) {
367 return false;
370 if (fsp->is_directory) {
371 return false;
374 if (fsp->fake_file_handle == NULL) {
375 return false;
378 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
379 return false;
382 if (fsp->fake_file_handle->private_data == NULL) {
383 return false;
386 return true;
389 /****************************************************************************
390 Check if we have a correct fsp. Replacement for the FSP_BELONGS_CONN macro
391 ****************************************************************************/
393 bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req,
394 files_struct *fsp)
396 if ((fsp) && (conn) && ((conn)==(fsp)->conn)
397 && (req->vuid == (fsp)->vuid)) {
398 return True;
401 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
402 return False;
405 static bool netbios_session_retarget(const char *name, int name_type)
407 char *trim_name;
408 char *trim_name_type;
409 const char *retarget_parm;
410 char *retarget;
411 char *p;
412 int retarget_type = 0x20;
413 int retarget_port = 139;
414 struct sockaddr_storage retarget_addr;
415 struct sockaddr_in *in_addr;
416 bool ret = false;
417 uint8_t outbuf[10];
419 if (get_socket_port(smbd_server_fd()) != 139) {
420 return false;
423 trim_name = talloc_strdup(talloc_tos(), name);
424 if (trim_name == NULL) {
425 goto fail;
427 trim_char(trim_name, ' ', ' ');
429 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
430 name_type);
431 if (trim_name_type == NULL) {
432 goto fail;
435 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
436 trim_name_type, NULL);
437 if (retarget_parm == NULL) {
438 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
439 trim_name, NULL);
441 if (retarget_parm == NULL) {
442 goto fail;
445 retarget = talloc_strdup(trim_name, retarget_parm);
446 if (retarget == NULL) {
447 goto fail;
450 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
452 p = strchr(retarget, ':');
453 if (p != NULL) {
454 *p++ = '\0';
455 retarget_port = atoi(p);
458 p = strchr_m(retarget, '#');
459 if (p != NULL) {
460 *p++ = '\0';
461 sscanf(p, "%x", &retarget_type);
464 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
465 if (!ret) {
466 DEBUG(10, ("could not resolve %s\n", retarget));
467 goto fail;
470 if (retarget_addr.ss_family != AF_INET) {
471 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
472 goto fail;
475 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
477 _smb_setlen(outbuf, 6);
478 SCVAL(outbuf, 0, 0x84);
479 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
480 *(uint16_t *)(outbuf+8) = htons(retarget_port);
482 if (!srv_send_smb(smbd_server_fd(), (char *)outbuf, false, 0, false,
483 NULL)) {
484 exit_server_cleanly("netbios_session_regarget: srv_send_smb "
485 "failed.");
488 ret = true;
489 fail:
490 TALLOC_FREE(trim_name);
491 return ret;
494 /****************************************************************************
495 Reply to a (netbios-level) special message.
496 ****************************************************************************/
498 void reply_special(char *inbuf)
500 int msg_type = CVAL(inbuf,0);
501 int msg_flags = CVAL(inbuf,1);
502 fstring name1,name2;
503 char name_type1, name_type2;
504 struct smbd_server_connection *sconn = smbd_server_conn;
507 * We only really use 4 bytes of the outbuf, but for the smb_setlen
508 * calculation & friends (srv_send_smb uses that) we need the full smb
509 * header.
511 char outbuf[smb_size];
513 *name1 = *name2 = 0;
515 memset(outbuf, '\0', sizeof(outbuf));
517 smb_setlen(outbuf,0);
519 switch (msg_type) {
520 case 0x81: /* session request */
522 if (sconn->nbt.got_session) {
523 exit_server_cleanly("multiple session request not permitted");
526 SCVAL(outbuf,0,0x82);
527 SCVAL(outbuf,3,0);
528 if (name_len(inbuf+4) > 50 ||
529 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
530 DEBUG(0,("Invalid name length in session request\n"));
531 return;
533 name_type1 = name_extract(inbuf,4,name1);
534 name_type2 = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
535 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
536 name1, name_type1, name2, name_type2));
538 if (netbios_session_retarget(name1, name_type1)) {
539 exit_server_cleanly("retargeted client");
542 set_local_machine_name(name1, True);
543 set_remote_machine_name(name2, True);
545 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
546 get_local_machine_name(), get_remote_machine_name(),
547 name_type2));
549 if (name_type2 == 'R') {
550 /* We are being asked for a pathworks session ---
551 no thanks! */
552 SCVAL(outbuf, 0,0x83);
553 break;
556 /* only add the client's machine name to the list
557 of possibly valid usernames if we are operating
558 in share mode security */
559 if (lp_security() == SEC_SHARE) {
560 add_session_user(sconn, get_remote_machine_name());
563 reload_services(True);
564 reopen_logs();
566 sconn->nbt.got_session = true;
567 break;
569 case 0x89: /* session keepalive request
570 (some old clients produce this?) */
571 SCVAL(outbuf,0,SMBkeepalive);
572 SCVAL(outbuf,3,0);
573 break;
575 case 0x82: /* positive session response */
576 case 0x83: /* negative session response */
577 case 0x84: /* retarget session response */
578 DEBUG(0,("Unexpected session response\n"));
579 break;
581 case SMBkeepalive: /* session keepalive */
582 default:
583 return;
586 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
587 msg_type, msg_flags));
589 srv_send_smb(smbd_server_fd(), outbuf, false, 0, false, NULL);
590 return;
593 /****************************************************************************
594 Reply to a tcon.
595 conn POINTER CAN BE NULL HERE !
596 ****************************************************************************/
598 void reply_tcon(struct smb_request *req)
600 connection_struct *conn = req->conn;
601 const char *service;
602 char *service_buf = NULL;
603 char *password = NULL;
604 char *dev = NULL;
605 int pwlen=0;
606 NTSTATUS nt_status;
607 const char *p;
608 DATA_BLOB password_blob;
609 TALLOC_CTX *ctx = talloc_tos();
610 struct smbd_server_connection *sconn = smbd_server_conn;
612 START_PROFILE(SMBtcon);
614 if (req->buflen < 4) {
615 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
616 END_PROFILE(SMBtcon);
617 return;
620 p = (const char *)req->buf + 1;
621 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
622 p += 1;
623 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
624 p += pwlen+1;
625 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
626 p += 1;
628 if (service_buf == NULL || password == NULL || dev == NULL) {
629 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
630 END_PROFILE(SMBtcon);
631 return;
633 p = strrchr_m(service_buf,'\\');
634 if (p) {
635 service = p+1;
636 } else {
637 service = service_buf;
640 password_blob = data_blob(password, pwlen+1);
642 conn = make_connection(sconn,service,password_blob,dev,
643 req->vuid,&nt_status);
644 req->conn = conn;
646 data_blob_clear_free(&password_blob);
648 if (!conn) {
649 reply_nterror(req, nt_status);
650 END_PROFILE(SMBtcon);
651 return;
654 reply_outbuf(req, 2, 0);
655 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
656 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
657 SSVAL(req->outbuf,smb_tid,conn->cnum);
659 DEBUG(3,("tcon service=%s cnum=%d\n",
660 service, conn->cnum));
662 END_PROFILE(SMBtcon);
663 return;
666 /****************************************************************************
667 Reply to a tcon and X.
668 conn POINTER CAN BE NULL HERE !
669 ****************************************************************************/
671 void reply_tcon_and_X(struct smb_request *req)
673 connection_struct *conn = req->conn;
674 const char *service = NULL;
675 DATA_BLOB password;
676 TALLOC_CTX *ctx = talloc_tos();
677 /* what the cleint thinks the device is */
678 char *client_devicetype = NULL;
679 /* what the server tells the client the share represents */
680 const char *server_devicetype;
681 NTSTATUS nt_status;
682 int passlen;
683 char *path = NULL;
684 const char *p, *q;
685 uint16 tcon_flags;
686 struct smbd_server_connection *sconn = smbd_server_conn;
688 START_PROFILE(SMBtconX);
690 if (req->wct < 4) {
691 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
692 END_PROFILE(SMBtconX);
693 return;
696 passlen = SVAL(req->vwv+3, 0);
697 tcon_flags = SVAL(req->vwv+2, 0);
699 /* we might have to close an old one */
700 if ((tcon_flags & 0x1) && conn) {
701 close_cnum(conn,req->vuid);
702 req->conn = NULL;
703 conn = NULL;
706 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
707 reply_doserror(req, ERRDOS, ERRbuftoosmall);
708 END_PROFILE(SMBtconX);
709 return;
712 if (sconn->smb1.negprot.encrypted_passwords) {
713 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
714 if (lp_security() == SEC_SHARE) {
716 * Security = share always has a pad byte
717 * after the password.
719 p = (const char *)req->buf + passlen + 1;
720 } else {
721 p = (const char *)req->buf + passlen;
723 } else {
724 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
725 /* Ensure correct termination */
726 password.data[passlen]=0;
727 p = (const char *)req->buf + passlen + 1;
730 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
732 if (path == NULL) {
733 data_blob_clear_free(&password);
734 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
735 END_PROFILE(SMBtconX);
736 return;
740 * the service name can be either: \\server\share
741 * or share directly like on the DELL PowerVault 705
743 if (*path=='\\') {
744 q = strchr_m(path+2,'\\');
745 if (!q) {
746 data_blob_clear_free(&password);
747 reply_doserror(req, ERRDOS, ERRnosuchshare);
748 END_PROFILE(SMBtconX);
749 return;
751 service = q+1;
752 } else {
753 service = path;
756 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
757 &client_devicetype, p,
758 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
760 if (client_devicetype == NULL) {
761 data_blob_clear_free(&password);
762 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
763 END_PROFILE(SMBtconX);
764 return;
767 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
769 conn = make_connection(sconn, service, password, client_devicetype,
770 req->vuid, &nt_status);
771 req->conn =conn;
773 data_blob_clear_free(&password);
775 if (!conn) {
776 reply_nterror(req, nt_status);
777 END_PROFILE(SMBtconX);
778 return;
781 if ( IS_IPC(conn) )
782 server_devicetype = "IPC";
783 else if ( IS_PRINT(conn) )
784 server_devicetype = "LPT1:";
785 else
786 server_devicetype = "A:";
788 if (get_Protocol() < PROTOCOL_NT1) {
789 reply_outbuf(req, 2, 0);
790 if (message_push_string(&req->outbuf, server_devicetype,
791 STR_TERMINATE|STR_ASCII) == -1) {
792 reply_nterror(req, NT_STATUS_NO_MEMORY);
793 END_PROFILE(SMBtconX);
794 return;
796 } else {
797 /* NT sets the fstype of IPC$ to the null string */
798 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
800 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
801 /* Return permissions. */
802 uint32 perm1 = 0;
803 uint32 perm2 = 0;
805 reply_outbuf(req, 7, 0);
807 if (IS_IPC(conn)) {
808 perm1 = FILE_ALL_ACCESS;
809 perm2 = FILE_ALL_ACCESS;
810 } else {
811 perm1 = CAN_WRITE(conn) ?
812 SHARE_ALL_ACCESS :
813 SHARE_READ_ONLY;
816 SIVAL(req->outbuf, smb_vwv3, perm1);
817 SIVAL(req->outbuf, smb_vwv5, perm2);
818 } else {
819 reply_outbuf(req, 3, 0);
822 if ((message_push_string(&req->outbuf, server_devicetype,
823 STR_TERMINATE|STR_ASCII) == -1)
824 || (message_push_string(&req->outbuf, fstype,
825 STR_TERMINATE) == -1)) {
826 reply_nterror(req, NT_STATUS_NO_MEMORY);
827 END_PROFILE(SMBtconX);
828 return;
831 /* what does setting this bit do? It is set by NT4 and
832 may affect the ability to autorun mounted cdroms */
833 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
834 (lp_csc_policy(SNUM(conn)) << 2));
836 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
837 DEBUG(2,("Serving %s as a Dfs root\n",
838 lp_servicename(SNUM(conn)) ));
839 SSVAL(req->outbuf, smb_vwv2,
840 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
845 DEBUG(3,("tconX service=%s \n",
846 service));
848 /* set the incoming and outgoing tid to the just created one */
849 SSVAL(req->inbuf,smb_tid,conn->cnum);
850 SSVAL(req->outbuf,smb_tid,conn->cnum);
852 END_PROFILE(SMBtconX);
854 req->tid = conn->cnum;
855 chain_reply(req);
856 return;
859 /****************************************************************************
860 Reply to an unknown type.
861 ****************************************************************************/
863 void reply_unknown_new(struct smb_request *req, uint8 type)
865 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
866 smb_fn_name(type), type, type));
867 reply_doserror(req, ERRSRV, ERRunknownsmb);
868 return;
871 /****************************************************************************
872 Reply to an ioctl.
873 conn POINTER CAN BE NULL HERE !
874 ****************************************************************************/
876 void reply_ioctl(struct smb_request *req)
878 connection_struct *conn = req->conn;
879 uint16 device;
880 uint16 function;
881 uint32 ioctl_code;
882 int replysize;
883 char *p;
885 START_PROFILE(SMBioctl);
887 if (req->wct < 3) {
888 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
889 END_PROFILE(SMBioctl);
890 return;
893 device = SVAL(req->vwv+1, 0);
894 function = SVAL(req->vwv+2, 0);
895 ioctl_code = (device << 16) + function;
897 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
899 switch (ioctl_code) {
900 case IOCTL_QUERY_JOB_INFO:
901 replysize = 32;
902 break;
903 default:
904 reply_doserror(req, ERRSRV, ERRnosupport);
905 END_PROFILE(SMBioctl);
906 return;
909 reply_outbuf(req, 8, replysize+1);
910 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
911 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
912 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
913 p = smb_buf(req->outbuf);
914 memset(p, '\0', replysize+1); /* valgrind-safe. */
915 p += 1; /* Allow for alignment */
917 switch (ioctl_code) {
918 case IOCTL_QUERY_JOB_INFO:
920 files_struct *fsp = file_fsp(
921 req, SVAL(req->vwv+0, 0));
922 if (!fsp) {
923 reply_doserror(req, ERRDOS, ERRbadfid);
924 END_PROFILE(SMBioctl);
925 return;
927 SSVAL(p,0,fsp->rap_print_jobid); /* Job number */
928 srvstr_push((char *)req->outbuf, req->flags2, p+2,
929 global_myname(), 15,
930 STR_TERMINATE|STR_ASCII);
931 if (conn) {
932 srvstr_push((char *)req->outbuf, req->flags2,
933 p+18, lp_servicename(SNUM(conn)),
934 13, STR_TERMINATE|STR_ASCII);
935 } else {
936 memset(p+18, 0, 13);
938 break;
942 END_PROFILE(SMBioctl);
943 return;
946 /****************************************************************************
947 Strange checkpath NTSTATUS mapping.
948 ****************************************************************************/
950 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
952 /* Strange DOS error code semantics only for checkpath... */
953 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
954 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
955 /* We need to map to ERRbadpath */
956 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
959 return status;
962 /****************************************************************************
963 Reply to a checkpath.
964 ****************************************************************************/
966 void reply_checkpath(struct smb_request *req)
968 connection_struct *conn = req->conn;
969 struct smb_filename *smb_fname = NULL;
970 char *name = NULL;
971 NTSTATUS status;
972 TALLOC_CTX *ctx = talloc_tos();
974 START_PROFILE(SMBcheckpath);
976 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
977 STR_TERMINATE, &status);
979 if (!NT_STATUS_IS_OK(status)) {
980 status = map_checkpath_error(req->flags2, status);
981 reply_nterror(req, status);
982 END_PROFILE(SMBcheckpath);
983 return;
986 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
988 status = filename_convert(ctx,
989 conn,
990 req->flags2 & FLAGS2_DFS_PATHNAMES,
991 name,
993 NULL,
994 &smb_fname);
996 if (!NT_STATUS_IS_OK(status)) {
997 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
998 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
999 ERRSRV, ERRbadpath);
1000 END_PROFILE(SMBcheckpath);
1001 return;
1003 goto path_err;
1006 if (!VALID_STAT(smb_fname->st) &&
1007 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1008 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1009 smb_fname_str_dbg(smb_fname), strerror(errno)));
1010 status = map_nt_error_from_unix(errno);
1011 goto path_err;
1014 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1015 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1016 ERRDOS, ERRbadpath);
1017 goto out;
1020 reply_outbuf(req, 0, 0);
1022 path_err:
1023 /* We special case this - as when a Windows machine
1024 is parsing a path is steps through the components
1025 one at a time - if a component fails it expects
1026 ERRbadpath, not ERRbadfile.
1028 status = map_checkpath_error(req->flags2, status);
1029 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1031 * Windows returns different error codes if
1032 * the parent directory is valid but not the
1033 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1034 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1035 * if the path is invalid.
1037 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1038 ERRDOS, ERRbadpath);
1039 goto out;
1042 reply_nterror(req, status);
1044 out:
1045 TALLOC_FREE(smb_fname);
1046 END_PROFILE(SMBcheckpath);
1047 return;
1050 /****************************************************************************
1051 Reply to a getatr.
1052 ****************************************************************************/
1054 void reply_getatr(struct smb_request *req)
1056 connection_struct *conn = req->conn;
1057 struct smb_filename *smb_fname = NULL;
1058 char *fname = NULL;
1059 int mode=0;
1060 SMB_OFF_T size=0;
1061 time_t mtime=0;
1062 const char *p;
1063 NTSTATUS status;
1064 TALLOC_CTX *ctx = talloc_tos();
1065 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1067 START_PROFILE(SMBgetatr);
1069 p = (const char *)req->buf + 1;
1070 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1071 if (!NT_STATUS_IS_OK(status)) {
1072 reply_nterror(req, status);
1073 goto out;
1076 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1077 under WfWg - weird! */
1078 if (*fname == '\0') {
1079 mode = aHIDDEN | aDIR;
1080 if (!CAN_WRITE(conn)) {
1081 mode |= aRONLY;
1083 size = 0;
1084 mtime = 0;
1085 } else {
1086 status = filename_convert(ctx,
1087 conn,
1088 req->flags2 & FLAGS2_DFS_PATHNAMES,
1089 fname,
1091 NULL,
1092 &smb_fname);
1093 if (!NT_STATUS_IS_OK(status)) {
1094 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1095 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1096 ERRSRV, ERRbadpath);
1097 goto out;
1099 reply_nterror(req, status);
1100 goto out;
1102 if (!VALID_STAT(smb_fname->st) &&
1103 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1104 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1105 smb_fname_str_dbg(smb_fname),
1106 strerror(errno)));
1107 reply_nterror(req, map_nt_error_from_unix(errno));
1108 goto out;
1111 mode = dos_mode(conn, smb_fname);
1112 size = smb_fname->st.st_ex_size;
1114 if (ask_sharemode) {
1115 struct timespec write_time_ts;
1116 struct file_id fileid;
1118 ZERO_STRUCT(write_time_ts);
1119 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1120 get_file_infos(fileid, NULL, &write_time_ts);
1121 if (!null_timespec(write_time_ts)) {
1122 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1126 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1127 if (mode & aDIR) {
1128 size = 0;
1132 reply_outbuf(req, 10, 0);
1134 SSVAL(req->outbuf,smb_vwv0,mode);
1135 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1136 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1137 } else {
1138 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1140 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1142 if (get_Protocol() >= PROTOCOL_NT1) {
1143 SSVAL(req->outbuf, smb_flg2,
1144 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1147 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1148 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1150 out:
1151 TALLOC_FREE(smb_fname);
1152 TALLOC_FREE(fname);
1153 END_PROFILE(SMBgetatr);
1154 return;
1157 /****************************************************************************
1158 Reply to a setatr.
1159 ****************************************************************************/
1161 void reply_setatr(struct smb_request *req)
1163 struct smb_file_time ft;
1164 connection_struct *conn = req->conn;
1165 struct smb_filename *smb_fname = NULL;
1166 char *fname = NULL;
1167 int mode;
1168 time_t mtime;
1169 const char *p;
1170 NTSTATUS status;
1171 TALLOC_CTX *ctx = talloc_tos();
1173 START_PROFILE(SMBsetatr);
1175 ZERO_STRUCT(ft);
1177 if (req->wct < 2) {
1178 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1179 goto out;
1182 p = (const char *)req->buf + 1;
1183 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1184 if (!NT_STATUS_IS_OK(status)) {
1185 reply_nterror(req, status);
1186 goto out;
1189 status = filename_convert(ctx,
1190 conn,
1191 req->flags2 & FLAGS2_DFS_PATHNAMES,
1192 fname,
1194 NULL,
1195 &smb_fname);
1196 if (!NT_STATUS_IS_OK(status)) {
1197 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1198 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1199 ERRSRV, ERRbadpath);
1200 goto out;
1202 reply_nterror(req, status);
1203 goto out;
1206 if (smb_fname->base_name[0] == '.' &&
1207 smb_fname->base_name[1] == '\0') {
1209 * Not sure here is the right place to catch this
1210 * condition. Might be moved to somewhere else later -- vl
1212 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1213 goto out;
1216 mode = SVAL(req->vwv+0, 0);
1217 mtime = srv_make_unix_date3(req->vwv+1);
1219 ft.mtime = convert_time_t_to_timespec(mtime);
1220 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1221 if (!NT_STATUS_IS_OK(status)) {
1222 reply_nterror(req, status);
1223 goto out;
1226 if (mode != FILE_ATTRIBUTE_NORMAL) {
1227 if (VALID_STAT_OF_DIR(smb_fname->st))
1228 mode |= aDIR;
1229 else
1230 mode &= ~aDIR;
1232 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1233 false) != 0) {
1234 reply_nterror(req, map_nt_error_from_unix(errno));
1235 goto out;
1239 reply_outbuf(req, 0, 0);
1241 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1242 mode));
1243 out:
1244 TALLOC_FREE(smb_fname);
1245 END_PROFILE(SMBsetatr);
1246 return;
1249 /****************************************************************************
1250 Reply to a dskattr.
1251 ****************************************************************************/
1253 void reply_dskattr(struct smb_request *req)
1255 connection_struct *conn = req->conn;
1256 uint64_t dfree,dsize,bsize;
1257 START_PROFILE(SMBdskattr);
1259 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1260 reply_nterror(req, map_nt_error_from_unix(errno));
1261 END_PROFILE(SMBdskattr);
1262 return;
1265 reply_outbuf(req, 5, 0);
1267 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1268 double total_space, free_space;
1269 /* we need to scale this to a number that DOS6 can handle. We
1270 use floating point so we can handle large drives on systems
1271 that don't have 64 bit integers
1273 we end up displaying a maximum of 2G to DOS systems
1275 total_space = dsize * (double)bsize;
1276 free_space = dfree * (double)bsize;
1278 dsize = (uint64_t)((total_space+63*512) / (64*512));
1279 dfree = (uint64_t)((free_space+63*512) / (64*512));
1281 if (dsize > 0xFFFF) dsize = 0xFFFF;
1282 if (dfree > 0xFFFF) dfree = 0xFFFF;
1284 SSVAL(req->outbuf,smb_vwv0,dsize);
1285 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1286 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1287 SSVAL(req->outbuf,smb_vwv3,dfree);
1288 } else {
1289 SSVAL(req->outbuf,smb_vwv0,dsize);
1290 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1291 SSVAL(req->outbuf,smb_vwv2,512);
1292 SSVAL(req->outbuf,smb_vwv3,dfree);
1295 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1297 END_PROFILE(SMBdskattr);
1298 return;
1302 * Utility function to split the filename from the directory.
1304 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1305 char **fname_dir_out,
1306 char **fname_mask_out)
1308 const char *p = NULL;
1309 char *fname_dir = NULL;
1310 char *fname_mask = NULL;
1312 p = strrchr_m(fname_in, '/');
1313 if (!p) {
1314 fname_dir = talloc_strdup(ctx, ".");
1315 fname_mask = talloc_strdup(ctx, fname_in);
1316 } else {
1317 fname_dir = talloc_strndup(ctx, fname_in,
1318 PTR_DIFF(p, fname_in));
1319 fname_mask = talloc_strdup(ctx, p+1);
1322 if (!fname_dir || !fname_mask) {
1323 TALLOC_FREE(fname_dir);
1324 TALLOC_FREE(fname_mask);
1325 return NT_STATUS_NO_MEMORY;
1328 *fname_dir_out = fname_dir;
1329 *fname_mask_out = fname_mask;
1330 return NT_STATUS_OK;
1333 /****************************************************************************
1334 Reply to a search.
1335 Can be called from SMBsearch, SMBffirst or SMBfunique.
1336 ****************************************************************************/
1338 void reply_search(struct smb_request *req)
1340 connection_struct *conn = req->conn;
1341 char *path = NULL;
1342 const char *mask = NULL;
1343 char *directory = NULL;
1344 struct smb_filename *smb_fname = NULL;
1345 char *fname = NULL;
1346 SMB_OFF_T size;
1347 uint32 mode;
1348 struct timespec date;
1349 uint32 dirtype;
1350 unsigned int numentries = 0;
1351 unsigned int maxentries = 0;
1352 bool finished = False;
1353 const char *p;
1354 int status_len;
1355 char status[21];
1356 int dptr_num= -1;
1357 bool check_descend = False;
1358 bool expect_close = False;
1359 NTSTATUS nt_status;
1360 bool mask_contains_wcard = False;
1361 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1362 TALLOC_CTX *ctx = talloc_tos();
1363 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1364 struct dptr_struct *dirptr = NULL;
1365 struct smbd_server_connection *sconn = smbd_server_conn;
1367 START_PROFILE(SMBsearch);
1369 if (req->wct < 2) {
1370 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1371 goto out;
1374 if (lp_posix_pathnames()) {
1375 reply_unknown_new(req, req->cmd);
1376 goto out;
1379 /* If we were called as SMBffirst then we must expect close. */
1380 if(req->cmd == SMBffirst) {
1381 expect_close = True;
1384 reply_outbuf(req, 1, 3);
1385 maxentries = SVAL(req->vwv+0, 0);
1386 dirtype = SVAL(req->vwv+1, 0);
1387 p = (const char *)req->buf + 1;
1388 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1389 &nt_status, &mask_contains_wcard);
1390 if (!NT_STATUS_IS_OK(nt_status)) {
1391 reply_nterror(req, nt_status);
1392 goto out;
1395 p++;
1396 status_len = SVAL(p, 0);
1397 p += 2;
1399 /* dirtype &= ~aDIR; */
1401 if (status_len == 0) {
1402 nt_status = filename_convert(ctx, conn,
1403 req->flags2 & FLAGS2_DFS_PATHNAMES,
1404 path,
1405 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1406 &mask_contains_wcard,
1407 &smb_fname);
1408 if (!NT_STATUS_IS_OK(nt_status)) {
1409 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1410 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1411 ERRSRV, ERRbadpath);
1412 goto out;
1414 reply_nterror(req, nt_status);
1415 goto out;
1418 directory = smb_fname->base_name;
1420 p = strrchr_m(directory,'/');
1421 if ((p != NULL) && (*directory != '/')) {
1422 mask = p + 1;
1423 directory = talloc_strndup(ctx, directory,
1424 PTR_DIFF(p, directory));
1425 } else {
1426 mask = directory;
1427 directory = talloc_strdup(ctx,".");
1430 if (!directory) {
1431 reply_nterror(req, NT_STATUS_NO_MEMORY);
1432 goto out;
1435 memset((char *)status,'\0',21);
1436 SCVAL(status,0,(dirtype & 0x1F));
1438 nt_status = dptr_create(conn,
1439 directory,
1440 True,
1441 expect_close,
1442 req->smbpid,
1443 mask,
1444 mask_contains_wcard,
1445 dirtype,
1446 &dirptr);
1447 if (!NT_STATUS_IS_OK(nt_status)) {
1448 reply_nterror(req, nt_status);
1449 goto out;
1451 dptr_num = dptr_dnum(dirptr);
1452 } else {
1453 int status_dirtype;
1454 const char *dirpath;
1456 memcpy(status,p,21);
1457 status_dirtype = CVAL(status,0) & 0x1F;
1458 if (status_dirtype != (dirtype & 0x1F)) {
1459 dirtype = status_dirtype;
1462 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1463 if (!dirptr) {
1464 goto SearchEmpty;
1466 dirpath = dptr_path(sconn, dptr_num);
1467 directory = talloc_strdup(ctx, dirpath);
1468 if (!directory) {
1469 reply_nterror(req, NT_STATUS_NO_MEMORY);
1470 goto out;
1473 mask = dptr_wcard(sconn, dptr_num);
1474 if (!mask) {
1475 goto SearchEmpty;
1478 * For a 'continue' search we have no string. So
1479 * check from the initial saved string.
1481 mask_contains_wcard = ms_has_wild(mask);
1482 dirtype = dptr_attr(sconn, dptr_num);
1485 DEBUG(4,("dptr_num is %d\n",dptr_num));
1487 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1488 dptr_init_search_op(dirptr);
1490 if ((dirtype&0x1F) == aVOLID) {
1491 char buf[DIR_STRUCT_SIZE];
1492 memcpy(buf,status,21);
1493 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1494 0,aVOLID,0,!allow_long_path_components)) {
1495 reply_nterror(req, NT_STATUS_NO_MEMORY);
1496 goto out;
1498 dptr_fill(sconn, buf+12,dptr_num);
1499 if (dptr_zero(buf+12) && (status_len==0)) {
1500 numentries = 1;
1501 } else {
1502 numentries = 0;
1504 if (message_push_blob(&req->outbuf,
1505 data_blob_const(buf, sizeof(buf)))
1506 == -1) {
1507 reply_nterror(req, NT_STATUS_NO_MEMORY);
1508 goto out;
1510 } else {
1511 unsigned int i;
1512 maxentries = MIN(
1513 maxentries,
1514 ((BUFFER_SIZE -
1515 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1516 /DIR_STRUCT_SIZE));
1518 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1519 directory,lp_dontdescend(SNUM(conn))));
1520 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1521 check_descend = True;
1524 for (i=numentries;(i<maxentries) && !finished;i++) {
1525 finished = !get_dir_entry(ctx,
1526 dirptr,
1527 mask,
1528 dirtype,
1529 &fname,
1530 &size,
1531 &mode,
1532 &date,
1533 check_descend,
1534 ask_sharemode);
1535 if (!finished) {
1536 char buf[DIR_STRUCT_SIZE];
1537 memcpy(buf,status,21);
1538 if (!make_dir_struct(ctx,
1539 buf,
1540 mask,
1541 fname,
1542 size,
1543 mode,
1544 convert_timespec_to_time_t(date),
1545 !allow_long_path_components)) {
1546 reply_nterror(req, NT_STATUS_NO_MEMORY);
1547 goto out;
1549 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1550 break;
1552 if (message_push_blob(&req->outbuf,
1553 data_blob_const(buf, sizeof(buf)))
1554 == -1) {
1555 reply_nterror(req, NT_STATUS_NO_MEMORY);
1556 goto out;
1558 numentries++;
1563 SearchEmpty:
1565 /* If we were called as SMBffirst with smb_search_id == NULL
1566 and no entries were found then return error and close dirptr
1567 (X/Open spec) */
1569 if (numentries == 0) {
1570 dptr_close(sconn, &dptr_num);
1571 } else if(expect_close && status_len == 0) {
1572 /* Close the dptr - we know it's gone */
1573 dptr_close(sconn, &dptr_num);
1576 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1577 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1578 dptr_close(sconn, &dptr_num);
1581 if ((numentries == 0) && !mask_contains_wcard) {
1582 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1583 goto out;
1586 SSVAL(req->outbuf,smb_vwv0,numentries);
1587 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1588 SCVAL(smb_buf(req->outbuf),0,5);
1589 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1591 /* The replies here are never long name. */
1592 SSVAL(req->outbuf, smb_flg2,
1593 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1594 if (!allow_long_path_components) {
1595 SSVAL(req->outbuf, smb_flg2,
1596 SVAL(req->outbuf, smb_flg2)
1597 & (~FLAGS2_LONG_PATH_COMPONENTS));
1600 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1601 SSVAL(req->outbuf, smb_flg2,
1602 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1604 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1605 smb_fn_name(req->cmd),
1606 mask,
1607 directory,
1608 dirtype,
1609 numentries,
1610 maxentries ));
1611 out:
1612 TALLOC_FREE(directory);
1613 TALLOC_FREE(smb_fname);
1614 END_PROFILE(SMBsearch);
1615 return;
1618 /****************************************************************************
1619 Reply to a fclose (stop directory search).
1620 ****************************************************************************/
1622 void reply_fclose(struct smb_request *req)
1624 int status_len;
1625 char status[21];
1626 int dptr_num= -2;
1627 const char *p;
1628 char *path = NULL;
1629 NTSTATUS err;
1630 bool path_contains_wcard = False;
1631 TALLOC_CTX *ctx = talloc_tos();
1632 struct smbd_server_connection *sconn = smbd_server_conn;
1634 START_PROFILE(SMBfclose);
1636 if (lp_posix_pathnames()) {
1637 reply_unknown_new(req, req->cmd);
1638 END_PROFILE(SMBfclose);
1639 return;
1642 p = (const char *)req->buf + 1;
1643 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1644 &err, &path_contains_wcard);
1645 if (!NT_STATUS_IS_OK(err)) {
1646 reply_nterror(req, err);
1647 END_PROFILE(SMBfclose);
1648 return;
1650 p++;
1651 status_len = SVAL(p,0);
1652 p += 2;
1654 if (status_len == 0) {
1655 reply_doserror(req, ERRSRV, ERRsrverror);
1656 END_PROFILE(SMBfclose);
1657 return;
1660 memcpy(status,p,21);
1662 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1663 /* Close the dptr - we know it's gone */
1664 dptr_close(sconn, &dptr_num);
1667 reply_outbuf(req, 1, 0);
1668 SSVAL(req->outbuf,smb_vwv0,0);
1670 DEBUG(3,("search close\n"));
1672 END_PROFILE(SMBfclose);
1673 return;
1676 /****************************************************************************
1677 Reply to an open.
1678 ****************************************************************************/
1680 void reply_open(struct smb_request *req)
1682 connection_struct *conn = req->conn;
1683 struct smb_filename *smb_fname = NULL;
1684 char *fname = NULL;
1685 uint32 fattr=0;
1686 SMB_OFF_T size = 0;
1687 time_t mtime=0;
1688 int info;
1689 files_struct *fsp;
1690 int oplock_request;
1691 int deny_mode;
1692 uint32 dos_attr;
1693 uint32 access_mask;
1694 uint32 share_mode;
1695 uint32 create_disposition;
1696 uint32 create_options = 0;
1697 NTSTATUS status;
1698 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1699 TALLOC_CTX *ctx = talloc_tos();
1701 START_PROFILE(SMBopen);
1703 if (req->wct < 2) {
1704 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1705 goto out;
1708 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1709 deny_mode = SVAL(req->vwv+0, 0);
1710 dos_attr = SVAL(req->vwv+1, 0);
1712 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1713 STR_TERMINATE, &status);
1714 if (!NT_STATUS_IS_OK(status)) {
1715 reply_nterror(req, status);
1716 goto out;
1719 status = filename_convert(ctx,
1720 conn,
1721 req->flags2 & FLAGS2_DFS_PATHNAMES,
1722 fname,
1724 NULL,
1725 &smb_fname);
1726 if (!NT_STATUS_IS_OK(status)) {
1727 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1728 reply_botherror(req,
1729 NT_STATUS_PATH_NOT_COVERED,
1730 ERRSRV, ERRbadpath);
1731 goto out;
1733 reply_nterror(req, status);
1734 goto out;
1737 if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
1738 OPENX_FILE_EXISTS_OPEN, &access_mask,
1739 &share_mode, &create_disposition,
1740 &create_options)) {
1741 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1742 goto out;
1745 status = SMB_VFS_CREATE_FILE(
1746 conn, /* conn */
1747 req, /* req */
1748 0, /* root_dir_fid */
1749 smb_fname, /* fname */
1750 access_mask, /* access_mask */
1751 share_mode, /* share_access */
1752 create_disposition, /* create_disposition*/
1753 create_options, /* create_options */
1754 dos_attr, /* file_attributes */
1755 oplock_request, /* oplock_request */
1756 0, /* allocation_size */
1757 NULL, /* sd */
1758 NULL, /* ea_list */
1759 &fsp, /* result */
1760 &info); /* pinfo */
1762 if (!NT_STATUS_IS_OK(status)) {
1763 if (open_was_deferred(req->mid)) {
1764 /* We have re-scheduled this call. */
1765 goto out;
1767 reply_openerror(req, status);
1768 goto out;
1771 size = smb_fname->st.st_ex_size;
1772 fattr = dos_mode(conn, smb_fname);
1774 /* Deal with other possible opens having a modified
1775 write time. JRA. */
1776 if (ask_sharemode) {
1777 struct timespec write_time_ts;
1779 ZERO_STRUCT(write_time_ts);
1780 get_file_infos(fsp->file_id, NULL, &write_time_ts);
1781 if (!null_timespec(write_time_ts)) {
1782 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1786 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1788 if (fattr & aDIR) {
1789 DEBUG(3,("attempt to open a directory %s\n",
1790 fsp_str_dbg(fsp)));
1791 close_file(req, fsp, ERROR_CLOSE);
1792 reply_doserror(req, ERRDOS,ERRnoaccess);
1793 goto out;
1796 reply_outbuf(req, 7, 0);
1797 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1798 SSVAL(req->outbuf,smb_vwv1,fattr);
1799 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1800 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1801 } else {
1802 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1804 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1805 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1807 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1808 SCVAL(req->outbuf,smb_flg,
1809 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1812 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1813 SCVAL(req->outbuf,smb_flg,
1814 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1816 out:
1817 TALLOC_FREE(smb_fname);
1818 END_PROFILE(SMBopen);
1819 return;
1822 /****************************************************************************
1823 Reply to an open and X.
1824 ****************************************************************************/
1826 void reply_open_and_X(struct smb_request *req)
1828 connection_struct *conn = req->conn;
1829 struct smb_filename *smb_fname = NULL;
1830 char *fname = NULL;
1831 uint16 open_flags;
1832 int deny_mode;
1833 uint32 smb_attr;
1834 /* Breakout the oplock request bits so we can set the
1835 reply bits separately. */
1836 int ex_oplock_request;
1837 int core_oplock_request;
1838 int oplock_request;
1839 #if 0
1840 int smb_sattr = SVAL(req->vwv+4, 0);
1841 uint32 smb_time = make_unix_date3(req->vwv+6);
1842 #endif
1843 int smb_ofun;
1844 uint32 fattr=0;
1845 int mtime=0;
1846 int smb_action = 0;
1847 files_struct *fsp;
1848 NTSTATUS status;
1849 uint64_t allocation_size;
1850 ssize_t retval = -1;
1851 uint32 access_mask;
1852 uint32 share_mode;
1853 uint32 create_disposition;
1854 uint32 create_options = 0;
1855 TALLOC_CTX *ctx = talloc_tos();
1857 START_PROFILE(SMBopenX);
1859 if (req->wct < 15) {
1860 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1861 goto out;
1864 open_flags = SVAL(req->vwv+2, 0);
1865 deny_mode = SVAL(req->vwv+3, 0);
1866 smb_attr = SVAL(req->vwv+5, 0);
1867 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1868 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1869 oplock_request = ex_oplock_request | core_oplock_request;
1870 smb_ofun = SVAL(req->vwv+8, 0);
1871 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1873 /* If it's an IPC, pass off the pipe handler. */
1874 if (IS_IPC(conn)) {
1875 if (lp_nt_pipe_support()) {
1876 reply_open_pipe_and_X(conn, req);
1877 } else {
1878 reply_doserror(req, ERRSRV, ERRaccess);
1880 goto out;
1883 /* XXXX we need to handle passed times, sattr and flags */
1884 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1885 STR_TERMINATE, &status);
1886 if (!NT_STATUS_IS_OK(status)) {
1887 reply_nterror(req, status);
1888 goto out;
1891 status = filename_convert(ctx,
1892 conn,
1893 req->flags2 & FLAGS2_DFS_PATHNAMES,
1894 fname,
1896 NULL,
1897 &smb_fname);
1898 if (!NT_STATUS_IS_OK(status)) {
1899 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1900 reply_botherror(req,
1901 NT_STATUS_PATH_NOT_COVERED,
1902 ERRSRV, ERRbadpath);
1903 goto out;
1905 reply_nterror(req, status);
1906 goto out;
1909 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
1910 &access_mask, &share_mode,
1911 &create_disposition,
1912 &create_options)) {
1913 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1914 goto out;
1917 status = SMB_VFS_CREATE_FILE(
1918 conn, /* conn */
1919 req, /* req */
1920 0, /* root_dir_fid */
1921 smb_fname, /* fname */
1922 access_mask, /* access_mask */
1923 share_mode, /* share_access */
1924 create_disposition, /* create_disposition*/
1925 create_options, /* create_options */
1926 smb_attr, /* file_attributes */
1927 oplock_request, /* oplock_request */
1928 0, /* allocation_size */
1929 NULL, /* sd */
1930 NULL, /* ea_list */
1931 &fsp, /* result */
1932 &smb_action); /* pinfo */
1934 if (!NT_STATUS_IS_OK(status)) {
1935 if (open_was_deferred(req->mid)) {
1936 /* We have re-scheduled this call. */
1937 goto out;
1939 reply_openerror(req, status);
1940 goto out;
1943 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1944 if the file is truncated or created. */
1945 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1946 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1947 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1948 close_file(req, fsp, ERROR_CLOSE);
1949 reply_nterror(req, NT_STATUS_DISK_FULL);
1950 goto out;
1952 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1953 if (retval < 0) {
1954 close_file(req, fsp, ERROR_CLOSE);
1955 reply_nterror(req, NT_STATUS_DISK_FULL);
1956 goto out;
1958 smb_fname->st.st_ex_size =
1959 SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st);
1962 fattr = dos_mode(conn, smb_fname);
1963 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1964 if (fattr & aDIR) {
1965 close_file(req, fsp, ERROR_CLOSE);
1966 reply_doserror(req, ERRDOS, ERRnoaccess);
1967 goto out;
1970 /* If the caller set the extended oplock request bit
1971 and we granted one (by whatever means) - set the
1972 correct bit for extended oplock reply.
1975 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1976 smb_action |= EXTENDED_OPLOCK_GRANTED;
1979 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1980 smb_action |= EXTENDED_OPLOCK_GRANTED;
1983 /* If the caller set the core oplock request bit
1984 and we granted one (by whatever means) - set the
1985 correct bit for core oplock reply.
1988 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1989 reply_outbuf(req, 19, 0);
1990 } else {
1991 reply_outbuf(req, 15, 0);
1994 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1995 SCVAL(req->outbuf, smb_flg,
1996 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1999 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2000 SCVAL(req->outbuf, smb_flg,
2001 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2004 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2005 SSVAL(req->outbuf,smb_vwv3,fattr);
2006 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2007 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2008 } else {
2009 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2011 SIVAL(req->outbuf,smb_vwv6,(uint32)smb_fname->st.st_ex_size);
2012 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2013 SSVAL(req->outbuf,smb_vwv11,smb_action);
2015 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2016 SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS);
2019 chain_reply(req);
2020 out:
2021 TALLOC_FREE(smb_fname);
2022 END_PROFILE(SMBopenX);
2023 return;
2026 /****************************************************************************
2027 Reply to a SMBulogoffX.
2028 ****************************************************************************/
2030 void reply_ulogoffX(struct smb_request *req)
2032 struct smbd_server_connection *sconn = smbd_server_conn;
2033 user_struct *vuser;
2035 START_PROFILE(SMBulogoffX);
2037 vuser = get_valid_user_struct(sconn, req->vuid);
2039 if(vuser == NULL) {
2040 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2041 req->vuid));
2044 /* in user level security we are supposed to close any files
2045 open by this user */
2046 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2047 file_close_user(req->vuid);
2050 invalidate_vuid(sconn, req->vuid);
2052 reply_outbuf(req, 2, 0);
2054 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2056 END_PROFILE(SMBulogoffX);
2057 req->vuid = UID_FIELD_INVALID;
2058 chain_reply(req);
2061 /****************************************************************************
2062 Reply to a mknew or a create.
2063 ****************************************************************************/
2065 void reply_mknew(struct smb_request *req)
2067 connection_struct *conn = req->conn;
2068 struct smb_filename *smb_fname = NULL;
2069 char *fname = NULL;
2070 uint32 fattr = 0;
2071 struct smb_file_time ft;
2072 files_struct *fsp;
2073 int oplock_request = 0;
2074 NTSTATUS status;
2075 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2076 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2077 uint32 create_disposition;
2078 uint32 create_options = 0;
2079 TALLOC_CTX *ctx = talloc_tos();
2081 START_PROFILE(SMBcreate);
2082 ZERO_STRUCT(ft);
2084 if (req->wct < 3) {
2085 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2086 goto out;
2089 fattr = SVAL(req->vwv+0, 0);
2090 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2092 /* mtime. */
2093 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2095 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2096 STR_TERMINATE, &status);
2097 if (!NT_STATUS_IS_OK(status)) {
2098 reply_nterror(req, status);
2099 goto out;
2102 status = filename_convert(ctx,
2103 conn,
2104 req->flags2 & FLAGS2_DFS_PATHNAMES,
2105 fname,
2107 NULL,
2108 &smb_fname);
2109 if (!NT_STATUS_IS_OK(status)) {
2110 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2111 reply_botherror(req,
2112 NT_STATUS_PATH_NOT_COVERED,
2113 ERRSRV, ERRbadpath);
2114 goto out;
2116 reply_nterror(req, status);
2117 goto out;
2120 if (fattr & aVOLID) {
2121 DEBUG(0,("Attempt to create file (%s) with volid set - "
2122 "please report this\n",
2123 smb_fname_str_dbg(smb_fname)));
2126 if(req->cmd == SMBmknew) {
2127 /* We should fail if file exists. */
2128 create_disposition = FILE_CREATE;
2129 } else {
2130 /* Create if file doesn't exist, truncate if it does. */
2131 create_disposition = FILE_OVERWRITE_IF;
2134 status = SMB_VFS_CREATE_FILE(
2135 conn, /* conn */
2136 req, /* req */
2137 0, /* root_dir_fid */
2138 smb_fname, /* fname */
2139 access_mask, /* access_mask */
2140 share_mode, /* share_access */
2141 create_disposition, /* create_disposition*/
2142 create_options, /* create_options */
2143 fattr, /* file_attributes */
2144 oplock_request, /* oplock_request */
2145 0, /* allocation_size */
2146 NULL, /* sd */
2147 NULL, /* ea_list */
2148 &fsp, /* result */
2149 NULL); /* pinfo */
2151 if (!NT_STATUS_IS_OK(status)) {
2152 if (open_was_deferred(req->mid)) {
2153 /* We have re-scheduled this call. */
2154 goto out;
2156 reply_openerror(req, status);
2157 goto out;
2160 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2161 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2162 if (!NT_STATUS_IS_OK(status)) {
2163 END_PROFILE(SMBcreate);
2164 goto out;
2167 reply_outbuf(req, 1, 0);
2168 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2170 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2171 SCVAL(req->outbuf,smb_flg,
2172 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2175 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2176 SCVAL(req->outbuf,smb_flg,
2177 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2180 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2181 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2182 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2183 (unsigned int)fattr));
2185 out:
2186 TALLOC_FREE(smb_fname);
2187 END_PROFILE(SMBcreate);
2188 return;
2191 /****************************************************************************
2192 Reply to a create temporary file.
2193 ****************************************************************************/
2195 void reply_ctemp(struct smb_request *req)
2197 connection_struct *conn = req->conn;
2198 struct smb_filename *smb_fname = NULL;
2199 char *fname = NULL;
2200 uint32 fattr;
2201 files_struct *fsp;
2202 int oplock_request;
2203 int tmpfd;
2204 char *s;
2205 NTSTATUS status;
2206 TALLOC_CTX *ctx = talloc_tos();
2208 START_PROFILE(SMBctemp);
2210 if (req->wct < 3) {
2211 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2212 goto out;
2215 fattr = SVAL(req->vwv+0, 0);
2216 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2218 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2219 STR_TERMINATE, &status);
2220 if (!NT_STATUS_IS_OK(status)) {
2221 reply_nterror(req, status);
2222 goto out;
2224 if (*fname) {
2225 fname = talloc_asprintf(ctx,
2226 "%s/TMXXXXXX",
2227 fname);
2228 } else {
2229 fname = talloc_strdup(ctx, "TMXXXXXX");
2232 if (!fname) {
2233 reply_nterror(req, NT_STATUS_NO_MEMORY);
2234 goto out;
2237 status = filename_convert(ctx, conn,
2238 req->flags2 & FLAGS2_DFS_PATHNAMES,
2239 fname,
2241 NULL,
2242 &smb_fname);
2243 if (!NT_STATUS_IS_OK(status)) {
2244 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2245 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2246 ERRSRV, ERRbadpath);
2247 goto out;
2249 reply_nterror(req, status);
2250 goto out;
2253 tmpfd = mkstemp(smb_fname->base_name);
2254 if (tmpfd == -1) {
2255 reply_nterror(req, map_nt_error_from_unix(errno));
2256 goto out;
2259 SMB_VFS_STAT(conn, smb_fname);
2261 /* We should fail if file does not exist. */
2262 status = SMB_VFS_CREATE_FILE(
2263 conn, /* conn */
2264 req, /* req */
2265 0, /* root_dir_fid */
2266 smb_fname, /* fname */
2267 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2268 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2269 FILE_OPEN, /* create_disposition*/
2270 0, /* create_options */
2271 fattr, /* file_attributes */
2272 oplock_request, /* oplock_request */
2273 0, /* allocation_size */
2274 NULL, /* sd */
2275 NULL, /* ea_list */
2276 &fsp, /* result */
2277 NULL); /* pinfo */
2279 /* close fd from mkstemp() */
2280 close(tmpfd);
2282 if (!NT_STATUS_IS_OK(status)) {
2283 if (open_was_deferred(req->mid)) {
2284 /* We have re-scheduled this call. */
2285 goto out;
2287 reply_openerror(req, status);
2288 goto out;
2291 reply_outbuf(req, 1, 0);
2292 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2294 /* the returned filename is relative to the directory */
2295 s = strrchr_m(fsp->fsp_name->base_name, '/');
2296 if (!s) {
2297 s = fsp->fsp_name->base_name;
2298 } else {
2299 s++;
2302 #if 0
2303 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2304 thing in the byte section. JRA */
2305 SSVALS(p, 0, -1); /* what is this? not in spec */
2306 #endif
2307 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2308 == -1) {
2309 reply_nterror(req, NT_STATUS_NO_MEMORY);
2310 goto out;
2313 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2314 SCVAL(req->outbuf, smb_flg,
2315 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2318 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2319 SCVAL(req->outbuf, smb_flg,
2320 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2323 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2324 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2325 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2326 out:
2327 TALLOC_FREE(smb_fname);
2328 END_PROFILE(SMBctemp);
2329 return;
2332 /*******************************************************************
2333 Check if a user is allowed to rename a file.
2334 ********************************************************************/
2336 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2337 uint16 dirtype, SMB_STRUCT_STAT *pst)
2339 uint32 fmode;
2341 if (!CAN_WRITE(conn)) {
2342 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2345 fmode = dos_mode(conn, fsp->fsp_name);
2346 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2347 return NT_STATUS_NO_SUCH_FILE;
2350 if (S_ISDIR(pst->st_ex_mode)) {
2351 if (fsp->posix_open) {
2352 return NT_STATUS_OK;
2355 /* If no pathnames are open below this
2356 directory, allow the rename. */
2358 if (file_find_subpath(fsp)) {
2359 return NT_STATUS_ACCESS_DENIED;
2361 return NT_STATUS_OK;
2364 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2365 return NT_STATUS_OK;
2368 return NT_STATUS_ACCESS_DENIED;
2371 /*******************************************************************
2372 * unlink a file with all relevant access checks
2373 *******************************************************************/
2375 static NTSTATUS do_unlink(connection_struct *conn,
2376 struct smb_request *req,
2377 struct smb_filename *smb_fname,
2378 uint32 dirtype)
2380 uint32 fattr;
2381 files_struct *fsp;
2382 uint32 dirtype_orig = dirtype;
2383 NTSTATUS status;
2384 int ret;
2385 bool posix_paths = lp_posix_pathnames();
2387 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2388 smb_fname_str_dbg(smb_fname),
2389 dirtype));
2391 if (!CAN_WRITE(conn)) {
2392 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2395 if (posix_paths) {
2396 ret = SMB_VFS_LSTAT(conn, smb_fname);
2397 } else {
2398 ret = SMB_VFS_LSTAT(conn, smb_fname);
2400 if (ret != 0) {
2401 return map_nt_error_from_unix(errno);
2404 fattr = dos_mode(conn, smb_fname);
2406 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2407 dirtype = aDIR|aARCH|aRONLY;
2410 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2411 if (!dirtype) {
2412 return NT_STATUS_NO_SUCH_FILE;
2415 if (!dir_check_ftype(conn, fattr, dirtype)) {
2416 if (fattr & aDIR) {
2417 return NT_STATUS_FILE_IS_A_DIRECTORY;
2419 return NT_STATUS_NO_SUCH_FILE;
2422 if (dirtype_orig & 0x8000) {
2423 /* These will never be set for POSIX. */
2424 return NT_STATUS_NO_SUCH_FILE;
2427 #if 0
2428 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2429 return NT_STATUS_FILE_IS_A_DIRECTORY;
2432 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2433 return NT_STATUS_NO_SUCH_FILE;
2436 if (dirtype & 0xFF00) {
2437 /* These will never be set for POSIX. */
2438 return NT_STATUS_NO_SUCH_FILE;
2441 dirtype &= 0xFF;
2442 if (!dirtype) {
2443 return NT_STATUS_NO_SUCH_FILE;
2446 /* Can't delete a directory. */
2447 if (fattr & aDIR) {
2448 return NT_STATUS_FILE_IS_A_DIRECTORY;
2450 #endif
2452 #if 0 /* JRATEST */
2453 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2454 return NT_STATUS_OBJECT_NAME_INVALID;
2455 #endif /* JRATEST */
2457 /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com>
2459 On a Windows share, a file with read-only dosmode can be opened with
2460 DELETE_ACCESS. But on a Samba share (delete readonly = no), it
2461 fails with NT_STATUS_CANNOT_DELETE error.
2463 This semantic causes a problem that a user can not
2464 rename a file with read-only dosmode on a Samba share
2465 from a Windows command prompt (i.e. cmd.exe, but can rename
2466 from Windows Explorer).
2469 if (!lp_delete_readonly(SNUM(conn))) {
2470 if (fattr & aRONLY) {
2471 return NT_STATUS_CANNOT_DELETE;
2475 /* On open checks the open itself will check the share mode, so
2476 don't do it here as we'll get it wrong. */
2478 status = SMB_VFS_CREATE_FILE
2479 (conn, /* conn */
2480 req, /* req */
2481 0, /* root_dir_fid */
2482 smb_fname, /* fname */
2483 DELETE_ACCESS, /* access_mask */
2484 FILE_SHARE_NONE, /* share_access */
2485 FILE_OPEN, /* create_disposition*/
2486 FILE_NON_DIRECTORY_FILE, /* create_options */
2487 /* file_attributes */
2488 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2489 FILE_ATTRIBUTE_NORMAL,
2490 0, /* oplock_request */
2491 0, /* allocation_size */
2492 NULL, /* sd */
2493 NULL, /* ea_list */
2494 &fsp, /* result */
2495 NULL); /* pinfo */
2497 if (!NT_STATUS_IS_OK(status)) {
2498 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2499 nt_errstr(status)));
2500 return status;
2503 /* The set is across all open files on this dev/inode pair. */
2504 if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) {
2505 close_file(req, fsp, NORMAL_CLOSE);
2506 return NT_STATUS_ACCESS_DENIED;
2509 return close_file(req, fsp, NORMAL_CLOSE);
2512 /****************************************************************************
2513 The guts of the unlink command, split out so it may be called by the NT SMB
2514 code.
2515 ****************************************************************************/
2517 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2518 uint32 dirtype, struct smb_filename *smb_fname,
2519 bool has_wild)
2521 char *fname_dir = NULL;
2522 char *fname_mask = NULL;
2523 int count=0;
2524 NTSTATUS status = NT_STATUS_OK;
2525 TALLOC_CTX *ctx = talloc_tos();
2527 /* Split up the directory from the filename/mask. */
2528 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2529 &fname_dir, &fname_mask);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 goto out;
2535 * We should only check the mangled cache
2536 * here if unix_convert failed. This means
2537 * that the path in 'mask' doesn't exist
2538 * on the file system and so we need to look
2539 * for a possible mangle. This patch from
2540 * Tine Smukavec <valentin.smukavec@hermes.si>.
2543 if (!VALID_STAT(smb_fname->st) &&
2544 mangle_is_mangled(fname_mask, conn->params)) {
2545 char *new_mask = NULL;
2546 mangle_lookup_name_from_8_3(ctx, fname_mask,
2547 &new_mask, conn->params);
2548 if (new_mask) {
2549 TALLOC_FREE(fname_mask);
2550 fname_mask = new_mask;
2554 if (!has_wild) {
2557 * Only one file needs to be unlinked. Append the mask back
2558 * onto the directory.
2560 TALLOC_FREE(smb_fname->base_name);
2561 smb_fname->base_name = talloc_asprintf(smb_fname,
2562 "%s/%s",
2563 fname_dir,
2564 fname_mask);
2565 if (!smb_fname->base_name) {
2566 status = NT_STATUS_NO_MEMORY;
2567 goto out;
2569 if (dirtype == 0) {
2570 dirtype = FILE_ATTRIBUTE_NORMAL;
2573 status = check_name(conn, smb_fname->base_name);
2574 if (!NT_STATUS_IS_OK(status)) {
2575 goto out;
2578 status = do_unlink(conn, req, smb_fname, dirtype);
2579 if (!NT_STATUS_IS_OK(status)) {
2580 goto out;
2583 count++;
2584 } else {
2585 struct smb_Dir *dir_hnd = NULL;
2586 long offset = 0;
2587 char *dname = NULL;
2589 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2590 status = NT_STATUS_OBJECT_NAME_INVALID;
2591 goto out;
2594 if (strequal(fname_mask,"????????.???")) {
2595 TALLOC_FREE(fname_mask);
2596 fname_mask = talloc_strdup(ctx, "*");
2597 if (!fname_mask) {
2598 status = NT_STATUS_NO_MEMORY;
2599 goto out;
2603 status = check_name(conn, fname_dir);
2604 if (!NT_STATUS_IS_OK(status)) {
2605 goto out;
2608 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2609 dirtype);
2610 if (dir_hnd == NULL) {
2611 status = map_nt_error_from_unix(errno);
2612 goto out;
2615 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2616 the pattern matches against the long name, otherwise the short name
2617 We don't implement this yet XXXX
2620 status = NT_STATUS_NO_SUCH_FILE;
2622 while ((dname = ReadDirName(dir_hnd, &offset,
2623 &smb_fname->st))) {
2624 TALLOC_CTX *frame = talloc_stackframe();
2626 if (!is_visible_file(conn, fname_dir, dname,
2627 &smb_fname->st, true)) {
2628 TALLOC_FREE(frame);
2629 TALLOC_FREE(dname);
2630 continue;
2633 /* Quick check for "." and ".." */
2634 if (ISDOT(dname) || ISDOTDOT(dname)) {
2635 TALLOC_FREE(frame);
2636 TALLOC_FREE(dname);
2637 continue;
2640 if(!mask_match(dname, fname_mask,
2641 conn->case_sensitive)) {
2642 TALLOC_FREE(frame);
2643 TALLOC_FREE(dname);
2644 continue;
2647 TALLOC_FREE(smb_fname->base_name);
2648 smb_fname->base_name =
2649 talloc_asprintf(smb_fname, "%s/%s",
2650 fname_dir, dname);
2652 if (!smb_fname->base_name) {
2653 TALLOC_FREE(dir_hnd);
2654 status = NT_STATUS_NO_MEMORY;
2655 TALLOC_FREE(frame);
2656 TALLOC_FREE(dname);
2657 goto out;
2660 status = check_name(conn, smb_fname->base_name);
2661 if (!NT_STATUS_IS_OK(status)) {
2662 TALLOC_FREE(dir_hnd);
2663 TALLOC_FREE(frame);
2664 TALLOC_FREE(dname);
2665 goto out;
2668 status = do_unlink(conn, req, smb_fname, dirtype);
2669 if (!NT_STATUS_IS_OK(status)) {
2670 TALLOC_FREE(frame);
2671 TALLOC_FREE(dname);
2672 continue;
2675 count++;
2676 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2677 smb_fname->base_name));
2679 TALLOC_FREE(frame);
2680 TALLOC_FREE(dname);
2682 TALLOC_FREE(dir_hnd);
2685 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2686 status = map_nt_error_from_unix(errno);
2689 out:
2690 TALLOC_FREE(fname_dir);
2691 TALLOC_FREE(fname_mask);
2692 return status;
2695 /****************************************************************************
2696 Reply to a unlink
2697 ****************************************************************************/
2699 void reply_unlink(struct smb_request *req)
2701 connection_struct *conn = req->conn;
2702 char *name = NULL;
2703 struct smb_filename *smb_fname = NULL;
2704 uint32 dirtype;
2705 NTSTATUS status;
2706 bool path_contains_wcard = False;
2707 TALLOC_CTX *ctx = talloc_tos();
2709 START_PROFILE(SMBunlink);
2711 if (req->wct < 1) {
2712 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2713 goto out;
2716 dirtype = SVAL(req->vwv+0, 0);
2718 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2719 STR_TERMINATE, &status,
2720 &path_contains_wcard);
2721 if (!NT_STATUS_IS_OK(status)) {
2722 reply_nterror(req, status);
2723 goto out;
2726 status = filename_convert(ctx, conn,
2727 req->flags2 & FLAGS2_DFS_PATHNAMES,
2728 name,
2729 UCF_COND_ALLOW_WCARD_LCOMP,
2730 &path_contains_wcard,
2731 &smb_fname);
2732 if (!NT_STATUS_IS_OK(status)) {
2733 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2734 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2735 ERRSRV, ERRbadpath);
2736 goto out;
2738 reply_nterror(req, status);
2739 goto out;
2742 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2744 status = unlink_internals(conn, req, dirtype, smb_fname,
2745 path_contains_wcard);
2746 if (!NT_STATUS_IS_OK(status)) {
2747 if (open_was_deferred(req->mid)) {
2748 /* We have re-scheduled this call. */
2749 goto out;
2751 reply_nterror(req, status);
2752 goto out;
2755 reply_outbuf(req, 0, 0);
2756 out:
2757 TALLOC_FREE(smb_fname);
2758 END_PROFILE(SMBunlink);
2759 return;
2762 /****************************************************************************
2763 Fail for readbraw.
2764 ****************************************************************************/
2766 static void fail_readraw(void)
2768 const char *errstr = talloc_asprintf(talloc_tos(),
2769 "FAIL ! reply_readbraw: socket write fail (%s)",
2770 strerror(errno));
2771 if (!errstr) {
2772 errstr = "";
2774 exit_server_cleanly(errstr);
2777 /****************************************************************************
2778 Fake (read/write) sendfile. Returns -1 on read or write fail.
2779 ****************************************************************************/
2781 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
2782 size_t nread)
2784 size_t bufsize;
2785 size_t tosend = nread;
2786 char *buf;
2788 if (nread == 0) {
2789 return 0;
2792 bufsize = MIN(nread, 65536);
2794 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2795 return -1;
2798 while (tosend > 0) {
2799 ssize_t ret;
2800 size_t cur_read;
2802 if (tosend > bufsize) {
2803 cur_read = bufsize;
2804 } else {
2805 cur_read = tosend;
2807 ret = read_file(fsp,buf,startpos,cur_read);
2808 if (ret == -1) {
2809 SAFE_FREE(buf);
2810 return -1;
2813 /* If we had a short read, fill with zeros. */
2814 if (ret < cur_read) {
2815 memset(buf + ret, '\0', cur_read - ret);
2818 if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
2819 SAFE_FREE(buf);
2820 return -1;
2822 tosend -= cur_read;
2823 startpos += cur_read;
2826 SAFE_FREE(buf);
2827 return (ssize_t)nread;
2830 #if defined(WITH_SENDFILE)
2831 /****************************************************************************
2832 Deal with the case of sendfile reading less bytes from the file than
2833 requested. Fill with zeros (all we can do).
2834 ****************************************************************************/
2836 static void sendfile_short_send(files_struct *fsp,
2837 ssize_t nread,
2838 size_t headersize,
2839 size_t smb_maxcnt)
2841 #define SHORT_SEND_BUFSIZE 1024
2842 if (nread < headersize) {
2843 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2844 "header for file %s (%s). Terminating\n",
2845 fsp_str_dbg(fsp), strerror(errno)));
2846 exit_server_cleanly("sendfile_short_send failed");
2849 nread -= headersize;
2851 if (nread < smb_maxcnt) {
2852 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2853 if (!buf) {
2854 exit_server_cleanly("sendfile_short_send: "
2855 "malloc failed");
2858 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2859 "with zeros !\n", fsp_str_dbg(fsp)));
2861 while (nread < smb_maxcnt) {
2863 * We asked for the real file size and told sendfile
2864 * to not go beyond the end of the file. But it can
2865 * happen that in between our fstat call and the
2866 * sendfile call the file was truncated. This is very
2867 * bad because we have already announced the larger
2868 * number of bytes to the client.
2870 * The best we can do now is to send 0-bytes, just as
2871 * a read from a hole in a sparse file would do.
2873 * This should happen rarely enough that I don't care
2874 * about efficiency here :-)
2876 size_t to_write;
2878 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2879 if (write_data(smbd_server_fd(), buf, to_write) != to_write) {
2880 exit_server_cleanly("sendfile_short_send: "
2881 "write_data failed");
2883 nread += to_write;
2885 SAFE_FREE(buf);
2888 #endif /* defined WITH_SENDFILE */
2890 /****************************************************************************
2891 Return a readbraw error (4 bytes of zero).
2892 ****************************************************************************/
2894 static void reply_readbraw_error(void)
2896 char header[4];
2897 SIVAL(header,0,0);
2898 if (write_data(smbd_server_fd(),header,4) != 4) {
2899 fail_readraw();
2903 /****************************************************************************
2904 Use sendfile in readbraw.
2905 ****************************************************************************/
2907 static void send_file_readbraw(connection_struct *conn,
2908 struct smb_request *req,
2909 files_struct *fsp,
2910 SMB_OFF_T startpos,
2911 size_t nread,
2912 ssize_t mincount)
2914 char *outbuf = NULL;
2915 ssize_t ret=0;
2917 #if defined(WITH_SENDFILE)
2919 * We can only use sendfile on a non-chained packet
2920 * but we can use on a non-oplocked file. tridge proved this
2921 * on a train in Germany :-). JRA.
2922 * reply_readbraw has already checked the length.
2925 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
2926 (fsp->wcp == NULL) &&
2927 lp_use_sendfile(SNUM(conn), smbd_server_conn->smb1.signing_state) ) {
2928 ssize_t sendfile_read = -1;
2929 char header[4];
2930 DATA_BLOB header_blob;
2932 _smb_setlen(header,nread);
2933 header_blob = data_blob_const(header, 4);
2935 if ((sendfile_read = SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
2936 &header_blob, startpos, nread)) == -1) {
2937 /* Returning ENOSYS means no data at all was sent.
2938 * Do this as a normal read. */
2939 if (errno == ENOSYS) {
2940 goto normal_readbraw;
2944 * Special hack for broken Linux with no working sendfile. If we
2945 * return EINTR we sent the header but not the rest of the data.
2946 * Fake this up by doing read/write calls.
2948 if (errno == EINTR) {
2949 /* Ensure we don't do this again. */
2950 set_use_sendfile(SNUM(conn), False);
2951 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2953 if (fake_sendfile(fsp, startpos, nread) == -1) {
2954 DEBUG(0,("send_file_readbraw: "
2955 "fake_sendfile failed for "
2956 "file %s (%s).\n",
2957 fsp_str_dbg(fsp),
2958 strerror(errno)));
2959 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2961 return;
2964 DEBUG(0,("send_file_readbraw: sendfile failed for "
2965 "file %s (%s). Terminating\n",
2966 fsp_str_dbg(fsp), strerror(errno)));
2967 exit_server_cleanly("send_file_readbraw sendfile failed");
2968 } else if (sendfile_read == 0) {
2970 * Some sendfile implementations return 0 to indicate
2971 * that there was a short read, but nothing was
2972 * actually written to the socket. In this case,
2973 * fallback to the normal read path so the header gets
2974 * the correct byte count.
2976 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
2977 "bytes falling back to the normal read: "
2978 "%s\n", fsp_str_dbg(fsp)));
2979 goto normal_readbraw;
2982 /* Deal with possible short send. */
2983 if (sendfile_read != 4+nread) {
2984 sendfile_short_send(fsp, sendfile_read, 4, nread);
2986 return;
2989 normal_readbraw:
2990 #endif
2992 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
2993 if (!outbuf) {
2994 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
2995 (unsigned)(nread+4)));
2996 reply_readbraw_error();
2997 return;
3000 if (nread > 0) {
3001 ret = read_file(fsp,outbuf+4,startpos,nread);
3002 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3003 if (ret < mincount)
3004 ret = 0;
3005 #else
3006 if (ret < nread)
3007 ret = 0;
3008 #endif
3011 _smb_setlen(outbuf,ret);
3012 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
3013 fail_readraw();
3015 TALLOC_FREE(outbuf);
3018 /****************************************************************************
3019 Reply to a readbraw (core+ protocol).
3020 ****************************************************************************/
3022 void reply_readbraw(struct smb_request *req)
3024 connection_struct *conn = req->conn;
3025 ssize_t maxcount,mincount;
3026 size_t nread = 0;
3027 SMB_OFF_T startpos;
3028 files_struct *fsp;
3029 struct lock_struct lock;
3030 SMB_STRUCT_STAT st;
3031 SMB_OFF_T size = 0;
3033 START_PROFILE(SMBreadbraw);
3035 if (srv_is_signing_active(smbd_server_conn) ||
3036 is_encrypted_packet(req->inbuf)) {
3037 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3038 "raw reads/writes are disallowed.");
3041 if (req->wct < 8) {
3042 reply_readbraw_error();
3043 END_PROFILE(SMBreadbraw);
3044 return;
3048 * Special check if an oplock break has been issued
3049 * and the readraw request croses on the wire, we must
3050 * return a zero length response here.
3053 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3056 * We have to do a check_fsp by hand here, as
3057 * we must always return 4 zero bytes on error,
3058 * not a NTSTATUS.
3061 if (!fsp || !conn || conn != fsp->conn ||
3062 req->vuid != fsp->vuid ||
3063 fsp->is_directory || fsp->fh->fd == -1) {
3065 * fsp could be NULL here so use the value from the packet. JRA.
3067 DEBUG(3,("reply_readbraw: fnum %d not valid "
3068 "- cache prime?\n",
3069 (int)SVAL(req->vwv+0, 0)));
3070 reply_readbraw_error();
3071 END_PROFILE(SMBreadbraw);
3072 return;
3075 /* Do a "by hand" version of CHECK_READ. */
3076 if (!(fsp->can_read ||
3077 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3078 (fsp->access_mask & FILE_EXECUTE)))) {
3079 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3080 (int)SVAL(req->vwv+0, 0)));
3081 reply_readbraw_error();
3082 END_PROFILE(SMBreadbraw);
3083 return;
3086 flush_write_cache(fsp, READRAW_FLUSH);
3088 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3089 if(req->wct == 10) {
3091 * This is a large offset (64 bit) read.
3093 #ifdef LARGE_SMB_OFF_T
3095 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3097 #else /* !LARGE_SMB_OFF_T */
3100 * Ensure we haven't been sent a >32 bit offset.
3103 if(IVAL(req->vwv+8, 0) != 0) {
3104 DEBUG(0,("reply_readbraw: large offset "
3105 "(%x << 32) used and we don't support "
3106 "64 bit offsets.\n",
3107 (unsigned int)IVAL(req->vwv+8, 0) ));
3108 reply_readbraw_error();
3109 END_PROFILE(SMBreadbraw);
3110 return;
3113 #endif /* LARGE_SMB_OFF_T */
3115 if(startpos < 0) {
3116 DEBUG(0,("reply_readbraw: negative 64 bit "
3117 "readraw offset (%.0f) !\n",
3118 (double)startpos ));
3119 reply_readbraw_error();
3120 END_PROFILE(SMBreadbraw);
3121 return;
3125 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3126 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3128 /* ensure we don't overrun the packet size */
3129 maxcount = MIN(65535,maxcount);
3131 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3132 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3133 &lock);
3135 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3136 reply_readbraw_error();
3137 END_PROFILE(SMBreadbraw);
3138 return;
3141 if (SMB_VFS_FSTAT(fsp, &st) == 0) {
3142 size = st.st_ex_size;
3145 if (startpos >= size) {
3146 nread = 0;
3147 } else {
3148 nread = MIN(maxcount,(size - startpos));
3151 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3152 if (nread < mincount)
3153 nread = 0;
3154 #endif
3156 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3157 "min=%lu nread=%lu\n",
3158 fsp->fnum, (double)startpos,
3159 (unsigned long)maxcount,
3160 (unsigned long)mincount,
3161 (unsigned long)nread ) );
3163 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3165 DEBUG(5,("reply_readbraw finished\n"));
3167 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3169 END_PROFILE(SMBreadbraw);
3170 return;
3173 #undef DBGC_CLASS
3174 #define DBGC_CLASS DBGC_LOCKING
3176 /****************************************************************************
3177 Reply to a lockread (core+ protocol).
3178 ****************************************************************************/
3180 void reply_lockread(struct smb_request *req)
3182 connection_struct *conn = req->conn;
3183 ssize_t nread = -1;
3184 char *data;
3185 SMB_OFF_T startpos;
3186 size_t numtoread;
3187 NTSTATUS status;
3188 files_struct *fsp;
3189 struct byte_range_lock *br_lck = NULL;
3190 char *p = NULL;
3191 struct smbd_server_connection *sconn = smbd_server_conn;
3193 START_PROFILE(SMBlockread);
3195 if (req->wct < 5) {
3196 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3197 END_PROFILE(SMBlockread);
3198 return;
3201 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3203 if (!check_fsp(conn, req, fsp)) {
3204 END_PROFILE(SMBlockread);
3205 return;
3208 if (!CHECK_READ(fsp,req)) {
3209 reply_doserror(req, ERRDOS, ERRbadaccess);
3210 END_PROFILE(SMBlockread);
3211 return;
3214 numtoread = SVAL(req->vwv+1, 0);
3215 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3217 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3219 reply_outbuf(req, 5, numtoread + 3);
3221 data = smb_buf(req->outbuf) + 3;
3224 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3225 * protocol request that predates the read/write lock concept.
3226 * Thus instead of asking for a read lock here we need to ask
3227 * for a write lock. JRA.
3228 * Note that the requested lock size is unaffected by max_recv.
3231 br_lck = do_lock(smbd_messaging_context(),
3232 fsp,
3233 req->smbpid,
3234 (uint64_t)numtoread,
3235 (uint64_t)startpos,
3236 WRITE_LOCK,
3237 WINDOWS_LOCK,
3238 False, /* Non-blocking lock. */
3239 &status,
3240 NULL,
3241 NULL);
3242 TALLOC_FREE(br_lck);
3244 if (NT_STATUS_V(status)) {
3245 reply_nterror(req, status);
3246 END_PROFILE(SMBlockread);
3247 return;
3251 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3254 if (numtoread > sconn->smb1.negprot.max_recv) {
3255 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3256 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3257 (unsigned int)numtoread,
3258 (unsigned int)sconn->smb1.negprot.max_recv));
3259 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3261 nread = read_file(fsp,data,startpos,numtoread);
3263 if (nread < 0) {
3264 reply_nterror(req, map_nt_error_from_unix(errno));
3265 END_PROFILE(SMBlockread);
3266 return;
3269 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3271 SSVAL(req->outbuf,smb_vwv0,nread);
3272 SSVAL(req->outbuf,smb_vwv5,nread+3);
3273 p = smb_buf(req->outbuf);
3274 SCVAL(p,0,0); /* pad byte. */
3275 SSVAL(p,1,nread);
3277 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3278 fsp->fnum, (int)numtoread, (int)nread));
3280 END_PROFILE(SMBlockread);
3281 return;
3284 #undef DBGC_CLASS
3285 #define DBGC_CLASS DBGC_ALL
3287 /****************************************************************************
3288 Reply to a read.
3289 ****************************************************************************/
3291 void reply_read(struct smb_request *req)
3293 connection_struct *conn = req->conn;
3294 size_t numtoread;
3295 ssize_t nread = 0;
3296 char *data;
3297 SMB_OFF_T startpos;
3298 int outsize = 0;
3299 files_struct *fsp;
3300 struct lock_struct lock;
3301 struct smbd_server_connection *sconn = smbd_server_conn;
3303 START_PROFILE(SMBread);
3305 if (req->wct < 3) {
3306 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3307 END_PROFILE(SMBread);
3308 return;
3311 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3313 if (!check_fsp(conn, req, fsp)) {
3314 END_PROFILE(SMBread);
3315 return;
3318 if (!CHECK_READ(fsp,req)) {
3319 reply_doserror(req, ERRDOS, ERRbadaccess);
3320 END_PROFILE(SMBread);
3321 return;
3324 numtoread = SVAL(req->vwv+1, 0);
3325 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3327 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3330 * The requested read size cannot be greater than max_recv. JRA.
3332 if (numtoread > sconn->smb1.negprot.max_recv) {
3333 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3334 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3335 (unsigned int)numtoread,
3336 (unsigned int)sconn->smb1.negprot.max_recv));
3337 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3340 reply_outbuf(req, 5, numtoread+3);
3342 data = smb_buf(req->outbuf) + 3;
3344 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3345 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3346 &lock);
3348 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3349 reply_doserror(req, ERRDOS,ERRlock);
3350 END_PROFILE(SMBread);
3351 return;
3354 if (numtoread > 0)
3355 nread = read_file(fsp,data,startpos,numtoread);
3357 if (nread < 0) {
3358 reply_nterror(req, map_nt_error_from_unix(errno));
3359 goto strict_unlock;
3362 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3364 SSVAL(req->outbuf,smb_vwv0,nread);
3365 SSVAL(req->outbuf,smb_vwv5,nread+3);
3366 SCVAL(smb_buf(req->outbuf),0,1);
3367 SSVAL(smb_buf(req->outbuf),1,nread);
3369 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3370 fsp->fnum, (int)numtoread, (int)nread ) );
3372 strict_unlock:
3373 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3375 END_PROFILE(SMBread);
3376 return;
3379 /****************************************************************************
3380 Setup readX header.
3381 ****************************************************************************/
3383 static int setup_readX_header(struct smb_request *req, char *outbuf,
3384 size_t smb_maxcnt)
3386 int outsize;
3387 char *data;
3389 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3390 data = smb_buf(outbuf);
3392 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3394 SCVAL(outbuf,smb_vwv0,0xFF);
3395 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3396 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3397 SSVAL(outbuf,smb_vwv6,
3398 req_wct_ofs(req)
3399 + 1 /* the wct field */
3400 + 12 * sizeof(uint16_t) /* vwv */
3401 + 2); /* the buflen field */
3402 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3403 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3404 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3405 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3406 return outsize;
3409 /****************************************************************************
3410 Reply to a read and X - possibly using sendfile.
3411 ****************************************************************************/
3413 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3414 files_struct *fsp, SMB_OFF_T startpos,
3415 size_t smb_maxcnt)
3417 SMB_STRUCT_STAT sbuf;
3418 ssize_t nread = -1;
3419 struct lock_struct lock;
3420 int saved_errno = 0;
3422 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
3423 reply_nterror(req, map_nt_error_from_unix(errno));
3424 return;
3427 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3428 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3429 &lock);
3431 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3432 reply_doserror(req, ERRDOS, ERRlock);
3433 return;
3436 if (!S_ISREG(sbuf.st_ex_mode) || (startpos > sbuf.st_ex_size)
3437 || (smb_maxcnt > (sbuf.st_ex_size - startpos))) {
3439 * We already know that we would do a short read, so don't
3440 * try the sendfile() path.
3442 goto nosendfile_read;
3445 #if defined(WITH_SENDFILE)
3447 * We can only use sendfile on a non-chained packet
3448 * but we can use on a non-oplocked file. tridge proved this
3449 * on a train in Germany :-). JRA.
3452 if (!req_is_in_chain(req) &&
3453 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3454 (fsp->wcp == NULL) &&
3455 lp_use_sendfile(SNUM(conn), smbd_server_conn->smb1.signing_state) ) {
3456 uint8 headerbuf[smb_size + 12 * 2];
3457 DATA_BLOB header;
3460 * Set up the packet header before send. We
3461 * assume here the sendfile will work (get the
3462 * correct amount of data).
3465 header = data_blob_const(headerbuf, sizeof(headerbuf));
3467 construct_reply_common_req(req, (char *)headerbuf);
3468 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3470 if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
3471 /* Returning ENOSYS means no data at all was sent.
3472 Do this as a normal read. */
3473 if (errno == ENOSYS) {
3474 goto normal_read;
3478 * Special hack for broken Linux with no working sendfile. If we
3479 * return EINTR we sent the header but not the rest of the data.
3480 * Fake this up by doing read/write calls.
3483 if (errno == EINTR) {
3484 /* Ensure we don't do this again. */
3485 set_use_sendfile(SNUM(conn), False);
3486 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3487 nread = fake_sendfile(fsp, startpos,
3488 smb_maxcnt);
3489 if (nread == -1) {
3490 DEBUG(0,("send_file_readX: "
3491 "fake_sendfile failed for "
3492 "file %s (%s).\n",
3493 fsp_str_dbg(fsp),
3494 strerror(errno)));
3495 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3497 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3498 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3499 /* No outbuf here means successful sendfile. */
3500 goto strict_unlock;
3503 DEBUG(0,("send_file_readX: sendfile failed for file "
3504 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3505 strerror(errno)));
3506 exit_server_cleanly("send_file_readX sendfile failed");
3507 } else if (nread == 0) {
3509 * Some sendfile implementations return 0 to indicate
3510 * that there was a short read, but nothing was
3511 * actually written to the socket. In this case,
3512 * fallback to the normal read path so the header gets
3513 * the correct byte count.
3515 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3516 "falling back to the normal read: %s\n",
3517 fsp_str_dbg(fsp)));
3518 goto normal_read;
3521 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3522 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3524 /* Deal with possible short send. */
3525 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3526 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3528 /* No outbuf here means successful sendfile. */
3529 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3530 SMB_PERFCOUNT_END(&req->pcd);
3531 goto strict_unlock;
3534 normal_read:
3536 #endif
3538 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3539 uint8 headerbuf[smb_size + 2*12];
3541 construct_reply_common_req(req, (char *)headerbuf);
3542 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3544 /* Send out the header. */
3545 if (write_data(smbd_server_fd(), (char *)headerbuf,
3546 sizeof(headerbuf)) != sizeof(headerbuf)) {
3547 DEBUG(0,("send_file_readX: write_data failed for file "
3548 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3549 strerror(errno)));
3550 exit_server_cleanly("send_file_readX sendfile failed");
3552 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3553 if (nread == -1) {
3554 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3555 "file %s (%s).\n", fsp_str_dbg(fsp),
3556 strerror(errno)));
3557 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3559 goto strict_unlock;
3562 nosendfile_read:
3564 reply_outbuf(req, 12, smb_maxcnt);
3566 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3567 saved_errno = errno;
3569 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3571 if (nread < 0) {
3572 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3573 return;
3576 setup_readX_header(req, (char *)req->outbuf, nread);
3578 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3579 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3581 chain_reply(req);
3582 return;
3584 strict_unlock:
3585 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3586 TALLOC_FREE(req->outbuf);
3587 return;
3590 /****************************************************************************
3591 Reply to a read and X.
3592 ****************************************************************************/
3594 void reply_read_and_X(struct smb_request *req)
3596 connection_struct *conn = req->conn;
3597 files_struct *fsp;
3598 SMB_OFF_T startpos;
3599 size_t smb_maxcnt;
3600 bool big_readX = False;
3601 #if 0
3602 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3603 #endif
3605 START_PROFILE(SMBreadX);
3607 if ((req->wct != 10) && (req->wct != 12)) {
3608 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3609 return;
3612 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3613 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3614 smb_maxcnt = SVAL(req->vwv+5, 0);
3616 /* If it's an IPC, pass off the pipe handler. */
3617 if (IS_IPC(conn)) {
3618 reply_pipe_read_and_X(req);
3619 END_PROFILE(SMBreadX);
3620 return;
3623 if (!check_fsp(conn, req, fsp)) {
3624 END_PROFILE(SMBreadX);
3625 return;
3628 if (!CHECK_READ(fsp,req)) {
3629 reply_doserror(req, ERRDOS,ERRbadaccess);
3630 END_PROFILE(SMBreadX);
3631 return;
3634 if (global_client_caps & CAP_LARGE_READX) {
3635 size_t upper_size = SVAL(req->vwv+7, 0);
3636 smb_maxcnt |= (upper_size<<16);
3637 if (upper_size > 1) {
3638 /* Can't do this on a chained packet. */
3639 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3640 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3641 END_PROFILE(SMBreadX);
3642 return;
3644 /* We currently don't do this on signed or sealed data. */
3645 if (srv_is_signing_active(smbd_server_conn) ||
3646 is_encrypted_packet(req->inbuf)) {
3647 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3648 END_PROFILE(SMBreadX);
3649 return;
3651 /* Is there room in the reply for this data ? */
3652 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3653 reply_nterror(req,
3654 NT_STATUS_INVALID_PARAMETER);
3655 END_PROFILE(SMBreadX);
3656 return;
3658 big_readX = True;
3662 if (req->wct == 12) {
3663 #ifdef LARGE_SMB_OFF_T
3665 * This is a large offset (64 bit) read.
3667 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3669 #else /* !LARGE_SMB_OFF_T */
3672 * Ensure we haven't been sent a >32 bit offset.
3675 if(IVAL(req->vwv+10, 0) != 0) {
3676 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3677 "used and we don't support 64 bit offsets.\n",
3678 (unsigned int)IVAL(req->vwv+10, 0) ));
3679 END_PROFILE(SMBreadX);
3680 reply_doserror(req, ERRDOS, ERRbadaccess);
3681 return;
3684 #endif /* LARGE_SMB_OFF_T */
3688 if (!big_readX &&
3689 schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
3690 goto out;
3693 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3695 out:
3696 END_PROFILE(SMBreadX);
3697 return;
3700 /****************************************************************************
3701 Error replies to writebraw must have smb_wct == 1. Fix this up.
3702 ****************************************************************************/
3704 void error_to_writebrawerr(struct smb_request *req)
3706 uint8 *old_outbuf = req->outbuf;
3708 reply_outbuf(req, 1, 0);
3710 memcpy(req->outbuf, old_outbuf, smb_size);
3711 TALLOC_FREE(old_outbuf);
3714 /****************************************************************************
3715 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3716 ****************************************************************************/
3718 void reply_writebraw(struct smb_request *req)
3720 connection_struct *conn = req->conn;
3721 char *buf = NULL;
3722 ssize_t nwritten=0;
3723 ssize_t total_written=0;
3724 size_t numtowrite=0;
3725 size_t tcount;
3726 SMB_OFF_T startpos;
3727 char *data=NULL;
3728 bool write_through;
3729 files_struct *fsp;
3730 struct lock_struct lock;
3731 NTSTATUS status;
3733 START_PROFILE(SMBwritebraw);
3736 * If we ever reply with an error, it must have the SMB command
3737 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3738 * we're finished.
3740 SCVAL(req->inbuf,smb_com,SMBwritec);
3742 if (srv_is_signing_active(smbd_server_conn)) {
3743 END_PROFILE(SMBwritebraw);
3744 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3745 "raw reads/writes are disallowed.");
3748 if (req->wct < 12) {
3749 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3750 error_to_writebrawerr(req);
3751 END_PROFILE(SMBwritebraw);
3752 return;
3755 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3756 if (!check_fsp(conn, req, fsp)) {
3757 error_to_writebrawerr(req);
3758 END_PROFILE(SMBwritebraw);
3759 return;
3762 if (!CHECK_WRITE(fsp)) {
3763 reply_doserror(req, ERRDOS, ERRbadaccess);
3764 error_to_writebrawerr(req);
3765 END_PROFILE(SMBwritebraw);
3766 return;
3769 tcount = IVAL(req->vwv+1, 0);
3770 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3771 write_through = BITSETW(req->vwv+7,0);
3773 /* We have to deal with slightly different formats depending
3774 on whether we are using the core+ or lanman1.0 protocol */
3776 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3777 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3778 data = smb_buf(req->inbuf);
3779 } else {
3780 numtowrite = SVAL(req->vwv+10, 0);
3781 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3784 /* Ensure we don't write bytes past the end of this packet. */
3785 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3786 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3787 error_to_writebrawerr(req);
3788 END_PROFILE(SMBwritebraw);
3789 return;
3792 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3793 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3794 &lock);
3796 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3797 reply_doserror(req, ERRDOS, ERRlock);
3798 error_to_writebrawerr(req);
3799 END_PROFILE(SMBwritebraw);
3800 return;
3803 if (numtowrite>0) {
3804 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3807 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3808 "wrote=%d sync=%d\n",
3809 fsp->fnum, (double)startpos, (int)numtowrite,
3810 (int)nwritten, (int)write_through));
3812 if (nwritten < (ssize_t)numtowrite) {
3813 reply_doserror(req, ERRHRD, ERRdiskfull);
3814 error_to_writebrawerr(req);
3815 goto strict_unlock;
3818 total_written = nwritten;
3820 /* Allocate a buffer of 64k + length. */
3821 buf = TALLOC_ARRAY(NULL, char, 65540);
3822 if (!buf) {
3823 reply_doserror(req, ERRDOS, ERRnomem);
3824 error_to_writebrawerr(req);
3825 goto strict_unlock;
3828 /* Return a SMBwritebraw message to the redirector to tell
3829 * it to send more bytes */
3831 memcpy(buf, req->inbuf, smb_size);
3832 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
3833 SCVAL(buf,smb_com,SMBwritebraw);
3834 SSVALS(buf,smb_vwv0,0xFFFF);
3835 show_msg(buf);
3836 if (!srv_send_smb(smbd_server_fd(),
3837 buf,
3838 false, 0, /* no signing */
3839 IS_CONN_ENCRYPTED(conn),
3840 &req->pcd)) {
3841 exit_server_cleanly("reply_writebraw: srv_send_smb "
3842 "failed.");
3845 /* Now read the raw data into the buffer and write it */
3846 status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
3847 &numtowrite);
3848 if (!NT_STATUS_IS_OK(status)) {
3849 exit_server_cleanly("secondary writebraw failed");
3852 /* Set up outbuf to return the correct size */
3853 reply_outbuf(req, 1, 0);
3855 if (numtowrite != 0) {
3857 if (numtowrite > 0xFFFF) {
3858 DEBUG(0,("reply_writebraw: Oversize secondary write "
3859 "raw requested (%u). Terminating\n",
3860 (unsigned int)numtowrite ));
3861 exit_server_cleanly("secondary writebraw failed");
3864 if (tcount > nwritten+numtowrite) {
3865 DEBUG(3,("reply_writebraw: Client overestimated the "
3866 "write %d %d %d\n",
3867 (int)tcount,(int)nwritten,(int)numtowrite));
3870 status = read_data(smbd_server_fd(), buf+4, numtowrite);
3872 if (!NT_STATUS_IS_OK(status)) {
3873 DEBUG(0,("reply_writebraw: Oversize secondary write "
3874 "raw read failed (%s). Terminating\n",
3875 nt_errstr(status)));
3876 exit_server_cleanly("secondary writebraw failed");
3879 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
3880 if (nwritten == -1) {
3881 TALLOC_FREE(buf);
3882 reply_nterror(req, map_nt_error_from_unix(errno));
3883 error_to_writebrawerr(req);
3884 goto strict_unlock;
3887 if (nwritten < (ssize_t)numtowrite) {
3888 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3889 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3892 if (nwritten > 0) {
3893 total_written += nwritten;
3897 TALLOC_FREE(buf);
3898 SSVAL(req->outbuf,smb_vwv0,total_written);
3900 status = sync_file(conn, fsp, write_through);
3901 if (!NT_STATUS_IS_OK(status)) {
3902 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
3903 fsp_str_dbg(fsp), nt_errstr(status)));
3904 reply_nterror(req, status);
3905 error_to_writebrawerr(req);
3906 goto strict_unlock;
3909 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
3910 "wrote=%d\n",
3911 fsp->fnum, (double)startpos, (int)numtowrite,
3912 (int)total_written));
3914 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3916 /* We won't return a status if write through is not selected - this
3917 * follows what WfWg does */
3918 END_PROFILE(SMBwritebraw);
3920 if (!write_through && total_written==tcount) {
3922 #if RABBIT_PELLET_FIX
3924 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
3925 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
3926 * JRA.
3928 if (!send_keepalive(smbd_server_fd())) {
3929 exit_server_cleanly("reply_writebraw: send of "
3930 "keepalive failed");
3932 #endif
3933 TALLOC_FREE(req->outbuf);
3935 return;
3937 strict_unlock:
3938 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3940 END_PROFILE(SMBwritebraw);
3941 return;
3944 #undef DBGC_CLASS
3945 #define DBGC_CLASS DBGC_LOCKING
3947 /****************************************************************************
3948 Reply to a writeunlock (core+).
3949 ****************************************************************************/
3951 void reply_writeunlock(struct smb_request *req)
3953 connection_struct *conn = req->conn;
3954 ssize_t nwritten = -1;
3955 size_t numtowrite;
3956 SMB_OFF_T startpos;
3957 const char *data;
3958 NTSTATUS status = NT_STATUS_OK;
3959 files_struct *fsp;
3960 struct lock_struct lock;
3961 int saved_errno = 0;
3963 START_PROFILE(SMBwriteunlock);
3965 if (req->wct < 5) {
3966 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3967 END_PROFILE(SMBwriteunlock);
3968 return;
3971 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3973 if (!check_fsp(conn, req, fsp)) {
3974 END_PROFILE(SMBwriteunlock);
3975 return;
3978 if (!CHECK_WRITE(fsp)) {
3979 reply_doserror(req, ERRDOS,ERRbadaccess);
3980 END_PROFILE(SMBwriteunlock);
3981 return;
3984 numtowrite = SVAL(req->vwv+1, 0);
3985 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3986 data = (const char *)req->buf + 3;
3988 if (numtowrite) {
3989 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3990 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
3991 &lock);
3993 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3994 reply_doserror(req, ERRDOS, ERRlock);
3995 END_PROFILE(SMBwriteunlock);
3996 return;
4000 /* The special X/Open SMB protocol handling of
4001 zero length writes is *NOT* done for
4002 this call */
4003 if(numtowrite == 0) {
4004 nwritten = 0;
4005 } else {
4006 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4007 saved_errno = errno;
4010 status = sync_file(conn, fsp, False /* write through */);
4011 if (!NT_STATUS_IS_OK(status)) {
4012 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4013 fsp_str_dbg(fsp), nt_errstr(status)));
4014 reply_nterror(req, status);
4015 goto strict_unlock;
4018 if(nwritten < 0) {
4019 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4020 goto strict_unlock;
4023 if((nwritten < numtowrite) && (numtowrite != 0)) {
4024 reply_doserror(req, ERRHRD, ERRdiskfull);
4025 goto strict_unlock;
4028 if (numtowrite) {
4029 status = do_unlock(smbd_messaging_context(),
4030 fsp,
4031 req->smbpid,
4032 (uint64_t)numtowrite,
4033 (uint64_t)startpos,
4034 WINDOWS_LOCK);
4036 if (NT_STATUS_V(status)) {
4037 reply_nterror(req, status);
4038 goto strict_unlock;
4042 reply_outbuf(req, 1, 0);
4044 SSVAL(req->outbuf,smb_vwv0,nwritten);
4046 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4047 fsp->fnum, (int)numtowrite, (int)nwritten));
4049 strict_unlock:
4050 if (numtowrite) {
4051 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4054 END_PROFILE(SMBwriteunlock);
4055 return;
4058 #undef DBGC_CLASS
4059 #define DBGC_CLASS DBGC_ALL
4061 /****************************************************************************
4062 Reply to a write.
4063 ****************************************************************************/
4065 void reply_write(struct smb_request *req)
4067 connection_struct *conn = req->conn;
4068 size_t numtowrite;
4069 ssize_t nwritten = -1;
4070 SMB_OFF_T startpos;
4071 const char *data;
4072 files_struct *fsp;
4073 struct lock_struct lock;
4074 NTSTATUS status;
4075 int saved_errno = 0;
4077 START_PROFILE(SMBwrite);
4079 if (req->wct < 5) {
4080 END_PROFILE(SMBwrite);
4081 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4082 return;
4085 /* If it's an IPC, pass off the pipe handler. */
4086 if (IS_IPC(conn)) {
4087 reply_pipe_write(req);
4088 END_PROFILE(SMBwrite);
4089 return;
4092 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4094 if (!check_fsp(conn, req, fsp)) {
4095 END_PROFILE(SMBwrite);
4096 return;
4099 if (!CHECK_WRITE(fsp)) {
4100 reply_doserror(req, ERRDOS, ERRbadaccess);
4101 END_PROFILE(SMBwrite);
4102 return;
4105 numtowrite = SVAL(req->vwv+1, 0);
4106 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4107 data = (const char *)req->buf + 3;
4109 init_strict_lock_struct(fsp, (uint32)req->smbpid,
4110 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4111 &lock);
4113 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4114 reply_doserror(req, ERRDOS, ERRlock);
4115 END_PROFILE(SMBwrite);
4116 return;
4120 * X/Open SMB protocol says that if smb_vwv1 is
4121 * zero then the file size should be extended or
4122 * truncated to the size given in smb_vwv[2-3].
4125 if(numtowrite == 0) {
4127 * This is actually an allocate call, and set EOF. JRA.
4129 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4130 if (nwritten < 0) {
4131 reply_nterror(req, NT_STATUS_DISK_FULL);
4132 goto strict_unlock;
4134 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4135 if (nwritten < 0) {
4136 reply_nterror(req, NT_STATUS_DISK_FULL);
4137 goto strict_unlock;
4139 trigger_write_time_update_immediate(fsp);
4140 } else {
4141 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4144 status = sync_file(conn, fsp, False);
4145 if (!NT_STATUS_IS_OK(status)) {
4146 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4147 fsp_str_dbg(fsp), nt_errstr(status)));
4148 reply_nterror(req, status);
4149 goto strict_unlock;
4152 if(nwritten < 0) {
4153 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4154 goto strict_unlock;
4157 if((nwritten == 0) && (numtowrite != 0)) {
4158 reply_doserror(req, ERRHRD, ERRdiskfull);
4159 goto strict_unlock;
4162 reply_outbuf(req, 1, 0);
4164 SSVAL(req->outbuf,smb_vwv0,nwritten);
4166 if (nwritten < (ssize_t)numtowrite) {
4167 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4168 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4171 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4173 strict_unlock:
4174 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4176 END_PROFILE(SMBwrite);
4177 return;
4180 /****************************************************************************
4181 Ensure a buffer is a valid writeX for recvfile purposes.
4182 ****************************************************************************/
4184 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4185 (2*14) + /* word count (including bcc) */ \
4186 1 /* pad byte */)
4188 bool is_valid_writeX_buffer(const uint8_t *inbuf)
4190 size_t numtowrite;
4191 connection_struct *conn = NULL;
4192 unsigned int doff = 0;
4193 size_t len = smb_len_large(inbuf);
4194 struct smbd_server_connection *sconn = smbd_server_conn;
4196 if (is_encrypted_packet(inbuf)) {
4197 /* Can't do this on encrypted
4198 * connections. */
4199 return false;
4202 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4203 return false;
4206 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4207 CVAL(inbuf,smb_wct) != 14) {
4208 DEBUG(10,("is_valid_writeX_buffer: chained or "
4209 "invalid word length.\n"));
4210 return false;
4213 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4214 if (conn == NULL) {
4215 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4216 return false;
4218 if (IS_IPC(conn)) {
4219 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4220 return false;
4222 if (IS_PRINT(conn)) {
4223 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4224 return false;
4226 doff = SVAL(inbuf,smb_vwv11);
4228 numtowrite = SVAL(inbuf,smb_vwv10);
4230 if (len > doff && len - doff > 0xFFFF) {
4231 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4234 if (numtowrite == 0) {
4235 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4236 return false;
4239 /* Ensure the sizes match up. */
4240 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4241 /* no pad byte...old smbclient :-( */
4242 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4243 (unsigned int)doff,
4244 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4245 return false;
4248 if (len - doff != numtowrite) {
4249 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4250 "len = %u, doff = %u, numtowrite = %u\n",
4251 (unsigned int)len,
4252 (unsigned int)doff,
4253 (unsigned int)numtowrite ));
4254 return false;
4257 DEBUG(10,("is_valid_writeX_buffer: true "
4258 "len = %u, doff = %u, numtowrite = %u\n",
4259 (unsigned int)len,
4260 (unsigned int)doff,
4261 (unsigned int)numtowrite ));
4263 return true;
4266 /****************************************************************************
4267 Reply to a write and X.
4268 ****************************************************************************/
4270 void reply_write_and_X(struct smb_request *req)
4272 connection_struct *conn = req->conn;
4273 files_struct *fsp;
4274 struct lock_struct lock;
4275 SMB_OFF_T startpos;
4276 size_t numtowrite;
4277 bool write_through;
4278 ssize_t nwritten;
4279 unsigned int smb_doff;
4280 unsigned int smblen;
4281 char *data;
4282 NTSTATUS status;
4284 START_PROFILE(SMBwriteX);
4286 if ((req->wct != 12) && (req->wct != 14)) {
4287 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4288 END_PROFILE(SMBwriteX);
4289 return;
4292 numtowrite = SVAL(req->vwv+10, 0);
4293 smb_doff = SVAL(req->vwv+11, 0);
4294 smblen = smb_len(req->inbuf);
4296 if (req->unread_bytes > 0xFFFF ||
4297 (smblen > smb_doff &&
4298 smblen - smb_doff > 0xFFFF)) {
4299 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4302 if (req->unread_bytes) {
4303 /* Can't do a recvfile write on IPC$ */
4304 if (IS_IPC(conn)) {
4305 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4306 END_PROFILE(SMBwriteX);
4307 return;
4309 if (numtowrite != req->unread_bytes) {
4310 reply_doserror(req, ERRDOS, ERRbadmem);
4311 END_PROFILE(SMBwriteX);
4312 return;
4314 } else {
4315 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4316 smb_doff + numtowrite > smblen) {
4317 reply_doserror(req, ERRDOS, ERRbadmem);
4318 END_PROFILE(SMBwriteX);
4319 return;
4323 /* If it's an IPC, pass off the pipe handler. */
4324 if (IS_IPC(conn)) {
4325 if (req->unread_bytes) {
4326 reply_doserror(req, ERRDOS, ERRbadmem);
4327 END_PROFILE(SMBwriteX);
4328 return;
4330 reply_pipe_write_and_X(req);
4331 END_PROFILE(SMBwriteX);
4332 return;
4335 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4336 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4337 write_through = BITSETW(req->vwv+7,0);
4339 if (!check_fsp(conn, req, fsp)) {
4340 END_PROFILE(SMBwriteX);
4341 return;
4344 if (!CHECK_WRITE(fsp)) {
4345 reply_doserror(req, ERRDOS, ERRbadaccess);
4346 END_PROFILE(SMBwriteX);
4347 return;
4350 data = smb_base(req->inbuf) + smb_doff;
4352 if(req->wct == 14) {
4353 #ifdef LARGE_SMB_OFF_T
4355 * This is a large offset (64 bit) write.
4357 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4359 #else /* !LARGE_SMB_OFF_T */
4362 * Ensure we haven't been sent a >32 bit offset.
4365 if(IVAL(req->vwv+12, 0) != 0) {
4366 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4367 "used and we don't support 64 bit offsets.\n",
4368 (unsigned int)IVAL(req->vwv+12, 0) ));
4369 reply_doserror(req, ERRDOS, ERRbadaccess);
4370 END_PROFILE(SMBwriteX);
4371 return;
4374 #endif /* LARGE_SMB_OFF_T */
4377 init_strict_lock_struct(fsp, (uint32)req->smbpid,
4378 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4379 &lock);
4381 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4382 reply_doserror(req, ERRDOS, ERRlock);
4383 END_PROFILE(SMBwriteX);
4384 return;
4387 /* X/Open SMB protocol says that, unlike SMBwrite
4388 if the length is zero then NO truncation is
4389 done, just a write of zero. To truncate a file,
4390 use SMBwrite. */
4392 if(numtowrite == 0) {
4393 nwritten = 0;
4394 } else {
4396 if ((req->unread_bytes == 0) &&
4397 schedule_aio_write_and_X(conn, req, fsp, data, startpos,
4398 numtowrite)) {
4399 goto strict_unlock;
4402 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4405 if(nwritten < 0) {
4406 reply_nterror(req, map_nt_error_from_unix(errno));
4407 goto strict_unlock;
4410 if((nwritten == 0) && (numtowrite != 0)) {
4411 reply_doserror(req, ERRHRD, ERRdiskfull);
4412 goto strict_unlock;
4415 reply_outbuf(req, 6, 0);
4416 SSVAL(req->outbuf,smb_vwv2,nwritten);
4417 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4419 if (nwritten < (ssize_t)numtowrite) {
4420 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4421 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4424 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4425 fsp->fnum, (int)numtowrite, (int)nwritten));
4427 status = sync_file(conn, fsp, write_through);
4428 if (!NT_STATUS_IS_OK(status)) {
4429 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4430 fsp_str_dbg(fsp), nt_errstr(status)));
4431 reply_nterror(req, status);
4432 goto strict_unlock;
4435 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4437 END_PROFILE(SMBwriteX);
4438 chain_reply(req);
4439 return;
4441 strict_unlock:
4442 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4444 END_PROFILE(SMBwriteX);
4445 return;
4448 /****************************************************************************
4449 Reply to a lseek.
4450 ****************************************************************************/
4452 void reply_lseek(struct smb_request *req)
4454 connection_struct *conn = req->conn;
4455 SMB_OFF_T startpos;
4456 SMB_OFF_T res= -1;
4457 int mode,umode;
4458 files_struct *fsp;
4460 START_PROFILE(SMBlseek);
4462 if (req->wct < 4) {
4463 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4464 END_PROFILE(SMBlseek);
4465 return;
4468 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4470 if (!check_fsp(conn, req, fsp)) {
4471 return;
4474 flush_write_cache(fsp, SEEK_FLUSH);
4476 mode = SVAL(req->vwv+1, 0) & 3;
4477 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4478 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4480 switch (mode) {
4481 case 0:
4482 umode = SEEK_SET;
4483 res = startpos;
4484 break;
4485 case 1:
4486 umode = SEEK_CUR;
4487 res = fsp->fh->pos + startpos;
4488 break;
4489 case 2:
4490 umode = SEEK_END;
4491 break;
4492 default:
4493 umode = SEEK_SET;
4494 res = startpos;
4495 break;
4498 if (umode == SEEK_END) {
4499 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4500 if(errno == EINVAL) {
4501 SMB_OFF_T current_pos = startpos;
4502 SMB_STRUCT_STAT sbuf;
4504 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
4505 reply_nterror(req,
4506 map_nt_error_from_unix(errno));
4507 END_PROFILE(SMBlseek);
4508 return;
4511 current_pos += sbuf.st_ex_size;
4512 if(current_pos < 0)
4513 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4517 if(res == -1) {
4518 reply_nterror(req, map_nt_error_from_unix(errno));
4519 END_PROFILE(SMBlseek);
4520 return;
4524 fsp->fh->pos = res;
4526 reply_outbuf(req, 2, 0);
4527 SIVAL(req->outbuf,smb_vwv0,res);
4529 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4530 fsp->fnum, (double)startpos, (double)res, mode));
4532 END_PROFILE(SMBlseek);
4533 return;
4536 /****************************************************************************
4537 Reply to a flush.
4538 ****************************************************************************/
4540 void reply_flush(struct smb_request *req)
4542 connection_struct *conn = req->conn;
4543 uint16 fnum;
4544 files_struct *fsp;
4546 START_PROFILE(SMBflush);
4548 if (req->wct < 1) {
4549 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4550 return;
4553 fnum = SVAL(req->vwv+0, 0);
4554 fsp = file_fsp(req, fnum);
4556 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4557 return;
4560 if (!fsp) {
4561 file_sync_all(conn);
4562 } else {
4563 NTSTATUS status = sync_file(conn, fsp, True);
4564 if (!NT_STATUS_IS_OK(status)) {
4565 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4566 fsp_str_dbg(fsp), nt_errstr(status)));
4567 reply_nterror(req, status);
4568 END_PROFILE(SMBflush);
4569 return;
4573 reply_outbuf(req, 0, 0);
4575 DEBUG(3,("flush\n"));
4576 END_PROFILE(SMBflush);
4577 return;
4580 /****************************************************************************
4581 Reply to a exit.
4582 conn POINTER CAN BE NULL HERE !
4583 ****************************************************************************/
4585 void reply_exit(struct smb_request *req)
4587 START_PROFILE(SMBexit);
4589 file_close_pid(req->smbpid, req->vuid);
4591 reply_outbuf(req, 0, 0);
4593 DEBUG(3,("exit\n"));
4595 END_PROFILE(SMBexit);
4596 return;
4599 /****************************************************************************
4600 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4601 ****************************************************************************/
4603 void reply_close(struct smb_request *req)
4605 connection_struct *conn = req->conn;
4606 NTSTATUS status = NT_STATUS_OK;
4607 files_struct *fsp = NULL;
4608 START_PROFILE(SMBclose);
4610 if (req->wct < 3) {
4611 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4612 END_PROFILE(SMBclose);
4613 return;
4616 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4619 * We can only use check_fsp if we know it's not a directory.
4622 if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
4623 reply_doserror(req, ERRDOS, ERRbadfid);
4624 END_PROFILE(SMBclose);
4625 return;
4628 if(fsp->is_directory) {
4630 * Special case - close NT SMB directory handle.
4632 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4633 status = close_file(req, fsp, NORMAL_CLOSE);
4634 } else {
4635 time_t t;
4637 * Close ordinary file.
4640 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4641 fsp->fh->fd, fsp->fnum,
4642 conn->num_files_open));
4645 * Take care of any time sent in the close.
4648 t = srv_make_unix_date3(req->vwv+1);
4649 set_close_write_time(NULL, fsp, convert_time_t_to_timespec(t));
4652 * close_file() returns the unix errno if an error
4653 * was detected on close - normally this is due to
4654 * a disk full error. If not then it was probably an I/O error.
4657 status = close_file(req, fsp, NORMAL_CLOSE);
4660 if (!NT_STATUS_IS_OK(status)) {
4661 reply_nterror(req, status);
4662 END_PROFILE(SMBclose);
4663 return;
4666 reply_outbuf(req, 0, 0);
4667 END_PROFILE(SMBclose);
4668 return;
4671 /****************************************************************************
4672 Reply to a writeclose (Core+ protocol).
4673 ****************************************************************************/
4675 void reply_writeclose(struct smb_request *req)
4677 connection_struct *conn = req->conn;
4678 size_t numtowrite;
4679 ssize_t nwritten = -1;
4680 NTSTATUS close_status = NT_STATUS_OK;
4681 SMB_OFF_T startpos;
4682 const char *data;
4683 struct timespec mtime;
4684 files_struct *fsp;
4685 struct lock_struct lock;
4687 START_PROFILE(SMBwriteclose);
4689 if (req->wct < 6) {
4690 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4691 END_PROFILE(SMBwriteclose);
4692 return;
4695 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4697 if (!check_fsp(conn, req, fsp)) {
4698 END_PROFILE(SMBwriteclose);
4699 return;
4701 if (!CHECK_WRITE(fsp)) {
4702 reply_doserror(req, ERRDOS,ERRbadaccess);
4703 END_PROFILE(SMBwriteclose);
4704 return;
4707 numtowrite = SVAL(req->vwv+1, 0);
4708 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4709 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4710 data = (const char *)req->buf + 1;
4712 if (numtowrite) {
4713 init_strict_lock_struct(fsp, (uint32)req->smbpid,
4714 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4715 &lock);
4717 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4718 reply_doserror(req, ERRDOS,ERRlock);
4719 END_PROFILE(SMBwriteclose);
4720 return;
4724 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4726 set_close_write_time(NULL, fsp, mtime);
4729 * More insanity. W2K only closes the file if writelen > 0.
4730 * JRA.
4733 if (numtowrite) {
4734 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4735 "file %s\n", fsp_str_dbg(fsp)));
4736 close_status = close_file(req, fsp, NORMAL_CLOSE);
4739 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4740 fsp->fnum, (int)numtowrite, (int)nwritten,
4741 conn->num_files_open));
4743 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4744 reply_doserror(req, ERRHRD, ERRdiskfull);
4745 goto strict_unlock;
4748 if(!NT_STATUS_IS_OK(close_status)) {
4749 reply_nterror(req, close_status);
4750 goto strict_unlock;
4753 reply_outbuf(req, 1, 0);
4755 SSVAL(req->outbuf,smb_vwv0,nwritten);
4757 strict_unlock:
4758 if (numtowrite) {
4759 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4762 END_PROFILE(SMBwriteclose);
4763 return;
4766 #undef DBGC_CLASS
4767 #define DBGC_CLASS DBGC_LOCKING
4769 /****************************************************************************
4770 Reply to a lock.
4771 ****************************************************************************/
4773 void reply_lock(struct smb_request *req)
4775 connection_struct *conn = req->conn;
4776 uint64_t count,offset;
4777 NTSTATUS status;
4778 files_struct *fsp;
4779 struct byte_range_lock *br_lck = NULL;
4781 START_PROFILE(SMBlock);
4783 if (req->wct < 5) {
4784 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4785 END_PROFILE(SMBlock);
4786 return;
4789 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4791 if (!check_fsp(conn, req, fsp)) {
4792 END_PROFILE(SMBlock);
4793 return;
4796 count = (uint64_t)IVAL(req->vwv+1, 0);
4797 offset = (uint64_t)IVAL(req->vwv+3, 0);
4799 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4800 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4802 br_lck = do_lock(smbd_messaging_context(),
4803 fsp,
4804 req->smbpid,
4805 count,
4806 offset,
4807 WRITE_LOCK,
4808 WINDOWS_LOCK,
4809 False, /* Non-blocking lock. */
4810 &status,
4811 NULL,
4812 NULL);
4814 TALLOC_FREE(br_lck);
4816 if (NT_STATUS_V(status)) {
4817 reply_nterror(req, status);
4818 END_PROFILE(SMBlock);
4819 return;
4822 reply_outbuf(req, 0, 0);
4824 END_PROFILE(SMBlock);
4825 return;
4828 /****************************************************************************
4829 Reply to a unlock.
4830 ****************************************************************************/
4832 void reply_unlock(struct smb_request *req)
4834 connection_struct *conn = req->conn;
4835 uint64_t count,offset;
4836 NTSTATUS status;
4837 files_struct *fsp;
4839 START_PROFILE(SMBunlock);
4841 if (req->wct < 5) {
4842 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4843 END_PROFILE(SMBunlock);
4844 return;
4847 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4849 if (!check_fsp(conn, req, fsp)) {
4850 END_PROFILE(SMBunlock);
4851 return;
4854 count = (uint64_t)IVAL(req->vwv+1, 0);
4855 offset = (uint64_t)IVAL(req->vwv+3, 0);
4857 status = do_unlock(smbd_messaging_context(),
4858 fsp,
4859 req->smbpid,
4860 count,
4861 offset,
4862 WINDOWS_LOCK);
4864 if (NT_STATUS_V(status)) {
4865 reply_nterror(req, status);
4866 END_PROFILE(SMBunlock);
4867 return;
4870 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4871 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
4873 reply_outbuf(req, 0, 0);
4875 END_PROFILE(SMBunlock);
4876 return;
4879 #undef DBGC_CLASS
4880 #define DBGC_CLASS DBGC_ALL
4882 /****************************************************************************
4883 Reply to a tdis.
4884 conn POINTER CAN BE NULL HERE !
4885 ****************************************************************************/
4887 void reply_tdis(struct smb_request *req)
4889 connection_struct *conn = req->conn;
4890 START_PROFILE(SMBtdis);
4892 if (!conn) {
4893 DEBUG(4,("Invalid connection in tdis\n"));
4894 reply_doserror(req, ERRSRV, ERRinvnid);
4895 END_PROFILE(SMBtdis);
4896 return;
4899 conn->used = False;
4901 close_cnum(conn,req->vuid);
4902 req->conn = NULL;
4904 reply_outbuf(req, 0, 0);
4905 END_PROFILE(SMBtdis);
4906 return;
4909 /****************************************************************************
4910 Reply to a echo.
4911 conn POINTER CAN BE NULL HERE !
4912 ****************************************************************************/
4914 void reply_echo(struct smb_request *req)
4916 connection_struct *conn = req->conn;
4917 struct smb_perfcount_data local_pcd;
4918 struct smb_perfcount_data *cur_pcd;
4919 int smb_reverb;
4920 int seq_num;
4922 START_PROFILE(SMBecho);
4924 smb_init_perfcount_data(&local_pcd);
4926 if (req->wct < 1) {
4927 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4928 END_PROFILE(SMBecho);
4929 return;
4932 smb_reverb = SVAL(req->vwv+0, 0);
4934 reply_outbuf(req, 1, req->buflen);
4936 /* copy any incoming data back out */
4937 if (req->buflen > 0) {
4938 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
4941 if (smb_reverb > 100) {
4942 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
4943 smb_reverb = 100;
4946 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
4948 /* this makes sure we catch the request pcd */
4949 if (seq_num == smb_reverb) {
4950 cur_pcd = &req->pcd;
4951 } else {
4952 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
4953 cur_pcd = &local_pcd;
4956 SSVAL(req->outbuf,smb_vwv0,seq_num);
4958 show_msg((char *)req->outbuf);
4959 if (!srv_send_smb(smbd_server_fd(),
4960 (char *)req->outbuf,
4961 true, req->seqnum+1,
4962 IS_CONN_ENCRYPTED(conn)||req->encrypted,
4963 cur_pcd))
4964 exit_server_cleanly("reply_echo: srv_send_smb failed.");
4967 DEBUG(3,("echo %d times\n", smb_reverb));
4969 TALLOC_FREE(req->outbuf);
4971 END_PROFILE(SMBecho);
4972 return;
4975 /****************************************************************************
4976 Reply to a printopen.
4977 ****************************************************************************/
4979 void reply_printopen(struct smb_request *req)
4981 connection_struct *conn = req->conn;
4982 files_struct *fsp;
4983 SMB_STRUCT_STAT sbuf;
4984 NTSTATUS status;
4986 START_PROFILE(SMBsplopen);
4988 if (req->wct < 2) {
4989 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4990 END_PROFILE(SMBsplopen);
4991 return;
4994 if (!CAN_PRINT(conn)) {
4995 reply_doserror(req, ERRDOS, ERRnoaccess);
4996 END_PROFILE(SMBsplopen);
4997 return;
5000 status = file_new(req, conn, &fsp);
5001 if(!NT_STATUS_IS_OK(status)) {
5002 reply_nterror(req, status);
5003 END_PROFILE(SMBsplopen);
5004 return;
5007 /* Open for exclusive use, write only. */
5008 status = print_fsp_open(req, conn, NULL, req->vuid, fsp, &sbuf);
5010 if (!NT_STATUS_IS_OK(status)) {
5011 file_free(req, fsp);
5012 reply_nterror(req, status);
5013 END_PROFILE(SMBsplopen);
5014 return;
5017 reply_outbuf(req, 1, 0);
5018 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5020 DEBUG(3,("openprint fd=%d fnum=%d\n",
5021 fsp->fh->fd, fsp->fnum));
5023 END_PROFILE(SMBsplopen);
5024 return;
5027 /****************************************************************************
5028 Reply to a printclose.
5029 ****************************************************************************/
5031 void reply_printclose(struct smb_request *req)
5033 connection_struct *conn = req->conn;
5034 files_struct *fsp;
5035 NTSTATUS status;
5037 START_PROFILE(SMBsplclose);
5039 if (req->wct < 1) {
5040 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5041 END_PROFILE(SMBsplclose);
5042 return;
5045 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5047 if (!check_fsp(conn, req, fsp)) {
5048 END_PROFILE(SMBsplclose);
5049 return;
5052 if (!CAN_PRINT(conn)) {
5053 reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
5054 END_PROFILE(SMBsplclose);
5055 return;
5058 DEBUG(3,("printclose fd=%d fnum=%d\n",
5059 fsp->fh->fd,fsp->fnum));
5061 status = close_file(req, fsp, NORMAL_CLOSE);
5063 if(!NT_STATUS_IS_OK(status)) {
5064 reply_nterror(req, status);
5065 END_PROFILE(SMBsplclose);
5066 return;
5069 reply_outbuf(req, 0, 0);
5071 END_PROFILE(SMBsplclose);
5072 return;
5075 /****************************************************************************
5076 Reply to a printqueue.
5077 ****************************************************************************/
5079 void reply_printqueue(struct smb_request *req)
5081 connection_struct *conn = req->conn;
5082 int max_count;
5083 int start_index;
5085 START_PROFILE(SMBsplretq);
5087 if (req->wct < 2) {
5088 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5089 END_PROFILE(SMBsplretq);
5090 return;
5093 max_count = SVAL(req->vwv+0, 0);
5094 start_index = SVAL(req->vwv+1, 0);
5096 /* we used to allow the client to get the cnum wrong, but that
5097 is really quite gross and only worked when there was only
5098 one printer - I think we should now only accept it if they
5099 get it right (tridge) */
5100 if (!CAN_PRINT(conn)) {
5101 reply_doserror(req, ERRDOS, ERRnoaccess);
5102 END_PROFILE(SMBsplretq);
5103 return;
5106 reply_outbuf(req, 2, 3);
5107 SSVAL(req->outbuf,smb_vwv0,0);
5108 SSVAL(req->outbuf,smb_vwv1,0);
5109 SCVAL(smb_buf(req->outbuf),0,1);
5110 SSVAL(smb_buf(req->outbuf),1,0);
5112 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5113 start_index, max_count));
5116 print_queue_struct *queue = NULL;
5117 print_status_struct status;
5118 int count = print_queue_status(SNUM(conn), &queue, &status);
5119 int num_to_get = ABS(max_count);
5120 int first = (max_count>0?start_index:start_index+max_count+1);
5121 int i;
5123 if (first >= count)
5124 num_to_get = 0;
5125 else
5126 num_to_get = MIN(num_to_get,count-first);
5129 for (i=first;i<first+num_to_get;i++) {
5130 char blob[28];
5131 char *p = blob;
5133 srv_put_dos_date2(p,0,queue[i].time);
5134 SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
5135 SSVAL(p,5, queue[i].job);
5136 SIVAL(p,7,queue[i].size);
5137 SCVAL(p,11,0);
5138 srvstr_push(blob, req->flags2, p+12,
5139 queue[i].fs_user, 16, STR_ASCII);
5141 if (message_push_blob(
5142 &req->outbuf,
5143 data_blob_const(
5144 blob, sizeof(blob))) == -1) {
5145 reply_nterror(req, NT_STATUS_NO_MEMORY);
5146 END_PROFILE(SMBsplretq);
5147 return;
5151 if (count > 0) {
5152 SSVAL(req->outbuf,smb_vwv0,count);
5153 SSVAL(req->outbuf,smb_vwv1,
5154 (max_count>0?first+count:first-1));
5155 SCVAL(smb_buf(req->outbuf),0,1);
5156 SSVAL(smb_buf(req->outbuf),1,28*count);
5159 SAFE_FREE(queue);
5161 DEBUG(3,("%d entries returned in queue\n",count));
5164 END_PROFILE(SMBsplretq);
5165 return;
5168 /****************************************************************************
5169 Reply to a printwrite.
5170 ****************************************************************************/
5172 void reply_printwrite(struct smb_request *req)
5174 connection_struct *conn = req->conn;
5175 int numtowrite;
5176 const char *data;
5177 files_struct *fsp;
5179 START_PROFILE(SMBsplwr);
5181 if (req->wct < 1) {
5182 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5183 END_PROFILE(SMBsplwr);
5184 return;
5187 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5189 if (!check_fsp(conn, req, fsp)) {
5190 END_PROFILE(SMBsplwr);
5191 return;
5194 if (!CAN_PRINT(conn)) {
5195 reply_doserror(req, ERRDOS, ERRnoaccess);
5196 END_PROFILE(SMBsplwr);
5197 return;
5200 if (!CHECK_WRITE(fsp)) {
5201 reply_doserror(req, ERRDOS, ERRbadaccess);
5202 END_PROFILE(SMBsplwr);
5203 return;
5206 numtowrite = SVAL(req->buf, 1);
5208 if (req->buflen < numtowrite + 3) {
5209 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5210 END_PROFILE(SMBsplwr);
5211 return;
5214 data = (const char *)req->buf + 3;
5216 if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) {
5217 reply_nterror(req, map_nt_error_from_unix(errno));
5218 END_PROFILE(SMBsplwr);
5219 return;
5222 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5224 END_PROFILE(SMBsplwr);
5225 return;
5228 /****************************************************************************
5229 Reply to a mkdir.
5230 ****************************************************************************/
5232 void reply_mkdir(struct smb_request *req)
5234 connection_struct *conn = req->conn;
5235 struct smb_filename *smb_dname = NULL;
5236 char *directory = NULL;
5237 NTSTATUS status;
5238 TALLOC_CTX *ctx = talloc_tos();
5240 START_PROFILE(SMBmkdir);
5242 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5243 STR_TERMINATE, &status);
5244 if (!NT_STATUS_IS_OK(status)) {
5245 reply_nterror(req, status);
5246 goto out;
5249 status = filename_convert(ctx, conn,
5250 req->flags2 & FLAGS2_DFS_PATHNAMES,
5251 directory,
5253 NULL,
5254 &smb_dname);
5255 if (!NT_STATUS_IS_OK(status)) {
5256 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5257 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5258 ERRSRV, ERRbadpath);
5259 goto out;
5261 reply_nterror(req, status);
5262 goto out;
5265 status = create_directory(conn, req, smb_dname);
5267 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5269 if (!NT_STATUS_IS_OK(status)) {
5271 if (!use_nt_status()
5272 && NT_STATUS_EQUAL(status,
5273 NT_STATUS_OBJECT_NAME_COLLISION)) {
5275 * Yes, in the DOS error code case we get a
5276 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5277 * samba4 torture test.
5279 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5282 reply_nterror(req, status);
5283 goto out;
5286 reply_outbuf(req, 0, 0);
5288 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5289 out:
5290 TALLOC_FREE(smb_dname);
5291 END_PROFILE(SMBmkdir);
5292 return;
5295 /****************************************************************************
5296 Static function used by reply_rmdir to delete an entire directory
5297 tree recursively. Return True on ok, False on fail.
5298 ****************************************************************************/
5300 static bool recursive_rmdir(TALLOC_CTX *ctx,
5301 connection_struct *conn,
5302 struct smb_filename *smb_dname)
5304 char *dname = NULL;
5305 bool ret = True;
5306 long offset = 0;
5307 SMB_STRUCT_STAT st;
5308 struct smb_Dir *dir_hnd;
5310 SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
5312 dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0);
5313 if(dir_hnd == NULL)
5314 return False;
5316 while((dname = ReadDirName(dir_hnd, &offset, &st))) {
5317 struct smb_filename *smb_dname_full = NULL;
5318 char *fullname = NULL;
5319 bool do_break = true;
5320 NTSTATUS status;
5322 if (ISDOT(dname) || ISDOTDOT(dname)) {
5323 TALLOC_FREE(dname);
5324 continue;
5327 if (!is_visible_file(conn, smb_dname->base_name, dname, &st,
5328 false)) {
5329 TALLOC_FREE(dname);
5330 continue;
5333 /* Construct the full name. */
5334 fullname = talloc_asprintf(ctx,
5335 "%s/%s",
5336 smb_dname->base_name,
5337 dname);
5338 if (!fullname) {
5339 errno = ENOMEM;
5340 goto err_break;
5343 status = create_synthetic_smb_fname(talloc_tos(), fullname,
5344 NULL, NULL,
5345 &smb_dname_full);
5346 if (!NT_STATUS_IS_OK(status)) {
5347 goto err_break;
5350 if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
5351 goto err_break;
5354 if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
5355 if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
5356 goto err_break;
5358 if(SMB_VFS_RMDIR(conn,
5359 smb_dname_full->base_name) != 0) {
5360 goto err_break;
5362 } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
5363 goto err_break;
5366 /* Successful iteration. */
5367 do_break = false;
5369 err_break:
5370 TALLOC_FREE(smb_dname_full);
5371 TALLOC_FREE(fullname);
5372 TALLOC_FREE(dname);
5373 if (do_break) {
5374 ret = false;
5375 break;
5378 TALLOC_FREE(dir_hnd);
5379 return ret;
5382 /****************************************************************************
5383 The internals of the rmdir code - called elsewhere.
5384 ****************************************************************************/
5386 NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
5387 connection_struct *conn,
5388 struct smb_filename *smb_dname)
5390 int ret;
5391 SMB_STRUCT_STAT st;
5393 SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
5395 /* Might be a symlink. */
5396 if(SMB_VFS_LSTAT(conn, smb_dname) != 0) {
5397 return map_nt_error_from_unix(errno);
5400 if (S_ISLNK(smb_dname->st.st_ex_mode)) {
5401 /* Is what it points to a directory ? */
5402 if(SMB_VFS_STAT(conn, smb_dname) != 0) {
5403 return map_nt_error_from_unix(errno);
5405 if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
5406 return NT_STATUS_NOT_A_DIRECTORY;
5408 ret = SMB_VFS_UNLINK(conn, smb_dname);
5409 } else {
5410 ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
5412 if (ret == 0) {
5413 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5414 FILE_NOTIFY_CHANGE_DIR_NAME,
5415 smb_dname->base_name);
5416 return NT_STATUS_OK;
5419 if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
5421 * Check to see if the only thing in this directory are
5422 * vetoed files/directories. If so then delete them and
5423 * retry. If we fail to delete any of them (and we *don't*
5424 * do a recursive delete) then fail the rmdir.
5426 char *dname = NULL;
5427 long dirpos = 0;
5428 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
5429 smb_dname->base_name, NULL,
5432 if(dir_hnd == NULL) {
5433 errno = ENOTEMPTY;
5434 goto err;
5437 while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
5438 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) {
5439 TALLOC_FREE(dname);
5440 continue;
5442 if (!is_visible_file(conn, smb_dname->base_name, dname,
5443 &st, false)) {
5444 TALLOC_FREE(dname);
5445 continue;
5447 if(!IS_VETO_PATH(conn, dname)) {
5448 TALLOC_FREE(dir_hnd);
5449 TALLOC_FREE(dname);
5450 errno = ENOTEMPTY;
5451 goto err;
5453 TALLOC_FREE(dname);
5456 /* We only have veto files/directories.
5457 * Are we allowed to delete them ? */
5459 if(!lp_recursive_veto_delete(SNUM(conn))) {
5460 TALLOC_FREE(dir_hnd);
5461 errno = ENOTEMPTY;
5462 goto err;
5465 /* Do a recursive delete. */
5466 RewindDir(dir_hnd,&dirpos);
5467 while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
5468 struct smb_filename *smb_dname_full = NULL;
5469 char *fullname = NULL;
5470 bool do_break = true;
5471 NTSTATUS status;
5473 if (ISDOT(dname) || ISDOTDOT(dname)) {
5474 TALLOC_FREE(dname);
5475 continue;
5477 if (!is_visible_file(conn, smb_dname->base_name, dname,
5478 &st, false)) {
5479 TALLOC_FREE(dname);
5480 continue;
5483 fullname = talloc_asprintf(ctx,
5484 "%s/%s",
5485 smb_dname->base_name,
5486 dname);
5488 if(!fullname) {
5489 errno = ENOMEM;
5490 goto err_break;
5493 status = create_synthetic_smb_fname(talloc_tos(),
5494 fullname, NULL,
5495 NULL,
5496 &smb_dname_full);
5497 if (!NT_STATUS_IS_OK(status)) {
5498 errno = map_errno_from_nt_status(status);
5499 goto err_break;
5502 if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
5503 goto err_break;
5505 if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
5506 if(!recursive_rmdir(ctx, conn,
5507 smb_dname_full)) {
5508 goto err_break;
5510 if(SMB_VFS_RMDIR(conn,
5511 smb_dname_full->base_name) != 0) {
5512 goto err_break;
5514 } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
5515 goto err_break;
5518 /* Successful iteration. */
5519 do_break = false;
5521 err_break:
5522 TALLOC_FREE(fullname);
5523 TALLOC_FREE(smb_dname_full);
5524 TALLOC_FREE(dname);
5525 if (do_break)
5526 break;
5528 TALLOC_FREE(dir_hnd);
5529 /* Retry the rmdir */
5530 ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
5533 err:
5535 if (ret != 0) {
5536 DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
5537 "%s\n", smb_fname_str_dbg(smb_dname),
5538 strerror(errno)));
5539 return map_nt_error_from_unix(errno);
5542 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5543 FILE_NOTIFY_CHANGE_DIR_NAME,
5544 smb_dname->base_name);
5546 return NT_STATUS_OK;
5549 /****************************************************************************
5550 Reply to a rmdir.
5551 ****************************************************************************/
5553 void reply_rmdir(struct smb_request *req)
5555 connection_struct *conn = req->conn;
5556 struct smb_filename *smb_dname = NULL;
5557 char *directory = NULL;
5558 NTSTATUS status;
5559 TALLOC_CTX *ctx = talloc_tos();
5560 struct smbd_server_connection *sconn = smbd_server_conn;
5562 START_PROFILE(SMBrmdir);
5564 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5565 STR_TERMINATE, &status);
5566 if (!NT_STATUS_IS_OK(status)) {
5567 reply_nterror(req, status);
5568 goto out;
5571 status = filename_convert(ctx, conn,
5572 req->flags2 & FLAGS2_DFS_PATHNAMES,
5573 directory,
5575 NULL,
5576 &smb_dname);
5577 if (!NT_STATUS_IS_OK(status)) {
5578 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5579 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5580 ERRSRV, ERRbadpath);
5581 goto out;
5583 reply_nterror(req, status);
5584 goto out;
5587 if (is_ntfs_stream_smb_fname(smb_dname)) {
5588 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5589 goto out;
5592 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5593 status = rmdir_internals(ctx, conn, smb_dname);
5594 if (!NT_STATUS_IS_OK(status)) {
5595 reply_nterror(req, status);
5596 goto out;
5599 reply_outbuf(req, 0, 0);
5601 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5602 out:
5603 TALLOC_FREE(smb_dname);
5604 END_PROFILE(SMBrmdir);
5605 return;
5608 /*******************************************************************
5609 Resolve wildcards in a filename rename.
5610 ********************************************************************/
5612 static bool resolve_wildcards(TALLOC_CTX *ctx,
5613 const char *name1,
5614 const char *name2,
5615 char **pp_newname)
5617 char *name2_copy = NULL;
5618 char *root1 = NULL;
5619 char *root2 = NULL;
5620 char *ext1 = NULL;
5621 char *ext2 = NULL;
5622 char *p,*p2, *pname1, *pname2;
5624 name2_copy = talloc_strdup(ctx, name2);
5625 if (!name2_copy) {
5626 return False;
5629 pname1 = strrchr_m(name1,'/');
5630 pname2 = strrchr_m(name2_copy,'/');
5632 if (!pname1 || !pname2) {
5633 return False;
5636 /* Truncate the copy of name2 at the last '/' */
5637 *pname2 = '\0';
5639 /* Now go past the '/' */
5640 pname1++;
5641 pname2++;
5643 root1 = talloc_strdup(ctx, pname1);
5644 root2 = talloc_strdup(ctx, pname2);
5646 if (!root1 || !root2) {
5647 return False;
5650 p = strrchr_m(root1,'.');
5651 if (p) {
5652 *p = 0;
5653 ext1 = talloc_strdup(ctx, p+1);
5654 } else {
5655 ext1 = talloc_strdup(ctx, "");
5657 p = strrchr_m(root2,'.');
5658 if (p) {
5659 *p = 0;
5660 ext2 = talloc_strdup(ctx, p+1);
5661 } else {
5662 ext2 = talloc_strdup(ctx, "");
5665 if (!ext1 || !ext2) {
5666 return False;
5669 p = root1;
5670 p2 = root2;
5671 while (*p2) {
5672 if (*p2 == '?') {
5673 /* Hmmm. Should this be mb-aware ? */
5674 *p2 = *p;
5675 p2++;
5676 } else if (*p2 == '*') {
5677 *p2 = '\0';
5678 root2 = talloc_asprintf(ctx, "%s%s",
5679 root2,
5681 if (!root2) {
5682 return False;
5684 break;
5685 } else {
5686 p2++;
5688 if (*p) {
5689 p++;
5693 p = ext1;
5694 p2 = ext2;
5695 while (*p2) {
5696 if (*p2 == '?') {
5697 /* Hmmm. Should this be mb-aware ? */
5698 *p2 = *p;
5699 p2++;
5700 } else if (*p2 == '*') {
5701 *p2 = '\0';
5702 ext2 = talloc_asprintf(ctx, "%s%s",
5703 ext2,
5705 if (!ext2) {
5706 return False;
5708 break;
5709 } else {
5710 p2++;
5712 if (*p) {
5713 p++;
5717 if (*ext2) {
5718 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5719 name2_copy,
5720 root2,
5721 ext2);
5722 } else {
5723 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5724 name2_copy,
5725 root2);
5728 if (!*pp_newname) {
5729 return False;
5732 return True;
5735 /****************************************************************************
5736 Ensure open files have their names updated. Updated to notify other smbd's
5737 asynchronously.
5738 ****************************************************************************/
5740 static void rename_open_files(connection_struct *conn,
5741 struct share_mode_lock *lck,
5742 const struct smb_filename *smb_fname_dst)
5744 files_struct *fsp;
5745 bool did_rename = False;
5746 NTSTATUS status;
5748 for(fsp = file_find_di_first(lck->id); fsp;
5749 fsp = file_find_di_next(fsp)) {
5750 /* fsp_name is a relative path under the fsp. To change this for other
5751 sharepaths we need to manipulate relative paths. */
5752 /* TODO - create the absolute path and manipulate the newname
5753 relative to the sharepath. */
5754 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5755 continue;
5757 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5758 "(file_id %s) from %s -> %s\n", fsp->fnum,
5759 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5760 smb_fname_str_dbg(smb_fname_dst)));
5762 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5763 if (NT_STATUS_IS_OK(status)) {
5764 did_rename = True;
5768 if (!did_rename) {
5769 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5770 "for %s\n", file_id_string_tos(&lck->id),
5771 smb_fname_str_dbg(smb_fname_dst)));
5774 /* Send messages to all smbd's (not ourself) that the name has changed. */
5775 rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
5776 smb_fname_dst);
5780 /****************************************************************************
5781 We need to check if the source path is a parent directory of the destination
5782 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5783 refuse the rename with a sharing violation. Under UNIX the above call can
5784 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5785 probably need to check that the client is a Windows one before disallowing
5786 this as a UNIX client (one with UNIX extensions) can know the source is a
5787 symlink and make this decision intelligently. Found by an excellent bug
5788 report from <AndyLiebman@aol.com>.
5789 ****************************************************************************/
5791 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5792 const struct smb_filename *smb_fname_dst)
5794 const char *psrc = smb_fname_src->base_name;
5795 const char *pdst = smb_fname_dst->base_name;
5796 size_t slen;
5798 if (psrc[0] == '.' && psrc[1] == '/') {
5799 psrc += 2;
5801 if (pdst[0] == '.' && pdst[1] == '/') {
5802 pdst += 2;
5804 if ((slen = strlen(psrc)) > strlen(pdst)) {
5805 return False;
5807 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5811 * Do the notify calls from a rename
5814 static void notify_rename(connection_struct *conn, bool is_dir,
5815 const struct smb_filename *smb_fname_src,
5816 const struct smb_filename *smb_fname_dst)
5818 char *parent_dir_src = NULL;
5819 char *parent_dir_dst = NULL;
5820 uint32 mask;
5822 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5823 : FILE_NOTIFY_CHANGE_FILE_NAME;
5825 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5826 &parent_dir_src, NULL) ||
5827 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5828 &parent_dir_dst, NULL)) {
5829 goto out;
5832 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5833 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5834 smb_fname_src->base_name);
5835 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5836 smb_fname_dst->base_name);
5838 else {
5839 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5840 smb_fname_src->base_name);
5841 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5842 smb_fname_dst->base_name);
5845 /* this is a strange one. w2k3 gives an additional event for
5846 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5847 files, but not directories */
5848 if (!is_dir) {
5849 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5850 FILE_NOTIFY_CHANGE_ATTRIBUTES
5851 |FILE_NOTIFY_CHANGE_CREATION,
5852 smb_fname_dst->base_name);
5854 out:
5855 TALLOC_FREE(parent_dir_src);
5856 TALLOC_FREE(parent_dir_dst);
5859 /****************************************************************************
5860 Rename an open file - given an fsp.
5861 ****************************************************************************/
5863 NTSTATUS rename_internals_fsp(connection_struct *conn,
5864 files_struct *fsp,
5865 const struct smb_filename *smb_fname_dst_in,
5866 uint32 attrs,
5867 bool replace_if_exists)
5869 TALLOC_CTX *ctx = talloc_tos();
5870 struct smb_filename *smb_fname_dst = NULL;
5871 NTSTATUS status = NT_STATUS_OK;
5872 struct share_mode_lock *lck = NULL;
5873 bool dst_exists, old_is_stream, new_is_stream;
5875 status = check_name(conn, smb_fname_dst_in->base_name);
5876 if (!NT_STATUS_IS_OK(status)) {
5877 return status;
5880 /* Make a copy of the dst smb_fname structs */
5882 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5883 if (!NT_STATUS_IS_OK(status)) {
5884 goto out;
5887 /* Ensure the dst smb_fname contains a '/' */
5888 if(strrchr_m(smb_fname_dst->base_name,'/') == 0) {
5889 char * tmp;
5890 tmp = talloc_asprintf(smb_fname_dst, "./%s",
5891 smb_fname_dst->base_name);
5892 if (!tmp) {
5893 status = NT_STATUS_NO_MEMORY;
5894 goto out;
5896 TALLOC_FREE(smb_fname_dst->base_name);
5897 smb_fname_dst->base_name = tmp;
5901 * Check for special case with case preserving and not
5902 * case sensitive. If the old last component differs from the original
5903 * last component only by case, then we should allow
5904 * the rename (user is trying to change the case of the
5905 * filename).
5907 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5908 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5909 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5910 char *last_slash;
5911 char *fname_dst_lcomp_base_mod = NULL;
5912 struct smb_filename *smb_fname_orig_lcomp = NULL;
5915 * Get the last component of the destination name. Note that
5916 * we guarantee that destination name contains a '/' character
5917 * above.
5919 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
5920 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
5921 if (!fname_dst_lcomp_base_mod) {
5922 status = NT_STATUS_NO_MEMORY;
5923 goto out;
5927 * Create an smb_filename struct using the original last
5928 * component of the destination.
5930 status = create_synthetic_smb_fname_split(ctx,
5931 smb_fname_dst->original_lcomp, NULL,
5932 &smb_fname_orig_lcomp);
5933 if (!NT_STATUS_IS_OK(status)) {
5934 TALLOC_FREE(fname_dst_lcomp_base_mod);
5935 goto out;
5938 /* If the base names only differ by case, use original. */
5939 if(!strcsequal(fname_dst_lcomp_base_mod,
5940 smb_fname_orig_lcomp->base_name)) {
5941 char *tmp;
5943 * Replace the modified last component with the
5944 * original.
5946 *last_slash = '\0'; /* Truncate at the '/' */
5947 tmp = talloc_asprintf(smb_fname_dst,
5948 "%s/%s",
5949 smb_fname_dst->base_name,
5950 smb_fname_orig_lcomp->base_name);
5951 if (tmp == NULL) {
5952 status = NT_STATUS_NO_MEMORY;
5953 TALLOC_FREE(fname_dst_lcomp_base_mod);
5954 TALLOC_FREE(smb_fname_orig_lcomp);
5955 goto out;
5957 TALLOC_FREE(smb_fname_dst->base_name);
5958 smb_fname_dst->base_name = tmp;
5961 /* If the stream_names only differ by case, use original. */
5962 if(!strcsequal(smb_fname_dst->stream_name,
5963 smb_fname_orig_lcomp->stream_name)) {
5964 char *tmp = NULL;
5965 /* Use the original stream. */
5966 tmp = talloc_strdup(smb_fname_dst,
5967 smb_fname_orig_lcomp->stream_name);
5968 if (tmp == NULL) {
5969 status = NT_STATUS_NO_MEMORY;
5970 TALLOC_FREE(fname_dst_lcomp_base_mod);
5971 TALLOC_FREE(smb_fname_orig_lcomp);
5972 goto out;
5974 TALLOC_FREE(smb_fname_dst->stream_name);
5975 smb_fname_dst->stream_name = tmp;
5977 TALLOC_FREE(fname_dst_lcomp_base_mod);
5978 TALLOC_FREE(smb_fname_orig_lcomp);
5982 * If the src and dest names are identical - including case,
5983 * don't do the rename, just return success.
5986 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5987 strcsequal(fsp->fsp_name->stream_name,
5988 smb_fname_dst->stream_name)) {
5989 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
5990 "- returning success\n",
5991 smb_fname_str_dbg(smb_fname_dst)));
5992 status = NT_STATUS_OK;
5993 goto out;
5996 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
5997 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
5999 /* Return the correct error code if both names aren't streams. */
6000 if (!old_is_stream && new_is_stream) {
6001 status = NT_STATUS_OBJECT_NAME_INVALID;
6002 goto out;
6005 if (old_is_stream && !new_is_stream) {
6006 status = NT_STATUS_INVALID_PARAMETER;
6007 goto out;
6010 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6012 if(!replace_if_exists && dst_exists) {
6013 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6014 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6015 smb_fname_str_dbg(smb_fname_dst)));
6016 status = NT_STATUS_OBJECT_NAME_COLLISION;
6017 goto out;
6020 if (dst_exists) {
6021 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6022 &smb_fname_dst->st);
6023 files_struct *dst_fsp = file_find_di_first(fileid);
6024 /* The file can be open when renaming a stream */
6025 if (dst_fsp && !new_is_stream) {
6026 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6027 status = NT_STATUS_ACCESS_DENIED;
6028 goto out;
6032 /* Ensure we have a valid stat struct for the source. */
6033 status = vfs_stat_fsp(fsp);
6034 if (!NT_STATUS_IS_OK(status)) {
6035 goto out;
6038 status = can_rename(conn, fsp, attrs, &fsp->fsp_name->st);
6040 if (!NT_STATUS_IS_OK(status)) {
6041 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6042 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6043 smb_fname_str_dbg(smb_fname_dst)));
6044 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6045 status = NT_STATUS_ACCESS_DENIED;
6046 goto out;
6049 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6050 status = NT_STATUS_ACCESS_DENIED;
6053 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6054 NULL);
6057 * We have the file open ourselves, so not being able to get the
6058 * corresponding share mode lock is a fatal error.
6061 SMB_ASSERT(lck != NULL);
6063 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6064 uint32 create_options = fsp->fh->private_options;
6066 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6067 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6068 smb_fname_str_dbg(smb_fname_dst)));
6070 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6071 smb_fname_dst);
6073 rename_open_files(conn, lck, smb_fname_dst);
6076 * A rename acts as a new file create w.r.t. allowing an initial delete
6077 * on close, probably because in Windows there is a new handle to the
6078 * new file. If initial delete on close was requested but not
6079 * originally set, we need to set it here. This is probably not 100% correct,
6080 * but will work for the CIFSFS client which in non-posix mode
6081 * depends on these semantics. JRA.
6084 if (create_options & FILE_DELETE_ON_CLOSE) {
6085 status = can_set_delete_on_close(fsp, True, 0);
6087 if (NT_STATUS_IS_OK(status)) {
6088 /* Note that here we set the *inital* delete on close flag,
6089 * not the regular one. The magic gets handled in close. */
6090 fsp->initial_delete_on_close = True;
6093 TALLOC_FREE(lck);
6094 status = NT_STATUS_OK;
6095 goto out;
6098 TALLOC_FREE(lck);
6100 if (errno == ENOTDIR || errno == EISDIR) {
6101 status = NT_STATUS_OBJECT_NAME_COLLISION;
6102 } else {
6103 status = map_nt_error_from_unix(errno);
6106 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6107 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6108 smb_fname_str_dbg(smb_fname_dst)));
6110 out:
6111 TALLOC_FREE(smb_fname_dst);
6113 return status;
6116 /****************************************************************************
6117 The guts of the rename command, split out so it may be called by the NT SMB
6118 code.
6119 ****************************************************************************/
6121 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6122 connection_struct *conn,
6123 struct smb_request *req,
6124 struct smb_filename *smb_fname_src,
6125 struct smb_filename *smb_fname_dst,
6126 uint32 attrs,
6127 bool replace_if_exists,
6128 bool src_has_wild,
6129 bool dest_has_wild,
6130 uint32_t access_mask)
6132 char *fname_src_dir = NULL;
6133 char *fname_src_mask = NULL;
6134 int count=0;
6135 NTSTATUS status = NT_STATUS_OK;
6136 struct smb_Dir *dir_hnd = NULL;
6137 char *dname = NULL;
6138 long offset = 0;
6139 int create_options = 0;
6140 bool posix_pathnames = lp_posix_pathnames();
6143 * Split the old name into directory and last component
6144 * strings. Note that unix_convert may have stripped off a
6145 * leading ./ from both name and newname if the rename is
6146 * at the root of the share. We need to make sure either both
6147 * name and newname contain a / character or neither of them do
6148 * as this is checked in resolve_wildcards().
6151 /* Split up the directory from the filename/mask. */
6152 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6153 &fname_src_dir, &fname_src_mask);
6154 if (!NT_STATUS_IS_OK(status)) {
6155 status = NT_STATUS_NO_MEMORY;
6156 goto out;
6160 * We should only check the mangled cache
6161 * here if unix_convert failed. This means
6162 * that the path in 'mask' doesn't exist
6163 * on the file system and so we need to look
6164 * for a possible mangle. This patch from
6165 * Tine Smukavec <valentin.smukavec@hermes.si>.
6168 if (!VALID_STAT(smb_fname_src->st) &&
6169 mangle_is_mangled(fname_src_mask, conn->params)) {
6170 char *new_mask = NULL;
6171 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6172 conn->params);
6173 if (new_mask) {
6174 TALLOC_FREE(fname_src_mask);
6175 fname_src_mask = new_mask;
6179 if (!src_has_wild) {
6180 files_struct *fsp;
6183 * Only one file needs to be renamed. Append the mask back
6184 * onto the directory.
6186 TALLOC_FREE(smb_fname_src->base_name);
6187 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6188 "%s/%s",
6189 fname_src_dir,
6190 fname_src_mask);
6191 if (!smb_fname_src->base_name) {
6192 status = NT_STATUS_NO_MEMORY;
6193 goto out;
6196 /* Ensure dst fname contains a '/' also */
6197 if(strrchr_m(smb_fname_dst->base_name, '/') == 0) {
6198 char *tmp;
6199 tmp = talloc_asprintf(smb_fname_dst, "./%s",
6200 smb_fname_dst->base_name);
6201 if (!tmp) {
6202 status = NT_STATUS_NO_MEMORY;
6203 goto out;
6205 TALLOC_FREE(smb_fname_dst->base_name);
6206 smb_fname_dst->base_name = tmp;
6209 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6210 "case_preserve = %d, short case preserve = %d, "
6211 "directory = %s, newname = %s, "
6212 "last_component_dest = %s\n",
6213 conn->case_sensitive, conn->case_preserve,
6214 conn->short_case_preserve,
6215 smb_fname_str_dbg(smb_fname_src),
6216 smb_fname_str_dbg(smb_fname_dst),
6217 smb_fname_dst->original_lcomp));
6219 /* The dest name still may have wildcards. */
6220 if (dest_has_wild) {
6221 char *fname_dst_mod = NULL;
6222 if (!resolve_wildcards(smb_fname_dst,
6223 smb_fname_src->base_name,
6224 smb_fname_dst->base_name,
6225 &fname_dst_mod)) {
6226 DEBUG(6, ("rename_internals: resolve_wildcards "
6227 "%s %s failed\n",
6228 smb_fname_src->base_name,
6229 smb_fname_dst->base_name));
6230 status = NT_STATUS_NO_MEMORY;
6231 goto out;
6233 TALLOC_FREE(smb_fname_dst->base_name);
6234 smb_fname_dst->base_name = fname_dst_mod;
6237 ZERO_STRUCT(smb_fname_src->st);
6238 if (posix_pathnames) {
6239 SMB_VFS_LSTAT(conn, smb_fname_src);
6240 } else {
6241 SMB_VFS_STAT(conn, smb_fname_src);
6244 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6245 create_options |= FILE_DIRECTORY_FILE;
6248 status = SMB_VFS_CREATE_FILE(
6249 conn, /* conn */
6250 req, /* req */
6251 0, /* root_dir_fid */
6252 smb_fname_src, /* fname */
6253 access_mask, /* access_mask */
6254 (FILE_SHARE_READ | /* share_access */
6255 FILE_SHARE_WRITE),
6256 FILE_OPEN, /* create_disposition*/
6257 create_options, /* create_options */
6258 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6259 0, /* oplock_request */
6260 0, /* allocation_size */
6261 NULL, /* sd */
6262 NULL, /* ea_list */
6263 &fsp, /* result */
6264 NULL); /* pinfo */
6266 if (!NT_STATUS_IS_OK(status)) {
6267 DEBUG(3, ("Could not open rename source %s: %s\n",
6268 smb_fname_str_dbg(smb_fname_src),
6269 nt_errstr(status)));
6270 goto out;
6273 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6274 attrs, replace_if_exists);
6276 close_file(req, fsp, NORMAL_CLOSE);
6278 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6279 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6280 smb_fname_str_dbg(smb_fname_dst)));
6282 goto out;
6286 * Wildcards - process each file that matches.
6288 if (strequal(fname_src_mask, "????????.???")) {
6289 TALLOC_FREE(fname_src_mask);
6290 fname_src_mask = talloc_strdup(ctx, "*");
6291 if (!fname_src_mask) {
6292 status = NT_STATUS_NO_MEMORY;
6293 goto out;
6297 status = check_name(conn, fname_src_dir);
6298 if (!NT_STATUS_IS_OK(status)) {
6299 goto out;
6302 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6303 attrs);
6304 if (dir_hnd == NULL) {
6305 status = map_nt_error_from_unix(errno);
6306 goto out;
6309 status = NT_STATUS_NO_SUCH_FILE;
6311 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6312 * - gentest fix. JRA
6315 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st))) {
6316 files_struct *fsp = NULL;
6317 char *destname = NULL;
6318 bool sysdir_entry = False;
6320 /* Quick check for "." and ".." */
6321 if (ISDOT(dname) || ISDOTDOT(dname)) {
6322 if (attrs & aDIR) {
6323 sysdir_entry = True;
6324 } else {
6325 TALLOC_FREE(dname);
6326 continue;
6330 if (!is_visible_file(conn, fname_src_dir, dname,
6331 &smb_fname_src->st, false)) {
6332 TALLOC_FREE(dname);
6333 continue;
6336 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6337 TALLOC_FREE(dname);
6338 continue;
6341 if (sysdir_entry) {
6342 status = NT_STATUS_OBJECT_NAME_INVALID;
6343 break;
6346 TALLOC_FREE(smb_fname_src->base_name);
6347 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6348 "%s/%s",
6349 fname_src_dir,
6350 dname);
6351 if (!smb_fname_src->base_name) {
6352 status = NT_STATUS_NO_MEMORY;
6353 goto out;
6356 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6357 smb_fname_dst->base_name,
6358 &destname)) {
6359 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6360 smb_fname_src->base_name, destname));
6361 TALLOC_FREE(dname);
6362 continue;
6364 if (!destname) {
6365 status = NT_STATUS_NO_MEMORY;
6366 goto out;
6369 TALLOC_FREE(smb_fname_dst->base_name);
6370 smb_fname_dst->base_name = destname;
6372 ZERO_STRUCT(smb_fname_src->st);
6373 if (posix_pathnames) {
6374 SMB_VFS_LSTAT(conn, smb_fname_src);
6375 } else {
6376 SMB_VFS_STAT(conn, smb_fname_src);
6379 create_options = 0;
6381 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6382 create_options |= FILE_DIRECTORY_FILE;
6385 status = SMB_VFS_CREATE_FILE(
6386 conn, /* conn */
6387 req, /* req */
6388 0, /* root_dir_fid */
6389 smb_fname_src, /* fname */
6390 access_mask, /* access_mask */
6391 (FILE_SHARE_READ | /* share_access */
6392 FILE_SHARE_WRITE),
6393 FILE_OPEN, /* create_disposition*/
6394 create_options, /* create_options */
6395 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6396 0, /* oplock_request */
6397 0, /* allocation_size */
6398 NULL, /* sd */
6399 NULL, /* ea_list */
6400 &fsp, /* result */
6401 NULL); /* pinfo */
6403 if (!NT_STATUS_IS_OK(status)) {
6404 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6405 "returned %s rename %s -> %s\n",
6406 nt_errstr(status),
6407 smb_fname_str_dbg(smb_fname_src),
6408 smb_fname_str_dbg(smb_fname_dst)));
6409 break;
6412 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6413 dname);
6414 if (!smb_fname_dst->original_lcomp) {
6415 status = NT_STATUS_NO_MEMORY;
6416 goto out;
6419 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6420 attrs, replace_if_exists);
6422 close_file(req, fsp, NORMAL_CLOSE);
6424 if (!NT_STATUS_IS_OK(status)) {
6425 DEBUG(3, ("rename_internals_fsp returned %s for "
6426 "rename %s -> %s\n", nt_errstr(status),
6427 smb_fname_str_dbg(smb_fname_src),
6428 smb_fname_str_dbg(smb_fname_dst)));
6429 break;
6432 count++;
6434 DEBUG(3,("rename_internals: doing rename on %s -> "
6435 "%s\n", smb_fname_str_dbg(smb_fname_src),
6436 smb_fname_str_dbg(smb_fname_src)));
6437 TALLOC_FREE(dname);
6439 TALLOC_FREE(dir_hnd);
6441 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6442 status = map_nt_error_from_unix(errno);
6445 out:
6446 TALLOC_FREE(dname);
6447 TALLOC_FREE(fname_src_dir);
6448 TALLOC_FREE(fname_src_mask);
6449 return status;
6452 /****************************************************************************
6453 Reply to a mv.
6454 ****************************************************************************/
6456 void reply_mv(struct smb_request *req)
6458 connection_struct *conn = req->conn;
6459 char *name = NULL;
6460 char *newname = NULL;
6461 const char *p;
6462 uint32 attrs;
6463 NTSTATUS status;
6464 bool src_has_wcard = False;
6465 bool dest_has_wcard = False;
6466 TALLOC_CTX *ctx = talloc_tos();
6467 struct smb_filename *smb_fname_src = NULL;
6468 struct smb_filename *smb_fname_dst = NULL;
6470 START_PROFILE(SMBmv);
6472 if (req->wct < 1) {
6473 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6474 goto out;
6477 attrs = SVAL(req->vwv+0, 0);
6479 p = (const char *)req->buf + 1;
6480 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6481 &status, &src_has_wcard);
6482 if (!NT_STATUS_IS_OK(status)) {
6483 reply_nterror(req, status);
6484 goto out;
6486 p++;
6487 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6488 &status, &dest_has_wcard);
6489 if (!NT_STATUS_IS_OK(status)) {
6490 reply_nterror(req, status);
6491 goto out;
6494 status = filename_convert(ctx,
6495 conn,
6496 req->flags2 & FLAGS2_DFS_PATHNAMES,
6497 name,
6498 UCF_COND_ALLOW_WCARD_LCOMP,
6499 &src_has_wcard,
6500 &smb_fname_src);
6502 if (!NT_STATUS_IS_OK(status)) {
6503 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6504 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6505 ERRSRV, ERRbadpath);
6506 goto out;
6508 reply_nterror(req, status);
6509 goto out;
6512 status = filename_convert(ctx,
6513 conn,
6514 req->flags2 & FLAGS2_DFS_PATHNAMES,
6515 newname,
6516 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6517 &dest_has_wcard,
6518 &smb_fname_dst);
6520 if (!NT_STATUS_IS_OK(status)) {
6521 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6522 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6523 ERRSRV, ERRbadpath);
6524 goto out;
6526 reply_nterror(req, status);
6527 goto out;
6530 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6531 smb_fname_str_dbg(smb_fname_dst)));
6533 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6534 attrs, False, src_has_wcard, dest_has_wcard,
6535 DELETE_ACCESS);
6536 if (!NT_STATUS_IS_OK(status)) {
6537 if (open_was_deferred(req->mid)) {
6538 /* We have re-scheduled this call. */
6539 goto out;
6541 reply_nterror(req, status);
6542 goto out;
6545 reply_outbuf(req, 0, 0);
6546 out:
6547 TALLOC_FREE(smb_fname_src);
6548 TALLOC_FREE(smb_fname_dst);
6549 END_PROFILE(SMBmv);
6550 return;
6553 /*******************************************************************
6554 Copy a file as part of a reply_copy.
6555 ******************************************************************/
6558 * TODO: check error codes on all callers
6561 NTSTATUS copy_file(TALLOC_CTX *ctx,
6562 connection_struct *conn,
6563 struct smb_filename *smb_fname_src,
6564 struct smb_filename *smb_fname_dst,
6565 int ofun,
6566 int count,
6567 bool target_is_directory)
6569 struct smb_filename *smb_fname_dst_tmp = NULL;
6570 SMB_OFF_T ret=-1;
6571 files_struct *fsp1,*fsp2;
6572 uint32 dosattrs;
6573 uint32 new_create_disposition;
6574 NTSTATUS status;
6577 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6578 if (!NT_STATUS_IS_OK(status)) {
6579 return status;
6583 * If the target is a directory, extract the last component from the
6584 * src filename and append it to the dst filename
6586 if (target_is_directory) {
6587 const char *p;
6589 /* dest/target can't be a stream if it's a directory. */
6590 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6592 p = strrchr_m(smb_fname_src->base_name,'/');
6593 if (p) {
6594 p++;
6595 } else {
6596 p = smb_fname_src->base_name;
6598 smb_fname_dst_tmp->base_name =
6599 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6601 if (!smb_fname_dst_tmp->base_name) {
6602 status = NT_STATUS_NO_MEMORY;
6603 goto out;
6607 status = vfs_file_exist(conn, smb_fname_src);
6608 if (!NT_STATUS_IS_OK(status)) {
6609 goto out;
6612 if (!target_is_directory && count) {
6613 new_create_disposition = FILE_OPEN;
6614 } else {
6615 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
6616 NULL, NULL,
6617 &new_create_disposition,
6618 NULL)) {
6619 status = NT_STATUS_INVALID_PARAMETER;
6620 goto out;
6624 /* Open the src file for reading. */
6625 status = SMB_VFS_CREATE_FILE(
6626 conn, /* conn */
6627 NULL, /* req */
6628 0, /* root_dir_fid */
6629 smb_fname_src, /* fname */
6630 FILE_GENERIC_READ, /* access_mask */
6631 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6632 FILE_OPEN, /* create_disposition*/
6633 0, /* create_options */
6634 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6635 INTERNAL_OPEN_ONLY, /* oplock_request */
6636 0, /* allocation_size */
6637 NULL, /* sd */
6638 NULL, /* ea_list */
6639 &fsp1, /* result */
6640 NULL); /* psbuf */
6642 if (!NT_STATUS_IS_OK(status)) {
6643 goto out;
6646 dosattrs = dos_mode(conn, smb_fname_src);
6648 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6649 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6652 /* Open the dst file for writing. */
6653 status = SMB_VFS_CREATE_FILE(
6654 conn, /* conn */
6655 NULL, /* req */
6656 0, /* root_dir_fid */
6657 smb_fname_dst, /* fname */
6658 FILE_GENERIC_WRITE, /* access_mask */
6659 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6660 new_create_disposition, /* create_disposition*/
6661 0, /* create_options */
6662 dosattrs, /* file_attributes */
6663 INTERNAL_OPEN_ONLY, /* oplock_request */
6664 0, /* allocation_size */
6665 NULL, /* sd */
6666 NULL, /* ea_list */
6667 &fsp2, /* result */
6668 NULL); /* psbuf */
6670 if (!NT_STATUS_IS_OK(status)) {
6671 close_file(NULL, fsp1, ERROR_CLOSE);
6672 goto out;
6675 if ((ofun&3) == 1) {
6676 if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
6677 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
6679 * Stop the copy from occurring.
6681 ret = -1;
6682 smb_fname_src->st.st_ex_size = 0;
6686 /* Do the actual copy. */
6687 if (smb_fname_src->st.st_ex_size) {
6688 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6691 close_file(NULL, fsp1, NORMAL_CLOSE);
6693 /* Ensure the modtime is set correctly on the destination file. */
6694 set_close_write_time(NULL, fsp2, smb_fname_src->st.st_ex_mtime);
6697 * As we are opening fsp1 read-only we only expect
6698 * an error on close on fsp2 if we are out of space.
6699 * Thus we don't look at the error return from the
6700 * close of fsp1.
6702 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6704 if (!NT_STATUS_IS_OK(status)) {
6705 goto out;
6708 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6709 status = NT_STATUS_DISK_FULL;
6710 goto out;
6713 status = NT_STATUS_OK;
6715 out:
6716 TALLOC_FREE(smb_fname_dst_tmp);
6717 return status;
6720 /****************************************************************************
6721 Reply to a file copy.
6722 ****************************************************************************/
6724 void reply_copy(struct smb_request *req)
6726 connection_struct *conn = req->conn;
6727 struct smb_filename *smb_fname_src = NULL;
6728 struct smb_filename *smb_fname_dst = NULL;
6729 char *fname_src = NULL;
6730 char *fname_dst = NULL;
6731 char *fname_src_mask = NULL;
6732 char *fname_src_dir = NULL;
6733 const char *p;
6734 int count=0;
6735 int error = ERRnoaccess;
6736 int tid2;
6737 int ofun;
6738 int flags;
6739 bool target_is_directory=False;
6740 bool source_has_wild = False;
6741 bool dest_has_wild = False;
6742 NTSTATUS status;
6743 TALLOC_CTX *ctx = talloc_tos();
6745 START_PROFILE(SMBcopy);
6747 if (req->wct < 3) {
6748 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6749 goto out;
6752 tid2 = SVAL(req->vwv+0, 0);
6753 ofun = SVAL(req->vwv+1, 0);
6754 flags = SVAL(req->vwv+2, 0);
6756 p = (const char *)req->buf;
6757 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6758 &status, &source_has_wild);
6759 if (!NT_STATUS_IS_OK(status)) {
6760 reply_nterror(req, status);
6761 goto out;
6763 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6764 &status, &dest_has_wild);
6765 if (!NT_STATUS_IS_OK(status)) {
6766 reply_nterror(req, status);
6767 goto out;
6770 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6772 if (tid2 != conn->cnum) {
6773 /* can't currently handle inter share copies XXXX */
6774 DEBUG(3,("Rejecting inter-share copy\n"));
6775 reply_doserror(req, ERRSRV, ERRinvdevice);
6776 goto out;
6779 status = filename_convert(ctx, conn,
6780 req->flags2 & FLAGS2_DFS_PATHNAMES,
6781 fname_src,
6782 UCF_COND_ALLOW_WCARD_LCOMP,
6783 &source_has_wild,
6784 &smb_fname_src);
6785 if (!NT_STATUS_IS_OK(status)) {
6786 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6787 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6788 ERRSRV, ERRbadpath);
6789 goto out;
6791 reply_nterror(req, status);
6792 goto out;
6795 status = filename_convert(ctx, conn,
6796 req->flags2 & FLAGS2_DFS_PATHNAMES,
6797 fname_dst,
6798 UCF_COND_ALLOW_WCARD_LCOMP,
6799 &dest_has_wild,
6800 &smb_fname_dst);
6801 if (!NT_STATUS_IS_OK(status)) {
6802 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6803 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6804 ERRSRV, ERRbadpath);
6805 goto out;
6807 reply_nterror(req, status);
6808 goto out;
6811 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6813 if ((flags&1) && target_is_directory) {
6814 reply_doserror(req, ERRDOS, ERRbadfile);
6815 goto out;
6818 if ((flags&2) && !target_is_directory) {
6819 reply_doserror(req, ERRDOS, ERRbadpath);
6820 goto out;
6823 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6824 /* wants a tree copy! XXXX */
6825 DEBUG(3,("Rejecting tree copy\n"));
6826 reply_doserror(req, ERRSRV, ERRerror);
6827 goto out;
6830 /* Split up the directory from the filename/mask. */
6831 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6832 &fname_src_dir, &fname_src_mask);
6833 if (!NT_STATUS_IS_OK(status)) {
6834 reply_nterror(req, NT_STATUS_NO_MEMORY);
6835 goto out;
6839 * We should only check the mangled cache
6840 * here if unix_convert failed. This means
6841 * that the path in 'mask' doesn't exist
6842 * on the file system and so we need to look
6843 * for a possible mangle. This patch from
6844 * Tine Smukavec <valentin.smukavec@hermes.si>.
6846 if (!VALID_STAT(smb_fname_src->st) &&
6847 mangle_is_mangled(fname_src_mask, conn->params)) {
6848 char *new_mask = NULL;
6849 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6850 &new_mask, conn->params);
6852 /* Use demangled name if one was successfully found. */
6853 if (new_mask) {
6854 TALLOC_FREE(fname_src_mask);
6855 fname_src_mask = new_mask;
6859 if (!source_has_wild) {
6862 * Only one file needs to be copied. Append the mask back onto
6863 * the directory.
6865 TALLOC_FREE(smb_fname_src->base_name);
6866 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6867 "%s/%s",
6868 fname_src_dir,
6869 fname_src_mask);
6870 if (!smb_fname_src->base_name) {
6871 reply_nterror(req, NT_STATUS_NO_MEMORY);
6872 goto out;
6875 if (dest_has_wild) {
6876 char *fname_dst_mod = NULL;
6877 if (!resolve_wildcards(smb_fname_dst,
6878 smb_fname_src->base_name,
6879 smb_fname_dst->base_name,
6880 &fname_dst_mod)) {
6881 reply_nterror(req, NT_STATUS_NO_MEMORY);
6882 goto out;
6884 TALLOC_FREE(smb_fname_dst->base_name);
6885 smb_fname_dst->base_name = fname_dst_mod;
6888 status = check_name(conn, smb_fname_src->base_name);
6889 if (!NT_STATUS_IS_OK(status)) {
6890 reply_nterror(req, status);
6891 goto out;
6894 status = check_name(conn, smb_fname_dst->base_name);
6895 if (!NT_STATUS_IS_OK(status)) {
6896 reply_nterror(req, status);
6897 goto out;
6900 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
6901 ofun, count, target_is_directory);
6903 if(!NT_STATUS_IS_OK(status)) {
6904 reply_nterror(req, status);
6905 goto out;
6906 } else {
6907 count++;
6909 } else {
6910 struct smb_Dir *dir_hnd = NULL;
6911 char *dname = NULL;
6912 long offset = 0;
6915 * There is a wildcard that requires us to actually read the
6916 * src dir and copy each file matching the mask to the dst.
6917 * Right now streams won't be copied, but this could
6918 * presumably be added with a nested loop for reach dir entry.
6920 SMB_ASSERT(!smb_fname_src->stream_name);
6921 SMB_ASSERT(!smb_fname_dst->stream_name);
6923 smb_fname_src->stream_name = NULL;
6924 smb_fname_dst->stream_name = NULL;
6926 if (strequal(fname_src_mask,"????????.???")) {
6927 TALLOC_FREE(fname_src_mask);
6928 fname_src_mask = talloc_strdup(ctx, "*");
6929 if (!fname_src_mask) {
6930 reply_nterror(req, NT_STATUS_NO_MEMORY);
6931 goto out;
6935 status = check_name(conn, fname_src_dir);
6936 if (!NT_STATUS_IS_OK(status)) {
6937 reply_nterror(req, status);
6938 goto out;
6941 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
6942 if (dir_hnd == NULL) {
6943 status = map_nt_error_from_unix(errno);
6944 reply_nterror(req, status);
6945 goto out;
6948 error = ERRbadfile;
6950 /* Iterate over the src dir copying each entry to the dst. */
6951 while ((dname = ReadDirName(dir_hnd, &offset,
6952 &smb_fname_src->st))) {
6953 char *destname = NULL;
6955 if (ISDOT(dname) || ISDOTDOT(dname)) {
6956 TALLOC_FREE(dname);
6957 continue;
6960 if (!is_visible_file(conn, fname_src_dir, dname,
6961 &smb_fname_src->st, false)) {
6962 TALLOC_FREE(dname);
6963 continue;
6966 if(!mask_match(dname, fname_src_mask,
6967 conn->case_sensitive)) {
6968 TALLOC_FREE(dname);
6969 continue;
6972 error = ERRnoaccess;
6974 /* Get the src smb_fname struct setup. */
6975 TALLOC_FREE(smb_fname_src->base_name);
6976 smb_fname_src->base_name =
6977 talloc_asprintf(smb_fname_src, "%s/%s",
6978 fname_src_dir, dname);
6980 if (!smb_fname_src->base_name) {
6981 TALLOC_FREE(dir_hnd);
6982 TALLOC_FREE(dname);
6983 reply_nterror(req, NT_STATUS_NO_MEMORY);
6984 goto out;
6987 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6988 smb_fname_dst->base_name,
6989 &destname)) {
6990 TALLOC_FREE(dname);
6991 continue;
6993 if (!destname) {
6994 TALLOC_FREE(dir_hnd);
6995 TALLOC_FREE(dname);
6996 reply_nterror(req, NT_STATUS_NO_MEMORY);
6997 goto out;
7000 TALLOC_FREE(smb_fname_dst->base_name);
7001 smb_fname_dst->base_name = destname;
7003 status = check_name(conn, smb_fname_src->base_name);
7004 if (!NT_STATUS_IS_OK(status)) {
7005 TALLOC_FREE(dir_hnd);
7006 TALLOC_FREE(dname);
7007 reply_nterror(req, status);
7008 goto out;
7011 status = check_name(conn, smb_fname_dst->base_name);
7012 if (!NT_STATUS_IS_OK(status)) {
7013 TALLOC_FREE(dir_hnd);
7014 TALLOC_FREE(dname);
7015 reply_nterror(req, status);
7016 goto out;
7019 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7020 smb_fname_src->base_name,
7021 smb_fname_dst->base_name));
7023 status = copy_file(ctx, conn, smb_fname_src,
7024 smb_fname_dst, ofun, count,
7025 target_is_directory);
7026 if (NT_STATUS_IS_OK(status)) {
7027 count++;
7030 TALLOC_FREE(dname);
7032 TALLOC_FREE(dir_hnd);
7035 if (count == 0) {
7036 reply_doserror(req, ERRDOS, error);
7037 goto out;
7040 reply_outbuf(req, 1, 0);
7041 SSVAL(req->outbuf,smb_vwv0,count);
7042 out:
7043 TALLOC_FREE(smb_fname_src);
7044 TALLOC_FREE(smb_fname_dst);
7045 TALLOC_FREE(fname_src);
7046 TALLOC_FREE(fname_dst);
7047 TALLOC_FREE(fname_src_mask);
7048 TALLOC_FREE(fname_src_dir);
7050 END_PROFILE(SMBcopy);
7051 return;
7054 #undef DBGC_CLASS
7055 #define DBGC_CLASS DBGC_LOCKING
7057 /****************************************************************************
7058 Get a lock pid, dealing with large count requests.
7059 ****************************************************************************/
7061 uint32 get_lock_pid(const uint8_t *data, int data_offset,
7062 bool large_file_format)
7064 if(!large_file_format)
7065 return (uint32)SVAL(data,SMB_LPID_OFFSET(data_offset));
7066 else
7067 return (uint32)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7070 /****************************************************************************
7071 Get a lock count, dealing with large count requests.
7072 ****************************************************************************/
7074 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7075 bool large_file_format)
7077 uint64_t count = 0;
7079 if(!large_file_format) {
7080 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7081 } else {
7083 #if defined(HAVE_LONGLONG)
7084 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7085 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7086 #else /* HAVE_LONGLONG */
7089 * NT4.x seems to be broken in that it sends large file (64 bit)
7090 * lockingX calls even if the CAP_LARGE_FILES was *not*
7091 * negotiated. For boxes without large unsigned ints truncate the
7092 * lock count by dropping the top 32 bits.
7095 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7096 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7097 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7098 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7099 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7102 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7103 #endif /* HAVE_LONGLONG */
7106 return count;
7109 #if !defined(HAVE_LONGLONG)
7110 /****************************************************************************
7111 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7112 ****************************************************************************/
7114 static uint32 map_lock_offset(uint32 high, uint32 low)
7116 unsigned int i;
7117 uint32 mask = 0;
7118 uint32 highcopy = high;
7121 * Try and find out how many significant bits there are in high.
7124 for(i = 0; highcopy; i++)
7125 highcopy >>= 1;
7128 * We use 31 bits not 32 here as POSIX
7129 * lock offsets may not be negative.
7132 mask = (~0) << (31 - i);
7134 if(low & mask)
7135 return 0; /* Fail. */
7137 high <<= (31 - i);
7139 return (high|low);
7141 #endif /* !defined(HAVE_LONGLONG) */
7143 /****************************************************************************
7144 Get a lock offset, dealing with large offset requests.
7145 ****************************************************************************/
7147 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7148 bool large_file_format, bool *err)
7150 uint64_t offset = 0;
7152 *err = False;
7154 if(!large_file_format) {
7155 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7156 } else {
7158 #if defined(HAVE_LONGLONG)
7159 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7160 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7161 #else /* HAVE_LONGLONG */
7164 * NT4.x seems to be broken in that it sends large file (64 bit)
7165 * lockingX calls even if the CAP_LARGE_FILES was *not*
7166 * negotiated. For boxes without large unsigned ints mangle the
7167 * lock offset by mapping the top 32 bits onto the lower 32.
7170 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7171 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7172 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7173 uint32 new_low = 0;
7175 if((new_low = map_lock_offset(high, low)) == 0) {
7176 *err = True;
7177 return (uint64_t)-1;
7180 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7181 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7182 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7183 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7186 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7187 #endif /* HAVE_LONGLONG */
7190 return offset;
7193 NTSTATUS smbd_do_locking(struct smb_request *req,
7194 files_struct *fsp,
7195 uint8_t type,
7196 int32_t timeout,
7197 uint16_t num_ulocks,
7198 struct smbd_lock_element *ulocks,
7199 uint16_t num_locks,
7200 struct smbd_lock_element *locks,
7201 bool *async)
7203 connection_struct *conn = req->conn;
7204 int i;
7205 NTSTATUS status = NT_STATUS_OK;
7207 *async = false;
7209 /* Data now points at the beginning of the list
7210 of smb_unlkrng structs */
7211 for(i = 0; i < (int)num_ulocks; i++) {
7212 struct smbd_lock_element *e = &ulocks[i];
7214 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7215 "pid %u, file %s\n",
7216 (double)e->offset,
7217 (double)e->count,
7218 (unsigned int)e->smbpid,
7219 fsp_str_dbg(fsp)));
7221 if (e->brltype != UNLOCK_LOCK) {
7222 /* this can only happen with SMB2 */
7223 return NT_STATUS_INVALID_PARAMETER;
7226 status = do_unlock(smbd_messaging_context(),
7227 fsp,
7228 e->smbpid,
7229 e->count,
7230 e->offset,
7231 WINDOWS_LOCK);
7233 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7234 nt_errstr(status)));
7236 if (!NT_STATUS_IS_OK(status)) {
7237 return status;
7241 /* Setup the timeout in seconds. */
7243 if (!lp_blocking_locks(SNUM(conn))) {
7244 timeout = 0;
7247 /* Data now points at the beginning of the list
7248 of smb_lkrng structs */
7250 for(i = 0; i < (int)num_locks; i++) {
7251 struct smbd_lock_element *e = &locks[i];
7253 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for pid "
7254 "%u, file %s timeout = %d\n",
7255 (double)e->offset,
7256 (double)e->count,
7257 (unsigned int)e->smbpid,
7258 fsp_str_dbg(fsp),
7259 (int)timeout));
7261 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7262 struct blocking_lock_record *blr = NULL;
7264 if (lp_blocking_locks(SNUM(conn))) {
7266 /* Schedule a message to ourselves to
7267 remove the blocking lock record and
7268 return the right error. */
7270 blr = blocking_lock_cancel(fsp,
7271 e->smbpid,
7272 e->offset,
7273 e->count,
7274 WINDOWS_LOCK,
7275 type,
7276 NT_STATUS_FILE_LOCK_CONFLICT);
7277 if (blr == NULL) {
7278 return NT_STATUS_DOS(
7279 ERRDOS,
7280 ERRcancelviolation);
7283 /* Remove a matching pending lock. */
7284 status = do_lock_cancel(fsp,
7285 e->smbpid,
7286 e->count,
7287 e->offset,
7288 WINDOWS_LOCK,
7289 blr);
7290 } else {
7291 bool blocking_lock = timeout ? true : false;
7292 bool defer_lock = false;
7293 struct byte_range_lock *br_lck;
7294 uint32_t block_smbpid;
7296 br_lck = do_lock(smbd_messaging_context(),
7297 fsp,
7298 e->smbpid,
7299 e->count,
7300 e->offset,
7301 e->brltype,
7302 WINDOWS_LOCK,
7303 blocking_lock,
7304 &status,
7305 &block_smbpid,
7306 NULL);
7308 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7309 /* Windows internal resolution for blocking locks seems
7310 to be about 200ms... Don't wait for less than that. JRA. */
7311 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7312 timeout = lp_lock_spin_time();
7314 defer_lock = true;
7317 /* This heuristic seems to match W2K3 very well. If a
7318 lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
7319 it pretends we asked for a timeout of between 150 - 300 milliseconds as
7320 far as I can tell. Replacement for do_lock_spin(). JRA. */
7322 if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
7323 NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
7324 defer_lock = true;
7325 timeout = lp_lock_spin_time();
7328 if (br_lck && defer_lock) {
7330 * A blocking lock was requested. Package up
7331 * this smb into a queued request and push it
7332 * onto the blocking lock queue.
7334 if(push_blocking_lock_request(br_lck,
7335 req,
7336 fsp,
7337 timeout,
7339 e->smbpid,
7340 e->brltype,
7341 WINDOWS_LOCK,
7342 e->offset,
7343 e->count,
7344 block_smbpid)) {
7345 TALLOC_FREE(br_lck);
7346 *async = true;
7347 return NT_STATUS_OK;
7351 TALLOC_FREE(br_lck);
7354 if (!NT_STATUS_IS_OK(status)) {
7355 break;
7359 /* If any of the above locks failed, then we must unlock
7360 all of the previous locks (X/Open spec). */
7362 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7364 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7365 i = -1; /* we want to skip the for loop */
7369 * Ensure we don't do a remove on the lock that just failed,
7370 * as under POSIX rules, if we have a lock already there, we
7371 * will delete it (and we shouldn't) .....
7373 for(i--; i >= 0; i--) {
7374 struct smbd_lock_element *e = &locks[i];
7376 do_unlock(smbd_messaging_context(),
7377 fsp,
7378 e->smbpid,
7379 e->count,
7380 e->offset,
7381 WINDOWS_LOCK);
7383 return status;
7386 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7387 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7389 return NT_STATUS_OK;
7392 /****************************************************************************
7393 Reply to a lockingX request.
7394 ****************************************************************************/
7396 void reply_lockingX(struct smb_request *req)
7398 connection_struct *conn = req->conn;
7399 files_struct *fsp;
7400 unsigned char locktype;
7401 unsigned char oplocklevel;
7402 uint16 num_ulocks;
7403 uint16 num_locks;
7404 int32 lock_timeout;
7405 int i;
7406 const uint8_t *data;
7407 bool large_file_format;
7408 bool err;
7409 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7410 struct smbd_lock_element *ulocks;
7411 struct smbd_lock_element *locks;
7412 bool async = false;
7414 START_PROFILE(SMBlockingX);
7416 if (req->wct < 8) {
7417 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7418 END_PROFILE(SMBlockingX);
7419 return;
7422 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7423 locktype = CVAL(req->vwv+3, 0);
7424 oplocklevel = CVAL(req->vwv+3, 1);
7425 num_ulocks = SVAL(req->vwv+6, 0);
7426 num_locks = SVAL(req->vwv+7, 0);
7427 lock_timeout = IVAL(req->vwv+4, 0);
7428 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7430 if (!check_fsp(conn, req, fsp)) {
7431 END_PROFILE(SMBlockingX);
7432 return;
7435 data = req->buf;
7437 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7438 /* we don't support these - and CANCEL_LOCK makes w2k
7439 and XP reboot so I don't really want to be
7440 compatible! (tridge) */
7441 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
7442 END_PROFILE(SMBlockingX);
7443 return;
7446 /* Check if this is an oplock break on a file
7447 we have granted an oplock on.
7449 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7450 /* Client can insist on breaking to none. */
7451 bool break_to_none = (oplocklevel == 0);
7452 bool result;
7454 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7455 "for fnum = %d\n", (unsigned int)oplocklevel,
7456 fsp->fnum ));
7459 * Make sure we have granted an exclusive or batch oplock on
7460 * this file.
7463 if (fsp->oplock_type == 0) {
7465 /* The Samba4 nbench simulator doesn't understand
7466 the difference between break to level2 and break
7467 to none from level2 - it sends oplock break
7468 replies in both cases. Don't keep logging an error
7469 message here - just ignore it. JRA. */
7471 DEBUG(5,("reply_lockingX: Error : oplock break from "
7472 "client for fnum = %d (oplock=%d) and no "
7473 "oplock granted on this file (%s).\n",
7474 fsp->fnum, fsp->oplock_type,
7475 fsp_str_dbg(fsp)));
7477 /* if this is a pure oplock break request then don't
7478 * send a reply */
7479 if (num_locks == 0 && num_ulocks == 0) {
7480 END_PROFILE(SMBlockingX);
7481 return;
7482 } else {
7483 END_PROFILE(SMBlockingX);
7484 reply_doserror(req, ERRDOS, ERRlock);
7485 return;
7489 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7490 (break_to_none)) {
7491 result = remove_oplock(fsp);
7492 } else {
7493 result = downgrade_oplock(fsp);
7496 if (!result) {
7497 DEBUG(0, ("reply_lockingX: error in removing "
7498 "oplock on file %s\n", fsp_str_dbg(fsp)));
7499 /* Hmmm. Is this panic justified? */
7500 smb_panic("internal tdb error");
7503 reply_to_oplock_break_requests(fsp);
7505 /* if this is a pure oplock break request then don't send a
7506 * reply */
7507 if (num_locks == 0 && num_ulocks == 0) {
7508 /* Sanity check - ensure a pure oplock break is not a
7509 chained request. */
7510 if(CVAL(req->vwv+0, 0) != 0xff)
7511 DEBUG(0,("reply_lockingX: Error : pure oplock "
7512 "break is a chained %d request !\n",
7513 (unsigned int)CVAL(req->vwv+0, 0)));
7514 END_PROFILE(SMBlockingX);
7515 return;
7519 if (req->buflen <
7520 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7521 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7522 END_PROFILE(SMBlockingX);
7523 return;
7526 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7527 if (ulocks == NULL) {
7528 reply_nterror(req, NT_STATUS_NO_MEMORY);
7529 END_PROFILE(SMBlockingX);
7530 return;
7533 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7534 if (locks == NULL) {
7535 reply_nterror(req, NT_STATUS_NO_MEMORY);
7536 END_PROFILE(SMBlockingX);
7537 return;
7540 /* Data now points at the beginning of the list
7541 of smb_unlkrng structs */
7542 for(i = 0; i < (int)num_ulocks; i++) {
7543 ulocks[i].smbpid = get_lock_pid(data, i, large_file_format);
7544 ulocks[i].count = get_lock_count(data, i, large_file_format);
7545 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7546 ulocks[i].brltype = UNLOCK_LOCK;
7549 * There is no error code marked "stupid client bug".... :-).
7551 if(err) {
7552 END_PROFILE(SMBlockingX);
7553 reply_doserror(req, ERRDOS, ERRnoaccess);
7554 return;
7558 /* Now do any requested locks */
7559 data += ((large_file_format ? 20 : 10)*num_ulocks);
7561 /* Data now points at the beginning of the list
7562 of smb_lkrng structs */
7564 for(i = 0; i < (int)num_locks; i++) {
7565 locks[i].smbpid = get_lock_pid(data, i, large_file_format);
7566 locks[i].count = get_lock_count(data, i, large_file_format);
7567 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7569 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7570 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7571 locks[i].brltype = PENDING_READ_LOCK;
7572 } else {
7573 locks[i].brltype = READ_LOCK;
7575 } else {
7576 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7577 locks[i].brltype = PENDING_WRITE_LOCK;
7578 } else {
7579 locks[i].brltype = WRITE_LOCK;
7584 * There is no error code marked "stupid client bug".... :-).
7586 if(err) {
7587 END_PROFILE(SMBlockingX);
7588 reply_doserror(req, ERRDOS, ERRnoaccess);
7589 return;
7593 status = smbd_do_locking(req, fsp,
7594 locktype, lock_timeout,
7595 num_ulocks, ulocks,
7596 num_locks, locks,
7597 &async);
7598 if (!NT_STATUS_IS_OK(status)) {
7599 END_PROFILE(SMBlockingX);
7600 reply_nterror(req, status);
7601 return;
7603 if (async) {
7604 END_PROFILE(SMBlockingX);
7605 return;
7608 reply_outbuf(req, 2, 0);
7610 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7611 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7613 END_PROFILE(SMBlockingX);
7614 chain_reply(req);
7617 #undef DBGC_CLASS
7618 #define DBGC_CLASS DBGC_ALL
7620 /****************************************************************************
7621 Reply to a SMBreadbmpx (read block multiplex) request.
7622 Always reply with an error, if someone has a platform really needs this,
7623 please contact vl@samba.org
7624 ****************************************************************************/
7626 void reply_readbmpx(struct smb_request *req)
7628 START_PROFILE(SMBreadBmpx);
7629 reply_doserror(req, ERRSRV, ERRuseSTD);
7630 END_PROFILE(SMBreadBmpx);
7631 return;
7634 /****************************************************************************
7635 Reply to a SMBreadbs (read block multiplex secondary) request.
7636 Always reply with an error, if someone has a platform really needs this,
7637 please contact vl@samba.org
7638 ****************************************************************************/
7640 void reply_readbs(struct smb_request *req)
7642 START_PROFILE(SMBreadBs);
7643 reply_doserror(req, ERRSRV, ERRuseSTD);
7644 END_PROFILE(SMBreadBs);
7645 return;
7648 /****************************************************************************
7649 Reply to a SMBsetattrE.
7650 ****************************************************************************/
7652 void reply_setattrE(struct smb_request *req)
7654 connection_struct *conn = req->conn;
7655 struct smb_file_time ft;
7656 files_struct *fsp;
7657 NTSTATUS status;
7659 START_PROFILE(SMBsetattrE);
7660 ZERO_STRUCT(ft);
7662 if (req->wct < 7) {
7663 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7664 goto out;
7667 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7669 if(!fsp || (fsp->conn != conn)) {
7670 reply_doserror(req, ERRDOS, ERRbadfid);
7671 goto out;
7675 * Convert the DOS times into unix times.
7678 ft.atime = convert_time_t_to_timespec(
7679 srv_make_unix_date2(req->vwv+3));
7680 ft.mtime = convert_time_t_to_timespec(
7681 srv_make_unix_date2(req->vwv+5));
7682 ft.create_time = convert_time_t_to_timespec(
7683 srv_make_unix_date2(req->vwv+1));
7685 reply_outbuf(req, 0, 0);
7688 * Patch from Ray Frush <frush@engr.colostate.edu>
7689 * Sometimes times are sent as zero - ignore them.
7692 /* Ensure we have a valid stat struct for the source. */
7693 status = vfs_stat_fsp(fsp);
7694 if (!NT_STATUS_IS_OK(status)) {
7695 reply_nterror(req, status);
7696 goto out;
7699 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7700 if (!NT_STATUS_IS_OK(status)) {
7701 reply_doserror(req, ERRDOS, ERRnoaccess);
7702 goto out;
7705 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7706 " createtime=%u\n",
7707 fsp->fnum,
7708 (unsigned int)ft.atime.tv_sec,
7709 (unsigned int)ft.mtime.tv_sec,
7710 (unsigned int)ft.create_time.tv_sec
7712 out:
7713 END_PROFILE(SMBsetattrE);
7714 return;
7718 /* Back from the dead for OS/2..... JRA. */
7720 /****************************************************************************
7721 Reply to a SMBwritebmpx (write block multiplex primary) request.
7722 Always reply with an error, if someone has a platform really needs this,
7723 please contact vl@samba.org
7724 ****************************************************************************/
7726 void reply_writebmpx(struct smb_request *req)
7728 START_PROFILE(SMBwriteBmpx);
7729 reply_doserror(req, ERRSRV, ERRuseSTD);
7730 END_PROFILE(SMBwriteBmpx);
7731 return;
7734 /****************************************************************************
7735 Reply to a SMBwritebs (write block multiplex secondary) request.
7736 Always reply with an error, if someone has a platform really needs this,
7737 please contact vl@samba.org
7738 ****************************************************************************/
7740 void reply_writebs(struct smb_request *req)
7742 START_PROFILE(SMBwriteBs);
7743 reply_doserror(req, ERRSRV, ERRuseSTD);
7744 END_PROFILE(SMBwriteBs);
7745 return;
7748 /****************************************************************************
7749 Reply to a SMBgetattrE.
7750 ****************************************************************************/
7752 void reply_getattrE(struct smb_request *req)
7754 connection_struct *conn = req->conn;
7755 SMB_STRUCT_STAT sbuf;
7756 int mode;
7757 files_struct *fsp;
7758 struct timespec create_ts;
7760 START_PROFILE(SMBgetattrE);
7762 if (req->wct < 1) {
7763 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7764 END_PROFILE(SMBgetattrE);
7765 return;
7768 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7770 if(!fsp || (fsp->conn != conn)) {
7771 reply_doserror(req, ERRDOS, ERRbadfid);
7772 END_PROFILE(SMBgetattrE);
7773 return;
7776 /* Do an fstat on this file */
7777 if(fsp_stat(fsp, &sbuf)) {
7778 reply_nterror(req, map_nt_error_from_unix(errno));
7779 END_PROFILE(SMBgetattrE);
7780 return;
7783 fsp->fsp_name->st = sbuf;
7785 mode = dos_mode(conn, fsp->fsp_name);
7788 * Convert the times into dos times. Set create
7789 * date to be last modify date as UNIX doesn't save
7790 * this.
7793 reply_outbuf(req, 11, 0);
7795 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7796 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7797 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7798 convert_timespec_to_time_t(sbuf.st_ex_atime));
7799 /* Should we check pending modtime here ? JRA */
7800 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7801 convert_timespec_to_time_t(sbuf.st_ex_mtime));
7803 if (mode & aDIR) {
7804 SIVAL(req->outbuf, smb_vwv6, 0);
7805 SIVAL(req->outbuf, smb_vwv8, 0);
7806 } else {
7807 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &sbuf);
7808 SIVAL(req->outbuf, smb_vwv6, (uint32)sbuf.st_ex_size);
7809 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7811 SSVAL(req->outbuf,smb_vwv10, mode);
7813 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7815 END_PROFILE(SMBgetattrE);
7816 return;