s3:librpc/gen_ndr: regen after wbint.idl changes
[Samba.git] / source3 / smbd / reply.c
blob3101e181fc89b9ac8f59a10fdd318f9ce50000b1
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 ((*s == ':') && !posix_path && !stream_started) {
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, size_t inbuf_size)
500 int msg_type = CVAL(inbuf,0);
501 int msg_flags = CVAL(inbuf,1);
502 struct smbd_server_connection *sconn = smbd_server_conn;
504 * We only really use 4 bytes of the outbuf, but for the smb_setlen
505 * calculation & friends (srv_send_smb uses that) we need the full smb
506 * header.
508 char outbuf[smb_size];
510 memset(outbuf, '\0', sizeof(outbuf));
512 smb_setlen(outbuf,0);
514 switch (msg_type) {
515 case 0x81: /* session request */
517 /* inbuf_size is guarenteed to be at least 4. */
518 fstring name1,name2;
519 int name_type1, name_type2;
520 int name_len1, name_len2;
522 *name1 = *name2 = 0;
524 if (sconn->nbt.got_session) {
525 exit_server_cleanly("multiple session request not permitted");
528 SCVAL(outbuf,0,0x82);
529 SCVAL(outbuf,3,0);
531 /* inbuf_size is guaranteed to be at least 4. */
532 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
533 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
534 DEBUG(0,("Invalid name length in session request\n"));
535 return;
537 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
538 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
539 DEBUG(0,("Invalid name length in session request\n"));
540 return;
543 name_type1 = name_extract((unsigned char *)inbuf,
544 inbuf_size,(unsigned int)4,name1);
545 name_type2 = name_extract((unsigned char *)inbuf,
546 inbuf_size,(unsigned int)(4 + name_len1),name2);
548 if (name_type1 == -1 || name_type2 == -1) {
549 DEBUG(0,("Invalid name type in session request\n"));
550 return;
553 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
554 name1, name_type1, name2, name_type2));
556 if (netbios_session_retarget(name1, name_type1)) {
557 exit_server_cleanly("retargeted client");
560 set_local_machine_name(name1, True);
561 set_remote_machine_name(name2, True);
563 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
564 get_local_machine_name(), get_remote_machine_name(),
565 name_type2));
567 if (name_type2 == 'R') {
568 /* We are being asked for a pathworks session ---
569 no thanks! */
570 SCVAL(outbuf, 0,0x83);
571 break;
574 /* only add the client's machine name to the list
575 of possibly valid usernames if we are operating
576 in share mode security */
577 if (lp_security() == SEC_SHARE) {
578 add_session_user(sconn, get_remote_machine_name());
581 reload_services(True);
582 reopen_logs();
584 sconn->nbt.got_session = true;
585 break;
588 case 0x89: /* session keepalive request
589 (some old clients produce this?) */
590 SCVAL(outbuf,0,SMBkeepalive);
591 SCVAL(outbuf,3,0);
592 break;
594 case 0x82: /* positive session response */
595 case 0x83: /* negative session response */
596 case 0x84: /* retarget session response */
597 DEBUG(0,("Unexpected session response\n"));
598 break;
600 case SMBkeepalive: /* session keepalive */
601 default:
602 return;
605 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
606 msg_type, msg_flags));
608 srv_send_smb(smbd_server_fd(), outbuf, false, 0, false, NULL);
609 return;
612 /****************************************************************************
613 Reply to a tcon.
614 conn POINTER CAN BE NULL HERE !
615 ****************************************************************************/
617 void reply_tcon(struct smb_request *req)
619 connection_struct *conn = req->conn;
620 const char *service;
621 char *service_buf = NULL;
622 char *password = NULL;
623 char *dev = NULL;
624 int pwlen=0;
625 NTSTATUS nt_status;
626 const char *p;
627 DATA_BLOB password_blob;
628 TALLOC_CTX *ctx = talloc_tos();
629 struct smbd_server_connection *sconn = smbd_server_conn;
631 START_PROFILE(SMBtcon);
633 if (req->buflen < 4) {
634 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
635 END_PROFILE(SMBtcon);
636 return;
639 p = (const char *)req->buf + 1;
640 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
641 p += 1;
642 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
643 p += pwlen+1;
644 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
645 p += 1;
647 if (service_buf == NULL || password == NULL || dev == NULL) {
648 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
649 END_PROFILE(SMBtcon);
650 return;
652 p = strrchr_m(service_buf,'\\');
653 if (p) {
654 service = p+1;
655 } else {
656 service = service_buf;
659 password_blob = data_blob(password, pwlen+1);
661 conn = make_connection(sconn,service,password_blob,dev,
662 req->vuid,&nt_status);
663 req->conn = conn;
665 data_blob_clear_free(&password_blob);
667 if (!conn) {
668 reply_nterror(req, nt_status);
669 END_PROFILE(SMBtcon);
670 return;
673 reply_outbuf(req, 2, 0);
674 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
675 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
676 SSVAL(req->outbuf,smb_tid,conn->cnum);
678 DEBUG(3,("tcon service=%s cnum=%d\n",
679 service, conn->cnum));
681 END_PROFILE(SMBtcon);
682 return;
685 /****************************************************************************
686 Reply to a tcon and X.
687 conn POINTER CAN BE NULL HERE !
688 ****************************************************************************/
690 void reply_tcon_and_X(struct smb_request *req)
692 connection_struct *conn = req->conn;
693 const char *service = NULL;
694 DATA_BLOB password;
695 TALLOC_CTX *ctx = talloc_tos();
696 /* what the cleint thinks the device is */
697 char *client_devicetype = NULL;
698 /* what the server tells the client the share represents */
699 const char *server_devicetype;
700 NTSTATUS nt_status;
701 int passlen;
702 char *path = NULL;
703 const char *p, *q;
704 uint16 tcon_flags;
705 struct smbd_server_connection *sconn = smbd_server_conn;
707 START_PROFILE(SMBtconX);
709 if (req->wct < 4) {
710 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
711 END_PROFILE(SMBtconX);
712 return;
715 passlen = SVAL(req->vwv+3, 0);
716 tcon_flags = SVAL(req->vwv+2, 0);
718 /* we might have to close an old one */
719 if ((tcon_flags & 0x1) && conn) {
720 close_cnum(conn,req->vuid);
721 req->conn = NULL;
722 conn = NULL;
725 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
726 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
727 END_PROFILE(SMBtconX);
728 return;
731 if (sconn->smb1.negprot.encrypted_passwords) {
732 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
733 if (lp_security() == SEC_SHARE) {
735 * Security = share always has a pad byte
736 * after the password.
738 p = (const char *)req->buf + passlen + 1;
739 } else {
740 p = (const char *)req->buf + passlen;
742 } else {
743 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
744 /* Ensure correct termination */
745 password.data[passlen]=0;
746 p = (const char *)req->buf + passlen + 1;
749 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
751 if (path == NULL) {
752 data_blob_clear_free(&password);
753 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
754 END_PROFILE(SMBtconX);
755 return;
759 * the service name can be either: \\server\share
760 * or share directly like on the DELL PowerVault 705
762 if (*path=='\\') {
763 q = strchr_m(path+2,'\\');
764 if (!q) {
765 data_blob_clear_free(&password);
766 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
767 END_PROFILE(SMBtconX);
768 return;
770 service = q+1;
771 } else {
772 service = path;
775 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
776 &client_devicetype, p,
777 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
779 if (client_devicetype == NULL) {
780 data_blob_clear_free(&password);
781 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
782 END_PROFILE(SMBtconX);
783 return;
786 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
788 conn = make_connection(sconn, service, password, client_devicetype,
789 req->vuid, &nt_status);
790 req->conn =conn;
792 data_blob_clear_free(&password);
794 if (!conn) {
795 reply_nterror(req, nt_status);
796 END_PROFILE(SMBtconX);
797 return;
800 if ( IS_IPC(conn) )
801 server_devicetype = "IPC";
802 else if ( IS_PRINT(conn) )
803 server_devicetype = "LPT1:";
804 else
805 server_devicetype = "A:";
807 if (get_Protocol() < PROTOCOL_NT1) {
808 reply_outbuf(req, 2, 0);
809 if (message_push_string(&req->outbuf, server_devicetype,
810 STR_TERMINATE|STR_ASCII) == -1) {
811 reply_nterror(req, NT_STATUS_NO_MEMORY);
812 END_PROFILE(SMBtconX);
813 return;
815 } else {
816 /* NT sets the fstype of IPC$ to the null string */
817 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
819 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
820 /* Return permissions. */
821 uint32 perm1 = 0;
822 uint32 perm2 = 0;
824 reply_outbuf(req, 7, 0);
826 if (IS_IPC(conn)) {
827 perm1 = FILE_ALL_ACCESS;
828 perm2 = FILE_ALL_ACCESS;
829 } else {
830 perm1 = CAN_WRITE(conn) ?
831 SHARE_ALL_ACCESS :
832 SHARE_READ_ONLY;
835 SIVAL(req->outbuf, smb_vwv3, perm1);
836 SIVAL(req->outbuf, smb_vwv5, perm2);
837 } else {
838 reply_outbuf(req, 3, 0);
841 if ((message_push_string(&req->outbuf, server_devicetype,
842 STR_TERMINATE|STR_ASCII) == -1)
843 || (message_push_string(&req->outbuf, fstype,
844 STR_TERMINATE) == -1)) {
845 reply_nterror(req, NT_STATUS_NO_MEMORY);
846 END_PROFILE(SMBtconX);
847 return;
850 /* what does setting this bit do? It is set by NT4 and
851 may affect the ability to autorun mounted cdroms */
852 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
853 (lp_csc_policy(SNUM(conn)) << 2));
855 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
856 DEBUG(2,("Serving %s as a Dfs root\n",
857 lp_servicename(SNUM(conn)) ));
858 SSVAL(req->outbuf, smb_vwv2,
859 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
864 DEBUG(3,("tconX service=%s \n",
865 service));
867 /* set the incoming and outgoing tid to the just created one */
868 SSVAL(req->inbuf,smb_tid,conn->cnum);
869 SSVAL(req->outbuf,smb_tid,conn->cnum);
871 END_PROFILE(SMBtconX);
873 req->tid = conn->cnum;
874 chain_reply(req);
875 return;
878 /****************************************************************************
879 Reply to an unknown type.
880 ****************************************************************************/
882 void reply_unknown_new(struct smb_request *req, uint8 type)
884 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
885 smb_fn_name(type), type, type));
886 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
887 return;
890 /****************************************************************************
891 Reply to an ioctl.
892 conn POINTER CAN BE NULL HERE !
893 ****************************************************************************/
895 void reply_ioctl(struct smb_request *req)
897 connection_struct *conn = req->conn;
898 uint16 device;
899 uint16 function;
900 uint32 ioctl_code;
901 int replysize;
902 char *p;
904 START_PROFILE(SMBioctl);
906 if (req->wct < 3) {
907 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
908 END_PROFILE(SMBioctl);
909 return;
912 device = SVAL(req->vwv+1, 0);
913 function = SVAL(req->vwv+2, 0);
914 ioctl_code = (device << 16) + function;
916 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
918 switch (ioctl_code) {
919 case IOCTL_QUERY_JOB_INFO:
920 replysize = 32;
921 break;
922 default:
923 reply_force_doserror(req, ERRSRV, ERRnosupport);
924 END_PROFILE(SMBioctl);
925 return;
928 reply_outbuf(req, 8, replysize+1);
929 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
930 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
931 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
932 p = smb_buf(req->outbuf);
933 memset(p, '\0', replysize+1); /* valgrind-safe. */
934 p += 1; /* Allow for alignment */
936 switch (ioctl_code) {
937 case IOCTL_QUERY_JOB_INFO:
939 files_struct *fsp = file_fsp(
940 req, SVAL(req->vwv+0, 0));
941 if (!fsp) {
942 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
943 END_PROFILE(SMBioctl);
944 return;
946 SSVAL(p,0,fsp->rap_print_jobid); /* Job number */
947 srvstr_push((char *)req->outbuf, req->flags2, p+2,
948 global_myname(), 15,
949 STR_TERMINATE|STR_ASCII);
950 if (conn) {
951 srvstr_push((char *)req->outbuf, req->flags2,
952 p+18, lp_servicename(SNUM(conn)),
953 13, STR_TERMINATE|STR_ASCII);
954 } else {
955 memset(p+18, 0, 13);
957 break;
961 END_PROFILE(SMBioctl);
962 return;
965 /****************************************************************************
966 Strange checkpath NTSTATUS mapping.
967 ****************************************************************************/
969 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
971 /* Strange DOS error code semantics only for checkpath... */
972 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
973 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
974 /* We need to map to ERRbadpath */
975 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
978 return status;
981 /****************************************************************************
982 Reply to a checkpath.
983 ****************************************************************************/
985 void reply_checkpath(struct smb_request *req)
987 connection_struct *conn = req->conn;
988 struct smb_filename *smb_fname = NULL;
989 char *name = NULL;
990 NTSTATUS status;
991 TALLOC_CTX *ctx = talloc_tos();
993 START_PROFILE(SMBcheckpath);
995 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
996 STR_TERMINATE, &status);
998 if (!NT_STATUS_IS_OK(status)) {
999 status = map_checkpath_error(req->flags2, status);
1000 reply_nterror(req, status);
1001 END_PROFILE(SMBcheckpath);
1002 return;
1005 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1007 status = filename_convert(ctx,
1008 conn,
1009 req->flags2 & FLAGS2_DFS_PATHNAMES,
1010 name,
1012 NULL,
1013 &smb_fname);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1017 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1018 ERRSRV, ERRbadpath);
1019 END_PROFILE(SMBcheckpath);
1020 return;
1022 goto path_err;
1025 if (!VALID_STAT(smb_fname->st) &&
1026 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1027 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1028 smb_fname_str_dbg(smb_fname), strerror(errno)));
1029 status = map_nt_error_from_unix(errno);
1030 goto path_err;
1033 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1034 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1035 ERRDOS, ERRbadpath);
1036 goto out;
1039 reply_outbuf(req, 0, 0);
1041 path_err:
1042 /* We special case this - as when a Windows machine
1043 is parsing a path is steps through the components
1044 one at a time - if a component fails it expects
1045 ERRbadpath, not ERRbadfile.
1047 status = map_checkpath_error(req->flags2, status);
1048 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1050 * Windows returns different error codes if
1051 * the parent directory is valid but not the
1052 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1053 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1054 * if the path is invalid.
1056 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1057 ERRDOS, ERRbadpath);
1058 goto out;
1061 reply_nterror(req, status);
1063 out:
1064 TALLOC_FREE(smb_fname);
1065 END_PROFILE(SMBcheckpath);
1066 return;
1069 /****************************************************************************
1070 Reply to a getatr.
1071 ****************************************************************************/
1073 void reply_getatr(struct smb_request *req)
1075 connection_struct *conn = req->conn;
1076 struct smb_filename *smb_fname = NULL;
1077 char *fname = NULL;
1078 int mode=0;
1079 SMB_OFF_T size=0;
1080 time_t mtime=0;
1081 const char *p;
1082 NTSTATUS status;
1083 TALLOC_CTX *ctx = talloc_tos();
1084 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1086 START_PROFILE(SMBgetatr);
1088 p = (const char *)req->buf + 1;
1089 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 reply_nterror(req, status);
1092 goto out;
1095 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1096 under WfWg - weird! */
1097 if (*fname == '\0') {
1098 mode = aHIDDEN | aDIR;
1099 if (!CAN_WRITE(conn)) {
1100 mode |= aRONLY;
1102 size = 0;
1103 mtime = 0;
1104 } else {
1105 status = filename_convert(ctx,
1106 conn,
1107 req->flags2 & FLAGS2_DFS_PATHNAMES,
1108 fname,
1110 NULL,
1111 &smb_fname);
1112 if (!NT_STATUS_IS_OK(status)) {
1113 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1114 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1115 ERRSRV, ERRbadpath);
1116 goto out;
1118 reply_nterror(req, status);
1119 goto out;
1121 if (!VALID_STAT(smb_fname->st) &&
1122 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1123 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1124 smb_fname_str_dbg(smb_fname),
1125 strerror(errno)));
1126 reply_nterror(req, map_nt_error_from_unix(errno));
1127 goto out;
1130 mode = dos_mode(conn, smb_fname);
1131 size = smb_fname->st.st_ex_size;
1133 if (ask_sharemode) {
1134 struct timespec write_time_ts;
1135 struct file_id fileid;
1137 ZERO_STRUCT(write_time_ts);
1138 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1139 get_file_infos(fileid, NULL, &write_time_ts);
1140 if (!null_timespec(write_time_ts)) {
1141 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1145 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1146 if (mode & aDIR) {
1147 size = 0;
1151 reply_outbuf(req, 10, 0);
1153 SSVAL(req->outbuf,smb_vwv0,mode);
1154 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1155 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1156 } else {
1157 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1159 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1161 if (get_Protocol() >= PROTOCOL_NT1) {
1162 SSVAL(req->outbuf, smb_flg2,
1163 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1166 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1167 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1169 out:
1170 TALLOC_FREE(smb_fname);
1171 TALLOC_FREE(fname);
1172 END_PROFILE(SMBgetatr);
1173 return;
1176 /****************************************************************************
1177 Reply to a setatr.
1178 ****************************************************************************/
1180 void reply_setatr(struct smb_request *req)
1182 struct smb_file_time ft;
1183 connection_struct *conn = req->conn;
1184 struct smb_filename *smb_fname = NULL;
1185 char *fname = NULL;
1186 int mode;
1187 time_t mtime;
1188 const char *p;
1189 NTSTATUS status;
1190 TALLOC_CTX *ctx = talloc_tos();
1192 START_PROFILE(SMBsetatr);
1194 ZERO_STRUCT(ft);
1196 if (req->wct < 2) {
1197 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1198 goto out;
1201 p = (const char *)req->buf + 1;
1202 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 reply_nterror(req, status);
1205 goto out;
1208 status = filename_convert(ctx,
1209 conn,
1210 req->flags2 & FLAGS2_DFS_PATHNAMES,
1211 fname,
1213 NULL,
1214 &smb_fname);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1217 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1218 ERRSRV, ERRbadpath);
1219 goto out;
1221 reply_nterror(req, status);
1222 goto out;
1225 if (smb_fname->base_name[0] == '.' &&
1226 smb_fname->base_name[1] == '\0') {
1228 * Not sure here is the right place to catch this
1229 * condition. Might be moved to somewhere else later -- vl
1231 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1232 goto out;
1235 mode = SVAL(req->vwv+0, 0);
1236 mtime = srv_make_unix_date3(req->vwv+1);
1238 ft.mtime = convert_time_t_to_timespec(mtime);
1239 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 reply_nterror(req, status);
1242 goto out;
1245 if (mode != FILE_ATTRIBUTE_NORMAL) {
1246 if (VALID_STAT_OF_DIR(smb_fname->st))
1247 mode |= aDIR;
1248 else
1249 mode &= ~aDIR;
1251 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1252 false) != 0) {
1253 reply_nterror(req, map_nt_error_from_unix(errno));
1254 goto out;
1258 reply_outbuf(req, 0, 0);
1260 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1261 mode));
1262 out:
1263 TALLOC_FREE(smb_fname);
1264 END_PROFILE(SMBsetatr);
1265 return;
1268 /****************************************************************************
1269 Reply to a dskattr.
1270 ****************************************************************************/
1272 void reply_dskattr(struct smb_request *req)
1274 connection_struct *conn = req->conn;
1275 uint64_t dfree,dsize,bsize;
1276 START_PROFILE(SMBdskattr);
1278 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1279 reply_nterror(req, map_nt_error_from_unix(errno));
1280 END_PROFILE(SMBdskattr);
1281 return;
1284 reply_outbuf(req, 5, 0);
1286 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1287 double total_space, free_space;
1288 /* we need to scale this to a number that DOS6 can handle. We
1289 use floating point so we can handle large drives on systems
1290 that don't have 64 bit integers
1292 we end up displaying a maximum of 2G to DOS systems
1294 total_space = dsize * (double)bsize;
1295 free_space = dfree * (double)bsize;
1297 dsize = (uint64_t)((total_space+63*512) / (64*512));
1298 dfree = (uint64_t)((free_space+63*512) / (64*512));
1300 if (dsize > 0xFFFF) dsize = 0xFFFF;
1301 if (dfree > 0xFFFF) dfree = 0xFFFF;
1303 SSVAL(req->outbuf,smb_vwv0,dsize);
1304 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1305 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1306 SSVAL(req->outbuf,smb_vwv3,dfree);
1307 } else {
1308 SSVAL(req->outbuf,smb_vwv0,dsize);
1309 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1310 SSVAL(req->outbuf,smb_vwv2,512);
1311 SSVAL(req->outbuf,smb_vwv3,dfree);
1314 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1316 END_PROFILE(SMBdskattr);
1317 return;
1321 * Utility function to split the filename from the directory.
1323 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1324 char **fname_dir_out,
1325 char **fname_mask_out)
1327 const char *p = NULL;
1328 char *fname_dir = NULL;
1329 char *fname_mask = NULL;
1331 p = strrchr_m(fname_in, '/');
1332 if (!p) {
1333 fname_dir = talloc_strdup(ctx, ".");
1334 fname_mask = talloc_strdup(ctx, fname_in);
1335 } else {
1336 fname_dir = talloc_strndup(ctx, fname_in,
1337 PTR_DIFF(p, fname_in));
1338 fname_mask = talloc_strdup(ctx, p+1);
1341 if (!fname_dir || !fname_mask) {
1342 TALLOC_FREE(fname_dir);
1343 TALLOC_FREE(fname_mask);
1344 return NT_STATUS_NO_MEMORY;
1347 *fname_dir_out = fname_dir;
1348 *fname_mask_out = fname_mask;
1349 return NT_STATUS_OK;
1352 /****************************************************************************
1353 Reply to a search.
1354 Can be called from SMBsearch, SMBffirst or SMBfunique.
1355 ****************************************************************************/
1357 void reply_search(struct smb_request *req)
1359 connection_struct *conn = req->conn;
1360 char *path = NULL;
1361 const char *mask = NULL;
1362 char *directory = NULL;
1363 struct smb_filename *smb_fname = NULL;
1364 char *fname = NULL;
1365 SMB_OFF_T size;
1366 uint32 mode;
1367 struct timespec date;
1368 uint32 dirtype;
1369 unsigned int numentries = 0;
1370 unsigned int maxentries = 0;
1371 bool finished = False;
1372 const char *p;
1373 int status_len;
1374 char status[21];
1375 int dptr_num= -1;
1376 bool check_descend = False;
1377 bool expect_close = False;
1378 NTSTATUS nt_status;
1379 bool mask_contains_wcard = False;
1380 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1381 TALLOC_CTX *ctx = talloc_tos();
1382 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1383 struct dptr_struct *dirptr = NULL;
1384 struct smbd_server_connection *sconn = smbd_server_conn;
1386 START_PROFILE(SMBsearch);
1388 if (req->wct < 2) {
1389 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1390 goto out;
1393 if (lp_posix_pathnames()) {
1394 reply_unknown_new(req, req->cmd);
1395 goto out;
1398 /* If we were called as SMBffirst then we must expect close. */
1399 if(req->cmd == SMBffirst) {
1400 expect_close = True;
1403 reply_outbuf(req, 1, 3);
1404 maxentries = SVAL(req->vwv+0, 0);
1405 dirtype = SVAL(req->vwv+1, 0);
1406 p = (const char *)req->buf + 1;
1407 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1408 &nt_status, &mask_contains_wcard);
1409 if (!NT_STATUS_IS_OK(nt_status)) {
1410 reply_nterror(req, nt_status);
1411 goto out;
1414 p++;
1415 status_len = SVAL(p, 0);
1416 p += 2;
1418 /* dirtype &= ~aDIR; */
1420 if (status_len == 0) {
1421 nt_status = filename_convert(ctx, conn,
1422 req->flags2 & FLAGS2_DFS_PATHNAMES,
1423 path,
1424 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1425 &mask_contains_wcard,
1426 &smb_fname);
1427 if (!NT_STATUS_IS_OK(nt_status)) {
1428 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1429 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1430 ERRSRV, ERRbadpath);
1431 goto out;
1433 reply_nterror(req, nt_status);
1434 goto out;
1437 directory = smb_fname->base_name;
1439 p = strrchr_m(directory,'/');
1440 if ((p != NULL) && (*directory != '/')) {
1441 mask = p + 1;
1442 directory = talloc_strndup(ctx, directory,
1443 PTR_DIFF(p, directory));
1444 } else {
1445 mask = directory;
1446 directory = talloc_strdup(ctx,".");
1449 if (!directory) {
1450 reply_nterror(req, NT_STATUS_NO_MEMORY);
1451 goto out;
1454 memset((char *)status,'\0',21);
1455 SCVAL(status,0,(dirtype & 0x1F));
1457 nt_status = dptr_create(conn,
1458 directory,
1459 True,
1460 expect_close,
1461 req->smbpid,
1462 mask,
1463 mask_contains_wcard,
1464 dirtype,
1465 &dirptr);
1466 if (!NT_STATUS_IS_OK(nt_status)) {
1467 reply_nterror(req, nt_status);
1468 goto out;
1470 dptr_num = dptr_dnum(dirptr);
1471 } else {
1472 int status_dirtype;
1473 const char *dirpath;
1475 memcpy(status,p,21);
1476 status_dirtype = CVAL(status,0) & 0x1F;
1477 if (status_dirtype != (dirtype & 0x1F)) {
1478 dirtype = status_dirtype;
1481 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1482 if (!dirptr) {
1483 goto SearchEmpty;
1485 dirpath = dptr_path(sconn, dptr_num);
1486 directory = talloc_strdup(ctx, dirpath);
1487 if (!directory) {
1488 reply_nterror(req, NT_STATUS_NO_MEMORY);
1489 goto out;
1492 mask = dptr_wcard(sconn, dptr_num);
1493 if (!mask) {
1494 goto SearchEmpty;
1497 * For a 'continue' search we have no string. So
1498 * check from the initial saved string.
1500 mask_contains_wcard = ms_has_wild(mask);
1501 dirtype = dptr_attr(sconn, dptr_num);
1504 DEBUG(4,("dptr_num is %d\n",dptr_num));
1506 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1507 dptr_init_search_op(dirptr);
1509 if ((dirtype&0x1F) == aVOLID) {
1510 char buf[DIR_STRUCT_SIZE];
1511 memcpy(buf,status,21);
1512 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1513 0,aVOLID,0,!allow_long_path_components)) {
1514 reply_nterror(req, NT_STATUS_NO_MEMORY);
1515 goto out;
1517 dptr_fill(sconn, buf+12,dptr_num);
1518 if (dptr_zero(buf+12) && (status_len==0)) {
1519 numentries = 1;
1520 } else {
1521 numentries = 0;
1523 if (message_push_blob(&req->outbuf,
1524 data_blob_const(buf, sizeof(buf)))
1525 == -1) {
1526 reply_nterror(req, NT_STATUS_NO_MEMORY);
1527 goto out;
1529 } else {
1530 unsigned int i;
1531 maxentries = MIN(
1532 maxentries,
1533 ((BUFFER_SIZE -
1534 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1535 /DIR_STRUCT_SIZE));
1537 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1538 directory,lp_dontdescend(SNUM(conn))));
1539 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1540 check_descend = True;
1543 for (i=numentries;(i<maxentries) && !finished;i++) {
1544 finished = !get_dir_entry(ctx,
1545 dirptr,
1546 mask,
1547 dirtype,
1548 &fname,
1549 &size,
1550 &mode,
1551 &date,
1552 check_descend,
1553 ask_sharemode);
1554 if (!finished) {
1555 char buf[DIR_STRUCT_SIZE];
1556 memcpy(buf,status,21);
1557 if (!make_dir_struct(ctx,
1558 buf,
1559 mask,
1560 fname,
1561 size,
1562 mode,
1563 convert_timespec_to_time_t(date),
1564 !allow_long_path_components)) {
1565 reply_nterror(req, NT_STATUS_NO_MEMORY);
1566 goto out;
1568 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1569 break;
1571 if (message_push_blob(&req->outbuf,
1572 data_blob_const(buf, sizeof(buf)))
1573 == -1) {
1574 reply_nterror(req, NT_STATUS_NO_MEMORY);
1575 goto out;
1577 numentries++;
1582 SearchEmpty:
1584 /* If we were called as SMBffirst with smb_search_id == NULL
1585 and no entries were found then return error and close dirptr
1586 (X/Open spec) */
1588 if (numentries == 0) {
1589 dptr_close(sconn, &dptr_num);
1590 } else if(expect_close && status_len == 0) {
1591 /* Close the dptr - we know it's gone */
1592 dptr_close(sconn, &dptr_num);
1595 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1596 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1597 dptr_close(sconn, &dptr_num);
1600 if ((numentries == 0) && !mask_contains_wcard) {
1601 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1602 goto out;
1605 SSVAL(req->outbuf,smb_vwv0,numentries);
1606 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1607 SCVAL(smb_buf(req->outbuf),0,5);
1608 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1610 /* The replies here are never long name. */
1611 SSVAL(req->outbuf, smb_flg2,
1612 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1613 if (!allow_long_path_components) {
1614 SSVAL(req->outbuf, smb_flg2,
1615 SVAL(req->outbuf, smb_flg2)
1616 & (~FLAGS2_LONG_PATH_COMPONENTS));
1619 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1620 SSVAL(req->outbuf, smb_flg2,
1621 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1623 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1624 smb_fn_name(req->cmd),
1625 mask,
1626 directory,
1627 dirtype,
1628 numentries,
1629 maxentries ));
1630 out:
1631 TALLOC_FREE(directory);
1632 TALLOC_FREE(smb_fname);
1633 END_PROFILE(SMBsearch);
1634 return;
1637 /****************************************************************************
1638 Reply to a fclose (stop directory search).
1639 ****************************************************************************/
1641 void reply_fclose(struct smb_request *req)
1643 int status_len;
1644 char status[21];
1645 int dptr_num= -2;
1646 const char *p;
1647 char *path = NULL;
1648 NTSTATUS err;
1649 bool path_contains_wcard = False;
1650 TALLOC_CTX *ctx = talloc_tos();
1651 struct smbd_server_connection *sconn = smbd_server_conn;
1653 START_PROFILE(SMBfclose);
1655 if (lp_posix_pathnames()) {
1656 reply_unknown_new(req, req->cmd);
1657 END_PROFILE(SMBfclose);
1658 return;
1661 p = (const char *)req->buf + 1;
1662 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1663 &err, &path_contains_wcard);
1664 if (!NT_STATUS_IS_OK(err)) {
1665 reply_nterror(req, err);
1666 END_PROFILE(SMBfclose);
1667 return;
1669 p++;
1670 status_len = SVAL(p,0);
1671 p += 2;
1673 if (status_len == 0) {
1674 reply_force_doserror(req, ERRSRV, ERRsrverror);
1675 END_PROFILE(SMBfclose);
1676 return;
1679 memcpy(status,p,21);
1681 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1682 /* Close the dptr - we know it's gone */
1683 dptr_close(sconn, &dptr_num);
1686 reply_outbuf(req, 1, 0);
1687 SSVAL(req->outbuf,smb_vwv0,0);
1689 DEBUG(3,("search close\n"));
1691 END_PROFILE(SMBfclose);
1692 return;
1695 /****************************************************************************
1696 Reply to an open.
1697 ****************************************************************************/
1699 void reply_open(struct smb_request *req)
1701 connection_struct *conn = req->conn;
1702 struct smb_filename *smb_fname = NULL;
1703 char *fname = NULL;
1704 uint32 fattr=0;
1705 SMB_OFF_T size = 0;
1706 time_t mtime=0;
1707 int info;
1708 files_struct *fsp;
1709 int oplock_request;
1710 int deny_mode;
1711 uint32 dos_attr;
1712 uint32 access_mask;
1713 uint32 share_mode;
1714 uint32 create_disposition;
1715 uint32 create_options = 0;
1716 NTSTATUS status;
1717 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1718 TALLOC_CTX *ctx = talloc_tos();
1720 START_PROFILE(SMBopen);
1722 if (req->wct < 2) {
1723 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1724 goto out;
1727 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1728 deny_mode = SVAL(req->vwv+0, 0);
1729 dos_attr = SVAL(req->vwv+1, 0);
1731 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1732 STR_TERMINATE, &status);
1733 if (!NT_STATUS_IS_OK(status)) {
1734 reply_nterror(req, status);
1735 goto out;
1738 status = filename_convert(ctx,
1739 conn,
1740 req->flags2 & FLAGS2_DFS_PATHNAMES,
1741 fname,
1743 NULL,
1744 &smb_fname);
1745 if (!NT_STATUS_IS_OK(status)) {
1746 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1747 reply_botherror(req,
1748 NT_STATUS_PATH_NOT_COVERED,
1749 ERRSRV, ERRbadpath);
1750 goto out;
1752 reply_nterror(req, status);
1753 goto out;
1756 if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
1757 OPENX_FILE_EXISTS_OPEN, &access_mask,
1758 &share_mode, &create_disposition,
1759 &create_options)) {
1760 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1761 goto out;
1764 status = SMB_VFS_CREATE_FILE(
1765 conn, /* conn */
1766 req, /* req */
1767 0, /* root_dir_fid */
1768 smb_fname, /* fname */
1769 access_mask, /* access_mask */
1770 share_mode, /* share_access */
1771 create_disposition, /* create_disposition*/
1772 create_options, /* create_options */
1773 dos_attr, /* file_attributes */
1774 oplock_request, /* oplock_request */
1775 0, /* allocation_size */
1776 NULL, /* sd */
1777 NULL, /* ea_list */
1778 &fsp, /* result */
1779 &info); /* pinfo */
1781 if (!NT_STATUS_IS_OK(status)) {
1782 if (open_was_deferred(req->mid)) {
1783 /* We have re-scheduled this call. */
1784 goto out;
1786 reply_openerror(req, status);
1787 goto out;
1790 size = smb_fname->st.st_ex_size;
1791 fattr = dos_mode(conn, smb_fname);
1793 /* Deal with other possible opens having a modified
1794 write time. JRA. */
1795 if (ask_sharemode) {
1796 struct timespec write_time_ts;
1798 ZERO_STRUCT(write_time_ts);
1799 get_file_infos(fsp->file_id, NULL, &write_time_ts);
1800 if (!null_timespec(write_time_ts)) {
1801 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1805 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1807 if (fattr & aDIR) {
1808 DEBUG(3,("attempt to open a directory %s\n",
1809 fsp_str_dbg(fsp)));
1810 close_file(req, fsp, ERROR_CLOSE);
1811 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1812 ERRDOS, ERRnoaccess);
1813 goto out;
1816 reply_outbuf(req, 7, 0);
1817 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1818 SSVAL(req->outbuf,smb_vwv1,fattr);
1819 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1820 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1821 } else {
1822 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1824 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1825 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1827 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1828 SCVAL(req->outbuf,smb_flg,
1829 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1832 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1833 SCVAL(req->outbuf,smb_flg,
1834 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1836 out:
1837 TALLOC_FREE(smb_fname);
1838 END_PROFILE(SMBopen);
1839 return;
1842 /****************************************************************************
1843 Reply to an open and X.
1844 ****************************************************************************/
1846 void reply_open_and_X(struct smb_request *req)
1848 connection_struct *conn = req->conn;
1849 struct smb_filename *smb_fname = NULL;
1850 char *fname = NULL;
1851 uint16 open_flags;
1852 int deny_mode;
1853 uint32 smb_attr;
1854 /* Breakout the oplock request bits so we can set the
1855 reply bits separately. */
1856 int ex_oplock_request;
1857 int core_oplock_request;
1858 int oplock_request;
1859 #if 0
1860 int smb_sattr = SVAL(req->vwv+4, 0);
1861 uint32 smb_time = make_unix_date3(req->vwv+6);
1862 #endif
1863 int smb_ofun;
1864 uint32 fattr=0;
1865 int mtime=0;
1866 int smb_action = 0;
1867 files_struct *fsp;
1868 NTSTATUS status;
1869 uint64_t allocation_size;
1870 ssize_t retval = -1;
1871 uint32 access_mask;
1872 uint32 share_mode;
1873 uint32 create_disposition;
1874 uint32 create_options = 0;
1875 TALLOC_CTX *ctx = talloc_tos();
1877 START_PROFILE(SMBopenX);
1879 if (req->wct < 15) {
1880 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1881 goto out;
1884 open_flags = SVAL(req->vwv+2, 0);
1885 deny_mode = SVAL(req->vwv+3, 0);
1886 smb_attr = SVAL(req->vwv+5, 0);
1887 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1888 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1889 oplock_request = ex_oplock_request | core_oplock_request;
1890 smb_ofun = SVAL(req->vwv+8, 0);
1891 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1893 /* If it's an IPC, pass off the pipe handler. */
1894 if (IS_IPC(conn)) {
1895 if (lp_nt_pipe_support()) {
1896 reply_open_pipe_and_X(conn, req);
1897 } else {
1898 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1900 goto out;
1903 /* XXXX we need to handle passed times, sattr and flags */
1904 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1905 STR_TERMINATE, &status);
1906 if (!NT_STATUS_IS_OK(status)) {
1907 reply_nterror(req, status);
1908 goto out;
1911 status = filename_convert(ctx,
1912 conn,
1913 req->flags2 & FLAGS2_DFS_PATHNAMES,
1914 fname,
1916 NULL,
1917 &smb_fname);
1918 if (!NT_STATUS_IS_OK(status)) {
1919 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1920 reply_botherror(req,
1921 NT_STATUS_PATH_NOT_COVERED,
1922 ERRSRV, ERRbadpath);
1923 goto out;
1925 reply_nterror(req, status);
1926 goto out;
1929 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
1930 &access_mask, &share_mode,
1931 &create_disposition,
1932 &create_options)) {
1933 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1934 goto out;
1937 status = SMB_VFS_CREATE_FILE(
1938 conn, /* conn */
1939 req, /* req */
1940 0, /* root_dir_fid */
1941 smb_fname, /* fname */
1942 access_mask, /* access_mask */
1943 share_mode, /* share_access */
1944 create_disposition, /* create_disposition*/
1945 create_options, /* create_options */
1946 smb_attr, /* file_attributes */
1947 oplock_request, /* oplock_request */
1948 0, /* allocation_size */
1949 NULL, /* sd */
1950 NULL, /* ea_list */
1951 &fsp, /* result */
1952 &smb_action); /* pinfo */
1954 if (!NT_STATUS_IS_OK(status)) {
1955 if (open_was_deferred(req->mid)) {
1956 /* We have re-scheduled this call. */
1957 goto out;
1959 reply_openerror(req, status);
1960 goto out;
1963 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1964 if the file is truncated or created. */
1965 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1966 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1967 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1968 close_file(req, fsp, ERROR_CLOSE);
1969 reply_nterror(req, NT_STATUS_DISK_FULL);
1970 goto out;
1972 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1973 if (retval < 0) {
1974 close_file(req, fsp, ERROR_CLOSE);
1975 reply_nterror(req, NT_STATUS_DISK_FULL);
1976 goto out;
1978 smb_fname->st.st_ex_size =
1979 SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st);
1982 fattr = dos_mode(conn, smb_fname);
1983 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1984 if (fattr & aDIR) {
1985 close_file(req, fsp, ERROR_CLOSE);
1986 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1987 goto out;
1990 /* If the caller set the extended oplock request bit
1991 and we granted one (by whatever means) - set the
1992 correct bit for extended oplock reply.
1995 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1996 smb_action |= EXTENDED_OPLOCK_GRANTED;
1999 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2000 smb_action |= EXTENDED_OPLOCK_GRANTED;
2003 /* If the caller set the core oplock request bit
2004 and we granted one (by whatever means) - set the
2005 correct bit for core oplock reply.
2008 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2009 reply_outbuf(req, 19, 0);
2010 } else {
2011 reply_outbuf(req, 15, 0);
2014 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2015 SCVAL(req->outbuf, smb_flg,
2016 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2019 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2020 SCVAL(req->outbuf, smb_flg,
2021 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2024 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2025 SSVAL(req->outbuf,smb_vwv3,fattr);
2026 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2027 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2028 } else {
2029 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2031 SIVAL(req->outbuf,smb_vwv6,(uint32)smb_fname->st.st_ex_size);
2032 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2033 SSVAL(req->outbuf,smb_vwv11,smb_action);
2035 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2036 SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS);
2039 chain_reply(req);
2040 out:
2041 TALLOC_FREE(smb_fname);
2042 END_PROFILE(SMBopenX);
2043 return;
2046 /****************************************************************************
2047 Reply to a SMBulogoffX.
2048 ****************************************************************************/
2050 void reply_ulogoffX(struct smb_request *req)
2052 struct smbd_server_connection *sconn = smbd_server_conn;
2053 user_struct *vuser;
2055 START_PROFILE(SMBulogoffX);
2057 vuser = get_valid_user_struct(sconn, req->vuid);
2059 if(vuser == NULL) {
2060 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2061 req->vuid));
2064 /* in user level security we are supposed to close any files
2065 open by this user */
2066 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2067 file_close_user(req->vuid);
2070 invalidate_vuid(sconn, req->vuid);
2072 reply_outbuf(req, 2, 0);
2074 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2076 END_PROFILE(SMBulogoffX);
2077 req->vuid = UID_FIELD_INVALID;
2078 chain_reply(req);
2081 /****************************************************************************
2082 Reply to a mknew or a create.
2083 ****************************************************************************/
2085 void reply_mknew(struct smb_request *req)
2087 connection_struct *conn = req->conn;
2088 struct smb_filename *smb_fname = NULL;
2089 char *fname = NULL;
2090 uint32 fattr = 0;
2091 struct smb_file_time ft;
2092 files_struct *fsp;
2093 int oplock_request = 0;
2094 NTSTATUS status;
2095 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2096 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2097 uint32 create_disposition;
2098 uint32 create_options = 0;
2099 TALLOC_CTX *ctx = talloc_tos();
2101 START_PROFILE(SMBcreate);
2102 ZERO_STRUCT(ft);
2104 if (req->wct < 3) {
2105 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2106 goto out;
2109 fattr = SVAL(req->vwv+0, 0);
2110 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2112 /* mtime. */
2113 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2115 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2116 STR_TERMINATE, &status);
2117 if (!NT_STATUS_IS_OK(status)) {
2118 reply_nterror(req, status);
2119 goto out;
2122 status = filename_convert(ctx,
2123 conn,
2124 req->flags2 & FLAGS2_DFS_PATHNAMES,
2125 fname,
2127 NULL,
2128 &smb_fname);
2129 if (!NT_STATUS_IS_OK(status)) {
2130 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2131 reply_botherror(req,
2132 NT_STATUS_PATH_NOT_COVERED,
2133 ERRSRV, ERRbadpath);
2134 goto out;
2136 reply_nterror(req, status);
2137 goto out;
2140 if (fattr & aVOLID) {
2141 DEBUG(0,("Attempt to create file (%s) with volid set - "
2142 "please report this\n",
2143 smb_fname_str_dbg(smb_fname)));
2146 if(req->cmd == SMBmknew) {
2147 /* We should fail if file exists. */
2148 create_disposition = FILE_CREATE;
2149 } else {
2150 /* Create if file doesn't exist, truncate if it does. */
2151 create_disposition = FILE_OVERWRITE_IF;
2154 status = SMB_VFS_CREATE_FILE(
2155 conn, /* conn */
2156 req, /* req */
2157 0, /* root_dir_fid */
2158 smb_fname, /* fname */
2159 access_mask, /* access_mask */
2160 share_mode, /* share_access */
2161 create_disposition, /* create_disposition*/
2162 create_options, /* create_options */
2163 fattr, /* file_attributes */
2164 oplock_request, /* oplock_request */
2165 0, /* allocation_size */
2166 NULL, /* sd */
2167 NULL, /* ea_list */
2168 &fsp, /* result */
2169 NULL); /* pinfo */
2171 if (!NT_STATUS_IS_OK(status)) {
2172 if (open_was_deferred(req->mid)) {
2173 /* We have re-scheduled this call. */
2174 goto out;
2176 reply_openerror(req, status);
2177 goto out;
2180 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2181 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2182 if (!NT_STATUS_IS_OK(status)) {
2183 END_PROFILE(SMBcreate);
2184 goto out;
2187 reply_outbuf(req, 1, 0);
2188 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2190 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2191 SCVAL(req->outbuf,smb_flg,
2192 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2195 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2196 SCVAL(req->outbuf,smb_flg,
2197 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2200 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2201 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2202 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2203 (unsigned int)fattr));
2205 out:
2206 TALLOC_FREE(smb_fname);
2207 END_PROFILE(SMBcreate);
2208 return;
2211 /****************************************************************************
2212 Reply to a create temporary file.
2213 ****************************************************************************/
2215 void reply_ctemp(struct smb_request *req)
2217 connection_struct *conn = req->conn;
2218 struct smb_filename *smb_fname = NULL;
2219 char *fname = NULL;
2220 uint32 fattr;
2221 files_struct *fsp;
2222 int oplock_request;
2223 int tmpfd;
2224 char *s;
2225 NTSTATUS status;
2226 TALLOC_CTX *ctx = talloc_tos();
2228 START_PROFILE(SMBctemp);
2230 if (req->wct < 3) {
2231 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2232 goto out;
2235 fattr = SVAL(req->vwv+0, 0);
2236 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2238 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2239 STR_TERMINATE, &status);
2240 if (!NT_STATUS_IS_OK(status)) {
2241 reply_nterror(req, status);
2242 goto out;
2244 if (*fname) {
2245 fname = talloc_asprintf(ctx,
2246 "%s/TMXXXXXX",
2247 fname);
2248 } else {
2249 fname = talloc_strdup(ctx, "TMXXXXXX");
2252 if (!fname) {
2253 reply_nterror(req, NT_STATUS_NO_MEMORY);
2254 goto out;
2257 status = filename_convert(ctx, conn,
2258 req->flags2 & FLAGS2_DFS_PATHNAMES,
2259 fname,
2261 NULL,
2262 &smb_fname);
2263 if (!NT_STATUS_IS_OK(status)) {
2264 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2265 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2266 ERRSRV, ERRbadpath);
2267 goto out;
2269 reply_nterror(req, status);
2270 goto out;
2273 tmpfd = mkstemp(smb_fname->base_name);
2274 if (tmpfd == -1) {
2275 reply_nterror(req, map_nt_error_from_unix(errno));
2276 goto out;
2279 SMB_VFS_STAT(conn, smb_fname);
2281 /* We should fail if file does not exist. */
2282 status = SMB_VFS_CREATE_FILE(
2283 conn, /* conn */
2284 req, /* req */
2285 0, /* root_dir_fid */
2286 smb_fname, /* fname */
2287 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2288 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2289 FILE_OPEN, /* create_disposition*/
2290 0, /* create_options */
2291 fattr, /* file_attributes */
2292 oplock_request, /* oplock_request */
2293 0, /* allocation_size */
2294 NULL, /* sd */
2295 NULL, /* ea_list */
2296 &fsp, /* result */
2297 NULL); /* pinfo */
2299 /* close fd from mkstemp() */
2300 close(tmpfd);
2302 if (!NT_STATUS_IS_OK(status)) {
2303 if (open_was_deferred(req->mid)) {
2304 /* We have re-scheduled this call. */
2305 goto out;
2307 reply_openerror(req, status);
2308 goto out;
2311 reply_outbuf(req, 1, 0);
2312 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2314 /* the returned filename is relative to the directory */
2315 s = strrchr_m(fsp->fsp_name->base_name, '/');
2316 if (!s) {
2317 s = fsp->fsp_name->base_name;
2318 } else {
2319 s++;
2322 #if 0
2323 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2324 thing in the byte section. JRA */
2325 SSVALS(p, 0, -1); /* what is this? not in spec */
2326 #endif
2327 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2328 == -1) {
2329 reply_nterror(req, NT_STATUS_NO_MEMORY);
2330 goto out;
2333 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2334 SCVAL(req->outbuf, smb_flg,
2335 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2338 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2339 SCVAL(req->outbuf, smb_flg,
2340 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2343 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2344 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2345 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2346 out:
2347 TALLOC_FREE(smb_fname);
2348 END_PROFILE(SMBctemp);
2349 return;
2352 /*******************************************************************
2353 Check if a user is allowed to rename a file.
2354 ********************************************************************/
2356 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2357 uint16 dirtype)
2359 uint32 fmode;
2361 if (!CAN_WRITE(conn)) {
2362 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2365 fmode = dos_mode(conn, fsp->fsp_name);
2366 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2367 return NT_STATUS_NO_SUCH_FILE;
2370 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2371 if (fsp->posix_open) {
2372 return NT_STATUS_OK;
2375 /* If no pathnames are open below this
2376 directory, allow the rename. */
2378 if (file_find_subpath(fsp)) {
2379 return NT_STATUS_ACCESS_DENIED;
2381 return NT_STATUS_OK;
2384 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2385 return NT_STATUS_OK;
2388 return NT_STATUS_ACCESS_DENIED;
2391 /*******************************************************************
2392 * unlink a file with all relevant access checks
2393 *******************************************************************/
2395 static NTSTATUS do_unlink(connection_struct *conn,
2396 struct smb_request *req,
2397 struct smb_filename *smb_fname,
2398 uint32 dirtype)
2400 uint32 fattr;
2401 files_struct *fsp;
2402 uint32 dirtype_orig = dirtype;
2403 NTSTATUS status;
2404 int ret;
2405 bool posix_paths = lp_posix_pathnames();
2407 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2408 smb_fname_str_dbg(smb_fname),
2409 dirtype));
2411 if (!CAN_WRITE(conn)) {
2412 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2415 if (posix_paths) {
2416 ret = SMB_VFS_LSTAT(conn, smb_fname);
2417 } else {
2418 ret = SMB_VFS_STAT(conn, smb_fname);
2420 if (ret != 0) {
2421 return map_nt_error_from_unix(errno);
2424 fattr = dos_mode(conn, smb_fname);
2426 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2427 dirtype = aDIR|aARCH|aRONLY;
2430 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2431 if (!dirtype) {
2432 return NT_STATUS_NO_SUCH_FILE;
2435 if (!dir_check_ftype(conn, fattr, dirtype)) {
2436 if (fattr & aDIR) {
2437 return NT_STATUS_FILE_IS_A_DIRECTORY;
2439 return NT_STATUS_NO_SUCH_FILE;
2442 if (dirtype_orig & 0x8000) {
2443 /* These will never be set for POSIX. */
2444 return NT_STATUS_NO_SUCH_FILE;
2447 #if 0
2448 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2449 return NT_STATUS_FILE_IS_A_DIRECTORY;
2452 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2453 return NT_STATUS_NO_SUCH_FILE;
2456 if (dirtype & 0xFF00) {
2457 /* These will never be set for POSIX. */
2458 return NT_STATUS_NO_SUCH_FILE;
2461 dirtype &= 0xFF;
2462 if (!dirtype) {
2463 return NT_STATUS_NO_SUCH_FILE;
2466 /* Can't delete a directory. */
2467 if (fattr & aDIR) {
2468 return NT_STATUS_FILE_IS_A_DIRECTORY;
2470 #endif
2472 #if 0 /* JRATEST */
2473 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2474 return NT_STATUS_OBJECT_NAME_INVALID;
2475 #endif /* JRATEST */
2477 /* On open checks the open itself will check the share mode, so
2478 don't do it here as we'll get it wrong. */
2480 status = SMB_VFS_CREATE_FILE
2481 (conn, /* conn */
2482 req, /* req */
2483 0, /* root_dir_fid */
2484 smb_fname, /* fname */
2485 DELETE_ACCESS, /* access_mask */
2486 FILE_SHARE_NONE, /* share_access */
2487 FILE_OPEN, /* create_disposition*/
2488 FILE_NON_DIRECTORY_FILE, /* create_options */
2489 /* file_attributes */
2490 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2491 FILE_ATTRIBUTE_NORMAL,
2492 0, /* oplock_request */
2493 0, /* allocation_size */
2494 NULL, /* sd */
2495 NULL, /* ea_list */
2496 &fsp, /* result */
2497 NULL); /* pinfo */
2499 if (!NT_STATUS_IS_OK(status)) {
2500 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2501 nt_errstr(status)));
2502 return status;
2505 status = can_set_delete_on_close(fsp, fattr);
2506 if (!NT_STATUS_IS_OK(status)) {
2507 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2508 "(%s)\n",
2509 smb_fname_str_dbg(smb_fname),
2510 nt_errstr(status)));
2511 close_file(req, fsp, NORMAL_CLOSE);
2512 return status;
2515 /* The set is across all open files on this dev/inode pair. */
2516 if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) {
2517 close_file(req, fsp, NORMAL_CLOSE);
2518 return NT_STATUS_ACCESS_DENIED;
2521 return close_file(req, fsp, NORMAL_CLOSE);
2524 /****************************************************************************
2525 The guts of the unlink command, split out so it may be called by the NT SMB
2526 code.
2527 ****************************************************************************/
2529 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2530 uint32 dirtype, struct smb_filename *smb_fname,
2531 bool has_wild)
2533 char *fname_dir = NULL;
2534 char *fname_mask = NULL;
2535 int count=0;
2536 NTSTATUS status = NT_STATUS_OK;
2537 TALLOC_CTX *ctx = talloc_tos();
2539 /* Split up the directory from the filename/mask. */
2540 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2541 &fname_dir, &fname_mask);
2542 if (!NT_STATUS_IS_OK(status)) {
2543 goto out;
2547 * We should only check the mangled cache
2548 * here if unix_convert failed. This means
2549 * that the path in 'mask' doesn't exist
2550 * on the file system and so we need to look
2551 * for a possible mangle. This patch from
2552 * Tine Smukavec <valentin.smukavec@hermes.si>.
2555 if (!VALID_STAT(smb_fname->st) &&
2556 mangle_is_mangled(fname_mask, conn->params)) {
2557 char *new_mask = NULL;
2558 mangle_lookup_name_from_8_3(ctx, fname_mask,
2559 &new_mask, conn->params);
2560 if (new_mask) {
2561 TALLOC_FREE(fname_mask);
2562 fname_mask = new_mask;
2566 if (!has_wild) {
2569 * Only one file needs to be unlinked. Append the mask back
2570 * onto the directory.
2572 TALLOC_FREE(smb_fname->base_name);
2573 smb_fname->base_name = talloc_asprintf(smb_fname,
2574 "%s/%s",
2575 fname_dir,
2576 fname_mask);
2577 if (!smb_fname->base_name) {
2578 status = NT_STATUS_NO_MEMORY;
2579 goto out;
2581 if (dirtype == 0) {
2582 dirtype = FILE_ATTRIBUTE_NORMAL;
2585 status = check_name(conn, smb_fname->base_name);
2586 if (!NT_STATUS_IS_OK(status)) {
2587 goto out;
2590 status = do_unlink(conn, req, smb_fname, dirtype);
2591 if (!NT_STATUS_IS_OK(status)) {
2592 goto out;
2595 count++;
2596 } else {
2597 struct smb_Dir *dir_hnd = NULL;
2598 long offset = 0;
2599 const char *dname = NULL;
2600 char *talloced = NULL;
2602 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2603 status = NT_STATUS_OBJECT_NAME_INVALID;
2604 goto out;
2607 if (strequal(fname_mask,"????????.???")) {
2608 TALLOC_FREE(fname_mask);
2609 fname_mask = talloc_strdup(ctx, "*");
2610 if (!fname_mask) {
2611 status = NT_STATUS_NO_MEMORY;
2612 goto out;
2616 status = check_name(conn, fname_dir);
2617 if (!NT_STATUS_IS_OK(status)) {
2618 goto out;
2621 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2622 dirtype);
2623 if (dir_hnd == NULL) {
2624 status = map_nt_error_from_unix(errno);
2625 goto out;
2628 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2629 the pattern matches against the long name, otherwise the short name
2630 We don't implement this yet XXXX
2633 status = NT_STATUS_NO_SUCH_FILE;
2635 while ((dname = ReadDirName(dir_hnd, &offset,
2636 &smb_fname->st, &talloced))) {
2637 TALLOC_CTX *frame = talloc_stackframe();
2639 if (!is_visible_file(conn, fname_dir, dname,
2640 &smb_fname->st, true)) {
2641 TALLOC_FREE(frame);
2642 TALLOC_FREE(talloced);
2643 continue;
2646 /* Quick check for "." and ".." */
2647 if (ISDOT(dname) || ISDOTDOT(dname)) {
2648 TALLOC_FREE(frame);
2649 TALLOC_FREE(talloced);
2650 continue;
2653 if(!mask_match(dname, fname_mask,
2654 conn->case_sensitive)) {
2655 TALLOC_FREE(frame);
2656 TALLOC_FREE(talloced);
2657 continue;
2660 TALLOC_FREE(smb_fname->base_name);
2661 smb_fname->base_name =
2662 talloc_asprintf(smb_fname, "%s/%s",
2663 fname_dir, dname);
2665 if (!smb_fname->base_name) {
2666 TALLOC_FREE(dir_hnd);
2667 status = NT_STATUS_NO_MEMORY;
2668 TALLOC_FREE(frame);
2669 TALLOC_FREE(talloced);
2670 goto out;
2673 status = check_name(conn, smb_fname->base_name);
2674 if (!NT_STATUS_IS_OK(status)) {
2675 TALLOC_FREE(dir_hnd);
2676 TALLOC_FREE(frame);
2677 TALLOC_FREE(talloced);
2678 goto out;
2681 status = do_unlink(conn, req, smb_fname, dirtype);
2682 if (!NT_STATUS_IS_OK(status)) {
2683 TALLOC_FREE(frame);
2684 TALLOC_FREE(talloced);
2685 continue;
2688 count++;
2689 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2690 smb_fname->base_name));
2692 TALLOC_FREE(frame);
2693 TALLOC_FREE(talloced);
2695 TALLOC_FREE(dir_hnd);
2698 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2699 status = map_nt_error_from_unix(errno);
2702 out:
2703 TALLOC_FREE(fname_dir);
2704 TALLOC_FREE(fname_mask);
2705 return status;
2708 /****************************************************************************
2709 Reply to a unlink
2710 ****************************************************************************/
2712 void reply_unlink(struct smb_request *req)
2714 connection_struct *conn = req->conn;
2715 char *name = NULL;
2716 struct smb_filename *smb_fname = NULL;
2717 uint32 dirtype;
2718 NTSTATUS status;
2719 bool path_contains_wcard = False;
2720 TALLOC_CTX *ctx = talloc_tos();
2722 START_PROFILE(SMBunlink);
2724 if (req->wct < 1) {
2725 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2726 goto out;
2729 dirtype = SVAL(req->vwv+0, 0);
2731 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2732 STR_TERMINATE, &status,
2733 &path_contains_wcard);
2734 if (!NT_STATUS_IS_OK(status)) {
2735 reply_nterror(req, status);
2736 goto out;
2739 status = filename_convert(ctx, conn,
2740 req->flags2 & FLAGS2_DFS_PATHNAMES,
2741 name,
2742 UCF_COND_ALLOW_WCARD_LCOMP,
2743 &path_contains_wcard,
2744 &smb_fname);
2745 if (!NT_STATUS_IS_OK(status)) {
2746 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2747 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2748 ERRSRV, ERRbadpath);
2749 goto out;
2751 reply_nterror(req, status);
2752 goto out;
2755 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2757 status = unlink_internals(conn, req, dirtype, smb_fname,
2758 path_contains_wcard);
2759 if (!NT_STATUS_IS_OK(status)) {
2760 if (open_was_deferred(req->mid)) {
2761 /* We have re-scheduled this call. */
2762 goto out;
2764 reply_nterror(req, status);
2765 goto out;
2768 reply_outbuf(req, 0, 0);
2769 out:
2770 TALLOC_FREE(smb_fname);
2771 END_PROFILE(SMBunlink);
2772 return;
2775 /****************************************************************************
2776 Fail for readbraw.
2777 ****************************************************************************/
2779 static void fail_readraw(void)
2781 const char *errstr = talloc_asprintf(talloc_tos(),
2782 "FAIL ! reply_readbraw: socket write fail (%s)",
2783 strerror(errno));
2784 if (!errstr) {
2785 errstr = "";
2787 exit_server_cleanly(errstr);
2790 /****************************************************************************
2791 Fake (read/write) sendfile. Returns -1 on read or write fail.
2792 ****************************************************************************/
2794 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
2795 size_t nread)
2797 size_t bufsize;
2798 size_t tosend = nread;
2799 char *buf;
2801 if (nread == 0) {
2802 return 0;
2805 bufsize = MIN(nread, 65536);
2807 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2808 return -1;
2811 while (tosend > 0) {
2812 ssize_t ret;
2813 size_t cur_read;
2815 if (tosend > bufsize) {
2816 cur_read = bufsize;
2817 } else {
2818 cur_read = tosend;
2820 ret = read_file(fsp,buf,startpos,cur_read);
2821 if (ret == -1) {
2822 SAFE_FREE(buf);
2823 return -1;
2826 /* If we had a short read, fill with zeros. */
2827 if (ret < cur_read) {
2828 memset(buf + ret, '\0', cur_read - ret);
2831 if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
2832 SAFE_FREE(buf);
2833 return -1;
2835 tosend -= cur_read;
2836 startpos += cur_read;
2839 SAFE_FREE(buf);
2840 return (ssize_t)nread;
2843 #if defined(WITH_SENDFILE)
2844 /****************************************************************************
2845 Deal with the case of sendfile reading less bytes from the file than
2846 requested. Fill with zeros (all we can do).
2847 ****************************************************************************/
2849 static void sendfile_short_send(files_struct *fsp,
2850 ssize_t nread,
2851 size_t headersize,
2852 size_t smb_maxcnt)
2854 #define SHORT_SEND_BUFSIZE 1024
2855 if (nread < headersize) {
2856 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2857 "header for file %s (%s). Terminating\n",
2858 fsp_str_dbg(fsp), strerror(errno)));
2859 exit_server_cleanly("sendfile_short_send failed");
2862 nread -= headersize;
2864 if (nread < smb_maxcnt) {
2865 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2866 if (!buf) {
2867 exit_server_cleanly("sendfile_short_send: "
2868 "malloc failed");
2871 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2872 "with zeros !\n", fsp_str_dbg(fsp)));
2874 while (nread < smb_maxcnt) {
2876 * We asked for the real file size and told sendfile
2877 * to not go beyond the end of the file. But it can
2878 * happen that in between our fstat call and the
2879 * sendfile call the file was truncated. This is very
2880 * bad because we have already announced the larger
2881 * number of bytes to the client.
2883 * The best we can do now is to send 0-bytes, just as
2884 * a read from a hole in a sparse file would do.
2886 * This should happen rarely enough that I don't care
2887 * about efficiency here :-)
2889 size_t to_write;
2891 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2892 if (write_data(smbd_server_fd(), buf, to_write) != to_write) {
2893 exit_server_cleanly("sendfile_short_send: "
2894 "write_data failed");
2896 nread += to_write;
2898 SAFE_FREE(buf);
2901 #endif /* defined WITH_SENDFILE */
2903 /****************************************************************************
2904 Return a readbraw error (4 bytes of zero).
2905 ****************************************************************************/
2907 static void reply_readbraw_error(void)
2909 char header[4];
2910 SIVAL(header,0,0);
2911 if (write_data(smbd_server_fd(),header,4) != 4) {
2912 fail_readraw();
2916 /****************************************************************************
2917 Use sendfile in readbraw.
2918 ****************************************************************************/
2920 static void send_file_readbraw(connection_struct *conn,
2921 struct smb_request *req,
2922 files_struct *fsp,
2923 SMB_OFF_T startpos,
2924 size_t nread,
2925 ssize_t mincount)
2927 char *outbuf = NULL;
2928 ssize_t ret=0;
2930 #if defined(WITH_SENDFILE)
2932 * We can only use sendfile on a non-chained packet
2933 * but we can use on a non-oplocked file. tridge proved this
2934 * on a train in Germany :-). JRA.
2935 * reply_readbraw has already checked the length.
2938 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
2939 (fsp->wcp == NULL) &&
2940 lp_use_sendfile(SNUM(conn), smbd_server_conn->smb1.signing_state) ) {
2941 ssize_t sendfile_read = -1;
2942 char header[4];
2943 DATA_BLOB header_blob;
2945 _smb_setlen(header,nread);
2946 header_blob = data_blob_const(header, 4);
2948 if ((sendfile_read = SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
2949 &header_blob, startpos, nread)) == -1) {
2950 /* Returning ENOSYS means no data at all was sent.
2951 * Do this as a normal read. */
2952 if (errno == ENOSYS) {
2953 goto normal_readbraw;
2957 * Special hack for broken Linux with no working sendfile. If we
2958 * return EINTR we sent the header but not the rest of the data.
2959 * Fake this up by doing read/write calls.
2961 if (errno == EINTR) {
2962 /* Ensure we don't do this again. */
2963 set_use_sendfile(SNUM(conn), False);
2964 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2966 if (fake_sendfile(fsp, startpos, nread) == -1) {
2967 DEBUG(0,("send_file_readbraw: "
2968 "fake_sendfile failed for "
2969 "file %s (%s).\n",
2970 fsp_str_dbg(fsp),
2971 strerror(errno)));
2972 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2974 return;
2977 DEBUG(0,("send_file_readbraw: sendfile failed for "
2978 "file %s (%s). Terminating\n",
2979 fsp_str_dbg(fsp), strerror(errno)));
2980 exit_server_cleanly("send_file_readbraw sendfile failed");
2981 } else if (sendfile_read == 0) {
2983 * Some sendfile implementations return 0 to indicate
2984 * that there was a short read, but nothing was
2985 * actually written to the socket. In this case,
2986 * fallback to the normal read path so the header gets
2987 * the correct byte count.
2989 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
2990 "bytes falling back to the normal read: "
2991 "%s\n", fsp_str_dbg(fsp)));
2992 goto normal_readbraw;
2995 /* Deal with possible short send. */
2996 if (sendfile_read != 4+nread) {
2997 sendfile_short_send(fsp, sendfile_read, 4, nread);
2999 return;
3002 normal_readbraw:
3003 #endif
3005 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
3006 if (!outbuf) {
3007 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
3008 (unsigned)(nread+4)));
3009 reply_readbraw_error();
3010 return;
3013 if (nread > 0) {
3014 ret = read_file(fsp,outbuf+4,startpos,nread);
3015 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3016 if (ret < mincount)
3017 ret = 0;
3018 #else
3019 if (ret < nread)
3020 ret = 0;
3021 #endif
3024 _smb_setlen(outbuf,ret);
3025 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
3026 fail_readraw();
3028 TALLOC_FREE(outbuf);
3031 /****************************************************************************
3032 Reply to a readbraw (core+ protocol).
3033 ****************************************************************************/
3035 void reply_readbraw(struct smb_request *req)
3037 connection_struct *conn = req->conn;
3038 ssize_t maxcount,mincount;
3039 size_t nread = 0;
3040 SMB_OFF_T startpos;
3041 files_struct *fsp;
3042 struct lock_struct lock;
3043 SMB_OFF_T size = 0;
3045 START_PROFILE(SMBreadbraw);
3047 if (srv_is_signing_active(smbd_server_conn) ||
3048 is_encrypted_packet(req->inbuf)) {
3049 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3050 "raw reads/writes are disallowed.");
3053 if (req->wct < 8) {
3054 reply_readbraw_error();
3055 END_PROFILE(SMBreadbraw);
3056 return;
3060 * Special check if an oplock break has been issued
3061 * and the readraw request croses on the wire, we must
3062 * return a zero length response here.
3065 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3068 * We have to do a check_fsp by hand here, as
3069 * we must always return 4 zero bytes on error,
3070 * not a NTSTATUS.
3073 if (!fsp || !conn || conn != fsp->conn ||
3074 req->vuid != fsp->vuid ||
3075 fsp->is_directory || fsp->fh->fd == -1) {
3077 * fsp could be NULL here so use the value from the packet. JRA.
3079 DEBUG(3,("reply_readbraw: fnum %d not valid "
3080 "- cache prime?\n",
3081 (int)SVAL(req->vwv+0, 0)));
3082 reply_readbraw_error();
3083 END_PROFILE(SMBreadbraw);
3084 return;
3087 /* Do a "by hand" version of CHECK_READ. */
3088 if (!(fsp->can_read ||
3089 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3090 (fsp->access_mask & FILE_EXECUTE)))) {
3091 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3092 (int)SVAL(req->vwv+0, 0)));
3093 reply_readbraw_error();
3094 END_PROFILE(SMBreadbraw);
3095 return;
3098 flush_write_cache(fsp, READRAW_FLUSH);
3100 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3101 if(req->wct == 10) {
3103 * This is a large offset (64 bit) read.
3105 #ifdef LARGE_SMB_OFF_T
3107 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3109 #else /* !LARGE_SMB_OFF_T */
3112 * Ensure we haven't been sent a >32 bit offset.
3115 if(IVAL(req->vwv+8, 0) != 0) {
3116 DEBUG(0,("reply_readbraw: large offset "
3117 "(%x << 32) used and we don't support "
3118 "64 bit offsets.\n",
3119 (unsigned int)IVAL(req->vwv+8, 0) ));
3120 reply_readbraw_error();
3121 END_PROFILE(SMBreadbraw);
3122 return;
3125 #endif /* LARGE_SMB_OFF_T */
3127 if(startpos < 0) {
3128 DEBUG(0,("reply_readbraw: negative 64 bit "
3129 "readraw offset (%.0f) !\n",
3130 (double)startpos ));
3131 reply_readbraw_error();
3132 END_PROFILE(SMBreadbraw);
3133 return;
3137 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3138 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3140 /* ensure we don't overrun the packet size */
3141 maxcount = MIN(65535,maxcount);
3143 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3144 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3145 &lock);
3147 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3148 reply_readbraw_error();
3149 END_PROFILE(SMBreadbraw);
3150 return;
3153 if (fsp_stat(fsp) == 0) {
3154 size = fsp->fsp_name->st.st_ex_size;
3157 if (startpos >= size) {
3158 nread = 0;
3159 } else {
3160 nread = MIN(maxcount,(size - startpos));
3163 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3164 if (nread < mincount)
3165 nread = 0;
3166 #endif
3168 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3169 "min=%lu nread=%lu\n",
3170 fsp->fnum, (double)startpos,
3171 (unsigned long)maxcount,
3172 (unsigned long)mincount,
3173 (unsigned long)nread ) );
3175 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3177 DEBUG(5,("reply_readbraw finished\n"));
3179 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3181 END_PROFILE(SMBreadbraw);
3182 return;
3185 #undef DBGC_CLASS
3186 #define DBGC_CLASS DBGC_LOCKING
3188 /****************************************************************************
3189 Reply to a lockread (core+ protocol).
3190 ****************************************************************************/
3192 void reply_lockread(struct smb_request *req)
3194 connection_struct *conn = req->conn;
3195 ssize_t nread = -1;
3196 char *data;
3197 SMB_OFF_T startpos;
3198 size_t numtoread;
3199 NTSTATUS status;
3200 files_struct *fsp;
3201 struct byte_range_lock *br_lck = NULL;
3202 char *p = NULL;
3203 struct smbd_server_connection *sconn = smbd_server_conn;
3205 START_PROFILE(SMBlockread);
3207 if (req->wct < 5) {
3208 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3209 END_PROFILE(SMBlockread);
3210 return;
3213 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3215 if (!check_fsp(conn, req, fsp)) {
3216 END_PROFILE(SMBlockread);
3217 return;
3220 if (!CHECK_READ(fsp,req)) {
3221 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3222 END_PROFILE(SMBlockread);
3223 return;
3226 numtoread = SVAL(req->vwv+1, 0);
3227 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3229 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3231 reply_outbuf(req, 5, numtoread + 3);
3233 data = smb_buf(req->outbuf) + 3;
3236 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3237 * protocol request that predates the read/write lock concept.
3238 * Thus instead of asking for a read lock here we need to ask
3239 * for a write lock. JRA.
3240 * Note that the requested lock size is unaffected by max_recv.
3243 br_lck = do_lock(smbd_messaging_context(),
3244 fsp,
3245 req->smbpid,
3246 (uint64_t)numtoread,
3247 (uint64_t)startpos,
3248 WRITE_LOCK,
3249 WINDOWS_LOCK,
3250 False, /* Non-blocking lock. */
3251 &status,
3252 NULL,
3253 NULL);
3254 TALLOC_FREE(br_lck);
3256 if (NT_STATUS_V(status)) {
3257 reply_nterror(req, status);
3258 END_PROFILE(SMBlockread);
3259 return;
3263 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3266 if (numtoread > sconn->smb1.negprot.max_recv) {
3267 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3268 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3269 (unsigned int)numtoread,
3270 (unsigned int)sconn->smb1.negprot.max_recv));
3271 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3273 nread = read_file(fsp,data,startpos,numtoread);
3275 if (nread < 0) {
3276 reply_nterror(req, map_nt_error_from_unix(errno));
3277 END_PROFILE(SMBlockread);
3278 return;
3281 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3283 SSVAL(req->outbuf,smb_vwv0,nread);
3284 SSVAL(req->outbuf,smb_vwv5,nread+3);
3285 p = smb_buf(req->outbuf);
3286 SCVAL(p,0,0); /* pad byte. */
3287 SSVAL(p,1,nread);
3289 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3290 fsp->fnum, (int)numtoread, (int)nread));
3292 END_PROFILE(SMBlockread);
3293 return;
3296 #undef DBGC_CLASS
3297 #define DBGC_CLASS DBGC_ALL
3299 /****************************************************************************
3300 Reply to a read.
3301 ****************************************************************************/
3303 void reply_read(struct smb_request *req)
3305 connection_struct *conn = req->conn;
3306 size_t numtoread;
3307 ssize_t nread = 0;
3308 char *data;
3309 SMB_OFF_T startpos;
3310 int outsize = 0;
3311 files_struct *fsp;
3312 struct lock_struct lock;
3313 struct smbd_server_connection *sconn = smbd_server_conn;
3315 START_PROFILE(SMBread);
3317 if (req->wct < 3) {
3318 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3319 END_PROFILE(SMBread);
3320 return;
3323 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3325 if (!check_fsp(conn, req, fsp)) {
3326 END_PROFILE(SMBread);
3327 return;
3330 if (!CHECK_READ(fsp,req)) {
3331 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3332 END_PROFILE(SMBread);
3333 return;
3336 numtoread = SVAL(req->vwv+1, 0);
3337 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3339 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3342 * The requested read size cannot be greater than max_recv. JRA.
3344 if (numtoread > sconn->smb1.negprot.max_recv) {
3345 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3346 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3347 (unsigned int)numtoread,
3348 (unsigned int)sconn->smb1.negprot.max_recv));
3349 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3352 reply_outbuf(req, 5, numtoread+3);
3354 data = smb_buf(req->outbuf) + 3;
3356 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3357 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3358 &lock);
3360 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3361 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3362 END_PROFILE(SMBread);
3363 return;
3366 if (numtoread > 0)
3367 nread = read_file(fsp,data,startpos,numtoread);
3369 if (nread < 0) {
3370 reply_nterror(req, map_nt_error_from_unix(errno));
3371 goto strict_unlock;
3374 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3376 SSVAL(req->outbuf,smb_vwv0,nread);
3377 SSVAL(req->outbuf,smb_vwv5,nread+3);
3378 SCVAL(smb_buf(req->outbuf),0,1);
3379 SSVAL(smb_buf(req->outbuf),1,nread);
3381 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3382 fsp->fnum, (int)numtoread, (int)nread ) );
3384 strict_unlock:
3385 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3387 END_PROFILE(SMBread);
3388 return;
3391 /****************************************************************************
3392 Setup readX header.
3393 ****************************************************************************/
3395 static int setup_readX_header(struct smb_request *req, char *outbuf,
3396 size_t smb_maxcnt)
3398 int outsize;
3399 char *data;
3401 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3402 data = smb_buf(outbuf);
3404 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3406 SCVAL(outbuf,smb_vwv0,0xFF);
3407 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3408 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3409 SSVAL(outbuf,smb_vwv6,
3410 req_wct_ofs(req)
3411 + 1 /* the wct field */
3412 + 12 * sizeof(uint16_t) /* vwv */
3413 + 2); /* the buflen field */
3414 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3415 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3416 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3417 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3418 return outsize;
3421 /****************************************************************************
3422 Reply to a read and X - possibly using sendfile.
3423 ****************************************************************************/
3425 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3426 files_struct *fsp, SMB_OFF_T startpos,
3427 size_t smb_maxcnt)
3429 ssize_t nread = -1;
3430 struct lock_struct lock;
3431 int saved_errno = 0;
3433 if(fsp_stat(fsp) == -1) {
3434 reply_nterror(req, map_nt_error_from_unix(errno));
3435 return;
3438 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3439 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3440 &lock);
3442 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3443 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3444 return;
3447 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3448 (startpos > fsp->fsp_name->st.st_ex_size)
3449 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3451 * We already know that we would do a short read, so don't
3452 * try the sendfile() path.
3454 goto nosendfile_read;
3457 #if defined(WITH_SENDFILE)
3459 * We can only use sendfile on a non-chained packet
3460 * but we can use on a non-oplocked file. tridge proved this
3461 * on a train in Germany :-). JRA.
3464 if (!req_is_in_chain(req) &&
3465 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3466 (fsp->wcp == NULL) &&
3467 lp_use_sendfile(SNUM(conn), smbd_server_conn->smb1.signing_state) ) {
3468 uint8 headerbuf[smb_size + 12 * 2];
3469 DATA_BLOB header;
3472 * Set up the packet header before send. We
3473 * assume here the sendfile will work (get the
3474 * correct amount of data).
3477 header = data_blob_const(headerbuf, sizeof(headerbuf));
3479 construct_reply_common_req(req, (char *)headerbuf);
3480 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3482 if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
3483 /* Returning ENOSYS means no data at all was sent.
3484 Do this as a normal read. */
3485 if (errno == ENOSYS) {
3486 goto normal_read;
3490 * Special hack for broken Linux with no working sendfile. If we
3491 * return EINTR we sent the header but not the rest of the data.
3492 * Fake this up by doing read/write calls.
3495 if (errno == EINTR) {
3496 /* Ensure we don't do this again. */
3497 set_use_sendfile(SNUM(conn), False);
3498 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3499 nread = fake_sendfile(fsp, startpos,
3500 smb_maxcnt);
3501 if (nread == -1) {
3502 DEBUG(0,("send_file_readX: "
3503 "fake_sendfile failed for "
3504 "file %s (%s).\n",
3505 fsp_str_dbg(fsp),
3506 strerror(errno)));
3507 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3509 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3510 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3511 /* No outbuf here means successful sendfile. */
3512 goto strict_unlock;
3515 DEBUG(0,("send_file_readX: sendfile failed for file "
3516 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3517 strerror(errno)));
3518 exit_server_cleanly("send_file_readX sendfile failed");
3519 } else if (nread == 0) {
3521 * Some sendfile implementations return 0 to indicate
3522 * that there was a short read, but nothing was
3523 * actually written to the socket. In this case,
3524 * fallback to the normal read path so the header gets
3525 * the correct byte count.
3527 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3528 "falling back to the normal read: %s\n",
3529 fsp_str_dbg(fsp)));
3530 goto normal_read;
3533 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3534 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3536 /* Deal with possible short send. */
3537 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3538 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3540 /* No outbuf here means successful sendfile. */
3541 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3542 SMB_PERFCOUNT_END(&req->pcd);
3543 goto strict_unlock;
3546 normal_read:
3548 #endif
3550 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3551 uint8 headerbuf[smb_size + 2*12];
3553 construct_reply_common_req(req, (char *)headerbuf);
3554 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3556 /* Send out the header. */
3557 if (write_data(smbd_server_fd(), (char *)headerbuf,
3558 sizeof(headerbuf)) != sizeof(headerbuf)) {
3559 DEBUG(0,("send_file_readX: write_data failed for file "
3560 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3561 strerror(errno)));
3562 exit_server_cleanly("send_file_readX sendfile failed");
3564 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3565 if (nread == -1) {
3566 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3567 "file %s (%s).\n", fsp_str_dbg(fsp),
3568 strerror(errno)));
3569 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3571 goto strict_unlock;
3574 nosendfile_read:
3576 reply_outbuf(req, 12, smb_maxcnt);
3578 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3579 saved_errno = errno;
3581 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3583 if (nread < 0) {
3584 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3585 return;
3588 setup_readX_header(req, (char *)req->outbuf, nread);
3590 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3591 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3593 chain_reply(req);
3594 return;
3596 strict_unlock:
3597 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3598 TALLOC_FREE(req->outbuf);
3599 return;
3602 /****************************************************************************
3603 Reply to a read and X.
3604 ****************************************************************************/
3606 void reply_read_and_X(struct smb_request *req)
3608 connection_struct *conn = req->conn;
3609 files_struct *fsp;
3610 SMB_OFF_T startpos;
3611 size_t smb_maxcnt;
3612 bool big_readX = False;
3613 #if 0
3614 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3615 #endif
3617 START_PROFILE(SMBreadX);
3619 if ((req->wct != 10) && (req->wct != 12)) {
3620 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3621 return;
3624 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3625 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3626 smb_maxcnt = SVAL(req->vwv+5, 0);
3628 /* If it's an IPC, pass off the pipe handler. */
3629 if (IS_IPC(conn)) {
3630 reply_pipe_read_and_X(req);
3631 END_PROFILE(SMBreadX);
3632 return;
3635 if (!check_fsp(conn, req, fsp)) {
3636 END_PROFILE(SMBreadX);
3637 return;
3640 if (!CHECK_READ(fsp,req)) {
3641 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3642 END_PROFILE(SMBreadX);
3643 return;
3646 if (global_client_caps & CAP_LARGE_READX) {
3647 size_t upper_size = SVAL(req->vwv+7, 0);
3648 smb_maxcnt |= (upper_size<<16);
3649 if (upper_size > 1) {
3650 /* Can't do this on a chained packet. */
3651 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3652 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3653 END_PROFILE(SMBreadX);
3654 return;
3656 /* We currently don't do this on signed or sealed data. */
3657 if (srv_is_signing_active(smbd_server_conn) ||
3658 is_encrypted_packet(req->inbuf)) {
3659 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3660 END_PROFILE(SMBreadX);
3661 return;
3663 /* Is there room in the reply for this data ? */
3664 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3665 reply_nterror(req,
3666 NT_STATUS_INVALID_PARAMETER);
3667 END_PROFILE(SMBreadX);
3668 return;
3670 big_readX = True;
3674 if (req->wct == 12) {
3675 #ifdef LARGE_SMB_OFF_T
3677 * This is a large offset (64 bit) read.
3679 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3681 #else /* !LARGE_SMB_OFF_T */
3684 * Ensure we haven't been sent a >32 bit offset.
3687 if(IVAL(req->vwv+10, 0) != 0) {
3688 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3689 "used and we don't support 64 bit offsets.\n",
3690 (unsigned int)IVAL(req->vwv+10, 0) ));
3691 END_PROFILE(SMBreadX);
3692 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3693 return;
3696 #endif /* LARGE_SMB_OFF_T */
3700 if (!big_readX &&
3701 schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
3702 goto out;
3705 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3707 out:
3708 END_PROFILE(SMBreadX);
3709 return;
3712 /****************************************************************************
3713 Error replies to writebraw must have smb_wct == 1. Fix this up.
3714 ****************************************************************************/
3716 void error_to_writebrawerr(struct smb_request *req)
3718 uint8 *old_outbuf = req->outbuf;
3720 reply_outbuf(req, 1, 0);
3722 memcpy(req->outbuf, old_outbuf, smb_size);
3723 TALLOC_FREE(old_outbuf);
3726 /****************************************************************************
3727 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3728 ****************************************************************************/
3730 void reply_writebraw(struct smb_request *req)
3732 connection_struct *conn = req->conn;
3733 char *buf = NULL;
3734 ssize_t nwritten=0;
3735 ssize_t total_written=0;
3736 size_t numtowrite=0;
3737 size_t tcount;
3738 SMB_OFF_T startpos;
3739 char *data=NULL;
3740 bool write_through;
3741 files_struct *fsp;
3742 struct lock_struct lock;
3743 NTSTATUS status;
3745 START_PROFILE(SMBwritebraw);
3748 * If we ever reply with an error, it must have the SMB command
3749 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3750 * we're finished.
3752 SCVAL(req->inbuf,smb_com,SMBwritec);
3754 if (srv_is_signing_active(smbd_server_conn)) {
3755 END_PROFILE(SMBwritebraw);
3756 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3757 "raw reads/writes are disallowed.");
3760 if (req->wct < 12) {
3761 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3762 error_to_writebrawerr(req);
3763 END_PROFILE(SMBwritebraw);
3764 return;
3767 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3768 if (!check_fsp(conn, req, fsp)) {
3769 error_to_writebrawerr(req);
3770 END_PROFILE(SMBwritebraw);
3771 return;
3774 if (!CHECK_WRITE(fsp)) {
3775 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3776 error_to_writebrawerr(req);
3777 END_PROFILE(SMBwritebraw);
3778 return;
3781 tcount = IVAL(req->vwv+1, 0);
3782 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3783 write_through = BITSETW(req->vwv+7,0);
3785 /* We have to deal with slightly different formats depending
3786 on whether we are using the core+ or lanman1.0 protocol */
3788 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3789 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3790 data = smb_buf(req->inbuf);
3791 } else {
3792 numtowrite = SVAL(req->vwv+10, 0);
3793 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3796 /* Ensure we don't write bytes past the end of this packet. */
3797 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3798 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3799 error_to_writebrawerr(req);
3800 END_PROFILE(SMBwritebraw);
3801 return;
3804 init_strict_lock_struct(fsp, (uint32)req->smbpid,
3805 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3806 &lock);
3808 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3809 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3810 error_to_writebrawerr(req);
3811 END_PROFILE(SMBwritebraw);
3812 return;
3815 if (numtowrite>0) {
3816 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3819 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3820 "wrote=%d sync=%d\n",
3821 fsp->fnum, (double)startpos, (int)numtowrite,
3822 (int)nwritten, (int)write_through));
3824 if (nwritten < (ssize_t)numtowrite) {
3825 reply_nterror(req, NT_STATUS_DISK_FULL);
3826 error_to_writebrawerr(req);
3827 goto strict_unlock;
3830 total_written = nwritten;
3832 /* Allocate a buffer of 64k + length. */
3833 buf = TALLOC_ARRAY(NULL, char, 65540);
3834 if (!buf) {
3835 reply_nterror(req, NT_STATUS_NO_MEMORY);
3836 error_to_writebrawerr(req);
3837 goto strict_unlock;
3840 /* Return a SMBwritebraw message to the redirector to tell
3841 * it to send more bytes */
3843 memcpy(buf, req->inbuf, smb_size);
3844 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
3845 SCVAL(buf,smb_com,SMBwritebraw);
3846 SSVALS(buf,smb_vwv0,0xFFFF);
3847 show_msg(buf);
3848 if (!srv_send_smb(smbd_server_fd(),
3849 buf,
3850 false, 0, /* no signing */
3851 IS_CONN_ENCRYPTED(conn),
3852 &req->pcd)) {
3853 exit_server_cleanly("reply_writebraw: srv_send_smb "
3854 "failed.");
3857 /* Now read the raw data into the buffer and write it */
3858 status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
3859 &numtowrite);
3860 if (!NT_STATUS_IS_OK(status)) {
3861 exit_server_cleanly("secondary writebraw failed");
3864 /* Set up outbuf to return the correct size */
3865 reply_outbuf(req, 1, 0);
3867 if (numtowrite != 0) {
3869 if (numtowrite > 0xFFFF) {
3870 DEBUG(0,("reply_writebraw: Oversize secondary write "
3871 "raw requested (%u). Terminating\n",
3872 (unsigned int)numtowrite ));
3873 exit_server_cleanly("secondary writebraw failed");
3876 if (tcount > nwritten+numtowrite) {
3877 DEBUG(3,("reply_writebraw: Client overestimated the "
3878 "write %d %d %d\n",
3879 (int)tcount,(int)nwritten,(int)numtowrite));
3882 status = read_data(smbd_server_fd(), buf+4, numtowrite);
3884 if (!NT_STATUS_IS_OK(status)) {
3885 DEBUG(0,("reply_writebraw: Oversize secondary write "
3886 "raw read failed (%s). Terminating\n",
3887 nt_errstr(status)));
3888 exit_server_cleanly("secondary writebraw failed");
3891 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
3892 if (nwritten == -1) {
3893 TALLOC_FREE(buf);
3894 reply_nterror(req, map_nt_error_from_unix(errno));
3895 error_to_writebrawerr(req);
3896 goto strict_unlock;
3899 if (nwritten < (ssize_t)numtowrite) {
3900 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3901 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3904 if (nwritten > 0) {
3905 total_written += nwritten;
3909 TALLOC_FREE(buf);
3910 SSVAL(req->outbuf,smb_vwv0,total_written);
3912 status = sync_file(conn, fsp, write_through);
3913 if (!NT_STATUS_IS_OK(status)) {
3914 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
3915 fsp_str_dbg(fsp), nt_errstr(status)));
3916 reply_nterror(req, status);
3917 error_to_writebrawerr(req);
3918 goto strict_unlock;
3921 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
3922 "wrote=%d\n",
3923 fsp->fnum, (double)startpos, (int)numtowrite,
3924 (int)total_written));
3926 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3928 /* We won't return a status if write through is not selected - this
3929 * follows what WfWg does */
3930 END_PROFILE(SMBwritebraw);
3932 if (!write_through && total_written==tcount) {
3934 #if RABBIT_PELLET_FIX
3936 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
3937 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
3938 * JRA.
3940 if (!send_keepalive(smbd_server_fd())) {
3941 exit_server_cleanly("reply_writebraw: send of "
3942 "keepalive failed");
3944 #endif
3945 TALLOC_FREE(req->outbuf);
3947 return;
3949 strict_unlock:
3950 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3952 END_PROFILE(SMBwritebraw);
3953 return;
3956 #undef DBGC_CLASS
3957 #define DBGC_CLASS DBGC_LOCKING
3959 /****************************************************************************
3960 Reply to a writeunlock (core+).
3961 ****************************************************************************/
3963 void reply_writeunlock(struct smb_request *req)
3965 connection_struct *conn = req->conn;
3966 ssize_t nwritten = -1;
3967 size_t numtowrite;
3968 SMB_OFF_T startpos;
3969 const char *data;
3970 NTSTATUS status = NT_STATUS_OK;
3971 files_struct *fsp;
3972 struct lock_struct lock;
3973 int saved_errno = 0;
3975 START_PROFILE(SMBwriteunlock);
3977 if (req->wct < 5) {
3978 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3979 END_PROFILE(SMBwriteunlock);
3980 return;
3983 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3985 if (!check_fsp(conn, req, fsp)) {
3986 END_PROFILE(SMBwriteunlock);
3987 return;
3990 if (!CHECK_WRITE(fsp)) {
3991 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3992 END_PROFILE(SMBwriteunlock);
3993 return;
3996 numtowrite = SVAL(req->vwv+1, 0);
3997 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3998 data = (const char *)req->buf + 3;
4000 if (numtowrite) {
4001 init_strict_lock_struct(fsp, (uint32)req->smbpid,
4002 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4003 &lock);
4005 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4006 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4007 END_PROFILE(SMBwriteunlock);
4008 return;
4012 /* The special X/Open SMB protocol handling of
4013 zero length writes is *NOT* done for
4014 this call */
4015 if(numtowrite == 0) {
4016 nwritten = 0;
4017 } else {
4018 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4019 saved_errno = errno;
4022 status = sync_file(conn, fsp, False /* write through */);
4023 if (!NT_STATUS_IS_OK(status)) {
4024 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4025 fsp_str_dbg(fsp), nt_errstr(status)));
4026 reply_nterror(req, status);
4027 goto strict_unlock;
4030 if(nwritten < 0) {
4031 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4032 goto strict_unlock;
4035 if((nwritten < numtowrite) && (numtowrite != 0)) {
4036 reply_nterror(req, NT_STATUS_DISK_FULL);
4037 goto strict_unlock;
4040 if (numtowrite) {
4041 status = do_unlock(smbd_messaging_context(),
4042 fsp,
4043 req->smbpid,
4044 (uint64_t)numtowrite,
4045 (uint64_t)startpos,
4046 WINDOWS_LOCK);
4048 if (NT_STATUS_V(status)) {
4049 reply_nterror(req, status);
4050 goto strict_unlock;
4054 reply_outbuf(req, 1, 0);
4056 SSVAL(req->outbuf,smb_vwv0,nwritten);
4058 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4059 fsp->fnum, (int)numtowrite, (int)nwritten));
4061 strict_unlock:
4062 if (numtowrite) {
4063 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4066 END_PROFILE(SMBwriteunlock);
4067 return;
4070 #undef DBGC_CLASS
4071 #define DBGC_CLASS DBGC_ALL
4073 /****************************************************************************
4074 Reply to a write.
4075 ****************************************************************************/
4077 void reply_write(struct smb_request *req)
4079 connection_struct *conn = req->conn;
4080 size_t numtowrite;
4081 ssize_t nwritten = -1;
4082 SMB_OFF_T startpos;
4083 const char *data;
4084 files_struct *fsp;
4085 struct lock_struct lock;
4086 NTSTATUS status;
4087 int saved_errno = 0;
4089 START_PROFILE(SMBwrite);
4091 if (req->wct < 5) {
4092 END_PROFILE(SMBwrite);
4093 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4094 return;
4097 /* If it's an IPC, pass off the pipe handler. */
4098 if (IS_IPC(conn)) {
4099 reply_pipe_write(req);
4100 END_PROFILE(SMBwrite);
4101 return;
4104 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4106 if (!check_fsp(conn, req, fsp)) {
4107 END_PROFILE(SMBwrite);
4108 return;
4111 if (!CHECK_WRITE(fsp)) {
4112 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4113 END_PROFILE(SMBwrite);
4114 return;
4117 numtowrite = SVAL(req->vwv+1, 0);
4118 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4119 data = (const char *)req->buf + 3;
4121 init_strict_lock_struct(fsp, (uint32)req->smbpid,
4122 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4123 &lock);
4125 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4126 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4127 END_PROFILE(SMBwrite);
4128 return;
4132 * X/Open SMB protocol says that if smb_vwv1 is
4133 * zero then the file size should be extended or
4134 * truncated to the size given in smb_vwv[2-3].
4137 if(numtowrite == 0) {
4139 * This is actually an allocate call, and set EOF. JRA.
4141 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4142 if (nwritten < 0) {
4143 reply_nterror(req, NT_STATUS_DISK_FULL);
4144 goto strict_unlock;
4146 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4147 if (nwritten < 0) {
4148 reply_nterror(req, NT_STATUS_DISK_FULL);
4149 goto strict_unlock;
4151 trigger_write_time_update_immediate(fsp);
4152 } else {
4153 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4156 status = sync_file(conn, fsp, False);
4157 if (!NT_STATUS_IS_OK(status)) {
4158 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4159 fsp_str_dbg(fsp), nt_errstr(status)));
4160 reply_nterror(req, status);
4161 goto strict_unlock;
4164 if(nwritten < 0) {
4165 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4166 goto strict_unlock;
4169 if((nwritten == 0) && (numtowrite != 0)) {
4170 reply_nterror(req, NT_STATUS_DISK_FULL);
4171 goto strict_unlock;
4174 reply_outbuf(req, 1, 0);
4176 SSVAL(req->outbuf,smb_vwv0,nwritten);
4178 if (nwritten < (ssize_t)numtowrite) {
4179 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4180 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4183 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4185 strict_unlock:
4186 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4188 END_PROFILE(SMBwrite);
4189 return;
4192 /****************************************************************************
4193 Ensure a buffer is a valid writeX for recvfile purposes.
4194 ****************************************************************************/
4196 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4197 (2*14) + /* word count (including bcc) */ \
4198 1 /* pad byte */)
4200 bool is_valid_writeX_buffer(const uint8_t *inbuf)
4202 size_t numtowrite;
4203 connection_struct *conn = NULL;
4204 unsigned int doff = 0;
4205 size_t len = smb_len_large(inbuf);
4206 struct smbd_server_connection *sconn = smbd_server_conn;
4208 if (is_encrypted_packet(inbuf)) {
4209 /* Can't do this on encrypted
4210 * connections. */
4211 return false;
4214 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4215 return false;
4218 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4219 CVAL(inbuf,smb_wct) != 14) {
4220 DEBUG(10,("is_valid_writeX_buffer: chained or "
4221 "invalid word length.\n"));
4222 return false;
4225 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4226 if (conn == NULL) {
4227 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4228 return false;
4230 if (IS_IPC(conn)) {
4231 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4232 return false;
4234 if (IS_PRINT(conn)) {
4235 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4236 return false;
4238 doff = SVAL(inbuf,smb_vwv11);
4240 numtowrite = SVAL(inbuf,smb_vwv10);
4242 if (len > doff && len - doff > 0xFFFF) {
4243 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4246 if (numtowrite == 0) {
4247 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4248 return false;
4251 /* Ensure the sizes match up. */
4252 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4253 /* no pad byte...old smbclient :-( */
4254 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4255 (unsigned int)doff,
4256 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4257 return false;
4260 if (len - doff != numtowrite) {
4261 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4262 "len = %u, doff = %u, numtowrite = %u\n",
4263 (unsigned int)len,
4264 (unsigned int)doff,
4265 (unsigned int)numtowrite ));
4266 return false;
4269 DEBUG(10,("is_valid_writeX_buffer: true "
4270 "len = %u, doff = %u, numtowrite = %u\n",
4271 (unsigned int)len,
4272 (unsigned int)doff,
4273 (unsigned int)numtowrite ));
4275 return true;
4278 /****************************************************************************
4279 Reply to a write and X.
4280 ****************************************************************************/
4282 void reply_write_and_X(struct smb_request *req)
4284 connection_struct *conn = req->conn;
4285 files_struct *fsp;
4286 struct lock_struct lock;
4287 SMB_OFF_T startpos;
4288 size_t numtowrite;
4289 bool write_through;
4290 ssize_t nwritten;
4291 unsigned int smb_doff;
4292 unsigned int smblen;
4293 char *data;
4294 NTSTATUS status;
4296 START_PROFILE(SMBwriteX);
4298 if ((req->wct != 12) && (req->wct != 14)) {
4299 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4300 END_PROFILE(SMBwriteX);
4301 return;
4304 numtowrite = SVAL(req->vwv+10, 0);
4305 smb_doff = SVAL(req->vwv+11, 0);
4306 smblen = smb_len(req->inbuf);
4308 if (req->unread_bytes > 0xFFFF ||
4309 (smblen > smb_doff &&
4310 smblen - smb_doff > 0xFFFF)) {
4311 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4314 if (req->unread_bytes) {
4315 /* Can't do a recvfile write on IPC$ */
4316 if (IS_IPC(conn)) {
4317 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4318 END_PROFILE(SMBwriteX);
4319 return;
4321 if (numtowrite != req->unread_bytes) {
4322 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4323 END_PROFILE(SMBwriteX);
4324 return;
4326 } else {
4327 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4328 smb_doff + numtowrite > smblen) {
4329 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4330 END_PROFILE(SMBwriteX);
4331 return;
4335 /* If it's an IPC, pass off the pipe handler. */
4336 if (IS_IPC(conn)) {
4337 if (req->unread_bytes) {
4338 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4339 END_PROFILE(SMBwriteX);
4340 return;
4342 reply_pipe_write_and_X(req);
4343 END_PROFILE(SMBwriteX);
4344 return;
4347 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4348 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4349 write_through = BITSETW(req->vwv+7,0);
4351 if (!check_fsp(conn, req, fsp)) {
4352 END_PROFILE(SMBwriteX);
4353 return;
4356 if (!CHECK_WRITE(fsp)) {
4357 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4358 END_PROFILE(SMBwriteX);
4359 return;
4362 data = smb_base(req->inbuf) + smb_doff;
4364 if(req->wct == 14) {
4365 #ifdef LARGE_SMB_OFF_T
4367 * This is a large offset (64 bit) write.
4369 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4371 #else /* !LARGE_SMB_OFF_T */
4374 * Ensure we haven't been sent a >32 bit offset.
4377 if(IVAL(req->vwv+12, 0) != 0) {
4378 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4379 "used and we don't support 64 bit offsets.\n",
4380 (unsigned int)IVAL(req->vwv+12, 0) ));
4381 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4382 END_PROFILE(SMBwriteX);
4383 return;
4386 #endif /* LARGE_SMB_OFF_T */
4389 init_strict_lock_struct(fsp, (uint32)req->smbpid,
4390 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4391 &lock);
4393 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4394 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4395 END_PROFILE(SMBwriteX);
4396 return;
4399 /* X/Open SMB protocol says that, unlike SMBwrite
4400 if the length is zero then NO truncation is
4401 done, just a write of zero. To truncate a file,
4402 use SMBwrite. */
4404 if(numtowrite == 0) {
4405 nwritten = 0;
4406 } else {
4408 if ((req->unread_bytes == 0) &&
4409 schedule_aio_write_and_X(conn, req, fsp, data, startpos,
4410 numtowrite)) {
4411 goto strict_unlock;
4414 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4417 if(nwritten < 0) {
4418 reply_nterror(req, map_nt_error_from_unix(errno));
4419 goto strict_unlock;
4422 if((nwritten == 0) && (numtowrite != 0)) {
4423 reply_nterror(req, NT_STATUS_DISK_FULL);
4424 goto strict_unlock;
4427 reply_outbuf(req, 6, 0);
4428 SSVAL(req->outbuf,smb_vwv2,nwritten);
4429 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4431 if (nwritten < (ssize_t)numtowrite) {
4432 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4433 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4436 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4437 fsp->fnum, (int)numtowrite, (int)nwritten));
4439 status = sync_file(conn, fsp, write_through);
4440 if (!NT_STATUS_IS_OK(status)) {
4441 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4442 fsp_str_dbg(fsp), nt_errstr(status)));
4443 reply_nterror(req, status);
4444 goto strict_unlock;
4447 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4449 END_PROFILE(SMBwriteX);
4450 chain_reply(req);
4451 return;
4453 strict_unlock:
4454 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4456 END_PROFILE(SMBwriteX);
4457 return;
4460 /****************************************************************************
4461 Reply to a lseek.
4462 ****************************************************************************/
4464 void reply_lseek(struct smb_request *req)
4466 connection_struct *conn = req->conn;
4467 SMB_OFF_T startpos;
4468 SMB_OFF_T res= -1;
4469 int mode,umode;
4470 files_struct *fsp;
4472 START_PROFILE(SMBlseek);
4474 if (req->wct < 4) {
4475 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4476 END_PROFILE(SMBlseek);
4477 return;
4480 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4482 if (!check_fsp(conn, req, fsp)) {
4483 return;
4486 flush_write_cache(fsp, SEEK_FLUSH);
4488 mode = SVAL(req->vwv+1, 0) & 3;
4489 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4490 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4492 switch (mode) {
4493 case 0:
4494 umode = SEEK_SET;
4495 res = startpos;
4496 break;
4497 case 1:
4498 umode = SEEK_CUR;
4499 res = fsp->fh->pos + startpos;
4500 break;
4501 case 2:
4502 umode = SEEK_END;
4503 break;
4504 default:
4505 umode = SEEK_SET;
4506 res = startpos;
4507 break;
4510 if (umode == SEEK_END) {
4511 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4512 if(errno == EINVAL) {
4513 SMB_OFF_T current_pos = startpos;
4515 if(fsp_stat(fsp) == -1) {
4516 reply_nterror(req,
4517 map_nt_error_from_unix(errno));
4518 END_PROFILE(SMBlseek);
4519 return;
4522 current_pos += fsp->fsp_name->st.st_ex_size;
4523 if(current_pos < 0)
4524 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4528 if(res == -1) {
4529 reply_nterror(req, map_nt_error_from_unix(errno));
4530 END_PROFILE(SMBlseek);
4531 return;
4535 fsp->fh->pos = res;
4537 reply_outbuf(req, 2, 0);
4538 SIVAL(req->outbuf,smb_vwv0,res);
4540 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4541 fsp->fnum, (double)startpos, (double)res, mode));
4543 END_PROFILE(SMBlseek);
4544 return;
4547 /****************************************************************************
4548 Reply to a flush.
4549 ****************************************************************************/
4551 void reply_flush(struct smb_request *req)
4553 connection_struct *conn = req->conn;
4554 uint16 fnum;
4555 files_struct *fsp;
4557 START_PROFILE(SMBflush);
4559 if (req->wct < 1) {
4560 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4561 return;
4564 fnum = SVAL(req->vwv+0, 0);
4565 fsp = file_fsp(req, fnum);
4567 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4568 return;
4571 if (!fsp) {
4572 file_sync_all(conn);
4573 } else {
4574 NTSTATUS status = sync_file(conn, fsp, True);
4575 if (!NT_STATUS_IS_OK(status)) {
4576 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4577 fsp_str_dbg(fsp), nt_errstr(status)));
4578 reply_nterror(req, status);
4579 END_PROFILE(SMBflush);
4580 return;
4584 reply_outbuf(req, 0, 0);
4586 DEBUG(3,("flush\n"));
4587 END_PROFILE(SMBflush);
4588 return;
4591 /****************************************************************************
4592 Reply to a exit.
4593 conn POINTER CAN BE NULL HERE !
4594 ****************************************************************************/
4596 void reply_exit(struct smb_request *req)
4598 START_PROFILE(SMBexit);
4600 file_close_pid(req->smbpid, req->vuid);
4602 reply_outbuf(req, 0, 0);
4604 DEBUG(3,("exit\n"));
4606 END_PROFILE(SMBexit);
4607 return;
4610 /****************************************************************************
4611 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4612 ****************************************************************************/
4614 void reply_close(struct smb_request *req)
4616 connection_struct *conn = req->conn;
4617 NTSTATUS status = NT_STATUS_OK;
4618 files_struct *fsp = NULL;
4619 START_PROFILE(SMBclose);
4621 if (req->wct < 3) {
4622 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4623 END_PROFILE(SMBclose);
4624 return;
4627 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4630 * We can only use check_fsp if we know it's not a directory.
4633 if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
4634 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4635 END_PROFILE(SMBclose);
4636 return;
4639 if(fsp->is_directory) {
4641 * Special case - close NT SMB directory handle.
4643 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4644 status = close_file(req, fsp, NORMAL_CLOSE);
4645 } else {
4646 time_t t;
4648 * Close ordinary file.
4651 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4652 fsp->fh->fd, fsp->fnum,
4653 conn->num_files_open));
4656 * Take care of any time sent in the close.
4659 t = srv_make_unix_date3(req->vwv+1);
4660 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4663 * close_file() returns the unix errno if an error
4664 * was detected on close - normally this is due to
4665 * a disk full error. If not then it was probably an I/O error.
4668 status = close_file(req, fsp, NORMAL_CLOSE);
4671 if (!NT_STATUS_IS_OK(status)) {
4672 reply_nterror(req, status);
4673 END_PROFILE(SMBclose);
4674 return;
4677 reply_outbuf(req, 0, 0);
4678 END_PROFILE(SMBclose);
4679 return;
4682 /****************************************************************************
4683 Reply to a writeclose (Core+ protocol).
4684 ****************************************************************************/
4686 void reply_writeclose(struct smb_request *req)
4688 connection_struct *conn = req->conn;
4689 size_t numtowrite;
4690 ssize_t nwritten = -1;
4691 NTSTATUS close_status = NT_STATUS_OK;
4692 SMB_OFF_T startpos;
4693 const char *data;
4694 struct timespec mtime;
4695 files_struct *fsp;
4696 struct lock_struct lock;
4698 START_PROFILE(SMBwriteclose);
4700 if (req->wct < 6) {
4701 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4702 END_PROFILE(SMBwriteclose);
4703 return;
4706 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4708 if (!check_fsp(conn, req, fsp)) {
4709 END_PROFILE(SMBwriteclose);
4710 return;
4712 if (!CHECK_WRITE(fsp)) {
4713 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4714 END_PROFILE(SMBwriteclose);
4715 return;
4718 numtowrite = SVAL(req->vwv+1, 0);
4719 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4720 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4721 data = (const char *)req->buf + 1;
4723 if (numtowrite) {
4724 init_strict_lock_struct(fsp, (uint32)req->smbpid,
4725 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4726 &lock);
4728 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4729 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4730 END_PROFILE(SMBwriteclose);
4731 return;
4735 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4737 set_close_write_time(fsp, mtime);
4740 * More insanity. W2K only closes the file if writelen > 0.
4741 * JRA.
4744 if (numtowrite) {
4745 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4746 "file %s\n", fsp_str_dbg(fsp)));
4747 close_status = close_file(req, fsp, NORMAL_CLOSE);
4750 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4751 fsp->fnum, (int)numtowrite, (int)nwritten,
4752 conn->num_files_open));
4754 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4755 reply_nterror(req, NT_STATUS_DISK_FULL);
4756 goto strict_unlock;
4759 if(!NT_STATUS_IS_OK(close_status)) {
4760 reply_nterror(req, close_status);
4761 goto strict_unlock;
4764 reply_outbuf(req, 1, 0);
4766 SSVAL(req->outbuf,smb_vwv0,nwritten);
4768 strict_unlock:
4769 if (numtowrite) {
4770 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4773 END_PROFILE(SMBwriteclose);
4774 return;
4777 #undef DBGC_CLASS
4778 #define DBGC_CLASS DBGC_LOCKING
4780 /****************************************************************************
4781 Reply to a lock.
4782 ****************************************************************************/
4784 void reply_lock(struct smb_request *req)
4786 connection_struct *conn = req->conn;
4787 uint64_t count,offset;
4788 NTSTATUS status;
4789 files_struct *fsp;
4790 struct byte_range_lock *br_lck = NULL;
4792 START_PROFILE(SMBlock);
4794 if (req->wct < 5) {
4795 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4796 END_PROFILE(SMBlock);
4797 return;
4800 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4802 if (!check_fsp(conn, req, fsp)) {
4803 END_PROFILE(SMBlock);
4804 return;
4807 count = (uint64_t)IVAL(req->vwv+1, 0);
4808 offset = (uint64_t)IVAL(req->vwv+3, 0);
4810 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4811 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4813 br_lck = do_lock(smbd_messaging_context(),
4814 fsp,
4815 req->smbpid,
4816 count,
4817 offset,
4818 WRITE_LOCK,
4819 WINDOWS_LOCK,
4820 False, /* Non-blocking lock. */
4821 &status,
4822 NULL,
4823 NULL);
4825 TALLOC_FREE(br_lck);
4827 if (NT_STATUS_V(status)) {
4828 reply_nterror(req, status);
4829 END_PROFILE(SMBlock);
4830 return;
4833 reply_outbuf(req, 0, 0);
4835 END_PROFILE(SMBlock);
4836 return;
4839 /****************************************************************************
4840 Reply to a unlock.
4841 ****************************************************************************/
4843 void reply_unlock(struct smb_request *req)
4845 connection_struct *conn = req->conn;
4846 uint64_t count,offset;
4847 NTSTATUS status;
4848 files_struct *fsp;
4850 START_PROFILE(SMBunlock);
4852 if (req->wct < 5) {
4853 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4854 END_PROFILE(SMBunlock);
4855 return;
4858 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4860 if (!check_fsp(conn, req, fsp)) {
4861 END_PROFILE(SMBunlock);
4862 return;
4865 count = (uint64_t)IVAL(req->vwv+1, 0);
4866 offset = (uint64_t)IVAL(req->vwv+3, 0);
4868 status = do_unlock(smbd_messaging_context(),
4869 fsp,
4870 req->smbpid,
4871 count,
4872 offset,
4873 WINDOWS_LOCK);
4875 if (NT_STATUS_V(status)) {
4876 reply_nterror(req, status);
4877 END_PROFILE(SMBunlock);
4878 return;
4881 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4882 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
4884 reply_outbuf(req, 0, 0);
4886 END_PROFILE(SMBunlock);
4887 return;
4890 #undef DBGC_CLASS
4891 #define DBGC_CLASS DBGC_ALL
4893 /****************************************************************************
4894 Reply to a tdis.
4895 conn POINTER CAN BE NULL HERE !
4896 ****************************************************************************/
4898 void reply_tdis(struct smb_request *req)
4900 connection_struct *conn = req->conn;
4901 START_PROFILE(SMBtdis);
4903 if (!conn) {
4904 DEBUG(4,("Invalid connection in tdis\n"));
4905 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
4906 END_PROFILE(SMBtdis);
4907 return;
4910 conn->used = False;
4912 close_cnum(conn,req->vuid);
4913 req->conn = NULL;
4915 reply_outbuf(req, 0, 0);
4916 END_PROFILE(SMBtdis);
4917 return;
4920 /****************************************************************************
4921 Reply to a echo.
4922 conn POINTER CAN BE NULL HERE !
4923 ****************************************************************************/
4925 void reply_echo(struct smb_request *req)
4927 connection_struct *conn = req->conn;
4928 struct smb_perfcount_data local_pcd;
4929 struct smb_perfcount_data *cur_pcd;
4930 int smb_reverb;
4931 int seq_num;
4933 START_PROFILE(SMBecho);
4935 smb_init_perfcount_data(&local_pcd);
4937 if (req->wct < 1) {
4938 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4939 END_PROFILE(SMBecho);
4940 return;
4943 smb_reverb = SVAL(req->vwv+0, 0);
4945 reply_outbuf(req, 1, req->buflen);
4947 /* copy any incoming data back out */
4948 if (req->buflen > 0) {
4949 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
4952 if (smb_reverb > 100) {
4953 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
4954 smb_reverb = 100;
4957 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
4959 /* this makes sure we catch the request pcd */
4960 if (seq_num == smb_reverb) {
4961 cur_pcd = &req->pcd;
4962 } else {
4963 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
4964 cur_pcd = &local_pcd;
4967 SSVAL(req->outbuf,smb_vwv0,seq_num);
4969 show_msg((char *)req->outbuf);
4970 if (!srv_send_smb(smbd_server_fd(),
4971 (char *)req->outbuf,
4972 true, req->seqnum+1,
4973 IS_CONN_ENCRYPTED(conn)||req->encrypted,
4974 cur_pcd))
4975 exit_server_cleanly("reply_echo: srv_send_smb failed.");
4978 DEBUG(3,("echo %d times\n", smb_reverb));
4980 TALLOC_FREE(req->outbuf);
4982 END_PROFILE(SMBecho);
4983 return;
4986 /****************************************************************************
4987 Reply to a printopen.
4988 ****************************************************************************/
4990 void reply_printopen(struct smb_request *req)
4992 connection_struct *conn = req->conn;
4993 files_struct *fsp;
4994 NTSTATUS status;
4996 START_PROFILE(SMBsplopen);
4998 if (req->wct < 2) {
4999 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5000 END_PROFILE(SMBsplopen);
5001 return;
5004 if (!CAN_PRINT(conn)) {
5005 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5006 END_PROFILE(SMBsplopen);
5007 return;
5010 status = file_new(req, conn, &fsp);
5011 if(!NT_STATUS_IS_OK(status)) {
5012 reply_nterror(req, status);
5013 END_PROFILE(SMBsplopen);
5014 return;
5017 /* Open for exclusive use, write only. */
5018 status = print_fsp_open(req, conn, NULL, req->vuid, fsp);
5020 if (!NT_STATUS_IS_OK(status)) {
5021 file_free(req, fsp);
5022 reply_nterror(req, status);
5023 END_PROFILE(SMBsplopen);
5024 return;
5027 reply_outbuf(req, 1, 0);
5028 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5030 DEBUG(3,("openprint fd=%d fnum=%d\n",
5031 fsp->fh->fd, fsp->fnum));
5033 END_PROFILE(SMBsplopen);
5034 return;
5037 /****************************************************************************
5038 Reply to a printclose.
5039 ****************************************************************************/
5041 void reply_printclose(struct smb_request *req)
5043 connection_struct *conn = req->conn;
5044 files_struct *fsp;
5045 NTSTATUS status;
5047 START_PROFILE(SMBsplclose);
5049 if (req->wct < 1) {
5050 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5051 END_PROFILE(SMBsplclose);
5052 return;
5055 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5057 if (!check_fsp(conn, req, fsp)) {
5058 END_PROFILE(SMBsplclose);
5059 return;
5062 if (!CAN_PRINT(conn)) {
5063 reply_force_doserror(req, ERRSRV, ERRerror);
5064 END_PROFILE(SMBsplclose);
5065 return;
5068 DEBUG(3,("printclose fd=%d fnum=%d\n",
5069 fsp->fh->fd,fsp->fnum));
5071 status = close_file(req, fsp, NORMAL_CLOSE);
5073 if(!NT_STATUS_IS_OK(status)) {
5074 reply_nterror(req, status);
5075 END_PROFILE(SMBsplclose);
5076 return;
5079 reply_outbuf(req, 0, 0);
5081 END_PROFILE(SMBsplclose);
5082 return;
5085 /****************************************************************************
5086 Reply to a printqueue.
5087 ****************************************************************************/
5089 void reply_printqueue(struct smb_request *req)
5091 connection_struct *conn = req->conn;
5092 int max_count;
5093 int start_index;
5095 START_PROFILE(SMBsplretq);
5097 if (req->wct < 2) {
5098 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5099 END_PROFILE(SMBsplretq);
5100 return;
5103 max_count = SVAL(req->vwv+0, 0);
5104 start_index = SVAL(req->vwv+1, 0);
5106 /* we used to allow the client to get the cnum wrong, but that
5107 is really quite gross and only worked when there was only
5108 one printer - I think we should now only accept it if they
5109 get it right (tridge) */
5110 if (!CAN_PRINT(conn)) {
5111 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5112 END_PROFILE(SMBsplretq);
5113 return;
5116 reply_outbuf(req, 2, 3);
5117 SSVAL(req->outbuf,smb_vwv0,0);
5118 SSVAL(req->outbuf,smb_vwv1,0);
5119 SCVAL(smb_buf(req->outbuf),0,1);
5120 SSVAL(smb_buf(req->outbuf),1,0);
5122 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5123 start_index, max_count));
5126 print_queue_struct *queue = NULL;
5127 print_status_struct status;
5128 int count = print_queue_status(SNUM(conn), &queue, &status);
5129 int num_to_get = ABS(max_count);
5130 int first = (max_count>0?start_index:start_index+max_count+1);
5131 int i;
5133 if (first >= count)
5134 num_to_get = 0;
5135 else
5136 num_to_get = MIN(num_to_get,count-first);
5139 for (i=first;i<first+num_to_get;i++) {
5140 char blob[28];
5141 char *p = blob;
5143 srv_put_dos_date2(p,0,queue[i].time);
5144 SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
5145 SSVAL(p,5, queue[i].job);
5146 SIVAL(p,7,queue[i].size);
5147 SCVAL(p,11,0);
5148 srvstr_push(blob, req->flags2, p+12,
5149 queue[i].fs_user, 16, STR_ASCII);
5151 if (message_push_blob(
5152 &req->outbuf,
5153 data_blob_const(
5154 blob, sizeof(blob))) == -1) {
5155 reply_nterror(req, NT_STATUS_NO_MEMORY);
5156 END_PROFILE(SMBsplretq);
5157 return;
5161 if (count > 0) {
5162 SSVAL(req->outbuf,smb_vwv0,count);
5163 SSVAL(req->outbuf,smb_vwv1,
5164 (max_count>0?first+count:first-1));
5165 SCVAL(smb_buf(req->outbuf),0,1);
5166 SSVAL(smb_buf(req->outbuf),1,28*count);
5169 SAFE_FREE(queue);
5171 DEBUG(3,("%d entries returned in queue\n",count));
5174 END_PROFILE(SMBsplretq);
5175 return;
5178 /****************************************************************************
5179 Reply to a printwrite.
5180 ****************************************************************************/
5182 void reply_printwrite(struct smb_request *req)
5184 connection_struct *conn = req->conn;
5185 int numtowrite;
5186 const char *data;
5187 files_struct *fsp;
5189 START_PROFILE(SMBsplwr);
5191 if (req->wct < 1) {
5192 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5193 END_PROFILE(SMBsplwr);
5194 return;
5197 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5199 if (!check_fsp(conn, req, fsp)) {
5200 END_PROFILE(SMBsplwr);
5201 return;
5204 if (!CAN_PRINT(conn)) {
5205 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5206 END_PROFILE(SMBsplwr);
5207 return;
5210 if (!CHECK_WRITE(fsp)) {
5211 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5212 END_PROFILE(SMBsplwr);
5213 return;
5216 numtowrite = SVAL(req->buf, 1);
5218 if (req->buflen < numtowrite + 3) {
5219 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5220 END_PROFILE(SMBsplwr);
5221 return;
5224 data = (const char *)req->buf + 3;
5226 if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) {
5227 reply_nterror(req, map_nt_error_from_unix(errno));
5228 END_PROFILE(SMBsplwr);
5229 return;
5232 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5234 END_PROFILE(SMBsplwr);
5235 return;
5238 /****************************************************************************
5239 Reply to a mkdir.
5240 ****************************************************************************/
5242 void reply_mkdir(struct smb_request *req)
5244 connection_struct *conn = req->conn;
5245 struct smb_filename *smb_dname = NULL;
5246 char *directory = NULL;
5247 NTSTATUS status;
5248 TALLOC_CTX *ctx = talloc_tos();
5250 START_PROFILE(SMBmkdir);
5252 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5253 STR_TERMINATE, &status);
5254 if (!NT_STATUS_IS_OK(status)) {
5255 reply_nterror(req, status);
5256 goto out;
5259 status = filename_convert(ctx, conn,
5260 req->flags2 & FLAGS2_DFS_PATHNAMES,
5261 directory,
5263 NULL,
5264 &smb_dname);
5265 if (!NT_STATUS_IS_OK(status)) {
5266 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5267 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5268 ERRSRV, ERRbadpath);
5269 goto out;
5271 reply_nterror(req, status);
5272 goto out;
5275 status = create_directory(conn, req, smb_dname);
5277 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5279 if (!NT_STATUS_IS_OK(status)) {
5281 if (!use_nt_status()
5282 && NT_STATUS_EQUAL(status,
5283 NT_STATUS_OBJECT_NAME_COLLISION)) {
5285 * Yes, in the DOS error code case we get a
5286 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5287 * samba4 torture test.
5289 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5292 reply_nterror(req, status);
5293 goto out;
5296 reply_outbuf(req, 0, 0);
5298 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5299 out:
5300 TALLOC_FREE(smb_dname);
5301 END_PROFILE(SMBmkdir);
5302 return;
5305 /****************************************************************************
5306 Reply to a rmdir.
5307 ****************************************************************************/
5309 void reply_rmdir(struct smb_request *req)
5311 connection_struct *conn = req->conn;
5312 struct smb_filename *smb_dname = NULL;
5313 char *directory = NULL;
5314 NTSTATUS status;
5315 TALLOC_CTX *ctx = talloc_tos();
5316 files_struct *fsp = NULL;
5317 int info = 0;
5318 struct smbd_server_connection *sconn = smbd_server_conn;
5320 START_PROFILE(SMBrmdir);
5322 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5323 STR_TERMINATE, &status);
5324 if (!NT_STATUS_IS_OK(status)) {
5325 reply_nterror(req, status);
5326 goto out;
5329 status = filename_convert(ctx, conn,
5330 req->flags2 & FLAGS2_DFS_PATHNAMES,
5331 directory,
5333 NULL,
5334 &smb_dname);
5335 if (!NT_STATUS_IS_OK(status)) {
5336 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5337 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5338 ERRSRV, ERRbadpath);
5339 goto out;
5341 reply_nterror(req, status);
5342 goto out;
5345 if (is_ntfs_stream_smb_fname(smb_dname)) {
5346 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5347 goto out;
5350 status = SMB_VFS_CREATE_FILE(
5351 conn, /* conn */
5352 req, /* req */
5353 0, /* root_dir_fid */
5354 smb_dname, /* fname */
5355 DELETE_ACCESS, /* access_mask */
5356 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5357 FILE_SHARE_DELETE),
5358 FILE_OPEN, /* create_disposition*/
5359 FILE_DIRECTORY_FILE, /* create_options */
5360 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5361 0, /* oplock_request */
5362 0, /* allocation_size */
5363 NULL, /* sd */
5364 NULL, /* ea_list */
5365 &fsp, /* result */
5366 &info); /* pinfo */
5368 if (!NT_STATUS_IS_OK(status)) {
5369 if (open_was_deferred(req->mid)) {
5370 /* We have re-scheduled this call. */
5371 goto out;
5373 reply_nterror(req, status);
5374 goto out;
5377 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5378 if (!NT_STATUS_IS_OK(status)) {
5379 close_file(req, fsp, ERROR_CLOSE);
5380 reply_nterror(req, status);
5381 goto out;
5384 if (!set_delete_on_close(fsp, true, &conn->server_info->utok)) {
5385 close_file(req, fsp, ERROR_CLOSE);
5386 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5387 goto out;
5390 status = close_file(req, fsp, NORMAL_CLOSE);
5391 if (!NT_STATUS_IS_OK(status)) {
5392 reply_nterror(req, status);
5393 } else {
5394 reply_outbuf(req, 0, 0);
5397 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5399 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5400 out:
5401 TALLOC_FREE(smb_dname);
5402 END_PROFILE(SMBrmdir);
5403 return;
5406 /*******************************************************************
5407 Resolve wildcards in a filename rename.
5408 ********************************************************************/
5410 static bool resolve_wildcards(TALLOC_CTX *ctx,
5411 const char *name1,
5412 const char *name2,
5413 char **pp_newname)
5415 char *name2_copy = NULL;
5416 char *root1 = NULL;
5417 char *root2 = NULL;
5418 char *ext1 = NULL;
5419 char *ext2 = NULL;
5420 char *p,*p2, *pname1, *pname2;
5422 name2_copy = talloc_strdup(ctx, name2);
5423 if (!name2_copy) {
5424 return False;
5427 pname1 = strrchr_m(name1,'/');
5428 pname2 = strrchr_m(name2_copy,'/');
5430 if (!pname1 || !pname2) {
5431 return False;
5434 /* Truncate the copy of name2 at the last '/' */
5435 *pname2 = '\0';
5437 /* Now go past the '/' */
5438 pname1++;
5439 pname2++;
5441 root1 = talloc_strdup(ctx, pname1);
5442 root2 = talloc_strdup(ctx, pname2);
5444 if (!root1 || !root2) {
5445 return False;
5448 p = strrchr_m(root1,'.');
5449 if (p) {
5450 *p = 0;
5451 ext1 = talloc_strdup(ctx, p+1);
5452 } else {
5453 ext1 = talloc_strdup(ctx, "");
5455 p = strrchr_m(root2,'.');
5456 if (p) {
5457 *p = 0;
5458 ext2 = talloc_strdup(ctx, p+1);
5459 } else {
5460 ext2 = talloc_strdup(ctx, "");
5463 if (!ext1 || !ext2) {
5464 return False;
5467 p = root1;
5468 p2 = root2;
5469 while (*p2) {
5470 if (*p2 == '?') {
5471 /* Hmmm. Should this be mb-aware ? */
5472 *p2 = *p;
5473 p2++;
5474 } else if (*p2 == '*') {
5475 *p2 = '\0';
5476 root2 = talloc_asprintf(ctx, "%s%s",
5477 root2,
5479 if (!root2) {
5480 return False;
5482 break;
5483 } else {
5484 p2++;
5486 if (*p) {
5487 p++;
5491 p = ext1;
5492 p2 = ext2;
5493 while (*p2) {
5494 if (*p2 == '?') {
5495 /* Hmmm. Should this be mb-aware ? */
5496 *p2 = *p;
5497 p2++;
5498 } else if (*p2 == '*') {
5499 *p2 = '\0';
5500 ext2 = talloc_asprintf(ctx, "%s%s",
5501 ext2,
5503 if (!ext2) {
5504 return False;
5506 break;
5507 } else {
5508 p2++;
5510 if (*p) {
5511 p++;
5515 if (*ext2) {
5516 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5517 name2_copy,
5518 root2,
5519 ext2);
5520 } else {
5521 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5522 name2_copy,
5523 root2);
5526 if (!*pp_newname) {
5527 return False;
5530 return True;
5533 /****************************************************************************
5534 Ensure open files have their names updated. Updated to notify other smbd's
5535 asynchronously.
5536 ****************************************************************************/
5538 static void rename_open_files(connection_struct *conn,
5539 struct share_mode_lock *lck,
5540 const struct smb_filename *smb_fname_dst)
5542 files_struct *fsp;
5543 bool did_rename = False;
5544 NTSTATUS status;
5546 for(fsp = file_find_di_first(lck->id); fsp;
5547 fsp = file_find_di_next(fsp)) {
5548 /* fsp_name is a relative path under the fsp. To change this for other
5549 sharepaths we need to manipulate relative paths. */
5550 /* TODO - create the absolute path and manipulate the newname
5551 relative to the sharepath. */
5552 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5553 continue;
5555 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5556 "(file_id %s) from %s -> %s\n", fsp->fnum,
5557 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5558 smb_fname_str_dbg(smb_fname_dst)));
5560 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5561 if (NT_STATUS_IS_OK(status)) {
5562 did_rename = True;
5566 if (!did_rename) {
5567 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5568 "for %s\n", file_id_string_tos(&lck->id),
5569 smb_fname_str_dbg(smb_fname_dst)));
5572 /* Send messages to all smbd's (not ourself) that the name has changed. */
5573 rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
5574 smb_fname_dst);
5578 /****************************************************************************
5579 We need to check if the source path is a parent directory of the destination
5580 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5581 refuse the rename with a sharing violation. Under UNIX the above call can
5582 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5583 probably need to check that the client is a Windows one before disallowing
5584 this as a UNIX client (one with UNIX extensions) can know the source is a
5585 symlink and make this decision intelligently. Found by an excellent bug
5586 report from <AndyLiebman@aol.com>.
5587 ****************************************************************************/
5589 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5590 const struct smb_filename *smb_fname_dst)
5592 const char *psrc = smb_fname_src->base_name;
5593 const char *pdst = smb_fname_dst->base_name;
5594 size_t slen;
5596 if (psrc[0] == '.' && psrc[1] == '/') {
5597 psrc += 2;
5599 if (pdst[0] == '.' && pdst[1] == '/') {
5600 pdst += 2;
5602 if ((slen = strlen(psrc)) > strlen(pdst)) {
5603 return False;
5605 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5609 * Do the notify calls from a rename
5612 static void notify_rename(connection_struct *conn, bool is_dir,
5613 const struct smb_filename *smb_fname_src,
5614 const struct smb_filename *smb_fname_dst)
5616 char *parent_dir_src = NULL;
5617 char *parent_dir_dst = NULL;
5618 uint32 mask;
5620 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5621 : FILE_NOTIFY_CHANGE_FILE_NAME;
5623 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5624 &parent_dir_src, NULL) ||
5625 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5626 &parent_dir_dst, NULL)) {
5627 goto out;
5630 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5631 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5632 smb_fname_src->base_name);
5633 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5634 smb_fname_dst->base_name);
5636 else {
5637 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5638 smb_fname_src->base_name);
5639 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5640 smb_fname_dst->base_name);
5643 /* this is a strange one. w2k3 gives an additional event for
5644 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5645 files, but not directories */
5646 if (!is_dir) {
5647 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5648 FILE_NOTIFY_CHANGE_ATTRIBUTES
5649 |FILE_NOTIFY_CHANGE_CREATION,
5650 smb_fname_dst->base_name);
5652 out:
5653 TALLOC_FREE(parent_dir_src);
5654 TALLOC_FREE(parent_dir_dst);
5657 /****************************************************************************
5658 Rename an open file - given an fsp.
5659 ****************************************************************************/
5661 NTSTATUS rename_internals_fsp(connection_struct *conn,
5662 files_struct *fsp,
5663 const struct smb_filename *smb_fname_dst_in,
5664 uint32 attrs,
5665 bool replace_if_exists)
5667 TALLOC_CTX *ctx = talloc_tos();
5668 struct smb_filename *smb_fname_dst = NULL;
5669 NTSTATUS status = NT_STATUS_OK;
5670 struct share_mode_lock *lck = NULL;
5671 bool dst_exists, old_is_stream, new_is_stream;
5673 status = check_name(conn, smb_fname_dst_in->base_name);
5674 if (!NT_STATUS_IS_OK(status)) {
5675 return status;
5678 /* Make a copy of the dst smb_fname structs */
5680 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5681 if (!NT_STATUS_IS_OK(status)) {
5682 goto out;
5685 /* Ensure the dst smb_fname contains a '/' */
5686 if(strrchr_m(smb_fname_dst->base_name,'/') == 0) {
5687 char * tmp;
5688 tmp = talloc_asprintf(smb_fname_dst, "./%s",
5689 smb_fname_dst->base_name);
5690 if (!tmp) {
5691 status = NT_STATUS_NO_MEMORY;
5692 goto out;
5694 TALLOC_FREE(smb_fname_dst->base_name);
5695 smb_fname_dst->base_name = tmp;
5699 * Check for special case with case preserving and not
5700 * case sensitive. If the old last component differs from the original
5701 * last component only by case, then we should allow
5702 * the rename (user is trying to change the case of the
5703 * filename).
5705 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5706 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5707 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5708 char *last_slash;
5709 char *fname_dst_lcomp_base_mod = NULL;
5710 struct smb_filename *smb_fname_orig_lcomp = NULL;
5713 * Get the last component of the destination name. Note that
5714 * we guarantee that destination name contains a '/' character
5715 * above.
5717 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
5718 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
5719 if (!fname_dst_lcomp_base_mod) {
5720 status = NT_STATUS_NO_MEMORY;
5721 goto out;
5725 * Create an smb_filename struct using the original last
5726 * component of the destination.
5728 status = create_synthetic_smb_fname_split(ctx,
5729 smb_fname_dst->original_lcomp, NULL,
5730 &smb_fname_orig_lcomp);
5731 if (!NT_STATUS_IS_OK(status)) {
5732 TALLOC_FREE(fname_dst_lcomp_base_mod);
5733 goto out;
5736 /* If the base names only differ by case, use original. */
5737 if(!strcsequal(fname_dst_lcomp_base_mod,
5738 smb_fname_orig_lcomp->base_name)) {
5739 char *tmp;
5741 * Replace the modified last component with the
5742 * original.
5744 *last_slash = '\0'; /* Truncate at the '/' */
5745 tmp = talloc_asprintf(smb_fname_dst,
5746 "%s/%s",
5747 smb_fname_dst->base_name,
5748 smb_fname_orig_lcomp->base_name);
5749 if (tmp == NULL) {
5750 status = NT_STATUS_NO_MEMORY;
5751 TALLOC_FREE(fname_dst_lcomp_base_mod);
5752 TALLOC_FREE(smb_fname_orig_lcomp);
5753 goto out;
5755 TALLOC_FREE(smb_fname_dst->base_name);
5756 smb_fname_dst->base_name = tmp;
5759 /* If the stream_names only differ by case, use original. */
5760 if(!strcsequal(smb_fname_dst->stream_name,
5761 smb_fname_orig_lcomp->stream_name)) {
5762 char *tmp = NULL;
5763 /* Use the original stream. */
5764 tmp = talloc_strdup(smb_fname_dst,
5765 smb_fname_orig_lcomp->stream_name);
5766 if (tmp == NULL) {
5767 status = NT_STATUS_NO_MEMORY;
5768 TALLOC_FREE(fname_dst_lcomp_base_mod);
5769 TALLOC_FREE(smb_fname_orig_lcomp);
5770 goto out;
5772 TALLOC_FREE(smb_fname_dst->stream_name);
5773 smb_fname_dst->stream_name = tmp;
5775 TALLOC_FREE(fname_dst_lcomp_base_mod);
5776 TALLOC_FREE(smb_fname_orig_lcomp);
5780 * If the src and dest names are identical - including case,
5781 * don't do the rename, just return success.
5784 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5785 strcsequal(fsp->fsp_name->stream_name,
5786 smb_fname_dst->stream_name)) {
5787 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
5788 "- returning success\n",
5789 smb_fname_str_dbg(smb_fname_dst)));
5790 status = NT_STATUS_OK;
5791 goto out;
5794 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
5795 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
5797 /* Return the correct error code if both names aren't streams. */
5798 if (!old_is_stream && new_is_stream) {
5799 status = NT_STATUS_OBJECT_NAME_INVALID;
5800 goto out;
5803 if (old_is_stream && !new_is_stream) {
5804 status = NT_STATUS_INVALID_PARAMETER;
5805 goto out;
5808 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
5810 if(!replace_if_exists && dst_exists) {
5811 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
5812 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
5813 smb_fname_str_dbg(smb_fname_dst)));
5814 status = NT_STATUS_OBJECT_NAME_COLLISION;
5815 goto out;
5818 if (dst_exists) {
5819 struct file_id fileid = vfs_file_id_from_sbuf(conn,
5820 &smb_fname_dst->st);
5821 files_struct *dst_fsp = file_find_di_first(fileid);
5822 /* The file can be open when renaming a stream */
5823 if (dst_fsp && !new_is_stream) {
5824 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
5825 status = NT_STATUS_ACCESS_DENIED;
5826 goto out;
5830 /* Ensure we have a valid stat struct for the source. */
5831 status = vfs_stat_fsp(fsp);
5832 if (!NT_STATUS_IS_OK(status)) {
5833 goto out;
5836 status = can_rename(conn, fsp, attrs);
5838 if (!NT_STATUS_IS_OK(status)) {
5839 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
5840 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
5841 smb_fname_str_dbg(smb_fname_dst)));
5842 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
5843 status = NT_STATUS_ACCESS_DENIED;
5844 goto out;
5847 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
5848 status = NT_STATUS_ACCESS_DENIED;
5851 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
5852 NULL);
5855 * We have the file open ourselves, so not being able to get the
5856 * corresponding share mode lock is a fatal error.
5859 SMB_ASSERT(lck != NULL);
5861 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
5862 uint32 create_options = fsp->fh->private_options;
5864 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
5865 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
5866 smb_fname_str_dbg(smb_fname_dst)));
5868 if (!lp_posix_pathnames() &&
5869 (lp_map_archive(SNUM(conn)) ||
5870 lp_store_dos_attributes(SNUM(conn)))) {
5871 /* We must set the archive bit on the newly
5872 renamed file. */
5873 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
5874 uint32_t old_dosmode = dos_mode(conn,
5875 smb_fname_dst);
5876 file_set_dosmode(conn,
5877 smb_fname_dst,
5878 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
5879 NULL,
5880 true);
5884 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
5885 smb_fname_dst);
5887 rename_open_files(conn, lck, smb_fname_dst);
5890 * A rename acts as a new file create w.r.t. allowing an initial delete
5891 * on close, probably because in Windows there is a new handle to the
5892 * new file. If initial delete on close was requested but not
5893 * originally set, we need to set it here. This is probably not 100% correct,
5894 * but will work for the CIFSFS client which in non-posix mode
5895 * depends on these semantics. JRA.
5898 if (create_options & FILE_DELETE_ON_CLOSE) {
5899 status = can_set_delete_on_close(fsp, 0);
5901 if (NT_STATUS_IS_OK(status)) {
5902 /* Note that here we set the *inital* delete on close flag,
5903 * not the regular one. The magic gets handled in close. */
5904 fsp->initial_delete_on_close = True;
5907 TALLOC_FREE(lck);
5908 status = NT_STATUS_OK;
5909 goto out;
5912 TALLOC_FREE(lck);
5914 if (errno == ENOTDIR || errno == EISDIR) {
5915 status = NT_STATUS_OBJECT_NAME_COLLISION;
5916 } else {
5917 status = map_nt_error_from_unix(errno);
5920 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
5921 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
5922 smb_fname_str_dbg(smb_fname_dst)));
5924 out:
5925 TALLOC_FREE(smb_fname_dst);
5927 return status;
5930 /****************************************************************************
5931 The guts of the rename command, split out so it may be called by the NT SMB
5932 code.
5933 ****************************************************************************/
5935 NTSTATUS rename_internals(TALLOC_CTX *ctx,
5936 connection_struct *conn,
5937 struct smb_request *req,
5938 struct smb_filename *smb_fname_src,
5939 struct smb_filename *smb_fname_dst,
5940 uint32 attrs,
5941 bool replace_if_exists,
5942 bool src_has_wild,
5943 bool dest_has_wild,
5944 uint32_t access_mask)
5946 char *fname_src_dir = NULL;
5947 char *fname_src_mask = NULL;
5948 int count=0;
5949 NTSTATUS status = NT_STATUS_OK;
5950 struct smb_Dir *dir_hnd = NULL;
5951 const char *dname = NULL;
5952 char *talloced = NULL;
5953 long offset = 0;
5954 int create_options = 0;
5955 bool posix_pathnames = lp_posix_pathnames();
5958 * Split the old name into directory and last component
5959 * strings. Note that unix_convert may have stripped off a
5960 * leading ./ from both name and newname if the rename is
5961 * at the root of the share. We need to make sure either both
5962 * name and newname contain a / character or neither of them do
5963 * as this is checked in resolve_wildcards().
5966 /* Split up the directory from the filename/mask. */
5967 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
5968 &fname_src_dir, &fname_src_mask);
5969 if (!NT_STATUS_IS_OK(status)) {
5970 status = NT_STATUS_NO_MEMORY;
5971 goto out;
5975 * We should only check the mangled cache
5976 * here if unix_convert failed. This means
5977 * that the path in 'mask' doesn't exist
5978 * on the file system and so we need to look
5979 * for a possible mangle. This patch from
5980 * Tine Smukavec <valentin.smukavec@hermes.si>.
5983 if (!VALID_STAT(smb_fname_src->st) &&
5984 mangle_is_mangled(fname_src_mask, conn->params)) {
5985 char *new_mask = NULL;
5986 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
5987 conn->params);
5988 if (new_mask) {
5989 TALLOC_FREE(fname_src_mask);
5990 fname_src_mask = new_mask;
5994 if (!src_has_wild) {
5995 files_struct *fsp;
5998 * Only one file needs to be renamed. Append the mask back
5999 * onto the directory.
6001 TALLOC_FREE(smb_fname_src->base_name);
6002 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6003 "%s/%s",
6004 fname_src_dir,
6005 fname_src_mask);
6006 if (!smb_fname_src->base_name) {
6007 status = NT_STATUS_NO_MEMORY;
6008 goto out;
6011 /* Ensure dst fname contains a '/' also */
6012 if(strrchr_m(smb_fname_dst->base_name, '/') == 0) {
6013 char *tmp;
6014 tmp = talloc_asprintf(smb_fname_dst, "./%s",
6015 smb_fname_dst->base_name);
6016 if (!tmp) {
6017 status = NT_STATUS_NO_MEMORY;
6018 goto out;
6020 TALLOC_FREE(smb_fname_dst->base_name);
6021 smb_fname_dst->base_name = tmp;
6024 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6025 "case_preserve = %d, short case preserve = %d, "
6026 "directory = %s, newname = %s, "
6027 "last_component_dest = %s\n",
6028 conn->case_sensitive, conn->case_preserve,
6029 conn->short_case_preserve,
6030 smb_fname_str_dbg(smb_fname_src),
6031 smb_fname_str_dbg(smb_fname_dst),
6032 smb_fname_dst->original_lcomp));
6034 /* The dest name still may have wildcards. */
6035 if (dest_has_wild) {
6036 char *fname_dst_mod = NULL;
6037 if (!resolve_wildcards(smb_fname_dst,
6038 smb_fname_src->base_name,
6039 smb_fname_dst->base_name,
6040 &fname_dst_mod)) {
6041 DEBUG(6, ("rename_internals: resolve_wildcards "
6042 "%s %s failed\n",
6043 smb_fname_src->base_name,
6044 smb_fname_dst->base_name));
6045 status = NT_STATUS_NO_MEMORY;
6046 goto out;
6048 TALLOC_FREE(smb_fname_dst->base_name);
6049 smb_fname_dst->base_name = fname_dst_mod;
6052 ZERO_STRUCT(smb_fname_src->st);
6053 if (posix_pathnames) {
6054 SMB_VFS_LSTAT(conn, smb_fname_src);
6055 } else {
6056 SMB_VFS_STAT(conn, smb_fname_src);
6059 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6060 create_options |= FILE_DIRECTORY_FILE;
6063 status = SMB_VFS_CREATE_FILE(
6064 conn, /* conn */
6065 req, /* req */
6066 0, /* root_dir_fid */
6067 smb_fname_src, /* fname */
6068 access_mask, /* access_mask */
6069 (FILE_SHARE_READ | /* share_access */
6070 FILE_SHARE_WRITE),
6071 FILE_OPEN, /* create_disposition*/
6072 create_options, /* create_options */
6073 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6074 0, /* oplock_request */
6075 0, /* allocation_size */
6076 NULL, /* sd */
6077 NULL, /* ea_list */
6078 &fsp, /* result */
6079 NULL); /* pinfo */
6081 if (!NT_STATUS_IS_OK(status)) {
6082 DEBUG(3, ("Could not open rename source %s: %s\n",
6083 smb_fname_str_dbg(smb_fname_src),
6084 nt_errstr(status)));
6085 goto out;
6088 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6089 attrs, replace_if_exists);
6091 close_file(req, fsp, NORMAL_CLOSE);
6093 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6094 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6095 smb_fname_str_dbg(smb_fname_dst)));
6097 goto out;
6101 * Wildcards - process each file that matches.
6103 if (strequal(fname_src_mask, "????????.???")) {
6104 TALLOC_FREE(fname_src_mask);
6105 fname_src_mask = talloc_strdup(ctx, "*");
6106 if (!fname_src_mask) {
6107 status = NT_STATUS_NO_MEMORY;
6108 goto out;
6112 status = check_name(conn, fname_src_dir);
6113 if (!NT_STATUS_IS_OK(status)) {
6114 goto out;
6117 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6118 attrs);
6119 if (dir_hnd == NULL) {
6120 status = map_nt_error_from_unix(errno);
6121 goto out;
6124 status = NT_STATUS_NO_SUCH_FILE;
6126 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6127 * - gentest fix. JRA
6130 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6131 &talloced))) {
6132 files_struct *fsp = NULL;
6133 char *destname = NULL;
6134 bool sysdir_entry = False;
6136 /* Quick check for "." and ".." */
6137 if (ISDOT(dname) || ISDOTDOT(dname)) {
6138 if (attrs & aDIR) {
6139 sysdir_entry = True;
6140 } else {
6141 TALLOC_FREE(talloced);
6142 continue;
6146 if (!is_visible_file(conn, fname_src_dir, dname,
6147 &smb_fname_src->st, false)) {
6148 TALLOC_FREE(talloced);
6149 continue;
6152 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6153 TALLOC_FREE(talloced);
6154 continue;
6157 if (sysdir_entry) {
6158 status = NT_STATUS_OBJECT_NAME_INVALID;
6159 break;
6162 TALLOC_FREE(smb_fname_src->base_name);
6163 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6164 "%s/%s",
6165 fname_src_dir,
6166 dname);
6167 if (!smb_fname_src->base_name) {
6168 status = NT_STATUS_NO_MEMORY;
6169 goto out;
6172 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6173 smb_fname_dst->base_name,
6174 &destname)) {
6175 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6176 smb_fname_src->base_name, destname));
6177 TALLOC_FREE(talloced);
6178 continue;
6180 if (!destname) {
6181 status = NT_STATUS_NO_MEMORY;
6182 goto out;
6185 TALLOC_FREE(smb_fname_dst->base_name);
6186 smb_fname_dst->base_name = destname;
6188 ZERO_STRUCT(smb_fname_src->st);
6189 if (posix_pathnames) {
6190 SMB_VFS_LSTAT(conn, smb_fname_src);
6191 } else {
6192 SMB_VFS_STAT(conn, smb_fname_src);
6195 create_options = 0;
6197 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6198 create_options |= FILE_DIRECTORY_FILE;
6201 status = SMB_VFS_CREATE_FILE(
6202 conn, /* conn */
6203 req, /* req */
6204 0, /* root_dir_fid */
6205 smb_fname_src, /* fname */
6206 access_mask, /* access_mask */
6207 (FILE_SHARE_READ | /* share_access */
6208 FILE_SHARE_WRITE),
6209 FILE_OPEN, /* create_disposition*/
6210 create_options, /* create_options */
6211 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6212 0, /* oplock_request */
6213 0, /* allocation_size */
6214 NULL, /* sd */
6215 NULL, /* ea_list */
6216 &fsp, /* result */
6217 NULL); /* pinfo */
6219 if (!NT_STATUS_IS_OK(status)) {
6220 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6221 "returned %s rename %s -> %s\n",
6222 nt_errstr(status),
6223 smb_fname_str_dbg(smb_fname_src),
6224 smb_fname_str_dbg(smb_fname_dst)));
6225 break;
6228 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6229 dname);
6230 if (!smb_fname_dst->original_lcomp) {
6231 status = NT_STATUS_NO_MEMORY;
6232 goto out;
6235 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6236 attrs, replace_if_exists);
6238 close_file(req, fsp, NORMAL_CLOSE);
6240 if (!NT_STATUS_IS_OK(status)) {
6241 DEBUG(3, ("rename_internals_fsp returned %s for "
6242 "rename %s -> %s\n", nt_errstr(status),
6243 smb_fname_str_dbg(smb_fname_src),
6244 smb_fname_str_dbg(smb_fname_dst)));
6245 break;
6248 count++;
6250 DEBUG(3,("rename_internals: doing rename on %s -> "
6251 "%s\n", smb_fname_str_dbg(smb_fname_src),
6252 smb_fname_str_dbg(smb_fname_src)));
6253 TALLOC_FREE(talloced);
6255 TALLOC_FREE(dir_hnd);
6257 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6258 status = map_nt_error_from_unix(errno);
6261 out:
6262 TALLOC_FREE(talloced);
6263 TALLOC_FREE(fname_src_dir);
6264 TALLOC_FREE(fname_src_mask);
6265 return status;
6268 /****************************************************************************
6269 Reply to a mv.
6270 ****************************************************************************/
6272 void reply_mv(struct smb_request *req)
6274 connection_struct *conn = req->conn;
6275 char *name = NULL;
6276 char *newname = NULL;
6277 const char *p;
6278 uint32 attrs;
6279 NTSTATUS status;
6280 bool src_has_wcard = False;
6281 bool dest_has_wcard = False;
6282 TALLOC_CTX *ctx = talloc_tos();
6283 struct smb_filename *smb_fname_src = NULL;
6284 struct smb_filename *smb_fname_dst = NULL;
6286 START_PROFILE(SMBmv);
6288 if (req->wct < 1) {
6289 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6290 goto out;
6293 attrs = SVAL(req->vwv+0, 0);
6295 p = (const char *)req->buf + 1;
6296 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6297 &status, &src_has_wcard);
6298 if (!NT_STATUS_IS_OK(status)) {
6299 reply_nterror(req, status);
6300 goto out;
6302 p++;
6303 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6304 &status, &dest_has_wcard);
6305 if (!NT_STATUS_IS_OK(status)) {
6306 reply_nterror(req, status);
6307 goto out;
6310 status = filename_convert(ctx,
6311 conn,
6312 req->flags2 & FLAGS2_DFS_PATHNAMES,
6313 name,
6314 UCF_COND_ALLOW_WCARD_LCOMP,
6315 &src_has_wcard,
6316 &smb_fname_src);
6318 if (!NT_STATUS_IS_OK(status)) {
6319 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6320 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6321 ERRSRV, ERRbadpath);
6322 goto out;
6324 reply_nterror(req, status);
6325 goto out;
6328 status = filename_convert(ctx,
6329 conn,
6330 req->flags2 & FLAGS2_DFS_PATHNAMES,
6331 newname,
6332 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6333 &dest_has_wcard,
6334 &smb_fname_dst);
6336 if (!NT_STATUS_IS_OK(status)) {
6337 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6338 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6339 ERRSRV, ERRbadpath);
6340 goto out;
6342 reply_nterror(req, status);
6343 goto out;
6346 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6347 smb_fname_str_dbg(smb_fname_dst)));
6349 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6350 attrs, False, src_has_wcard, dest_has_wcard,
6351 DELETE_ACCESS);
6352 if (!NT_STATUS_IS_OK(status)) {
6353 if (open_was_deferred(req->mid)) {
6354 /* We have re-scheduled this call. */
6355 goto out;
6357 reply_nterror(req, status);
6358 goto out;
6361 reply_outbuf(req, 0, 0);
6362 out:
6363 TALLOC_FREE(smb_fname_src);
6364 TALLOC_FREE(smb_fname_dst);
6365 END_PROFILE(SMBmv);
6366 return;
6369 /*******************************************************************
6370 Copy a file as part of a reply_copy.
6371 ******************************************************************/
6374 * TODO: check error codes on all callers
6377 NTSTATUS copy_file(TALLOC_CTX *ctx,
6378 connection_struct *conn,
6379 struct smb_filename *smb_fname_src,
6380 struct smb_filename *smb_fname_dst,
6381 int ofun,
6382 int count,
6383 bool target_is_directory)
6385 struct smb_filename *smb_fname_dst_tmp = NULL;
6386 SMB_OFF_T ret=-1;
6387 files_struct *fsp1,*fsp2;
6388 uint32 dosattrs;
6389 uint32 new_create_disposition;
6390 NTSTATUS status;
6393 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6394 if (!NT_STATUS_IS_OK(status)) {
6395 return status;
6399 * If the target is a directory, extract the last component from the
6400 * src filename and append it to the dst filename
6402 if (target_is_directory) {
6403 const char *p;
6405 /* dest/target can't be a stream if it's a directory. */
6406 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6408 p = strrchr_m(smb_fname_src->base_name,'/');
6409 if (p) {
6410 p++;
6411 } else {
6412 p = smb_fname_src->base_name;
6414 smb_fname_dst_tmp->base_name =
6415 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6417 if (!smb_fname_dst_tmp->base_name) {
6418 status = NT_STATUS_NO_MEMORY;
6419 goto out;
6423 status = vfs_file_exist(conn, smb_fname_src);
6424 if (!NT_STATUS_IS_OK(status)) {
6425 goto out;
6428 if (!target_is_directory && count) {
6429 new_create_disposition = FILE_OPEN;
6430 } else {
6431 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
6432 NULL, NULL,
6433 &new_create_disposition,
6434 NULL)) {
6435 status = NT_STATUS_INVALID_PARAMETER;
6436 goto out;
6440 /* Open the src file for reading. */
6441 status = SMB_VFS_CREATE_FILE(
6442 conn, /* conn */
6443 NULL, /* req */
6444 0, /* root_dir_fid */
6445 smb_fname_src, /* fname */
6446 FILE_GENERIC_READ, /* access_mask */
6447 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6448 FILE_OPEN, /* create_disposition*/
6449 0, /* create_options */
6450 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6451 INTERNAL_OPEN_ONLY, /* oplock_request */
6452 0, /* allocation_size */
6453 NULL, /* sd */
6454 NULL, /* ea_list */
6455 &fsp1, /* result */
6456 NULL); /* psbuf */
6458 if (!NT_STATUS_IS_OK(status)) {
6459 goto out;
6462 dosattrs = dos_mode(conn, smb_fname_src);
6464 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6465 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6468 /* Open the dst file for writing. */
6469 status = SMB_VFS_CREATE_FILE(
6470 conn, /* conn */
6471 NULL, /* req */
6472 0, /* root_dir_fid */
6473 smb_fname_dst, /* fname */
6474 FILE_GENERIC_WRITE, /* access_mask */
6475 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6476 new_create_disposition, /* create_disposition*/
6477 0, /* create_options */
6478 dosattrs, /* file_attributes */
6479 INTERNAL_OPEN_ONLY, /* oplock_request */
6480 0, /* allocation_size */
6481 NULL, /* sd */
6482 NULL, /* ea_list */
6483 &fsp2, /* result */
6484 NULL); /* psbuf */
6486 if (!NT_STATUS_IS_OK(status)) {
6487 close_file(NULL, fsp1, ERROR_CLOSE);
6488 goto out;
6491 if ((ofun&3) == 1) {
6492 if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
6493 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
6495 * Stop the copy from occurring.
6497 ret = -1;
6498 smb_fname_src->st.st_ex_size = 0;
6502 /* Do the actual copy. */
6503 if (smb_fname_src->st.st_ex_size) {
6504 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6507 close_file(NULL, fsp1, NORMAL_CLOSE);
6509 /* Ensure the modtime is set correctly on the destination file. */
6510 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6513 * As we are opening fsp1 read-only we only expect
6514 * an error on close on fsp2 if we are out of space.
6515 * Thus we don't look at the error return from the
6516 * close of fsp1.
6518 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6520 if (!NT_STATUS_IS_OK(status)) {
6521 goto out;
6524 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6525 status = NT_STATUS_DISK_FULL;
6526 goto out;
6529 status = NT_STATUS_OK;
6531 out:
6532 TALLOC_FREE(smb_fname_dst_tmp);
6533 return status;
6536 /****************************************************************************
6537 Reply to a file copy.
6538 ****************************************************************************/
6540 void reply_copy(struct smb_request *req)
6542 connection_struct *conn = req->conn;
6543 struct smb_filename *smb_fname_src = NULL;
6544 struct smb_filename *smb_fname_dst = NULL;
6545 char *fname_src = NULL;
6546 char *fname_dst = NULL;
6547 char *fname_src_mask = NULL;
6548 char *fname_src_dir = NULL;
6549 const char *p;
6550 int count=0;
6551 int error = ERRnoaccess;
6552 int tid2;
6553 int ofun;
6554 int flags;
6555 bool target_is_directory=False;
6556 bool source_has_wild = False;
6557 bool dest_has_wild = False;
6558 NTSTATUS status;
6559 TALLOC_CTX *ctx = talloc_tos();
6561 START_PROFILE(SMBcopy);
6563 if (req->wct < 3) {
6564 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6565 goto out;
6568 tid2 = SVAL(req->vwv+0, 0);
6569 ofun = SVAL(req->vwv+1, 0);
6570 flags = SVAL(req->vwv+2, 0);
6572 p = (const char *)req->buf;
6573 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6574 &status, &source_has_wild);
6575 if (!NT_STATUS_IS_OK(status)) {
6576 reply_nterror(req, status);
6577 goto out;
6579 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6580 &status, &dest_has_wild);
6581 if (!NT_STATUS_IS_OK(status)) {
6582 reply_nterror(req, status);
6583 goto out;
6586 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6588 if (tid2 != conn->cnum) {
6589 /* can't currently handle inter share copies XXXX */
6590 DEBUG(3,("Rejecting inter-share copy\n"));
6591 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6592 goto out;
6595 status = filename_convert(ctx, conn,
6596 req->flags2 & FLAGS2_DFS_PATHNAMES,
6597 fname_src,
6598 UCF_COND_ALLOW_WCARD_LCOMP,
6599 &source_has_wild,
6600 &smb_fname_src);
6601 if (!NT_STATUS_IS_OK(status)) {
6602 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6603 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6604 ERRSRV, ERRbadpath);
6605 goto out;
6607 reply_nterror(req, status);
6608 goto out;
6611 status = filename_convert(ctx, conn,
6612 req->flags2 & FLAGS2_DFS_PATHNAMES,
6613 fname_dst,
6614 UCF_COND_ALLOW_WCARD_LCOMP,
6615 &dest_has_wild,
6616 &smb_fname_dst);
6617 if (!NT_STATUS_IS_OK(status)) {
6618 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6619 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6620 ERRSRV, ERRbadpath);
6621 goto out;
6623 reply_nterror(req, status);
6624 goto out;
6627 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6629 if ((flags&1) && target_is_directory) {
6630 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6631 goto out;
6634 if ((flags&2) && !target_is_directory) {
6635 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6636 goto out;
6639 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6640 /* wants a tree copy! XXXX */
6641 DEBUG(3,("Rejecting tree copy\n"));
6642 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6643 goto out;
6646 /* Split up the directory from the filename/mask. */
6647 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6648 &fname_src_dir, &fname_src_mask);
6649 if (!NT_STATUS_IS_OK(status)) {
6650 reply_nterror(req, NT_STATUS_NO_MEMORY);
6651 goto out;
6655 * We should only check the mangled cache
6656 * here if unix_convert failed. This means
6657 * that the path in 'mask' doesn't exist
6658 * on the file system and so we need to look
6659 * for a possible mangle. This patch from
6660 * Tine Smukavec <valentin.smukavec@hermes.si>.
6662 if (!VALID_STAT(smb_fname_src->st) &&
6663 mangle_is_mangled(fname_src_mask, conn->params)) {
6664 char *new_mask = NULL;
6665 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6666 &new_mask, conn->params);
6668 /* Use demangled name if one was successfully found. */
6669 if (new_mask) {
6670 TALLOC_FREE(fname_src_mask);
6671 fname_src_mask = new_mask;
6675 if (!source_has_wild) {
6678 * Only one file needs to be copied. Append the mask back onto
6679 * the directory.
6681 TALLOC_FREE(smb_fname_src->base_name);
6682 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6683 "%s/%s",
6684 fname_src_dir,
6685 fname_src_mask);
6686 if (!smb_fname_src->base_name) {
6687 reply_nterror(req, NT_STATUS_NO_MEMORY);
6688 goto out;
6691 if (dest_has_wild) {
6692 char *fname_dst_mod = NULL;
6693 if (!resolve_wildcards(smb_fname_dst,
6694 smb_fname_src->base_name,
6695 smb_fname_dst->base_name,
6696 &fname_dst_mod)) {
6697 reply_nterror(req, NT_STATUS_NO_MEMORY);
6698 goto out;
6700 TALLOC_FREE(smb_fname_dst->base_name);
6701 smb_fname_dst->base_name = fname_dst_mod;
6704 status = check_name(conn, smb_fname_src->base_name);
6705 if (!NT_STATUS_IS_OK(status)) {
6706 reply_nterror(req, status);
6707 goto out;
6710 status = check_name(conn, smb_fname_dst->base_name);
6711 if (!NT_STATUS_IS_OK(status)) {
6712 reply_nterror(req, status);
6713 goto out;
6716 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
6717 ofun, count, target_is_directory);
6719 if(!NT_STATUS_IS_OK(status)) {
6720 reply_nterror(req, status);
6721 goto out;
6722 } else {
6723 count++;
6725 } else {
6726 struct smb_Dir *dir_hnd = NULL;
6727 const char *dname = NULL;
6728 char *talloced = NULL;
6729 long offset = 0;
6732 * There is a wildcard that requires us to actually read the
6733 * src dir and copy each file matching the mask to the dst.
6734 * Right now streams won't be copied, but this could
6735 * presumably be added with a nested loop for reach dir entry.
6737 SMB_ASSERT(!smb_fname_src->stream_name);
6738 SMB_ASSERT(!smb_fname_dst->stream_name);
6740 smb_fname_src->stream_name = NULL;
6741 smb_fname_dst->stream_name = NULL;
6743 if (strequal(fname_src_mask,"????????.???")) {
6744 TALLOC_FREE(fname_src_mask);
6745 fname_src_mask = talloc_strdup(ctx, "*");
6746 if (!fname_src_mask) {
6747 reply_nterror(req, NT_STATUS_NO_MEMORY);
6748 goto out;
6752 status = check_name(conn, fname_src_dir);
6753 if (!NT_STATUS_IS_OK(status)) {
6754 reply_nterror(req, status);
6755 goto out;
6758 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
6759 if (dir_hnd == NULL) {
6760 status = map_nt_error_from_unix(errno);
6761 reply_nterror(req, status);
6762 goto out;
6765 error = ERRbadfile;
6767 /* Iterate over the src dir copying each entry to the dst. */
6768 while ((dname = ReadDirName(dir_hnd, &offset,
6769 &smb_fname_src->st, &talloced))) {
6770 char *destname = NULL;
6772 if (ISDOT(dname) || ISDOTDOT(dname)) {
6773 TALLOC_FREE(talloced);
6774 continue;
6777 if (!is_visible_file(conn, fname_src_dir, dname,
6778 &smb_fname_src->st, false)) {
6779 TALLOC_FREE(talloced);
6780 continue;
6783 if(!mask_match(dname, fname_src_mask,
6784 conn->case_sensitive)) {
6785 TALLOC_FREE(talloced);
6786 continue;
6789 error = ERRnoaccess;
6791 /* Get the src smb_fname struct setup. */
6792 TALLOC_FREE(smb_fname_src->base_name);
6793 smb_fname_src->base_name =
6794 talloc_asprintf(smb_fname_src, "%s/%s",
6795 fname_src_dir, dname);
6797 if (!smb_fname_src->base_name) {
6798 TALLOC_FREE(dir_hnd);
6799 TALLOC_FREE(talloced);
6800 reply_nterror(req, NT_STATUS_NO_MEMORY);
6801 goto out;
6804 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6805 smb_fname_dst->base_name,
6806 &destname)) {
6807 TALLOC_FREE(talloced);
6808 continue;
6810 if (!destname) {
6811 TALLOC_FREE(dir_hnd);
6812 TALLOC_FREE(talloced);
6813 reply_nterror(req, NT_STATUS_NO_MEMORY);
6814 goto out;
6817 TALLOC_FREE(smb_fname_dst->base_name);
6818 smb_fname_dst->base_name = destname;
6820 status = check_name(conn, smb_fname_src->base_name);
6821 if (!NT_STATUS_IS_OK(status)) {
6822 TALLOC_FREE(dir_hnd);
6823 TALLOC_FREE(talloced);
6824 reply_nterror(req, status);
6825 goto out;
6828 status = check_name(conn, smb_fname_dst->base_name);
6829 if (!NT_STATUS_IS_OK(status)) {
6830 TALLOC_FREE(dir_hnd);
6831 TALLOC_FREE(talloced);
6832 reply_nterror(req, status);
6833 goto out;
6836 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
6837 smb_fname_src->base_name,
6838 smb_fname_dst->base_name));
6840 status = copy_file(ctx, conn, smb_fname_src,
6841 smb_fname_dst, ofun, count,
6842 target_is_directory);
6843 if (NT_STATUS_IS_OK(status)) {
6844 count++;
6847 TALLOC_FREE(talloced);
6849 TALLOC_FREE(dir_hnd);
6852 if (count == 0) {
6853 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
6854 goto out;
6857 reply_outbuf(req, 1, 0);
6858 SSVAL(req->outbuf,smb_vwv0,count);
6859 out:
6860 TALLOC_FREE(smb_fname_src);
6861 TALLOC_FREE(smb_fname_dst);
6862 TALLOC_FREE(fname_src);
6863 TALLOC_FREE(fname_dst);
6864 TALLOC_FREE(fname_src_mask);
6865 TALLOC_FREE(fname_src_dir);
6867 END_PROFILE(SMBcopy);
6868 return;
6871 #undef DBGC_CLASS
6872 #define DBGC_CLASS DBGC_LOCKING
6874 /****************************************************************************
6875 Get a lock pid, dealing with large count requests.
6876 ****************************************************************************/
6878 uint32 get_lock_pid(const uint8_t *data, int data_offset,
6879 bool large_file_format)
6881 if(!large_file_format)
6882 return (uint32)SVAL(data,SMB_LPID_OFFSET(data_offset));
6883 else
6884 return (uint32)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
6887 /****************************************************************************
6888 Get a lock count, dealing with large count requests.
6889 ****************************************************************************/
6891 uint64_t get_lock_count(const uint8_t *data, int data_offset,
6892 bool large_file_format)
6894 uint64_t count = 0;
6896 if(!large_file_format) {
6897 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
6898 } else {
6900 #if defined(HAVE_LONGLONG)
6901 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
6902 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
6903 #else /* HAVE_LONGLONG */
6906 * NT4.x seems to be broken in that it sends large file (64 bit)
6907 * lockingX calls even if the CAP_LARGE_FILES was *not*
6908 * negotiated. For boxes without large unsigned ints truncate the
6909 * lock count by dropping the top 32 bits.
6912 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
6913 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
6914 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
6915 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
6916 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
6919 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
6920 #endif /* HAVE_LONGLONG */
6923 return count;
6926 #if !defined(HAVE_LONGLONG)
6927 /****************************************************************************
6928 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
6929 ****************************************************************************/
6931 static uint32 map_lock_offset(uint32 high, uint32 low)
6933 unsigned int i;
6934 uint32 mask = 0;
6935 uint32 highcopy = high;
6938 * Try and find out how many significant bits there are in high.
6941 for(i = 0; highcopy; i++)
6942 highcopy >>= 1;
6945 * We use 31 bits not 32 here as POSIX
6946 * lock offsets may not be negative.
6949 mask = (~0) << (31 - i);
6951 if(low & mask)
6952 return 0; /* Fail. */
6954 high <<= (31 - i);
6956 return (high|low);
6958 #endif /* !defined(HAVE_LONGLONG) */
6960 /****************************************************************************
6961 Get a lock offset, dealing with large offset requests.
6962 ****************************************************************************/
6964 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
6965 bool large_file_format, bool *err)
6967 uint64_t offset = 0;
6969 *err = False;
6971 if(!large_file_format) {
6972 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
6973 } else {
6975 #if defined(HAVE_LONGLONG)
6976 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
6977 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
6978 #else /* HAVE_LONGLONG */
6981 * NT4.x seems to be broken in that it sends large file (64 bit)
6982 * lockingX calls even if the CAP_LARGE_FILES was *not*
6983 * negotiated. For boxes without large unsigned ints mangle the
6984 * lock offset by mapping the top 32 bits onto the lower 32.
6987 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
6988 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
6989 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
6990 uint32 new_low = 0;
6992 if((new_low = map_lock_offset(high, low)) == 0) {
6993 *err = True;
6994 return (uint64_t)-1;
6997 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
6998 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
6999 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7000 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7003 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7004 #endif /* HAVE_LONGLONG */
7007 return offset;
7010 NTSTATUS smbd_do_locking(struct smb_request *req,
7011 files_struct *fsp,
7012 uint8_t type,
7013 int32_t timeout,
7014 uint16_t num_ulocks,
7015 struct smbd_lock_element *ulocks,
7016 uint16_t num_locks,
7017 struct smbd_lock_element *locks,
7018 bool *async)
7020 connection_struct *conn = req->conn;
7021 int i;
7022 NTSTATUS status = NT_STATUS_OK;
7024 *async = false;
7026 /* Data now points at the beginning of the list
7027 of smb_unlkrng structs */
7028 for(i = 0; i < (int)num_ulocks; i++) {
7029 struct smbd_lock_element *e = &ulocks[i];
7031 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7032 "pid %u, file %s\n",
7033 (double)e->offset,
7034 (double)e->count,
7035 (unsigned int)e->smbpid,
7036 fsp_str_dbg(fsp)));
7038 if (e->brltype != UNLOCK_LOCK) {
7039 /* this can only happen with SMB2 */
7040 return NT_STATUS_INVALID_PARAMETER;
7043 status = do_unlock(smbd_messaging_context(),
7044 fsp,
7045 e->smbpid,
7046 e->count,
7047 e->offset,
7048 WINDOWS_LOCK);
7050 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7051 nt_errstr(status)));
7053 if (!NT_STATUS_IS_OK(status)) {
7054 return status;
7058 /* Setup the timeout in seconds. */
7060 if (!lp_blocking_locks(SNUM(conn))) {
7061 timeout = 0;
7064 /* Data now points at the beginning of the list
7065 of smb_lkrng structs */
7067 for(i = 0; i < (int)num_locks; i++) {
7068 struct smbd_lock_element *e = &locks[i];
7070 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for pid "
7071 "%u, file %s timeout = %d\n",
7072 (double)e->offset,
7073 (double)e->count,
7074 (unsigned int)e->smbpid,
7075 fsp_str_dbg(fsp),
7076 (int)timeout));
7078 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7079 struct blocking_lock_record *blr = NULL;
7081 if (num_locks > 1) {
7083 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7084 * if the lock vector contains one entry. When given mutliple cancel
7085 * requests in a single PDU we expect the server to return an
7086 * error. Windows servers seem to accept the request but only
7087 * cancel the first lock.
7088 * JRA - Do what Windows does (tm) :-).
7091 #if 0
7092 /* MS-CIFS (2.2.4.32.1) behavior. */
7093 return NT_STATUS_DOS(ERRDOS,
7094 ERRcancelviolation);
7095 #else
7096 /* Windows behavior. */
7097 if (i != 0) {
7098 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7099 "cancel request\n"));
7100 continue;
7102 #endif
7105 if (lp_blocking_locks(SNUM(conn))) {
7107 /* Schedule a message to ourselves to
7108 remove the blocking lock record and
7109 return the right error. */
7111 blr = blocking_lock_cancel(fsp,
7112 e->smbpid,
7113 e->offset,
7114 e->count,
7115 WINDOWS_LOCK,
7116 type,
7117 NT_STATUS_FILE_LOCK_CONFLICT);
7118 if (blr == NULL) {
7119 return NT_STATUS_DOS(
7120 ERRDOS,
7121 ERRcancelviolation);
7124 /* Remove a matching pending lock. */
7125 status = do_lock_cancel(fsp,
7126 e->smbpid,
7127 e->count,
7128 e->offset,
7129 WINDOWS_LOCK,
7130 blr);
7131 } else {
7132 bool blocking_lock = timeout ? true : false;
7133 bool defer_lock = false;
7134 struct byte_range_lock *br_lck;
7135 uint32_t block_smbpid;
7137 br_lck = do_lock(smbd_messaging_context(),
7138 fsp,
7139 e->smbpid,
7140 e->count,
7141 e->offset,
7142 e->brltype,
7143 WINDOWS_LOCK,
7144 blocking_lock,
7145 &status,
7146 &block_smbpid,
7147 NULL);
7149 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7150 /* Windows internal resolution for blocking locks seems
7151 to be about 200ms... Don't wait for less than that. JRA. */
7152 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7153 timeout = lp_lock_spin_time();
7155 defer_lock = true;
7158 /* If a lock sent with timeout of zero would fail, and
7159 * this lock has been requested multiple times,
7160 * according to brl_lock_failed() we convert this
7161 * request to a blocking lock with a timeout of between
7162 * 150 - 300 milliseconds.
7164 * If lp_lock_spin_time() has been set to 0, we skip
7165 * this blocking retry and fail immediately.
7167 * Replacement for do_lock_spin(). JRA. */
7169 if (br_lck && lp_blocking_locks(SNUM(conn)) &&
7170 lp_lock_spin_time() && !blocking_lock &&
7171 NT_STATUS_EQUAL((status),
7172 NT_STATUS_FILE_LOCK_CONFLICT))
7174 defer_lock = true;
7175 timeout = lp_lock_spin_time();
7178 if (br_lck && defer_lock) {
7180 * A blocking lock was requested. Package up
7181 * this smb into a queued request and push it
7182 * onto the blocking lock queue.
7184 if(push_blocking_lock_request(br_lck,
7185 req,
7186 fsp,
7187 timeout,
7189 e->smbpid,
7190 e->brltype,
7191 WINDOWS_LOCK,
7192 e->offset,
7193 e->count,
7194 block_smbpid)) {
7195 TALLOC_FREE(br_lck);
7196 *async = true;
7197 return NT_STATUS_OK;
7201 TALLOC_FREE(br_lck);
7204 if (!NT_STATUS_IS_OK(status)) {
7205 break;
7209 /* If any of the above locks failed, then we must unlock
7210 all of the previous locks (X/Open spec). */
7212 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7214 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7215 i = -1; /* we want to skip the for loop */
7219 * Ensure we don't do a remove on the lock that just failed,
7220 * as under POSIX rules, if we have a lock already there, we
7221 * will delete it (and we shouldn't) .....
7223 for(i--; i >= 0; i--) {
7224 struct smbd_lock_element *e = &locks[i];
7226 do_unlock(smbd_messaging_context(),
7227 fsp,
7228 e->smbpid,
7229 e->count,
7230 e->offset,
7231 WINDOWS_LOCK);
7233 return status;
7236 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7237 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7239 return NT_STATUS_OK;
7242 /****************************************************************************
7243 Reply to a lockingX request.
7244 ****************************************************************************/
7246 void reply_lockingX(struct smb_request *req)
7248 connection_struct *conn = req->conn;
7249 files_struct *fsp;
7250 unsigned char locktype;
7251 unsigned char oplocklevel;
7252 uint16 num_ulocks;
7253 uint16 num_locks;
7254 int32 lock_timeout;
7255 int i;
7256 const uint8_t *data;
7257 bool large_file_format;
7258 bool err;
7259 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7260 struct smbd_lock_element *ulocks;
7261 struct smbd_lock_element *locks;
7262 bool async = false;
7264 START_PROFILE(SMBlockingX);
7266 if (req->wct < 8) {
7267 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7268 END_PROFILE(SMBlockingX);
7269 return;
7272 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7273 locktype = CVAL(req->vwv+3, 0);
7274 oplocklevel = CVAL(req->vwv+3, 1);
7275 num_ulocks = SVAL(req->vwv+6, 0);
7276 num_locks = SVAL(req->vwv+7, 0);
7277 lock_timeout = IVAL(req->vwv+4, 0);
7278 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7280 if (!check_fsp(conn, req, fsp)) {
7281 END_PROFILE(SMBlockingX);
7282 return;
7285 data = req->buf;
7287 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7288 /* we don't support these - and CANCEL_LOCK makes w2k
7289 and XP reboot so I don't really want to be
7290 compatible! (tridge) */
7291 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7292 END_PROFILE(SMBlockingX);
7293 return;
7296 /* Check if this is an oplock break on a file
7297 we have granted an oplock on.
7299 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7300 /* Client can insist on breaking to none. */
7301 bool break_to_none = (oplocklevel == 0);
7302 bool result;
7304 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7305 "for fnum = %d\n", (unsigned int)oplocklevel,
7306 fsp->fnum ));
7309 * Make sure we have granted an exclusive or batch oplock on
7310 * this file.
7313 if (fsp->oplock_type == 0) {
7315 /* The Samba4 nbench simulator doesn't understand
7316 the difference between break to level2 and break
7317 to none from level2 - it sends oplock break
7318 replies in both cases. Don't keep logging an error
7319 message here - just ignore it. JRA. */
7321 DEBUG(5,("reply_lockingX: Error : oplock break from "
7322 "client for fnum = %d (oplock=%d) and no "
7323 "oplock granted on this file (%s).\n",
7324 fsp->fnum, fsp->oplock_type,
7325 fsp_str_dbg(fsp)));
7327 /* if this is a pure oplock break request then don't
7328 * send a reply */
7329 if (num_locks == 0 && num_ulocks == 0) {
7330 END_PROFILE(SMBlockingX);
7331 return;
7332 } else {
7333 END_PROFILE(SMBlockingX);
7334 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7335 return;
7339 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7340 (break_to_none)) {
7341 result = remove_oplock(fsp);
7342 } else {
7343 result = downgrade_oplock(fsp);
7346 if (!result) {
7347 DEBUG(0, ("reply_lockingX: error in removing "
7348 "oplock on file %s\n", fsp_str_dbg(fsp)));
7349 /* Hmmm. Is this panic justified? */
7350 smb_panic("internal tdb error");
7353 reply_to_oplock_break_requests(fsp);
7355 /* if this is a pure oplock break request then don't send a
7356 * reply */
7357 if (num_locks == 0 && num_ulocks == 0) {
7358 /* Sanity check - ensure a pure oplock break is not a
7359 chained request. */
7360 if(CVAL(req->vwv+0, 0) != 0xff)
7361 DEBUG(0,("reply_lockingX: Error : pure oplock "
7362 "break is a chained %d request !\n",
7363 (unsigned int)CVAL(req->vwv+0, 0)));
7364 END_PROFILE(SMBlockingX);
7365 return;
7369 if (req->buflen <
7370 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7371 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7372 END_PROFILE(SMBlockingX);
7373 return;
7376 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7377 if (ulocks == NULL) {
7378 reply_nterror(req, NT_STATUS_NO_MEMORY);
7379 END_PROFILE(SMBlockingX);
7380 return;
7383 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7384 if (locks == NULL) {
7385 reply_nterror(req, NT_STATUS_NO_MEMORY);
7386 END_PROFILE(SMBlockingX);
7387 return;
7390 /* Data now points at the beginning of the list
7391 of smb_unlkrng structs */
7392 for(i = 0; i < (int)num_ulocks; i++) {
7393 ulocks[i].smbpid = get_lock_pid(data, i, large_file_format);
7394 ulocks[i].count = get_lock_count(data, i, large_file_format);
7395 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7396 ulocks[i].brltype = UNLOCK_LOCK;
7399 * There is no error code marked "stupid client bug".... :-).
7401 if(err) {
7402 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7403 END_PROFILE(SMBlockingX);
7404 return;
7408 /* Now do any requested locks */
7409 data += ((large_file_format ? 20 : 10)*num_ulocks);
7411 /* Data now points at the beginning of the list
7412 of smb_lkrng structs */
7414 for(i = 0; i < (int)num_locks; i++) {
7415 locks[i].smbpid = get_lock_pid(data, i, large_file_format);
7416 locks[i].count = get_lock_count(data, i, large_file_format);
7417 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7419 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7420 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7421 locks[i].brltype = PENDING_READ_LOCK;
7422 } else {
7423 locks[i].brltype = READ_LOCK;
7425 } else {
7426 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7427 locks[i].brltype = PENDING_WRITE_LOCK;
7428 } else {
7429 locks[i].brltype = WRITE_LOCK;
7434 * There is no error code marked "stupid client bug".... :-).
7436 if(err) {
7437 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7438 END_PROFILE(SMBlockingX);
7439 return;
7443 status = smbd_do_locking(req, fsp,
7444 locktype, lock_timeout,
7445 num_ulocks, ulocks,
7446 num_locks, locks,
7447 &async);
7448 if (!NT_STATUS_IS_OK(status)) {
7449 END_PROFILE(SMBlockingX);
7450 reply_nterror(req, status);
7451 return;
7453 if (async) {
7454 END_PROFILE(SMBlockingX);
7455 return;
7458 reply_outbuf(req, 2, 0);
7460 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7461 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7463 END_PROFILE(SMBlockingX);
7464 chain_reply(req);
7467 #undef DBGC_CLASS
7468 #define DBGC_CLASS DBGC_ALL
7470 /****************************************************************************
7471 Reply to a SMBreadbmpx (read block multiplex) request.
7472 Always reply with an error, if someone has a platform really needs this,
7473 please contact vl@samba.org
7474 ****************************************************************************/
7476 void reply_readbmpx(struct smb_request *req)
7478 START_PROFILE(SMBreadBmpx);
7479 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7480 END_PROFILE(SMBreadBmpx);
7481 return;
7484 /****************************************************************************
7485 Reply to a SMBreadbs (read block multiplex secondary) request.
7486 Always reply with an error, if someone has a platform really needs this,
7487 please contact vl@samba.org
7488 ****************************************************************************/
7490 void reply_readbs(struct smb_request *req)
7492 START_PROFILE(SMBreadBs);
7493 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7494 END_PROFILE(SMBreadBs);
7495 return;
7498 /****************************************************************************
7499 Reply to a SMBsetattrE.
7500 ****************************************************************************/
7502 void reply_setattrE(struct smb_request *req)
7504 connection_struct *conn = req->conn;
7505 struct smb_file_time ft;
7506 files_struct *fsp;
7507 NTSTATUS status;
7509 START_PROFILE(SMBsetattrE);
7510 ZERO_STRUCT(ft);
7512 if (req->wct < 7) {
7513 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7514 goto out;
7517 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7519 if(!fsp || (fsp->conn != conn)) {
7520 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7521 goto out;
7525 * Convert the DOS times into unix times.
7528 ft.atime = convert_time_t_to_timespec(
7529 srv_make_unix_date2(req->vwv+3));
7530 ft.mtime = convert_time_t_to_timespec(
7531 srv_make_unix_date2(req->vwv+5));
7532 ft.create_time = convert_time_t_to_timespec(
7533 srv_make_unix_date2(req->vwv+1));
7535 reply_outbuf(req, 0, 0);
7538 * Patch from Ray Frush <frush@engr.colostate.edu>
7539 * Sometimes times are sent as zero - ignore them.
7542 /* Ensure we have a valid stat struct for the source. */
7543 status = vfs_stat_fsp(fsp);
7544 if (!NT_STATUS_IS_OK(status)) {
7545 reply_nterror(req, status);
7546 goto out;
7549 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7550 if (!NT_STATUS_IS_OK(status)) {
7551 reply_nterror(req, status);
7552 goto out;
7555 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7556 " createtime=%u\n",
7557 fsp->fnum,
7558 (unsigned int)ft.atime.tv_sec,
7559 (unsigned int)ft.mtime.tv_sec,
7560 (unsigned int)ft.create_time.tv_sec
7562 out:
7563 END_PROFILE(SMBsetattrE);
7564 return;
7568 /* Back from the dead for OS/2..... JRA. */
7570 /****************************************************************************
7571 Reply to a SMBwritebmpx (write block multiplex primary) request.
7572 Always reply with an error, if someone has a platform really needs this,
7573 please contact vl@samba.org
7574 ****************************************************************************/
7576 void reply_writebmpx(struct smb_request *req)
7578 START_PROFILE(SMBwriteBmpx);
7579 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7580 END_PROFILE(SMBwriteBmpx);
7581 return;
7584 /****************************************************************************
7585 Reply to a SMBwritebs (write block multiplex secondary) request.
7586 Always reply with an error, if someone has a platform really needs this,
7587 please contact vl@samba.org
7588 ****************************************************************************/
7590 void reply_writebs(struct smb_request *req)
7592 START_PROFILE(SMBwriteBs);
7593 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7594 END_PROFILE(SMBwriteBs);
7595 return;
7598 /****************************************************************************
7599 Reply to a SMBgetattrE.
7600 ****************************************************************************/
7602 void reply_getattrE(struct smb_request *req)
7604 connection_struct *conn = req->conn;
7605 int mode;
7606 files_struct *fsp;
7607 struct timespec create_ts;
7609 START_PROFILE(SMBgetattrE);
7611 if (req->wct < 1) {
7612 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7613 END_PROFILE(SMBgetattrE);
7614 return;
7617 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7619 if(!fsp || (fsp->conn != conn)) {
7620 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7621 END_PROFILE(SMBgetattrE);
7622 return;
7625 /* Do an fstat on this file */
7626 if(fsp_stat(fsp)) {
7627 reply_nterror(req, map_nt_error_from_unix(errno));
7628 END_PROFILE(SMBgetattrE);
7629 return;
7632 mode = dos_mode(conn, fsp->fsp_name);
7635 * Convert the times into dos times. Set create
7636 * date to be last modify date as UNIX doesn't save
7637 * this.
7640 reply_outbuf(req, 11, 0);
7642 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7643 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7644 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7645 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
7646 /* Should we check pending modtime here ? JRA */
7647 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7648 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
7650 if (mode & aDIR) {
7651 SIVAL(req->outbuf, smb_vwv6, 0);
7652 SIVAL(req->outbuf, smb_vwv8, 0);
7653 } else {
7654 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
7655 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
7656 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7658 SSVAL(req->outbuf,smb_vwv10, mode);
7660 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7662 END_PROFILE(SMBgetattrE);
7663 return;