s3: Use tevent_req_nterror properly in a few places
[Samba.git] / source3 / smbd / reply.c
blob96595223a60ad2b08f6a5b77d43d873bff3ef359
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 "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "rpc_client/cli_spoolss.h"
36 #include "rpc_client/init_spoolss.h"
37 #include "rpc_server/rpc_ncacn_np.h"
38 #include "libcli/security/security.h"
39 #include "libsmb/nmblib.h"
40 #include "auth.h"
41 #include "smbprofile.h"
43 /****************************************************************************
44 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
45 path or anything including wildcards.
46 We're assuming here that '/' is not the second byte in any multibyte char
47 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
48 set.
49 ****************************************************************************/
51 /* Custom version for processing POSIX paths. */
52 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
54 static NTSTATUS check_path_syntax_internal(char *path,
55 bool posix_path,
56 bool *p_last_component_contains_wcard)
58 char *d = path;
59 const char *s = path;
60 NTSTATUS ret = NT_STATUS_OK;
61 bool start_of_name_component = True;
62 bool stream_started = false;
64 *p_last_component_contains_wcard = False;
66 while (*s) {
67 if (stream_started) {
68 switch (*s) {
69 case '/':
70 case '\\':
71 return NT_STATUS_OBJECT_NAME_INVALID;
72 case ':':
73 if (s[1] == '\0') {
74 return NT_STATUS_OBJECT_NAME_INVALID;
76 if (strchr_m(&s[1], ':')) {
77 return NT_STATUS_OBJECT_NAME_INVALID;
79 break;
83 if ((*s == ':') && !posix_path && !stream_started) {
84 if (*p_last_component_contains_wcard) {
85 return NT_STATUS_OBJECT_NAME_INVALID;
87 /* Stream names allow more characters than file names.
88 We're overloading posix_path here to allow a wider
89 range of characters. If stream_started is true this
90 is still a Windows path even if posix_path is true.
91 JRA.
93 stream_started = true;
94 start_of_name_component = false;
95 posix_path = true;
97 if (s[1] == '\0') {
98 return NT_STATUS_OBJECT_NAME_INVALID;
102 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
104 * Safe to assume is not the second part of a mb char
105 * as this is handled below.
107 /* Eat multiple '/' or '\\' */
108 while (IS_PATH_SEP(*s,posix_path)) {
109 s++;
111 if ((d != path) && (*s != '\0')) {
112 /* We only care about non-leading or trailing '/' or '\\' */
113 *d++ = '/';
116 start_of_name_component = True;
117 /* New component. */
118 *p_last_component_contains_wcard = False;
119 continue;
122 if (start_of_name_component) {
123 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
124 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
127 * No mb char starts with '.' so we're safe checking the directory separator here.
130 /* If we just added a '/' - delete it */
131 if ((d > path) && (*(d-1) == '/')) {
132 *(d-1) = '\0';
133 d--;
136 /* Are we at the start ? Can't go back further if so. */
137 if (d <= path) {
138 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
139 break;
141 /* Go back one level... */
142 /* We know this is safe as '/' cannot be part of a mb sequence. */
143 /* NOTE - if this assumption is invalid we are not in good shape... */
144 /* Decrement d first as d points to the *next* char to write into. */
145 for (d--; d > path; d--) {
146 if (*d == '/')
147 break;
149 s += 2; /* Else go past the .. */
150 /* We're still at the start of a name component, just the previous one. */
151 continue;
153 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
154 if (posix_path) {
155 /* Eat the '.' */
156 s++;
157 continue;
163 if (!(*s & 0x80)) {
164 if (!posix_path) {
165 if (*s <= 0x1f || *s == '|') {
166 return NT_STATUS_OBJECT_NAME_INVALID;
168 switch (*s) {
169 case '*':
170 case '?':
171 case '<':
172 case '>':
173 case '"':
174 *p_last_component_contains_wcard = True;
175 break;
176 default:
177 break;
180 *d++ = *s++;
181 } else {
182 size_t siz;
183 /* Get the size of the next MB character. */
184 next_codepoint(s,&siz);
185 switch(siz) {
186 case 5:
187 *d++ = *s++;
188 /*fall through*/
189 case 4:
190 *d++ = *s++;
191 /*fall through*/
192 case 3:
193 *d++ = *s++;
194 /*fall through*/
195 case 2:
196 *d++ = *s++;
197 /*fall through*/
198 case 1:
199 *d++ = *s++;
200 break;
201 default:
202 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
203 *d = '\0';
204 return NT_STATUS_INVALID_PARAMETER;
207 start_of_name_component = False;
210 *d = '\0';
212 return ret;
215 /****************************************************************************
216 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
217 No wildcards allowed.
218 ****************************************************************************/
220 NTSTATUS check_path_syntax(char *path)
222 bool ignore;
223 return check_path_syntax_internal(path, False, &ignore);
226 /****************************************************************************
227 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
228 Wildcards allowed - p_contains_wcard returns true if the last component contained
229 a wildcard.
230 ****************************************************************************/
232 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
234 return check_path_syntax_internal(path, False, p_contains_wcard);
237 /****************************************************************************
238 Check the path for a POSIX client.
239 We're assuming here that '/' is not the second byte in any multibyte char
240 set (a safe assumption).
241 ****************************************************************************/
243 NTSTATUS check_path_syntax_posix(char *path)
245 bool ignore;
246 return check_path_syntax_internal(path, True, &ignore);
249 /****************************************************************************
250 Pull a string and check the path allowing a wilcard - provide for error return.
251 ****************************************************************************/
253 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
254 const char *base_ptr,
255 uint16 smb_flags2,
256 char **pp_dest,
257 const char *src,
258 size_t src_len,
259 int flags,
260 NTSTATUS *err,
261 bool *contains_wcard)
263 size_t ret;
265 *pp_dest = NULL;
267 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
268 src_len, flags);
270 if (!*pp_dest) {
271 *err = NT_STATUS_INVALID_PARAMETER;
272 return ret;
275 *contains_wcard = False;
277 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
279 * For a DFS path the function parse_dfs_path()
280 * will do the path processing, just make a copy.
282 *err = NT_STATUS_OK;
283 return ret;
286 if (lp_posix_pathnames()) {
287 *err = check_path_syntax_posix(*pp_dest);
288 } else {
289 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
292 return ret;
295 /****************************************************************************
296 Pull a string and check the path - provide for error return.
297 ****************************************************************************/
299 size_t srvstr_get_path(TALLOC_CTX *ctx,
300 const char *base_ptr,
301 uint16 smb_flags2,
302 char **pp_dest,
303 const char *src,
304 size_t src_len,
305 int flags,
306 NTSTATUS *err)
308 bool ignore;
309 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
310 src_len, flags, err, &ignore);
313 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
314 char **pp_dest, const char *src, int flags,
315 NTSTATUS *err, bool *contains_wcard)
317 return srvstr_get_path_wcard(mem_ctx, (char *)req->inbuf, req->flags2,
318 pp_dest, src, smbreq_bufrem(req, src),
319 flags, err, contains_wcard);
322 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
323 char **pp_dest, const char *src, int flags,
324 NTSTATUS *err)
326 bool ignore;
327 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
328 flags, err, &ignore);
331 /****************************************************************************
332 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
333 ****************************************************************************/
335 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
336 files_struct *fsp)
338 if ((fsp == NULL) || (conn == NULL)) {
339 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
340 return False;
342 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
343 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
344 return False;
346 return True;
349 /****************************************************************************
350 Check if we have a correct fsp pointing to a file.
351 ****************************************************************************/
353 bool check_fsp(connection_struct *conn, struct smb_request *req,
354 files_struct *fsp)
356 if (!check_fsp_open(conn, req, fsp)) {
357 return False;
359 if (fsp->is_directory) {
360 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
361 return False;
363 if (fsp->fh->fd == -1) {
364 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
365 return False;
367 fsp->num_smb_operations++;
368 return True;
371 /****************************************************************************
372 Check if we have a correct fsp pointing to a quota fake file. Replacement for
373 the CHECK_NTQUOTA_HANDLE_OK macro.
374 ****************************************************************************/
376 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
377 files_struct *fsp)
379 if (!check_fsp_open(conn, req, fsp)) {
380 return false;
383 if (fsp->is_directory) {
384 return false;
387 if (fsp->fake_file_handle == NULL) {
388 return false;
391 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
392 return false;
395 if (fsp->fake_file_handle->private_data == NULL) {
396 return false;
399 return true;
402 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
403 const char *name, int name_type)
405 char *trim_name;
406 char *trim_name_type;
407 const char *retarget_parm;
408 char *retarget;
409 char *p;
410 int retarget_type = 0x20;
411 int retarget_port = 139;
412 struct sockaddr_storage retarget_addr;
413 struct sockaddr_in *in_addr;
414 bool ret = false;
415 uint8_t outbuf[10];
417 if (get_socket_port(sconn->sock) != 139) {
418 return false;
421 trim_name = talloc_strdup(talloc_tos(), name);
422 if (trim_name == NULL) {
423 goto fail;
425 trim_char(trim_name, ' ', ' ');
427 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
428 name_type);
429 if (trim_name_type == NULL) {
430 goto fail;
433 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
434 trim_name_type, NULL);
435 if (retarget_parm == NULL) {
436 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
437 trim_name, NULL);
439 if (retarget_parm == NULL) {
440 goto fail;
443 retarget = talloc_strdup(trim_name, retarget_parm);
444 if (retarget == NULL) {
445 goto fail;
448 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
450 p = strchr(retarget, ':');
451 if (p != NULL) {
452 *p++ = '\0';
453 retarget_port = atoi(p);
456 p = strchr_m(retarget, '#');
457 if (p != NULL) {
458 *p++ = '\0';
459 sscanf(p, "%x", &retarget_type);
462 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
463 if (!ret) {
464 DEBUG(10, ("could not resolve %s\n", retarget));
465 goto fail;
468 if (retarget_addr.ss_family != AF_INET) {
469 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
470 goto fail;
473 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
475 _smb_setlen(outbuf, 6);
476 SCVAL(outbuf, 0, 0x84);
477 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
478 *(uint16_t *)(outbuf+8) = htons(retarget_port);
480 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
481 NULL)) {
482 exit_server_cleanly("netbios_session_regarget: srv_send_smb "
483 "failed.");
486 ret = true;
487 fail:
488 TALLOC_FREE(trim_name);
489 return ret;
492 /****************************************************************************
493 Reply to a (netbios-level) special message.
494 ****************************************************************************/
496 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
498 int msg_type = CVAL(inbuf,0);
499 int msg_flags = CVAL(inbuf,1);
501 * We only really use 4 bytes of the outbuf, but for the smb_setlen
502 * calculation & friends (srv_send_smb uses that) we need the full smb
503 * header.
505 char outbuf[smb_size];
507 memset(outbuf, '\0', sizeof(outbuf));
509 smb_setlen(outbuf,0);
511 switch (msg_type) {
512 case 0x81: /* session request */
514 /* inbuf_size is guarenteed to be at least 4. */
515 fstring name1,name2;
516 int name_type1, name_type2;
517 int name_len1, name_len2;
519 *name1 = *name2 = 0;
521 if (sconn->nbt.got_session) {
522 exit_server_cleanly("multiple session request not permitted");
525 SCVAL(outbuf,0,0x82);
526 SCVAL(outbuf,3,0);
528 /* inbuf_size is guaranteed to be at least 4. */
529 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
530 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
531 DEBUG(0,("Invalid name length in session request\n"));
532 break;
534 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
535 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
536 DEBUG(0,("Invalid name length in session request\n"));
537 break;
540 name_type1 = name_extract((unsigned char *)inbuf,
541 inbuf_size,(unsigned int)4,name1);
542 name_type2 = name_extract((unsigned char *)inbuf,
543 inbuf_size,(unsigned int)(4 + name_len1),name2);
545 if (name_type1 == -1 || name_type2 == -1) {
546 DEBUG(0,("Invalid name type in session request\n"));
547 break;
550 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
551 name1, name_type1, name2, name_type2));
553 if (netbios_session_retarget(sconn, name1, name_type1)) {
554 exit_server_cleanly("retargeted client");
558 * Windows NT/2k uses "*SMBSERVER" and XP uses
559 * "*SMBSERV" arrggg!!!
561 if (strequal(name1, "*SMBSERVER ")
562 || strequal(name1, "*SMBSERV ")) {
563 fstrcpy(name1, sconn->client_id.addr);
566 set_local_machine_name(name1, True);
567 set_remote_machine_name(name2, True);
569 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
570 get_local_machine_name(), get_remote_machine_name(),
571 name_type2));
573 if (name_type2 == 'R') {
574 /* We are being asked for a pathworks session ---
575 no thanks! */
576 SCVAL(outbuf, 0,0x83);
577 break;
580 /* only add the client's machine name to the list
581 of possibly valid usernames if we are operating
582 in share mode security */
583 if (lp_security() == SEC_SHARE) {
584 add_session_user(sconn, get_remote_machine_name());
587 reload_services(sconn->msg_ctx, sconn->sock, True);
588 reopen_logs();
590 sconn->nbt.got_session = true;
591 break;
594 case 0x89: /* session keepalive request
595 (some old clients produce this?) */
596 SCVAL(outbuf,0,SMBkeepalive);
597 SCVAL(outbuf,3,0);
598 break;
600 case 0x82: /* positive session response */
601 case 0x83: /* negative session response */
602 case 0x84: /* retarget session response */
603 DEBUG(0,("Unexpected session response\n"));
604 break;
606 case SMBkeepalive: /* session keepalive */
607 default:
608 return;
611 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
612 msg_type, msg_flags));
614 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
615 return;
618 /****************************************************************************
619 Reply to a tcon.
620 conn POINTER CAN BE NULL HERE !
621 ****************************************************************************/
623 void reply_tcon(struct smb_request *req)
625 connection_struct *conn = req->conn;
626 const char *service;
627 char *service_buf = NULL;
628 char *password = NULL;
629 char *dev = NULL;
630 int pwlen=0;
631 NTSTATUS nt_status;
632 const char *p;
633 DATA_BLOB password_blob;
634 TALLOC_CTX *ctx = talloc_tos();
635 struct smbd_server_connection *sconn = req->sconn;
637 START_PROFILE(SMBtcon);
639 if (req->buflen < 4) {
640 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
641 END_PROFILE(SMBtcon);
642 return;
645 p = (const char *)req->buf + 1;
646 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
647 p += 1;
648 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
649 p += pwlen+1;
650 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
651 p += 1;
653 if (service_buf == NULL || password == NULL || dev == NULL) {
654 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
655 END_PROFILE(SMBtcon);
656 return;
658 p = strrchr_m(service_buf,'\\');
659 if (p) {
660 service = p+1;
661 } else {
662 service = service_buf;
665 password_blob = data_blob(password, pwlen+1);
667 conn = make_connection(sconn,service,password_blob,dev,
668 req->vuid,&nt_status);
669 req->conn = conn;
671 data_blob_clear_free(&password_blob);
673 if (!conn) {
674 reply_nterror(req, nt_status);
675 END_PROFILE(SMBtcon);
676 return;
679 reply_outbuf(req, 2, 0);
680 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
681 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
682 SSVAL(req->outbuf,smb_tid,conn->cnum);
684 DEBUG(3,("tcon service=%s cnum=%d\n",
685 service, conn->cnum));
687 END_PROFILE(SMBtcon);
688 return;
691 /****************************************************************************
692 Reply to a tcon and X.
693 conn POINTER CAN BE NULL HERE !
694 ****************************************************************************/
696 void reply_tcon_and_X(struct smb_request *req)
698 connection_struct *conn = req->conn;
699 const char *service = NULL;
700 DATA_BLOB password;
701 TALLOC_CTX *ctx = talloc_tos();
702 /* what the cleint thinks the device is */
703 char *client_devicetype = NULL;
704 /* what the server tells the client the share represents */
705 const char *server_devicetype;
706 NTSTATUS nt_status;
707 int passlen;
708 char *path = NULL;
709 const char *p, *q;
710 uint16 tcon_flags;
711 struct smbd_server_connection *sconn = req->sconn;
713 START_PROFILE(SMBtconX);
715 if (req->wct < 4) {
716 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
717 END_PROFILE(SMBtconX);
718 return;
721 passlen = SVAL(req->vwv+3, 0);
722 tcon_flags = SVAL(req->vwv+2, 0);
724 /* we might have to close an old one */
725 if ((tcon_flags & 0x1) && conn) {
726 close_cnum(conn,req->vuid);
727 req->conn = NULL;
728 conn = NULL;
731 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
732 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
733 END_PROFILE(SMBtconX);
734 return;
737 if (sconn->smb1.negprot.encrypted_passwords) {
738 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
739 if (lp_security() == SEC_SHARE) {
741 * Security = share always has a pad byte
742 * after the password.
744 p = (const char *)req->buf + passlen + 1;
745 } else {
746 p = (const char *)req->buf + passlen;
748 } else {
749 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
750 /* Ensure correct termination */
751 password.data[passlen]=0;
752 p = (const char *)req->buf + passlen + 1;
755 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
757 if (path == NULL) {
758 data_blob_clear_free(&password);
759 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
760 END_PROFILE(SMBtconX);
761 return;
765 * the service name can be either: \\server\share
766 * or share directly like on the DELL PowerVault 705
768 if (*path=='\\') {
769 q = strchr_m(path+2,'\\');
770 if (!q) {
771 data_blob_clear_free(&password);
772 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
773 END_PROFILE(SMBtconX);
774 return;
776 service = q+1;
777 } else {
778 service = path;
781 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
782 &client_devicetype, p,
783 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
785 if (client_devicetype == NULL) {
786 data_blob_clear_free(&password);
787 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
788 END_PROFILE(SMBtconX);
789 return;
792 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
794 conn = make_connection(sconn, service, password, client_devicetype,
795 req->vuid, &nt_status);
796 req->conn =conn;
798 data_blob_clear_free(&password);
800 if (!conn) {
801 reply_nterror(req, nt_status);
802 END_PROFILE(SMBtconX);
803 return;
806 if ( IS_IPC(conn) )
807 server_devicetype = "IPC";
808 else if ( IS_PRINT(conn) )
809 server_devicetype = "LPT1:";
810 else
811 server_devicetype = "A:";
813 if (get_Protocol() < PROTOCOL_NT1) {
814 reply_outbuf(req, 2, 0);
815 if (message_push_string(&req->outbuf, server_devicetype,
816 STR_TERMINATE|STR_ASCII) == -1) {
817 reply_nterror(req, NT_STATUS_NO_MEMORY);
818 END_PROFILE(SMBtconX);
819 return;
821 } else {
822 /* NT sets the fstype of IPC$ to the null string */
823 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
825 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
826 /* Return permissions. */
827 uint32 perm1 = 0;
828 uint32 perm2 = 0;
830 reply_outbuf(req, 7, 0);
832 if (IS_IPC(conn)) {
833 perm1 = FILE_ALL_ACCESS;
834 perm2 = FILE_ALL_ACCESS;
835 } else {
836 perm1 = CAN_WRITE(conn) ?
837 SHARE_ALL_ACCESS :
838 SHARE_READ_ONLY;
841 SIVAL(req->outbuf, smb_vwv3, perm1);
842 SIVAL(req->outbuf, smb_vwv5, perm2);
843 } else {
844 reply_outbuf(req, 3, 0);
847 if ((message_push_string(&req->outbuf, server_devicetype,
848 STR_TERMINATE|STR_ASCII) == -1)
849 || (message_push_string(&req->outbuf, fstype,
850 STR_TERMINATE) == -1)) {
851 reply_nterror(req, NT_STATUS_NO_MEMORY);
852 END_PROFILE(SMBtconX);
853 return;
856 /* what does setting this bit do? It is set by NT4 and
857 may affect the ability to autorun mounted cdroms */
858 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
859 (lp_csc_policy(SNUM(conn)) << 2));
861 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
862 DEBUG(2,("Serving %s as a Dfs root\n",
863 lp_servicename(SNUM(conn)) ));
864 SSVAL(req->outbuf, smb_vwv2,
865 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
870 DEBUG(3,("tconX service=%s \n",
871 service));
873 /* set the incoming and outgoing tid to the just created one */
874 SSVAL(req->inbuf,smb_tid,conn->cnum);
875 SSVAL(req->outbuf,smb_tid,conn->cnum);
877 END_PROFILE(SMBtconX);
879 req->tid = conn->cnum;
880 chain_reply(req);
881 return;
884 /****************************************************************************
885 Reply to an unknown type.
886 ****************************************************************************/
888 void reply_unknown_new(struct smb_request *req, uint8 type)
890 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
891 smb_fn_name(type), type, type));
892 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
893 return;
896 /****************************************************************************
897 Reply to an ioctl.
898 conn POINTER CAN BE NULL HERE !
899 ****************************************************************************/
901 void reply_ioctl(struct smb_request *req)
903 connection_struct *conn = req->conn;
904 uint16 device;
905 uint16 function;
906 uint32 ioctl_code;
907 int replysize;
908 char *p;
910 START_PROFILE(SMBioctl);
912 if (req->wct < 3) {
913 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
914 END_PROFILE(SMBioctl);
915 return;
918 device = SVAL(req->vwv+1, 0);
919 function = SVAL(req->vwv+2, 0);
920 ioctl_code = (device << 16) + function;
922 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
924 switch (ioctl_code) {
925 case IOCTL_QUERY_JOB_INFO:
926 replysize = 32;
927 break;
928 default:
929 reply_force_doserror(req, ERRSRV, ERRnosupport);
930 END_PROFILE(SMBioctl);
931 return;
934 reply_outbuf(req, 8, replysize+1);
935 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
936 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
937 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
938 p = smb_buf(req->outbuf);
939 memset(p, '\0', replysize+1); /* valgrind-safe. */
940 p += 1; /* Allow for alignment */
942 switch (ioctl_code) {
943 case IOCTL_QUERY_JOB_INFO:
945 files_struct *fsp = file_fsp(
946 req, SVAL(req->vwv+0, 0));
947 if (!fsp) {
948 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
949 END_PROFILE(SMBioctl);
950 return;
952 /* Job number */
953 if (fsp->print_file) {
954 SSVAL(p, 0, fsp->print_file->rap_jobid);
955 } else {
956 SSVAL(p, 0, 0);
958 srvstr_push((char *)req->outbuf, req->flags2, p+2,
959 global_myname(), 15,
960 STR_TERMINATE|STR_ASCII);
961 if (conn) {
962 srvstr_push((char *)req->outbuf, req->flags2,
963 p+18, lp_servicename(SNUM(conn)),
964 13, STR_TERMINATE|STR_ASCII);
965 } else {
966 memset(p+18, 0, 13);
968 break;
972 END_PROFILE(SMBioctl);
973 return;
976 /****************************************************************************
977 Strange checkpath NTSTATUS mapping.
978 ****************************************************************************/
980 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
982 /* Strange DOS error code semantics only for checkpath... */
983 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
984 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
985 /* We need to map to ERRbadpath */
986 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
989 return status;
992 /****************************************************************************
993 Reply to a checkpath.
994 ****************************************************************************/
996 void reply_checkpath(struct smb_request *req)
998 connection_struct *conn = req->conn;
999 struct smb_filename *smb_fname = NULL;
1000 char *name = NULL;
1001 NTSTATUS status;
1002 TALLOC_CTX *ctx = talloc_tos();
1004 START_PROFILE(SMBcheckpath);
1006 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1007 STR_TERMINATE, &status);
1009 if (!NT_STATUS_IS_OK(status)) {
1010 status = map_checkpath_error(req->flags2, status);
1011 reply_nterror(req, status);
1012 END_PROFILE(SMBcheckpath);
1013 return;
1016 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1018 status = filename_convert(ctx,
1019 conn,
1020 req->flags2 & FLAGS2_DFS_PATHNAMES,
1021 name,
1023 NULL,
1024 &smb_fname);
1026 if (!NT_STATUS_IS_OK(status)) {
1027 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1028 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1029 ERRSRV, ERRbadpath);
1030 END_PROFILE(SMBcheckpath);
1031 return;
1033 goto path_err;
1036 if (!VALID_STAT(smb_fname->st) &&
1037 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1038 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1039 smb_fname_str_dbg(smb_fname), strerror(errno)));
1040 status = map_nt_error_from_unix(errno);
1041 goto path_err;
1044 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1045 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1046 ERRDOS, ERRbadpath);
1047 goto out;
1050 reply_outbuf(req, 0, 0);
1052 path_err:
1053 /* We special case this - as when a Windows machine
1054 is parsing a path is steps through the components
1055 one at a time - if a component fails it expects
1056 ERRbadpath, not ERRbadfile.
1058 status = map_checkpath_error(req->flags2, status);
1059 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1061 * Windows returns different error codes if
1062 * the parent directory is valid but not the
1063 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1064 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1065 * if the path is invalid.
1067 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1068 ERRDOS, ERRbadpath);
1069 goto out;
1072 reply_nterror(req, status);
1074 out:
1075 TALLOC_FREE(smb_fname);
1076 END_PROFILE(SMBcheckpath);
1077 return;
1080 /****************************************************************************
1081 Reply to a getatr.
1082 ****************************************************************************/
1084 void reply_getatr(struct smb_request *req)
1086 connection_struct *conn = req->conn;
1087 struct smb_filename *smb_fname = NULL;
1088 char *fname = NULL;
1089 int mode=0;
1090 SMB_OFF_T size=0;
1091 time_t mtime=0;
1092 const char *p;
1093 NTSTATUS status;
1094 TALLOC_CTX *ctx = talloc_tos();
1095 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1097 START_PROFILE(SMBgetatr);
1099 p = (const char *)req->buf + 1;
1100 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1101 if (!NT_STATUS_IS_OK(status)) {
1102 reply_nterror(req, status);
1103 goto out;
1106 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1107 under WfWg - weird! */
1108 if (*fname == '\0') {
1109 mode = aHIDDEN | aDIR;
1110 if (!CAN_WRITE(conn)) {
1111 mode |= aRONLY;
1113 size = 0;
1114 mtime = 0;
1115 } else {
1116 status = filename_convert(ctx,
1117 conn,
1118 req->flags2 & FLAGS2_DFS_PATHNAMES,
1119 fname,
1121 NULL,
1122 &smb_fname);
1123 if (!NT_STATUS_IS_OK(status)) {
1124 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1125 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1126 ERRSRV, ERRbadpath);
1127 goto out;
1129 reply_nterror(req, status);
1130 goto out;
1132 if (!VALID_STAT(smb_fname->st) &&
1133 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1134 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1135 smb_fname_str_dbg(smb_fname),
1136 strerror(errno)));
1137 reply_nterror(req, map_nt_error_from_unix(errno));
1138 goto out;
1141 mode = dos_mode(conn, smb_fname);
1142 size = smb_fname->st.st_ex_size;
1144 if (ask_sharemode) {
1145 struct timespec write_time_ts;
1146 struct file_id fileid;
1148 ZERO_STRUCT(write_time_ts);
1149 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1150 get_file_infos(fileid, 0, NULL, &write_time_ts);
1151 if (!null_timespec(write_time_ts)) {
1152 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1156 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1157 if (mode & aDIR) {
1158 size = 0;
1162 reply_outbuf(req, 10, 0);
1164 SSVAL(req->outbuf,smb_vwv0,mode);
1165 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1166 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1167 } else {
1168 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1170 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1172 if (get_Protocol() >= PROTOCOL_NT1) {
1173 SSVAL(req->outbuf, smb_flg2,
1174 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1177 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1178 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1180 out:
1181 TALLOC_FREE(smb_fname);
1182 TALLOC_FREE(fname);
1183 END_PROFILE(SMBgetatr);
1184 return;
1187 /****************************************************************************
1188 Reply to a setatr.
1189 ****************************************************************************/
1191 void reply_setatr(struct smb_request *req)
1193 struct smb_file_time ft;
1194 connection_struct *conn = req->conn;
1195 struct smb_filename *smb_fname = NULL;
1196 char *fname = NULL;
1197 int mode;
1198 time_t mtime;
1199 const char *p;
1200 NTSTATUS status;
1201 TALLOC_CTX *ctx = talloc_tos();
1203 START_PROFILE(SMBsetatr);
1205 ZERO_STRUCT(ft);
1207 if (req->wct < 2) {
1208 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1209 goto out;
1212 p = (const char *)req->buf + 1;
1213 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 reply_nterror(req, status);
1216 goto out;
1219 status = filename_convert(ctx,
1220 conn,
1221 req->flags2 & FLAGS2_DFS_PATHNAMES,
1222 fname,
1224 NULL,
1225 &smb_fname);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1228 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1229 ERRSRV, ERRbadpath);
1230 goto out;
1232 reply_nterror(req, status);
1233 goto out;
1236 if (smb_fname->base_name[0] == '.' &&
1237 smb_fname->base_name[1] == '\0') {
1239 * Not sure here is the right place to catch this
1240 * condition. Might be moved to somewhere else later -- vl
1242 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1243 goto out;
1246 mode = SVAL(req->vwv+0, 0);
1247 mtime = srv_make_unix_date3(req->vwv+1);
1249 ft.mtime = convert_time_t_to_timespec(mtime);
1250 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 reply_nterror(req, status);
1253 goto out;
1256 if (mode != FILE_ATTRIBUTE_NORMAL) {
1257 if (VALID_STAT_OF_DIR(smb_fname->st))
1258 mode |= aDIR;
1259 else
1260 mode &= ~aDIR;
1262 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1263 false) != 0) {
1264 reply_nterror(req, map_nt_error_from_unix(errno));
1265 goto out;
1269 reply_outbuf(req, 0, 0);
1271 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1272 mode));
1273 out:
1274 TALLOC_FREE(smb_fname);
1275 END_PROFILE(SMBsetatr);
1276 return;
1279 /****************************************************************************
1280 Reply to a dskattr.
1281 ****************************************************************************/
1283 void reply_dskattr(struct smb_request *req)
1285 connection_struct *conn = req->conn;
1286 uint64_t dfree,dsize,bsize;
1287 START_PROFILE(SMBdskattr);
1289 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1290 reply_nterror(req, map_nt_error_from_unix(errno));
1291 END_PROFILE(SMBdskattr);
1292 return;
1295 reply_outbuf(req, 5, 0);
1297 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1298 double total_space, free_space;
1299 /* we need to scale this to a number that DOS6 can handle. We
1300 use floating point so we can handle large drives on systems
1301 that don't have 64 bit integers
1303 we end up displaying a maximum of 2G to DOS systems
1305 total_space = dsize * (double)bsize;
1306 free_space = dfree * (double)bsize;
1308 dsize = (uint64_t)((total_space+63*512) / (64*512));
1309 dfree = (uint64_t)((free_space+63*512) / (64*512));
1311 if (dsize > 0xFFFF) dsize = 0xFFFF;
1312 if (dfree > 0xFFFF) dfree = 0xFFFF;
1314 SSVAL(req->outbuf,smb_vwv0,dsize);
1315 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1316 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1317 SSVAL(req->outbuf,smb_vwv3,dfree);
1318 } else {
1319 SSVAL(req->outbuf,smb_vwv0,dsize);
1320 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1321 SSVAL(req->outbuf,smb_vwv2,512);
1322 SSVAL(req->outbuf,smb_vwv3,dfree);
1325 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1327 END_PROFILE(SMBdskattr);
1328 return;
1332 * Utility function to split the filename from the directory.
1334 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1335 char **fname_dir_out,
1336 char **fname_mask_out)
1338 const char *p = NULL;
1339 char *fname_dir = NULL;
1340 char *fname_mask = NULL;
1342 p = strrchr_m(fname_in, '/');
1343 if (!p) {
1344 fname_dir = talloc_strdup(ctx, ".");
1345 fname_mask = talloc_strdup(ctx, fname_in);
1346 } else {
1347 fname_dir = talloc_strndup(ctx, fname_in,
1348 PTR_DIFF(p, fname_in));
1349 fname_mask = talloc_strdup(ctx, p+1);
1352 if (!fname_dir || !fname_mask) {
1353 TALLOC_FREE(fname_dir);
1354 TALLOC_FREE(fname_mask);
1355 return NT_STATUS_NO_MEMORY;
1358 *fname_dir_out = fname_dir;
1359 *fname_mask_out = fname_mask;
1360 return NT_STATUS_OK;
1363 /****************************************************************************
1364 Reply to a search.
1365 Can be called from SMBsearch, SMBffirst or SMBfunique.
1366 ****************************************************************************/
1368 void reply_search(struct smb_request *req)
1370 connection_struct *conn = req->conn;
1371 char *path = NULL;
1372 const char *mask = NULL;
1373 char *directory = NULL;
1374 struct smb_filename *smb_fname = NULL;
1375 char *fname = NULL;
1376 SMB_OFF_T size;
1377 uint32 mode;
1378 struct timespec date;
1379 uint32 dirtype;
1380 unsigned int numentries = 0;
1381 unsigned int maxentries = 0;
1382 bool finished = False;
1383 const char *p;
1384 int status_len;
1385 char status[21];
1386 int dptr_num= -1;
1387 bool check_descend = False;
1388 bool expect_close = False;
1389 NTSTATUS nt_status;
1390 bool mask_contains_wcard = False;
1391 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1392 TALLOC_CTX *ctx = talloc_tos();
1393 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1394 struct dptr_struct *dirptr = NULL;
1395 struct smbd_server_connection *sconn = req->sconn;
1397 START_PROFILE(SMBsearch);
1399 if (req->wct < 2) {
1400 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1401 goto out;
1404 if (lp_posix_pathnames()) {
1405 reply_unknown_new(req, req->cmd);
1406 goto out;
1409 /* If we were called as SMBffirst then we must expect close. */
1410 if(req->cmd == SMBffirst) {
1411 expect_close = True;
1414 reply_outbuf(req, 1, 3);
1415 maxentries = SVAL(req->vwv+0, 0);
1416 dirtype = SVAL(req->vwv+1, 0);
1417 p = (const char *)req->buf + 1;
1418 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1419 &nt_status, &mask_contains_wcard);
1420 if (!NT_STATUS_IS_OK(nt_status)) {
1421 reply_nterror(req, nt_status);
1422 goto out;
1425 p++;
1426 status_len = SVAL(p, 0);
1427 p += 2;
1429 /* dirtype &= ~aDIR; */
1431 if (status_len == 0) {
1432 nt_status = filename_convert(ctx, conn,
1433 req->flags2 & FLAGS2_DFS_PATHNAMES,
1434 path,
1435 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1436 &mask_contains_wcard,
1437 &smb_fname);
1438 if (!NT_STATUS_IS_OK(nt_status)) {
1439 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1440 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1441 ERRSRV, ERRbadpath);
1442 goto out;
1444 reply_nterror(req, nt_status);
1445 goto out;
1448 directory = smb_fname->base_name;
1450 p = strrchr_m(directory,'/');
1451 if ((p != NULL) && (*directory != '/')) {
1452 mask = p + 1;
1453 directory = talloc_strndup(ctx, directory,
1454 PTR_DIFF(p, directory));
1455 } else {
1456 mask = directory;
1457 directory = talloc_strdup(ctx,".");
1460 if (!directory) {
1461 reply_nterror(req, NT_STATUS_NO_MEMORY);
1462 goto out;
1465 memset((char *)status,'\0',21);
1466 SCVAL(status,0,(dirtype & 0x1F));
1468 nt_status = dptr_create(conn,
1469 NULL, /* fsp */
1470 directory,
1471 True,
1472 expect_close,
1473 req->smbpid,
1474 mask,
1475 mask_contains_wcard,
1476 dirtype,
1477 &dirptr);
1478 if (!NT_STATUS_IS_OK(nt_status)) {
1479 reply_nterror(req, nt_status);
1480 goto out;
1482 dptr_num = dptr_dnum(dirptr);
1483 } else {
1484 int status_dirtype;
1485 const char *dirpath;
1487 memcpy(status,p,21);
1488 status_dirtype = CVAL(status,0) & 0x1F;
1489 if (status_dirtype != (dirtype & 0x1F)) {
1490 dirtype = status_dirtype;
1493 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1494 if (!dirptr) {
1495 goto SearchEmpty;
1497 dirpath = dptr_path(sconn, dptr_num);
1498 directory = talloc_strdup(ctx, dirpath);
1499 if (!directory) {
1500 reply_nterror(req, NT_STATUS_NO_MEMORY);
1501 goto out;
1504 mask = dptr_wcard(sconn, dptr_num);
1505 if (!mask) {
1506 goto SearchEmpty;
1509 * For a 'continue' search we have no string. So
1510 * check from the initial saved string.
1512 mask_contains_wcard = ms_has_wild(mask);
1513 dirtype = dptr_attr(sconn, dptr_num);
1516 DEBUG(4,("dptr_num is %d\n",dptr_num));
1518 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1519 dptr_init_search_op(dirptr);
1521 if ((dirtype&0x1F) == aVOLID) {
1522 char buf[DIR_STRUCT_SIZE];
1523 memcpy(buf,status,21);
1524 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1525 0,aVOLID,0,!allow_long_path_components)) {
1526 reply_nterror(req, NT_STATUS_NO_MEMORY);
1527 goto out;
1529 dptr_fill(sconn, buf+12,dptr_num);
1530 if (dptr_zero(buf+12) && (status_len==0)) {
1531 numentries = 1;
1532 } else {
1533 numentries = 0;
1535 if (message_push_blob(&req->outbuf,
1536 data_blob_const(buf, sizeof(buf)))
1537 == -1) {
1538 reply_nterror(req, NT_STATUS_NO_MEMORY);
1539 goto out;
1541 } else {
1542 unsigned int i;
1543 maxentries = MIN(
1544 maxentries,
1545 ((BUFFER_SIZE -
1546 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1547 /DIR_STRUCT_SIZE));
1549 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1550 directory,lp_dontdescend(SNUM(conn))));
1551 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1552 check_descend = True;
1555 for (i=numentries;(i<maxentries) && !finished;i++) {
1556 finished = !get_dir_entry(ctx,
1557 dirptr,
1558 mask,
1559 dirtype,
1560 &fname,
1561 &size,
1562 &mode,
1563 &date,
1564 check_descend,
1565 ask_sharemode);
1566 if (!finished) {
1567 char buf[DIR_STRUCT_SIZE];
1568 memcpy(buf,status,21);
1569 if (!make_dir_struct(ctx,
1570 buf,
1571 mask,
1572 fname,
1573 size,
1574 mode,
1575 convert_timespec_to_time_t(date),
1576 !allow_long_path_components)) {
1577 reply_nterror(req, NT_STATUS_NO_MEMORY);
1578 goto out;
1580 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1581 break;
1583 if (message_push_blob(&req->outbuf,
1584 data_blob_const(buf, sizeof(buf)))
1585 == -1) {
1586 reply_nterror(req, NT_STATUS_NO_MEMORY);
1587 goto out;
1589 numentries++;
1594 SearchEmpty:
1596 /* If we were called as SMBffirst with smb_search_id == NULL
1597 and no entries were found then return error and close dirptr
1598 (X/Open spec) */
1600 if (numentries == 0) {
1601 dptr_close(sconn, &dptr_num);
1602 } else if(expect_close && status_len == 0) {
1603 /* Close the dptr - we know it's gone */
1604 dptr_close(sconn, &dptr_num);
1607 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1608 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1609 dptr_close(sconn, &dptr_num);
1612 if ((numentries == 0) && !mask_contains_wcard) {
1613 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1614 goto out;
1617 SSVAL(req->outbuf,smb_vwv0,numentries);
1618 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1619 SCVAL(smb_buf(req->outbuf),0,5);
1620 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1622 /* The replies here are never long name. */
1623 SSVAL(req->outbuf, smb_flg2,
1624 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1625 if (!allow_long_path_components) {
1626 SSVAL(req->outbuf, smb_flg2,
1627 SVAL(req->outbuf, smb_flg2)
1628 & (~FLAGS2_LONG_PATH_COMPONENTS));
1631 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1632 SSVAL(req->outbuf, smb_flg2,
1633 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1635 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1636 smb_fn_name(req->cmd),
1637 mask,
1638 directory,
1639 dirtype,
1640 numentries,
1641 maxentries ));
1642 out:
1643 TALLOC_FREE(directory);
1644 TALLOC_FREE(smb_fname);
1645 END_PROFILE(SMBsearch);
1646 return;
1649 /****************************************************************************
1650 Reply to a fclose (stop directory search).
1651 ****************************************************************************/
1653 void reply_fclose(struct smb_request *req)
1655 int status_len;
1656 char status[21];
1657 int dptr_num= -2;
1658 const char *p;
1659 char *path = NULL;
1660 NTSTATUS err;
1661 bool path_contains_wcard = False;
1662 TALLOC_CTX *ctx = talloc_tos();
1663 struct smbd_server_connection *sconn = req->sconn;
1665 START_PROFILE(SMBfclose);
1667 if (lp_posix_pathnames()) {
1668 reply_unknown_new(req, req->cmd);
1669 END_PROFILE(SMBfclose);
1670 return;
1673 p = (const char *)req->buf + 1;
1674 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1675 &err, &path_contains_wcard);
1676 if (!NT_STATUS_IS_OK(err)) {
1677 reply_nterror(req, err);
1678 END_PROFILE(SMBfclose);
1679 return;
1681 p++;
1682 status_len = SVAL(p,0);
1683 p += 2;
1685 if (status_len == 0) {
1686 reply_force_doserror(req, ERRSRV, ERRsrverror);
1687 END_PROFILE(SMBfclose);
1688 return;
1691 memcpy(status,p,21);
1693 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1694 /* Close the dptr - we know it's gone */
1695 dptr_close(sconn, &dptr_num);
1698 reply_outbuf(req, 1, 0);
1699 SSVAL(req->outbuf,smb_vwv0,0);
1701 DEBUG(3,("search close\n"));
1703 END_PROFILE(SMBfclose);
1704 return;
1707 /****************************************************************************
1708 Reply to an open.
1709 ****************************************************************************/
1711 void reply_open(struct smb_request *req)
1713 connection_struct *conn = req->conn;
1714 struct smb_filename *smb_fname = NULL;
1715 char *fname = NULL;
1716 uint32 fattr=0;
1717 SMB_OFF_T size = 0;
1718 time_t mtime=0;
1719 int info;
1720 files_struct *fsp;
1721 int oplock_request;
1722 int deny_mode;
1723 uint32 dos_attr;
1724 uint32 access_mask;
1725 uint32 share_mode;
1726 uint32 create_disposition;
1727 uint32 create_options = 0;
1728 uint32_t private_flags = 0;
1729 NTSTATUS status;
1730 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1731 TALLOC_CTX *ctx = talloc_tos();
1733 START_PROFILE(SMBopen);
1735 if (req->wct < 2) {
1736 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1737 goto out;
1740 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1741 deny_mode = SVAL(req->vwv+0, 0);
1742 dos_attr = SVAL(req->vwv+1, 0);
1744 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1745 STR_TERMINATE, &status);
1746 if (!NT_STATUS_IS_OK(status)) {
1747 reply_nterror(req, status);
1748 goto out;
1751 status = filename_convert(ctx,
1752 conn,
1753 req->flags2 & FLAGS2_DFS_PATHNAMES,
1754 fname,
1756 NULL,
1757 &smb_fname);
1758 if (!NT_STATUS_IS_OK(status)) {
1759 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1760 reply_botherror(req,
1761 NT_STATUS_PATH_NOT_COVERED,
1762 ERRSRV, ERRbadpath);
1763 goto out;
1765 reply_nterror(req, status);
1766 goto out;
1769 if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
1770 OPENX_FILE_EXISTS_OPEN, &access_mask,
1771 &share_mode, &create_disposition,
1772 &create_options, &private_flags)) {
1773 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1774 goto out;
1777 status = SMB_VFS_CREATE_FILE(
1778 conn, /* conn */
1779 req, /* req */
1780 0, /* root_dir_fid */
1781 smb_fname, /* fname */
1782 access_mask, /* access_mask */
1783 share_mode, /* share_access */
1784 create_disposition, /* create_disposition*/
1785 create_options, /* create_options */
1786 dos_attr, /* file_attributes */
1787 oplock_request, /* oplock_request */
1788 0, /* allocation_size */
1789 private_flags,
1790 NULL, /* sd */
1791 NULL, /* ea_list */
1792 &fsp, /* result */
1793 &info); /* pinfo */
1795 if (!NT_STATUS_IS_OK(status)) {
1796 if (open_was_deferred(req->mid)) {
1797 /* We have re-scheduled this call. */
1798 goto out;
1800 reply_openerror(req, status);
1801 goto out;
1804 size = smb_fname->st.st_ex_size;
1805 fattr = dos_mode(conn, smb_fname);
1807 /* Deal with other possible opens having a modified
1808 write time. JRA. */
1809 if (ask_sharemode) {
1810 struct timespec write_time_ts;
1812 ZERO_STRUCT(write_time_ts);
1813 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1814 if (!null_timespec(write_time_ts)) {
1815 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1819 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1821 if (fattr & aDIR) {
1822 DEBUG(3,("attempt to open a directory %s\n",
1823 fsp_str_dbg(fsp)));
1824 close_file(req, fsp, ERROR_CLOSE);
1825 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1826 ERRDOS, ERRnoaccess);
1827 goto out;
1830 reply_outbuf(req, 7, 0);
1831 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1832 SSVAL(req->outbuf,smb_vwv1,fattr);
1833 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1834 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1835 } else {
1836 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1838 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1839 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1841 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1842 SCVAL(req->outbuf,smb_flg,
1843 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1846 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1847 SCVAL(req->outbuf,smb_flg,
1848 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1850 out:
1851 TALLOC_FREE(smb_fname);
1852 END_PROFILE(SMBopen);
1853 return;
1856 /****************************************************************************
1857 Reply to an open and X.
1858 ****************************************************************************/
1860 void reply_open_and_X(struct smb_request *req)
1862 connection_struct *conn = req->conn;
1863 struct smb_filename *smb_fname = NULL;
1864 char *fname = NULL;
1865 uint16 open_flags;
1866 int deny_mode;
1867 uint32 smb_attr;
1868 /* Breakout the oplock request bits so we can set the
1869 reply bits separately. */
1870 int ex_oplock_request;
1871 int core_oplock_request;
1872 int oplock_request;
1873 #if 0
1874 int smb_sattr = SVAL(req->vwv+4, 0);
1875 uint32 smb_time = make_unix_date3(req->vwv+6);
1876 #endif
1877 int smb_ofun;
1878 uint32 fattr=0;
1879 int mtime=0;
1880 int smb_action = 0;
1881 files_struct *fsp;
1882 NTSTATUS status;
1883 uint64_t allocation_size;
1884 ssize_t retval = -1;
1885 uint32 access_mask;
1886 uint32 share_mode;
1887 uint32 create_disposition;
1888 uint32 create_options = 0;
1889 uint32_t private_flags = 0;
1890 TALLOC_CTX *ctx = talloc_tos();
1892 START_PROFILE(SMBopenX);
1894 if (req->wct < 15) {
1895 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1896 goto out;
1899 open_flags = SVAL(req->vwv+2, 0);
1900 deny_mode = SVAL(req->vwv+3, 0);
1901 smb_attr = SVAL(req->vwv+5, 0);
1902 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1903 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1904 oplock_request = ex_oplock_request | core_oplock_request;
1905 smb_ofun = SVAL(req->vwv+8, 0);
1906 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1908 /* If it's an IPC, pass off the pipe handler. */
1909 if (IS_IPC(conn)) {
1910 if (lp_nt_pipe_support()) {
1911 reply_open_pipe_and_X(conn, req);
1912 } else {
1913 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1915 goto out;
1918 /* XXXX we need to handle passed times, sattr and flags */
1919 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1920 STR_TERMINATE, &status);
1921 if (!NT_STATUS_IS_OK(status)) {
1922 reply_nterror(req, status);
1923 goto out;
1926 status = filename_convert(ctx,
1927 conn,
1928 req->flags2 & FLAGS2_DFS_PATHNAMES,
1929 fname,
1931 NULL,
1932 &smb_fname);
1933 if (!NT_STATUS_IS_OK(status)) {
1934 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1935 reply_botherror(req,
1936 NT_STATUS_PATH_NOT_COVERED,
1937 ERRSRV, ERRbadpath);
1938 goto out;
1940 reply_nterror(req, status);
1941 goto out;
1944 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
1945 &access_mask, &share_mode,
1946 &create_disposition,
1947 &create_options,
1948 &private_flags)) {
1949 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1950 goto out;
1953 status = SMB_VFS_CREATE_FILE(
1954 conn, /* conn */
1955 req, /* req */
1956 0, /* root_dir_fid */
1957 smb_fname, /* fname */
1958 access_mask, /* access_mask */
1959 share_mode, /* share_access */
1960 create_disposition, /* create_disposition*/
1961 create_options, /* create_options */
1962 smb_attr, /* file_attributes */
1963 oplock_request, /* oplock_request */
1964 0, /* allocation_size */
1965 private_flags,
1966 NULL, /* sd */
1967 NULL, /* ea_list */
1968 &fsp, /* result */
1969 &smb_action); /* pinfo */
1971 if (!NT_STATUS_IS_OK(status)) {
1972 if (open_was_deferred(req->mid)) {
1973 /* We have re-scheduled this call. */
1974 goto out;
1976 reply_openerror(req, status);
1977 goto out;
1980 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1981 if the file is truncated or created. */
1982 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1983 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1984 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1985 close_file(req, fsp, ERROR_CLOSE);
1986 reply_nterror(req, NT_STATUS_DISK_FULL);
1987 goto out;
1989 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1990 if (retval < 0) {
1991 close_file(req, fsp, ERROR_CLOSE);
1992 reply_nterror(req, NT_STATUS_DISK_FULL);
1993 goto out;
1995 status = vfs_stat_fsp(fsp);
1996 if (!NT_STATUS_IS_OK(status)) {
1997 close_file(req, fsp, ERROR_CLOSE);
1998 reply_nterror(req, status);
1999 goto out;
2003 fattr = dos_mode(conn, fsp->fsp_name);
2004 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2005 if (fattr & aDIR) {
2006 close_file(req, fsp, ERROR_CLOSE);
2007 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2008 goto out;
2011 /* If the caller set the extended oplock request bit
2012 and we granted one (by whatever means) - set the
2013 correct bit for extended oplock reply.
2016 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2017 smb_action |= EXTENDED_OPLOCK_GRANTED;
2020 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2021 smb_action |= EXTENDED_OPLOCK_GRANTED;
2024 /* If the caller set the core oplock request bit
2025 and we granted one (by whatever means) - set the
2026 correct bit for core oplock reply.
2029 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2030 reply_outbuf(req, 19, 0);
2031 } else {
2032 reply_outbuf(req, 15, 0);
2035 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2036 SCVAL(req->outbuf, smb_flg,
2037 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2040 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2041 SCVAL(req->outbuf, smb_flg,
2042 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2045 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2046 SSVAL(req->outbuf,smb_vwv3,fattr);
2047 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2048 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2049 } else {
2050 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2052 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2053 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2054 SSVAL(req->outbuf,smb_vwv11,smb_action);
2056 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2057 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2060 chain_reply(req);
2061 out:
2062 TALLOC_FREE(smb_fname);
2063 END_PROFILE(SMBopenX);
2064 return;
2067 /****************************************************************************
2068 Reply to a SMBulogoffX.
2069 ****************************************************************************/
2071 void reply_ulogoffX(struct smb_request *req)
2073 struct smbd_server_connection *sconn = req->sconn;
2074 user_struct *vuser;
2076 START_PROFILE(SMBulogoffX);
2078 vuser = get_valid_user_struct(sconn, req->vuid);
2080 if(vuser == NULL) {
2081 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2082 req->vuid));
2085 /* in user level security we are supposed to close any files
2086 open by this user */
2087 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2088 file_close_user(sconn, req->vuid);
2091 invalidate_vuid(sconn, req->vuid);
2093 reply_outbuf(req, 2, 0);
2095 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2097 END_PROFILE(SMBulogoffX);
2098 req->vuid = UID_FIELD_INVALID;
2099 chain_reply(req);
2102 /****************************************************************************
2103 Reply to a mknew or a create.
2104 ****************************************************************************/
2106 void reply_mknew(struct smb_request *req)
2108 connection_struct *conn = req->conn;
2109 struct smb_filename *smb_fname = NULL;
2110 char *fname = NULL;
2111 uint32 fattr = 0;
2112 struct smb_file_time ft;
2113 files_struct *fsp;
2114 int oplock_request = 0;
2115 NTSTATUS status;
2116 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2117 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2118 uint32 create_disposition;
2119 uint32 create_options = 0;
2120 TALLOC_CTX *ctx = talloc_tos();
2122 START_PROFILE(SMBcreate);
2123 ZERO_STRUCT(ft);
2125 if (req->wct < 3) {
2126 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2127 goto out;
2130 fattr = SVAL(req->vwv+0, 0);
2131 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2133 /* mtime. */
2134 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2136 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2137 STR_TERMINATE, &status);
2138 if (!NT_STATUS_IS_OK(status)) {
2139 reply_nterror(req, status);
2140 goto out;
2143 status = filename_convert(ctx,
2144 conn,
2145 req->flags2 & FLAGS2_DFS_PATHNAMES,
2146 fname,
2148 NULL,
2149 &smb_fname);
2150 if (!NT_STATUS_IS_OK(status)) {
2151 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2152 reply_botherror(req,
2153 NT_STATUS_PATH_NOT_COVERED,
2154 ERRSRV, ERRbadpath);
2155 goto out;
2157 reply_nterror(req, status);
2158 goto out;
2161 if (fattr & aVOLID) {
2162 DEBUG(0,("Attempt to create file (%s) with volid set - "
2163 "please report this\n",
2164 smb_fname_str_dbg(smb_fname)));
2167 if(req->cmd == SMBmknew) {
2168 /* We should fail if file exists. */
2169 create_disposition = FILE_CREATE;
2170 } else {
2171 /* Create if file doesn't exist, truncate if it does. */
2172 create_disposition = FILE_OVERWRITE_IF;
2175 status = SMB_VFS_CREATE_FILE(
2176 conn, /* conn */
2177 req, /* req */
2178 0, /* root_dir_fid */
2179 smb_fname, /* fname */
2180 access_mask, /* access_mask */
2181 share_mode, /* share_access */
2182 create_disposition, /* create_disposition*/
2183 create_options, /* create_options */
2184 fattr, /* file_attributes */
2185 oplock_request, /* oplock_request */
2186 0, /* allocation_size */
2187 0, /* private_flags */
2188 NULL, /* sd */
2189 NULL, /* ea_list */
2190 &fsp, /* result */
2191 NULL); /* pinfo */
2193 if (!NT_STATUS_IS_OK(status)) {
2194 if (open_was_deferred(req->mid)) {
2195 /* We have re-scheduled this call. */
2196 goto out;
2198 reply_openerror(req, status);
2199 goto out;
2202 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2203 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2204 if (!NT_STATUS_IS_OK(status)) {
2205 END_PROFILE(SMBcreate);
2206 goto out;
2209 reply_outbuf(req, 1, 0);
2210 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2212 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2213 SCVAL(req->outbuf,smb_flg,
2214 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2217 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2218 SCVAL(req->outbuf,smb_flg,
2219 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2222 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2223 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2224 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2225 (unsigned int)fattr));
2227 out:
2228 TALLOC_FREE(smb_fname);
2229 END_PROFILE(SMBcreate);
2230 return;
2233 /****************************************************************************
2234 Reply to a create temporary file.
2235 ****************************************************************************/
2237 void reply_ctemp(struct smb_request *req)
2239 connection_struct *conn = req->conn;
2240 struct smb_filename *smb_fname = NULL;
2241 char *fname = NULL;
2242 uint32 fattr;
2243 files_struct *fsp;
2244 int oplock_request;
2245 int tmpfd;
2246 char *s;
2247 NTSTATUS status;
2248 TALLOC_CTX *ctx = talloc_tos();
2250 START_PROFILE(SMBctemp);
2252 if (req->wct < 3) {
2253 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2254 goto out;
2257 fattr = SVAL(req->vwv+0, 0);
2258 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2260 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2261 STR_TERMINATE, &status);
2262 if (!NT_STATUS_IS_OK(status)) {
2263 reply_nterror(req, status);
2264 goto out;
2266 if (*fname) {
2267 fname = talloc_asprintf(ctx,
2268 "%s/TMXXXXXX",
2269 fname);
2270 } else {
2271 fname = talloc_strdup(ctx, "TMXXXXXX");
2274 if (!fname) {
2275 reply_nterror(req, NT_STATUS_NO_MEMORY);
2276 goto out;
2279 status = filename_convert(ctx, conn,
2280 req->flags2 & FLAGS2_DFS_PATHNAMES,
2281 fname,
2283 NULL,
2284 &smb_fname);
2285 if (!NT_STATUS_IS_OK(status)) {
2286 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2287 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2288 ERRSRV, ERRbadpath);
2289 goto out;
2291 reply_nterror(req, status);
2292 goto out;
2295 tmpfd = mkstemp(smb_fname->base_name);
2296 if (tmpfd == -1) {
2297 reply_nterror(req, map_nt_error_from_unix(errno));
2298 goto out;
2301 SMB_VFS_STAT(conn, smb_fname);
2303 /* We should fail if file does not exist. */
2304 status = SMB_VFS_CREATE_FILE(
2305 conn, /* conn */
2306 req, /* req */
2307 0, /* root_dir_fid */
2308 smb_fname, /* fname */
2309 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2310 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2311 FILE_OPEN, /* create_disposition*/
2312 0, /* create_options */
2313 fattr, /* file_attributes */
2314 oplock_request, /* oplock_request */
2315 0, /* allocation_size */
2316 0, /* private_flags */
2317 NULL, /* sd */
2318 NULL, /* ea_list */
2319 &fsp, /* result */
2320 NULL); /* pinfo */
2322 /* close fd from mkstemp() */
2323 close(tmpfd);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 if (open_was_deferred(req->mid)) {
2327 /* We have re-scheduled this call. */
2328 goto out;
2330 reply_openerror(req, status);
2331 goto out;
2334 reply_outbuf(req, 1, 0);
2335 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2337 /* the returned filename is relative to the directory */
2338 s = strrchr_m(fsp->fsp_name->base_name, '/');
2339 if (!s) {
2340 s = fsp->fsp_name->base_name;
2341 } else {
2342 s++;
2345 #if 0
2346 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2347 thing in the byte section. JRA */
2348 SSVALS(p, 0, -1); /* what is this? not in spec */
2349 #endif
2350 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2351 == -1) {
2352 reply_nterror(req, NT_STATUS_NO_MEMORY);
2353 goto out;
2356 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2357 SCVAL(req->outbuf, smb_flg,
2358 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2361 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2362 SCVAL(req->outbuf, smb_flg,
2363 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2366 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2367 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2368 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2369 out:
2370 TALLOC_FREE(smb_fname);
2371 END_PROFILE(SMBctemp);
2372 return;
2375 /*******************************************************************
2376 Check if a user is allowed to rename a file.
2377 ********************************************************************/
2379 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2380 uint16 dirtype)
2382 uint32 fmode;
2384 if (!CAN_WRITE(conn)) {
2385 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2388 fmode = dos_mode(conn, fsp->fsp_name);
2389 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2390 return NT_STATUS_NO_SUCH_FILE;
2393 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2394 if (fsp->posix_open) {
2395 return NT_STATUS_OK;
2398 /* If no pathnames are open below this
2399 directory, allow the rename. */
2401 if (file_find_subpath(fsp)) {
2402 return NT_STATUS_ACCESS_DENIED;
2404 return NT_STATUS_OK;
2407 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2408 return NT_STATUS_OK;
2411 return NT_STATUS_ACCESS_DENIED;
2414 /*******************************************************************
2415 * unlink a file with all relevant access checks
2416 *******************************************************************/
2418 static NTSTATUS do_unlink(connection_struct *conn,
2419 struct smb_request *req,
2420 struct smb_filename *smb_fname,
2421 uint32 dirtype)
2423 uint32 fattr;
2424 files_struct *fsp;
2425 uint32 dirtype_orig = dirtype;
2426 NTSTATUS status;
2427 int ret;
2428 bool posix_paths = lp_posix_pathnames();
2430 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2431 smb_fname_str_dbg(smb_fname),
2432 dirtype));
2434 if (!CAN_WRITE(conn)) {
2435 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2438 if (posix_paths) {
2439 ret = SMB_VFS_LSTAT(conn, smb_fname);
2440 } else {
2441 ret = SMB_VFS_STAT(conn, smb_fname);
2443 if (ret != 0) {
2444 return map_nt_error_from_unix(errno);
2447 fattr = dos_mode(conn, smb_fname);
2449 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2450 dirtype = aDIR|aARCH|aRONLY;
2453 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2454 if (!dirtype) {
2455 return NT_STATUS_NO_SUCH_FILE;
2458 if (!dir_check_ftype(conn, fattr, dirtype)) {
2459 if (fattr & aDIR) {
2460 return NT_STATUS_FILE_IS_A_DIRECTORY;
2462 return NT_STATUS_NO_SUCH_FILE;
2465 if (dirtype_orig & 0x8000) {
2466 /* These will never be set for POSIX. */
2467 return NT_STATUS_NO_SUCH_FILE;
2470 #if 0
2471 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2472 return NT_STATUS_FILE_IS_A_DIRECTORY;
2475 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2476 return NT_STATUS_NO_SUCH_FILE;
2479 if (dirtype & 0xFF00) {
2480 /* These will never be set for POSIX. */
2481 return NT_STATUS_NO_SUCH_FILE;
2484 dirtype &= 0xFF;
2485 if (!dirtype) {
2486 return NT_STATUS_NO_SUCH_FILE;
2489 /* Can't delete a directory. */
2490 if (fattr & aDIR) {
2491 return NT_STATUS_FILE_IS_A_DIRECTORY;
2493 #endif
2495 #if 0 /* JRATEST */
2496 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2497 return NT_STATUS_OBJECT_NAME_INVALID;
2498 #endif /* JRATEST */
2500 /* On open checks the open itself will check the share mode, so
2501 don't do it here as we'll get it wrong. */
2503 status = SMB_VFS_CREATE_FILE
2504 (conn, /* conn */
2505 req, /* req */
2506 0, /* root_dir_fid */
2507 smb_fname, /* fname */
2508 DELETE_ACCESS, /* access_mask */
2509 FILE_SHARE_NONE, /* share_access */
2510 FILE_OPEN, /* create_disposition*/
2511 FILE_NON_DIRECTORY_FILE, /* create_options */
2512 /* file_attributes */
2513 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2514 FILE_ATTRIBUTE_NORMAL,
2515 0, /* oplock_request */
2516 0, /* allocation_size */
2517 0, /* private_flags */
2518 NULL, /* sd */
2519 NULL, /* ea_list */
2520 &fsp, /* result */
2521 NULL); /* pinfo */
2523 if (!NT_STATUS_IS_OK(status)) {
2524 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2525 nt_errstr(status)));
2526 return status;
2529 status = can_set_delete_on_close(fsp, fattr);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2532 "(%s)\n",
2533 smb_fname_str_dbg(smb_fname),
2534 nt_errstr(status)));
2535 close_file(req, fsp, NORMAL_CLOSE);
2536 return status;
2539 /* The set is across all open files on this dev/inode pair. */
2540 if (!set_delete_on_close(fsp, True, &conn->session_info->utok)) {
2541 close_file(req, fsp, NORMAL_CLOSE);
2542 return NT_STATUS_ACCESS_DENIED;
2545 return close_file(req, fsp, NORMAL_CLOSE);
2548 /****************************************************************************
2549 The guts of the unlink command, split out so it may be called by the NT SMB
2550 code.
2551 ****************************************************************************/
2553 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2554 uint32 dirtype, struct smb_filename *smb_fname,
2555 bool has_wild)
2557 char *fname_dir = NULL;
2558 char *fname_mask = NULL;
2559 int count=0;
2560 NTSTATUS status = NT_STATUS_OK;
2561 TALLOC_CTX *ctx = talloc_tos();
2563 /* Split up the directory from the filename/mask. */
2564 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2565 &fname_dir, &fname_mask);
2566 if (!NT_STATUS_IS_OK(status)) {
2567 goto out;
2571 * We should only check the mangled cache
2572 * here if unix_convert failed. This means
2573 * that the path in 'mask' doesn't exist
2574 * on the file system and so we need to look
2575 * for a possible mangle. This patch from
2576 * Tine Smukavec <valentin.smukavec@hermes.si>.
2579 if (!VALID_STAT(smb_fname->st) &&
2580 mangle_is_mangled(fname_mask, conn->params)) {
2581 char *new_mask = NULL;
2582 mangle_lookup_name_from_8_3(ctx, fname_mask,
2583 &new_mask, conn->params);
2584 if (new_mask) {
2585 TALLOC_FREE(fname_mask);
2586 fname_mask = new_mask;
2590 if (!has_wild) {
2593 * Only one file needs to be unlinked. Append the mask back
2594 * onto the directory.
2596 TALLOC_FREE(smb_fname->base_name);
2597 if (ISDOT(fname_dir)) {
2598 /* Ensure we use canonical names on open. */
2599 smb_fname->base_name = talloc_asprintf(smb_fname,
2600 "%s",
2601 fname_mask);
2602 } else {
2603 smb_fname->base_name = talloc_asprintf(smb_fname,
2604 "%s/%s",
2605 fname_dir,
2606 fname_mask);
2608 if (!smb_fname->base_name) {
2609 status = NT_STATUS_NO_MEMORY;
2610 goto out;
2612 if (dirtype == 0) {
2613 dirtype = FILE_ATTRIBUTE_NORMAL;
2616 status = check_name(conn, smb_fname->base_name);
2617 if (!NT_STATUS_IS_OK(status)) {
2618 goto out;
2621 status = do_unlink(conn, req, smb_fname, dirtype);
2622 if (!NT_STATUS_IS_OK(status)) {
2623 goto out;
2626 count++;
2627 } else {
2628 struct smb_Dir *dir_hnd = NULL;
2629 long offset = 0;
2630 const char *dname = NULL;
2631 char *talloced = NULL;
2633 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2634 status = NT_STATUS_OBJECT_NAME_INVALID;
2635 goto out;
2638 if (strequal(fname_mask,"????????.???")) {
2639 TALLOC_FREE(fname_mask);
2640 fname_mask = talloc_strdup(ctx, "*");
2641 if (!fname_mask) {
2642 status = NT_STATUS_NO_MEMORY;
2643 goto out;
2647 status = check_name(conn, fname_dir);
2648 if (!NT_STATUS_IS_OK(status)) {
2649 goto out;
2652 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2653 dirtype);
2654 if (dir_hnd == NULL) {
2655 status = map_nt_error_from_unix(errno);
2656 goto out;
2659 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2660 the pattern matches against the long name, otherwise the short name
2661 We don't implement this yet XXXX
2664 status = NT_STATUS_NO_SUCH_FILE;
2666 while ((dname = ReadDirName(dir_hnd, &offset,
2667 &smb_fname->st, &talloced))) {
2668 TALLOC_CTX *frame = talloc_stackframe();
2670 if (!is_visible_file(conn, fname_dir, dname,
2671 &smb_fname->st, true)) {
2672 TALLOC_FREE(frame);
2673 TALLOC_FREE(talloced);
2674 continue;
2677 /* Quick check for "." and ".." */
2678 if (ISDOT(dname) || ISDOTDOT(dname)) {
2679 TALLOC_FREE(frame);
2680 TALLOC_FREE(talloced);
2681 continue;
2684 if(!mask_match(dname, fname_mask,
2685 conn->case_sensitive)) {
2686 TALLOC_FREE(frame);
2687 TALLOC_FREE(talloced);
2688 continue;
2691 TALLOC_FREE(smb_fname->base_name);
2692 if (ISDOT(fname_dir)) {
2693 /* Ensure we use canonical names on open. */
2694 smb_fname->base_name =
2695 talloc_asprintf(smb_fname, "%s",
2696 dname);
2697 } else {
2698 smb_fname->base_name =
2699 talloc_asprintf(smb_fname, "%s/%s",
2700 fname_dir, dname);
2703 if (!smb_fname->base_name) {
2704 TALLOC_FREE(dir_hnd);
2705 status = NT_STATUS_NO_MEMORY;
2706 TALLOC_FREE(frame);
2707 TALLOC_FREE(talloced);
2708 goto out;
2711 status = check_name(conn, smb_fname->base_name);
2712 if (!NT_STATUS_IS_OK(status)) {
2713 TALLOC_FREE(dir_hnd);
2714 TALLOC_FREE(frame);
2715 TALLOC_FREE(talloced);
2716 goto out;
2719 status = do_unlink(conn, req, smb_fname, dirtype);
2720 if (!NT_STATUS_IS_OK(status)) {
2721 TALLOC_FREE(frame);
2722 TALLOC_FREE(talloced);
2723 continue;
2726 count++;
2727 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2728 smb_fname->base_name));
2730 TALLOC_FREE(frame);
2731 TALLOC_FREE(talloced);
2733 TALLOC_FREE(dir_hnd);
2736 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2737 status = map_nt_error_from_unix(errno);
2740 out:
2741 TALLOC_FREE(fname_dir);
2742 TALLOC_FREE(fname_mask);
2743 return status;
2746 /****************************************************************************
2747 Reply to a unlink
2748 ****************************************************************************/
2750 void reply_unlink(struct smb_request *req)
2752 connection_struct *conn = req->conn;
2753 char *name = NULL;
2754 struct smb_filename *smb_fname = NULL;
2755 uint32 dirtype;
2756 NTSTATUS status;
2757 bool path_contains_wcard = False;
2758 TALLOC_CTX *ctx = talloc_tos();
2760 START_PROFILE(SMBunlink);
2762 if (req->wct < 1) {
2763 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2764 goto out;
2767 dirtype = SVAL(req->vwv+0, 0);
2769 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2770 STR_TERMINATE, &status,
2771 &path_contains_wcard);
2772 if (!NT_STATUS_IS_OK(status)) {
2773 reply_nterror(req, status);
2774 goto out;
2777 status = filename_convert(ctx, conn,
2778 req->flags2 & FLAGS2_DFS_PATHNAMES,
2779 name,
2780 UCF_COND_ALLOW_WCARD_LCOMP,
2781 &path_contains_wcard,
2782 &smb_fname);
2783 if (!NT_STATUS_IS_OK(status)) {
2784 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2785 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2786 ERRSRV, ERRbadpath);
2787 goto out;
2789 reply_nterror(req, status);
2790 goto out;
2793 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2795 status = unlink_internals(conn, req, dirtype, smb_fname,
2796 path_contains_wcard);
2797 if (!NT_STATUS_IS_OK(status)) {
2798 if (open_was_deferred(req->mid)) {
2799 /* We have re-scheduled this call. */
2800 goto out;
2802 reply_nterror(req, status);
2803 goto out;
2806 reply_outbuf(req, 0, 0);
2807 out:
2808 TALLOC_FREE(smb_fname);
2809 END_PROFILE(SMBunlink);
2810 return;
2813 /****************************************************************************
2814 Fail for readbraw.
2815 ****************************************************************************/
2817 static void fail_readraw(void)
2819 const char *errstr = talloc_asprintf(talloc_tos(),
2820 "FAIL ! reply_readbraw: socket write fail (%s)",
2821 strerror(errno));
2822 if (!errstr) {
2823 errstr = "";
2825 exit_server_cleanly(errstr);
2828 /****************************************************************************
2829 Fake (read/write) sendfile. Returns -1 on read or write fail.
2830 ****************************************************************************/
2832 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2834 size_t bufsize;
2835 size_t tosend = nread;
2836 char *buf;
2838 if (nread == 0) {
2839 return 0;
2842 bufsize = MIN(nread, 65536);
2844 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2845 return -1;
2848 while (tosend > 0) {
2849 ssize_t ret;
2850 size_t cur_read;
2852 if (tosend > bufsize) {
2853 cur_read = bufsize;
2854 } else {
2855 cur_read = tosend;
2857 ret = read_file(fsp,buf,startpos,cur_read);
2858 if (ret == -1) {
2859 SAFE_FREE(buf);
2860 return -1;
2863 /* If we had a short read, fill with zeros. */
2864 if (ret < cur_read) {
2865 memset(buf + ret, '\0', cur_read - ret);
2868 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2869 != cur_read) {
2870 char addr[INET6_ADDRSTRLEN];
2872 * Try and give an error message saying what
2873 * client failed.
2875 DEBUG(0, ("write_data failed for client %s. "
2876 "Error %s\n",
2877 get_peer_addr(fsp->conn->sconn->sock, addr,
2878 sizeof(addr)),
2879 strerror(errno)));
2880 SAFE_FREE(buf);
2881 return -1;
2883 tosend -= cur_read;
2884 startpos += cur_read;
2887 SAFE_FREE(buf);
2888 return (ssize_t)nread;
2891 /****************************************************************************
2892 Deal with the case of sendfile reading less bytes from the file than
2893 requested. Fill with zeros (all we can do).
2894 ****************************************************************************/
2896 void sendfile_short_send(files_struct *fsp,
2897 ssize_t nread,
2898 size_t headersize,
2899 size_t smb_maxcnt)
2901 #define SHORT_SEND_BUFSIZE 1024
2902 if (nread < headersize) {
2903 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2904 "header for file %s (%s). Terminating\n",
2905 fsp_str_dbg(fsp), strerror(errno)));
2906 exit_server_cleanly("sendfile_short_send failed");
2909 nread -= headersize;
2911 if (nread < smb_maxcnt) {
2912 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2913 if (!buf) {
2914 exit_server_cleanly("sendfile_short_send: "
2915 "malloc failed");
2918 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2919 "with zeros !\n", fsp_str_dbg(fsp)));
2921 while (nread < smb_maxcnt) {
2923 * We asked for the real file size and told sendfile
2924 * to not go beyond the end of the file. But it can
2925 * happen that in between our fstat call and the
2926 * sendfile call the file was truncated. This is very
2927 * bad because we have already announced the larger
2928 * number of bytes to the client.
2930 * The best we can do now is to send 0-bytes, just as
2931 * a read from a hole in a sparse file would do.
2933 * This should happen rarely enough that I don't care
2934 * about efficiency here :-)
2936 size_t to_write;
2938 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2939 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2940 != to_write) {
2941 char addr[INET6_ADDRSTRLEN];
2943 * Try and give an error message saying what
2944 * client failed.
2946 DEBUG(0, ("write_data failed for client %s. "
2947 "Error %s\n",
2948 get_peer_addr(
2949 fsp->conn->sconn->sock, addr,
2950 sizeof(addr)),
2951 strerror(errno)));
2952 exit_server_cleanly("sendfile_short_send: "
2953 "write_data failed");
2955 nread += to_write;
2957 SAFE_FREE(buf);
2961 /****************************************************************************
2962 Return a readbraw error (4 bytes of zero).
2963 ****************************************************************************/
2965 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2967 char header[4];
2969 SIVAL(header,0,0);
2971 smbd_lock_socket(sconn);
2972 if (write_data(sconn->sock,header,4) != 4) {
2973 char addr[INET6_ADDRSTRLEN];
2975 * Try and give an error message saying what
2976 * client failed.
2978 DEBUG(0, ("write_data failed for client %s. "
2979 "Error %s\n",
2980 get_peer_addr(sconn->sock, addr, sizeof(addr)),
2981 strerror(errno)));
2983 fail_readraw();
2985 smbd_unlock_socket(sconn);
2988 /****************************************************************************
2989 Use sendfile in readbraw.
2990 ****************************************************************************/
2992 static void send_file_readbraw(connection_struct *conn,
2993 struct smb_request *req,
2994 files_struct *fsp,
2995 SMB_OFF_T startpos,
2996 size_t nread,
2997 ssize_t mincount)
2999 struct smbd_server_connection *sconn = req->sconn;
3000 char *outbuf = NULL;
3001 ssize_t ret=0;
3004 * We can only use sendfile on a non-chained packet
3005 * but we can use on a non-oplocked file. tridge proved this
3006 * on a train in Germany :-). JRA.
3007 * reply_readbraw has already checked the length.
3010 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3011 (fsp->wcp == NULL) &&
3012 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3013 ssize_t sendfile_read = -1;
3014 char header[4];
3015 DATA_BLOB header_blob;
3017 _smb_setlen(header,nread);
3018 header_blob = data_blob_const(header, 4);
3020 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3021 &header_blob, startpos,
3022 nread);
3023 if (sendfile_read == -1) {
3024 /* Returning ENOSYS means no data at all was sent.
3025 * Do this as a normal read. */
3026 if (errno == ENOSYS) {
3027 goto normal_readbraw;
3031 * Special hack for broken Linux with no working sendfile. If we
3032 * return EINTR we sent the header but not the rest of the data.
3033 * Fake this up by doing read/write calls.
3035 if (errno == EINTR) {
3036 /* Ensure we don't do this again. */
3037 set_use_sendfile(SNUM(conn), False);
3038 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3040 if (fake_sendfile(fsp, startpos, nread) == -1) {
3041 DEBUG(0,("send_file_readbraw: "
3042 "fake_sendfile failed for "
3043 "file %s (%s).\n",
3044 fsp_str_dbg(fsp),
3045 strerror(errno)));
3046 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3048 return;
3051 DEBUG(0,("send_file_readbraw: sendfile failed for "
3052 "file %s (%s). Terminating\n",
3053 fsp_str_dbg(fsp), strerror(errno)));
3054 exit_server_cleanly("send_file_readbraw sendfile failed");
3055 } else if (sendfile_read == 0) {
3057 * Some sendfile implementations return 0 to indicate
3058 * that there was a short read, but nothing was
3059 * actually written to the socket. In this case,
3060 * fallback to the normal read path so the header gets
3061 * the correct byte count.
3063 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3064 "bytes falling back to the normal read: "
3065 "%s\n", fsp_str_dbg(fsp)));
3066 goto normal_readbraw;
3069 /* Deal with possible short send. */
3070 if (sendfile_read != 4+nread) {
3071 sendfile_short_send(fsp, sendfile_read, 4, nread);
3073 return;
3076 normal_readbraw:
3078 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
3079 if (!outbuf) {
3080 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
3081 (unsigned)(nread+4)));
3082 reply_readbraw_error(sconn);
3083 return;
3086 if (nread > 0) {
3087 ret = read_file(fsp,outbuf+4,startpos,nread);
3088 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3089 if (ret < mincount)
3090 ret = 0;
3091 #else
3092 if (ret < nread)
3093 ret = 0;
3094 #endif
3097 _smb_setlen(outbuf,ret);
3098 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3099 char addr[INET6_ADDRSTRLEN];
3101 * Try and give an error message saying what
3102 * client failed.
3104 DEBUG(0, ("write_data failed for client %s. "
3105 "Error %s\n",
3106 get_peer_addr(fsp->conn->sconn->sock, addr,
3107 sizeof(addr)),
3108 strerror(errno)));
3110 fail_readraw();
3113 TALLOC_FREE(outbuf);
3116 /****************************************************************************
3117 Reply to a readbraw (core+ protocol).
3118 ****************************************************************************/
3120 void reply_readbraw(struct smb_request *req)
3122 connection_struct *conn = req->conn;
3123 struct smbd_server_connection *sconn = req->sconn;
3124 ssize_t maxcount,mincount;
3125 size_t nread = 0;
3126 SMB_OFF_T startpos;
3127 files_struct *fsp;
3128 struct lock_struct lock;
3129 SMB_OFF_T size = 0;
3131 START_PROFILE(SMBreadbraw);
3133 if (srv_is_signing_active(sconn) ||
3134 is_encrypted_packet(req->inbuf)) {
3135 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3136 "raw reads/writes are disallowed.");
3139 if (req->wct < 8) {
3140 reply_readbraw_error(sconn);
3141 END_PROFILE(SMBreadbraw);
3142 return;
3145 if (sconn->smb1.echo_handler.trusted_fde) {
3146 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3147 "'async smb echo handler = yes'\n"));
3148 reply_readbraw_error(sconn);
3149 END_PROFILE(SMBreadbraw);
3150 return;
3154 * Special check if an oplock break has been issued
3155 * and the readraw request croses on the wire, we must
3156 * return a zero length response here.
3159 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3162 * We have to do a check_fsp by hand here, as
3163 * we must always return 4 zero bytes on error,
3164 * not a NTSTATUS.
3167 if (!fsp || !conn || conn != fsp->conn ||
3168 req->vuid != fsp->vuid ||
3169 fsp->is_directory || fsp->fh->fd == -1) {
3171 * fsp could be NULL here so use the value from the packet. JRA.
3173 DEBUG(3,("reply_readbraw: fnum %d not valid "
3174 "- cache prime?\n",
3175 (int)SVAL(req->vwv+0, 0)));
3176 reply_readbraw_error(sconn);
3177 END_PROFILE(SMBreadbraw);
3178 return;
3181 /* Do a "by hand" version of CHECK_READ. */
3182 if (!(fsp->can_read ||
3183 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3184 (fsp->access_mask & FILE_EXECUTE)))) {
3185 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3186 (int)SVAL(req->vwv+0, 0)));
3187 reply_readbraw_error(sconn);
3188 END_PROFILE(SMBreadbraw);
3189 return;
3192 flush_write_cache(fsp, READRAW_FLUSH);
3194 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3195 if(req->wct == 10) {
3197 * This is a large offset (64 bit) read.
3199 #ifdef LARGE_SMB_OFF_T
3201 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3203 #else /* !LARGE_SMB_OFF_T */
3206 * Ensure we haven't been sent a >32 bit offset.
3209 if(IVAL(req->vwv+8, 0) != 0) {
3210 DEBUG(0,("reply_readbraw: large offset "
3211 "(%x << 32) used and we don't support "
3212 "64 bit offsets.\n",
3213 (unsigned int)IVAL(req->vwv+8, 0) ));
3214 reply_readbraw_error();
3215 END_PROFILE(SMBreadbraw);
3216 return;
3219 #endif /* LARGE_SMB_OFF_T */
3221 if(startpos < 0) {
3222 DEBUG(0,("reply_readbraw: negative 64 bit "
3223 "readraw offset (%.0f) !\n",
3224 (double)startpos ));
3225 reply_readbraw_error(sconn);
3226 END_PROFILE(SMBreadbraw);
3227 return;
3231 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3232 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3234 /* ensure we don't overrun the packet size */
3235 maxcount = MIN(65535,maxcount);
3237 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3238 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3239 &lock);
3241 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3242 reply_readbraw_error(sconn);
3243 END_PROFILE(SMBreadbraw);
3244 return;
3247 if (fsp_stat(fsp) == 0) {
3248 size = fsp->fsp_name->st.st_ex_size;
3251 if (startpos >= size) {
3252 nread = 0;
3253 } else {
3254 nread = MIN(maxcount,(size - startpos));
3257 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3258 if (nread < mincount)
3259 nread = 0;
3260 #endif
3262 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3263 "min=%lu nread=%lu\n",
3264 fsp->fnum, (double)startpos,
3265 (unsigned long)maxcount,
3266 (unsigned long)mincount,
3267 (unsigned long)nread ) );
3269 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3271 DEBUG(5,("reply_readbraw finished\n"));
3273 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3275 END_PROFILE(SMBreadbraw);
3276 return;
3279 #undef DBGC_CLASS
3280 #define DBGC_CLASS DBGC_LOCKING
3282 /****************************************************************************
3283 Reply to a lockread (core+ protocol).
3284 ****************************************************************************/
3286 void reply_lockread(struct smb_request *req)
3288 connection_struct *conn = req->conn;
3289 ssize_t nread = -1;
3290 char *data;
3291 SMB_OFF_T startpos;
3292 size_t numtoread;
3293 NTSTATUS status;
3294 files_struct *fsp;
3295 struct byte_range_lock *br_lck = NULL;
3296 char *p = NULL;
3297 struct smbd_server_connection *sconn = req->sconn;
3299 START_PROFILE(SMBlockread);
3301 if (req->wct < 5) {
3302 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3303 END_PROFILE(SMBlockread);
3304 return;
3307 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3309 if (!check_fsp(conn, req, fsp)) {
3310 END_PROFILE(SMBlockread);
3311 return;
3314 if (!CHECK_READ(fsp,req)) {
3315 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3316 END_PROFILE(SMBlockread);
3317 return;
3320 numtoread = SVAL(req->vwv+1, 0);
3321 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3323 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3325 reply_outbuf(req, 5, numtoread + 3);
3327 data = smb_buf(req->outbuf) + 3;
3330 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3331 * protocol request that predates the read/write lock concept.
3332 * Thus instead of asking for a read lock here we need to ask
3333 * for a write lock. JRA.
3334 * Note that the requested lock size is unaffected by max_recv.
3337 br_lck = do_lock(req->sconn->msg_ctx,
3338 fsp,
3339 (uint64_t)req->smbpid,
3340 (uint64_t)numtoread,
3341 (uint64_t)startpos,
3342 WRITE_LOCK,
3343 WINDOWS_LOCK,
3344 False, /* Non-blocking lock. */
3345 &status,
3346 NULL,
3347 NULL);
3348 TALLOC_FREE(br_lck);
3350 if (NT_STATUS_V(status)) {
3351 reply_nterror(req, status);
3352 END_PROFILE(SMBlockread);
3353 return;
3357 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3360 if (numtoread > sconn->smb1.negprot.max_recv) {
3361 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3362 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3363 (unsigned int)numtoread,
3364 (unsigned int)sconn->smb1.negprot.max_recv));
3365 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3367 nread = read_file(fsp,data,startpos,numtoread);
3369 if (nread < 0) {
3370 reply_nterror(req, map_nt_error_from_unix(errno));
3371 END_PROFILE(SMBlockread);
3372 return;
3375 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3377 SSVAL(req->outbuf,smb_vwv0,nread);
3378 SSVAL(req->outbuf,smb_vwv5,nread+3);
3379 p = smb_buf(req->outbuf);
3380 SCVAL(p,0,0); /* pad byte. */
3381 SSVAL(p,1,nread);
3383 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3384 fsp->fnum, (int)numtoread, (int)nread));
3386 END_PROFILE(SMBlockread);
3387 return;
3390 #undef DBGC_CLASS
3391 #define DBGC_CLASS DBGC_ALL
3393 /****************************************************************************
3394 Reply to a read.
3395 ****************************************************************************/
3397 void reply_read(struct smb_request *req)
3399 connection_struct *conn = req->conn;
3400 size_t numtoread;
3401 ssize_t nread = 0;
3402 char *data;
3403 SMB_OFF_T startpos;
3404 int outsize = 0;
3405 files_struct *fsp;
3406 struct lock_struct lock;
3407 struct smbd_server_connection *sconn = req->sconn;
3409 START_PROFILE(SMBread);
3411 if (req->wct < 3) {
3412 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3413 END_PROFILE(SMBread);
3414 return;
3417 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3419 if (!check_fsp(conn, req, fsp)) {
3420 END_PROFILE(SMBread);
3421 return;
3424 if (!CHECK_READ(fsp,req)) {
3425 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3426 END_PROFILE(SMBread);
3427 return;
3430 numtoread = SVAL(req->vwv+1, 0);
3431 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3433 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3436 * The requested read size cannot be greater than max_recv. JRA.
3438 if (numtoread > sconn->smb1.negprot.max_recv) {
3439 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3440 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3441 (unsigned int)numtoread,
3442 (unsigned int)sconn->smb1.negprot.max_recv));
3443 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3446 reply_outbuf(req, 5, numtoread+3);
3448 data = smb_buf(req->outbuf) + 3;
3450 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3451 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3452 &lock);
3454 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3455 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3456 END_PROFILE(SMBread);
3457 return;
3460 if (numtoread > 0)
3461 nread = read_file(fsp,data,startpos,numtoread);
3463 if (nread < 0) {
3464 reply_nterror(req, map_nt_error_from_unix(errno));
3465 goto strict_unlock;
3468 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3470 SSVAL(req->outbuf,smb_vwv0,nread);
3471 SSVAL(req->outbuf,smb_vwv5,nread+3);
3472 SCVAL(smb_buf(req->outbuf),0,1);
3473 SSVAL(smb_buf(req->outbuf),1,nread);
3475 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3476 fsp->fnum, (int)numtoread, (int)nread ) );
3478 strict_unlock:
3479 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3481 END_PROFILE(SMBread);
3482 return;
3485 /****************************************************************************
3486 Setup readX header.
3487 ****************************************************************************/
3489 static int setup_readX_header(struct smb_request *req, char *outbuf,
3490 size_t smb_maxcnt)
3492 int outsize;
3493 char *data;
3495 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3496 data = smb_buf(outbuf);
3498 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3500 SCVAL(outbuf,smb_vwv0,0xFF);
3501 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3502 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3503 SSVAL(outbuf,smb_vwv6,
3504 req_wct_ofs(req)
3505 + 1 /* the wct field */
3506 + 12 * sizeof(uint16_t) /* vwv */
3507 + 2); /* the buflen field */
3508 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3509 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3510 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3511 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3512 return outsize;
3515 /****************************************************************************
3516 Reply to a read and X - possibly using sendfile.
3517 ****************************************************************************/
3519 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3520 files_struct *fsp, SMB_OFF_T startpos,
3521 size_t smb_maxcnt)
3523 ssize_t nread = -1;
3524 struct lock_struct lock;
3525 int saved_errno = 0;
3527 if(fsp_stat(fsp) == -1) {
3528 reply_nterror(req, map_nt_error_from_unix(errno));
3529 return;
3532 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3533 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3534 &lock);
3536 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3537 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3538 return;
3541 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3542 (startpos > fsp->fsp_name->st.st_ex_size)
3543 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3545 * We already know that we would do a short read, so don't
3546 * try the sendfile() path.
3548 goto nosendfile_read;
3552 * We can only use sendfile on a non-chained packet
3553 * but we can use on a non-oplocked file. tridge proved this
3554 * on a train in Germany :-). JRA.
3557 if (!req_is_in_chain(req) &&
3558 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3559 (fsp->wcp == NULL) &&
3560 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3561 uint8 headerbuf[smb_size + 12 * 2];
3562 DATA_BLOB header;
3565 * Set up the packet header before send. We
3566 * assume here the sendfile will work (get the
3567 * correct amount of data).
3570 header = data_blob_const(headerbuf, sizeof(headerbuf));
3572 construct_reply_common_req(req, (char *)headerbuf);
3573 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3575 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3576 startpos, smb_maxcnt);
3577 if (nread == -1) {
3578 /* Returning ENOSYS means no data at all was sent.
3579 Do this as a normal read. */
3580 if (errno == ENOSYS) {
3581 goto normal_read;
3585 * Special hack for broken Linux with no working sendfile. If we
3586 * return EINTR we sent the header but not the rest of the data.
3587 * Fake this up by doing read/write calls.
3590 if (errno == EINTR) {
3591 /* Ensure we don't do this again. */
3592 set_use_sendfile(SNUM(conn), False);
3593 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3594 nread = fake_sendfile(fsp, startpos,
3595 smb_maxcnt);
3596 if (nread == -1) {
3597 DEBUG(0,("send_file_readX: "
3598 "fake_sendfile failed for "
3599 "file %s (%s).\n",
3600 fsp_str_dbg(fsp),
3601 strerror(errno)));
3602 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3604 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3605 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3606 /* No outbuf here means successful sendfile. */
3607 goto strict_unlock;
3610 DEBUG(0,("send_file_readX: sendfile failed for file "
3611 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3612 strerror(errno)));
3613 exit_server_cleanly("send_file_readX sendfile failed");
3614 } else if (nread == 0) {
3616 * Some sendfile implementations return 0 to indicate
3617 * that there was a short read, but nothing was
3618 * actually written to the socket. In this case,
3619 * fallback to the normal read path so the header gets
3620 * the correct byte count.
3622 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3623 "falling back to the normal read: %s\n",
3624 fsp_str_dbg(fsp)));
3625 goto normal_read;
3628 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3629 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3631 /* Deal with possible short send. */
3632 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3633 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3635 /* No outbuf here means successful sendfile. */
3636 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3637 SMB_PERFCOUNT_END(&req->pcd);
3638 goto strict_unlock;
3641 normal_read:
3643 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3644 uint8 headerbuf[smb_size + 2*12];
3646 construct_reply_common_req(req, (char *)headerbuf);
3647 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3649 /* Send out the header. */
3650 if (write_data(req->sconn->sock, (char *)headerbuf,
3651 sizeof(headerbuf)) != sizeof(headerbuf)) {
3653 char addr[INET6_ADDRSTRLEN];
3655 * Try and give an error message saying what
3656 * client failed.
3658 DEBUG(0, ("write_data failed for client %s. "
3659 "Error %s\n",
3660 get_peer_addr(req->sconn->sock, addr,
3661 sizeof(addr)),
3662 strerror(errno)));
3664 DEBUG(0,("send_file_readX: write_data failed for file "
3665 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3666 strerror(errno)));
3667 exit_server_cleanly("send_file_readX sendfile failed");
3669 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3670 if (nread == -1) {
3671 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3672 "file %s (%s).\n", fsp_str_dbg(fsp),
3673 strerror(errno)));
3674 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3676 goto strict_unlock;
3679 nosendfile_read:
3681 reply_outbuf(req, 12, smb_maxcnt);
3683 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3684 saved_errno = errno;
3686 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3688 if (nread < 0) {
3689 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3690 return;
3693 setup_readX_header(req, (char *)req->outbuf, nread);
3695 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3696 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3698 chain_reply(req);
3699 return;
3701 strict_unlock:
3702 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3703 TALLOC_FREE(req->outbuf);
3704 return;
3707 /****************************************************************************
3708 Reply to a read and X.
3709 ****************************************************************************/
3711 void reply_read_and_X(struct smb_request *req)
3713 connection_struct *conn = req->conn;
3714 files_struct *fsp;
3715 SMB_OFF_T startpos;
3716 size_t smb_maxcnt;
3717 bool big_readX = False;
3718 #if 0
3719 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3720 #endif
3722 START_PROFILE(SMBreadX);
3724 if ((req->wct != 10) && (req->wct != 12)) {
3725 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3726 return;
3729 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3730 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3731 smb_maxcnt = SVAL(req->vwv+5, 0);
3733 /* If it's an IPC, pass off the pipe handler. */
3734 if (IS_IPC(conn)) {
3735 reply_pipe_read_and_X(req);
3736 END_PROFILE(SMBreadX);
3737 return;
3740 if (!check_fsp(conn, req, fsp)) {
3741 END_PROFILE(SMBreadX);
3742 return;
3745 if (!CHECK_READ(fsp,req)) {
3746 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3747 END_PROFILE(SMBreadX);
3748 return;
3751 if (global_client_caps & CAP_LARGE_READX) {
3752 size_t upper_size = SVAL(req->vwv+7, 0);
3753 smb_maxcnt |= (upper_size<<16);
3754 if (upper_size > 1) {
3755 /* Can't do this on a chained packet. */
3756 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3757 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3758 END_PROFILE(SMBreadX);
3759 return;
3761 /* We currently don't do this on signed or sealed data. */
3762 if (srv_is_signing_active(req->sconn) ||
3763 is_encrypted_packet(req->inbuf)) {
3764 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3765 END_PROFILE(SMBreadX);
3766 return;
3768 /* Is there room in the reply for this data ? */
3769 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3770 reply_nterror(req,
3771 NT_STATUS_INVALID_PARAMETER);
3772 END_PROFILE(SMBreadX);
3773 return;
3775 big_readX = True;
3779 if (req->wct == 12) {
3780 #ifdef LARGE_SMB_OFF_T
3782 * This is a large offset (64 bit) read.
3784 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3786 #else /* !LARGE_SMB_OFF_T */
3789 * Ensure we haven't been sent a >32 bit offset.
3792 if(IVAL(req->vwv+10, 0) != 0) {
3793 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3794 "used and we don't support 64 bit offsets.\n",
3795 (unsigned int)IVAL(req->vwv+10, 0) ));
3796 END_PROFILE(SMBreadX);
3797 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3798 return;
3801 #endif /* LARGE_SMB_OFF_T */
3805 if (!big_readX) {
3806 NTSTATUS status = schedule_aio_read_and_X(conn,
3807 req,
3808 fsp,
3809 startpos,
3810 smb_maxcnt);
3811 if (NT_STATUS_IS_OK(status)) {
3812 /* Read scheduled - we're done. */
3813 goto out;
3815 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3816 /* Real error - report to client. */
3817 END_PROFILE(SMBreadX);
3818 reply_nterror(req, status);
3819 return;
3821 /* NT_STATUS_RETRY - fall back to sync read. */
3824 smbd_lock_socket(req->sconn);
3825 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3826 smbd_unlock_socket(req->sconn);
3828 out:
3829 END_PROFILE(SMBreadX);
3830 return;
3833 /****************************************************************************
3834 Error replies to writebraw must have smb_wct == 1. Fix this up.
3835 ****************************************************************************/
3837 void error_to_writebrawerr(struct smb_request *req)
3839 uint8 *old_outbuf = req->outbuf;
3841 reply_outbuf(req, 1, 0);
3843 memcpy(req->outbuf, old_outbuf, smb_size);
3844 TALLOC_FREE(old_outbuf);
3847 /****************************************************************************
3848 Read 4 bytes of a smb packet and return the smb length of the packet.
3849 Store the result in the buffer. This version of the function will
3850 never return a session keepalive (length of zero).
3851 Timeout is in milliseconds.
3852 ****************************************************************************/
3854 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3855 size_t *len)
3857 uint8_t msgtype = SMBkeepalive;
3859 while (msgtype == SMBkeepalive) {
3860 NTSTATUS status;
3862 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3863 len);
3864 if (!NT_STATUS_IS_OK(status)) {
3865 char addr[INET6_ADDRSTRLEN];
3866 /* Try and give an error message
3867 * saying what client failed. */
3868 DEBUG(0, ("read_fd_with_timeout failed for "
3869 "client %s read error = %s.\n",
3870 get_peer_addr(fd,addr,sizeof(addr)),
3871 nt_errstr(status)));
3872 return status;
3875 msgtype = CVAL(inbuf, 0);
3878 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3879 (unsigned long)len));
3881 return NT_STATUS_OK;
3884 /****************************************************************************
3885 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3886 ****************************************************************************/
3888 void reply_writebraw(struct smb_request *req)
3890 connection_struct *conn = req->conn;
3891 char *buf = NULL;
3892 ssize_t nwritten=0;
3893 ssize_t total_written=0;
3894 size_t numtowrite=0;
3895 size_t tcount;
3896 SMB_OFF_T startpos;
3897 char *data=NULL;
3898 bool write_through;
3899 files_struct *fsp;
3900 struct lock_struct lock;
3901 NTSTATUS status;
3903 START_PROFILE(SMBwritebraw);
3906 * If we ever reply with an error, it must have the SMB command
3907 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3908 * we're finished.
3910 SCVAL(req->inbuf,smb_com,SMBwritec);
3912 if (srv_is_signing_active(req->sconn)) {
3913 END_PROFILE(SMBwritebraw);
3914 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3915 "raw reads/writes are disallowed.");
3918 if (req->wct < 12) {
3919 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3920 error_to_writebrawerr(req);
3921 END_PROFILE(SMBwritebraw);
3922 return;
3925 if (req->sconn->smb1.echo_handler.trusted_fde) {
3926 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3927 "'async smb echo handler = yes'\n"));
3928 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3929 error_to_writebrawerr(req);
3930 END_PROFILE(SMBwritebraw);
3931 return;
3934 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3935 if (!check_fsp(conn, req, fsp)) {
3936 error_to_writebrawerr(req);
3937 END_PROFILE(SMBwritebraw);
3938 return;
3941 if (!CHECK_WRITE(fsp)) {
3942 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3943 error_to_writebrawerr(req);
3944 END_PROFILE(SMBwritebraw);
3945 return;
3948 tcount = IVAL(req->vwv+1, 0);
3949 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3950 write_through = BITSETW(req->vwv+7,0);
3952 /* We have to deal with slightly different formats depending
3953 on whether we are using the core+ or lanman1.0 protocol */
3955 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3956 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3957 data = smb_buf(req->inbuf);
3958 } else {
3959 numtowrite = SVAL(req->vwv+10, 0);
3960 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3963 /* Ensure we don't write bytes past the end of this packet. */
3964 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3965 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3966 error_to_writebrawerr(req);
3967 END_PROFILE(SMBwritebraw);
3968 return;
3971 if (!fsp->print_file) {
3972 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3973 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3974 &lock);
3976 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3977 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3978 error_to_writebrawerr(req);
3979 END_PROFILE(SMBwritebraw);
3980 return;
3984 if (numtowrite>0) {
3985 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3988 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3989 "wrote=%d sync=%d\n",
3990 fsp->fnum, (double)startpos, (int)numtowrite,
3991 (int)nwritten, (int)write_through));
3993 if (nwritten < (ssize_t)numtowrite) {
3994 reply_nterror(req, NT_STATUS_DISK_FULL);
3995 error_to_writebrawerr(req);
3996 goto strict_unlock;
3999 total_written = nwritten;
4001 /* Allocate a buffer of 64k + length. */
4002 buf = TALLOC_ARRAY(NULL, char, 65540);
4003 if (!buf) {
4004 reply_nterror(req, NT_STATUS_NO_MEMORY);
4005 error_to_writebrawerr(req);
4006 goto strict_unlock;
4009 /* Return a SMBwritebraw message to the redirector to tell
4010 * it to send more bytes */
4012 memcpy(buf, req->inbuf, smb_size);
4013 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4014 SCVAL(buf,smb_com,SMBwritebraw);
4015 SSVALS(buf,smb_vwv0,0xFFFF);
4016 show_msg(buf);
4017 if (!srv_send_smb(req->sconn,
4018 buf,
4019 false, 0, /* no signing */
4020 IS_CONN_ENCRYPTED(conn),
4021 &req->pcd)) {
4022 exit_server_cleanly("reply_writebraw: srv_send_smb "
4023 "failed.");
4026 /* Now read the raw data into the buffer and write it */
4027 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4028 &numtowrite);
4029 if (!NT_STATUS_IS_OK(status)) {
4030 exit_server_cleanly("secondary writebraw failed");
4033 /* Set up outbuf to return the correct size */
4034 reply_outbuf(req, 1, 0);
4036 if (numtowrite != 0) {
4038 if (numtowrite > 0xFFFF) {
4039 DEBUG(0,("reply_writebraw: Oversize secondary write "
4040 "raw requested (%u). Terminating\n",
4041 (unsigned int)numtowrite ));
4042 exit_server_cleanly("secondary writebraw failed");
4045 if (tcount > nwritten+numtowrite) {
4046 DEBUG(3,("reply_writebraw: Client overestimated the "
4047 "write %d %d %d\n",
4048 (int)tcount,(int)nwritten,(int)numtowrite));
4051 status = read_data(req->sconn->sock, buf+4, numtowrite);
4053 if (!NT_STATUS_IS_OK(status)) {
4054 char addr[INET6_ADDRSTRLEN];
4055 /* Try and give an error message
4056 * saying what client failed. */
4057 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4058 "raw read failed (%s) for client %s. "
4059 "Terminating\n", nt_errstr(status),
4060 get_peer_addr(req->sconn->sock, addr,
4061 sizeof(addr))));
4062 exit_server_cleanly("secondary writebraw failed");
4065 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4066 if (nwritten == -1) {
4067 TALLOC_FREE(buf);
4068 reply_nterror(req, map_nt_error_from_unix(errno));
4069 error_to_writebrawerr(req);
4070 goto strict_unlock;
4073 if (nwritten < (ssize_t)numtowrite) {
4074 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4075 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4078 if (nwritten > 0) {
4079 total_written += nwritten;
4083 TALLOC_FREE(buf);
4084 SSVAL(req->outbuf,smb_vwv0,total_written);
4086 status = sync_file(conn, fsp, write_through);
4087 if (!NT_STATUS_IS_OK(status)) {
4088 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4089 fsp_str_dbg(fsp), nt_errstr(status)));
4090 reply_nterror(req, status);
4091 error_to_writebrawerr(req);
4092 goto strict_unlock;
4095 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4096 "wrote=%d\n",
4097 fsp->fnum, (double)startpos, (int)numtowrite,
4098 (int)total_written));
4100 if (!fsp->print_file) {
4101 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4104 /* We won't return a status if write through is not selected - this
4105 * follows what WfWg does */
4106 END_PROFILE(SMBwritebraw);
4108 if (!write_through && total_written==tcount) {
4110 #if RABBIT_PELLET_FIX
4112 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4113 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
4114 * JRA.
4116 if (!send_keepalive(req->sconn->sock)) {
4117 exit_server_cleanly("reply_writebraw: send of "
4118 "keepalive failed");
4120 #endif
4121 TALLOC_FREE(req->outbuf);
4123 return;
4125 strict_unlock:
4126 if (!fsp->print_file) {
4127 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4130 END_PROFILE(SMBwritebraw);
4131 return;
4134 #undef DBGC_CLASS
4135 #define DBGC_CLASS DBGC_LOCKING
4137 /****************************************************************************
4138 Reply to a writeunlock (core+).
4139 ****************************************************************************/
4141 void reply_writeunlock(struct smb_request *req)
4143 connection_struct *conn = req->conn;
4144 ssize_t nwritten = -1;
4145 size_t numtowrite;
4146 SMB_OFF_T startpos;
4147 const char *data;
4148 NTSTATUS status = NT_STATUS_OK;
4149 files_struct *fsp;
4150 struct lock_struct lock;
4151 int saved_errno = 0;
4153 START_PROFILE(SMBwriteunlock);
4155 if (req->wct < 5) {
4156 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4157 END_PROFILE(SMBwriteunlock);
4158 return;
4161 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4163 if (!check_fsp(conn, req, fsp)) {
4164 END_PROFILE(SMBwriteunlock);
4165 return;
4168 if (!CHECK_WRITE(fsp)) {
4169 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4170 END_PROFILE(SMBwriteunlock);
4171 return;
4174 numtowrite = SVAL(req->vwv+1, 0);
4175 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4176 data = (const char *)req->buf + 3;
4178 if (!fsp->print_file && numtowrite > 0) {
4179 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4180 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4181 &lock);
4183 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4184 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4185 END_PROFILE(SMBwriteunlock);
4186 return;
4190 /* The special X/Open SMB protocol handling of
4191 zero length writes is *NOT* done for
4192 this call */
4193 if(numtowrite == 0) {
4194 nwritten = 0;
4195 } else {
4196 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4197 saved_errno = errno;
4200 status = sync_file(conn, fsp, False /* write through */);
4201 if (!NT_STATUS_IS_OK(status)) {
4202 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4203 fsp_str_dbg(fsp), nt_errstr(status)));
4204 reply_nterror(req, status);
4205 goto strict_unlock;
4208 if(nwritten < 0) {
4209 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4210 goto strict_unlock;
4213 if((nwritten < numtowrite) && (numtowrite != 0)) {
4214 reply_nterror(req, NT_STATUS_DISK_FULL);
4215 goto strict_unlock;
4218 if (numtowrite && !fsp->print_file) {
4219 status = do_unlock(req->sconn->msg_ctx,
4220 fsp,
4221 (uint64_t)req->smbpid,
4222 (uint64_t)numtowrite,
4223 (uint64_t)startpos,
4224 WINDOWS_LOCK);
4226 if (NT_STATUS_V(status)) {
4227 reply_nterror(req, status);
4228 goto strict_unlock;
4232 reply_outbuf(req, 1, 0);
4234 SSVAL(req->outbuf,smb_vwv0,nwritten);
4236 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4237 fsp->fnum, (int)numtowrite, (int)nwritten));
4239 strict_unlock:
4240 if (numtowrite && !fsp->print_file) {
4241 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4244 END_PROFILE(SMBwriteunlock);
4245 return;
4248 #undef DBGC_CLASS
4249 #define DBGC_CLASS DBGC_ALL
4251 /****************************************************************************
4252 Reply to a write.
4253 ****************************************************************************/
4255 void reply_write(struct smb_request *req)
4257 connection_struct *conn = req->conn;
4258 size_t numtowrite;
4259 ssize_t nwritten = -1;
4260 SMB_OFF_T startpos;
4261 const char *data;
4262 files_struct *fsp;
4263 struct lock_struct lock;
4264 NTSTATUS status;
4265 int saved_errno = 0;
4267 START_PROFILE(SMBwrite);
4269 if (req->wct < 5) {
4270 END_PROFILE(SMBwrite);
4271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4272 return;
4275 /* If it's an IPC, pass off the pipe handler. */
4276 if (IS_IPC(conn)) {
4277 reply_pipe_write(req);
4278 END_PROFILE(SMBwrite);
4279 return;
4282 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4284 if (!check_fsp(conn, req, fsp)) {
4285 END_PROFILE(SMBwrite);
4286 return;
4289 if (!CHECK_WRITE(fsp)) {
4290 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4291 END_PROFILE(SMBwrite);
4292 return;
4295 numtowrite = SVAL(req->vwv+1, 0);
4296 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4297 data = (const char *)req->buf + 3;
4299 if (!fsp->print_file) {
4300 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4301 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4302 &lock);
4304 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4305 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4306 END_PROFILE(SMBwrite);
4307 return;
4312 * X/Open SMB protocol says that if smb_vwv1 is
4313 * zero then the file size should be extended or
4314 * truncated to the size given in smb_vwv[2-3].
4317 if(numtowrite == 0) {
4319 * This is actually an allocate call, and set EOF. JRA.
4321 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4322 if (nwritten < 0) {
4323 reply_nterror(req, NT_STATUS_DISK_FULL);
4324 goto strict_unlock;
4326 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4327 if (nwritten < 0) {
4328 reply_nterror(req, NT_STATUS_DISK_FULL);
4329 goto strict_unlock;
4331 trigger_write_time_update_immediate(fsp);
4332 } else {
4333 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4336 status = sync_file(conn, fsp, False);
4337 if (!NT_STATUS_IS_OK(status)) {
4338 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4339 fsp_str_dbg(fsp), nt_errstr(status)));
4340 reply_nterror(req, status);
4341 goto strict_unlock;
4344 if(nwritten < 0) {
4345 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4346 goto strict_unlock;
4349 if((nwritten == 0) && (numtowrite != 0)) {
4350 reply_nterror(req, NT_STATUS_DISK_FULL);
4351 goto strict_unlock;
4354 reply_outbuf(req, 1, 0);
4356 SSVAL(req->outbuf,smb_vwv0,nwritten);
4358 if (nwritten < (ssize_t)numtowrite) {
4359 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4360 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4363 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4365 strict_unlock:
4366 if (!fsp->print_file) {
4367 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4370 END_PROFILE(SMBwrite);
4371 return;
4374 /****************************************************************************
4375 Ensure a buffer is a valid writeX for recvfile purposes.
4376 ****************************************************************************/
4378 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4379 (2*14) + /* word count (including bcc) */ \
4380 1 /* pad byte */)
4382 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4383 const uint8_t *inbuf)
4385 size_t numtowrite;
4386 connection_struct *conn = NULL;
4387 unsigned int doff = 0;
4388 size_t len = smb_len_large(inbuf);
4390 if (is_encrypted_packet(inbuf)) {
4391 /* Can't do this on encrypted
4392 * connections. */
4393 return false;
4396 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4397 return false;
4400 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4401 CVAL(inbuf,smb_wct) != 14) {
4402 DEBUG(10,("is_valid_writeX_buffer: chained or "
4403 "invalid word length.\n"));
4404 return false;
4407 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4408 if (conn == NULL) {
4409 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4410 return false;
4412 if (IS_IPC(conn)) {
4413 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4414 return false;
4416 if (IS_PRINT(conn)) {
4417 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4418 return false;
4420 doff = SVAL(inbuf,smb_vwv11);
4422 numtowrite = SVAL(inbuf,smb_vwv10);
4424 if (len > doff && len - doff > 0xFFFF) {
4425 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4428 if (numtowrite == 0) {
4429 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4430 return false;
4433 /* Ensure the sizes match up. */
4434 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4435 /* no pad byte...old smbclient :-( */
4436 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4437 (unsigned int)doff,
4438 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4439 return false;
4442 if (len - doff != numtowrite) {
4443 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4444 "len = %u, doff = %u, numtowrite = %u\n",
4445 (unsigned int)len,
4446 (unsigned int)doff,
4447 (unsigned int)numtowrite ));
4448 return false;
4451 DEBUG(10,("is_valid_writeX_buffer: true "
4452 "len = %u, doff = %u, numtowrite = %u\n",
4453 (unsigned int)len,
4454 (unsigned int)doff,
4455 (unsigned int)numtowrite ));
4457 return true;
4460 /****************************************************************************
4461 Reply to a write and X.
4462 ****************************************************************************/
4464 void reply_write_and_X(struct smb_request *req)
4466 connection_struct *conn = req->conn;
4467 files_struct *fsp;
4468 struct lock_struct lock;
4469 SMB_OFF_T startpos;
4470 size_t numtowrite;
4471 bool write_through;
4472 ssize_t nwritten;
4473 unsigned int smb_doff;
4474 unsigned int smblen;
4475 char *data;
4476 NTSTATUS status;
4477 int saved_errno = 0;
4479 START_PROFILE(SMBwriteX);
4481 if ((req->wct != 12) && (req->wct != 14)) {
4482 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4483 END_PROFILE(SMBwriteX);
4484 return;
4487 numtowrite = SVAL(req->vwv+10, 0);
4488 smb_doff = SVAL(req->vwv+11, 0);
4489 smblen = smb_len(req->inbuf);
4491 if (req->unread_bytes > 0xFFFF ||
4492 (smblen > smb_doff &&
4493 smblen - smb_doff > 0xFFFF)) {
4494 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4497 if (req->unread_bytes) {
4498 /* Can't do a recvfile write on IPC$ */
4499 if (IS_IPC(conn)) {
4500 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4501 END_PROFILE(SMBwriteX);
4502 return;
4504 if (numtowrite != req->unread_bytes) {
4505 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4506 END_PROFILE(SMBwriteX);
4507 return;
4509 } else {
4510 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4511 smb_doff + numtowrite > smblen) {
4512 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4513 END_PROFILE(SMBwriteX);
4514 return;
4518 /* If it's an IPC, pass off the pipe handler. */
4519 if (IS_IPC(conn)) {
4520 if (req->unread_bytes) {
4521 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4522 END_PROFILE(SMBwriteX);
4523 return;
4525 reply_pipe_write_and_X(req);
4526 END_PROFILE(SMBwriteX);
4527 return;
4530 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4531 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4532 write_through = BITSETW(req->vwv+7,0);
4534 if (!check_fsp(conn, req, fsp)) {
4535 END_PROFILE(SMBwriteX);
4536 return;
4539 if (!CHECK_WRITE(fsp)) {
4540 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4541 END_PROFILE(SMBwriteX);
4542 return;
4545 data = smb_base(req->inbuf) + smb_doff;
4547 if(req->wct == 14) {
4548 #ifdef LARGE_SMB_OFF_T
4550 * This is a large offset (64 bit) write.
4552 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4554 #else /* !LARGE_SMB_OFF_T */
4557 * Ensure we haven't been sent a >32 bit offset.
4560 if(IVAL(req->vwv+12, 0) != 0) {
4561 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4562 "used and we don't support 64 bit offsets.\n",
4563 (unsigned int)IVAL(req->vwv+12, 0) ));
4564 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4565 END_PROFILE(SMBwriteX);
4566 return;
4569 #endif /* LARGE_SMB_OFF_T */
4572 /* X/Open SMB protocol says that, unlike SMBwrite
4573 if the length is zero then NO truncation is
4574 done, just a write of zero. To truncate a file,
4575 use SMBwrite. */
4577 if(numtowrite == 0) {
4578 nwritten = 0;
4579 } else {
4580 if (req->unread_bytes == 0) {
4581 status = schedule_aio_write_and_X(conn,
4582 req,
4583 fsp,
4584 data,
4585 startpos,
4586 numtowrite);
4588 if (NT_STATUS_IS_OK(status)) {
4589 /* write scheduled - we're done. */
4590 goto out;
4592 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4593 /* Real error - report to client. */
4594 reply_nterror(req, status);
4595 goto out;
4597 /* NT_STATUS_RETRY - fall through to sync write. */
4600 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4601 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4602 &lock);
4604 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4605 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4606 goto out;
4609 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4610 saved_errno = errno;
4612 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4615 if(nwritten < 0) {
4616 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4617 goto out;
4620 if((nwritten == 0) && (numtowrite != 0)) {
4621 reply_nterror(req, NT_STATUS_DISK_FULL);
4622 goto out;
4625 reply_outbuf(req, 6, 0);
4626 SSVAL(req->outbuf,smb_vwv2,nwritten);
4627 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4629 if (nwritten < (ssize_t)numtowrite) {
4630 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4631 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4634 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4635 fsp->fnum, (int)numtowrite, (int)nwritten));
4637 status = sync_file(conn, fsp, write_through);
4638 if (!NT_STATUS_IS_OK(status)) {
4639 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4640 fsp_str_dbg(fsp), nt_errstr(status)));
4641 reply_nterror(req, status);
4642 goto out;
4645 END_PROFILE(SMBwriteX);
4646 chain_reply(req);
4647 return;
4649 out:
4650 END_PROFILE(SMBwriteX);
4651 return;
4654 /****************************************************************************
4655 Reply to a lseek.
4656 ****************************************************************************/
4658 void reply_lseek(struct smb_request *req)
4660 connection_struct *conn = req->conn;
4661 SMB_OFF_T startpos;
4662 SMB_OFF_T res= -1;
4663 int mode,umode;
4664 files_struct *fsp;
4666 START_PROFILE(SMBlseek);
4668 if (req->wct < 4) {
4669 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4670 END_PROFILE(SMBlseek);
4671 return;
4674 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4676 if (!check_fsp(conn, req, fsp)) {
4677 return;
4680 flush_write_cache(fsp, SEEK_FLUSH);
4682 mode = SVAL(req->vwv+1, 0) & 3;
4683 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4684 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4686 switch (mode) {
4687 case 0:
4688 umode = SEEK_SET;
4689 res = startpos;
4690 break;
4691 case 1:
4692 umode = SEEK_CUR;
4693 res = fsp->fh->pos + startpos;
4694 break;
4695 case 2:
4696 umode = SEEK_END;
4697 break;
4698 default:
4699 umode = SEEK_SET;
4700 res = startpos;
4701 break;
4704 if (umode == SEEK_END) {
4705 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4706 if(errno == EINVAL) {
4707 SMB_OFF_T current_pos = startpos;
4709 if(fsp_stat(fsp) == -1) {
4710 reply_nterror(req,
4711 map_nt_error_from_unix(errno));
4712 END_PROFILE(SMBlseek);
4713 return;
4716 current_pos += fsp->fsp_name->st.st_ex_size;
4717 if(current_pos < 0)
4718 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4722 if(res == -1) {
4723 reply_nterror(req, map_nt_error_from_unix(errno));
4724 END_PROFILE(SMBlseek);
4725 return;
4729 fsp->fh->pos = res;
4731 reply_outbuf(req, 2, 0);
4732 SIVAL(req->outbuf,smb_vwv0,res);
4734 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4735 fsp->fnum, (double)startpos, (double)res, mode));
4737 END_PROFILE(SMBlseek);
4738 return;
4741 /****************************************************************************
4742 Reply to a flush.
4743 ****************************************************************************/
4745 void reply_flush(struct smb_request *req)
4747 connection_struct *conn = req->conn;
4748 uint16 fnum;
4749 files_struct *fsp;
4751 START_PROFILE(SMBflush);
4753 if (req->wct < 1) {
4754 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4755 return;
4758 fnum = SVAL(req->vwv+0, 0);
4759 fsp = file_fsp(req, fnum);
4761 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4762 return;
4765 if (!fsp) {
4766 file_sync_all(conn);
4767 } else {
4768 NTSTATUS status = sync_file(conn, fsp, True);
4769 if (!NT_STATUS_IS_OK(status)) {
4770 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4771 fsp_str_dbg(fsp), nt_errstr(status)));
4772 reply_nterror(req, status);
4773 END_PROFILE(SMBflush);
4774 return;
4778 reply_outbuf(req, 0, 0);
4780 DEBUG(3,("flush\n"));
4781 END_PROFILE(SMBflush);
4782 return;
4785 /****************************************************************************
4786 Reply to a exit.
4787 conn POINTER CAN BE NULL HERE !
4788 ****************************************************************************/
4790 void reply_exit(struct smb_request *req)
4792 START_PROFILE(SMBexit);
4794 file_close_pid(req->sconn, req->smbpid, req->vuid);
4796 reply_outbuf(req, 0, 0);
4798 DEBUG(3,("exit\n"));
4800 END_PROFILE(SMBexit);
4801 return;
4804 /****************************************************************************
4805 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4806 ****************************************************************************/
4808 void reply_close(struct smb_request *req)
4810 connection_struct *conn = req->conn;
4811 NTSTATUS status = NT_STATUS_OK;
4812 files_struct *fsp = NULL;
4813 START_PROFILE(SMBclose);
4815 if (req->wct < 3) {
4816 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4817 END_PROFILE(SMBclose);
4818 return;
4821 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4824 * We can only use check_fsp if we know it's not a directory.
4827 if (!check_fsp_open(conn, req, fsp)) {
4828 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4829 END_PROFILE(SMBclose);
4830 return;
4833 if(fsp->is_directory) {
4835 * Special case - close NT SMB directory handle.
4837 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4838 status = close_file(req, fsp, NORMAL_CLOSE);
4839 } else {
4840 time_t t;
4842 * Close ordinary file.
4845 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4846 fsp->fh->fd, fsp->fnum,
4847 conn->num_files_open));
4850 * Take care of any time sent in the close.
4853 t = srv_make_unix_date3(req->vwv+1);
4854 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4857 * close_file() returns the unix errno if an error
4858 * was detected on close - normally this is due to
4859 * a disk full error. If not then it was probably an I/O error.
4862 status = close_file(req, fsp, NORMAL_CLOSE);
4865 if (!NT_STATUS_IS_OK(status)) {
4866 reply_nterror(req, status);
4867 END_PROFILE(SMBclose);
4868 return;
4871 reply_outbuf(req, 0, 0);
4872 END_PROFILE(SMBclose);
4873 return;
4876 /****************************************************************************
4877 Reply to a writeclose (Core+ protocol).
4878 ****************************************************************************/
4880 void reply_writeclose(struct smb_request *req)
4882 connection_struct *conn = req->conn;
4883 size_t numtowrite;
4884 ssize_t nwritten = -1;
4885 NTSTATUS close_status = NT_STATUS_OK;
4886 SMB_OFF_T startpos;
4887 const char *data;
4888 struct timespec mtime;
4889 files_struct *fsp;
4890 struct lock_struct lock;
4892 START_PROFILE(SMBwriteclose);
4894 if (req->wct < 6) {
4895 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4896 END_PROFILE(SMBwriteclose);
4897 return;
4900 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4902 if (!check_fsp(conn, req, fsp)) {
4903 END_PROFILE(SMBwriteclose);
4904 return;
4906 if (!CHECK_WRITE(fsp)) {
4907 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4908 END_PROFILE(SMBwriteclose);
4909 return;
4912 numtowrite = SVAL(req->vwv+1, 0);
4913 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4914 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4915 data = (const char *)req->buf + 1;
4917 if (!fsp->print_file) {
4918 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4919 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4920 &lock);
4922 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4923 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4924 END_PROFILE(SMBwriteclose);
4925 return;
4929 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4931 set_close_write_time(fsp, mtime);
4934 * More insanity. W2K only closes the file if writelen > 0.
4935 * JRA.
4938 if (numtowrite) {
4939 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4940 "file %s\n", fsp_str_dbg(fsp)));
4941 close_status = close_file(req, fsp, NORMAL_CLOSE);
4944 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4945 fsp->fnum, (int)numtowrite, (int)nwritten,
4946 conn->num_files_open));
4948 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4949 reply_nterror(req, NT_STATUS_DISK_FULL);
4950 goto strict_unlock;
4953 if(!NT_STATUS_IS_OK(close_status)) {
4954 reply_nterror(req, close_status);
4955 goto strict_unlock;
4958 reply_outbuf(req, 1, 0);
4960 SSVAL(req->outbuf,smb_vwv0,nwritten);
4962 strict_unlock:
4963 if (numtowrite && !fsp->print_file) {
4964 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4967 END_PROFILE(SMBwriteclose);
4968 return;
4971 #undef DBGC_CLASS
4972 #define DBGC_CLASS DBGC_LOCKING
4974 /****************************************************************************
4975 Reply to a lock.
4976 ****************************************************************************/
4978 void reply_lock(struct smb_request *req)
4980 connection_struct *conn = req->conn;
4981 uint64_t count,offset;
4982 NTSTATUS status;
4983 files_struct *fsp;
4984 struct byte_range_lock *br_lck = NULL;
4986 START_PROFILE(SMBlock);
4988 if (req->wct < 5) {
4989 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4990 END_PROFILE(SMBlock);
4991 return;
4994 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4996 if (!check_fsp(conn, req, fsp)) {
4997 END_PROFILE(SMBlock);
4998 return;
5001 count = (uint64_t)IVAL(req->vwv+1, 0);
5002 offset = (uint64_t)IVAL(req->vwv+3, 0);
5004 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5005 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5007 br_lck = do_lock(req->sconn->msg_ctx,
5008 fsp,
5009 (uint64_t)req->smbpid,
5010 count,
5011 offset,
5012 WRITE_LOCK,
5013 WINDOWS_LOCK,
5014 False, /* Non-blocking lock. */
5015 &status,
5016 NULL,
5017 NULL);
5019 TALLOC_FREE(br_lck);
5021 if (NT_STATUS_V(status)) {
5022 reply_nterror(req, status);
5023 END_PROFILE(SMBlock);
5024 return;
5027 reply_outbuf(req, 0, 0);
5029 END_PROFILE(SMBlock);
5030 return;
5033 /****************************************************************************
5034 Reply to a unlock.
5035 ****************************************************************************/
5037 void reply_unlock(struct smb_request *req)
5039 connection_struct *conn = req->conn;
5040 uint64_t count,offset;
5041 NTSTATUS status;
5042 files_struct *fsp;
5044 START_PROFILE(SMBunlock);
5046 if (req->wct < 5) {
5047 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5048 END_PROFILE(SMBunlock);
5049 return;
5052 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5054 if (!check_fsp(conn, req, fsp)) {
5055 END_PROFILE(SMBunlock);
5056 return;
5059 count = (uint64_t)IVAL(req->vwv+1, 0);
5060 offset = (uint64_t)IVAL(req->vwv+3, 0);
5062 status = do_unlock(req->sconn->msg_ctx,
5063 fsp,
5064 (uint64_t)req->smbpid,
5065 count,
5066 offset,
5067 WINDOWS_LOCK);
5069 if (NT_STATUS_V(status)) {
5070 reply_nterror(req, status);
5071 END_PROFILE(SMBunlock);
5072 return;
5075 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5076 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5078 reply_outbuf(req, 0, 0);
5080 END_PROFILE(SMBunlock);
5081 return;
5084 #undef DBGC_CLASS
5085 #define DBGC_CLASS DBGC_ALL
5087 /****************************************************************************
5088 Reply to a tdis.
5089 conn POINTER CAN BE NULL HERE !
5090 ****************************************************************************/
5092 void reply_tdis(struct smb_request *req)
5094 connection_struct *conn = req->conn;
5095 START_PROFILE(SMBtdis);
5097 if (!conn) {
5098 DEBUG(4,("Invalid connection in tdis\n"));
5099 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5100 END_PROFILE(SMBtdis);
5101 return;
5104 conn->used = False;
5106 close_cnum(conn,req->vuid);
5107 req->conn = NULL;
5109 reply_outbuf(req, 0, 0);
5110 END_PROFILE(SMBtdis);
5111 return;
5114 /****************************************************************************
5115 Reply to a echo.
5116 conn POINTER CAN BE NULL HERE !
5117 ****************************************************************************/
5119 void reply_echo(struct smb_request *req)
5121 connection_struct *conn = req->conn;
5122 struct smb_perfcount_data local_pcd;
5123 struct smb_perfcount_data *cur_pcd;
5124 int smb_reverb;
5125 int seq_num;
5127 START_PROFILE(SMBecho);
5129 smb_init_perfcount_data(&local_pcd);
5131 if (req->wct < 1) {
5132 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5133 END_PROFILE(SMBecho);
5134 return;
5137 smb_reverb = SVAL(req->vwv+0, 0);
5139 reply_outbuf(req, 1, req->buflen);
5141 /* copy any incoming data back out */
5142 if (req->buflen > 0) {
5143 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5146 if (smb_reverb > 100) {
5147 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5148 smb_reverb = 100;
5151 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5153 /* this makes sure we catch the request pcd */
5154 if (seq_num == smb_reverb) {
5155 cur_pcd = &req->pcd;
5156 } else {
5157 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5158 cur_pcd = &local_pcd;
5161 SSVAL(req->outbuf,smb_vwv0,seq_num);
5163 show_msg((char *)req->outbuf);
5164 if (!srv_send_smb(req->sconn,
5165 (char *)req->outbuf,
5166 true, req->seqnum+1,
5167 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5168 cur_pcd))
5169 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5172 DEBUG(3,("echo %d times\n", smb_reverb));
5174 TALLOC_FREE(req->outbuf);
5176 END_PROFILE(SMBecho);
5177 return;
5180 /****************************************************************************
5181 Reply to a printopen.
5182 ****************************************************************************/
5184 void reply_printopen(struct smb_request *req)
5186 connection_struct *conn = req->conn;
5187 files_struct *fsp;
5188 NTSTATUS status;
5190 START_PROFILE(SMBsplopen);
5192 if (req->wct < 2) {
5193 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5194 END_PROFILE(SMBsplopen);
5195 return;
5198 if (!CAN_PRINT(conn)) {
5199 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5200 END_PROFILE(SMBsplopen);
5201 return;
5204 status = file_new(req, conn, &fsp);
5205 if(!NT_STATUS_IS_OK(status)) {
5206 reply_nterror(req, status);
5207 END_PROFILE(SMBsplopen);
5208 return;
5211 /* Open for exclusive use, write only. */
5212 status = print_spool_open(fsp, NULL, req->vuid);
5214 if (!NT_STATUS_IS_OK(status)) {
5215 file_free(req, fsp);
5216 reply_nterror(req, status);
5217 END_PROFILE(SMBsplopen);
5218 return;
5221 reply_outbuf(req, 1, 0);
5222 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5224 DEBUG(3,("openprint fd=%d fnum=%d\n",
5225 fsp->fh->fd, fsp->fnum));
5227 END_PROFILE(SMBsplopen);
5228 return;
5231 /****************************************************************************
5232 Reply to a printclose.
5233 ****************************************************************************/
5235 void reply_printclose(struct smb_request *req)
5237 connection_struct *conn = req->conn;
5238 files_struct *fsp;
5239 NTSTATUS status;
5241 START_PROFILE(SMBsplclose);
5243 if (req->wct < 1) {
5244 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5245 END_PROFILE(SMBsplclose);
5246 return;
5249 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5251 if (!check_fsp(conn, req, fsp)) {
5252 END_PROFILE(SMBsplclose);
5253 return;
5256 if (!CAN_PRINT(conn)) {
5257 reply_force_doserror(req, ERRSRV, ERRerror);
5258 END_PROFILE(SMBsplclose);
5259 return;
5262 DEBUG(3,("printclose fd=%d fnum=%d\n",
5263 fsp->fh->fd,fsp->fnum));
5265 status = close_file(req, fsp, NORMAL_CLOSE);
5267 if(!NT_STATUS_IS_OK(status)) {
5268 reply_nterror(req, status);
5269 END_PROFILE(SMBsplclose);
5270 return;
5273 reply_outbuf(req, 0, 0);
5275 END_PROFILE(SMBsplclose);
5276 return;
5279 /****************************************************************************
5280 Reply to a printqueue.
5281 ****************************************************************************/
5283 void reply_printqueue(struct smb_request *req)
5285 connection_struct *conn = req->conn;
5286 int max_count;
5287 int start_index;
5289 START_PROFILE(SMBsplretq);
5291 if (req->wct < 2) {
5292 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5293 END_PROFILE(SMBsplretq);
5294 return;
5297 max_count = SVAL(req->vwv+0, 0);
5298 start_index = SVAL(req->vwv+1, 0);
5300 /* we used to allow the client to get the cnum wrong, but that
5301 is really quite gross and only worked when there was only
5302 one printer - I think we should now only accept it if they
5303 get it right (tridge) */
5304 if (!CAN_PRINT(conn)) {
5305 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5306 END_PROFILE(SMBsplretq);
5307 return;
5310 reply_outbuf(req, 2, 3);
5311 SSVAL(req->outbuf,smb_vwv0,0);
5312 SSVAL(req->outbuf,smb_vwv1,0);
5313 SCVAL(smb_buf(req->outbuf),0,1);
5314 SSVAL(smb_buf(req->outbuf),1,0);
5316 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5317 start_index, max_count));
5320 TALLOC_CTX *mem_ctx = talloc_tos();
5321 NTSTATUS status;
5322 WERROR werr;
5323 const char *sharename = lp_servicename(SNUM(conn));
5324 struct rpc_pipe_client *cli = NULL;
5325 struct dcerpc_binding_handle *b = NULL;
5326 struct policy_handle handle;
5327 struct spoolss_DevmodeContainer devmode_ctr;
5328 union spoolss_JobInfo *info;
5329 uint32_t count;
5330 uint32_t num_to_get;
5331 uint32_t first;
5332 uint32_t i;
5334 ZERO_STRUCT(handle);
5336 status = rpc_pipe_open_interface(conn,
5337 &ndr_table_spoolss.syntax_id,
5338 conn->session_info,
5339 &conn->sconn->client_id,
5340 conn->sconn->msg_ctx,
5341 &cli);
5342 if (!NT_STATUS_IS_OK(status)) {
5343 DEBUG(0, ("reply_printqueue: "
5344 "could not connect to spoolss: %s\n",
5345 nt_errstr(status)));
5346 reply_nterror(req, status);
5347 goto out;
5349 b = cli->binding_handle;
5351 ZERO_STRUCT(devmode_ctr);
5353 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5354 sharename,
5355 NULL, devmode_ctr,
5356 SEC_FLAG_MAXIMUM_ALLOWED,
5357 &handle,
5358 &werr);
5359 if (!NT_STATUS_IS_OK(status)) {
5360 reply_nterror(req, status);
5361 goto out;
5363 if (!W_ERROR_IS_OK(werr)) {
5364 reply_nterror(req, werror_to_ntstatus(werr));
5365 goto out;
5368 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5369 &handle,
5370 0, /* firstjob */
5371 0xff, /* numjobs */
5372 2, /* level */
5373 0, /* offered */
5374 &count,
5375 &info);
5376 if (!W_ERROR_IS_OK(werr)) {
5377 reply_nterror(req, werror_to_ntstatus(werr));
5378 goto out;
5381 if (max_count > 0) {
5382 first = start_index;
5383 } else {
5384 first = start_index + max_count + 1;
5387 if (first >= count) {
5388 num_to_get = first;
5389 } else {
5390 num_to_get = first + MIN(ABS(max_count), count - first);
5393 for (i = first; i < num_to_get; i++) {
5394 char blob[28];
5395 char *p = blob;
5396 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5397 int qstatus;
5398 uint16_t qrapjobid = pjobid_to_rap(sharename,
5399 info[i].info2.job_id);
5401 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5402 qstatus = 2;
5403 } else {
5404 qstatus = 3;
5407 srv_put_dos_date2(p, 0, qtime);
5408 SCVAL(p, 4, qstatus);
5409 SSVAL(p, 5, qrapjobid);
5410 SIVAL(p, 7, info[i].info2.size);
5411 SCVAL(p, 11, 0);
5412 srvstr_push(blob, req->flags2, p+12,
5413 info[i].info2.notify_name, 16, STR_ASCII);
5415 if (message_push_blob(
5416 &req->outbuf,
5417 data_blob_const(
5418 blob, sizeof(blob))) == -1) {
5419 reply_nterror(req, NT_STATUS_NO_MEMORY);
5420 goto out;
5424 if (count > 0) {
5425 SSVAL(req->outbuf,smb_vwv0,count);
5426 SSVAL(req->outbuf,smb_vwv1,
5427 (max_count>0?first+count:first-1));
5428 SCVAL(smb_buf(req->outbuf),0,1);
5429 SSVAL(smb_buf(req->outbuf),1,28*count);
5433 DEBUG(3, ("%u entries returned in queue\n",
5434 (unsigned)count));
5436 out:
5437 if (b && is_valid_policy_hnd(&handle)) {
5438 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5443 END_PROFILE(SMBsplretq);
5444 return;
5447 /****************************************************************************
5448 Reply to a printwrite.
5449 ****************************************************************************/
5451 void reply_printwrite(struct smb_request *req)
5453 connection_struct *conn = req->conn;
5454 int numtowrite;
5455 const char *data;
5456 files_struct *fsp;
5458 START_PROFILE(SMBsplwr);
5460 if (req->wct < 1) {
5461 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5462 END_PROFILE(SMBsplwr);
5463 return;
5466 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5468 if (!check_fsp(conn, req, fsp)) {
5469 END_PROFILE(SMBsplwr);
5470 return;
5473 if (!fsp->print_file) {
5474 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5475 END_PROFILE(SMBsplwr);
5476 return;
5479 if (!CHECK_WRITE(fsp)) {
5480 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5481 END_PROFILE(SMBsplwr);
5482 return;
5485 numtowrite = SVAL(req->buf, 1);
5487 if (req->buflen < numtowrite + 3) {
5488 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5489 END_PROFILE(SMBsplwr);
5490 return;
5493 data = (const char *)req->buf + 3;
5495 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5496 reply_nterror(req, map_nt_error_from_unix(errno));
5497 END_PROFILE(SMBsplwr);
5498 return;
5501 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5503 END_PROFILE(SMBsplwr);
5504 return;
5507 /****************************************************************************
5508 Reply to a mkdir.
5509 ****************************************************************************/
5511 void reply_mkdir(struct smb_request *req)
5513 connection_struct *conn = req->conn;
5514 struct smb_filename *smb_dname = NULL;
5515 char *directory = NULL;
5516 NTSTATUS status;
5517 TALLOC_CTX *ctx = talloc_tos();
5519 START_PROFILE(SMBmkdir);
5521 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5522 STR_TERMINATE, &status);
5523 if (!NT_STATUS_IS_OK(status)) {
5524 reply_nterror(req, status);
5525 goto out;
5528 status = filename_convert(ctx, conn,
5529 req->flags2 & FLAGS2_DFS_PATHNAMES,
5530 directory,
5532 NULL,
5533 &smb_dname);
5534 if (!NT_STATUS_IS_OK(status)) {
5535 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5536 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5537 ERRSRV, ERRbadpath);
5538 goto out;
5540 reply_nterror(req, status);
5541 goto out;
5544 status = create_directory(conn, req, smb_dname);
5546 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5548 if (!NT_STATUS_IS_OK(status)) {
5550 if (!use_nt_status()
5551 && NT_STATUS_EQUAL(status,
5552 NT_STATUS_OBJECT_NAME_COLLISION)) {
5554 * Yes, in the DOS error code case we get a
5555 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5556 * samba4 torture test.
5558 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5561 reply_nterror(req, status);
5562 goto out;
5565 reply_outbuf(req, 0, 0);
5567 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5568 out:
5569 TALLOC_FREE(smb_dname);
5570 END_PROFILE(SMBmkdir);
5571 return;
5574 /****************************************************************************
5575 Reply to a rmdir.
5576 ****************************************************************************/
5578 void reply_rmdir(struct smb_request *req)
5580 connection_struct *conn = req->conn;
5581 struct smb_filename *smb_dname = NULL;
5582 char *directory = NULL;
5583 NTSTATUS status;
5584 TALLOC_CTX *ctx = talloc_tos();
5585 files_struct *fsp = NULL;
5586 int info = 0;
5587 struct smbd_server_connection *sconn = req->sconn;
5589 START_PROFILE(SMBrmdir);
5591 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5592 STR_TERMINATE, &status);
5593 if (!NT_STATUS_IS_OK(status)) {
5594 reply_nterror(req, status);
5595 goto out;
5598 status = filename_convert(ctx, conn,
5599 req->flags2 & FLAGS2_DFS_PATHNAMES,
5600 directory,
5602 NULL,
5603 &smb_dname);
5604 if (!NT_STATUS_IS_OK(status)) {
5605 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5606 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5607 ERRSRV, ERRbadpath);
5608 goto out;
5610 reply_nterror(req, status);
5611 goto out;
5614 if (is_ntfs_stream_smb_fname(smb_dname)) {
5615 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5616 goto out;
5619 status = SMB_VFS_CREATE_FILE(
5620 conn, /* conn */
5621 req, /* req */
5622 0, /* root_dir_fid */
5623 smb_dname, /* fname */
5624 DELETE_ACCESS, /* access_mask */
5625 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5626 FILE_SHARE_DELETE),
5627 FILE_OPEN, /* create_disposition*/
5628 FILE_DIRECTORY_FILE, /* create_options */
5629 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5630 0, /* oplock_request */
5631 0, /* allocation_size */
5632 0, /* private_flags */
5633 NULL, /* sd */
5634 NULL, /* ea_list */
5635 &fsp, /* result */
5636 &info); /* pinfo */
5638 if (!NT_STATUS_IS_OK(status)) {
5639 if (open_was_deferred(req->mid)) {
5640 /* We have re-scheduled this call. */
5641 goto out;
5643 reply_nterror(req, status);
5644 goto out;
5647 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5648 if (!NT_STATUS_IS_OK(status)) {
5649 close_file(req, fsp, ERROR_CLOSE);
5650 reply_nterror(req, status);
5651 goto out;
5654 if (!set_delete_on_close(fsp, true, &conn->session_info->utok)) {
5655 close_file(req, fsp, ERROR_CLOSE);
5656 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5657 goto out;
5660 status = close_file(req, fsp, NORMAL_CLOSE);
5661 if (!NT_STATUS_IS_OK(status)) {
5662 reply_nterror(req, status);
5663 } else {
5664 reply_outbuf(req, 0, 0);
5667 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5669 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5670 out:
5671 TALLOC_FREE(smb_dname);
5672 END_PROFILE(SMBrmdir);
5673 return;
5676 /*******************************************************************
5677 Resolve wildcards in a filename rename.
5678 ********************************************************************/
5680 static bool resolve_wildcards(TALLOC_CTX *ctx,
5681 const char *name1,
5682 const char *name2,
5683 char **pp_newname)
5685 char *name2_copy = NULL;
5686 char *root1 = NULL;
5687 char *root2 = NULL;
5688 char *ext1 = NULL;
5689 char *ext2 = NULL;
5690 char *p,*p2, *pname1, *pname2;
5692 name2_copy = talloc_strdup(ctx, name2);
5693 if (!name2_copy) {
5694 return False;
5697 pname1 = strrchr_m(name1,'/');
5698 pname2 = strrchr_m(name2_copy,'/');
5700 if (!pname1 || !pname2) {
5701 return False;
5704 /* Truncate the copy of name2 at the last '/' */
5705 *pname2 = '\0';
5707 /* Now go past the '/' */
5708 pname1++;
5709 pname2++;
5711 root1 = talloc_strdup(ctx, pname1);
5712 root2 = talloc_strdup(ctx, pname2);
5714 if (!root1 || !root2) {
5715 return False;
5718 p = strrchr_m(root1,'.');
5719 if (p) {
5720 *p = 0;
5721 ext1 = talloc_strdup(ctx, p+1);
5722 } else {
5723 ext1 = talloc_strdup(ctx, "");
5725 p = strrchr_m(root2,'.');
5726 if (p) {
5727 *p = 0;
5728 ext2 = talloc_strdup(ctx, p+1);
5729 } else {
5730 ext2 = talloc_strdup(ctx, "");
5733 if (!ext1 || !ext2) {
5734 return False;
5737 p = root1;
5738 p2 = root2;
5739 while (*p2) {
5740 if (*p2 == '?') {
5741 /* Hmmm. Should this be mb-aware ? */
5742 *p2 = *p;
5743 p2++;
5744 } else if (*p2 == '*') {
5745 *p2 = '\0';
5746 root2 = talloc_asprintf(ctx, "%s%s",
5747 root2,
5749 if (!root2) {
5750 return False;
5752 break;
5753 } else {
5754 p2++;
5756 if (*p) {
5757 p++;
5761 p = ext1;
5762 p2 = ext2;
5763 while (*p2) {
5764 if (*p2 == '?') {
5765 /* Hmmm. Should this be mb-aware ? */
5766 *p2 = *p;
5767 p2++;
5768 } else if (*p2 == '*') {
5769 *p2 = '\0';
5770 ext2 = talloc_asprintf(ctx, "%s%s",
5771 ext2,
5773 if (!ext2) {
5774 return False;
5776 break;
5777 } else {
5778 p2++;
5780 if (*p) {
5781 p++;
5785 if (*ext2) {
5786 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5787 name2_copy,
5788 root2,
5789 ext2);
5790 } else {
5791 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5792 name2_copy,
5793 root2);
5796 if (!*pp_newname) {
5797 return False;
5800 return True;
5803 /****************************************************************************
5804 Ensure open files have their names updated. Updated to notify other smbd's
5805 asynchronously.
5806 ****************************************************************************/
5808 static void rename_open_files(connection_struct *conn,
5809 struct share_mode_lock *lck,
5810 uint32_t orig_name_hash,
5811 const struct smb_filename *smb_fname_dst)
5813 files_struct *fsp;
5814 bool did_rename = False;
5815 NTSTATUS status;
5816 uint32_t new_name_hash;
5818 for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
5819 fsp = file_find_di_next(fsp)) {
5820 /* fsp_name is a relative path under the fsp. To change this for other
5821 sharepaths we need to manipulate relative paths. */
5822 /* TODO - create the absolute path and manipulate the newname
5823 relative to the sharepath. */
5824 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5825 continue;
5827 if (fsp->name_hash != orig_name_hash) {
5828 continue;
5830 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5831 "(file_id %s) from %s -> %s\n", fsp->fnum,
5832 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5833 smb_fname_str_dbg(smb_fname_dst)));
5835 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5836 if (NT_STATUS_IS_OK(status)) {
5837 did_rename = True;
5838 new_name_hash = fsp->name_hash;
5842 if (!did_rename) {
5843 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5844 "for %s\n", file_id_string_tos(&lck->id),
5845 smb_fname_str_dbg(smb_fname_dst)));
5848 /* Send messages to all smbd's (not ourself) that the name has changed. */
5849 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5850 orig_name_hash, new_name_hash,
5851 smb_fname_dst);
5855 /****************************************************************************
5856 We need to check if the source path is a parent directory of the destination
5857 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5858 refuse the rename with a sharing violation. Under UNIX the above call can
5859 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5860 probably need to check that the client is a Windows one before disallowing
5861 this as a UNIX client (one with UNIX extensions) can know the source is a
5862 symlink and make this decision intelligently. Found by an excellent bug
5863 report from <AndyLiebman@aol.com>.
5864 ****************************************************************************/
5866 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5867 const struct smb_filename *smb_fname_dst)
5869 const char *psrc = smb_fname_src->base_name;
5870 const char *pdst = smb_fname_dst->base_name;
5871 size_t slen;
5873 if (psrc[0] == '.' && psrc[1] == '/') {
5874 psrc += 2;
5876 if (pdst[0] == '.' && pdst[1] == '/') {
5877 pdst += 2;
5879 if ((slen = strlen(psrc)) > strlen(pdst)) {
5880 return False;
5882 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5886 * Do the notify calls from a rename
5889 static void notify_rename(connection_struct *conn, bool is_dir,
5890 const struct smb_filename *smb_fname_src,
5891 const struct smb_filename *smb_fname_dst)
5893 char *parent_dir_src = NULL;
5894 char *parent_dir_dst = NULL;
5895 uint32 mask;
5897 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5898 : FILE_NOTIFY_CHANGE_FILE_NAME;
5900 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5901 &parent_dir_src, NULL) ||
5902 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5903 &parent_dir_dst, NULL)) {
5904 goto out;
5907 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5908 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5909 smb_fname_src->base_name);
5910 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5911 smb_fname_dst->base_name);
5913 else {
5914 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5915 smb_fname_src->base_name);
5916 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5917 smb_fname_dst->base_name);
5920 /* this is a strange one. w2k3 gives an additional event for
5921 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5922 files, but not directories */
5923 if (!is_dir) {
5924 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5925 FILE_NOTIFY_CHANGE_ATTRIBUTES
5926 |FILE_NOTIFY_CHANGE_CREATION,
5927 smb_fname_dst->base_name);
5929 out:
5930 TALLOC_FREE(parent_dir_src);
5931 TALLOC_FREE(parent_dir_dst);
5934 /****************************************************************************
5935 Rename an open file - given an fsp.
5936 ****************************************************************************/
5938 NTSTATUS rename_internals_fsp(connection_struct *conn,
5939 files_struct *fsp,
5940 const struct smb_filename *smb_fname_dst_in,
5941 uint32 attrs,
5942 bool replace_if_exists)
5944 TALLOC_CTX *ctx = talloc_tos();
5945 struct smb_filename *smb_fname_dst = NULL;
5946 NTSTATUS status = NT_STATUS_OK;
5947 struct share_mode_lock *lck = NULL;
5948 bool dst_exists, old_is_stream, new_is_stream;
5950 status = check_name(conn, smb_fname_dst_in->base_name);
5951 if (!NT_STATUS_IS_OK(status)) {
5952 return status;
5955 /* Make a copy of the dst smb_fname structs */
5957 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5958 if (!NT_STATUS_IS_OK(status)) {
5959 goto out;
5963 * Check for special case with case preserving and not
5964 * case sensitive. If the old last component differs from the original
5965 * last component only by case, then we should allow
5966 * the rename (user is trying to change the case of the
5967 * filename).
5969 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5970 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5971 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5972 char *last_slash;
5973 char *fname_dst_lcomp_base_mod = NULL;
5974 struct smb_filename *smb_fname_orig_lcomp = NULL;
5977 * Get the last component of the destination name.
5979 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
5980 if (last_slash) {
5981 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
5982 } else {
5983 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
5985 if (!fname_dst_lcomp_base_mod) {
5986 status = NT_STATUS_NO_MEMORY;
5987 goto out;
5991 * Create an smb_filename struct using the original last
5992 * component of the destination.
5994 status = create_synthetic_smb_fname_split(ctx,
5995 smb_fname_dst->original_lcomp, NULL,
5996 &smb_fname_orig_lcomp);
5997 if (!NT_STATUS_IS_OK(status)) {
5998 TALLOC_FREE(fname_dst_lcomp_base_mod);
5999 goto out;
6002 /* If the base names only differ by case, use original. */
6003 if(!strcsequal(fname_dst_lcomp_base_mod,
6004 smb_fname_orig_lcomp->base_name)) {
6005 char *tmp;
6007 * Replace the modified last component with the
6008 * original.
6010 if (last_slash) {
6011 *last_slash = '\0'; /* Truncate at the '/' */
6012 tmp = talloc_asprintf(smb_fname_dst,
6013 "%s/%s",
6014 smb_fname_dst->base_name,
6015 smb_fname_orig_lcomp->base_name);
6016 } else {
6017 tmp = talloc_asprintf(smb_fname_dst,
6018 "%s",
6019 smb_fname_orig_lcomp->base_name);
6021 if (tmp == NULL) {
6022 status = NT_STATUS_NO_MEMORY;
6023 TALLOC_FREE(fname_dst_lcomp_base_mod);
6024 TALLOC_FREE(smb_fname_orig_lcomp);
6025 goto out;
6027 TALLOC_FREE(smb_fname_dst->base_name);
6028 smb_fname_dst->base_name = tmp;
6031 /* If the stream_names only differ by case, use original. */
6032 if(!strcsequal(smb_fname_dst->stream_name,
6033 smb_fname_orig_lcomp->stream_name)) {
6034 char *tmp = NULL;
6035 /* Use the original stream. */
6036 tmp = talloc_strdup(smb_fname_dst,
6037 smb_fname_orig_lcomp->stream_name);
6038 if (tmp == NULL) {
6039 status = NT_STATUS_NO_MEMORY;
6040 TALLOC_FREE(fname_dst_lcomp_base_mod);
6041 TALLOC_FREE(smb_fname_orig_lcomp);
6042 goto out;
6044 TALLOC_FREE(smb_fname_dst->stream_name);
6045 smb_fname_dst->stream_name = tmp;
6047 TALLOC_FREE(fname_dst_lcomp_base_mod);
6048 TALLOC_FREE(smb_fname_orig_lcomp);
6052 * If the src and dest names are identical - including case,
6053 * don't do the rename, just return success.
6056 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6057 strcsequal(fsp->fsp_name->stream_name,
6058 smb_fname_dst->stream_name)) {
6059 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6060 "- returning success\n",
6061 smb_fname_str_dbg(smb_fname_dst)));
6062 status = NT_STATUS_OK;
6063 goto out;
6066 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6067 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6069 /* Return the correct error code if both names aren't streams. */
6070 if (!old_is_stream && new_is_stream) {
6071 status = NT_STATUS_OBJECT_NAME_INVALID;
6072 goto out;
6075 if (old_is_stream && !new_is_stream) {
6076 status = NT_STATUS_INVALID_PARAMETER;
6077 goto out;
6080 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6082 if(!replace_if_exists && dst_exists) {
6083 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6084 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6085 smb_fname_str_dbg(smb_fname_dst)));
6086 status = NT_STATUS_OBJECT_NAME_COLLISION;
6087 goto out;
6090 if (dst_exists) {
6091 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6092 &smb_fname_dst->st);
6093 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6094 fileid);
6095 /* The file can be open when renaming a stream */
6096 if (dst_fsp && !new_is_stream) {
6097 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6098 status = NT_STATUS_ACCESS_DENIED;
6099 goto out;
6103 /* Ensure we have a valid stat struct for the source. */
6104 status = vfs_stat_fsp(fsp);
6105 if (!NT_STATUS_IS_OK(status)) {
6106 goto out;
6109 status = can_rename(conn, fsp, attrs);
6111 if (!NT_STATUS_IS_OK(status)) {
6112 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6113 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6114 smb_fname_str_dbg(smb_fname_dst)));
6115 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6116 status = NT_STATUS_ACCESS_DENIED;
6117 goto out;
6120 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6121 status = NT_STATUS_ACCESS_DENIED;
6124 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6125 NULL);
6128 * We have the file open ourselves, so not being able to get the
6129 * corresponding share mode lock is a fatal error.
6132 SMB_ASSERT(lck != NULL);
6134 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6135 uint32 create_options = fsp->fh->private_options;
6137 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6138 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6139 smb_fname_str_dbg(smb_fname_dst)));
6141 if (!lp_posix_pathnames() &&
6142 (lp_map_archive(SNUM(conn)) ||
6143 lp_store_dos_attributes(SNUM(conn)))) {
6144 /* We must set the archive bit on the newly
6145 renamed file. */
6146 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6147 uint32_t old_dosmode = dos_mode(conn,
6148 smb_fname_dst);
6149 file_set_dosmode(conn,
6150 smb_fname_dst,
6151 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6152 NULL,
6153 true);
6157 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6158 smb_fname_dst);
6160 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6163 * A rename acts as a new file create w.r.t. allowing an initial delete
6164 * on close, probably because in Windows there is a new handle to the
6165 * new file. If initial delete on close was requested but not
6166 * originally set, we need to set it here. This is probably not 100% correct,
6167 * but will work for the CIFSFS client which in non-posix mode
6168 * depends on these semantics. JRA.
6171 if (create_options & FILE_DELETE_ON_CLOSE) {
6172 status = can_set_delete_on_close(fsp, 0);
6174 if (NT_STATUS_IS_OK(status)) {
6175 /* Note that here we set the *inital* delete on close flag,
6176 * not the regular one. The magic gets handled in close. */
6177 fsp->initial_delete_on_close = True;
6180 TALLOC_FREE(lck);
6181 status = NT_STATUS_OK;
6182 goto out;
6185 TALLOC_FREE(lck);
6187 if (errno == ENOTDIR || errno == EISDIR) {
6188 status = NT_STATUS_OBJECT_NAME_COLLISION;
6189 } else {
6190 status = map_nt_error_from_unix(errno);
6193 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6194 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6195 smb_fname_str_dbg(smb_fname_dst)));
6197 out:
6198 TALLOC_FREE(smb_fname_dst);
6200 return status;
6203 /****************************************************************************
6204 The guts of the rename command, split out so it may be called by the NT SMB
6205 code.
6206 ****************************************************************************/
6208 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6209 connection_struct *conn,
6210 struct smb_request *req,
6211 struct smb_filename *smb_fname_src,
6212 struct smb_filename *smb_fname_dst,
6213 uint32 attrs,
6214 bool replace_if_exists,
6215 bool src_has_wild,
6216 bool dest_has_wild,
6217 uint32_t access_mask)
6219 char *fname_src_dir = NULL;
6220 char *fname_src_mask = NULL;
6221 int count=0;
6222 NTSTATUS status = NT_STATUS_OK;
6223 struct smb_Dir *dir_hnd = NULL;
6224 const char *dname = NULL;
6225 char *talloced = NULL;
6226 long offset = 0;
6227 int create_options = 0;
6228 bool posix_pathnames = lp_posix_pathnames();
6231 * Split the old name into directory and last component
6232 * strings. Note that unix_convert may have stripped off a
6233 * leading ./ from both name and newname if the rename is
6234 * at the root of the share. We need to make sure either both
6235 * name and newname contain a / character or neither of them do
6236 * as this is checked in resolve_wildcards().
6239 /* Split up the directory from the filename/mask. */
6240 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6241 &fname_src_dir, &fname_src_mask);
6242 if (!NT_STATUS_IS_OK(status)) {
6243 status = NT_STATUS_NO_MEMORY;
6244 goto out;
6248 * We should only check the mangled cache
6249 * here if unix_convert failed. This means
6250 * that the path in 'mask' doesn't exist
6251 * on the file system and so we need to look
6252 * for a possible mangle. This patch from
6253 * Tine Smukavec <valentin.smukavec@hermes.si>.
6256 if (!VALID_STAT(smb_fname_src->st) &&
6257 mangle_is_mangled(fname_src_mask, conn->params)) {
6258 char *new_mask = NULL;
6259 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6260 conn->params);
6261 if (new_mask) {
6262 TALLOC_FREE(fname_src_mask);
6263 fname_src_mask = new_mask;
6267 if (!src_has_wild) {
6268 files_struct *fsp;
6271 * Only one file needs to be renamed. Append the mask back
6272 * onto the directory.
6274 TALLOC_FREE(smb_fname_src->base_name);
6275 if (ISDOT(fname_src_dir)) {
6276 /* Ensure we use canonical names on open. */
6277 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6278 "%s",
6279 fname_src_mask);
6280 } else {
6281 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6282 "%s/%s",
6283 fname_src_dir,
6284 fname_src_mask);
6286 if (!smb_fname_src->base_name) {
6287 status = NT_STATUS_NO_MEMORY;
6288 goto out;
6291 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6292 "case_preserve = %d, short case preserve = %d, "
6293 "directory = %s, newname = %s, "
6294 "last_component_dest = %s\n",
6295 conn->case_sensitive, conn->case_preserve,
6296 conn->short_case_preserve,
6297 smb_fname_str_dbg(smb_fname_src),
6298 smb_fname_str_dbg(smb_fname_dst),
6299 smb_fname_dst->original_lcomp));
6301 /* The dest name still may have wildcards. */
6302 if (dest_has_wild) {
6303 char *fname_dst_mod = NULL;
6304 if (!resolve_wildcards(smb_fname_dst,
6305 smb_fname_src->base_name,
6306 smb_fname_dst->base_name,
6307 &fname_dst_mod)) {
6308 DEBUG(6, ("rename_internals: resolve_wildcards "
6309 "%s %s failed\n",
6310 smb_fname_src->base_name,
6311 smb_fname_dst->base_name));
6312 status = NT_STATUS_NO_MEMORY;
6313 goto out;
6315 TALLOC_FREE(smb_fname_dst->base_name);
6316 smb_fname_dst->base_name = fname_dst_mod;
6319 ZERO_STRUCT(smb_fname_src->st);
6320 if (posix_pathnames) {
6321 SMB_VFS_LSTAT(conn, smb_fname_src);
6322 } else {
6323 SMB_VFS_STAT(conn, smb_fname_src);
6326 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6327 create_options |= FILE_DIRECTORY_FILE;
6330 status = SMB_VFS_CREATE_FILE(
6331 conn, /* conn */
6332 req, /* req */
6333 0, /* root_dir_fid */
6334 smb_fname_src, /* fname */
6335 access_mask, /* access_mask */
6336 (FILE_SHARE_READ | /* share_access */
6337 FILE_SHARE_WRITE),
6338 FILE_OPEN, /* create_disposition*/
6339 create_options, /* create_options */
6340 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6341 0, /* oplock_request */
6342 0, /* allocation_size */
6343 0, /* private_flags */
6344 NULL, /* sd */
6345 NULL, /* ea_list */
6346 &fsp, /* result */
6347 NULL); /* pinfo */
6349 if (!NT_STATUS_IS_OK(status)) {
6350 DEBUG(3, ("Could not open rename source %s: %s\n",
6351 smb_fname_str_dbg(smb_fname_src),
6352 nt_errstr(status)));
6353 goto out;
6356 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6357 attrs, replace_if_exists);
6359 close_file(req, fsp, NORMAL_CLOSE);
6361 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6362 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6363 smb_fname_str_dbg(smb_fname_dst)));
6365 goto out;
6369 * Wildcards - process each file that matches.
6371 if (strequal(fname_src_mask, "????????.???")) {
6372 TALLOC_FREE(fname_src_mask);
6373 fname_src_mask = talloc_strdup(ctx, "*");
6374 if (!fname_src_mask) {
6375 status = NT_STATUS_NO_MEMORY;
6376 goto out;
6380 status = check_name(conn, fname_src_dir);
6381 if (!NT_STATUS_IS_OK(status)) {
6382 goto out;
6385 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6386 attrs);
6387 if (dir_hnd == NULL) {
6388 status = map_nt_error_from_unix(errno);
6389 goto out;
6392 status = NT_STATUS_NO_SUCH_FILE;
6394 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6395 * - gentest fix. JRA
6398 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6399 &talloced))) {
6400 files_struct *fsp = NULL;
6401 char *destname = NULL;
6402 bool sysdir_entry = False;
6404 /* Quick check for "." and ".." */
6405 if (ISDOT(dname) || ISDOTDOT(dname)) {
6406 if (attrs & aDIR) {
6407 sysdir_entry = True;
6408 } else {
6409 TALLOC_FREE(talloced);
6410 continue;
6414 if (!is_visible_file(conn, fname_src_dir, dname,
6415 &smb_fname_src->st, false)) {
6416 TALLOC_FREE(talloced);
6417 continue;
6420 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6421 TALLOC_FREE(talloced);
6422 continue;
6425 if (sysdir_entry) {
6426 status = NT_STATUS_OBJECT_NAME_INVALID;
6427 break;
6430 TALLOC_FREE(smb_fname_src->base_name);
6431 if (ISDOT(fname_src_dir)) {
6432 /* Ensure we use canonical names on open. */
6433 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6434 "%s",
6435 dname);
6436 } else {
6437 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6438 "%s/%s",
6439 fname_src_dir,
6440 dname);
6442 if (!smb_fname_src->base_name) {
6443 status = NT_STATUS_NO_MEMORY;
6444 goto out;
6447 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6448 smb_fname_dst->base_name,
6449 &destname)) {
6450 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6451 smb_fname_src->base_name, destname));
6452 TALLOC_FREE(talloced);
6453 continue;
6455 if (!destname) {
6456 status = NT_STATUS_NO_MEMORY;
6457 goto out;
6460 TALLOC_FREE(smb_fname_dst->base_name);
6461 smb_fname_dst->base_name = destname;
6463 ZERO_STRUCT(smb_fname_src->st);
6464 if (posix_pathnames) {
6465 SMB_VFS_LSTAT(conn, smb_fname_src);
6466 } else {
6467 SMB_VFS_STAT(conn, smb_fname_src);
6470 create_options = 0;
6472 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6473 create_options |= FILE_DIRECTORY_FILE;
6476 status = SMB_VFS_CREATE_FILE(
6477 conn, /* conn */
6478 req, /* req */
6479 0, /* root_dir_fid */
6480 smb_fname_src, /* fname */
6481 access_mask, /* access_mask */
6482 (FILE_SHARE_READ | /* share_access */
6483 FILE_SHARE_WRITE),
6484 FILE_OPEN, /* create_disposition*/
6485 create_options, /* create_options */
6486 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6487 0, /* oplock_request */
6488 0, /* allocation_size */
6489 0, /* private_flags */
6490 NULL, /* sd */
6491 NULL, /* ea_list */
6492 &fsp, /* result */
6493 NULL); /* pinfo */
6495 if (!NT_STATUS_IS_OK(status)) {
6496 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6497 "returned %s rename %s -> %s\n",
6498 nt_errstr(status),
6499 smb_fname_str_dbg(smb_fname_src),
6500 smb_fname_str_dbg(smb_fname_dst)));
6501 break;
6504 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6505 dname);
6506 if (!smb_fname_dst->original_lcomp) {
6507 status = NT_STATUS_NO_MEMORY;
6508 goto out;
6511 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6512 attrs, replace_if_exists);
6514 close_file(req, fsp, NORMAL_CLOSE);
6516 if (!NT_STATUS_IS_OK(status)) {
6517 DEBUG(3, ("rename_internals_fsp returned %s for "
6518 "rename %s -> %s\n", nt_errstr(status),
6519 smb_fname_str_dbg(smb_fname_src),
6520 smb_fname_str_dbg(smb_fname_dst)));
6521 break;
6524 count++;
6526 DEBUG(3,("rename_internals: doing rename on %s -> "
6527 "%s\n", smb_fname_str_dbg(smb_fname_src),
6528 smb_fname_str_dbg(smb_fname_src)));
6529 TALLOC_FREE(talloced);
6531 TALLOC_FREE(dir_hnd);
6533 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6534 status = map_nt_error_from_unix(errno);
6537 out:
6538 TALLOC_FREE(talloced);
6539 TALLOC_FREE(fname_src_dir);
6540 TALLOC_FREE(fname_src_mask);
6541 return status;
6544 /****************************************************************************
6545 Reply to a mv.
6546 ****************************************************************************/
6548 void reply_mv(struct smb_request *req)
6550 connection_struct *conn = req->conn;
6551 char *name = NULL;
6552 char *newname = NULL;
6553 const char *p;
6554 uint32 attrs;
6555 NTSTATUS status;
6556 bool src_has_wcard = False;
6557 bool dest_has_wcard = False;
6558 TALLOC_CTX *ctx = talloc_tos();
6559 struct smb_filename *smb_fname_src = NULL;
6560 struct smb_filename *smb_fname_dst = NULL;
6561 bool stream_rename = false;
6563 START_PROFILE(SMBmv);
6565 if (req->wct < 1) {
6566 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6567 goto out;
6570 attrs = SVAL(req->vwv+0, 0);
6572 p = (const char *)req->buf + 1;
6573 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6574 &status, &src_has_wcard);
6575 if (!NT_STATUS_IS_OK(status)) {
6576 reply_nterror(req, status);
6577 goto out;
6579 p++;
6580 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6581 &status, &dest_has_wcard);
6582 if (!NT_STATUS_IS_OK(status)) {
6583 reply_nterror(req, status);
6584 goto out;
6587 if (!lp_posix_pathnames()) {
6588 /* The newname must begin with a ':' if the
6589 name contains a ':'. */
6590 if (strchr_m(name, ':')) {
6591 if (newname[0] != ':') {
6592 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6593 goto out;
6595 stream_rename = true;
6599 status = filename_convert(ctx,
6600 conn,
6601 req->flags2 & FLAGS2_DFS_PATHNAMES,
6602 name,
6603 UCF_COND_ALLOW_WCARD_LCOMP,
6604 &src_has_wcard,
6605 &smb_fname_src);
6607 if (!NT_STATUS_IS_OK(status)) {
6608 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6609 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6610 ERRSRV, ERRbadpath);
6611 goto out;
6613 reply_nterror(req, status);
6614 goto out;
6617 status = filename_convert(ctx,
6618 conn,
6619 req->flags2 & FLAGS2_DFS_PATHNAMES,
6620 newname,
6621 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6622 &dest_has_wcard,
6623 &smb_fname_dst);
6625 if (!NT_STATUS_IS_OK(status)) {
6626 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6627 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6628 ERRSRV, ERRbadpath);
6629 goto out;
6631 reply_nterror(req, status);
6632 goto out;
6635 if (stream_rename) {
6636 /* smb_fname_dst->base_name must be the same as
6637 smb_fname_src->base_name. */
6638 TALLOC_FREE(smb_fname_dst->base_name);
6639 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6640 smb_fname_src->base_name);
6641 if (!smb_fname_dst->base_name) {
6642 reply_nterror(req, NT_STATUS_NO_MEMORY);
6643 goto out;
6647 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6648 smb_fname_str_dbg(smb_fname_dst)));
6650 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6651 attrs, False, src_has_wcard, dest_has_wcard,
6652 DELETE_ACCESS);
6653 if (!NT_STATUS_IS_OK(status)) {
6654 if (open_was_deferred(req->mid)) {
6655 /* We have re-scheduled this call. */
6656 goto out;
6658 reply_nterror(req, status);
6659 goto out;
6662 reply_outbuf(req, 0, 0);
6663 out:
6664 TALLOC_FREE(smb_fname_src);
6665 TALLOC_FREE(smb_fname_dst);
6666 END_PROFILE(SMBmv);
6667 return;
6670 /*******************************************************************
6671 Copy a file as part of a reply_copy.
6672 ******************************************************************/
6675 * TODO: check error codes on all callers
6678 NTSTATUS copy_file(TALLOC_CTX *ctx,
6679 connection_struct *conn,
6680 struct smb_filename *smb_fname_src,
6681 struct smb_filename *smb_fname_dst,
6682 int ofun,
6683 int count,
6684 bool target_is_directory)
6686 struct smb_filename *smb_fname_dst_tmp = NULL;
6687 SMB_OFF_T ret=-1;
6688 files_struct *fsp1,*fsp2;
6689 uint32 dosattrs;
6690 uint32 new_create_disposition;
6691 NTSTATUS status;
6694 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6695 if (!NT_STATUS_IS_OK(status)) {
6696 return status;
6700 * If the target is a directory, extract the last component from the
6701 * src filename and append it to the dst filename
6703 if (target_is_directory) {
6704 const char *p;
6706 /* dest/target can't be a stream if it's a directory. */
6707 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6709 p = strrchr_m(smb_fname_src->base_name,'/');
6710 if (p) {
6711 p++;
6712 } else {
6713 p = smb_fname_src->base_name;
6715 smb_fname_dst_tmp->base_name =
6716 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6718 if (!smb_fname_dst_tmp->base_name) {
6719 status = NT_STATUS_NO_MEMORY;
6720 goto out;
6724 status = vfs_file_exist(conn, smb_fname_src);
6725 if (!NT_STATUS_IS_OK(status)) {
6726 goto out;
6729 if (!target_is_directory && count) {
6730 new_create_disposition = FILE_OPEN;
6731 } else {
6732 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
6733 NULL, NULL,
6734 &new_create_disposition,
6735 NULL,
6736 NULL)) {
6737 status = NT_STATUS_INVALID_PARAMETER;
6738 goto out;
6742 /* Open the src file for reading. */
6743 status = SMB_VFS_CREATE_FILE(
6744 conn, /* conn */
6745 NULL, /* req */
6746 0, /* root_dir_fid */
6747 smb_fname_src, /* fname */
6748 FILE_GENERIC_READ, /* access_mask */
6749 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6750 FILE_OPEN, /* create_disposition*/
6751 0, /* create_options */
6752 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6753 INTERNAL_OPEN_ONLY, /* oplock_request */
6754 0, /* allocation_size */
6755 0, /* private_flags */
6756 NULL, /* sd */
6757 NULL, /* ea_list */
6758 &fsp1, /* result */
6759 NULL); /* psbuf */
6761 if (!NT_STATUS_IS_OK(status)) {
6762 goto out;
6765 dosattrs = dos_mode(conn, smb_fname_src);
6767 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6768 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6771 /* Open the dst file for writing. */
6772 status = SMB_VFS_CREATE_FILE(
6773 conn, /* conn */
6774 NULL, /* req */
6775 0, /* root_dir_fid */
6776 smb_fname_dst, /* fname */
6777 FILE_GENERIC_WRITE, /* access_mask */
6778 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6779 new_create_disposition, /* create_disposition*/
6780 0, /* create_options */
6781 dosattrs, /* file_attributes */
6782 INTERNAL_OPEN_ONLY, /* oplock_request */
6783 0, /* allocation_size */
6784 0, /* private_flags */
6785 NULL, /* sd */
6786 NULL, /* ea_list */
6787 &fsp2, /* result */
6788 NULL); /* psbuf */
6790 if (!NT_STATUS_IS_OK(status)) {
6791 close_file(NULL, fsp1, ERROR_CLOSE);
6792 goto out;
6795 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6796 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6797 if (ret == -1) {
6798 DEBUG(0, ("error - vfs lseek returned error %s\n",
6799 strerror(errno)));
6800 status = map_nt_error_from_unix(errno);
6801 close_file(NULL, fsp1, ERROR_CLOSE);
6802 close_file(NULL, fsp2, ERROR_CLOSE);
6803 goto out;
6807 /* Do the actual copy. */
6808 if (smb_fname_src->st.st_ex_size) {
6809 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6810 } else {
6811 ret = 0;
6814 close_file(NULL, fsp1, NORMAL_CLOSE);
6816 /* Ensure the modtime is set correctly on the destination file. */
6817 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6820 * As we are opening fsp1 read-only we only expect
6821 * an error on close on fsp2 if we are out of space.
6822 * Thus we don't look at the error return from the
6823 * close of fsp1.
6825 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6827 if (!NT_STATUS_IS_OK(status)) {
6828 goto out;
6831 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6832 status = NT_STATUS_DISK_FULL;
6833 goto out;
6836 status = NT_STATUS_OK;
6838 out:
6839 TALLOC_FREE(smb_fname_dst_tmp);
6840 return status;
6843 /****************************************************************************
6844 Reply to a file copy.
6845 ****************************************************************************/
6847 void reply_copy(struct smb_request *req)
6849 connection_struct *conn = req->conn;
6850 struct smb_filename *smb_fname_src = NULL;
6851 struct smb_filename *smb_fname_dst = NULL;
6852 char *fname_src = NULL;
6853 char *fname_dst = NULL;
6854 char *fname_src_mask = NULL;
6855 char *fname_src_dir = NULL;
6856 const char *p;
6857 int count=0;
6858 int error = ERRnoaccess;
6859 int tid2;
6860 int ofun;
6861 int flags;
6862 bool target_is_directory=False;
6863 bool source_has_wild = False;
6864 bool dest_has_wild = False;
6865 NTSTATUS status;
6866 TALLOC_CTX *ctx = talloc_tos();
6868 START_PROFILE(SMBcopy);
6870 if (req->wct < 3) {
6871 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6872 goto out;
6875 tid2 = SVAL(req->vwv+0, 0);
6876 ofun = SVAL(req->vwv+1, 0);
6877 flags = SVAL(req->vwv+2, 0);
6879 p = (const char *)req->buf;
6880 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6881 &status, &source_has_wild);
6882 if (!NT_STATUS_IS_OK(status)) {
6883 reply_nterror(req, status);
6884 goto out;
6886 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6887 &status, &dest_has_wild);
6888 if (!NT_STATUS_IS_OK(status)) {
6889 reply_nterror(req, status);
6890 goto out;
6893 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6895 if (tid2 != conn->cnum) {
6896 /* can't currently handle inter share copies XXXX */
6897 DEBUG(3,("Rejecting inter-share copy\n"));
6898 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6899 goto out;
6902 status = filename_convert(ctx, conn,
6903 req->flags2 & FLAGS2_DFS_PATHNAMES,
6904 fname_src,
6905 UCF_COND_ALLOW_WCARD_LCOMP,
6906 &source_has_wild,
6907 &smb_fname_src);
6908 if (!NT_STATUS_IS_OK(status)) {
6909 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6910 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6911 ERRSRV, ERRbadpath);
6912 goto out;
6914 reply_nterror(req, status);
6915 goto out;
6918 status = filename_convert(ctx, conn,
6919 req->flags2 & FLAGS2_DFS_PATHNAMES,
6920 fname_dst,
6921 UCF_COND_ALLOW_WCARD_LCOMP,
6922 &dest_has_wild,
6923 &smb_fname_dst);
6924 if (!NT_STATUS_IS_OK(status)) {
6925 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6926 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6927 ERRSRV, ERRbadpath);
6928 goto out;
6930 reply_nterror(req, status);
6931 goto out;
6934 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6936 if ((flags&1) && target_is_directory) {
6937 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6938 goto out;
6941 if ((flags&2) && !target_is_directory) {
6942 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6943 goto out;
6946 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6947 /* wants a tree copy! XXXX */
6948 DEBUG(3,("Rejecting tree copy\n"));
6949 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6950 goto out;
6953 /* Split up the directory from the filename/mask. */
6954 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6955 &fname_src_dir, &fname_src_mask);
6956 if (!NT_STATUS_IS_OK(status)) {
6957 reply_nterror(req, NT_STATUS_NO_MEMORY);
6958 goto out;
6962 * We should only check the mangled cache
6963 * here if unix_convert failed. This means
6964 * that the path in 'mask' doesn't exist
6965 * on the file system and so we need to look
6966 * for a possible mangle. This patch from
6967 * Tine Smukavec <valentin.smukavec@hermes.si>.
6969 if (!VALID_STAT(smb_fname_src->st) &&
6970 mangle_is_mangled(fname_src_mask, conn->params)) {
6971 char *new_mask = NULL;
6972 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6973 &new_mask, conn->params);
6975 /* Use demangled name if one was successfully found. */
6976 if (new_mask) {
6977 TALLOC_FREE(fname_src_mask);
6978 fname_src_mask = new_mask;
6982 if (!source_has_wild) {
6985 * Only one file needs to be copied. Append the mask back onto
6986 * the directory.
6988 TALLOC_FREE(smb_fname_src->base_name);
6989 if (ISDOT(fname_src_dir)) {
6990 /* Ensure we use canonical names on open. */
6991 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6992 "%s",
6993 fname_src_mask);
6994 } else {
6995 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6996 "%s/%s",
6997 fname_src_dir,
6998 fname_src_mask);
7000 if (!smb_fname_src->base_name) {
7001 reply_nterror(req, NT_STATUS_NO_MEMORY);
7002 goto out;
7005 if (dest_has_wild) {
7006 char *fname_dst_mod = NULL;
7007 if (!resolve_wildcards(smb_fname_dst,
7008 smb_fname_src->base_name,
7009 smb_fname_dst->base_name,
7010 &fname_dst_mod)) {
7011 reply_nterror(req, NT_STATUS_NO_MEMORY);
7012 goto out;
7014 TALLOC_FREE(smb_fname_dst->base_name);
7015 smb_fname_dst->base_name = fname_dst_mod;
7018 status = check_name(conn, smb_fname_src->base_name);
7019 if (!NT_STATUS_IS_OK(status)) {
7020 reply_nterror(req, status);
7021 goto out;
7024 status = check_name(conn, smb_fname_dst->base_name);
7025 if (!NT_STATUS_IS_OK(status)) {
7026 reply_nterror(req, status);
7027 goto out;
7030 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7031 ofun, count, target_is_directory);
7033 if(!NT_STATUS_IS_OK(status)) {
7034 reply_nterror(req, status);
7035 goto out;
7036 } else {
7037 count++;
7039 } else {
7040 struct smb_Dir *dir_hnd = NULL;
7041 const char *dname = NULL;
7042 char *talloced = NULL;
7043 long offset = 0;
7046 * There is a wildcard that requires us to actually read the
7047 * src dir and copy each file matching the mask to the dst.
7048 * Right now streams won't be copied, but this could
7049 * presumably be added with a nested loop for reach dir entry.
7051 SMB_ASSERT(!smb_fname_src->stream_name);
7052 SMB_ASSERT(!smb_fname_dst->stream_name);
7054 smb_fname_src->stream_name = NULL;
7055 smb_fname_dst->stream_name = NULL;
7057 if (strequal(fname_src_mask,"????????.???")) {
7058 TALLOC_FREE(fname_src_mask);
7059 fname_src_mask = talloc_strdup(ctx, "*");
7060 if (!fname_src_mask) {
7061 reply_nterror(req, NT_STATUS_NO_MEMORY);
7062 goto out;
7066 status = check_name(conn, fname_src_dir);
7067 if (!NT_STATUS_IS_OK(status)) {
7068 reply_nterror(req, status);
7069 goto out;
7072 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7073 if (dir_hnd == NULL) {
7074 status = map_nt_error_from_unix(errno);
7075 reply_nterror(req, status);
7076 goto out;
7079 error = ERRbadfile;
7081 /* Iterate over the src dir copying each entry to the dst. */
7082 while ((dname = ReadDirName(dir_hnd, &offset,
7083 &smb_fname_src->st, &talloced))) {
7084 char *destname = NULL;
7086 if (ISDOT(dname) || ISDOTDOT(dname)) {
7087 TALLOC_FREE(talloced);
7088 continue;
7091 if (!is_visible_file(conn, fname_src_dir, dname,
7092 &smb_fname_src->st, false)) {
7093 TALLOC_FREE(talloced);
7094 continue;
7097 if(!mask_match(dname, fname_src_mask,
7098 conn->case_sensitive)) {
7099 TALLOC_FREE(talloced);
7100 continue;
7103 error = ERRnoaccess;
7105 /* Get the src smb_fname struct setup. */
7106 TALLOC_FREE(smb_fname_src->base_name);
7107 if (ISDOT(fname_src_dir)) {
7108 /* Ensure we use canonical names on open. */
7109 smb_fname_src->base_name =
7110 talloc_asprintf(smb_fname_src, "%s",
7111 dname);
7112 } else {
7113 smb_fname_src->base_name =
7114 talloc_asprintf(smb_fname_src, "%s/%s",
7115 fname_src_dir, dname);
7118 if (!smb_fname_src->base_name) {
7119 TALLOC_FREE(dir_hnd);
7120 TALLOC_FREE(talloced);
7121 reply_nterror(req, NT_STATUS_NO_MEMORY);
7122 goto out;
7125 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7126 smb_fname_dst->base_name,
7127 &destname)) {
7128 TALLOC_FREE(talloced);
7129 continue;
7131 if (!destname) {
7132 TALLOC_FREE(dir_hnd);
7133 TALLOC_FREE(talloced);
7134 reply_nterror(req, NT_STATUS_NO_MEMORY);
7135 goto out;
7138 TALLOC_FREE(smb_fname_dst->base_name);
7139 smb_fname_dst->base_name = destname;
7141 status = check_name(conn, smb_fname_src->base_name);
7142 if (!NT_STATUS_IS_OK(status)) {
7143 TALLOC_FREE(dir_hnd);
7144 TALLOC_FREE(talloced);
7145 reply_nterror(req, status);
7146 goto out;
7149 status = check_name(conn, smb_fname_dst->base_name);
7150 if (!NT_STATUS_IS_OK(status)) {
7151 TALLOC_FREE(dir_hnd);
7152 TALLOC_FREE(talloced);
7153 reply_nterror(req, status);
7154 goto out;
7157 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7158 smb_fname_src->base_name,
7159 smb_fname_dst->base_name));
7161 status = copy_file(ctx, conn, smb_fname_src,
7162 smb_fname_dst, ofun, count,
7163 target_is_directory);
7164 if (NT_STATUS_IS_OK(status)) {
7165 count++;
7168 TALLOC_FREE(talloced);
7170 TALLOC_FREE(dir_hnd);
7173 if (count == 0) {
7174 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7175 goto out;
7178 reply_outbuf(req, 1, 0);
7179 SSVAL(req->outbuf,smb_vwv0,count);
7180 out:
7181 TALLOC_FREE(smb_fname_src);
7182 TALLOC_FREE(smb_fname_dst);
7183 TALLOC_FREE(fname_src);
7184 TALLOC_FREE(fname_dst);
7185 TALLOC_FREE(fname_src_mask);
7186 TALLOC_FREE(fname_src_dir);
7188 END_PROFILE(SMBcopy);
7189 return;
7192 #undef DBGC_CLASS
7193 #define DBGC_CLASS DBGC_LOCKING
7195 /****************************************************************************
7196 Get a lock pid, dealing with large count requests.
7197 ****************************************************************************/
7199 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7200 bool large_file_format)
7202 if(!large_file_format)
7203 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7204 else
7205 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7208 /****************************************************************************
7209 Get a lock count, dealing with large count requests.
7210 ****************************************************************************/
7212 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7213 bool large_file_format)
7215 uint64_t count = 0;
7217 if(!large_file_format) {
7218 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7219 } else {
7221 #if defined(HAVE_LONGLONG)
7222 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7223 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7224 #else /* HAVE_LONGLONG */
7227 * NT4.x seems to be broken in that it sends large file (64 bit)
7228 * lockingX calls even if the CAP_LARGE_FILES was *not*
7229 * negotiated. For boxes without large unsigned ints truncate the
7230 * lock count by dropping the top 32 bits.
7233 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7234 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7235 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7236 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7237 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7240 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7241 #endif /* HAVE_LONGLONG */
7244 return count;
7247 #if !defined(HAVE_LONGLONG)
7248 /****************************************************************************
7249 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7250 ****************************************************************************/
7252 static uint32 map_lock_offset(uint32 high, uint32 low)
7254 unsigned int i;
7255 uint32 mask = 0;
7256 uint32 highcopy = high;
7259 * Try and find out how many significant bits there are in high.
7262 for(i = 0; highcopy; i++)
7263 highcopy >>= 1;
7266 * We use 31 bits not 32 here as POSIX
7267 * lock offsets may not be negative.
7270 mask = (~0) << (31 - i);
7272 if(low & mask)
7273 return 0; /* Fail. */
7275 high <<= (31 - i);
7277 return (high|low);
7279 #endif /* !defined(HAVE_LONGLONG) */
7281 /****************************************************************************
7282 Get a lock offset, dealing with large offset requests.
7283 ****************************************************************************/
7285 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7286 bool large_file_format, bool *err)
7288 uint64_t offset = 0;
7290 *err = False;
7292 if(!large_file_format) {
7293 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7294 } else {
7296 #if defined(HAVE_LONGLONG)
7297 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7298 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7299 #else /* HAVE_LONGLONG */
7302 * NT4.x seems to be broken in that it sends large file (64 bit)
7303 * lockingX calls even if the CAP_LARGE_FILES was *not*
7304 * negotiated. For boxes without large unsigned ints mangle the
7305 * lock offset by mapping the top 32 bits onto the lower 32.
7308 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7309 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7310 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7311 uint32 new_low = 0;
7313 if((new_low = map_lock_offset(high, low)) == 0) {
7314 *err = True;
7315 return (uint64_t)-1;
7318 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7319 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7320 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7321 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7324 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7325 #endif /* HAVE_LONGLONG */
7328 return offset;
7331 NTSTATUS smbd_do_locking(struct smb_request *req,
7332 files_struct *fsp,
7333 uint8_t type,
7334 int32_t timeout,
7335 uint16_t num_ulocks,
7336 struct smbd_lock_element *ulocks,
7337 uint16_t num_locks,
7338 struct smbd_lock_element *locks,
7339 bool *async)
7341 connection_struct *conn = req->conn;
7342 int i;
7343 NTSTATUS status = NT_STATUS_OK;
7345 *async = false;
7347 /* Data now points at the beginning of the list
7348 of smb_unlkrng structs */
7349 for(i = 0; i < (int)num_ulocks; i++) {
7350 struct smbd_lock_element *e = &ulocks[i];
7352 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7353 "pid %u, file %s\n",
7354 (double)e->offset,
7355 (double)e->count,
7356 (unsigned int)e->smblctx,
7357 fsp_str_dbg(fsp)));
7359 if (e->brltype != UNLOCK_LOCK) {
7360 /* this can only happen with SMB2 */
7361 return NT_STATUS_INVALID_PARAMETER;
7364 status = do_unlock(req->sconn->msg_ctx,
7365 fsp,
7366 e->smblctx,
7367 e->count,
7368 e->offset,
7369 WINDOWS_LOCK);
7371 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7372 nt_errstr(status)));
7374 if (!NT_STATUS_IS_OK(status)) {
7375 return status;
7379 /* Setup the timeout in seconds. */
7381 if (!lp_blocking_locks(SNUM(conn))) {
7382 timeout = 0;
7385 /* Data now points at the beginning of the list
7386 of smb_lkrng structs */
7388 for(i = 0; i < (int)num_locks; i++) {
7389 struct smbd_lock_element *e = &locks[i];
7391 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7392 "%llu, file %s timeout = %d\n",
7393 (double)e->offset,
7394 (double)e->count,
7395 (unsigned long long)e->smblctx,
7396 fsp_str_dbg(fsp),
7397 (int)timeout));
7399 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7400 struct blocking_lock_record *blr = NULL;
7402 if (num_locks > 1) {
7404 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7405 * if the lock vector contains one entry. When given mutliple cancel
7406 * requests in a single PDU we expect the server to return an
7407 * error. Windows servers seem to accept the request but only
7408 * cancel the first lock.
7409 * JRA - Do what Windows does (tm) :-).
7412 #if 0
7413 /* MS-CIFS (2.2.4.32.1) behavior. */
7414 return NT_STATUS_DOS(ERRDOS,
7415 ERRcancelviolation);
7416 #else
7417 /* Windows behavior. */
7418 if (i != 0) {
7419 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7420 "cancel request\n"));
7421 continue;
7423 #endif
7426 if (lp_blocking_locks(SNUM(conn))) {
7428 /* Schedule a message to ourselves to
7429 remove the blocking lock record and
7430 return the right error. */
7432 blr = blocking_lock_cancel_smb1(fsp,
7433 e->smblctx,
7434 e->offset,
7435 e->count,
7436 WINDOWS_LOCK,
7437 type,
7438 NT_STATUS_FILE_LOCK_CONFLICT);
7439 if (blr == NULL) {
7440 return NT_STATUS_DOS(
7441 ERRDOS,
7442 ERRcancelviolation);
7445 /* Remove a matching pending lock. */
7446 status = do_lock_cancel(fsp,
7447 e->smblctx,
7448 e->count,
7449 e->offset,
7450 WINDOWS_LOCK,
7451 blr);
7452 } else {
7453 bool blocking_lock = timeout ? true : false;
7454 bool defer_lock = false;
7455 struct byte_range_lock *br_lck;
7456 uint64_t block_smblctx;
7458 br_lck = do_lock(req->sconn->msg_ctx,
7459 fsp,
7460 e->smblctx,
7461 e->count,
7462 e->offset,
7463 e->brltype,
7464 WINDOWS_LOCK,
7465 blocking_lock,
7466 &status,
7467 &block_smblctx,
7468 NULL);
7470 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7471 /* Windows internal resolution for blocking locks seems
7472 to be about 200ms... Don't wait for less than that. JRA. */
7473 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7474 timeout = lp_lock_spin_time();
7476 defer_lock = true;
7479 /* If a lock sent with timeout of zero would fail, and
7480 * this lock has been requested multiple times,
7481 * according to brl_lock_failed() we convert this
7482 * request to a blocking lock with a timeout of between
7483 * 150 - 300 milliseconds.
7485 * If lp_lock_spin_time() has been set to 0, we skip
7486 * this blocking retry and fail immediately.
7488 * Replacement for do_lock_spin(). JRA. */
7490 if (!req->sconn->using_smb2 &&
7491 br_lck && lp_blocking_locks(SNUM(conn)) &&
7492 lp_lock_spin_time() && !blocking_lock &&
7493 NT_STATUS_EQUAL((status),
7494 NT_STATUS_FILE_LOCK_CONFLICT))
7496 defer_lock = true;
7497 timeout = lp_lock_spin_time();
7500 if (br_lck && defer_lock) {
7502 * A blocking lock was requested. Package up
7503 * this smb into a queued request and push it
7504 * onto the blocking lock queue.
7506 if(push_blocking_lock_request(br_lck,
7507 req,
7508 fsp,
7509 timeout,
7511 e->smblctx,
7512 e->brltype,
7513 WINDOWS_LOCK,
7514 e->offset,
7515 e->count,
7516 block_smblctx)) {
7517 TALLOC_FREE(br_lck);
7518 *async = true;
7519 return NT_STATUS_OK;
7523 TALLOC_FREE(br_lck);
7526 if (!NT_STATUS_IS_OK(status)) {
7527 break;
7531 /* If any of the above locks failed, then we must unlock
7532 all of the previous locks (X/Open spec). */
7534 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7536 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7537 i = -1; /* we want to skip the for loop */
7541 * Ensure we don't do a remove on the lock that just failed,
7542 * as under POSIX rules, if we have a lock already there, we
7543 * will delete it (and we shouldn't) .....
7545 for(i--; i >= 0; i--) {
7546 struct smbd_lock_element *e = &locks[i];
7548 do_unlock(req->sconn->msg_ctx,
7549 fsp,
7550 e->smblctx,
7551 e->count,
7552 e->offset,
7553 WINDOWS_LOCK);
7555 return status;
7558 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7559 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7561 return NT_STATUS_OK;
7564 /****************************************************************************
7565 Reply to a lockingX request.
7566 ****************************************************************************/
7568 void reply_lockingX(struct smb_request *req)
7570 connection_struct *conn = req->conn;
7571 files_struct *fsp;
7572 unsigned char locktype;
7573 unsigned char oplocklevel;
7574 uint16 num_ulocks;
7575 uint16 num_locks;
7576 int32 lock_timeout;
7577 int i;
7578 const uint8_t *data;
7579 bool large_file_format;
7580 bool err;
7581 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7582 struct smbd_lock_element *ulocks;
7583 struct smbd_lock_element *locks;
7584 bool async = false;
7586 START_PROFILE(SMBlockingX);
7588 if (req->wct < 8) {
7589 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7590 END_PROFILE(SMBlockingX);
7591 return;
7594 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7595 locktype = CVAL(req->vwv+3, 0);
7596 oplocklevel = CVAL(req->vwv+3, 1);
7597 num_ulocks = SVAL(req->vwv+6, 0);
7598 num_locks = SVAL(req->vwv+7, 0);
7599 lock_timeout = IVAL(req->vwv+4, 0);
7600 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7602 if (!check_fsp(conn, req, fsp)) {
7603 END_PROFILE(SMBlockingX);
7604 return;
7607 data = req->buf;
7609 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7610 /* we don't support these - and CANCEL_LOCK makes w2k
7611 and XP reboot so I don't really want to be
7612 compatible! (tridge) */
7613 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7614 END_PROFILE(SMBlockingX);
7615 return;
7618 /* Check if this is an oplock break on a file
7619 we have granted an oplock on.
7621 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7622 /* Client can insist on breaking to none. */
7623 bool break_to_none = (oplocklevel == 0);
7624 bool result;
7626 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7627 "for fnum = %d\n", (unsigned int)oplocklevel,
7628 fsp->fnum ));
7631 * Make sure we have granted an exclusive or batch oplock on
7632 * this file.
7635 if (fsp->oplock_type == 0) {
7637 /* The Samba4 nbench simulator doesn't understand
7638 the difference between break to level2 and break
7639 to none from level2 - it sends oplock break
7640 replies in both cases. Don't keep logging an error
7641 message here - just ignore it. JRA. */
7643 DEBUG(5,("reply_lockingX: Error : oplock break from "
7644 "client for fnum = %d (oplock=%d) and no "
7645 "oplock granted on this file (%s).\n",
7646 fsp->fnum, fsp->oplock_type,
7647 fsp_str_dbg(fsp)));
7649 /* if this is a pure oplock break request then don't
7650 * send a reply */
7651 if (num_locks == 0 && num_ulocks == 0) {
7652 END_PROFILE(SMBlockingX);
7653 return;
7654 } else {
7655 END_PROFILE(SMBlockingX);
7656 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7657 return;
7661 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7662 (break_to_none)) {
7663 result = remove_oplock(fsp);
7664 } else {
7665 result = downgrade_oplock(fsp);
7668 if (!result) {
7669 DEBUG(0, ("reply_lockingX: error in removing "
7670 "oplock on file %s\n", fsp_str_dbg(fsp)));
7671 /* Hmmm. Is this panic justified? */
7672 smb_panic("internal tdb error");
7675 reply_to_oplock_break_requests(fsp);
7677 /* if this is a pure oplock break request then don't send a
7678 * reply */
7679 if (num_locks == 0 && num_ulocks == 0) {
7680 /* Sanity check - ensure a pure oplock break is not a
7681 chained request. */
7682 if(CVAL(req->vwv+0, 0) != 0xff)
7683 DEBUG(0,("reply_lockingX: Error : pure oplock "
7684 "break is a chained %d request !\n",
7685 (unsigned int)CVAL(req->vwv+0, 0)));
7686 END_PROFILE(SMBlockingX);
7687 return;
7691 if (req->buflen <
7692 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7693 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7694 END_PROFILE(SMBlockingX);
7695 return;
7698 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7699 if (ulocks == NULL) {
7700 reply_nterror(req, NT_STATUS_NO_MEMORY);
7701 END_PROFILE(SMBlockingX);
7702 return;
7705 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7706 if (locks == NULL) {
7707 reply_nterror(req, NT_STATUS_NO_MEMORY);
7708 END_PROFILE(SMBlockingX);
7709 return;
7712 /* Data now points at the beginning of the list
7713 of smb_unlkrng structs */
7714 for(i = 0; i < (int)num_ulocks; i++) {
7715 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7716 ulocks[i].count = get_lock_count(data, i, large_file_format);
7717 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7718 ulocks[i].brltype = UNLOCK_LOCK;
7721 * There is no error code marked "stupid client bug".... :-).
7723 if(err) {
7724 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7725 END_PROFILE(SMBlockingX);
7726 return;
7730 /* Now do any requested locks */
7731 data += ((large_file_format ? 20 : 10)*num_ulocks);
7733 /* Data now points at the beginning of the list
7734 of smb_lkrng structs */
7736 for(i = 0; i < (int)num_locks; i++) {
7737 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7738 locks[i].count = get_lock_count(data, i, large_file_format);
7739 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7741 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7742 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7743 locks[i].brltype = PENDING_READ_LOCK;
7744 } else {
7745 locks[i].brltype = READ_LOCK;
7747 } else {
7748 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7749 locks[i].brltype = PENDING_WRITE_LOCK;
7750 } else {
7751 locks[i].brltype = WRITE_LOCK;
7756 * There is no error code marked "stupid client bug".... :-).
7758 if(err) {
7759 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7760 END_PROFILE(SMBlockingX);
7761 return;
7765 status = smbd_do_locking(req, fsp,
7766 locktype, lock_timeout,
7767 num_ulocks, ulocks,
7768 num_locks, locks,
7769 &async);
7770 if (!NT_STATUS_IS_OK(status)) {
7771 END_PROFILE(SMBlockingX);
7772 reply_nterror(req, status);
7773 return;
7775 if (async) {
7776 END_PROFILE(SMBlockingX);
7777 return;
7780 reply_outbuf(req, 2, 0);
7782 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7783 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7785 END_PROFILE(SMBlockingX);
7786 chain_reply(req);
7789 #undef DBGC_CLASS
7790 #define DBGC_CLASS DBGC_ALL
7792 /****************************************************************************
7793 Reply to a SMBreadbmpx (read block multiplex) request.
7794 Always reply with an error, if someone has a platform really needs this,
7795 please contact vl@samba.org
7796 ****************************************************************************/
7798 void reply_readbmpx(struct smb_request *req)
7800 START_PROFILE(SMBreadBmpx);
7801 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7802 END_PROFILE(SMBreadBmpx);
7803 return;
7806 /****************************************************************************
7807 Reply to a SMBreadbs (read block multiplex secondary) request.
7808 Always reply with an error, if someone has a platform really needs this,
7809 please contact vl@samba.org
7810 ****************************************************************************/
7812 void reply_readbs(struct smb_request *req)
7814 START_PROFILE(SMBreadBs);
7815 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7816 END_PROFILE(SMBreadBs);
7817 return;
7820 /****************************************************************************
7821 Reply to a SMBsetattrE.
7822 ****************************************************************************/
7824 void reply_setattrE(struct smb_request *req)
7826 connection_struct *conn = req->conn;
7827 struct smb_file_time ft;
7828 files_struct *fsp;
7829 NTSTATUS status;
7831 START_PROFILE(SMBsetattrE);
7832 ZERO_STRUCT(ft);
7834 if (req->wct < 7) {
7835 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7836 goto out;
7839 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7841 if(!fsp || (fsp->conn != conn)) {
7842 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7843 goto out;
7847 * Convert the DOS times into unix times.
7850 ft.atime = convert_time_t_to_timespec(
7851 srv_make_unix_date2(req->vwv+3));
7852 ft.mtime = convert_time_t_to_timespec(
7853 srv_make_unix_date2(req->vwv+5));
7854 ft.create_time = convert_time_t_to_timespec(
7855 srv_make_unix_date2(req->vwv+1));
7857 reply_outbuf(req, 0, 0);
7860 * Patch from Ray Frush <frush@engr.colostate.edu>
7861 * Sometimes times are sent as zero - ignore them.
7864 /* Ensure we have a valid stat struct for the source. */
7865 status = vfs_stat_fsp(fsp);
7866 if (!NT_STATUS_IS_OK(status)) {
7867 reply_nterror(req, status);
7868 goto out;
7871 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7872 if (!NT_STATUS_IS_OK(status)) {
7873 reply_nterror(req, status);
7874 goto out;
7877 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7878 " createtime=%u\n",
7879 fsp->fnum,
7880 (unsigned int)ft.atime.tv_sec,
7881 (unsigned int)ft.mtime.tv_sec,
7882 (unsigned int)ft.create_time.tv_sec
7884 out:
7885 END_PROFILE(SMBsetattrE);
7886 return;
7890 /* Back from the dead for OS/2..... JRA. */
7892 /****************************************************************************
7893 Reply to a SMBwritebmpx (write block multiplex primary) request.
7894 Always reply with an error, if someone has a platform really needs this,
7895 please contact vl@samba.org
7896 ****************************************************************************/
7898 void reply_writebmpx(struct smb_request *req)
7900 START_PROFILE(SMBwriteBmpx);
7901 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7902 END_PROFILE(SMBwriteBmpx);
7903 return;
7906 /****************************************************************************
7907 Reply to a SMBwritebs (write block multiplex secondary) request.
7908 Always reply with an error, if someone has a platform really needs this,
7909 please contact vl@samba.org
7910 ****************************************************************************/
7912 void reply_writebs(struct smb_request *req)
7914 START_PROFILE(SMBwriteBs);
7915 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7916 END_PROFILE(SMBwriteBs);
7917 return;
7920 /****************************************************************************
7921 Reply to a SMBgetattrE.
7922 ****************************************************************************/
7924 void reply_getattrE(struct smb_request *req)
7926 connection_struct *conn = req->conn;
7927 int mode;
7928 files_struct *fsp;
7929 struct timespec create_ts;
7931 START_PROFILE(SMBgetattrE);
7933 if (req->wct < 1) {
7934 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7935 END_PROFILE(SMBgetattrE);
7936 return;
7939 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7941 if(!fsp || (fsp->conn != conn)) {
7942 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7943 END_PROFILE(SMBgetattrE);
7944 return;
7947 /* Do an fstat on this file */
7948 if(fsp_stat(fsp)) {
7949 reply_nterror(req, map_nt_error_from_unix(errno));
7950 END_PROFILE(SMBgetattrE);
7951 return;
7954 mode = dos_mode(conn, fsp->fsp_name);
7957 * Convert the times into dos times. Set create
7958 * date to be last modify date as UNIX doesn't save
7959 * this.
7962 reply_outbuf(req, 11, 0);
7964 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7965 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7966 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7967 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
7968 /* Should we check pending modtime here ? JRA */
7969 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7970 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
7972 if (mode & aDIR) {
7973 SIVAL(req->outbuf, smb_vwv6, 0);
7974 SIVAL(req->outbuf, smb_vwv8, 0);
7975 } else {
7976 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
7977 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
7978 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7980 SSVAL(req->outbuf,smb_vwv10, mode);
7982 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7984 END_PROFILE(SMBgetattrE);
7985 return;