s3: Lift the smbd_messaging_context from nt_printer_publish_ads
[Samba/wip.git] / source3 / smbd / reply.c
blobba4c90d55299dce791712866a87c508706659f96
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 "printing.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_spoolss.h"
31 #include "rpc_client/cli_spoolss.h"
32 #include "rpc_client/init_spoolss.h"
34 /****************************************************************************
35 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
36 path or anything including wildcards.
37 We're assuming here that '/' is not the second byte in any multibyte char
38 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
39 set.
40 ****************************************************************************/
42 /* Custom version for processing POSIX paths. */
43 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
45 static NTSTATUS check_path_syntax_internal(char *path,
46 bool posix_path,
47 bool *p_last_component_contains_wcard)
49 char *d = path;
50 const char *s = path;
51 NTSTATUS ret = NT_STATUS_OK;
52 bool start_of_name_component = True;
53 bool stream_started = false;
55 *p_last_component_contains_wcard = False;
57 while (*s) {
58 if (stream_started) {
59 switch (*s) {
60 case '/':
61 case '\\':
62 return NT_STATUS_OBJECT_NAME_INVALID;
63 case ':':
64 if (s[1] == '\0') {
65 return NT_STATUS_OBJECT_NAME_INVALID;
67 if (strchr_m(&s[1], ':')) {
68 return NT_STATUS_OBJECT_NAME_INVALID;
70 break;
74 if ((*s == ':') && !posix_path && !stream_started) {
75 if (*p_last_component_contains_wcard) {
76 return NT_STATUS_OBJECT_NAME_INVALID;
78 /* Stream names allow more characters than file names.
79 We're overloading posix_path here to allow a wider
80 range of characters. If stream_started is true this
81 is still a Windows path even if posix_path is true.
82 JRA.
84 stream_started = true;
85 start_of_name_component = false;
86 posix_path = true;
88 if (s[1] == '\0') {
89 return NT_STATUS_OBJECT_NAME_INVALID;
93 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
95 * Safe to assume is not the second part of a mb char
96 * as this is handled below.
98 /* Eat multiple '/' or '\\' */
99 while (IS_PATH_SEP(*s,posix_path)) {
100 s++;
102 if ((d != path) && (*s != '\0')) {
103 /* We only care about non-leading or trailing '/' or '\\' */
104 *d++ = '/';
107 start_of_name_component = True;
108 /* New component. */
109 *p_last_component_contains_wcard = False;
110 continue;
113 if (start_of_name_component) {
114 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
115 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
118 * No mb char starts with '.' so we're safe checking the directory separator here.
121 /* If we just added a '/' - delete it */
122 if ((d > path) && (*(d-1) == '/')) {
123 *(d-1) = '\0';
124 d--;
127 /* Are we at the start ? Can't go back further if so. */
128 if (d <= path) {
129 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
130 break;
132 /* Go back one level... */
133 /* We know this is safe as '/' cannot be part of a mb sequence. */
134 /* NOTE - if this assumption is invalid we are not in good shape... */
135 /* Decrement d first as d points to the *next* char to write into. */
136 for (d--; d > path; d--) {
137 if (*d == '/')
138 break;
140 s += 2; /* Else go past the .. */
141 /* We're still at the start of a name component, just the previous one. */
142 continue;
144 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
145 if (posix_path) {
146 /* Eat the '.' */
147 s++;
148 continue;
154 if (!(*s & 0x80)) {
155 if (!posix_path) {
156 if (*s <= 0x1f || *s == '|') {
157 return NT_STATUS_OBJECT_NAME_INVALID;
159 switch (*s) {
160 case '*':
161 case '?':
162 case '<':
163 case '>':
164 case '"':
165 *p_last_component_contains_wcard = True;
166 break;
167 default:
168 break;
171 *d++ = *s++;
172 } else {
173 size_t siz;
174 /* Get the size of the next MB character. */
175 next_codepoint(s,&siz);
176 switch(siz) {
177 case 5:
178 *d++ = *s++;
179 /*fall through*/
180 case 4:
181 *d++ = *s++;
182 /*fall through*/
183 case 3:
184 *d++ = *s++;
185 /*fall through*/
186 case 2:
187 *d++ = *s++;
188 /*fall through*/
189 case 1:
190 *d++ = *s++;
191 break;
192 default:
193 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
194 *d = '\0';
195 return NT_STATUS_INVALID_PARAMETER;
198 start_of_name_component = False;
201 *d = '\0';
203 return ret;
206 /****************************************************************************
207 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
208 No wildcards allowed.
209 ****************************************************************************/
211 NTSTATUS check_path_syntax(char *path)
213 bool ignore;
214 return check_path_syntax_internal(path, False, &ignore);
217 /****************************************************************************
218 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
219 Wildcards allowed - p_contains_wcard returns true if the last component contained
220 a wildcard.
221 ****************************************************************************/
223 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
225 return check_path_syntax_internal(path, False, p_contains_wcard);
228 /****************************************************************************
229 Check the path for a POSIX client.
230 We're assuming here that '/' is not the second byte in any multibyte char
231 set (a safe assumption).
232 ****************************************************************************/
234 NTSTATUS check_path_syntax_posix(char *path)
236 bool ignore;
237 return check_path_syntax_internal(path, True, &ignore);
240 /****************************************************************************
241 Pull a string and check the path allowing a wilcard - provide for error return.
242 ****************************************************************************/
244 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
245 const char *base_ptr,
246 uint16 smb_flags2,
247 char **pp_dest,
248 const char *src,
249 size_t src_len,
250 int flags,
251 NTSTATUS *err,
252 bool *contains_wcard)
254 size_t ret;
256 *pp_dest = NULL;
258 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
259 src_len, flags);
261 if (!*pp_dest) {
262 *err = NT_STATUS_INVALID_PARAMETER;
263 return ret;
266 *contains_wcard = False;
268 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
270 * For a DFS path the function parse_dfs_path()
271 * will do the path processing, just make a copy.
273 *err = NT_STATUS_OK;
274 return ret;
277 if (lp_posix_pathnames()) {
278 *err = check_path_syntax_posix(*pp_dest);
279 } else {
280 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
283 return ret;
286 /****************************************************************************
287 Pull a string and check the path - provide for error return.
288 ****************************************************************************/
290 size_t srvstr_get_path(TALLOC_CTX *ctx,
291 const char *base_ptr,
292 uint16 smb_flags2,
293 char **pp_dest,
294 const char *src,
295 size_t src_len,
296 int flags,
297 NTSTATUS *err)
299 bool ignore;
300 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
301 src_len, flags, err, &ignore);
304 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
305 char **pp_dest, const char *src, int flags,
306 NTSTATUS *err, bool *contains_wcard)
308 return srvstr_get_path_wcard(mem_ctx, (char *)req->inbuf, req->flags2,
309 pp_dest, src, smbreq_bufrem(req, src),
310 flags, err, contains_wcard);
313 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
314 char **pp_dest, const char *src, int flags,
315 NTSTATUS *err)
317 bool ignore;
318 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
319 flags, err, &ignore);
322 /****************************************************************************
323 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
324 ****************************************************************************/
326 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
327 files_struct *fsp)
329 if ((fsp == NULL) || (conn == NULL)) {
330 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
331 return False;
333 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
334 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
335 return False;
337 return True;
340 /****************************************************************************
341 Check if we have a correct fsp pointing to a file.
342 ****************************************************************************/
344 bool check_fsp(connection_struct *conn, struct smb_request *req,
345 files_struct *fsp)
347 if (!check_fsp_open(conn, req, fsp)) {
348 return False;
350 if (fsp->is_directory) {
351 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
352 return False;
354 if (fsp->fh->fd == -1) {
355 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
356 return False;
358 fsp->num_smb_operations++;
359 return True;
362 /****************************************************************************
363 Check if we have a correct fsp pointing to a quota fake file. Replacement for
364 the CHECK_NTQUOTA_HANDLE_OK macro.
365 ****************************************************************************/
367 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
368 files_struct *fsp)
370 if (!check_fsp_open(conn, req, fsp)) {
371 return false;
374 if (fsp->is_directory) {
375 return false;
378 if (fsp->fake_file_handle == NULL) {
379 return false;
382 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
383 return false;
386 if (fsp->fake_file_handle->private_data == NULL) {
387 return false;
390 return true;
393 static bool netbios_session_retarget(const char *name, int name_type)
395 char *trim_name;
396 char *trim_name_type;
397 const char *retarget_parm;
398 char *retarget;
399 char *p;
400 int retarget_type = 0x20;
401 int retarget_port = 139;
402 struct sockaddr_storage retarget_addr;
403 struct sockaddr_in *in_addr;
404 bool ret = false;
405 uint8_t outbuf[10];
407 if (get_socket_port(smbd_server_fd()) != 139) {
408 return false;
411 trim_name = talloc_strdup(talloc_tos(), name);
412 if (trim_name == NULL) {
413 goto fail;
415 trim_char(trim_name, ' ', ' ');
417 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
418 name_type);
419 if (trim_name_type == NULL) {
420 goto fail;
423 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
424 trim_name_type, NULL);
425 if (retarget_parm == NULL) {
426 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
427 trim_name, NULL);
429 if (retarget_parm == NULL) {
430 goto fail;
433 retarget = talloc_strdup(trim_name, retarget_parm);
434 if (retarget == NULL) {
435 goto fail;
438 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
440 p = strchr(retarget, ':');
441 if (p != NULL) {
442 *p++ = '\0';
443 retarget_port = atoi(p);
446 p = strchr_m(retarget, '#');
447 if (p != NULL) {
448 *p++ = '\0';
449 sscanf(p, "%x", &retarget_type);
452 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
453 if (!ret) {
454 DEBUG(10, ("could not resolve %s\n", retarget));
455 goto fail;
458 if (retarget_addr.ss_family != AF_INET) {
459 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
460 goto fail;
463 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
465 _smb_setlen(outbuf, 6);
466 SCVAL(outbuf, 0, 0x84);
467 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
468 *(uint16_t *)(outbuf+8) = htons(retarget_port);
470 if (!srv_send_smb(smbd_server_fd(), (char *)outbuf, false, 0, false,
471 NULL)) {
472 exit_server_cleanly("netbios_session_regarget: srv_send_smb "
473 "failed.");
476 ret = true;
477 fail:
478 TALLOC_FREE(trim_name);
479 return ret;
482 /****************************************************************************
483 Reply to a (netbios-level) special message.
484 ****************************************************************************/
486 void reply_special(struct smbd_server_connection *sconn, char *inbuf)
488 int msg_type = CVAL(inbuf,0);
489 int msg_flags = CVAL(inbuf,1);
490 fstring name1,name2;
491 char name_type1, name_type2;
494 * We only really use 4 bytes of the outbuf, but for the smb_setlen
495 * calculation & friends (srv_send_smb uses that) we need the full smb
496 * header.
498 char outbuf[smb_size];
500 *name1 = *name2 = 0;
502 memset(outbuf, '\0', sizeof(outbuf));
504 smb_setlen(outbuf,0);
506 switch (msg_type) {
507 case 0x81: /* session request */
509 if (sconn->nbt.got_session) {
510 exit_server_cleanly("multiple session request not permitted");
513 SCVAL(outbuf,0,0x82);
514 SCVAL(outbuf,3,0);
515 if (name_len(inbuf+4) > 50 ||
516 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
517 DEBUG(0,("Invalid name length in session request\n"));
518 return;
520 name_type1 = name_extract(inbuf,4,name1);
521 name_type2 = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
522 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
523 name1, name_type1, name2, name_type2));
525 if (netbios_session_retarget(name1, name_type1)) {
526 exit_server_cleanly("retargeted client");
529 set_local_machine_name(name1, True);
530 set_remote_machine_name(name2, True);
532 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
533 get_local_machine_name(), get_remote_machine_name(),
534 name_type2));
536 if (name_type2 == 'R') {
537 /* We are being asked for a pathworks session ---
538 no thanks! */
539 SCVAL(outbuf, 0,0x83);
540 break;
543 /* only add the client's machine name to the list
544 of possibly valid usernames if we are operating
545 in share mode security */
546 if (lp_security() == SEC_SHARE) {
547 add_session_user(sconn, get_remote_machine_name());
550 reload_services(True);
551 reopen_logs();
553 sconn->nbt.got_session = true;
554 break;
556 case 0x89: /* session keepalive request
557 (some old clients produce this?) */
558 SCVAL(outbuf,0,SMBkeepalive);
559 SCVAL(outbuf,3,0);
560 break;
562 case 0x82: /* positive session response */
563 case 0x83: /* negative session response */
564 case 0x84: /* retarget session response */
565 DEBUG(0,("Unexpected session response\n"));
566 break;
568 case SMBkeepalive: /* session keepalive */
569 default:
570 return;
573 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
574 msg_type, msg_flags));
576 srv_send_smb(smbd_server_fd(), outbuf, false, 0, false, NULL);
577 return;
580 /****************************************************************************
581 Reply to a tcon.
582 conn POINTER CAN BE NULL HERE !
583 ****************************************************************************/
585 void reply_tcon(struct smb_request *req)
587 connection_struct *conn = req->conn;
588 const char *service;
589 char *service_buf = NULL;
590 char *password = NULL;
591 char *dev = NULL;
592 int pwlen=0;
593 NTSTATUS nt_status;
594 const char *p;
595 DATA_BLOB password_blob;
596 TALLOC_CTX *ctx = talloc_tos();
597 struct smbd_server_connection *sconn = req->sconn;
599 START_PROFILE(SMBtcon);
601 if (req->buflen < 4) {
602 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
603 END_PROFILE(SMBtcon);
604 return;
607 p = (const char *)req->buf + 1;
608 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
609 p += 1;
610 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
611 p += pwlen+1;
612 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
613 p += 1;
615 if (service_buf == NULL || password == NULL || dev == NULL) {
616 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
617 END_PROFILE(SMBtcon);
618 return;
620 p = strrchr_m(service_buf,'\\');
621 if (p) {
622 service = p+1;
623 } else {
624 service = service_buf;
627 password_blob = data_blob(password, pwlen+1);
629 conn = make_connection(sconn,service,password_blob,dev,
630 req->vuid,&nt_status);
631 req->conn = conn;
633 data_blob_clear_free(&password_blob);
635 if (!conn) {
636 reply_nterror(req, nt_status);
637 END_PROFILE(SMBtcon);
638 return;
641 reply_outbuf(req, 2, 0);
642 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
643 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
644 SSVAL(req->outbuf,smb_tid,conn->cnum);
646 DEBUG(3,("tcon service=%s cnum=%d\n",
647 service, conn->cnum));
649 END_PROFILE(SMBtcon);
650 return;
653 /****************************************************************************
654 Reply to a tcon and X.
655 conn POINTER CAN BE NULL HERE !
656 ****************************************************************************/
658 void reply_tcon_and_X(struct smb_request *req)
660 connection_struct *conn = req->conn;
661 const char *service = NULL;
662 DATA_BLOB password;
663 TALLOC_CTX *ctx = talloc_tos();
664 /* what the cleint thinks the device is */
665 char *client_devicetype = NULL;
666 /* what the server tells the client the share represents */
667 const char *server_devicetype;
668 NTSTATUS nt_status;
669 int passlen;
670 char *path = NULL;
671 const char *p, *q;
672 uint16 tcon_flags;
673 struct smbd_server_connection *sconn = req->sconn;
675 START_PROFILE(SMBtconX);
677 if (req->wct < 4) {
678 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
679 END_PROFILE(SMBtconX);
680 return;
683 passlen = SVAL(req->vwv+3, 0);
684 tcon_flags = SVAL(req->vwv+2, 0);
686 /* we might have to close an old one */
687 if ((tcon_flags & 0x1) && conn) {
688 close_cnum(conn,req->vuid);
689 req->conn = NULL;
690 conn = NULL;
693 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
694 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
695 END_PROFILE(SMBtconX);
696 return;
699 if (sconn->smb1.negprot.encrypted_passwords) {
700 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
701 if (lp_security() == SEC_SHARE) {
703 * Security = share always has a pad byte
704 * after the password.
706 p = (const char *)req->buf + passlen + 1;
707 } else {
708 p = (const char *)req->buf + passlen;
710 } else {
711 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
712 /* Ensure correct termination */
713 password.data[passlen]=0;
714 p = (const char *)req->buf + passlen + 1;
717 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
719 if (path == NULL) {
720 data_blob_clear_free(&password);
721 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
722 END_PROFILE(SMBtconX);
723 return;
727 * the service name can be either: \\server\share
728 * or share directly like on the DELL PowerVault 705
730 if (*path=='\\') {
731 q = strchr_m(path+2,'\\');
732 if (!q) {
733 data_blob_clear_free(&password);
734 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
735 END_PROFILE(SMBtconX);
736 return;
738 service = q+1;
739 } else {
740 service = path;
743 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
744 &client_devicetype, p,
745 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
747 if (client_devicetype == NULL) {
748 data_blob_clear_free(&password);
749 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
750 END_PROFILE(SMBtconX);
751 return;
754 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
756 conn = make_connection(sconn, service, password, client_devicetype,
757 req->vuid, &nt_status);
758 req->conn =conn;
760 data_blob_clear_free(&password);
762 if (!conn) {
763 reply_nterror(req, nt_status);
764 END_PROFILE(SMBtconX);
765 return;
768 if ( IS_IPC(conn) )
769 server_devicetype = "IPC";
770 else if ( IS_PRINT(conn) )
771 server_devicetype = "LPT1:";
772 else
773 server_devicetype = "A:";
775 if (get_Protocol() < PROTOCOL_NT1) {
776 reply_outbuf(req, 2, 0);
777 if (message_push_string(&req->outbuf, server_devicetype,
778 STR_TERMINATE|STR_ASCII) == -1) {
779 reply_nterror(req, NT_STATUS_NO_MEMORY);
780 END_PROFILE(SMBtconX);
781 return;
783 } else {
784 /* NT sets the fstype of IPC$ to the null string */
785 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
787 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
788 /* Return permissions. */
789 uint32 perm1 = 0;
790 uint32 perm2 = 0;
792 reply_outbuf(req, 7, 0);
794 if (IS_IPC(conn)) {
795 perm1 = FILE_ALL_ACCESS;
796 perm2 = FILE_ALL_ACCESS;
797 } else {
798 perm1 = CAN_WRITE(conn) ?
799 SHARE_ALL_ACCESS :
800 SHARE_READ_ONLY;
803 SIVAL(req->outbuf, smb_vwv3, perm1);
804 SIVAL(req->outbuf, smb_vwv5, perm2);
805 } else {
806 reply_outbuf(req, 3, 0);
809 if ((message_push_string(&req->outbuf, server_devicetype,
810 STR_TERMINATE|STR_ASCII) == -1)
811 || (message_push_string(&req->outbuf, fstype,
812 STR_TERMINATE) == -1)) {
813 reply_nterror(req, NT_STATUS_NO_MEMORY);
814 END_PROFILE(SMBtconX);
815 return;
818 /* what does setting this bit do? It is set by NT4 and
819 may affect the ability to autorun mounted cdroms */
820 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
821 (lp_csc_policy(SNUM(conn)) << 2));
823 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
824 DEBUG(2,("Serving %s as a Dfs root\n",
825 lp_servicename(SNUM(conn)) ));
826 SSVAL(req->outbuf, smb_vwv2,
827 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
832 DEBUG(3,("tconX service=%s \n",
833 service));
835 /* set the incoming and outgoing tid to the just created one */
836 SSVAL(req->inbuf,smb_tid,conn->cnum);
837 SSVAL(req->outbuf,smb_tid,conn->cnum);
839 END_PROFILE(SMBtconX);
841 req->tid = conn->cnum;
842 chain_reply(req);
843 return;
846 /****************************************************************************
847 Reply to an unknown type.
848 ****************************************************************************/
850 void reply_unknown_new(struct smb_request *req, uint8 type)
852 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
853 smb_fn_name(type), type, type));
854 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
855 return;
858 /****************************************************************************
859 Reply to an ioctl.
860 conn POINTER CAN BE NULL HERE !
861 ****************************************************************************/
863 void reply_ioctl(struct smb_request *req)
865 connection_struct *conn = req->conn;
866 uint16 device;
867 uint16 function;
868 uint32 ioctl_code;
869 int replysize;
870 char *p;
872 START_PROFILE(SMBioctl);
874 if (req->wct < 3) {
875 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
876 END_PROFILE(SMBioctl);
877 return;
880 device = SVAL(req->vwv+1, 0);
881 function = SVAL(req->vwv+2, 0);
882 ioctl_code = (device << 16) + function;
884 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
886 switch (ioctl_code) {
887 case IOCTL_QUERY_JOB_INFO:
888 replysize = 32;
889 break;
890 default:
891 reply_force_doserror(req, ERRSRV, ERRnosupport);
892 END_PROFILE(SMBioctl);
893 return;
896 reply_outbuf(req, 8, replysize+1);
897 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
898 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
899 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
900 p = smb_buf(req->outbuf);
901 memset(p, '\0', replysize+1); /* valgrind-safe. */
902 p += 1; /* Allow for alignment */
904 switch (ioctl_code) {
905 case IOCTL_QUERY_JOB_INFO:
907 files_struct *fsp = file_fsp(
908 req, SVAL(req->vwv+0, 0));
909 if (!fsp) {
910 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
911 END_PROFILE(SMBioctl);
912 return;
914 /* Job number */
915 if (fsp->print_file) {
916 SSVAL(p, 0, fsp->print_file->rap_jobid);
917 } else {
918 SSVAL(p, 0, 0);
920 srvstr_push((char *)req->outbuf, req->flags2, p+2,
921 global_myname(), 15,
922 STR_TERMINATE|STR_ASCII);
923 if (conn) {
924 srvstr_push((char *)req->outbuf, req->flags2,
925 p+18, lp_servicename(SNUM(conn)),
926 13, STR_TERMINATE|STR_ASCII);
927 } else {
928 memset(p+18, 0, 13);
930 break;
934 END_PROFILE(SMBioctl);
935 return;
938 /****************************************************************************
939 Strange checkpath NTSTATUS mapping.
940 ****************************************************************************/
942 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
944 /* Strange DOS error code semantics only for checkpath... */
945 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
946 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
947 /* We need to map to ERRbadpath */
948 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
951 return status;
954 /****************************************************************************
955 Reply to a checkpath.
956 ****************************************************************************/
958 void reply_checkpath(struct smb_request *req)
960 connection_struct *conn = req->conn;
961 struct smb_filename *smb_fname = NULL;
962 char *name = NULL;
963 NTSTATUS status;
964 TALLOC_CTX *ctx = talloc_tos();
966 START_PROFILE(SMBcheckpath);
968 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
969 STR_TERMINATE, &status);
971 if (!NT_STATUS_IS_OK(status)) {
972 status = map_checkpath_error(req->flags2, status);
973 reply_nterror(req, status);
974 END_PROFILE(SMBcheckpath);
975 return;
978 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
980 status = filename_convert(ctx,
981 conn,
982 req->flags2 & FLAGS2_DFS_PATHNAMES,
983 name,
985 NULL,
986 &smb_fname);
988 if (!NT_STATUS_IS_OK(status)) {
989 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
990 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
991 ERRSRV, ERRbadpath);
992 END_PROFILE(SMBcheckpath);
993 return;
995 goto path_err;
998 if (!VALID_STAT(smb_fname->st) &&
999 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1000 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1001 smb_fname_str_dbg(smb_fname), strerror(errno)));
1002 status = map_nt_error_from_unix(errno);
1003 goto path_err;
1006 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1007 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1008 ERRDOS, ERRbadpath);
1009 goto out;
1012 reply_outbuf(req, 0, 0);
1014 path_err:
1015 /* We special case this - as when a Windows machine
1016 is parsing a path is steps through the components
1017 one at a time - if a component fails it expects
1018 ERRbadpath, not ERRbadfile.
1020 status = map_checkpath_error(req->flags2, status);
1021 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1023 * Windows returns different error codes if
1024 * the parent directory is valid but not the
1025 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1026 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1027 * if the path is invalid.
1029 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1030 ERRDOS, ERRbadpath);
1031 goto out;
1034 reply_nterror(req, status);
1036 out:
1037 TALLOC_FREE(smb_fname);
1038 END_PROFILE(SMBcheckpath);
1039 return;
1042 /****************************************************************************
1043 Reply to a getatr.
1044 ****************************************************************************/
1046 void reply_getatr(struct smb_request *req)
1048 connection_struct *conn = req->conn;
1049 struct smb_filename *smb_fname = NULL;
1050 char *fname = NULL;
1051 int mode=0;
1052 SMB_OFF_T size=0;
1053 time_t mtime=0;
1054 const char *p;
1055 NTSTATUS status;
1056 TALLOC_CTX *ctx = talloc_tos();
1057 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1059 START_PROFILE(SMBgetatr);
1061 p = (const char *)req->buf + 1;
1062 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1063 if (!NT_STATUS_IS_OK(status)) {
1064 reply_nterror(req, status);
1065 goto out;
1068 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1069 under WfWg - weird! */
1070 if (*fname == '\0') {
1071 mode = aHIDDEN | aDIR;
1072 if (!CAN_WRITE(conn)) {
1073 mode |= aRONLY;
1075 size = 0;
1076 mtime = 0;
1077 } else {
1078 status = filename_convert(ctx,
1079 conn,
1080 req->flags2 & FLAGS2_DFS_PATHNAMES,
1081 fname,
1083 NULL,
1084 &smb_fname);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1087 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1088 ERRSRV, ERRbadpath);
1089 goto out;
1091 reply_nterror(req, status);
1092 goto out;
1094 if (!VALID_STAT(smb_fname->st) &&
1095 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1096 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1097 smb_fname_str_dbg(smb_fname),
1098 strerror(errno)));
1099 reply_nterror(req, map_nt_error_from_unix(errno));
1100 goto out;
1103 mode = dos_mode(conn, smb_fname);
1104 size = smb_fname->st.st_ex_size;
1106 if (ask_sharemode) {
1107 struct timespec write_time_ts;
1108 struct file_id fileid;
1110 ZERO_STRUCT(write_time_ts);
1111 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1112 get_file_infos(fileid, NULL, &write_time_ts);
1113 if (!null_timespec(write_time_ts)) {
1114 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1118 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1119 if (mode & aDIR) {
1120 size = 0;
1124 reply_outbuf(req, 10, 0);
1126 SSVAL(req->outbuf,smb_vwv0,mode);
1127 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1128 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1129 } else {
1130 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1132 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1134 if (get_Protocol() >= PROTOCOL_NT1) {
1135 SSVAL(req->outbuf, smb_flg2,
1136 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1139 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1140 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1142 out:
1143 TALLOC_FREE(smb_fname);
1144 TALLOC_FREE(fname);
1145 END_PROFILE(SMBgetatr);
1146 return;
1149 /****************************************************************************
1150 Reply to a setatr.
1151 ****************************************************************************/
1153 void reply_setatr(struct smb_request *req)
1155 struct smb_file_time ft;
1156 connection_struct *conn = req->conn;
1157 struct smb_filename *smb_fname = NULL;
1158 char *fname = NULL;
1159 int mode;
1160 time_t mtime;
1161 const char *p;
1162 NTSTATUS status;
1163 TALLOC_CTX *ctx = talloc_tos();
1165 START_PROFILE(SMBsetatr);
1167 ZERO_STRUCT(ft);
1169 if (req->wct < 2) {
1170 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1171 goto out;
1174 p = (const char *)req->buf + 1;
1175 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 reply_nterror(req, status);
1178 goto out;
1181 status = filename_convert(ctx,
1182 conn,
1183 req->flags2 & FLAGS2_DFS_PATHNAMES,
1184 fname,
1186 NULL,
1187 &smb_fname);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1190 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1191 ERRSRV, ERRbadpath);
1192 goto out;
1194 reply_nterror(req, status);
1195 goto out;
1198 if (smb_fname->base_name[0] == '.' &&
1199 smb_fname->base_name[1] == '\0') {
1201 * Not sure here is the right place to catch this
1202 * condition. Might be moved to somewhere else later -- vl
1204 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1205 goto out;
1208 mode = SVAL(req->vwv+0, 0);
1209 mtime = srv_make_unix_date3(req->vwv+1);
1211 ft.mtime = convert_time_t_to_timespec(mtime);
1212 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1213 if (!NT_STATUS_IS_OK(status)) {
1214 reply_nterror(req, status);
1215 goto out;
1218 if (mode != FILE_ATTRIBUTE_NORMAL) {
1219 if (VALID_STAT_OF_DIR(smb_fname->st))
1220 mode |= aDIR;
1221 else
1222 mode &= ~aDIR;
1224 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1225 false) != 0) {
1226 reply_nterror(req, map_nt_error_from_unix(errno));
1227 goto out;
1231 reply_outbuf(req, 0, 0);
1233 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1234 mode));
1235 out:
1236 TALLOC_FREE(smb_fname);
1237 END_PROFILE(SMBsetatr);
1238 return;
1241 /****************************************************************************
1242 Reply to a dskattr.
1243 ****************************************************************************/
1245 void reply_dskattr(struct smb_request *req)
1247 connection_struct *conn = req->conn;
1248 uint64_t dfree,dsize,bsize;
1249 START_PROFILE(SMBdskattr);
1251 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1252 reply_nterror(req, map_nt_error_from_unix(errno));
1253 END_PROFILE(SMBdskattr);
1254 return;
1257 reply_outbuf(req, 5, 0);
1259 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1260 double total_space, free_space;
1261 /* we need to scale this to a number that DOS6 can handle. We
1262 use floating point so we can handle large drives on systems
1263 that don't have 64 bit integers
1265 we end up displaying a maximum of 2G to DOS systems
1267 total_space = dsize * (double)bsize;
1268 free_space = dfree * (double)bsize;
1270 dsize = (uint64_t)((total_space+63*512) / (64*512));
1271 dfree = (uint64_t)((free_space+63*512) / (64*512));
1273 if (dsize > 0xFFFF) dsize = 0xFFFF;
1274 if (dfree > 0xFFFF) dfree = 0xFFFF;
1276 SSVAL(req->outbuf,smb_vwv0,dsize);
1277 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1278 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1279 SSVAL(req->outbuf,smb_vwv3,dfree);
1280 } else {
1281 SSVAL(req->outbuf,smb_vwv0,dsize);
1282 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1283 SSVAL(req->outbuf,smb_vwv2,512);
1284 SSVAL(req->outbuf,smb_vwv3,dfree);
1287 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1289 END_PROFILE(SMBdskattr);
1290 return;
1294 * Utility function to split the filename from the directory.
1296 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1297 char **fname_dir_out,
1298 char **fname_mask_out)
1300 const char *p = NULL;
1301 char *fname_dir = NULL;
1302 char *fname_mask = NULL;
1304 p = strrchr_m(fname_in, '/');
1305 if (!p) {
1306 fname_dir = talloc_strdup(ctx, ".");
1307 fname_mask = talloc_strdup(ctx, fname_in);
1308 } else {
1309 fname_dir = talloc_strndup(ctx, fname_in,
1310 PTR_DIFF(p, fname_in));
1311 fname_mask = talloc_strdup(ctx, p+1);
1314 if (!fname_dir || !fname_mask) {
1315 TALLOC_FREE(fname_dir);
1316 TALLOC_FREE(fname_mask);
1317 return NT_STATUS_NO_MEMORY;
1320 *fname_dir_out = fname_dir;
1321 *fname_mask_out = fname_mask;
1322 return NT_STATUS_OK;
1325 /****************************************************************************
1326 Reply to a search.
1327 Can be called from SMBsearch, SMBffirst or SMBfunique.
1328 ****************************************************************************/
1330 void reply_search(struct smb_request *req)
1332 connection_struct *conn = req->conn;
1333 char *path = NULL;
1334 const char *mask = NULL;
1335 char *directory = NULL;
1336 struct smb_filename *smb_fname = NULL;
1337 char *fname = NULL;
1338 SMB_OFF_T size;
1339 uint32 mode;
1340 struct timespec date;
1341 uint32 dirtype;
1342 unsigned int numentries = 0;
1343 unsigned int maxentries = 0;
1344 bool finished = False;
1345 const char *p;
1346 int status_len;
1347 char status[21];
1348 int dptr_num= -1;
1349 bool check_descend = False;
1350 bool expect_close = False;
1351 NTSTATUS nt_status;
1352 bool mask_contains_wcard = False;
1353 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1354 TALLOC_CTX *ctx = talloc_tos();
1355 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1356 struct dptr_struct *dirptr = NULL;
1357 struct smbd_server_connection *sconn = req->sconn;
1359 START_PROFILE(SMBsearch);
1361 if (req->wct < 2) {
1362 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1363 goto out;
1366 if (lp_posix_pathnames()) {
1367 reply_unknown_new(req, req->cmd);
1368 goto out;
1371 /* If we were called as SMBffirst then we must expect close. */
1372 if(req->cmd == SMBffirst) {
1373 expect_close = True;
1376 reply_outbuf(req, 1, 3);
1377 maxentries = SVAL(req->vwv+0, 0);
1378 dirtype = SVAL(req->vwv+1, 0);
1379 p = (const char *)req->buf + 1;
1380 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1381 &nt_status, &mask_contains_wcard);
1382 if (!NT_STATUS_IS_OK(nt_status)) {
1383 reply_nterror(req, nt_status);
1384 goto out;
1387 p++;
1388 status_len = SVAL(p, 0);
1389 p += 2;
1391 /* dirtype &= ~aDIR; */
1393 if (status_len == 0) {
1394 nt_status = filename_convert(ctx, conn,
1395 req->flags2 & FLAGS2_DFS_PATHNAMES,
1396 path,
1397 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1398 &mask_contains_wcard,
1399 &smb_fname);
1400 if (!NT_STATUS_IS_OK(nt_status)) {
1401 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1402 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1403 ERRSRV, ERRbadpath);
1404 goto out;
1406 reply_nterror(req, nt_status);
1407 goto out;
1410 directory = smb_fname->base_name;
1412 p = strrchr_m(directory,'/');
1413 if ((p != NULL) && (*directory != '/')) {
1414 mask = p + 1;
1415 directory = talloc_strndup(ctx, directory,
1416 PTR_DIFF(p, directory));
1417 } else {
1418 mask = directory;
1419 directory = talloc_strdup(ctx,".");
1422 if (!directory) {
1423 reply_nterror(req, NT_STATUS_NO_MEMORY);
1424 goto out;
1427 memset((char *)status,'\0',21);
1428 SCVAL(status,0,(dirtype & 0x1F));
1430 nt_status = dptr_create(conn,
1431 directory,
1432 True,
1433 expect_close,
1434 req->smbpid,
1435 mask,
1436 mask_contains_wcard,
1437 dirtype,
1438 &dirptr);
1439 if (!NT_STATUS_IS_OK(nt_status)) {
1440 reply_nterror(req, nt_status);
1441 goto out;
1443 dptr_num = dptr_dnum(dirptr);
1444 } else {
1445 int status_dirtype;
1446 const char *dirpath;
1448 memcpy(status,p,21);
1449 status_dirtype = CVAL(status,0) & 0x1F;
1450 if (status_dirtype != (dirtype & 0x1F)) {
1451 dirtype = status_dirtype;
1454 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1455 if (!dirptr) {
1456 goto SearchEmpty;
1458 dirpath = dptr_path(sconn, dptr_num);
1459 directory = talloc_strdup(ctx, dirpath);
1460 if (!directory) {
1461 reply_nterror(req, NT_STATUS_NO_MEMORY);
1462 goto out;
1465 mask = dptr_wcard(sconn, dptr_num);
1466 if (!mask) {
1467 goto SearchEmpty;
1470 * For a 'continue' search we have no string. So
1471 * check from the initial saved string.
1473 mask_contains_wcard = ms_has_wild(mask);
1474 dirtype = dptr_attr(sconn, dptr_num);
1477 DEBUG(4,("dptr_num is %d\n",dptr_num));
1479 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1480 dptr_init_search_op(dirptr);
1482 if ((dirtype&0x1F) == aVOLID) {
1483 char buf[DIR_STRUCT_SIZE];
1484 memcpy(buf,status,21);
1485 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1486 0,aVOLID,0,!allow_long_path_components)) {
1487 reply_nterror(req, NT_STATUS_NO_MEMORY);
1488 goto out;
1490 dptr_fill(sconn, buf+12,dptr_num);
1491 if (dptr_zero(buf+12) && (status_len==0)) {
1492 numentries = 1;
1493 } else {
1494 numentries = 0;
1496 if (message_push_blob(&req->outbuf,
1497 data_blob_const(buf, sizeof(buf)))
1498 == -1) {
1499 reply_nterror(req, NT_STATUS_NO_MEMORY);
1500 goto out;
1502 } else {
1503 unsigned int i;
1504 maxentries = MIN(
1505 maxentries,
1506 ((BUFFER_SIZE -
1507 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1508 /DIR_STRUCT_SIZE));
1510 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1511 directory,lp_dontdescend(SNUM(conn))));
1512 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1513 check_descend = True;
1516 for (i=numentries;(i<maxentries) && !finished;i++) {
1517 finished = !get_dir_entry(ctx,
1518 dirptr,
1519 mask,
1520 dirtype,
1521 &fname,
1522 &size,
1523 &mode,
1524 &date,
1525 check_descend,
1526 ask_sharemode);
1527 if (!finished) {
1528 char buf[DIR_STRUCT_SIZE];
1529 memcpy(buf,status,21);
1530 if (!make_dir_struct(ctx,
1531 buf,
1532 mask,
1533 fname,
1534 size,
1535 mode,
1536 convert_timespec_to_time_t(date),
1537 !allow_long_path_components)) {
1538 reply_nterror(req, NT_STATUS_NO_MEMORY);
1539 goto out;
1541 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1542 break;
1544 if (message_push_blob(&req->outbuf,
1545 data_blob_const(buf, sizeof(buf)))
1546 == -1) {
1547 reply_nterror(req, NT_STATUS_NO_MEMORY);
1548 goto out;
1550 numentries++;
1555 SearchEmpty:
1557 /* If we were called as SMBffirst with smb_search_id == NULL
1558 and no entries were found then return error and close dirptr
1559 (X/Open spec) */
1561 if (numentries == 0) {
1562 dptr_close(sconn, &dptr_num);
1563 } else if(expect_close && status_len == 0) {
1564 /* Close the dptr - we know it's gone */
1565 dptr_close(sconn, &dptr_num);
1568 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1569 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1570 dptr_close(sconn, &dptr_num);
1573 if ((numentries == 0) && !mask_contains_wcard) {
1574 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1575 goto out;
1578 SSVAL(req->outbuf,smb_vwv0,numentries);
1579 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1580 SCVAL(smb_buf(req->outbuf),0,5);
1581 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1583 /* The replies here are never long name. */
1584 SSVAL(req->outbuf, smb_flg2,
1585 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1586 if (!allow_long_path_components) {
1587 SSVAL(req->outbuf, smb_flg2,
1588 SVAL(req->outbuf, smb_flg2)
1589 & (~FLAGS2_LONG_PATH_COMPONENTS));
1592 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1593 SSVAL(req->outbuf, smb_flg2,
1594 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1596 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1597 smb_fn_name(req->cmd),
1598 mask,
1599 directory,
1600 dirtype,
1601 numentries,
1602 maxentries ));
1603 out:
1604 TALLOC_FREE(directory);
1605 TALLOC_FREE(smb_fname);
1606 END_PROFILE(SMBsearch);
1607 return;
1610 /****************************************************************************
1611 Reply to a fclose (stop directory search).
1612 ****************************************************************************/
1614 void reply_fclose(struct smb_request *req)
1616 int status_len;
1617 char status[21];
1618 int dptr_num= -2;
1619 const char *p;
1620 char *path = NULL;
1621 NTSTATUS err;
1622 bool path_contains_wcard = False;
1623 TALLOC_CTX *ctx = talloc_tos();
1624 struct smbd_server_connection *sconn = req->sconn;
1626 START_PROFILE(SMBfclose);
1628 if (lp_posix_pathnames()) {
1629 reply_unknown_new(req, req->cmd);
1630 END_PROFILE(SMBfclose);
1631 return;
1634 p = (const char *)req->buf + 1;
1635 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1636 &err, &path_contains_wcard);
1637 if (!NT_STATUS_IS_OK(err)) {
1638 reply_nterror(req, err);
1639 END_PROFILE(SMBfclose);
1640 return;
1642 p++;
1643 status_len = SVAL(p,0);
1644 p += 2;
1646 if (status_len == 0) {
1647 reply_force_doserror(req, ERRSRV, ERRsrverror);
1648 END_PROFILE(SMBfclose);
1649 return;
1652 memcpy(status,p,21);
1654 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1655 /* Close the dptr - we know it's gone */
1656 dptr_close(sconn, &dptr_num);
1659 reply_outbuf(req, 1, 0);
1660 SSVAL(req->outbuf,smb_vwv0,0);
1662 DEBUG(3,("search close\n"));
1664 END_PROFILE(SMBfclose);
1665 return;
1668 /****************************************************************************
1669 Reply to an open.
1670 ****************************************************************************/
1672 void reply_open(struct smb_request *req)
1674 connection_struct *conn = req->conn;
1675 struct smb_filename *smb_fname = NULL;
1676 char *fname = NULL;
1677 uint32 fattr=0;
1678 SMB_OFF_T size = 0;
1679 time_t mtime=0;
1680 int info;
1681 files_struct *fsp;
1682 int oplock_request;
1683 int deny_mode;
1684 uint32 dos_attr;
1685 uint32 access_mask;
1686 uint32 share_mode;
1687 uint32 create_disposition;
1688 uint32 create_options = 0;
1689 uint32_t private_flags = 0;
1690 NTSTATUS status;
1691 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1692 TALLOC_CTX *ctx = talloc_tos();
1694 START_PROFILE(SMBopen);
1696 if (req->wct < 2) {
1697 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1698 goto out;
1701 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1702 deny_mode = SVAL(req->vwv+0, 0);
1703 dos_attr = SVAL(req->vwv+1, 0);
1705 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1706 STR_TERMINATE, &status);
1707 if (!NT_STATUS_IS_OK(status)) {
1708 reply_nterror(req, status);
1709 goto out;
1712 status = filename_convert(ctx,
1713 conn,
1714 req->flags2 & FLAGS2_DFS_PATHNAMES,
1715 fname,
1717 NULL,
1718 &smb_fname);
1719 if (!NT_STATUS_IS_OK(status)) {
1720 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1721 reply_botherror(req,
1722 NT_STATUS_PATH_NOT_COVERED,
1723 ERRSRV, ERRbadpath);
1724 goto out;
1726 reply_nterror(req, status);
1727 goto out;
1730 if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
1731 OPENX_FILE_EXISTS_OPEN, &access_mask,
1732 &share_mode, &create_disposition,
1733 &create_options, &private_flags)) {
1734 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1735 goto out;
1738 status = SMB_VFS_CREATE_FILE(
1739 conn, /* conn */
1740 req, /* req */
1741 0, /* root_dir_fid */
1742 smb_fname, /* fname */
1743 access_mask, /* access_mask */
1744 share_mode, /* share_access */
1745 create_disposition, /* create_disposition*/
1746 create_options, /* create_options */
1747 dos_attr, /* file_attributes */
1748 oplock_request, /* oplock_request */
1749 0, /* allocation_size */
1750 private_flags,
1751 NULL, /* sd */
1752 NULL, /* ea_list */
1753 &fsp, /* result */
1754 &info); /* pinfo */
1756 if (!NT_STATUS_IS_OK(status)) {
1757 if (open_was_deferred(req->mid)) {
1758 /* We have re-scheduled this call. */
1759 goto out;
1761 reply_openerror(req, status);
1762 goto out;
1765 size = smb_fname->st.st_ex_size;
1766 fattr = dos_mode(conn, smb_fname);
1768 /* Deal with other possible opens having a modified
1769 write time. JRA. */
1770 if (ask_sharemode) {
1771 struct timespec write_time_ts;
1773 ZERO_STRUCT(write_time_ts);
1774 get_file_infos(fsp->file_id, NULL, &write_time_ts);
1775 if (!null_timespec(write_time_ts)) {
1776 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1780 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1782 if (fattr & aDIR) {
1783 DEBUG(3,("attempt to open a directory %s\n",
1784 fsp_str_dbg(fsp)));
1785 close_file(req, fsp, ERROR_CLOSE);
1786 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1787 ERRDOS, ERRnoaccess);
1788 goto out;
1791 reply_outbuf(req, 7, 0);
1792 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1793 SSVAL(req->outbuf,smb_vwv1,fattr);
1794 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1795 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1796 } else {
1797 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1799 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1800 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1802 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1803 SCVAL(req->outbuf,smb_flg,
1804 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1807 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1808 SCVAL(req->outbuf,smb_flg,
1809 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1811 out:
1812 TALLOC_FREE(smb_fname);
1813 END_PROFILE(SMBopen);
1814 return;
1817 /****************************************************************************
1818 Reply to an open and X.
1819 ****************************************************************************/
1821 void reply_open_and_X(struct smb_request *req)
1823 connection_struct *conn = req->conn;
1824 struct smb_filename *smb_fname = NULL;
1825 char *fname = NULL;
1826 uint16 open_flags;
1827 int deny_mode;
1828 uint32 smb_attr;
1829 /* Breakout the oplock request bits so we can set the
1830 reply bits separately. */
1831 int ex_oplock_request;
1832 int core_oplock_request;
1833 int oplock_request;
1834 #if 0
1835 int smb_sattr = SVAL(req->vwv+4, 0);
1836 uint32 smb_time = make_unix_date3(req->vwv+6);
1837 #endif
1838 int smb_ofun;
1839 uint32 fattr=0;
1840 int mtime=0;
1841 int smb_action = 0;
1842 files_struct *fsp;
1843 NTSTATUS status;
1844 uint64_t allocation_size;
1845 ssize_t retval = -1;
1846 uint32 access_mask;
1847 uint32 share_mode;
1848 uint32 create_disposition;
1849 uint32 create_options = 0;
1850 uint32_t private_flags = 0;
1851 TALLOC_CTX *ctx = talloc_tos();
1853 START_PROFILE(SMBopenX);
1855 if (req->wct < 15) {
1856 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1857 goto out;
1860 open_flags = SVAL(req->vwv+2, 0);
1861 deny_mode = SVAL(req->vwv+3, 0);
1862 smb_attr = SVAL(req->vwv+5, 0);
1863 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1864 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1865 oplock_request = ex_oplock_request | core_oplock_request;
1866 smb_ofun = SVAL(req->vwv+8, 0);
1867 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1869 /* If it's an IPC, pass off the pipe handler. */
1870 if (IS_IPC(conn)) {
1871 if (lp_nt_pipe_support()) {
1872 reply_open_pipe_and_X(conn, req);
1873 } else {
1874 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1876 goto out;
1879 /* XXXX we need to handle passed times, sattr and flags */
1880 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1881 STR_TERMINATE, &status);
1882 if (!NT_STATUS_IS_OK(status)) {
1883 reply_nterror(req, status);
1884 goto out;
1887 status = filename_convert(ctx,
1888 conn,
1889 req->flags2 & FLAGS2_DFS_PATHNAMES,
1890 fname,
1892 NULL,
1893 &smb_fname);
1894 if (!NT_STATUS_IS_OK(status)) {
1895 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1896 reply_botherror(req,
1897 NT_STATUS_PATH_NOT_COVERED,
1898 ERRSRV, ERRbadpath);
1899 goto out;
1901 reply_nterror(req, status);
1902 goto out;
1905 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
1906 &access_mask, &share_mode,
1907 &create_disposition,
1908 &create_options,
1909 &private_flags)) {
1910 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1911 goto out;
1914 status = SMB_VFS_CREATE_FILE(
1915 conn, /* conn */
1916 req, /* req */
1917 0, /* root_dir_fid */
1918 smb_fname, /* fname */
1919 access_mask, /* access_mask */
1920 share_mode, /* share_access */
1921 create_disposition, /* create_disposition*/
1922 create_options, /* create_options */
1923 smb_attr, /* file_attributes */
1924 oplock_request, /* oplock_request */
1925 0, /* allocation_size */
1926 private_flags,
1927 NULL, /* sd */
1928 NULL, /* ea_list */
1929 &fsp, /* result */
1930 &smb_action); /* pinfo */
1932 if (!NT_STATUS_IS_OK(status)) {
1933 if (open_was_deferred(req->mid)) {
1934 /* We have re-scheduled this call. */
1935 goto out;
1937 reply_openerror(req, status);
1938 goto out;
1941 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1942 if the file is truncated or created. */
1943 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1944 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1945 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1946 close_file(req, fsp, ERROR_CLOSE);
1947 reply_nterror(req, NT_STATUS_DISK_FULL);
1948 goto out;
1950 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1951 if (retval < 0) {
1952 close_file(req, fsp, ERROR_CLOSE);
1953 reply_nterror(req, NT_STATUS_DISK_FULL);
1954 goto out;
1956 smb_fname->st.st_ex_size =
1957 SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st);
1960 fattr = dos_mode(conn, smb_fname);
1961 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1962 if (fattr & aDIR) {
1963 close_file(req, fsp, ERROR_CLOSE);
1964 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1965 goto out;
1968 /* If the caller set the extended oplock request bit
1969 and we granted one (by whatever means) - set the
1970 correct bit for extended oplock reply.
1973 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1974 smb_action |= EXTENDED_OPLOCK_GRANTED;
1977 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1978 smb_action |= EXTENDED_OPLOCK_GRANTED;
1981 /* If the caller set the core oplock request bit
1982 and we granted one (by whatever means) - set the
1983 correct bit for core oplock reply.
1986 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1987 reply_outbuf(req, 19, 0);
1988 } else {
1989 reply_outbuf(req, 15, 0);
1992 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1993 SCVAL(req->outbuf, smb_flg,
1994 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1997 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1998 SCVAL(req->outbuf, smb_flg,
1999 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2002 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2003 SSVAL(req->outbuf,smb_vwv3,fattr);
2004 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2005 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2006 } else {
2007 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2009 SIVAL(req->outbuf,smb_vwv6,(uint32)smb_fname->st.st_ex_size);
2010 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2011 SSVAL(req->outbuf,smb_vwv11,smb_action);
2013 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2014 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2017 chain_reply(req);
2018 out:
2019 TALLOC_FREE(smb_fname);
2020 END_PROFILE(SMBopenX);
2021 return;
2024 /****************************************************************************
2025 Reply to a SMBulogoffX.
2026 ****************************************************************************/
2028 void reply_ulogoffX(struct smb_request *req)
2030 struct smbd_server_connection *sconn = req->sconn;
2031 user_struct *vuser;
2033 START_PROFILE(SMBulogoffX);
2035 vuser = get_valid_user_struct(sconn, req->vuid);
2037 if(vuser == NULL) {
2038 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2039 req->vuid));
2042 /* in user level security we are supposed to close any files
2043 open by this user */
2044 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2045 file_close_user(req->vuid);
2048 invalidate_vuid(sconn, req->vuid);
2050 reply_outbuf(req, 2, 0);
2052 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2054 END_PROFILE(SMBulogoffX);
2055 req->vuid = UID_FIELD_INVALID;
2056 chain_reply(req);
2059 /****************************************************************************
2060 Reply to a mknew or a create.
2061 ****************************************************************************/
2063 void reply_mknew(struct smb_request *req)
2065 connection_struct *conn = req->conn;
2066 struct smb_filename *smb_fname = NULL;
2067 char *fname = NULL;
2068 uint32 fattr = 0;
2069 struct smb_file_time ft;
2070 files_struct *fsp;
2071 int oplock_request = 0;
2072 NTSTATUS status;
2073 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2074 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2075 uint32 create_disposition;
2076 uint32 create_options = 0;
2077 TALLOC_CTX *ctx = talloc_tos();
2079 START_PROFILE(SMBcreate);
2080 ZERO_STRUCT(ft);
2082 if (req->wct < 3) {
2083 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2084 goto out;
2087 fattr = SVAL(req->vwv+0, 0);
2088 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2090 /* mtime. */
2091 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2093 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2094 STR_TERMINATE, &status);
2095 if (!NT_STATUS_IS_OK(status)) {
2096 reply_nterror(req, status);
2097 goto out;
2100 status = filename_convert(ctx,
2101 conn,
2102 req->flags2 & FLAGS2_DFS_PATHNAMES,
2103 fname,
2105 NULL,
2106 &smb_fname);
2107 if (!NT_STATUS_IS_OK(status)) {
2108 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2109 reply_botherror(req,
2110 NT_STATUS_PATH_NOT_COVERED,
2111 ERRSRV, ERRbadpath);
2112 goto out;
2114 reply_nterror(req, status);
2115 goto out;
2118 if (fattr & aVOLID) {
2119 DEBUG(0,("Attempt to create file (%s) with volid set - "
2120 "please report this\n",
2121 smb_fname_str_dbg(smb_fname)));
2124 if(req->cmd == SMBmknew) {
2125 /* We should fail if file exists. */
2126 create_disposition = FILE_CREATE;
2127 } else {
2128 /* Create if file doesn't exist, truncate if it does. */
2129 create_disposition = FILE_OVERWRITE_IF;
2132 status = SMB_VFS_CREATE_FILE(
2133 conn, /* conn */
2134 req, /* req */
2135 0, /* root_dir_fid */
2136 smb_fname, /* fname */
2137 access_mask, /* access_mask */
2138 share_mode, /* share_access */
2139 create_disposition, /* create_disposition*/
2140 create_options, /* create_options */
2141 fattr, /* file_attributes */
2142 oplock_request, /* oplock_request */
2143 0, /* allocation_size */
2144 0, /* private_flags */
2145 NULL, /* sd */
2146 NULL, /* ea_list */
2147 &fsp, /* result */
2148 NULL); /* pinfo */
2150 if (!NT_STATUS_IS_OK(status)) {
2151 if (open_was_deferred(req->mid)) {
2152 /* We have re-scheduled this call. */
2153 goto out;
2155 reply_openerror(req, status);
2156 goto out;
2159 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2160 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2161 if (!NT_STATUS_IS_OK(status)) {
2162 END_PROFILE(SMBcreate);
2163 goto out;
2166 reply_outbuf(req, 1, 0);
2167 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2169 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2170 SCVAL(req->outbuf,smb_flg,
2171 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2174 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2175 SCVAL(req->outbuf,smb_flg,
2176 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2179 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2180 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2181 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2182 (unsigned int)fattr));
2184 out:
2185 TALLOC_FREE(smb_fname);
2186 END_PROFILE(SMBcreate);
2187 return;
2190 /****************************************************************************
2191 Reply to a create temporary file.
2192 ****************************************************************************/
2194 void reply_ctemp(struct smb_request *req)
2196 connection_struct *conn = req->conn;
2197 struct smb_filename *smb_fname = NULL;
2198 char *fname = NULL;
2199 uint32 fattr;
2200 files_struct *fsp;
2201 int oplock_request;
2202 int tmpfd;
2203 char *s;
2204 NTSTATUS status;
2205 TALLOC_CTX *ctx = talloc_tos();
2207 START_PROFILE(SMBctemp);
2209 if (req->wct < 3) {
2210 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2211 goto out;
2214 fattr = SVAL(req->vwv+0, 0);
2215 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2217 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2218 STR_TERMINATE, &status);
2219 if (!NT_STATUS_IS_OK(status)) {
2220 reply_nterror(req, status);
2221 goto out;
2223 if (*fname) {
2224 fname = talloc_asprintf(ctx,
2225 "%s/TMXXXXXX",
2226 fname);
2227 } else {
2228 fname = talloc_strdup(ctx, "TMXXXXXX");
2231 if (!fname) {
2232 reply_nterror(req, NT_STATUS_NO_MEMORY);
2233 goto out;
2236 status = filename_convert(ctx, conn,
2237 req->flags2 & FLAGS2_DFS_PATHNAMES,
2238 fname,
2240 NULL,
2241 &smb_fname);
2242 if (!NT_STATUS_IS_OK(status)) {
2243 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2244 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2245 ERRSRV, ERRbadpath);
2246 goto out;
2248 reply_nterror(req, status);
2249 goto out;
2252 tmpfd = mkstemp(smb_fname->base_name);
2253 if (tmpfd == -1) {
2254 reply_nterror(req, map_nt_error_from_unix(errno));
2255 goto out;
2258 SMB_VFS_STAT(conn, smb_fname);
2260 /* We should fail if file does not exist. */
2261 status = SMB_VFS_CREATE_FILE(
2262 conn, /* conn */
2263 req, /* req */
2264 0, /* root_dir_fid */
2265 smb_fname, /* fname */
2266 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2267 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2268 FILE_OPEN, /* create_disposition*/
2269 0, /* create_options */
2270 fattr, /* file_attributes */
2271 oplock_request, /* oplock_request */
2272 0, /* allocation_size */
2273 0, /* private_flags */
2274 NULL, /* sd */
2275 NULL, /* ea_list */
2276 &fsp, /* result */
2277 NULL); /* pinfo */
2279 /* close fd from mkstemp() */
2280 close(tmpfd);
2282 if (!NT_STATUS_IS_OK(status)) {
2283 if (open_was_deferred(req->mid)) {
2284 /* We have re-scheduled this call. */
2285 goto out;
2287 reply_openerror(req, status);
2288 goto out;
2291 reply_outbuf(req, 1, 0);
2292 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2294 /* the returned filename is relative to the directory */
2295 s = strrchr_m(fsp->fsp_name->base_name, '/');
2296 if (!s) {
2297 s = fsp->fsp_name->base_name;
2298 } else {
2299 s++;
2302 #if 0
2303 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2304 thing in the byte section. JRA */
2305 SSVALS(p, 0, -1); /* what is this? not in spec */
2306 #endif
2307 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2308 == -1) {
2309 reply_nterror(req, NT_STATUS_NO_MEMORY);
2310 goto out;
2313 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2314 SCVAL(req->outbuf, smb_flg,
2315 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2318 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2319 SCVAL(req->outbuf, smb_flg,
2320 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2323 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2324 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2325 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2326 out:
2327 TALLOC_FREE(smb_fname);
2328 END_PROFILE(SMBctemp);
2329 return;
2332 /*******************************************************************
2333 Check if a user is allowed to rename a file.
2334 ********************************************************************/
2336 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2337 uint16 dirtype)
2339 uint32 fmode;
2341 if (!CAN_WRITE(conn)) {
2342 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2345 fmode = dos_mode(conn, fsp->fsp_name);
2346 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2347 return NT_STATUS_NO_SUCH_FILE;
2350 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2351 if (fsp->posix_open) {
2352 return NT_STATUS_OK;
2355 /* If no pathnames are open below this
2356 directory, allow the rename. */
2358 if (file_find_subpath(fsp)) {
2359 return NT_STATUS_ACCESS_DENIED;
2361 return NT_STATUS_OK;
2364 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2365 return NT_STATUS_OK;
2368 return NT_STATUS_ACCESS_DENIED;
2371 /*******************************************************************
2372 * unlink a file with all relevant access checks
2373 *******************************************************************/
2375 static NTSTATUS do_unlink(connection_struct *conn,
2376 struct smb_request *req,
2377 struct smb_filename *smb_fname,
2378 uint32 dirtype)
2380 uint32 fattr;
2381 files_struct *fsp;
2382 uint32 dirtype_orig = dirtype;
2383 NTSTATUS status;
2384 int ret;
2385 bool posix_paths = lp_posix_pathnames();
2387 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2388 smb_fname_str_dbg(smb_fname),
2389 dirtype));
2391 if (!CAN_WRITE(conn)) {
2392 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2395 if (posix_paths) {
2396 ret = SMB_VFS_LSTAT(conn, smb_fname);
2397 } else {
2398 ret = SMB_VFS_STAT(conn, smb_fname);
2400 if (ret != 0) {
2401 return map_nt_error_from_unix(errno);
2404 fattr = dos_mode(conn, smb_fname);
2406 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2407 dirtype = aDIR|aARCH|aRONLY;
2410 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2411 if (!dirtype) {
2412 return NT_STATUS_NO_SUCH_FILE;
2415 if (!dir_check_ftype(conn, fattr, dirtype)) {
2416 if (fattr & aDIR) {
2417 return NT_STATUS_FILE_IS_A_DIRECTORY;
2419 return NT_STATUS_NO_SUCH_FILE;
2422 if (dirtype_orig & 0x8000) {
2423 /* These will never be set for POSIX. */
2424 return NT_STATUS_NO_SUCH_FILE;
2427 #if 0
2428 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2429 return NT_STATUS_FILE_IS_A_DIRECTORY;
2432 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2433 return NT_STATUS_NO_SUCH_FILE;
2436 if (dirtype & 0xFF00) {
2437 /* These will never be set for POSIX. */
2438 return NT_STATUS_NO_SUCH_FILE;
2441 dirtype &= 0xFF;
2442 if (!dirtype) {
2443 return NT_STATUS_NO_SUCH_FILE;
2446 /* Can't delete a directory. */
2447 if (fattr & aDIR) {
2448 return NT_STATUS_FILE_IS_A_DIRECTORY;
2450 #endif
2452 #if 0 /* JRATEST */
2453 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2454 return NT_STATUS_OBJECT_NAME_INVALID;
2455 #endif /* JRATEST */
2457 /* On open checks the open itself will check the share mode, so
2458 don't do it here as we'll get it wrong. */
2460 status = SMB_VFS_CREATE_FILE
2461 (conn, /* conn */
2462 req, /* req */
2463 0, /* root_dir_fid */
2464 smb_fname, /* fname */
2465 DELETE_ACCESS, /* access_mask */
2466 FILE_SHARE_NONE, /* share_access */
2467 FILE_OPEN, /* create_disposition*/
2468 FILE_NON_DIRECTORY_FILE, /* create_options */
2469 /* file_attributes */
2470 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2471 FILE_ATTRIBUTE_NORMAL,
2472 0, /* oplock_request */
2473 0, /* allocation_size */
2474 0, /* private_flags */
2475 NULL, /* sd */
2476 NULL, /* ea_list */
2477 &fsp, /* result */
2478 NULL); /* pinfo */
2480 if (!NT_STATUS_IS_OK(status)) {
2481 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2482 nt_errstr(status)));
2483 return status;
2486 status = can_set_delete_on_close(fsp, fattr);
2487 if (!NT_STATUS_IS_OK(status)) {
2488 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2489 "(%s)\n",
2490 smb_fname_str_dbg(smb_fname),
2491 nt_errstr(status)));
2492 close_file(req, fsp, NORMAL_CLOSE);
2493 return status;
2496 /* The set is across all open files on this dev/inode pair. */
2497 if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) {
2498 close_file(req, fsp, NORMAL_CLOSE);
2499 return NT_STATUS_ACCESS_DENIED;
2502 return close_file(req, fsp, NORMAL_CLOSE);
2505 /****************************************************************************
2506 The guts of the unlink command, split out so it may be called by the NT SMB
2507 code.
2508 ****************************************************************************/
2510 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2511 uint32 dirtype, struct smb_filename *smb_fname,
2512 bool has_wild)
2514 char *fname_dir = NULL;
2515 char *fname_mask = NULL;
2516 int count=0;
2517 NTSTATUS status = NT_STATUS_OK;
2518 TALLOC_CTX *ctx = talloc_tos();
2520 /* Split up the directory from the filename/mask. */
2521 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2522 &fname_dir, &fname_mask);
2523 if (!NT_STATUS_IS_OK(status)) {
2524 goto out;
2528 * We should only check the mangled cache
2529 * here if unix_convert failed. This means
2530 * that the path in 'mask' doesn't exist
2531 * on the file system and so we need to look
2532 * for a possible mangle. This patch from
2533 * Tine Smukavec <valentin.smukavec@hermes.si>.
2536 if (!VALID_STAT(smb_fname->st) &&
2537 mangle_is_mangled(fname_mask, conn->params)) {
2538 char *new_mask = NULL;
2539 mangle_lookup_name_from_8_3(ctx, fname_mask,
2540 &new_mask, conn->params);
2541 if (new_mask) {
2542 TALLOC_FREE(fname_mask);
2543 fname_mask = new_mask;
2547 if (!has_wild) {
2550 * Only one file needs to be unlinked. Append the mask back
2551 * onto the directory.
2553 TALLOC_FREE(smb_fname->base_name);
2554 smb_fname->base_name = talloc_asprintf(smb_fname,
2555 "%s/%s",
2556 fname_dir,
2557 fname_mask);
2558 if (!smb_fname->base_name) {
2559 status = NT_STATUS_NO_MEMORY;
2560 goto out;
2562 if (dirtype == 0) {
2563 dirtype = FILE_ATTRIBUTE_NORMAL;
2566 status = check_name(conn, smb_fname->base_name);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 goto out;
2571 status = do_unlink(conn, req, smb_fname, dirtype);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 goto out;
2576 count++;
2577 } else {
2578 struct smb_Dir *dir_hnd = NULL;
2579 long offset = 0;
2580 const char *dname = NULL;
2581 char *talloced = NULL;
2583 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2584 status = NT_STATUS_OBJECT_NAME_INVALID;
2585 goto out;
2588 if (strequal(fname_mask,"????????.???")) {
2589 TALLOC_FREE(fname_mask);
2590 fname_mask = talloc_strdup(ctx, "*");
2591 if (!fname_mask) {
2592 status = NT_STATUS_NO_MEMORY;
2593 goto out;
2597 status = check_name(conn, fname_dir);
2598 if (!NT_STATUS_IS_OK(status)) {
2599 goto out;
2602 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2603 dirtype);
2604 if (dir_hnd == NULL) {
2605 status = map_nt_error_from_unix(errno);
2606 goto out;
2609 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2610 the pattern matches against the long name, otherwise the short name
2611 We don't implement this yet XXXX
2614 status = NT_STATUS_NO_SUCH_FILE;
2616 while ((dname = ReadDirName(dir_hnd, &offset,
2617 &smb_fname->st, &talloced))) {
2618 TALLOC_CTX *frame = talloc_stackframe();
2620 if (!is_visible_file(conn, fname_dir, dname,
2621 &smb_fname->st, true)) {
2622 TALLOC_FREE(frame);
2623 TALLOC_FREE(talloced);
2624 continue;
2627 /* Quick check for "." and ".." */
2628 if (ISDOT(dname) || ISDOTDOT(dname)) {
2629 TALLOC_FREE(frame);
2630 TALLOC_FREE(talloced);
2631 continue;
2634 if(!mask_match(dname, fname_mask,
2635 conn->case_sensitive)) {
2636 TALLOC_FREE(frame);
2637 TALLOC_FREE(talloced);
2638 continue;
2641 TALLOC_FREE(smb_fname->base_name);
2642 smb_fname->base_name =
2643 talloc_asprintf(smb_fname, "%s/%s",
2644 fname_dir, dname);
2646 if (!smb_fname->base_name) {
2647 TALLOC_FREE(dir_hnd);
2648 status = NT_STATUS_NO_MEMORY;
2649 TALLOC_FREE(frame);
2650 TALLOC_FREE(talloced);
2651 goto out;
2654 status = check_name(conn, smb_fname->base_name);
2655 if (!NT_STATUS_IS_OK(status)) {
2656 TALLOC_FREE(dir_hnd);
2657 TALLOC_FREE(frame);
2658 TALLOC_FREE(talloced);
2659 goto out;
2662 status = do_unlink(conn, req, smb_fname, dirtype);
2663 if (!NT_STATUS_IS_OK(status)) {
2664 TALLOC_FREE(frame);
2665 TALLOC_FREE(talloced);
2666 continue;
2669 count++;
2670 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2671 smb_fname->base_name));
2673 TALLOC_FREE(frame);
2674 TALLOC_FREE(talloced);
2676 TALLOC_FREE(dir_hnd);
2679 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2680 status = map_nt_error_from_unix(errno);
2683 out:
2684 TALLOC_FREE(fname_dir);
2685 TALLOC_FREE(fname_mask);
2686 return status;
2689 /****************************************************************************
2690 Reply to a unlink
2691 ****************************************************************************/
2693 void reply_unlink(struct smb_request *req)
2695 connection_struct *conn = req->conn;
2696 char *name = NULL;
2697 struct smb_filename *smb_fname = NULL;
2698 uint32 dirtype;
2699 NTSTATUS status;
2700 bool path_contains_wcard = False;
2701 TALLOC_CTX *ctx = talloc_tos();
2703 START_PROFILE(SMBunlink);
2705 if (req->wct < 1) {
2706 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2707 goto out;
2710 dirtype = SVAL(req->vwv+0, 0);
2712 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2713 STR_TERMINATE, &status,
2714 &path_contains_wcard);
2715 if (!NT_STATUS_IS_OK(status)) {
2716 reply_nterror(req, status);
2717 goto out;
2720 status = filename_convert(ctx, conn,
2721 req->flags2 & FLAGS2_DFS_PATHNAMES,
2722 name,
2723 UCF_COND_ALLOW_WCARD_LCOMP,
2724 &path_contains_wcard,
2725 &smb_fname);
2726 if (!NT_STATUS_IS_OK(status)) {
2727 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2728 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2729 ERRSRV, ERRbadpath);
2730 goto out;
2732 reply_nterror(req, status);
2733 goto out;
2736 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2738 status = unlink_internals(conn, req, dirtype, smb_fname,
2739 path_contains_wcard);
2740 if (!NT_STATUS_IS_OK(status)) {
2741 if (open_was_deferred(req->mid)) {
2742 /* We have re-scheduled this call. */
2743 goto out;
2745 reply_nterror(req, status);
2746 goto out;
2749 reply_outbuf(req, 0, 0);
2750 out:
2751 TALLOC_FREE(smb_fname);
2752 END_PROFILE(SMBunlink);
2753 return;
2756 /****************************************************************************
2757 Fail for readbraw.
2758 ****************************************************************************/
2760 static void fail_readraw(void)
2762 const char *errstr = talloc_asprintf(talloc_tos(),
2763 "FAIL ! reply_readbraw: socket write fail (%s)",
2764 strerror(errno));
2765 if (!errstr) {
2766 errstr = "";
2768 exit_server_cleanly(errstr);
2771 /****************************************************************************
2772 Fake (read/write) sendfile. Returns -1 on read or write fail.
2773 ****************************************************************************/
2775 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
2776 size_t nread)
2778 size_t bufsize;
2779 size_t tosend = nread;
2780 char *buf;
2782 if (nread == 0) {
2783 return 0;
2786 bufsize = MIN(nread, 65536);
2788 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2789 return -1;
2792 while (tosend > 0) {
2793 ssize_t ret;
2794 size_t cur_read;
2796 if (tosend > bufsize) {
2797 cur_read = bufsize;
2798 } else {
2799 cur_read = tosend;
2801 ret = read_file(fsp,buf,startpos,cur_read);
2802 if (ret == -1) {
2803 SAFE_FREE(buf);
2804 return -1;
2807 /* If we had a short read, fill with zeros. */
2808 if (ret < cur_read) {
2809 memset(buf + ret, '\0', cur_read - ret);
2812 if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
2813 SAFE_FREE(buf);
2814 return -1;
2816 tosend -= cur_read;
2817 startpos += cur_read;
2820 SAFE_FREE(buf);
2821 return (ssize_t)nread;
2824 #if defined(WITH_SENDFILE)
2825 /****************************************************************************
2826 Deal with the case of sendfile reading less bytes from the file than
2827 requested. Fill with zeros (all we can do).
2828 ****************************************************************************/
2830 static void sendfile_short_send(files_struct *fsp,
2831 ssize_t nread,
2832 size_t headersize,
2833 size_t smb_maxcnt)
2835 #define SHORT_SEND_BUFSIZE 1024
2836 if (nread < headersize) {
2837 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2838 "header for file %s (%s). Terminating\n",
2839 fsp_str_dbg(fsp), strerror(errno)));
2840 exit_server_cleanly("sendfile_short_send failed");
2843 nread -= headersize;
2845 if (nread < smb_maxcnt) {
2846 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2847 if (!buf) {
2848 exit_server_cleanly("sendfile_short_send: "
2849 "malloc failed");
2852 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2853 "with zeros !\n", fsp_str_dbg(fsp)));
2855 while (nread < smb_maxcnt) {
2857 * We asked for the real file size and told sendfile
2858 * to not go beyond the end of the file. But it can
2859 * happen that in between our fstat call and the
2860 * sendfile call the file was truncated. This is very
2861 * bad because we have already announced the larger
2862 * number of bytes to the client.
2864 * The best we can do now is to send 0-bytes, just as
2865 * a read from a hole in a sparse file would do.
2867 * This should happen rarely enough that I don't care
2868 * about efficiency here :-)
2870 size_t to_write;
2872 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2873 if (write_data(smbd_server_fd(), buf, to_write) != to_write) {
2874 exit_server_cleanly("sendfile_short_send: "
2875 "write_data failed");
2877 nread += to_write;
2879 SAFE_FREE(buf);
2882 #endif /* defined WITH_SENDFILE */
2884 /****************************************************************************
2885 Return a readbraw error (4 bytes of zero).
2886 ****************************************************************************/
2888 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2890 char header[4];
2892 SIVAL(header,0,0);
2894 smbd_lock_socket(sconn);
2895 if (write_data(smbd_server_fd(),header,4) != 4) {
2896 fail_readraw();
2898 smbd_unlock_socket(sconn);
2901 /****************************************************************************
2902 Use sendfile in readbraw.
2903 ****************************************************************************/
2905 static void send_file_readbraw(connection_struct *conn,
2906 struct smb_request *req,
2907 files_struct *fsp,
2908 SMB_OFF_T startpos,
2909 size_t nread,
2910 ssize_t mincount)
2912 struct smbd_server_connection *sconn = req->sconn;
2913 char *outbuf = NULL;
2914 ssize_t ret=0;
2916 #if defined(WITH_SENDFILE)
2918 * We can only use sendfile on a non-chained packet
2919 * but we can use on a non-oplocked file. tridge proved this
2920 * on a train in Germany :-). JRA.
2921 * reply_readbraw has already checked the length.
2924 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
2925 (fsp->wcp == NULL) &&
2926 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
2927 ssize_t sendfile_read = -1;
2928 char header[4];
2929 DATA_BLOB header_blob;
2931 _smb_setlen(header,nread);
2932 header_blob = data_blob_const(header, 4);
2934 if ((sendfile_read = SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
2935 &header_blob, startpos, nread)) == -1) {
2936 /* Returning ENOSYS means no data at all was sent.
2937 * Do this as a normal read. */
2938 if (errno == ENOSYS) {
2939 goto normal_readbraw;
2943 * Special hack for broken Linux with no working sendfile. If we
2944 * return EINTR we sent the header but not the rest of the data.
2945 * Fake this up by doing read/write calls.
2947 if (errno == EINTR) {
2948 /* Ensure we don't do this again. */
2949 set_use_sendfile(SNUM(conn), False);
2950 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2952 if (fake_sendfile(fsp, startpos, nread) == -1) {
2953 DEBUG(0,("send_file_readbraw: "
2954 "fake_sendfile failed for "
2955 "file %s (%s).\n",
2956 fsp_str_dbg(fsp),
2957 strerror(errno)));
2958 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2960 return;
2963 DEBUG(0,("send_file_readbraw: sendfile failed for "
2964 "file %s (%s). Terminating\n",
2965 fsp_str_dbg(fsp), strerror(errno)));
2966 exit_server_cleanly("send_file_readbraw sendfile failed");
2967 } else if (sendfile_read == 0) {
2969 * Some sendfile implementations return 0 to indicate
2970 * that there was a short read, but nothing was
2971 * actually written to the socket. In this case,
2972 * fallback to the normal read path so the header gets
2973 * the correct byte count.
2975 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
2976 "bytes falling back to the normal read: "
2977 "%s\n", fsp_str_dbg(fsp)));
2978 goto normal_readbraw;
2981 /* Deal with possible short send. */
2982 if (sendfile_read != 4+nread) {
2983 sendfile_short_send(fsp, sendfile_read, 4, nread);
2985 return;
2988 normal_readbraw:
2989 #endif
2991 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
2992 if (!outbuf) {
2993 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
2994 (unsigned)(nread+4)));
2995 reply_readbraw_error(sconn);
2996 return;
2999 if (nread > 0) {
3000 ret = read_file(fsp,outbuf+4,startpos,nread);
3001 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3002 if (ret < mincount)
3003 ret = 0;
3004 #else
3005 if (ret < nread)
3006 ret = 0;
3007 #endif
3010 _smb_setlen(outbuf,ret);
3011 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
3012 fail_readraw();
3014 TALLOC_FREE(outbuf);
3017 /****************************************************************************
3018 Reply to a readbraw (core+ protocol).
3019 ****************************************************************************/
3021 void reply_readbraw(struct smb_request *req)
3023 connection_struct *conn = req->conn;
3024 struct smbd_server_connection *sconn = req->sconn;
3025 ssize_t maxcount,mincount;
3026 size_t nread = 0;
3027 SMB_OFF_T startpos;
3028 files_struct *fsp;
3029 struct lock_struct lock;
3030 SMB_OFF_T size = 0;
3032 START_PROFILE(SMBreadbraw);
3034 if (srv_is_signing_active(sconn) ||
3035 is_encrypted_packet(req->inbuf)) {
3036 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3037 "raw reads/writes are disallowed.");
3040 if (req->wct < 8) {
3041 reply_readbraw_error(sconn);
3042 END_PROFILE(SMBreadbraw);
3043 return;
3046 if (sconn->smb1.echo_handler.trusted_fde) {
3047 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3048 "'async smb echo handler = yes'\n"));
3049 reply_readbraw_error(sconn);
3050 END_PROFILE(SMBreadbraw);
3051 return;
3055 * Special check if an oplock break has been issued
3056 * and the readraw request croses on the wire, we must
3057 * return a zero length response here.
3060 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3063 * We have to do a check_fsp by hand here, as
3064 * we must always return 4 zero bytes on error,
3065 * not a NTSTATUS.
3068 if (!fsp || !conn || conn != fsp->conn ||
3069 req->vuid != fsp->vuid ||
3070 fsp->is_directory || fsp->fh->fd == -1) {
3072 * fsp could be NULL here so use the value from the packet. JRA.
3074 DEBUG(3,("reply_readbraw: fnum %d not valid "
3075 "- cache prime?\n",
3076 (int)SVAL(req->vwv+0, 0)));
3077 reply_readbraw_error(sconn);
3078 END_PROFILE(SMBreadbraw);
3079 return;
3082 /* Do a "by hand" version of CHECK_READ. */
3083 if (!(fsp->can_read ||
3084 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3085 (fsp->access_mask & FILE_EXECUTE)))) {
3086 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3087 (int)SVAL(req->vwv+0, 0)));
3088 reply_readbraw_error(sconn);
3089 END_PROFILE(SMBreadbraw);
3090 return;
3093 flush_write_cache(fsp, READRAW_FLUSH);
3095 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3096 if(req->wct == 10) {
3098 * This is a large offset (64 bit) read.
3100 #ifdef LARGE_SMB_OFF_T
3102 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3104 #else /* !LARGE_SMB_OFF_T */
3107 * Ensure we haven't been sent a >32 bit offset.
3110 if(IVAL(req->vwv+8, 0) != 0) {
3111 DEBUG(0,("reply_readbraw: large offset "
3112 "(%x << 32) used and we don't support "
3113 "64 bit offsets.\n",
3114 (unsigned int)IVAL(req->vwv+8, 0) ));
3115 reply_readbraw_error();
3116 END_PROFILE(SMBreadbraw);
3117 return;
3120 #endif /* LARGE_SMB_OFF_T */
3122 if(startpos < 0) {
3123 DEBUG(0,("reply_readbraw: negative 64 bit "
3124 "readraw offset (%.0f) !\n",
3125 (double)startpos ));
3126 reply_readbraw_error(sconn);
3127 END_PROFILE(SMBreadbraw);
3128 return;
3132 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3133 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3135 /* ensure we don't overrun the packet size */
3136 maxcount = MIN(65535,maxcount);
3138 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3139 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3140 &lock);
3142 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3143 reply_readbraw_error(sconn);
3144 END_PROFILE(SMBreadbraw);
3145 return;
3148 if (fsp_stat(fsp) == 0) {
3149 size = fsp->fsp_name->st.st_ex_size;
3152 if (startpos >= size) {
3153 nread = 0;
3154 } else {
3155 nread = MIN(maxcount,(size - startpos));
3158 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3159 if (nread < mincount)
3160 nread = 0;
3161 #endif
3163 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3164 "min=%lu nread=%lu\n",
3165 fsp->fnum, (double)startpos,
3166 (unsigned long)maxcount,
3167 (unsigned long)mincount,
3168 (unsigned long)nread ) );
3170 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3172 DEBUG(5,("reply_readbraw finished\n"));
3174 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3176 END_PROFILE(SMBreadbraw);
3177 return;
3180 #undef DBGC_CLASS
3181 #define DBGC_CLASS DBGC_LOCKING
3183 /****************************************************************************
3184 Reply to a lockread (core+ protocol).
3185 ****************************************************************************/
3187 void reply_lockread(struct smb_request *req)
3189 connection_struct *conn = req->conn;
3190 ssize_t nread = -1;
3191 char *data;
3192 SMB_OFF_T startpos;
3193 size_t numtoread;
3194 NTSTATUS status;
3195 files_struct *fsp;
3196 struct byte_range_lock *br_lck = NULL;
3197 char *p = NULL;
3198 struct smbd_server_connection *sconn = req->sconn;
3200 START_PROFILE(SMBlockread);
3202 if (req->wct < 5) {
3203 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3204 END_PROFILE(SMBlockread);
3205 return;
3208 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3210 if (!check_fsp(conn, req, fsp)) {
3211 END_PROFILE(SMBlockread);
3212 return;
3215 if (!CHECK_READ(fsp,req)) {
3216 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3217 END_PROFILE(SMBlockread);
3218 return;
3221 numtoread = SVAL(req->vwv+1, 0);
3222 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3224 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3226 reply_outbuf(req, 5, numtoread + 3);
3228 data = smb_buf(req->outbuf) + 3;
3231 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3232 * protocol request that predates the read/write lock concept.
3233 * Thus instead of asking for a read lock here we need to ask
3234 * for a write lock. JRA.
3235 * Note that the requested lock size is unaffected by max_recv.
3238 br_lck = do_lock(req->sconn->msg_ctx,
3239 fsp,
3240 (uint64_t)req->smbpid,
3241 (uint64_t)numtoread,
3242 (uint64_t)startpos,
3243 WRITE_LOCK,
3244 WINDOWS_LOCK,
3245 False, /* Non-blocking lock. */
3246 &status,
3247 NULL,
3248 NULL);
3249 TALLOC_FREE(br_lck);
3251 if (NT_STATUS_V(status)) {
3252 reply_nterror(req, status);
3253 END_PROFILE(SMBlockread);
3254 return;
3258 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3261 if (numtoread > sconn->smb1.negprot.max_recv) {
3262 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3263 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3264 (unsigned int)numtoread,
3265 (unsigned int)sconn->smb1.negprot.max_recv));
3266 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3268 nread = read_file(fsp,data,startpos,numtoread);
3270 if (nread < 0) {
3271 reply_nterror(req, map_nt_error_from_unix(errno));
3272 END_PROFILE(SMBlockread);
3273 return;
3276 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3278 SSVAL(req->outbuf,smb_vwv0,nread);
3279 SSVAL(req->outbuf,smb_vwv5,nread+3);
3280 p = smb_buf(req->outbuf);
3281 SCVAL(p,0,0); /* pad byte. */
3282 SSVAL(p,1,nread);
3284 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3285 fsp->fnum, (int)numtoread, (int)nread));
3287 END_PROFILE(SMBlockread);
3288 return;
3291 #undef DBGC_CLASS
3292 #define DBGC_CLASS DBGC_ALL
3294 /****************************************************************************
3295 Reply to a read.
3296 ****************************************************************************/
3298 void reply_read(struct smb_request *req)
3300 connection_struct *conn = req->conn;
3301 size_t numtoread;
3302 ssize_t nread = 0;
3303 char *data;
3304 SMB_OFF_T startpos;
3305 int outsize = 0;
3306 files_struct *fsp;
3307 struct lock_struct lock;
3308 struct smbd_server_connection *sconn = req->sconn;
3310 START_PROFILE(SMBread);
3312 if (req->wct < 3) {
3313 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3314 END_PROFILE(SMBread);
3315 return;
3318 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3320 if (!check_fsp(conn, req, fsp)) {
3321 END_PROFILE(SMBread);
3322 return;
3325 if (!CHECK_READ(fsp,req)) {
3326 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3327 END_PROFILE(SMBread);
3328 return;
3331 numtoread = SVAL(req->vwv+1, 0);
3332 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3334 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3337 * The requested read size cannot be greater than max_recv. JRA.
3339 if (numtoread > sconn->smb1.negprot.max_recv) {
3340 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3341 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3342 (unsigned int)numtoread,
3343 (unsigned int)sconn->smb1.negprot.max_recv));
3344 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3347 reply_outbuf(req, 5, numtoread+3);
3349 data = smb_buf(req->outbuf) + 3;
3351 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3352 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3353 &lock);
3355 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3356 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3357 END_PROFILE(SMBread);
3358 return;
3361 if (numtoread > 0)
3362 nread = read_file(fsp,data,startpos,numtoread);
3364 if (nread < 0) {
3365 reply_nterror(req, map_nt_error_from_unix(errno));
3366 goto strict_unlock;
3369 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3371 SSVAL(req->outbuf,smb_vwv0,nread);
3372 SSVAL(req->outbuf,smb_vwv5,nread+3);
3373 SCVAL(smb_buf(req->outbuf),0,1);
3374 SSVAL(smb_buf(req->outbuf),1,nread);
3376 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3377 fsp->fnum, (int)numtoread, (int)nread ) );
3379 strict_unlock:
3380 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3382 END_PROFILE(SMBread);
3383 return;
3386 /****************************************************************************
3387 Setup readX header.
3388 ****************************************************************************/
3390 static int setup_readX_header(struct smb_request *req, char *outbuf,
3391 size_t smb_maxcnt)
3393 int outsize;
3394 char *data;
3396 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3397 data = smb_buf(outbuf);
3399 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3401 SCVAL(outbuf,smb_vwv0,0xFF);
3402 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3403 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3404 SSVAL(outbuf,smb_vwv6,
3405 req_wct_ofs(req)
3406 + 1 /* the wct field */
3407 + 12 * sizeof(uint16_t) /* vwv */
3408 + 2); /* the buflen field */
3409 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3410 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3411 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3412 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3413 return outsize;
3416 /****************************************************************************
3417 Reply to a read and X - possibly using sendfile.
3418 ****************************************************************************/
3420 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3421 files_struct *fsp, SMB_OFF_T startpos,
3422 size_t smb_maxcnt)
3424 ssize_t nread = -1;
3425 struct lock_struct lock;
3426 int saved_errno = 0;
3428 if(fsp_stat(fsp) == -1) {
3429 reply_nterror(req, map_nt_error_from_unix(errno));
3430 return;
3433 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3434 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3435 &lock);
3437 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3438 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3439 return;
3442 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3443 (startpos > fsp->fsp_name->st.st_ex_size)
3444 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3446 * We already know that we would do a short read, so don't
3447 * try the sendfile() path.
3449 goto nosendfile_read;
3452 #if defined(WITH_SENDFILE)
3454 * We can only use sendfile on a non-chained packet
3455 * but we can use on a non-oplocked file. tridge proved this
3456 * on a train in Germany :-). JRA.
3459 if (!req_is_in_chain(req) &&
3460 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3461 (fsp->wcp == NULL) &&
3462 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3463 uint8 headerbuf[smb_size + 12 * 2];
3464 DATA_BLOB header;
3467 * Set up the packet header before send. We
3468 * assume here the sendfile will work (get the
3469 * correct amount of data).
3472 header = data_blob_const(headerbuf, sizeof(headerbuf));
3474 construct_reply_common_req(req, (char *)headerbuf);
3475 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3477 if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
3478 /* Returning ENOSYS means no data at all was sent.
3479 Do this as a normal read. */
3480 if (errno == ENOSYS) {
3481 goto normal_read;
3485 * Special hack for broken Linux with no working sendfile. If we
3486 * return EINTR we sent the header but not the rest of the data.
3487 * Fake this up by doing read/write calls.
3490 if (errno == EINTR) {
3491 /* Ensure we don't do this again. */
3492 set_use_sendfile(SNUM(conn), False);
3493 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3494 nread = fake_sendfile(fsp, startpos,
3495 smb_maxcnt);
3496 if (nread == -1) {
3497 DEBUG(0,("send_file_readX: "
3498 "fake_sendfile failed for "
3499 "file %s (%s).\n",
3500 fsp_str_dbg(fsp),
3501 strerror(errno)));
3502 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3504 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3505 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3506 /* No outbuf here means successful sendfile. */
3507 goto strict_unlock;
3510 DEBUG(0,("send_file_readX: sendfile failed for file "
3511 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3512 strerror(errno)));
3513 exit_server_cleanly("send_file_readX sendfile failed");
3514 } else if (nread == 0) {
3516 * Some sendfile implementations return 0 to indicate
3517 * that there was a short read, but nothing was
3518 * actually written to the socket. In this case,
3519 * fallback to the normal read path so the header gets
3520 * the correct byte count.
3522 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3523 "falling back to the normal read: %s\n",
3524 fsp_str_dbg(fsp)));
3525 goto normal_read;
3528 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3529 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3531 /* Deal with possible short send. */
3532 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3533 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3535 /* No outbuf here means successful sendfile. */
3536 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3537 SMB_PERFCOUNT_END(&req->pcd);
3538 goto strict_unlock;
3541 normal_read:
3543 #endif
3545 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3546 uint8 headerbuf[smb_size + 2*12];
3548 construct_reply_common_req(req, (char *)headerbuf);
3549 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3551 /* Send out the header. */
3552 if (write_data(smbd_server_fd(), (char *)headerbuf,
3553 sizeof(headerbuf)) != sizeof(headerbuf)) {
3554 DEBUG(0,("send_file_readX: write_data failed for file "
3555 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3556 strerror(errno)));
3557 exit_server_cleanly("send_file_readX sendfile failed");
3559 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3560 if (nread == -1) {
3561 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3562 "file %s (%s).\n", fsp_str_dbg(fsp),
3563 strerror(errno)));
3564 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3566 goto strict_unlock;
3569 nosendfile_read:
3571 reply_outbuf(req, 12, smb_maxcnt);
3573 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3574 saved_errno = errno;
3576 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3578 if (nread < 0) {
3579 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3580 return;
3583 setup_readX_header(req, (char *)req->outbuf, nread);
3585 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3586 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3588 chain_reply(req);
3589 return;
3591 strict_unlock:
3592 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3593 TALLOC_FREE(req->outbuf);
3594 return;
3597 /****************************************************************************
3598 Reply to a read and X.
3599 ****************************************************************************/
3601 void reply_read_and_X(struct smb_request *req)
3603 connection_struct *conn = req->conn;
3604 files_struct *fsp;
3605 SMB_OFF_T startpos;
3606 size_t smb_maxcnt;
3607 bool big_readX = False;
3608 #if 0
3609 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3610 #endif
3612 START_PROFILE(SMBreadX);
3614 if ((req->wct != 10) && (req->wct != 12)) {
3615 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3616 return;
3619 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3620 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3621 smb_maxcnt = SVAL(req->vwv+5, 0);
3623 /* If it's an IPC, pass off the pipe handler. */
3624 if (IS_IPC(conn)) {
3625 reply_pipe_read_and_X(req);
3626 END_PROFILE(SMBreadX);
3627 return;
3630 if (!check_fsp(conn, req, fsp)) {
3631 END_PROFILE(SMBreadX);
3632 return;
3635 if (!CHECK_READ(fsp,req)) {
3636 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3637 END_PROFILE(SMBreadX);
3638 return;
3641 if (global_client_caps & CAP_LARGE_READX) {
3642 size_t upper_size = SVAL(req->vwv+7, 0);
3643 smb_maxcnt |= (upper_size<<16);
3644 if (upper_size > 1) {
3645 /* Can't do this on a chained packet. */
3646 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3647 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3648 END_PROFILE(SMBreadX);
3649 return;
3651 /* We currently don't do this on signed or sealed data. */
3652 if (srv_is_signing_active(req->sconn) ||
3653 is_encrypted_packet(req->inbuf)) {
3654 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3655 END_PROFILE(SMBreadX);
3656 return;
3658 /* Is there room in the reply for this data ? */
3659 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3660 reply_nterror(req,
3661 NT_STATUS_INVALID_PARAMETER);
3662 END_PROFILE(SMBreadX);
3663 return;
3665 big_readX = True;
3669 if (req->wct == 12) {
3670 #ifdef LARGE_SMB_OFF_T
3672 * This is a large offset (64 bit) read.
3674 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3676 #else /* !LARGE_SMB_OFF_T */
3679 * Ensure we haven't been sent a >32 bit offset.
3682 if(IVAL(req->vwv+10, 0) != 0) {
3683 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3684 "used and we don't support 64 bit offsets.\n",
3685 (unsigned int)IVAL(req->vwv+10, 0) ));
3686 END_PROFILE(SMBreadX);
3687 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3688 return;
3691 #endif /* LARGE_SMB_OFF_T */
3695 if (!big_readX) {
3696 NTSTATUS status = schedule_aio_read_and_X(conn,
3697 req,
3698 fsp,
3699 startpos,
3700 smb_maxcnt);
3701 if (NT_STATUS_IS_OK(status)) {
3702 /* Read scheduled - we're done. */
3703 goto out;
3705 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3706 /* Real error - report to client. */
3707 END_PROFILE(SMBreadX);
3708 reply_nterror(req, status);
3709 return;
3711 /* NT_STATUS_RETRY - fall back to sync read. */
3714 smbd_lock_socket(req->sconn);
3715 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3716 smbd_unlock_socket(req->sconn);
3718 out:
3719 END_PROFILE(SMBreadX);
3720 return;
3723 /****************************************************************************
3724 Error replies to writebraw must have smb_wct == 1. Fix this up.
3725 ****************************************************************************/
3727 void error_to_writebrawerr(struct smb_request *req)
3729 uint8 *old_outbuf = req->outbuf;
3731 reply_outbuf(req, 1, 0);
3733 memcpy(req->outbuf, old_outbuf, smb_size);
3734 TALLOC_FREE(old_outbuf);
3737 /****************************************************************************
3738 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3739 ****************************************************************************/
3741 void reply_writebraw(struct smb_request *req)
3743 connection_struct *conn = req->conn;
3744 char *buf = NULL;
3745 ssize_t nwritten=0;
3746 ssize_t total_written=0;
3747 size_t numtowrite=0;
3748 size_t tcount;
3749 SMB_OFF_T startpos;
3750 char *data=NULL;
3751 bool write_through;
3752 files_struct *fsp;
3753 struct lock_struct lock;
3754 NTSTATUS status;
3756 START_PROFILE(SMBwritebraw);
3759 * If we ever reply with an error, it must have the SMB command
3760 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3761 * we're finished.
3763 SCVAL(req->inbuf,smb_com,SMBwritec);
3765 if (srv_is_signing_active(req->sconn)) {
3766 END_PROFILE(SMBwritebraw);
3767 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3768 "raw reads/writes are disallowed.");
3771 if (req->wct < 12) {
3772 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3773 error_to_writebrawerr(req);
3774 END_PROFILE(SMBwritebraw);
3775 return;
3778 if (req->sconn->smb1.echo_handler.trusted_fde) {
3779 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3780 "'async smb echo handler = yes'\n"));
3781 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3782 error_to_writebrawerr(req);
3783 END_PROFILE(SMBwritebraw);
3784 return;
3787 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3788 if (!check_fsp(conn, req, fsp)) {
3789 error_to_writebrawerr(req);
3790 END_PROFILE(SMBwritebraw);
3791 return;
3794 if (!CHECK_WRITE(fsp)) {
3795 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3796 error_to_writebrawerr(req);
3797 END_PROFILE(SMBwritebraw);
3798 return;
3801 tcount = IVAL(req->vwv+1, 0);
3802 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3803 write_through = BITSETW(req->vwv+7,0);
3805 /* We have to deal with slightly different formats depending
3806 on whether we are using the core+ or lanman1.0 protocol */
3808 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3809 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3810 data = smb_buf(req->inbuf);
3811 } else {
3812 numtowrite = SVAL(req->vwv+10, 0);
3813 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3816 /* Ensure we don't write bytes past the end of this packet. */
3817 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3818 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3819 error_to_writebrawerr(req);
3820 END_PROFILE(SMBwritebraw);
3821 return;
3824 if (!fsp->print_file) {
3825 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3826 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3827 &lock);
3829 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3830 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3831 error_to_writebrawerr(req);
3832 END_PROFILE(SMBwritebraw);
3833 return;
3837 if (numtowrite>0) {
3838 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3841 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3842 "wrote=%d sync=%d\n",
3843 fsp->fnum, (double)startpos, (int)numtowrite,
3844 (int)nwritten, (int)write_through));
3846 if (nwritten < (ssize_t)numtowrite) {
3847 reply_nterror(req, NT_STATUS_DISK_FULL);
3848 error_to_writebrawerr(req);
3849 goto strict_unlock;
3852 total_written = nwritten;
3854 /* Allocate a buffer of 64k + length. */
3855 buf = TALLOC_ARRAY(NULL, char, 65540);
3856 if (!buf) {
3857 reply_nterror(req, NT_STATUS_NO_MEMORY);
3858 error_to_writebrawerr(req);
3859 goto strict_unlock;
3862 /* Return a SMBwritebraw message to the redirector to tell
3863 * it to send more bytes */
3865 memcpy(buf, req->inbuf, smb_size);
3866 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
3867 SCVAL(buf,smb_com,SMBwritebraw);
3868 SSVALS(buf,smb_vwv0,0xFFFF);
3869 show_msg(buf);
3870 if (!srv_send_smb(smbd_server_fd(),
3871 buf,
3872 false, 0, /* no signing */
3873 IS_CONN_ENCRYPTED(conn),
3874 &req->pcd)) {
3875 exit_server_cleanly("reply_writebraw: srv_send_smb "
3876 "failed.");
3879 /* Now read the raw data into the buffer and write it */
3880 status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
3881 &numtowrite);
3882 if (!NT_STATUS_IS_OK(status)) {
3883 exit_server_cleanly("secondary writebraw failed");
3886 /* Set up outbuf to return the correct size */
3887 reply_outbuf(req, 1, 0);
3889 if (numtowrite != 0) {
3891 if (numtowrite > 0xFFFF) {
3892 DEBUG(0,("reply_writebraw: Oversize secondary write "
3893 "raw requested (%u). Terminating\n",
3894 (unsigned int)numtowrite ));
3895 exit_server_cleanly("secondary writebraw failed");
3898 if (tcount > nwritten+numtowrite) {
3899 DEBUG(3,("reply_writebraw: Client overestimated the "
3900 "write %d %d %d\n",
3901 (int)tcount,(int)nwritten,(int)numtowrite));
3904 status = read_data(smbd_server_fd(), buf+4, numtowrite);
3906 if (!NT_STATUS_IS_OK(status)) {
3907 DEBUG(0,("reply_writebraw: Oversize secondary write "
3908 "raw read failed (%s). Terminating\n",
3909 nt_errstr(status)));
3910 exit_server_cleanly("secondary writebraw failed");
3913 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
3914 if (nwritten == -1) {
3915 TALLOC_FREE(buf);
3916 reply_nterror(req, map_nt_error_from_unix(errno));
3917 error_to_writebrawerr(req);
3918 goto strict_unlock;
3921 if (nwritten < (ssize_t)numtowrite) {
3922 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3923 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3926 if (nwritten > 0) {
3927 total_written += nwritten;
3931 TALLOC_FREE(buf);
3932 SSVAL(req->outbuf,smb_vwv0,total_written);
3934 status = sync_file(conn, fsp, write_through);
3935 if (!NT_STATUS_IS_OK(status)) {
3936 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
3937 fsp_str_dbg(fsp), nt_errstr(status)));
3938 reply_nterror(req, status);
3939 error_to_writebrawerr(req);
3940 goto strict_unlock;
3943 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
3944 "wrote=%d\n",
3945 fsp->fnum, (double)startpos, (int)numtowrite,
3946 (int)total_written));
3948 if (!fsp->print_file) {
3949 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3952 /* We won't return a status if write through is not selected - this
3953 * follows what WfWg does */
3954 END_PROFILE(SMBwritebraw);
3956 if (!write_through && total_written==tcount) {
3958 #if RABBIT_PELLET_FIX
3960 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
3961 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
3962 * JRA.
3964 if (!send_keepalive(smbd_server_fd())) {
3965 exit_server_cleanly("reply_writebraw: send of "
3966 "keepalive failed");
3968 #endif
3969 TALLOC_FREE(req->outbuf);
3971 return;
3973 strict_unlock:
3974 if (!fsp->print_file) {
3975 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3978 END_PROFILE(SMBwritebraw);
3979 return;
3982 #undef DBGC_CLASS
3983 #define DBGC_CLASS DBGC_LOCKING
3985 /****************************************************************************
3986 Reply to a writeunlock (core+).
3987 ****************************************************************************/
3989 void reply_writeunlock(struct smb_request *req)
3991 connection_struct *conn = req->conn;
3992 ssize_t nwritten = -1;
3993 size_t numtowrite;
3994 SMB_OFF_T startpos;
3995 const char *data;
3996 NTSTATUS status = NT_STATUS_OK;
3997 files_struct *fsp;
3998 struct lock_struct lock;
3999 int saved_errno = 0;
4001 START_PROFILE(SMBwriteunlock);
4003 if (req->wct < 5) {
4004 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4005 END_PROFILE(SMBwriteunlock);
4006 return;
4009 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4011 if (!check_fsp(conn, req, fsp)) {
4012 END_PROFILE(SMBwriteunlock);
4013 return;
4016 if (!CHECK_WRITE(fsp)) {
4017 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4018 END_PROFILE(SMBwriteunlock);
4019 return;
4022 numtowrite = SVAL(req->vwv+1, 0);
4023 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4024 data = (const char *)req->buf + 3;
4026 if (!fsp->print_file && numtowrite > 0) {
4027 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4028 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4029 &lock);
4031 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4032 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4033 END_PROFILE(SMBwriteunlock);
4034 return;
4038 /* The special X/Open SMB protocol handling of
4039 zero length writes is *NOT* done for
4040 this call */
4041 if(numtowrite == 0) {
4042 nwritten = 0;
4043 } else {
4044 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4045 saved_errno = errno;
4048 status = sync_file(conn, fsp, False /* write through */);
4049 if (!NT_STATUS_IS_OK(status)) {
4050 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4051 fsp_str_dbg(fsp), nt_errstr(status)));
4052 reply_nterror(req, status);
4053 goto strict_unlock;
4056 if(nwritten < 0) {
4057 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4058 goto strict_unlock;
4061 if((nwritten < numtowrite) && (numtowrite != 0)) {
4062 reply_nterror(req, NT_STATUS_DISK_FULL);
4063 goto strict_unlock;
4066 if (numtowrite && !fsp->print_file) {
4067 status = do_unlock(req->sconn->msg_ctx,
4068 fsp,
4069 (uint64_t)req->smbpid,
4070 (uint64_t)numtowrite,
4071 (uint64_t)startpos,
4072 WINDOWS_LOCK);
4074 if (NT_STATUS_V(status)) {
4075 reply_nterror(req, status);
4076 goto strict_unlock;
4080 reply_outbuf(req, 1, 0);
4082 SSVAL(req->outbuf,smb_vwv0,nwritten);
4084 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4085 fsp->fnum, (int)numtowrite, (int)nwritten));
4087 strict_unlock:
4088 if (numtowrite && !fsp->print_file) {
4089 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4092 END_PROFILE(SMBwriteunlock);
4093 return;
4096 #undef DBGC_CLASS
4097 #define DBGC_CLASS DBGC_ALL
4099 /****************************************************************************
4100 Reply to a write.
4101 ****************************************************************************/
4103 void reply_write(struct smb_request *req)
4105 connection_struct *conn = req->conn;
4106 size_t numtowrite;
4107 ssize_t nwritten = -1;
4108 SMB_OFF_T startpos;
4109 const char *data;
4110 files_struct *fsp;
4111 struct lock_struct lock;
4112 NTSTATUS status;
4113 int saved_errno = 0;
4115 START_PROFILE(SMBwrite);
4117 if (req->wct < 5) {
4118 END_PROFILE(SMBwrite);
4119 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4120 return;
4123 /* If it's an IPC, pass off the pipe handler. */
4124 if (IS_IPC(conn)) {
4125 reply_pipe_write(req);
4126 END_PROFILE(SMBwrite);
4127 return;
4130 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4132 if (!check_fsp(conn, req, fsp)) {
4133 END_PROFILE(SMBwrite);
4134 return;
4137 if (!CHECK_WRITE(fsp)) {
4138 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4139 END_PROFILE(SMBwrite);
4140 return;
4143 numtowrite = SVAL(req->vwv+1, 0);
4144 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4145 data = (const char *)req->buf + 3;
4147 if (!fsp->print_file) {
4148 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4149 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4150 &lock);
4152 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4153 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4154 END_PROFILE(SMBwrite);
4155 return;
4160 * X/Open SMB protocol says that if smb_vwv1 is
4161 * zero then the file size should be extended or
4162 * truncated to the size given in smb_vwv[2-3].
4165 if(numtowrite == 0) {
4167 * This is actually an allocate call, and set EOF. JRA.
4169 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4170 if (nwritten < 0) {
4171 reply_nterror(req, NT_STATUS_DISK_FULL);
4172 goto strict_unlock;
4174 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4175 if (nwritten < 0) {
4176 reply_nterror(req, NT_STATUS_DISK_FULL);
4177 goto strict_unlock;
4179 trigger_write_time_update_immediate(fsp);
4180 } else {
4181 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4184 status = sync_file(conn, fsp, False);
4185 if (!NT_STATUS_IS_OK(status)) {
4186 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4187 fsp_str_dbg(fsp), nt_errstr(status)));
4188 reply_nterror(req, status);
4189 goto strict_unlock;
4192 if(nwritten < 0) {
4193 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4194 goto strict_unlock;
4197 if((nwritten == 0) && (numtowrite != 0)) {
4198 reply_nterror(req, NT_STATUS_DISK_FULL);
4199 goto strict_unlock;
4202 reply_outbuf(req, 1, 0);
4204 SSVAL(req->outbuf,smb_vwv0,nwritten);
4206 if (nwritten < (ssize_t)numtowrite) {
4207 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4208 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4211 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4213 strict_unlock:
4214 if (!fsp->print_file) {
4215 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4218 END_PROFILE(SMBwrite);
4219 return;
4222 /****************************************************************************
4223 Ensure a buffer is a valid writeX for recvfile purposes.
4224 ****************************************************************************/
4226 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4227 (2*14) + /* word count (including bcc) */ \
4228 1 /* pad byte */)
4230 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4231 const uint8_t *inbuf)
4233 size_t numtowrite;
4234 connection_struct *conn = NULL;
4235 unsigned int doff = 0;
4236 size_t len = smb_len_large(inbuf);
4238 if (is_encrypted_packet(inbuf)) {
4239 /* Can't do this on encrypted
4240 * connections. */
4241 return false;
4244 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4245 return false;
4248 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4249 CVAL(inbuf,smb_wct) != 14) {
4250 DEBUG(10,("is_valid_writeX_buffer: chained or "
4251 "invalid word length.\n"));
4252 return false;
4255 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4256 if (conn == NULL) {
4257 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4258 return false;
4260 if (IS_IPC(conn)) {
4261 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4262 return false;
4264 if (IS_PRINT(conn)) {
4265 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4266 return false;
4268 doff = SVAL(inbuf,smb_vwv11);
4270 numtowrite = SVAL(inbuf,smb_vwv10);
4272 if (len > doff && len - doff > 0xFFFF) {
4273 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4276 if (numtowrite == 0) {
4277 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4278 return false;
4281 /* Ensure the sizes match up. */
4282 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4283 /* no pad byte...old smbclient :-( */
4284 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4285 (unsigned int)doff,
4286 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4287 return false;
4290 if (len - doff != numtowrite) {
4291 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4292 "len = %u, doff = %u, numtowrite = %u\n",
4293 (unsigned int)len,
4294 (unsigned int)doff,
4295 (unsigned int)numtowrite ));
4296 return false;
4299 DEBUG(10,("is_valid_writeX_buffer: true "
4300 "len = %u, doff = %u, numtowrite = %u\n",
4301 (unsigned int)len,
4302 (unsigned int)doff,
4303 (unsigned int)numtowrite ));
4305 return true;
4308 /****************************************************************************
4309 Reply to a write and X.
4310 ****************************************************************************/
4312 void reply_write_and_X(struct smb_request *req)
4314 connection_struct *conn = req->conn;
4315 files_struct *fsp;
4316 struct lock_struct lock;
4317 SMB_OFF_T startpos;
4318 size_t numtowrite;
4319 bool write_through;
4320 ssize_t nwritten;
4321 unsigned int smb_doff;
4322 unsigned int smblen;
4323 char *data;
4324 NTSTATUS status;
4325 int saved_errno = 0;
4327 START_PROFILE(SMBwriteX);
4329 if ((req->wct != 12) && (req->wct != 14)) {
4330 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4331 END_PROFILE(SMBwriteX);
4332 return;
4335 numtowrite = SVAL(req->vwv+10, 0);
4336 smb_doff = SVAL(req->vwv+11, 0);
4337 smblen = smb_len(req->inbuf);
4339 if (req->unread_bytes > 0xFFFF ||
4340 (smblen > smb_doff &&
4341 smblen - smb_doff > 0xFFFF)) {
4342 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4345 if (req->unread_bytes) {
4346 /* Can't do a recvfile write on IPC$ */
4347 if (IS_IPC(conn)) {
4348 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4349 END_PROFILE(SMBwriteX);
4350 return;
4352 if (numtowrite != req->unread_bytes) {
4353 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4354 END_PROFILE(SMBwriteX);
4355 return;
4357 } else {
4358 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4359 smb_doff + numtowrite > smblen) {
4360 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4361 END_PROFILE(SMBwriteX);
4362 return;
4366 /* If it's an IPC, pass off the pipe handler. */
4367 if (IS_IPC(conn)) {
4368 if (req->unread_bytes) {
4369 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4370 END_PROFILE(SMBwriteX);
4371 return;
4373 reply_pipe_write_and_X(req);
4374 END_PROFILE(SMBwriteX);
4375 return;
4378 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4379 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4380 write_through = BITSETW(req->vwv+7,0);
4382 if (!check_fsp(conn, req, fsp)) {
4383 END_PROFILE(SMBwriteX);
4384 return;
4387 if (!CHECK_WRITE(fsp)) {
4388 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4389 END_PROFILE(SMBwriteX);
4390 return;
4393 data = smb_base(req->inbuf) + smb_doff;
4395 if(req->wct == 14) {
4396 #ifdef LARGE_SMB_OFF_T
4398 * This is a large offset (64 bit) write.
4400 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4402 #else /* !LARGE_SMB_OFF_T */
4405 * Ensure we haven't been sent a >32 bit offset.
4408 if(IVAL(req->vwv+12, 0) != 0) {
4409 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4410 "used and we don't support 64 bit offsets.\n",
4411 (unsigned int)IVAL(req->vwv+12, 0) ));
4412 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4413 END_PROFILE(SMBwriteX);
4414 return;
4417 #endif /* LARGE_SMB_OFF_T */
4420 /* X/Open SMB protocol says that, unlike SMBwrite
4421 if the length is zero then NO truncation is
4422 done, just a write of zero. To truncate a file,
4423 use SMBwrite. */
4425 if(numtowrite == 0) {
4426 nwritten = 0;
4427 } else {
4428 if (req->unread_bytes == 0) {
4429 status = schedule_aio_write_and_X(conn,
4430 req,
4431 fsp,
4432 data,
4433 startpos,
4434 numtowrite);
4436 if (NT_STATUS_IS_OK(status)) {
4437 /* write scheduled - we're done. */
4438 goto out;
4440 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4441 /* Real error - report to client. */
4442 reply_nterror(req, status);
4443 goto out;
4445 /* NT_STATUS_RETRY - fall through to sync write. */
4448 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4449 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4450 &lock);
4452 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4453 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4454 goto out;
4457 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4458 saved_errno = errno;
4460 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4463 if(nwritten < 0) {
4464 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4465 goto out;
4468 if((nwritten == 0) && (numtowrite != 0)) {
4469 reply_nterror(req, NT_STATUS_DISK_FULL);
4470 goto out;
4473 reply_outbuf(req, 6, 0);
4474 SSVAL(req->outbuf,smb_vwv2,nwritten);
4475 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4477 if (nwritten < (ssize_t)numtowrite) {
4478 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4479 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4482 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4483 fsp->fnum, (int)numtowrite, (int)nwritten));
4485 status = sync_file(conn, fsp, write_through);
4486 if (!NT_STATUS_IS_OK(status)) {
4487 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4488 fsp_str_dbg(fsp), nt_errstr(status)));
4489 reply_nterror(req, status);
4490 goto out;
4493 END_PROFILE(SMBwriteX);
4494 chain_reply(req);
4495 return;
4497 out:
4498 END_PROFILE(SMBwriteX);
4499 return;
4502 /****************************************************************************
4503 Reply to a lseek.
4504 ****************************************************************************/
4506 void reply_lseek(struct smb_request *req)
4508 connection_struct *conn = req->conn;
4509 SMB_OFF_T startpos;
4510 SMB_OFF_T res= -1;
4511 int mode,umode;
4512 files_struct *fsp;
4514 START_PROFILE(SMBlseek);
4516 if (req->wct < 4) {
4517 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4518 END_PROFILE(SMBlseek);
4519 return;
4522 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4524 if (!check_fsp(conn, req, fsp)) {
4525 return;
4528 flush_write_cache(fsp, SEEK_FLUSH);
4530 mode = SVAL(req->vwv+1, 0) & 3;
4531 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4532 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4534 switch (mode) {
4535 case 0:
4536 umode = SEEK_SET;
4537 res = startpos;
4538 break;
4539 case 1:
4540 umode = SEEK_CUR;
4541 res = fsp->fh->pos + startpos;
4542 break;
4543 case 2:
4544 umode = SEEK_END;
4545 break;
4546 default:
4547 umode = SEEK_SET;
4548 res = startpos;
4549 break;
4552 if (umode == SEEK_END) {
4553 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4554 if(errno == EINVAL) {
4555 SMB_OFF_T current_pos = startpos;
4557 if(fsp_stat(fsp) == -1) {
4558 reply_nterror(req,
4559 map_nt_error_from_unix(errno));
4560 END_PROFILE(SMBlseek);
4561 return;
4564 current_pos += fsp->fsp_name->st.st_ex_size;
4565 if(current_pos < 0)
4566 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4570 if(res == -1) {
4571 reply_nterror(req, map_nt_error_from_unix(errno));
4572 END_PROFILE(SMBlseek);
4573 return;
4577 fsp->fh->pos = res;
4579 reply_outbuf(req, 2, 0);
4580 SIVAL(req->outbuf,smb_vwv0,res);
4582 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4583 fsp->fnum, (double)startpos, (double)res, mode));
4585 END_PROFILE(SMBlseek);
4586 return;
4589 /****************************************************************************
4590 Reply to a flush.
4591 ****************************************************************************/
4593 void reply_flush(struct smb_request *req)
4595 connection_struct *conn = req->conn;
4596 uint16 fnum;
4597 files_struct *fsp;
4599 START_PROFILE(SMBflush);
4601 if (req->wct < 1) {
4602 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4603 return;
4606 fnum = SVAL(req->vwv+0, 0);
4607 fsp = file_fsp(req, fnum);
4609 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4610 return;
4613 if (!fsp) {
4614 file_sync_all(conn);
4615 } else {
4616 NTSTATUS status = sync_file(conn, fsp, True);
4617 if (!NT_STATUS_IS_OK(status)) {
4618 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4619 fsp_str_dbg(fsp), nt_errstr(status)));
4620 reply_nterror(req, status);
4621 END_PROFILE(SMBflush);
4622 return;
4626 reply_outbuf(req, 0, 0);
4628 DEBUG(3,("flush\n"));
4629 END_PROFILE(SMBflush);
4630 return;
4633 /****************************************************************************
4634 Reply to a exit.
4635 conn POINTER CAN BE NULL HERE !
4636 ****************************************************************************/
4638 void reply_exit(struct smb_request *req)
4640 START_PROFILE(SMBexit);
4642 file_close_pid(req->smbpid, req->vuid);
4644 reply_outbuf(req, 0, 0);
4646 DEBUG(3,("exit\n"));
4648 END_PROFILE(SMBexit);
4649 return;
4652 /****************************************************************************
4653 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4654 ****************************************************************************/
4656 void reply_close(struct smb_request *req)
4658 connection_struct *conn = req->conn;
4659 NTSTATUS status = NT_STATUS_OK;
4660 files_struct *fsp = NULL;
4661 START_PROFILE(SMBclose);
4663 if (req->wct < 3) {
4664 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4665 END_PROFILE(SMBclose);
4666 return;
4669 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4672 * We can only use check_fsp if we know it's not a directory.
4675 if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
4676 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4677 END_PROFILE(SMBclose);
4678 return;
4681 if(fsp->is_directory) {
4683 * Special case - close NT SMB directory handle.
4685 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4686 status = close_file(req, fsp, NORMAL_CLOSE);
4687 } else {
4688 time_t t;
4690 * Close ordinary file.
4693 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4694 fsp->fh->fd, fsp->fnum,
4695 conn->num_files_open));
4698 * Take care of any time sent in the close.
4701 t = srv_make_unix_date3(req->vwv+1);
4702 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4705 * close_file() returns the unix errno if an error
4706 * was detected on close - normally this is due to
4707 * a disk full error. If not then it was probably an I/O error.
4710 status = close_file(req, fsp, NORMAL_CLOSE);
4713 if (!NT_STATUS_IS_OK(status)) {
4714 reply_nterror(req, status);
4715 END_PROFILE(SMBclose);
4716 return;
4719 reply_outbuf(req, 0, 0);
4720 END_PROFILE(SMBclose);
4721 return;
4724 /****************************************************************************
4725 Reply to a writeclose (Core+ protocol).
4726 ****************************************************************************/
4728 void reply_writeclose(struct smb_request *req)
4730 connection_struct *conn = req->conn;
4731 size_t numtowrite;
4732 ssize_t nwritten = -1;
4733 NTSTATUS close_status = NT_STATUS_OK;
4734 SMB_OFF_T startpos;
4735 const char *data;
4736 struct timespec mtime;
4737 files_struct *fsp;
4738 struct lock_struct lock;
4740 START_PROFILE(SMBwriteclose);
4742 if (req->wct < 6) {
4743 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4744 END_PROFILE(SMBwriteclose);
4745 return;
4748 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4750 if (!check_fsp(conn, req, fsp)) {
4751 END_PROFILE(SMBwriteclose);
4752 return;
4754 if (!CHECK_WRITE(fsp)) {
4755 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4756 END_PROFILE(SMBwriteclose);
4757 return;
4760 numtowrite = SVAL(req->vwv+1, 0);
4761 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4762 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4763 data = (const char *)req->buf + 1;
4765 if (!fsp->print_file) {
4766 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4767 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4768 &lock);
4770 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4771 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4772 END_PROFILE(SMBwriteclose);
4773 return;
4777 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4779 set_close_write_time(fsp, mtime);
4782 * More insanity. W2K only closes the file if writelen > 0.
4783 * JRA.
4786 if (numtowrite) {
4787 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4788 "file %s\n", fsp_str_dbg(fsp)));
4789 close_status = close_file(req, fsp, NORMAL_CLOSE);
4792 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4793 fsp->fnum, (int)numtowrite, (int)nwritten,
4794 conn->num_files_open));
4796 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4797 reply_nterror(req, NT_STATUS_DISK_FULL);
4798 goto strict_unlock;
4801 if(!NT_STATUS_IS_OK(close_status)) {
4802 reply_nterror(req, close_status);
4803 goto strict_unlock;
4806 reply_outbuf(req, 1, 0);
4808 SSVAL(req->outbuf,smb_vwv0,nwritten);
4810 strict_unlock:
4811 if (numtowrite && !fsp->print_file) {
4812 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4815 END_PROFILE(SMBwriteclose);
4816 return;
4819 #undef DBGC_CLASS
4820 #define DBGC_CLASS DBGC_LOCKING
4822 /****************************************************************************
4823 Reply to a lock.
4824 ****************************************************************************/
4826 void reply_lock(struct smb_request *req)
4828 connection_struct *conn = req->conn;
4829 uint64_t count,offset;
4830 NTSTATUS status;
4831 files_struct *fsp;
4832 struct byte_range_lock *br_lck = NULL;
4834 START_PROFILE(SMBlock);
4836 if (req->wct < 5) {
4837 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4838 END_PROFILE(SMBlock);
4839 return;
4842 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4844 if (!check_fsp(conn, req, fsp)) {
4845 END_PROFILE(SMBlock);
4846 return;
4849 count = (uint64_t)IVAL(req->vwv+1, 0);
4850 offset = (uint64_t)IVAL(req->vwv+3, 0);
4852 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4853 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4855 br_lck = do_lock(req->sconn->msg_ctx,
4856 fsp,
4857 (uint64_t)req->smbpid,
4858 count,
4859 offset,
4860 WRITE_LOCK,
4861 WINDOWS_LOCK,
4862 False, /* Non-blocking lock. */
4863 &status,
4864 NULL,
4865 NULL);
4867 TALLOC_FREE(br_lck);
4869 if (NT_STATUS_V(status)) {
4870 reply_nterror(req, status);
4871 END_PROFILE(SMBlock);
4872 return;
4875 reply_outbuf(req, 0, 0);
4877 END_PROFILE(SMBlock);
4878 return;
4881 /****************************************************************************
4882 Reply to a unlock.
4883 ****************************************************************************/
4885 void reply_unlock(struct smb_request *req)
4887 connection_struct *conn = req->conn;
4888 uint64_t count,offset;
4889 NTSTATUS status;
4890 files_struct *fsp;
4892 START_PROFILE(SMBunlock);
4894 if (req->wct < 5) {
4895 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4896 END_PROFILE(SMBunlock);
4897 return;
4900 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4902 if (!check_fsp(conn, req, fsp)) {
4903 END_PROFILE(SMBunlock);
4904 return;
4907 count = (uint64_t)IVAL(req->vwv+1, 0);
4908 offset = (uint64_t)IVAL(req->vwv+3, 0);
4910 status = do_unlock(req->sconn->msg_ctx,
4911 fsp,
4912 (uint64_t)req->smbpid,
4913 count,
4914 offset,
4915 WINDOWS_LOCK);
4917 if (NT_STATUS_V(status)) {
4918 reply_nterror(req, status);
4919 END_PROFILE(SMBunlock);
4920 return;
4923 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4924 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
4926 reply_outbuf(req, 0, 0);
4928 END_PROFILE(SMBunlock);
4929 return;
4932 #undef DBGC_CLASS
4933 #define DBGC_CLASS DBGC_ALL
4935 /****************************************************************************
4936 Reply to a tdis.
4937 conn POINTER CAN BE NULL HERE !
4938 ****************************************************************************/
4940 void reply_tdis(struct smb_request *req)
4942 connection_struct *conn = req->conn;
4943 START_PROFILE(SMBtdis);
4945 if (!conn) {
4946 DEBUG(4,("Invalid connection in tdis\n"));
4947 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
4948 END_PROFILE(SMBtdis);
4949 return;
4952 conn->used = False;
4954 close_cnum(conn,req->vuid);
4955 req->conn = NULL;
4957 reply_outbuf(req, 0, 0);
4958 END_PROFILE(SMBtdis);
4959 return;
4962 /****************************************************************************
4963 Reply to a echo.
4964 conn POINTER CAN BE NULL HERE !
4965 ****************************************************************************/
4967 void reply_echo(struct smb_request *req)
4969 connection_struct *conn = req->conn;
4970 struct smb_perfcount_data local_pcd;
4971 struct smb_perfcount_data *cur_pcd;
4972 int smb_reverb;
4973 int seq_num;
4975 START_PROFILE(SMBecho);
4977 smb_init_perfcount_data(&local_pcd);
4979 if (req->wct < 1) {
4980 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4981 END_PROFILE(SMBecho);
4982 return;
4985 smb_reverb = SVAL(req->vwv+0, 0);
4987 reply_outbuf(req, 1, req->buflen);
4989 /* copy any incoming data back out */
4990 if (req->buflen > 0) {
4991 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
4994 if (smb_reverb > 100) {
4995 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
4996 smb_reverb = 100;
4999 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5001 /* this makes sure we catch the request pcd */
5002 if (seq_num == smb_reverb) {
5003 cur_pcd = &req->pcd;
5004 } else {
5005 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5006 cur_pcd = &local_pcd;
5009 SSVAL(req->outbuf,smb_vwv0,seq_num);
5011 show_msg((char *)req->outbuf);
5012 if (!srv_send_smb(smbd_server_fd(),
5013 (char *)req->outbuf,
5014 true, req->seqnum+1,
5015 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5016 cur_pcd))
5017 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5020 DEBUG(3,("echo %d times\n", smb_reverb));
5022 TALLOC_FREE(req->outbuf);
5024 END_PROFILE(SMBecho);
5025 return;
5028 /****************************************************************************
5029 Reply to a printopen.
5030 ****************************************************************************/
5032 void reply_printopen(struct smb_request *req)
5034 connection_struct *conn = req->conn;
5035 files_struct *fsp;
5036 NTSTATUS status;
5038 START_PROFILE(SMBsplopen);
5040 if (req->wct < 2) {
5041 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5042 END_PROFILE(SMBsplopen);
5043 return;
5046 if (!CAN_PRINT(conn)) {
5047 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5048 END_PROFILE(SMBsplopen);
5049 return;
5052 status = file_new(req, conn, &fsp);
5053 if(!NT_STATUS_IS_OK(status)) {
5054 reply_nterror(req, status);
5055 END_PROFILE(SMBsplopen);
5056 return;
5059 /* Open for exclusive use, write only. */
5060 status = print_spool_open(fsp, NULL, req->vuid);
5062 if (!NT_STATUS_IS_OK(status)) {
5063 file_free(req, fsp);
5064 reply_nterror(req, status);
5065 END_PROFILE(SMBsplopen);
5066 return;
5069 reply_outbuf(req, 1, 0);
5070 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5072 DEBUG(3,("openprint fd=%d fnum=%d\n",
5073 fsp->fh->fd, fsp->fnum));
5075 END_PROFILE(SMBsplopen);
5076 return;
5079 /****************************************************************************
5080 Reply to a printclose.
5081 ****************************************************************************/
5083 void reply_printclose(struct smb_request *req)
5085 connection_struct *conn = req->conn;
5086 files_struct *fsp;
5087 NTSTATUS status;
5089 START_PROFILE(SMBsplclose);
5091 if (req->wct < 1) {
5092 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5093 END_PROFILE(SMBsplclose);
5094 return;
5097 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5099 if (!check_fsp(conn, req, fsp)) {
5100 END_PROFILE(SMBsplclose);
5101 return;
5104 if (!CAN_PRINT(conn)) {
5105 reply_force_doserror(req, ERRSRV, ERRerror);
5106 END_PROFILE(SMBsplclose);
5107 return;
5110 DEBUG(3,("printclose fd=%d fnum=%d\n",
5111 fsp->fh->fd,fsp->fnum));
5113 status = close_file(req, fsp, NORMAL_CLOSE);
5115 if(!NT_STATUS_IS_OK(status)) {
5116 reply_nterror(req, status);
5117 END_PROFILE(SMBsplclose);
5118 return;
5121 reply_outbuf(req, 0, 0);
5123 END_PROFILE(SMBsplclose);
5124 return;
5127 /****************************************************************************
5128 Reply to a printqueue.
5129 ****************************************************************************/
5131 void reply_printqueue(struct smb_request *req)
5133 connection_struct *conn = req->conn;
5134 int max_count;
5135 int start_index;
5137 START_PROFILE(SMBsplretq);
5139 if (req->wct < 2) {
5140 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5141 END_PROFILE(SMBsplretq);
5142 return;
5145 max_count = SVAL(req->vwv+0, 0);
5146 start_index = SVAL(req->vwv+1, 0);
5148 /* we used to allow the client to get the cnum wrong, but that
5149 is really quite gross and only worked when there was only
5150 one printer - I think we should now only accept it if they
5151 get it right (tridge) */
5152 if (!CAN_PRINT(conn)) {
5153 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5154 END_PROFILE(SMBsplretq);
5155 return;
5158 reply_outbuf(req, 2, 3);
5159 SSVAL(req->outbuf,smb_vwv0,0);
5160 SSVAL(req->outbuf,smb_vwv1,0);
5161 SCVAL(smb_buf(req->outbuf),0,1);
5162 SSVAL(smb_buf(req->outbuf),1,0);
5164 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5165 start_index, max_count));
5168 TALLOC_CTX *mem_ctx = talloc_tos();
5169 NTSTATUS status;
5170 WERROR werr;
5171 const char *sharename = lp_servicename(SNUM(conn));
5172 struct rpc_pipe_client *cli = NULL;
5173 struct policy_handle handle;
5174 struct spoolss_DevmodeContainer devmode_ctr;
5175 union spoolss_JobInfo *info;
5176 uint32_t count;
5177 uint32_t num_to_get;
5178 uint32_t first;
5179 uint32_t i;
5181 ZERO_STRUCT(handle);
5183 status = rpc_connect_spoolss_pipe(conn, &cli);
5184 if (!NT_STATUS_IS_OK(status)) {
5185 DEBUG(0, ("reply_printqueue: "
5186 "could not connect to spoolss: %s\n",
5187 nt_errstr(status)));
5188 reply_nterror(req, status);
5189 goto out;
5192 ZERO_STRUCT(devmode_ctr);
5194 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
5195 sharename,
5196 NULL, devmode_ctr,
5197 SEC_FLAG_MAXIMUM_ALLOWED,
5198 &handle,
5199 &werr);
5200 if (!NT_STATUS_IS_OK(status)) {
5201 reply_nterror(req, status);
5202 goto out;
5204 if (!W_ERROR_IS_OK(werr)) {
5205 reply_nterror(req, werror_to_ntstatus(werr));
5206 goto out;
5209 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5210 &handle,
5211 0, /* firstjob */
5212 0xff, /* numjobs */
5213 2, /* level */
5214 0, /* offered */
5215 &count,
5216 &info);
5217 if (!W_ERROR_IS_OK(werr)) {
5218 reply_nterror(req, werror_to_ntstatus(werr));
5219 goto out;
5222 if (max_count > 0) {
5223 first = start_index;
5224 } else {
5225 first = start_index + max_count + 1;
5228 if (first >= count) {
5229 num_to_get = first;
5230 } else {
5231 num_to_get = first + MIN(ABS(max_count), count - first);
5234 for (i = first; i < num_to_get; i++) {
5235 char blob[28];
5236 char *p = blob;
5237 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5238 int qstatus;
5239 uint16_t qrapjobid = pjobid_to_rap(sharename,
5240 info[i].info2.job_id);
5242 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5243 qstatus = 2;
5244 } else {
5245 qstatus = 3;
5248 srv_put_dos_date2(p, 0, qtime);
5249 SCVAL(p, 4, qstatus);
5250 SSVAL(p, 5, qrapjobid);
5251 SIVAL(p, 7, info[i].info2.size);
5252 SCVAL(p, 11, 0);
5253 srvstr_push(blob, req->flags2, p+12,
5254 info[i].info2.notify_name, 16, STR_ASCII);
5256 if (message_push_blob(
5257 &req->outbuf,
5258 data_blob_const(
5259 blob, sizeof(blob))) == -1) {
5260 reply_nterror(req, NT_STATUS_NO_MEMORY);
5261 goto out;
5265 if (count > 0) {
5266 SSVAL(req->outbuf,smb_vwv0,count);
5267 SSVAL(req->outbuf,smb_vwv1,
5268 (max_count>0?first+count:first-1));
5269 SCVAL(smb_buf(req->outbuf),0,1);
5270 SSVAL(smb_buf(req->outbuf),1,28*count);
5274 DEBUG(3, ("%u entries returned in queue\n",
5275 (unsigned)count));
5277 out:
5278 if (cli && is_valid_policy_hnd(&handle)) {
5279 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5284 END_PROFILE(SMBsplretq);
5285 return;
5288 /****************************************************************************
5289 Reply to a printwrite.
5290 ****************************************************************************/
5292 void reply_printwrite(struct smb_request *req)
5294 connection_struct *conn = req->conn;
5295 int numtowrite;
5296 const char *data;
5297 files_struct *fsp;
5299 START_PROFILE(SMBsplwr);
5301 if (req->wct < 1) {
5302 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5303 END_PROFILE(SMBsplwr);
5304 return;
5307 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5309 if (!check_fsp(conn, req, fsp)) {
5310 END_PROFILE(SMBsplwr);
5311 return;
5314 if (!fsp->print_file) {
5315 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5316 END_PROFILE(SMBsplwr);
5317 return;
5320 if (!CHECK_WRITE(fsp)) {
5321 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5322 END_PROFILE(SMBsplwr);
5323 return;
5326 numtowrite = SVAL(req->buf, 1);
5328 if (req->buflen < numtowrite + 3) {
5329 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5330 END_PROFILE(SMBsplwr);
5331 return;
5334 data = (const char *)req->buf + 3;
5336 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5337 reply_nterror(req, map_nt_error_from_unix(errno));
5338 END_PROFILE(SMBsplwr);
5339 return;
5342 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5344 END_PROFILE(SMBsplwr);
5345 return;
5348 /****************************************************************************
5349 Reply to a mkdir.
5350 ****************************************************************************/
5352 void reply_mkdir(struct smb_request *req)
5354 connection_struct *conn = req->conn;
5355 struct smb_filename *smb_dname = NULL;
5356 char *directory = NULL;
5357 NTSTATUS status;
5358 TALLOC_CTX *ctx = talloc_tos();
5360 START_PROFILE(SMBmkdir);
5362 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5363 STR_TERMINATE, &status);
5364 if (!NT_STATUS_IS_OK(status)) {
5365 reply_nterror(req, status);
5366 goto out;
5369 status = filename_convert(ctx, conn,
5370 req->flags2 & FLAGS2_DFS_PATHNAMES,
5371 directory,
5373 NULL,
5374 &smb_dname);
5375 if (!NT_STATUS_IS_OK(status)) {
5376 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5377 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5378 ERRSRV, ERRbadpath);
5379 goto out;
5381 reply_nterror(req, status);
5382 goto out;
5385 status = create_directory(conn, req, smb_dname);
5387 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5389 if (!NT_STATUS_IS_OK(status)) {
5391 if (!use_nt_status()
5392 && NT_STATUS_EQUAL(status,
5393 NT_STATUS_OBJECT_NAME_COLLISION)) {
5395 * Yes, in the DOS error code case we get a
5396 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5397 * samba4 torture test.
5399 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5402 reply_nterror(req, status);
5403 goto out;
5406 reply_outbuf(req, 0, 0);
5408 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5409 out:
5410 TALLOC_FREE(smb_dname);
5411 END_PROFILE(SMBmkdir);
5412 return;
5415 /****************************************************************************
5416 Reply to a rmdir.
5417 ****************************************************************************/
5419 void reply_rmdir(struct smb_request *req)
5421 connection_struct *conn = req->conn;
5422 struct smb_filename *smb_dname = NULL;
5423 char *directory = NULL;
5424 NTSTATUS status;
5425 TALLOC_CTX *ctx = talloc_tos();
5426 files_struct *fsp = NULL;
5427 int info = 0;
5428 struct smbd_server_connection *sconn = req->sconn;
5430 START_PROFILE(SMBrmdir);
5432 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5433 STR_TERMINATE, &status);
5434 if (!NT_STATUS_IS_OK(status)) {
5435 reply_nterror(req, status);
5436 goto out;
5439 status = filename_convert(ctx, conn,
5440 req->flags2 & FLAGS2_DFS_PATHNAMES,
5441 directory,
5443 NULL,
5444 &smb_dname);
5445 if (!NT_STATUS_IS_OK(status)) {
5446 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5447 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5448 ERRSRV, ERRbadpath);
5449 goto out;
5451 reply_nterror(req, status);
5452 goto out;
5455 if (is_ntfs_stream_smb_fname(smb_dname)) {
5456 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5457 goto out;
5460 status = SMB_VFS_CREATE_FILE(
5461 conn, /* conn */
5462 req, /* req */
5463 0, /* root_dir_fid */
5464 smb_dname, /* fname */
5465 DELETE_ACCESS, /* access_mask */
5466 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5467 FILE_SHARE_DELETE),
5468 FILE_OPEN, /* create_disposition*/
5469 FILE_DIRECTORY_FILE, /* create_options */
5470 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5471 0, /* oplock_request */
5472 0, /* allocation_size */
5473 0, /* private_flags */
5474 NULL, /* sd */
5475 NULL, /* ea_list */
5476 &fsp, /* result */
5477 &info); /* pinfo */
5479 if (!NT_STATUS_IS_OK(status)) {
5480 if (open_was_deferred(req->mid)) {
5481 /* We have re-scheduled this call. */
5482 goto out;
5484 reply_nterror(req, status);
5485 goto out;
5488 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5489 if (!NT_STATUS_IS_OK(status)) {
5490 close_file(req, fsp, ERROR_CLOSE);
5491 reply_nterror(req, status);
5492 goto out;
5495 if (!set_delete_on_close(fsp, true, &conn->server_info->utok)) {
5496 close_file(req, fsp, ERROR_CLOSE);
5497 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5498 goto out;
5501 status = close_file(req, fsp, NORMAL_CLOSE);
5502 if (!NT_STATUS_IS_OK(status)) {
5503 reply_nterror(req, status);
5504 } else {
5505 reply_outbuf(req, 0, 0);
5508 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5510 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5511 out:
5512 TALLOC_FREE(smb_dname);
5513 END_PROFILE(SMBrmdir);
5514 return;
5517 /*******************************************************************
5518 Resolve wildcards in a filename rename.
5519 ********************************************************************/
5521 static bool resolve_wildcards(TALLOC_CTX *ctx,
5522 const char *name1,
5523 const char *name2,
5524 char **pp_newname)
5526 char *name2_copy = NULL;
5527 char *root1 = NULL;
5528 char *root2 = NULL;
5529 char *ext1 = NULL;
5530 char *ext2 = NULL;
5531 char *p,*p2, *pname1, *pname2;
5533 name2_copy = talloc_strdup(ctx, name2);
5534 if (!name2_copy) {
5535 return False;
5538 pname1 = strrchr_m(name1,'/');
5539 pname2 = strrchr_m(name2_copy,'/');
5541 if (!pname1 || !pname2) {
5542 return False;
5545 /* Truncate the copy of name2 at the last '/' */
5546 *pname2 = '\0';
5548 /* Now go past the '/' */
5549 pname1++;
5550 pname2++;
5552 root1 = talloc_strdup(ctx, pname1);
5553 root2 = talloc_strdup(ctx, pname2);
5555 if (!root1 || !root2) {
5556 return False;
5559 p = strrchr_m(root1,'.');
5560 if (p) {
5561 *p = 0;
5562 ext1 = talloc_strdup(ctx, p+1);
5563 } else {
5564 ext1 = talloc_strdup(ctx, "");
5566 p = strrchr_m(root2,'.');
5567 if (p) {
5568 *p = 0;
5569 ext2 = talloc_strdup(ctx, p+1);
5570 } else {
5571 ext2 = talloc_strdup(ctx, "");
5574 if (!ext1 || !ext2) {
5575 return False;
5578 p = root1;
5579 p2 = root2;
5580 while (*p2) {
5581 if (*p2 == '?') {
5582 /* Hmmm. Should this be mb-aware ? */
5583 *p2 = *p;
5584 p2++;
5585 } else if (*p2 == '*') {
5586 *p2 = '\0';
5587 root2 = talloc_asprintf(ctx, "%s%s",
5588 root2,
5590 if (!root2) {
5591 return False;
5593 break;
5594 } else {
5595 p2++;
5597 if (*p) {
5598 p++;
5602 p = ext1;
5603 p2 = ext2;
5604 while (*p2) {
5605 if (*p2 == '?') {
5606 /* Hmmm. Should this be mb-aware ? */
5607 *p2 = *p;
5608 p2++;
5609 } else if (*p2 == '*') {
5610 *p2 = '\0';
5611 ext2 = talloc_asprintf(ctx, "%s%s",
5612 ext2,
5614 if (!ext2) {
5615 return False;
5617 break;
5618 } else {
5619 p2++;
5621 if (*p) {
5622 p++;
5626 if (*ext2) {
5627 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5628 name2_copy,
5629 root2,
5630 ext2);
5631 } else {
5632 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5633 name2_copy,
5634 root2);
5637 if (!*pp_newname) {
5638 return False;
5641 return True;
5644 /****************************************************************************
5645 Ensure open files have their names updated. Updated to notify other smbd's
5646 asynchronously.
5647 ****************************************************************************/
5649 static void rename_open_files(connection_struct *conn,
5650 struct share_mode_lock *lck,
5651 const struct smb_filename *smb_fname_dst)
5653 files_struct *fsp;
5654 bool did_rename = False;
5655 NTSTATUS status;
5657 for(fsp = file_find_di_first(lck->id); fsp;
5658 fsp = file_find_di_next(fsp)) {
5659 /* fsp_name is a relative path under the fsp. To change this for other
5660 sharepaths we need to manipulate relative paths. */
5661 /* TODO - create the absolute path and manipulate the newname
5662 relative to the sharepath. */
5663 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5664 continue;
5666 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5667 "(file_id %s) from %s -> %s\n", fsp->fnum,
5668 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5669 smb_fname_str_dbg(smb_fname_dst)));
5671 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5672 if (NT_STATUS_IS_OK(status)) {
5673 did_rename = True;
5677 if (!did_rename) {
5678 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5679 "for %s\n", file_id_string_tos(&lck->id),
5680 smb_fname_str_dbg(smb_fname_dst)));
5683 /* Send messages to all smbd's (not ourself) that the name has changed. */
5684 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5685 smb_fname_dst);
5689 /****************************************************************************
5690 We need to check if the source path is a parent directory of the destination
5691 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5692 refuse the rename with a sharing violation. Under UNIX the above call can
5693 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5694 probably need to check that the client is a Windows one before disallowing
5695 this as a UNIX client (one with UNIX extensions) can know the source is a
5696 symlink and make this decision intelligently. Found by an excellent bug
5697 report from <AndyLiebman@aol.com>.
5698 ****************************************************************************/
5700 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5701 const struct smb_filename *smb_fname_dst)
5703 const char *psrc = smb_fname_src->base_name;
5704 const char *pdst = smb_fname_dst->base_name;
5705 size_t slen;
5707 if (psrc[0] == '.' && psrc[1] == '/') {
5708 psrc += 2;
5710 if (pdst[0] == '.' && pdst[1] == '/') {
5711 pdst += 2;
5713 if ((slen = strlen(psrc)) > strlen(pdst)) {
5714 return False;
5716 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5720 * Do the notify calls from a rename
5723 static void notify_rename(connection_struct *conn, bool is_dir,
5724 const struct smb_filename *smb_fname_src,
5725 const struct smb_filename *smb_fname_dst)
5727 char *parent_dir_src = NULL;
5728 char *parent_dir_dst = NULL;
5729 uint32 mask;
5731 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5732 : FILE_NOTIFY_CHANGE_FILE_NAME;
5734 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5735 &parent_dir_src, NULL) ||
5736 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5737 &parent_dir_dst, NULL)) {
5738 goto out;
5741 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5742 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5743 smb_fname_src->base_name);
5744 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5745 smb_fname_dst->base_name);
5747 else {
5748 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5749 smb_fname_src->base_name);
5750 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5751 smb_fname_dst->base_name);
5754 /* this is a strange one. w2k3 gives an additional event for
5755 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5756 files, but not directories */
5757 if (!is_dir) {
5758 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5759 FILE_NOTIFY_CHANGE_ATTRIBUTES
5760 |FILE_NOTIFY_CHANGE_CREATION,
5761 smb_fname_dst->base_name);
5763 out:
5764 TALLOC_FREE(parent_dir_src);
5765 TALLOC_FREE(parent_dir_dst);
5768 /****************************************************************************
5769 Rename an open file - given an fsp.
5770 ****************************************************************************/
5772 NTSTATUS rename_internals_fsp(connection_struct *conn,
5773 files_struct *fsp,
5774 const struct smb_filename *smb_fname_dst_in,
5775 uint32 attrs,
5776 bool replace_if_exists)
5778 TALLOC_CTX *ctx = talloc_tos();
5779 struct smb_filename *smb_fname_dst = NULL;
5780 NTSTATUS status = NT_STATUS_OK;
5781 struct share_mode_lock *lck = NULL;
5782 bool dst_exists, old_is_stream, new_is_stream;
5784 status = check_name(conn, smb_fname_dst_in->base_name);
5785 if (!NT_STATUS_IS_OK(status)) {
5786 return status;
5789 /* Make a copy of the dst smb_fname structs */
5791 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5792 if (!NT_STATUS_IS_OK(status)) {
5793 goto out;
5796 /* Ensure the dst smb_fname contains a '/' */
5797 if(strrchr_m(smb_fname_dst->base_name,'/') == 0) {
5798 char * tmp;
5799 tmp = talloc_asprintf(smb_fname_dst, "./%s",
5800 smb_fname_dst->base_name);
5801 if (!tmp) {
5802 status = NT_STATUS_NO_MEMORY;
5803 goto out;
5805 TALLOC_FREE(smb_fname_dst->base_name);
5806 smb_fname_dst->base_name = tmp;
5810 * Check for special case with case preserving and not
5811 * case sensitive. If the old last component differs from the original
5812 * last component only by case, then we should allow
5813 * the rename (user is trying to change the case of the
5814 * filename).
5816 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5817 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5818 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5819 char *last_slash;
5820 char *fname_dst_lcomp_base_mod = NULL;
5821 struct smb_filename *smb_fname_orig_lcomp = NULL;
5824 * Get the last component of the destination name. Note that
5825 * we guarantee that destination name contains a '/' character
5826 * above.
5828 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
5829 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
5830 if (!fname_dst_lcomp_base_mod) {
5831 status = NT_STATUS_NO_MEMORY;
5832 goto out;
5836 * Create an smb_filename struct using the original last
5837 * component of the destination.
5839 status = create_synthetic_smb_fname_split(ctx,
5840 smb_fname_dst->original_lcomp, NULL,
5841 &smb_fname_orig_lcomp);
5842 if (!NT_STATUS_IS_OK(status)) {
5843 TALLOC_FREE(fname_dst_lcomp_base_mod);
5844 goto out;
5847 /* If the base names only differ by case, use original. */
5848 if(!strcsequal(fname_dst_lcomp_base_mod,
5849 smb_fname_orig_lcomp->base_name)) {
5850 char *tmp;
5852 * Replace the modified last component with the
5853 * original.
5855 *last_slash = '\0'; /* Truncate at the '/' */
5856 tmp = talloc_asprintf(smb_fname_dst,
5857 "%s/%s",
5858 smb_fname_dst->base_name,
5859 smb_fname_orig_lcomp->base_name);
5860 if (tmp == NULL) {
5861 status = NT_STATUS_NO_MEMORY;
5862 TALLOC_FREE(fname_dst_lcomp_base_mod);
5863 TALLOC_FREE(smb_fname_orig_lcomp);
5864 goto out;
5866 TALLOC_FREE(smb_fname_dst->base_name);
5867 smb_fname_dst->base_name = tmp;
5870 /* If the stream_names only differ by case, use original. */
5871 if(!strcsequal(smb_fname_dst->stream_name,
5872 smb_fname_orig_lcomp->stream_name)) {
5873 char *tmp = NULL;
5874 /* Use the original stream. */
5875 tmp = talloc_strdup(smb_fname_dst,
5876 smb_fname_orig_lcomp->stream_name);
5877 if (tmp == NULL) {
5878 status = NT_STATUS_NO_MEMORY;
5879 TALLOC_FREE(fname_dst_lcomp_base_mod);
5880 TALLOC_FREE(smb_fname_orig_lcomp);
5881 goto out;
5883 TALLOC_FREE(smb_fname_dst->stream_name);
5884 smb_fname_dst->stream_name = tmp;
5886 TALLOC_FREE(fname_dst_lcomp_base_mod);
5887 TALLOC_FREE(smb_fname_orig_lcomp);
5891 * If the src and dest names are identical - including case,
5892 * don't do the rename, just return success.
5895 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5896 strcsequal(fsp->fsp_name->stream_name,
5897 smb_fname_dst->stream_name)) {
5898 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
5899 "- returning success\n",
5900 smb_fname_str_dbg(smb_fname_dst)));
5901 status = NT_STATUS_OK;
5902 goto out;
5905 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
5906 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
5908 /* Return the correct error code if both names aren't streams. */
5909 if (!old_is_stream && new_is_stream) {
5910 status = NT_STATUS_OBJECT_NAME_INVALID;
5911 goto out;
5914 if (old_is_stream && !new_is_stream) {
5915 status = NT_STATUS_INVALID_PARAMETER;
5916 goto out;
5919 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
5921 if(!replace_if_exists && dst_exists) {
5922 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
5923 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
5924 smb_fname_str_dbg(smb_fname_dst)));
5925 status = NT_STATUS_OBJECT_NAME_COLLISION;
5926 goto out;
5929 if (dst_exists) {
5930 struct file_id fileid = vfs_file_id_from_sbuf(conn,
5931 &smb_fname_dst->st);
5932 files_struct *dst_fsp = file_find_di_first(fileid);
5933 /* The file can be open when renaming a stream */
5934 if (dst_fsp && !new_is_stream) {
5935 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
5936 status = NT_STATUS_ACCESS_DENIED;
5937 goto out;
5941 /* Ensure we have a valid stat struct for the source. */
5942 status = vfs_stat_fsp(fsp);
5943 if (!NT_STATUS_IS_OK(status)) {
5944 goto out;
5947 status = can_rename(conn, fsp, attrs);
5949 if (!NT_STATUS_IS_OK(status)) {
5950 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
5951 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
5952 smb_fname_str_dbg(smb_fname_dst)));
5953 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
5954 status = NT_STATUS_ACCESS_DENIED;
5955 goto out;
5958 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
5959 status = NT_STATUS_ACCESS_DENIED;
5962 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
5963 NULL);
5966 * We have the file open ourselves, so not being able to get the
5967 * corresponding share mode lock is a fatal error.
5970 SMB_ASSERT(lck != NULL);
5972 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
5973 uint32 create_options = fsp->fh->private_options;
5975 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
5976 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
5977 smb_fname_str_dbg(smb_fname_dst)));
5979 if (lp_map_archive(SNUM(conn)) ||
5980 lp_store_dos_attributes(SNUM(conn))) {
5981 /* We must set the archive bit on the newly
5982 renamed file. */
5983 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
5984 uint32_t old_dosmode = dos_mode(conn,
5985 smb_fname_dst);
5986 file_set_dosmode(conn,
5987 smb_fname_dst,
5988 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
5989 NULL,
5990 true);
5994 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
5995 smb_fname_dst);
5997 rename_open_files(conn, lck, smb_fname_dst);
6000 * A rename acts as a new file create w.r.t. allowing an initial delete
6001 * on close, probably because in Windows there is a new handle to the
6002 * new file. If initial delete on close was requested but not
6003 * originally set, we need to set it here. This is probably not 100% correct,
6004 * but will work for the CIFSFS client which in non-posix mode
6005 * depends on these semantics. JRA.
6008 if (create_options & FILE_DELETE_ON_CLOSE) {
6009 status = can_set_delete_on_close(fsp, 0);
6011 if (NT_STATUS_IS_OK(status)) {
6012 /* Note that here we set the *inital* delete on close flag,
6013 * not the regular one. The magic gets handled in close. */
6014 fsp->initial_delete_on_close = True;
6017 TALLOC_FREE(lck);
6018 status = NT_STATUS_OK;
6019 goto out;
6022 TALLOC_FREE(lck);
6024 if (errno == ENOTDIR || errno == EISDIR) {
6025 status = NT_STATUS_OBJECT_NAME_COLLISION;
6026 } else {
6027 status = map_nt_error_from_unix(errno);
6030 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6031 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6032 smb_fname_str_dbg(smb_fname_dst)));
6034 out:
6035 TALLOC_FREE(smb_fname_dst);
6037 return status;
6040 /****************************************************************************
6041 The guts of the rename command, split out so it may be called by the NT SMB
6042 code.
6043 ****************************************************************************/
6045 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6046 connection_struct *conn,
6047 struct smb_request *req,
6048 struct smb_filename *smb_fname_src,
6049 struct smb_filename *smb_fname_dst,
6050 uint32 attrs,
6051 bool replace_if_exists,
6052 bool src_has_wild,
6053 bool dest_has_wild,
6054 uint32_t access_mask)
6056 char *fname_src_dir = NULL;
6057 char *fname_src_mask = NULL;
6058 int count=0;
6059 NTSTATUS status = NT_STATUS_OK;
6060 struct smb_Dir *dir_hnd = NULL;
6061 const char *dname = NULL;
6062 char *talloced = NULL;
6063 long offset = 0;
6064 int create_options = 0;
6065 bool posix_pathnames = lp_posix_pathnames();
6068 * Split the old name into directory and last component
6069 * strings. Note that unix_convert may have stripped off a
6070 * leading ./ from both name and newname if the rename is
6071 * at the root of the share. We need to make sure either both
6072 * name and newname contain a / character or neither of them do
6073 * as this is checked in resolve_wildcards().
6076 /* Split up the directory from the filename/mask. */
6077 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6078 &fname_src_dir, &fname_src_mask);
6079 if (!NT_STATUS_IS_OK(status)) {
6080 status = NT_STATUS_NO_MEMORY;
6081 goto out;
6085 * We should only check the mangled cache
6086 * here if unix_convert failed. This means
6087 * that the path in 'mask' doesn't exist
6088 * on the file system and so we need to look
6089 * for a possible mangle. This patch from
6090 * Tine Smukavec <valentin.smukavec@hermes.si>.
6093 if (!VALID_STAT(smb_fname_src->st) &&
6094 mangle_is_mangled(fname_src_mask, conn->params)) {
6095 char *new_mask = NULL;
6096 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6097 conn->params);
6098 if (new_mask) {
6099 TALLOC_FREE(fname_src_mask);
6100 fname_src_mask = new_mask;
6104 if (!src_has_wild) {
6105 files_struct *fsp;
6108 * Only one file needs to be renamed. Append the mask back
6109 * onto the directory.
6111 TALLOC_FREE(smb_fname_src->base_name);
6112 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6113 "%s/%s",
6114 fname_src_dir,
6115 fname_src_mask);
6116 if (!smb_fname_src->base_name) {
6117 status = NT_STATUS_NO_MEMORY;
6118 goto out;
6121 /* Ensure dst fname contains a '/' also */
6122 if(strrchr_m(smb_fname_dst->base_name, '/') == 0) {
6123 char *tmp;
6124 tmp = talloc_asprintf(smb_fname_dst, "./%s",
6125 smb_fname_dst->base_name);
6126 if (!tmp) {
6127 status = NT_STATUS_NO_MEMORY;
6128 goto out;
6130 TALLOC_FREE(smb_fname_dst->base_name);
6131 smb_fname_dst->base_name = tmp;
6134 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6135 "case_preserve = %d, short case preserve = %d, "
6136 "directory = %s, newname = %s, "
6137 "last_component_dest = %s\n",
6138 conn->case_sensitive, conn->case_preserve,
6139 conn->short_case_preserve,
6140 smb_fname_str_dbg(smb_fname_src),
6141 smb_fname_str_dbg(smb_fname_dst),
6142 smb_fname_dst->original_lcomp));
6144 /* The dest name still may have wildcards. */
6145 if (dest_has_wild) {
6146 char *fname_dst_mod = NULL;
6147 if (!resolve_wildcards(smb_fname_dst,
6148 smb_fname_src->base_name,
6149 smb_fname_dst->base_name,
6150 &fname_dst_mod)) {
6151 DEBUG(6, ("rename_internals: resolve_wildcards "
6152 "%s %s failed\n",
6153 smb_fname_src->base_name,
6154 smb_fname_dst->base_name));
6155 status = NT_STATUS_NO_MEMORY;
6156 goto out;
6158 TALLOC_FREE(smb_fname_dst->base_name);
6159 smb_fname_dst->base_name = fname_dst_mod;
6162 ZERO_STRUCT(smb_fname_src->st);
6163 if (posix_pathnames) {
6164 SMB_VFS_LSTAT(conn, smb_fname_src);
6165 } else {
6166 SMB_VFS_STAT(conn, smb_fname_src);
6169 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6170 create_options |= FILE_DIRECTORY_FILE;
6173 status = SMB_VFS_CREATE_FILE(
6174 conn, /* conn */
6175 req, /* req */
6176 0, /* root_dir_fid */
6177 smb_fname_src, /* fname */
6178 access_mask, /* access_mask */
6179 (FILE_SHARE_READ | /* share_access */
6180 FILE_SHARE_WRITE),
6181 FILE_OPEN, /* create_disposition*/
6182 create_options, /* create_options */
6183 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6184 0, /* oplock_request */
6185 0, /* allocation_size */
6186 0, /* private_flags */
6187 NULL, /* sd */
6188 NULL, /* ea_list */
6189 &fsp, /* result */
6190 NULL); /* pinfo */
6192 if (!NT_STATUS_IS_OK(status)) {
6193 DEBUG(3, ("Could not open rename source %s: %s\n",
6194 smb_fname_str_dbg(smb_fname_src),
6195 nt_errstr(status)));
6196 goto out;
6199 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6200 attrs, replace_if_exists);
6202 close_file(req, fsp, NORMAL_CLOSE);
6204 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6205 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6206 smb_fname_str_dbg(smb_fname_dst)));
6208 goto out;
6212 * Wildcards - process each file that matches.
6214 if (strequal(fname_src_mask, "????????.???")) {
6215 TALLOC_FREE(fname_src_mask);
6216 fname_src_mask = talloc_strdup(ctx, "*");
6217 if (!fname_src_mask) {
6218 status = NT_STATUS_NO_MEMORY;
6219 goto out;
6223 status = check_name(conn, fname_src_dir);
6224 if (!NT_STATUS_IS_OK(status)) {
6225 goto out;
6228 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6229 attrs);
6230 if (dir_hnd == NULL) {
6231 status = map_nt_error_from_unix(errno);
6232 goto out;
6235 status = NT_STATUS_NO_SUCH_FILE;
6237 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6238 * - gentest fix. JRA
6241 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6242 &talloced))) {
6243 files_struct *fsp = NULL;
6244 char *destname = NULL;
6245 bool sysdir_entry = False;
6247 /* Quick check for "." and ".." */
6248 if (ISDOT(dname) || ISDOTDOT(dname)) {
6249 if (attrs & aDIR) {
6250 sysdir_entry = True;
6251 } else {
6252 TALLOC_FREE(talloced);
6253 continue;
6257 if (!is_visible_file(conn, fname_src_dir, dname,
6258 &smb_fname_src->st, false)) {
6259 TALLOC_FREE(talloced);
6260 continue;
6263 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6264 TALLOC_FREE(talloced);
6265 continue;
6268 if (sysdir_entry) {
6269 status = NT_STATUS_OBJECT_NAME_INVALID;
6270 break;
6273 TALLOC_FREE(smb_fname_src->base_name);
6274 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6275 "%s/%s",
6276 fname_src_dir,
6277 dname);
6278 if (!smb_fname_src->base_name) {
6279 status = NT_STATUS_NO_MEMORY;
6280 goto out;
6283 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6284 smb_fname_dst->base_name,
6285 &destname)) {
6286 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6287 smb_fname_src->base_name, destname));
6288 TALLOC_FREE(talloced);
6289 continue;
6291 if (!destname) {
6292 status = NT_STATUS_NO_MEMORY;
6293 goto out;
6296 TALLOC_FREE(smb_fname_dst->base_name);
6297 smb_fname_dst->base_name = destname;
6299 ZERO_STRUCT(smb_fname_src->st);
6300 if (posix_pathnames) {
6301 SMB_VFS_LSTAT(conn, smb_fname_src);
6302 } else {
6303 SMB_VFS_STAT(conn, smb_fname_src);
6306 create_options = 0;
6308 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6309 create_options |= FILE_DIRECTORY_FILE;
6312 status = SMB_VFS_CREATE_FILE(
6313 conn, /* conn */
6314 req, /* req */
6315 0, /* root_dir_fid */
6316 smb_fname_src, /* fname */
6317 access_mask, /* access_mask */
6318 (FILE_SHARE_READ | /* share_access */
6319 FILE_SHARE_WRITE),
6320 FILE_OPEN, /* create_disposition*/
6321 create_options, /* create_options */
6322 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6323 0, /* oplock_request */
6324 0, /* allocation_size */
6325 0, /* private_flags */
6326 NULL, /* sd */
6327 NULL, /* ea_list */
6328 &fsp, /* result */
6329 NULL); /* pinfo */
6331 if (!NT_STATUS_IS_OK(status)) {
6332 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6333 "returned %s rename %s -> %s\n",
6334 nt_errstr(status),
6335 smb_fname_str_dbg(smb_fname_src),
6336 smb_fname_str_dbg(smb_fname_dst)));
6337 break;
6340 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6341 dname);
6342 if (!smb_fname_dst->original_lcomp) {
6343 status = NT_STATUS_NO_MEMORY;
6344 goto out;
6347 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6348 attrs, replace_if_exists);
6350 close_file(req, fsp, NORMAL_CLOSE);
6352 if (!NT_STATUS_IS_OK(status)) {
6353 DEBUG(3, ("rename_internals_fsp returned %s for "
6354 "rename %s -> %s\n", nt_errstr(status),
6355 smb_fname_str_dbg(smb_fname_src),
6356 smb_fname_str_dbg(smb_fname_dst)));
6357 break;
6360 count++;
6362 DEBUG(3,("rename_internals: doing rename on %s -> "
6363 "%s\n", smb_fname_str_dbg(smb_fname_src),
6364 smb_fname_str_dbg(smb_fname_src)));
6365 TALLOC_FREE(talloced);
6367 TALLOC_FREE(dir_hnd);
6369 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6370 status = map_nt_error_from_unix(errno);
6373 out:
6374 TALLOC_FREE(talloced);
6375 TALLOC_FREE(fname_src_dir);
6376 TALLOC_FREE(fname_src_mask);
6377 return status;
6380 /****************************************************************************
6381 Reply to a mv.
6382 ****************************************************************************/
6384 void reply_mv(struct smb_request *req)
6386 connection_struct *conn = req->conn;
6387 char *name = NULL;
6388 char *newname = NULL;
6389 const char *p;
6390 uint32 attrs;
6391 NTSTATUS status;
6392 bool src_has_wcard = False;
6393 bool dest_has_wcard = False;
6394 TALLOC_CTX *ctx = talloc_tos();
6395 struct smb_filename *smb_fname_src = NULL;
6396 struct smb_filename *smb_fname_dst = NULL;
6398 START_PROFILE(SMBmv);
6400 if (req->wct < 1) {
6401 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6402 goto out;
6405 attrs = SVAL(req->vwv+0, 0);
6407 p = (const char *)req->buf + 1;
6408 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6409 &status, &src_has_wcard);
6410 if (!NT_STATUS_IS_OK(status)) {
6411 reply_nterror(req, status);
6412 goto out;
6414 p++;
6415 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6416 &status, &dest_has_wcard);
6417 if (!NT_STATUS_IS_OK(status)) {
6418 reply_nterror(req, status);
6419 goto out;
6422 status = filename_convert(ctx,
6423 conn,
6424 req->flags2 & FLAGS2_DFS_PATHNAMES,
6425 name,
6426 UCF_COND_ALLOW_WCARD_LCOMP,
6427 &src_has_wcard,
6428 &smb_fname_src);
6430 if (!NT_STATUS_IS_OK(status)) {
6431 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6432 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6433 ERRSRV, ERRbadpath);
6434 goto out;
6436 reply_nterror(req, status);
6437 goto out;
6440 status = filename_convert(ctx,
6441 conn,
6442 req->flags2 & FLAGS2_DFS_PATHNAMES,
6443 newname,
6444 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6445 &dest_has_wcard,
6446 &smb_fname_dst);
6448 if (!NT_STATUS_IS_OK(status)) {
6449 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6450 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6451 ERRSRV, ERRbadpath);
6452 goto out;
6454 reply_nterror(req, status);
6455 goto out;
6458 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6459 smb_fname_str_dbg(smb_fname_dst)));
6461 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6462 attrs, False, src_has_wcard, dest_has_wcard,
6463 DELETE_ACCESS);
6464 if (!NT_STATUS_IS_OK(status)) {
6465 if (open_was_deferred(req->mid)) {
6466 /* We have re-scheduled this call. */
6467 goto out;
6469 reply_nterror(req, status);
6470 goto out;
6473 reply_outbuf(req, 0, 0);
6474 out:
6475 TALLOC_FREE(smb_fname_src);
6476 TALLOC_FREE(smb_fname_dst);
6477 END_PROFILE(SMBmv);
6478 return;
6481 /*******************************************************************
6482 Copy a file as part of a reply_copy.
6483 ******************************************************************/
6486 * TODO: check error codes on all callers
6489 NTSTATUS copy_file(TALLOC_CTX *ctx,
6490 connection_struct *conn,
6491 struct smb_filename *smb_fname_src,
6492 struct smb_filename *smb_fname_dst,
6493 int ofun,
6494 int count,
6495 bool target_is_directory)
6497 struct smb_filename *smb_fname_dst_tmp = NULL;
6498 SMB_OFF_T ret=-1;
6499 files_struct *fsp1,*fsp2;
6500 uint32 dosattrs;
6501 uint32 new_create_disposition;
6502 NTSTATUS status;
6505 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6506 if (!NT_STATUS_IS_OK(status)) {
6507 return status;
6511 * If the target is a directory, extract the last component from the
6512 * src filename and append it to the dst filename
6514 if (target_is_directory) {
6515 const char *p;
6517 /* dest/target can't be a stream if it's a directory. */
6518 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6520 p = strrchr_m(smb_fname_src->base_name,'/');
6521 if (p) {
6522 p++;
6523 } else {
6524 p = smb_fname_src->base_name;
6526 smb_fname_dst_tmp->base_name =
6527 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6529 if (!smb_fname_dst_tmp->base_name) {
6530 status = NT_STATUS_NO_MEMORY;
6531 goto out;
6535 status = vfs_file_exist(conn, smb_fname_src);
6536 if (!NT_STATUS_IS_OK(status)) {
6537 goto out;
6540 if (!target_is_directory && count) {
6541 new_create_disposition = FILE_OPEN;
6542 } else {
6543 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
6544 NULL, NULL,
6545 &new_create_disposition,
6546 NULL,
6547 NULL)) {
6548 status = NT_STATUS_INVALID_PARAMETER;
6549 goto out;
6553 /* Open the src file for reading. */
6554 status = SMB_VFS_CREATE_FILE(
6555 conn, /* conn */
6556 NULL, /* req */
6557 0, /* root_dir_fid */
6558 smb_fname_src, /* fname */
6559 FILE_GENERIC_READ, /* access_mask */
6560 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6561 FILE_OPEN, /* create_disposition*/
6562 0, /* create_options */
6563 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6564 INTERNAL_OPEN_ONLY, /* oplock_request */
6565 0, /* allocation_size */
6566 0, /* private_flags */
6567 NULL, /* sd */
6568 NULL, /* ea_list */
6569 &fsp1, /* result */
6570 NULL); /* psbuf */
6572 if (!NT_STATUS_IS_OK(status)) {
6573 goto out;
6576 dosattrs = dos_mode(conn, smb_fname_src);
6578 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6579 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6582 /* Open the dst file for writing. */
6583 status = SMB_VFS_CREATE_FILE(
6584 conn, /* conn */
6585 NULL, /* req */
6586 0, /* root_dir_fid */
6587 smb_fname_dst, /* fname */
6588 FILE_GENERIC_WRITE, /* access_mask */
6589 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6590 new_create_disposition, /* create_disposition*/
6591 0, /* create_options */
6592 dosattrs, /* file_attributes */
6593 INTERNAL_OPEN_ONLY, /* oplock_request */
6594 0, /* allocation_size */
6595 0, /* private_flags */
6596 NULL, /* sd */
6597 NULL, /* ea_list */
6598 &fsp2, /* result */
6599 NULL); /* psbuf */
6601 if (!NT_STATUS_IS_OK(status)) {
6602 close_file(NULL, fsp1, ERROR_CLOSE);
6603 goto out;
6606 if ((ofun&3) == 1) {
6607 if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
6608 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
6610 * Stop the copy from occurring.
6612 ret = -1;
6613 smb_fname_src->st.st_ex_size = 0;
6617 /* Do the actual copy. */
6618 if (smb_fname_src->st.st_ex_size) {
6619 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6622 close_file(NULL, fsp1, NORMAL_CLOSE);
6624 /* Ensure the modtime is set correctly on the destination file. */
6625 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6628 * As we are opening fsp1 read-only we only expect
6629 * an error on close on fsp2 if we are out of space.
6630 * Thus we don't look at the error return from the
6631 * close of fsp1.
6633 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6635 if (!NT_STATUS_IS_OK(status)) {
6636 goto out;
6639 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6640 status = NT_STATUS_DISK_FULL;
6641 goto out;
6644 status = NT_STATUS_OK;
6646 out:
6647 TALLOC_FREE(smb_fname_dst_tmp);
6648 return status;
6651 /****************************************************************************
6652 Reply to a file copy.
6653 ****************************************************************************/
6655 void reply_copy(struct smb_request *req)
6657 connection_struct *conn = req->conn;
6658 struct smb_filename *smb_fname_src = NULL;
6659 struct smb_filename *smb_fname_dst = NULL;
6660 char *fname_src = NULL;
6661 char *fname_dst = NULL;
6662 char *fname_src_mask = NULL;
6663 char *fname_src_dir = NULL;
6664 const char *p;
6665 int count=0;
6666 int error = ERRnoaccess;
6667 int tid2;
6668 int ofun;
6669 int flags;
6670 bool target_is_directory=False;
6671 bool source_has_wild = False;
6672 bool dest_has_wild = False;
6673 NTSTATUS status;
6674 TALLOC_CTX *ctx = talloc_tos();
6676 START_PROFILE(SMBcopy);
6678 if (req->wct < 3) {
6679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6680 goto out;
6683 tid2 = SVAL(req->vwv+0, 0);
6684 ofun = SVAL(req->vwv+1, 0);
6685 flags = SVAL(req->vwv+2, 0);
6687 p = (const char *)req->buf;
6688 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6689 &status, &source_has_wild);
6690 if (!NT_STATUS_IS_OK(status)) {
6691 reply_nterror(req, status);
6692 goto out;
6694 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6695 &status, &dest_has_wild);
6696 if (!NT_STATUS_IS_OK(status)) {
6697 reply_nterror(req, status);
6698 goto out;
6701 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6703 if (tid2 != conn->cnum) {
6704 /* can't currently handle inter share copies XXXX */
6705 DEBUG(3,("Rejecting inter-share copy\n"));
6706 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6707 goto out;
6710 status = filename_convert(ctx, conn,
6711 req->flags2 & FLAGS2_DFS_PATHNAMES,
6712 fname_src,
6713 UCF_COND_ALLOW_WCARD_LCOMP,
6714 &source_has_wild,
6715 &smb_fname_src);
6716 if (!NT_STATUS_IS_OK(status)) {
6717 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6718 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6719 ERRSRV, ERRbadpath);
6720 goto out;
6722 reply_nterror(req, status);
6723 goto out;
6726 status = filename_convert(ctx, conn,
6727 req->flags2 & FLAGS2_DFS_PATHNAMES,
6728 fname_dst,
6729 UCF_COND_ALLOW_WCARD_LCOMP,
6730 &dest_has_wild,
6731 &smb_fname_dst);
6732 if (!NT_STATUS_IS_OK(status)) {
6733 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6734 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6735 ERRSRV, ERRbadpath);
6736 goto out;
6738 reply_nterror(req, status);
6739 goto out;
6742 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6744 if ((flags&1) && target_is_directory) {
6745 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6746 goto out;
6749 if ((flags&2) && !target_is_directory) {
6750 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6751 goto out;
6754 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6755 /* wants a tree copy! XXXX */
6756 DEBUG(3,("Rejecting tree copy\n"));
6757 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6758 goto out;
6761 /* Split up the directory from the filename/mask. */
6762 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6763 &fname_src_dir, &fname_src_mask);
6764 if (!NT_STATUS_IS_OK(status)) {
6765 reply_nterror(req, NT_STATUS_NO_MEMORY);
6766 goto out;
6770 * We should only check the mangled cache
6771 * here if unix_convert failed. This means
6772 * that the path in 'mask' doesn't exist
6773 * on the file system and so we need to look
6774 * for a possible mangle. This patch from
6775 * Tine Smukavec <valentin.smukavec@hermes.si>.
6777 if (!VALID_STAT(smb_fname_src->st) &&
6778 mangle_is_mangled(fname_src_mask, conn->params)) {
6779 char *new_mask = NULL;
6780 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6781 &new_mask, conn->params);
6783 /* Use demangled name if one was successfully found. */
6784 if (new_mask) {
6785 TALLOC_FREE(fname_src_mask);
6786 fname_src_mask = new_mask;
6790 if (!source_has_wild) {
6793 * Only one file needs to be copied. Append the mask back onto
6794 * the directory.
6796 TALLOC_FREE(smb_fname_src->base_name);
6797 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6798 "%s/%s",
6799 fname_src_dir,
6800 fname_src_mask);
6801 if (!smb_fname_src->base_name) {
6802 reply_nterror(req, NT_STATUS_NO_MEMORY);
6803 goto out;
6806 if (dest_has_wild) {
6807 char *fname_dst_mod = NULL;
6808 if (!resolve_wildcards(smb_fname_dst,
6809 smb_fname_src->base_name,
6810 smb_fname_dst->base_name,
6811 &fname_dst_mod)) {
6812 reply_nterror(req, NT_STATUS_NO_MEMORY);
6813 goto out;
6815 TALLOC_FREE(smb_fname_dst->base_name);
6816 smb_fname_dst->base_name = fname_dst_mod;
6819 status = check_name(conn, smb_fname_src->base_name);
6820 if (!NT_STATUS_IS_OK(status)) {
6821 reply_nterror(req, status);
6822 goto out;
6825 status = check_name(conn, smb_fname_dst->base_name);
6826 if (!NT_STATUS_IS_OK(status)) {
6827 reply_nterror(req, status);
6828 goto out;
6831 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
6832 ofun, count, target_is_directory);
6834 if(!NT_STATUS_IS_OK(status)) {
6835 reply_nterror(req, status);
6836 goto out;
6837 } else {
6838 count++;
6840 } else {
6841 struct smb_Dir *dir_hnd = NULL;
6842 const char *dname = NULL;
6843 char *talloced = NULL;
6844 long offset = 0;
6847 * There is a wildcard that requires us to actually read the
6848 * src dir and copy each file matching the mask to the dst.
6849 * Right now streams won't be copied, but this could
6850 * presumably be added with a nested loop for reach dir entry.
6852 SMB_ASSERT(!smb_fname_src->stream_name);
6853 SMB_ASSERT(!smb_fname_dst->stream_name);
6855 smb_fname_src->stream_name = NULL;
6856 smb_fname_dst->stream_name = NULL;
6858 if (strequal(fname_src_mask,"????????.???")) {
6859 TALLOC_FREE(fname_src_mask);
6860 fname_src_mask = talloc_strdup(ctx, "*");
6861 if (!fname_src_mask) {
6862 reply_nterror(req, NT_STATUS_NO_MEMORY);
6863 goto out;
6867 status = check_name(conn, fname_src_dir);
6868 if (!NT_STATUS_IS_OK(status)) {
6869 reply_nterror(req, status);
6870 goto out;
6873 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
6874 if (dir_hnd == NULL) {
6875 status = map_nt_error_from_unix(errno);
6876 reply_nterror(req, status);
6877 goto out;
6880 error = ERRbadfile;
6882 /* Iterate over the src dir copying each entry to the dst. */
6883 while ((dname = ReadDirName(dir_hnd, &offset,
6884 &smb_fname_src->st, &talloced))) {
6885 char *destname = NULL;
6887 if (ISDOT(dname) || ISDOTDOT(dname)) {
6888 TALLOC_FREE(talloced);
6889 continue;
6892 if (!is_visible_file(conn, fname_src_dir, dname,
6893 &smb_fname_src->st, false)) {
6894 TALLOC_FREE(talloced);
6895 continue;
6898 if(!mask_match(dname, fname_src_mask,
6899 conn->case_sensitive)) {
6900 TALLOC_FREE(talloced);
6901 continue;
6904 error = ERRnoaccess;
6906 /* Get the src smb_fname struct setup. */
6907 TALLOC_FREE(smb_fname_src->base_name);
6908 smb_fname_src->base_name =
6909 talloc_asprintf(smb_fname_src, "%s/%s",
6910 fname_src_dir, dname);
6912 if (!smb_fname_src->base_name) {
6913 TALLOC_FREE(dir_hnd);
6914 TALLOC_FREE(talloced);
6915 reply_nterror(req, NT_STATUS_NO_MEMORY);
6916 goto out;
6919 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6920 smb_fname_dst->base_name,
6921 &destname)) {
6922 TALLOC_FREE(talloced);
6923 continue;
6925 if (!destname) {
6926 TALLOC_FREE(dir_hnd);
6927 TALLOC_FREE(talloced);
6928 reply_nterror(req, NT_STATUS_NO_MEMORY);
6929 goto out;
6932 TALLOC_FREE(smb_fname_dst->base_name);
6933 smb_fname_dst->base_name = destname;
6935 status = check_name(conn, smb_fname_src->base_name);
6936 if (!NT_STATUS_IS_OK(status)) {
6937 TALLOC_FREE(dir_hnd);
6938 TALLOC_FREE(talloced);
6939 reply_nterror(req, status);
6940 goto out;
6943 status = check_name(conn, smb_fname_dst->base_name);
6944 if (!NT_STATUS_IS_OK(status)) {
6945 TALLOC_FREE(dir_hnd);
6946 TALLOC_FREE(talloced);
6947 reply_nterror(req, status);
6948 goto out;
6951 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
6952 smb_fname_src->base_name,
6953 smb_fname_dst->base_name));
6955 status = copy_file(ctx, conn, smb_fname_src,
6956 smb_fname_dst, ofun, count,
6957 target_is_directory);
6958 if (NT_STATUS_IS_OK(status)) {
6959 count++;
6962 TALLOC_FREE(talloced);
6964 TALLOC_FREE(dir_hnd);
6967 if (count == 0) {
6968 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
6969 goto out;
6972 reply_outbuf(req, 1, 0);
6973 SSVAL(req->outbuf,smb_vwv0,count);
6974 out:
6975 TALLOC_FREE(smb_fname_src);
6976 TALLOC_FREE(smb_fname_dst);
6977 TALLOC_FREE(fname_src);
6978 TALLOC_FREE(fname_dst);
6979 TALLOC_FREE(fname_src_mask);
6980 TALLOC_FREE(fname_src_dir);
6982 END_PROFILE(SMBcopy);
6983 return;
6986 #undef DBGC_CLASS
6987 #define DBGC_CLASS DBGC_LOCKING
6989 /****************************************************************************
6990 Get a lock pid, dealing with large count requests.
6991 ****************************************************************************/
6993 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
6994 bool large_file_format)
6996 if(!large_file_format)
6997 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
6998 else
6999 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7002 /****************************************************************************
7003 Get a lock count, dealing with large count requests.
7004 ****************************************************************************/
7006 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7007 bool large_file_format)
7009 uint64_t count = 0;
7011 if(!large_file_format) {
7012 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7013 } else {
7015 #if defined(HAVE_LONGLONG)
7016 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7017 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7018 #else /* HAVE_LONGLONG */
7021 * NT4.x seems to be broken in that it sends large file (64 bit)
7022 * lockingX calls even if the CAP_LARGE_FILES was *not*
7023 * negotiated. For boxes without large unsigned ints truncate the
7024 * lock count by dropping the top 32 bits.
7027 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7028 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7029 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7030 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7031 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7034 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7035 #endif /* HAVE_LONGLONG */
7038 return count;
7041 #if !defined(HAVE_LONGLONG)
7042 /****************************************************************************
7043 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7044 ****************************************************************************/
7046 static uint32 map_lock_offset(uint32 high, uint32 low)
7048 unsigned int i;
7049 uint32 mask = 0;
7050 uint32 highcopy = high;
7053 * Try and find out how many significant bits there are in high.
7056 for(i = 0; highcopy; i++)
7057 highcopy >>= 1;
7060 * We use 31 bits not 32 here as POSIX
7061 * lock offsets may not be negative.
7064 mask = (~0) << (31 - i);
7066 if(low & mask)
7067 return 0; /* Fail. */
7069 high <<= (31 - i);
7071 return (high|low);
7073 #endif /* !defined(HAVE_LONGLONG) */
7075 /****************************************************************************
7076 Get a lock offset, dealing with large offset requests.
7077 ****************************************************************************/
7079 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7080 bool large_file_format, bool *err)
7082 uint64_t offset = 0;
7084 *err = False;
7086 if(!large_file_format) {
7087 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7088 } else {
7090 #if defined(HAVE_LONGLONG)
7091 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7092 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7093 #else /* HAVE_LONGLONG */
7096 * NT4.x seems to be broken in that it sends large file (64 bit)
7097 * lockingX calls even if the CAP_LARGE_FILES was *not*
7098 * negotiated. For boxes without large unsigned ints mangle the
7099 * lock offset by mapping the top 32 bits onto the lower 32.
7102 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7103 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7104 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7105 uint32 new_low = 0;
7107 if((new_low = map_lock_offset(high, low)) == 0) {
7108 *err = True;
7109 return (uint64_t)-1;
7112 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7113 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7114 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7115 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7118 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7119 #endif /* HAVE_LONGLONG */
7122 return offset;
7125 NTSTATUS smbd_do_locking(struct smb_request *req,
7126 files_struct *fsp,
7127 uint8_t type,
7128 int32_t timeout,
7129 uint16_t num_ulocks,
7130 struct smbd_lock_element *ulocks,
7131 uint16_t num_locks,
7132 struct smbd_lock_element *locks,
7133 bool *async)
7135 connection_struct *conn = req->conn;
7136 int i;
7137 NTSTATUS status = NT_STATUS_OK;
7139 *async = false;
7141 /* Data now points at the beginning of the list
7142 of smb_unlkrng structs */
7143 for(i = 0; i < (int)num_ulocks; i++) {
7144 struct smbd_lock_element *e = &ulocks[i];
7146 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7147 "pid %u, file %s\n",
7148 (double)e->offset,
7149 (double)e->count,
7150 (unsigned int)e->smblctx,
7151 fsp_str_dbg(fsp)));
7153 if (e->brltype != UNLOCK_LOCK) {
7154 /* this can only happen with SMB2 */
7155 return NT_STATUS_INVALID_PARAMETER;
7158 status = do_unlock(req->sconn->msg_ctx,
7159 fsp,
7160 e->smblctx,
7161 e->count,
7162 e->offset,
7163 WINDOWS_LOCK);
7165 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7166 nt_errstr(status)));
7168 if (!NT_STATUS_IS_OK(status)) {
7169 return status;
7173 /* Setup the timeout in seconds. */
7175 if (!lp_blocking_locks(SNUM(conn))) {
7176 timeout = 0;
7179 /* Data now points at the beginning of the list
7180 of smb_lkrng structs */
7182 for(i = 0; i < (int)num_locks; i++) {
7183 struct smbd_lock_element *e = &locks[i];
7185 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7186 "%llu, file %s timeout = %d\n",
7187 (double)e->offset,
7188 (double)e->count,
7189 (unsigned long long)e->smblctx,
7190 fsp_str_dbg(fsp),
7191 (int)timeout));
7193 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7194 struct blocking_lock_record *blr = NULL;
7196 if (num_locks > 1) {
7198 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7199 * if the lock vector contains one entry. When given mutliple cancel
7200 * requests in a single PDU we expect the server to return an
7201 * error. Windows servers seem to accept the request but only
7202 * cancel the first lock.
7203 * JRA - Do what Windows does (tm) :-).
7206 #if 0
7207 /* MS-CIFS (2.2.4.32.1) behavior. */
7208 return NT_STATUS_DOS(ERRDOS,
7209 ERRcancelviolation);
7210 #else
7211 /* Windows behavior. */
7212 if (i != 0) {
7213 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7214 "cancel request\n"));
7215 continue;
7217 #endif
7220 if (lp_blocking_locks(SNUM(conn))) {
7222 /* Schedule a message to ourselves to
7223 remove the blocking lock record and
7224 return the right error. */
7226 blr = blocking_lock_cancel_smb1(fsp,
7227 e->smblctx,
7228 e->offset,
7229 e->count,
7230 WINDOWS_LOCK,
7231 type,
7232 NT_STATUS_FILE_LOCK_CONFLICT);
7233 if (blr == NULL) {
7234 return NT_STATUS_DOS(
7235 ERRDOS,
7236 ERRcancelviolation);
7239 /* Remove a matching pending lock. */
7240 status = do_lock_cancel(fsp,
7241 e->smblctx,
7242 e->count,
7243 e->offset,
7244 WINDOWS_LOCK,
7245 blr);
7246 } else {
7247 bool blocking_lock = timeout ? true : false;
7248 bool defer_lock = false;
7249 struct byte_range_lock *br_lck;
7250 uint64_t block_smblctx;
7252 br_lck = do_lock(req->sconn->msg_ctx,
7253 fsp,
7254 e->smblctx,
7255 e->count,
7256 e->offset,
7257 e->brltype,
7258 WINDOWS_LOCK,
7259 blocking_lock,
7260 &status,
7261 &block_smblctx,
7262 NULL);
7264 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7265 /* Windows internal resolution for blocking locks seems
7266 to be about 200ms... Don't wait for less than that. JRA. */
7267 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7268 timeout = lp_lock_spin_time();
7270 defer_lock = true;
7273 /* If a lock sent with timeout of zero would fail, and
7274 * this lock has been requested multiple times,
7275 * according to brl_lock_failed() we convert this
7276 * request to a blocking lock with a timeout of between
7277 * 150 - 300 milliseconds.
7279 * If lp_lock_spin_time() has been set to 0, we skip
7280 * this blocking retry and fail immediately.
7282 * Replacement for do_lock_spin(). JRA. */
7284 if (!req->sconn->using_smb2 &&
7285 br_lck && lp_blocking_locks(SNUM(conn)) &&
7286 lp_lock_spin_time() && !blocking_lock &&
7287 NT_STATUS_EQUAL((status),
7288 NT_STATUS_FILE_LOCK_CONFLICT))
7290 defer_lock = true;
7291 timeout = lp_lock_spin_time();
7294 if (br_lck && defer_lock) {
7296 * A blocking lock was requested. Package up
7297 * this smb into a queued request and push it
7298 * onto the blocking lock queue.
7300 if(push_blocking_lock_request(br_lck,
7301 req,
7302 fsp,
7303 timeout,
7305 e->smblctx,
7306 e->brltype,
7307 WINDOWS_LOCK,
7308 e->offset,
7309 e->count,
7310 block_smblctx)) {
7311 TALLOC_FREE(br_lck);
7312 *async = true;
7313 return NT_STATUS_OK;
7317 TALLOC_FREE(br_lck);
7320 if (!NT_STATUS_IS_OK(status)) {
7321 break;
7325 /* If any of the above locks failed, then we must unlock
7326 all of the previous locks (X/Open spec). */
7328 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7330 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7331 i = -1; /* we want to skip the for loop */
7335 * Ensure we don't do a remove on the lock that just failed,
7336 * as under POSIX rules, if we have a lock already there, we
7337 * will delete it (and we shouldn't) .....
7339 for(i--; i >= 0; i--) {
7340 struct smbd_lock_element *e = &locks[i];
7342 do_unlock(req->sconn->msg_ctx,
7343 fsp,
7344 e->smblctx,
7345 e->count,
7346 e->offset,
7347 WINDOWS_LOCK);
7349 return status;
7352 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7353 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7355 return NT_STATUS_OK;
7358 /****************************************************************************
7359 Reply to a lockingX request.
7360 ****************************************************************************/
7362 void reply_lockingX(struct smb_request *req)
7364 connection_struct *conn = req->conn;
7365 files_struct *fsp;
7366 unsigned char locktype;
7367 unsigned char oplocklevel;
7368 uint16 num_ulocks;
7369 uint16 num_locks;
7370 int32 lock_timeout;
7371 int i;
7372 const uint8_t *data;
7373 bool large_file_format;
7374 bool err;
7375 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7376 struct smbd_lock_element *ulocks;
7377 struct smbd_lock_element *locks;
7378 bool async = false;
7380 START_PROFILE(SMBlockingX);
7382 if (req->wct < 8) {
7383 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7384 END_PROFILE(SMBlockingX);
7385 return;
7388 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7389 locktype = CVAL(req->vwv+3, 0);
7390 oplocklevel = CVAL(req->vwv+3, 1);
7391 num_ulocks = SVAL(req->vwv+6, 0);
7392 num_locks = SVAL(req->vwv+7, 0);
7393 lock_timeout = IVAL(req->vwv+4, 0);
7394 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7396 if (!check_fsp(conn, req, fsp)) {
7397 END_PROFILE(SMBlockingX);
7398 return;
7401 data = req->buf;
7403 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7404 /* we don't support these - and CANCEL_LOCK makes w2k
7405 and XP reboot so I don't really want to be
7406 compatible! (tridge) */
7407 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7408 END_PROFILE(SMBlockingX);
7409 return;
7412 /* Check if this is an oplock break on a file
7413 we have granted an oplock on.
7415 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7416 /* Client can insist on breaking to none. */
7417 bool break_to_none = (oplocklevel == 0);
7418 bool result;
7420 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7421 "for fnum = %d\n", (unsigned int)oplocklevel,
7422 fsp->fnum ));
7425 * Make sure we have granted an exclusive or batch oplock on
7426 * this file.
7429 if (fsp->oplock_type == 0) {
7431 /* The Samba4 nbench simulator doesn't understand
7432 the difference between break to level2 and break
7433 to none from level2 - it sends oplock break
7434 replies in both cases. Don't keep logging an error
7435 message here - just ignore it. JRA. */
7437 DEBUG(5,("reply_lockingX: Error : oplock break from "
7438 "client for fnum = %d (oplock=%d) and no "
7439 "oplock granted on this file (%s).\n",
7440 fsp->fnum, fsp->oplock_type,
7441 fsp_str_dbg(fsp)));
7443 /* if this is a pure oplock break request then don't
7444 * send a reply */
7445 if (num_locks == 0 && num_ulocks == 0) {
7446 END_PROFILE(SMBlockingX);
7447 return;
7448 } else {
7449 END_PROFILE(SMBlockingX);
7450 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7451 return;
7455 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7456 (break_to_none)) {
7457 result = remove_oplock(fsp);
7458 } else {
7459 result = downgrade_oplock(fsp);
7462 if (!result) {
7463 DEBUG(0, ("reply_lockingX: error in removing "
7464 "oplock on file %s\n", fsp_str_dbg(fsp)));
7465 /* Hmmm. Is this panic justified? */
7466 smb_panic("internal tdb error");
7469 reply_to_oplock_break_requests(fsp);
7471 /* if this is a pure oplock break request then don't send a
7472 * reply */
7473 if (num_locks == 0 && num_ulocks == 0) {
7474 /* Sanity check - ensure a pure oplock break is not a
7475 chained request. */
7476 if(CVAL(req->vwv+0, 0) != 0xff)
7477 DEBUG(0,("reply_lockingX: Error : pure oplock "
7478 "break is a chained %d request !\n",
7479 (unsigned int)CVAL(req->vwv+0, 0)));
7480 END_PROFILE(SMBlockingX);
7481 return;
7485 if (req->buflen <
7486 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7487 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7488 END_PROFILE(SMBlockingX);
7489 return;
7492 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7493 if (ulocks == NULL) {
7494 reply_nterror(req, NT_STATUS_NO_MEMORY);
7495 END_PROFILE(SMBlockingX);
7496 return;
7499 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7500 if (locks == NULL) {
7501 reply_nterror(req, NT_STATUS_NO_MEMORY);
7502 END_PROFILE(SMBlockingX);
7503 return;
7506 /* Data now points at the beginning of the list
7507 of smb_unlkrng structs */
7508 for(i = 0; i < (int)num_ulocks; i++) {
7509 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7510 ulocks[i].count = get_lock_count(data, i, large_file_format);
7511 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7512 ulocks[i].brltype = UNLOCK_LOCK;
7515 * There is no error code marked "stupid client bug".... :-).
7517 if(err) {
7518 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7519 END_PROFILE(SMBlockingX);
7520 return;
7524 /* Now do any requested locks */
7525 data += ((large_file_format ? 20 : 10)*num_ulocks);
7527 /* Data now points at the beginning of the list
7528 of smb_lkrng structs */
7530 for(i = 0; i < (int)num_locks; i++) {
7531 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7532 locks[i].count = get_lock_count(data, i, large_file_format);
7533 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7535 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7536 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7537 locks[i].brltype = PENDING_READ_LOCK;
7538 } else {
7539 locks[i].brltype = READ_LOCK;
7541 } else {
7542 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7543 locks[i].brltype = PENDING_WRITE_LOCK;
7544 } else {
7545 locks[i].brltype = WRITE_LOCK;
7550 * There is no error code marked "stupid client bug".... :-).
7552 if(err) {
7553 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7554 END_PROFILE(SMBlockingX);
7555 return;
7559 status = smbd_do_locking(req, fsp,
7560 locktype, lock_timeout,
7561 num_ulocks, ulocks,
7562 num_locks, locks,
7563 &async);
7564 if (!NT_STATUS_IS_OK(status)) {
7565 END_PROFILE(SMBlockingX);
7566 reply_nterror(req, status);
7567 return;
7569 if (async) {
7570 END_PROFILE(SMBlockingX);
7571 return;
7574 reply_outbuf(req, 2, 0);
7576 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7577 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7579 END_PROFILE(SMBlockingX);
7580 chain_reply(req);
7583 #undef DBGC_CLASS
7584 #define DBGC_CLASS DBGC_ALL
7586 /****************************************************************************
7587 Reply to a SMBreadbmpx (read block multiplex) request.
7588 Always reply with an error, if someone has a platform really needs this,
7589 please contact vl@samba.org
7590 ****************************************************************************/
7592 void reply_readbmpx(struct smb_request *req)
7594 START_PROFILE(SMBreadBmpx);
7595 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7596 END_PROFILE(SMBreadBmpx);
7597 return;
7600 /****************************************************************************
7601 Reply to a SMBreadbs (read block multiplex secondary) request.
7602 Always reply with an error, if someone has a platform really needs this,
7603 please contact vl@samba.org
7604 ****************************************************************************/
7606 void reply_readbs(struct smb_request *req)
7608 START_PROFILE(SMBreadBs);
7609 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7610 END_PROFILE(SMBreadBs);
7611 return;
7614 /****************************************************************************
7615 Reply to a SMBsetattrE.
7616 ****************************************************************************/
7618 void reply_setattrE(struct smb_request *req)
7620 connection_struct *conn = req->conn;
7621 struct smb_file_time ft;
7622 files_struct *fsp;
7623 NTSTATUS status;
7625 START_PROFILE(SMBsetattrE);
7626 ZERO_STRUCT(ft);
7628 if (req->wct < 7) {
7629 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7630 goto out;
7633 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7635 if(!fsp || (fsp->conn != conn)) {
7636 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7637 goto out;
7641 * Convert the DOS times into unix times.
7644 ft.atime = convert_time_t_to_timespec(
7645 srv_make_unix_date2(req->vwv+3));
7646 ft.mtime = convert_time_t_to_timespec(
7647 srv_make_unix_date2(req->vwv+5));
7648 ft.create_time = convert_time_t_to_timespec(
7649 srv_make_unix_date2(req->vwv+1));
7651 reply_outbuf(req, 0, 0);
7654 * Patch from Ray Frush <frush@engr.colostate.edu>
7655 * Sometimes times are sent as zero - ignore them.
7658 /* Ensure we have a valid stat struct for the source. */
7659 status = vfs_stat_fsp(fsp);
7660 if (!NT_STATUS_IS_OK(status)) {
7661 reply_nterror(req, status);
7662 goto out;
7665 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7666 if (!NT_STATUS_IS_OK(status)) {
7667 reply_nterror(req, status);
7668 goto out;
7671 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7672 " createtime=%u\n",
7673 fsp->fnum,
7674 (unsigned int)ft.atime.tv_sec,
7675 (unsigned int)ft.mtime.tv_sec,
7676 (unsigned int)ft.create_time.tv_sec
7678 out:
7679 END_PROFILE(SMBsetattrE);
7680 return;
7684 /* Back from the dead for OS/2..... JRA. */
7686 /****************************************************************************
7687 Reply to a SMBwritebmpx (write block multiplex primary) request.
7688 Always reply with an error, if someone has a platform really needs this,
7689 please contact vl@samba.org
7690 ****************************************************************************/
7692 void reply_writebmpx(struct smb_request *req)
7694 START_PROFILE(SMBwriteBmpx);
7695 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7696 END_PROFILE(SMBwriteBmpx);
7697 return;
7700 /****************************************************************************
7701 Reply to a SMBwritebs (write block multiplex secondary) request.
7702 Always reply with an error, if someone has a platform really needs this,
7703 please contact vl@samba.org
7704 ****************************************************************************/
7706 void reply_writebs(struct smb_request *req)
7708 START_PROFILE(SMBwriteBs);
7709 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7710 END_PROFILE(SMBwriteBs);
7711 return;
7714 /****************************************************************************
7715 Reply to a SMBgetattrE.
7716 ****************************************************************************/
7718 void reply_getattrE(struct smb_request *req)
7720 connection_struct *conn = req->conn;
7721 int mode;
7722 files_struct *fsp;
7723 struct timespec create_ts;
7725 START_PROFILE(SMBgetattrE);
7727 if (req->wct < 1) {
7728 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7729 END_PROFILE(SMBgetattrE);
7730 return;
7733 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7735 if(!fsp || (fsp->conn != conn)) {
7736 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7737 END_PROFILE(SMBgetattrE);
7738 return;
7741 /* Do an fstat on this file */
7742 if(fsp_stat(fsp)) {
7743 reply_nterror(req, map_nt_error_from_unix(errno));
7744 END_PROFILE(SMBgetattrE);
7745 return;
7748 mode = dos_mode(conn, fsp->fsp_name);
7751 * Convert the times into dos times. Set create
7752 * date to be last modify date as UNIX doesn't save
7753 * this.
7756 reply_outbuf(req, 11, 0);
7758 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7759 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7760 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7761 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
7762 /* Should we check pending modtime here ? JRA */
7763 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7764 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
7766 if (mode & aDIR) {
7767 SIVAL(req->outbuf, smb_vwv6, 0);
7768 SIVAL(req->outbuf, smb_vwv8, 0);
7769 } else {
7770 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
7771 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
7772 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7774 SSVAL(req->outbuf,smb_vwv10, mode);
7776 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7778 END_PROFILE(SMBgetattrE);
7779 return;