Line data Source code
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
8 :
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.
13 :
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.
18 :
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/>.
21 : */
22 : /*
23 : This file handles most of the reply_ calls that the server
24 : makes to handle specific protocols
25 : */
26 :
27 : #include "includes.h"
28 : #include "libsmb/namequery.h"
29 : #include "system/filesys.h"
30 : #include "printing.h"
31 : #include "locking/share_mode_lock.h"
32 : #include "smbd/smbd.h"
33 : #include "smbd/globals.h"
34 : #include "smbd/smbXsrv_open.h"
35 : #include "fake_file.h"
36 : #include "rpc_client/rpc_client.h"
37 : #include "../librpc/gen_ndr/ndr_spoolss_c.h"
38 : #include "rpc_client/cli_spoolss.h"
39 : #include "rpc_client/init_spoolss.h"
40 : #include "rpc_server/rpc_ncacn_np.h"
41 : #include "libcli/security/security.h"
42 : #include "libsmb/nmblib.h"
43 : #include "auth.h"
44 : #include "smbprofile.h"
45 : #include "../lib/tsocket/tsocket.h"
46 : #include "lib/util/tevent_ntstatus.h"
47 : #include "libcli/smb/smb_signing.h"
48 : #include "lib/util/sys_rw_data.h"
49 : #include "librpc/gen_ndr/open_files.h"
50 : #include "libcli/smb/smb2_posix.h"
51 : #include "lib/util/string_wrappers.h"
52 : #include "source3/printing/rap_jobid.h"
53 : #include "source3/lib/substitute.h"
54 :
55 : /****************************************************************************
56 : Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
57 : path or anything including wildcards.
58 : We're assuming here that '/' is not the second byte in any multibyte char
59 : set (a safe assumption). '\\' *may* be the second byte in a multibyte char
60 : set.
61 : ****************************************************************************/
62 :
63 : /* Custom version for processing POSIX paths. */
64 : #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
65 :
66 16415 : static NTSTATUS check_path_syntax_internal(char *path,
67 : bool posix_path)
68 : {
69 16415 : char *d = path;
70 16415 : const char *s = path;
71 16415 : NTSTATUS ret = NT_STATUS_OK;
72 16415 : bool start_of_name_component = True;
73 16415 : bool stream_started = false;
74 16415 : bool last_component_contains_wcard = false;
75 :
76 735727 : while (*s) {
77 705864 : if (stream_started) {
78 188 : switch (*s) {
79 0 : case '/':
80 : case '\\':
81 0 : return NT_STATUS_OBJECT_NAME_INVALID;
82 1 : case ':':
83 1 : if (s[1] == '\0') {
84 0 : return NT_STATUS_OBJECT_NAME_INVALID;
85 : }
86 1 : if (strchr_m(&s[1], ':')) {
87 0 : return NT_STATUS_OBJECT_NAME_INVALID;
88 : }
89 1 : break;
90 : }
91 : }
92 :
93 705864 : if ((*s == ':') && !posix_path && !stream_started) {
94 49 : if (last_component_contains_wcard) {
95 0 : return NT_STATUS_OBJECT_NAME_INVALID;
96 : }
97 : /* Stream names allow more characters than file names.
98 : We're overloading posix_path here to allow a wider
99 : range of characters. If stream_started is true this
100 : is still a Windows path even if posix_path is true.
101 : JRA.
102 : */
103 49 : stream_started = true;
104 49 : start_of_name_component = false;
105 49 : posix_path = true;
106 :
107 49 : if (s[1] == '\0') {
108 0 : return NT_STATUS_OBJECT_NAME_INVALID;
109 : }
110 : }
111 :
112 705864 : if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
113 : /*
114 : * Safe to assume is not the second part of a mb char
115 : * as this is handled below.
116 : */
117 : /* Eat multiple '/' or '\\' */
118 142197 : while (IS_PATH_SEP(*s,posix_path)) {
119 52459 : s++;
120 : }
121 52420 : if ((d != path) && (*s != '\0')) {
122 : /* We only care about non-leading or trailing '/' or '\\' */
123 52415 : *d++ = '/';
124 : }
125 :
126 52420 : start_of_name_component = True;
127 : /* New component. */
128 52420 : last_component_contains_wcard = false;
129 52420 : continue;
130 : }
131 :
132 653444 : if (start_of_name_component) {
133 63063 : if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
134 : /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
135 :
136 : /*
137 : * No mb char starts with '.' so we're safe checking the directory separator here.
138 : */
139 :
140 : /* If we just added a '/' - delete it */
141 0 : if ((d > path) && (*(d-1) == '/')) {
142 0 : *(d-1) = '\0';
143 0 : d--;
144 : }
145 :
146 : /* Are we at the start ? Can't go back further if so. */
147 0 : if (d <= path) {
148 0 : ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
149 0 : break;
150 : }
151 : /* Go back one level... */
152 : /* We know this is safe as '/' cannot be part of a mb sequence. */
153 : /* NOTE - if this assumption is invalid we are not in good shape... */
154 : /* Decrement d first as d points to the *next* char to write into. */
155 0 : for (d--; d > path; d--) {
156 0 : if (*d == '/')
157 0 : break;
158 : }
159 0 : s += 2; /* Else go past the .. */
160 : /* We're still at the start of a name component, just the previous one. */
161 0 : continue;
162 :
163 63063 : } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
164 0 : if (posix_path) {
165 : /* Eat the '.' */
166 0 : s++;
167 0 : continue;
168 : }
169 : }
170 :
171 : }
172 :
173 653444 : if (!(*s & 0x80)) {
174 653444 : if (!posix_path) {
175 653207 : if (*s <= 0x1f || *s == '|') {
176 0 : return NT_STATUS_OBJECT_NAME_INVALID;
177 : }
178 653207 : switch (*s) {
179 0 : case '*':
180 : case '?':
181 : case '<':
182 : case '>':
183 : case '"':
184 0 : last_component_contains_wcard = true;
185 0 : break;
186 653207 : default:
187 653207 : break;
188 : }
189 129 : }
190 653444 : *d++ = *s++;
191 : } else {
192 : size_t siz;
193 : /* Get the size of the next MB character. */
194 0 : next_codepoint(s,&siz);
195 0 : switch(siz) {
196 0 : case 5:
197 0 : *d++ = *s++;
198 : FALL_THROUGH;
199 0 : case 4:
200 0 : *d++ = *s++;
201 : FALL_THROUGH;
202 0 : case 3:
203 0 : *d++ = *s++;
204 : FALL_THROUGH;
205 0 : case 2:
206 0 : *d++ = *s++;
207 : FALL_THROUGH;
208 0 : case 1:
209 0 : *d++ = *s++;
210 0 : break;
211 0 : default:
212 0 : DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
213 0 : *d = '\0';
214 0 : return NT_STATUS_INVALID_PARAMETER;
215 : }
216 : }
217 653444 : start_of_name_component = False;
218 : }
219 :
220 16415 : *d = '\0';
221 :
222 16415 : return ret;
223 : }
224 :
225 : /****************************************************************************
226 : Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
227 : No wildcards allowed.
228 : ****************************************************************************/
229 :
230 16415 : NTSTATUS check_path_syntax(char *path)
231 : {
232 16415 : return check_path_syntax_internal(path, false);
233 : }
234 :
235 : /****************************************************************************
236 : Check the path for a POSIX client.
237 : We're assuming here that '/' is not the second byte in any multibyte char
238 : set (a safe assumption).
239 : ****************************************************************************/
240 :
241 0 : NTSTATUS check_path_syntax_posix(char *path)
242 : {
243 0 : return check_path_syntax_internal(path, true);
244 : }
245 :
246 : /****************************************************************************
247 : Check the path for an SMB2 DFS path.
248 : SMB2 DFS paths look like hostname\share (followed by a possible \extrapath.
249 : Path returned from here must look like:
250 : hostname/share (followed by a possible /extrapath).
251 : ****************************************************************************/
252 :
253 1036 : static NTSTATUS check_path_syntax_smb2_msdfs(char *path)
254 : {
255 1036 : char *share = NULL;
256 1036 : char *remaining_path = NULL;
257 : /* No SMB2 names can start with '\\' */
258 1036 : if (path[0] == '\\') {
259 0 : return NT_STATUS_OBJECT_NAME_INVALID;
260 : }
261 : /*
262 : * smbclient libraries sometimes set the DFS flag and send
263 : * local pathnames. Cope with this by just calling
264 : * check_path_syntax() on the whole path if it doesn't
265 : * look like a DFS path, similar to what parse_dfs_path() does.
266 : */
267 : /* servername should be at path[0] */
268 1036 : share = strchr(path, '\\');
269 1036 : if (share == NULL) {
270 0 : return check_path_syntax(path);
271 : }
272 1036 : *share++ = '/';
273 1036 : remaining_path = strchr(share, '\\');
274 1036 : if (remaining_path == NULL) {
275 : /* Only hostname\share. We're done. */
276 84 : return NT_STATUS_OK;
277 : }
278 952 : *remaining_path++ = '/';
279 952 : return check_path_syntax(remaining_path);
280 : }
281 :
282 13808 : NTSTATUS check_path_syntax_smb2(char *path, bool dfs_path)
283 : {
284 13808 : if (dfs_path) {
285 1036 : return check_path_syntax_smb2_msdfs(path);
286 : } else {
287 12772 : return check_path_syntax(path);
288 : }
289 : }
290 :
291 : /****************************************************************************
292 : Pull a string and check the path allowing a wildcard - provide for error return.
293 : Passes in posix flag.
294 : ****************************************************************************/
295 :
296 4 : static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
297 : const char *base_ptr,
298 : uint16_t smb_flags2,
299 : char **pp_dest,
300 : const char *src,
301 : size_t src_len,
302 : int flags,
303 : bool posix_pathnames,
304 : NTSTATUS *err)
305 : {
306 : size_t ret;
307 4 : char *dst = NULL;
308 :
309 4 : *pp_dest = NULL;
310 :
311 4 : ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
312 : src_len, flags);
313 :
314 4 : if (!*pp_dest) {
315 0 : *err = NT_STATUS_INVALID_PARAMETER;
316 0 : return ret;
317 : }
318 :
319 4 : dst = *pp_dest;
320 :
321 4 : if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
322 : /*
323 : * A valid DFS path looks either like
324 : * /server/share
325 : * \server\share
326 : * (there may be more components after).
327 : * Either way it must have at least two separators.
328 : *
329 : * Ensure we end up as /server/share
330 : * so we don't need to special case
331 : * separator characters elsewhere in
332 : * the code.
333 : */
334 0 : char *server = NULL;
335 0 : char *share = NULL;
336 0 : char *remaining_path = NULL;
337 0 : char path_sep = 0;
338 0 : char *p = NULL;
339 :
340 0 : if (posix_pathnames && (dst[0] == '/')) {
341 0 : path_sep = dst[0];
342 0 : } else if (dst[0] == '\\') {
343 0 : path_sep = dst[0];
344 : }
345 :
346 0 : if (path_sep == 0) {
347 0 : goto local_path;
348 : }
349 : /*
350 : * May be a DFS path.
351 : * We need some heuristics here,
352 : * as clients differ on what constitutes
353 : * a well-formed DFS path. If the path
354 : * appears malformed, just fall back to
355 : * processing as a local path.
356 : */
357 0 : server = dst;
358 :
359 : /*
360 : * Cosmetic fix for Linux-only DFS clients.
361 : * The Linux kernel SMB1 client has a bug - it sends
362 : * DFS pathnames as:
363 : *
364 : * \\server\share\path
365 : *
366 : * Causing us to mis-parse server,share,remaining_path here
367 : * and jump into 'goto local_path' at 'share\path' instead
368 : * of 'path'.
369 : *
370 : * This doesn't cause an error as the limits on share names
371 : * are similar to those on pathnames.
372 : *
373 : * parse_dfs_path() which we call before filename parsing
374 : * copes with this by calling trim_char on the leading '\'
375 : * characters before processing.
376 : * Do the same here so logging of pathnames looks better.
377 : */
378 0 : if (server[1] == path_sep) {
379 0 : trim_char(&server[1], path_sep, '\0');
380 : }
381 :
382 : /*
383 : * Look to see if we also have /share following.
384 : */
385 0 : share = strchr(server+1, path_sep);
386 0 : if (share == NULL) {
387 0 : goto local_path;
388 : }
389 : /*
390 : * Ensure the server name does not contain
391 : * any possible path components by converting
392 : * them to _'s.
393 : */
394 0 : for (p = server + 1; p < share; p++) {
395 0 : if (*p == '/' || *p == '\\') {
396 0 : *p = '_';
397 : }
398 : }
399 : /*
400 : * It's a well formed DFS path with
401 : * at least server and share components.
402 : * Replace the slashes with '/' and
403 : * pass the remainder to local_path.
404 : */
405 0 : *server = '/';
406 0 : *share = '/';
407 : /*
408 : * Skip past share so we don't pass the
409 : * sharename into check_path_syntax().
410 : */
411 0 : remaining_path = strchr(share+1, path_sep);
412 0 : if (remaining_path == NULL) {
413 : /*
414 : * Ensure the share name does not contain
415 : * any possible path components by converting
416 : * them to _'s.
417 : */
418 0 : for (p = share + 1; *p; p++) {
419 0 : if (*p == '/' || *p == '\\') {
420 0 : *p = '_';
421 : }
422 : }
423 : /*
424 : * If no remaining path this was
425 : * a bare /server/share path. Just return.
426 : */
427 0 : *err = NT_STATUS_OK;
428 0 : return ret;
429 : }
430 : /*
431 : * Ensure the share name does not contain
432 : * any possible path components by converting
433 : * them to _'s.
434 : */
435 0 : for (p = share + 1; p < remaining_path; p++) {
436 0 : if (*p == '/' || *p == '\\') {
437 0 : *p = '_';
438 : }
439 : }
440 0 : *remaining_path = '/';
441 0 : dst = remaining_path + 1;
442 : /* dst now points at any following components. */
443 : }
444 :
445 6 : local_path:
446 :
447 4 : if (posix_pathnames) {
448 0 : *err = check_path_syntax_posix(dst);
449 : } else {
450 4 : *err = check_path_syntax(dst);
451 : }
452 :
453 4 : return ret;
454 : }
455 :
456 : /****************************************************************************
457 : Pull a string and check the path - provide for error return.
458 : ****************************************************************************/
459 :
460 4 : size_t srvstr_get_path(TALLOC_CTX *ctx,
461 : const char *base_ptr,
462 : uint16_t smb_flags2,
463 : char **pp_dest,
464 : const char *src,
465 : size_t src_len,
466 : int flags,
467 : NTSTATUS *err)
468 : {
469 4 : return srvstr_get_path_internal(ctx,
470 : base_ptr,
471 : smb_flags2,
472 : pp_dest,
473 : src,
474 : src_len,
475 : flags,
476 : false,
477 : err);
478 : }
479 :
480 : /****************************************************************************
481 : Pull a string and check the path - provide for error return.
482 : posix_pathnames version.
483 : ****************************************************************************/
484 :
485 0 : size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
486 : const char *base_ptr,
487 : uint16_t smb_flags2,
488 : char **pp_dest,
489 : const char *src,
490 : size_t src_len,
491 : int flags,
492 : NTSTATUS *err)
493 : {
494 0 : return srvstr_get_path_internal(ctx,
495 : base_ptr,
496 : smb_flags2,
497 : pp_dest,
498 : src,
499 : src_len,
500 : flags,
501 : true,
502 : err);
503 : }
504 :
505 :
506 0 : size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
507 : char **pp_dest, const char *src, int flags,
508 : NTSTATUS *err)
509 : {
510 0 : ssize_t bufrem = smbreq_bufrem(req, src);
511 :
512 0 : if (bufrem == 0) {
513 0 : *err = NT_STATUS_INVALID_PARAMETER;
514 0 : return 0;
515 : }
516 :
517 0 : if (req->posix_pathnames) {
518 0 : return srvstr_get_path_internal(mem_ctx,
519 0 : (const char *)req->inbuf,
520 0 : req->flags2,
521 : pp_dest,
522 : src,
523 : bufrem,
524 : flags,
525 : true,
526 : err);
527 : } else {
528 0 : return srvstr_get_path_internal(mem_ctx,
529 0 : (const char *)req->inbuf,
530 0 : req->flags2,
531 : pp_dest,
532 : src,
533 : bufrem,
534 : flags,
535 : false,
536 : err);
537 : }
538 : }
539 :
540 : /**
541 : * pull a string from the smb_buf part of a packet. In this case the
542 : * string can either be null terminated or it can be terminated by the
543 : * end of the smbbuf area
544 : */
545 170 : size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
546 : char **dest, const uint8_t *src, int flags)
547 : {
548 170 : ssize_t bufrem = smbreq_bufrem(req, src);
549 :
550 170 : if (bufrem == 0) {
551 28 : *dest = NULL;
552 28 : return 0;
553 : }
554 :
555 142 : return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
556 : bufrem, flags);
557 : }
558 :
559 : /****************************************************************************
560 : Check if we have a correct fsp pointing to a file. Basic check for open fsp.
561 : ****************************************************************************/
562 :
563 0 : bool check_fsp_open(connection_struct *conn, struct smb_request *req,
564 : files_struct *fsp)
565 : {
566 0 : if ((fsp == NULL) || (conn == NULL)) {
567 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
568 0 : return False;
569 : }
570 0 : if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
571 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
572 0 : return False;
573 : }
574 0 : return True;
575 : }
576 :
577 : /****************************************************************************
578 : Check if we have a correct fsp pointing to a file.
579 : ****************************************************************************/
580 :
581 0 : bool check_fsp(connection_struct *conn, struct smb_request *req,
582 : files_struct *fsp)
583 : {
584 0 : if (!check_fsp_open(conn, req, fsp)) {
585 0 : return False;
586 : }
587 0 : if (fsp->fsp_flags.is_directory) {
588 0 : reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
589 0 : return False;
590 : }
591 0 : if (fsp_get_pathref_fd(fsp) == -1) {
592 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
593 0 : return False;
594 : }
595 0 : fsp->num_smb_operations++;
596 0 : return True;
597 : }
598 :
599 : /****************************************************************************
600 : Check if we have a correct fsp pointing to a quota fake file. Replacement for
601 : the CHECK_NTQUOTA_HANDLE_OK macro.
602 : ****************************************************************************/
603 :
604 0 : bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
605 : files_struct *fsp)
606 : {
607 0 : if (!check_fsp_open(conn, req, fsp)) {
608 0 : return false;
609 : }
610 :
611 0 : if (fsp->fsp_flags.is_directory) {
612 0 : return false;
613 : }
614 :
615 0 : if (fsp->fake_file_handle == NULL) {
616 0 : return false;
617 : }
618 :
619 0 : if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
620 0 : return false;
621 : }
622 :
623 0 : if (fsp->fake_file_handle->private_data == NULL) {
624 0 : return false;
625 : }
626 :
627 0 : return true;
628 : }
629 :
630 : /****************************************************************************
631 : Return the port number we've bound to on a socket.
632 : ****************************************************************************/
633 :
634 376 : static int get_socket_port(int fd)
635 : {
636 376 : struct samba_sockaddr saddr = {
637 : .sa_socklen = sizeof(struct sockaddr_storage),
638 : };
639 :
640 376 : if (fd == -1) {
641 0 : return -1;
642 : }
643 :
644 376 : if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
645 0 : int level = (errno == ENOTCONN) ? 2 : 0;
646 0 : DEBUG(level, ("getsockname failed. Error was %s\n",
647 : strerror(errno)));
648 0 : return -1;
649 : }
650 :
651 : #if defined(HAVE_IPV6)
652 376 : if (saddr.u.sa.sa_family == AF_INET6) {
653 13 : return ntohs(saddr.u.in6.sin6_port);
654 : }
655 : #endif
656 363 : if (saddr.u.sa.sa_family == AF_INET) {
657 363 : return ntohs(saddr.u.in.sin_port);
658 : }
659 0 : return -1;
660 : }
661 :
662 376 : static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
663 : const char *name, int name_type)
664 : {
665 : char *trim_name;
666 : char *trim_name_type;
667 : const char *retarget_parm;
668 : char *retarget;
669 : char *p;
670 376 : int retarget_type = 0x20;
671 376 : int retarget_port = NBT_SMB_PORT;
672 : struct sockaddr_storage retarget_addr;
673 : struct sockaddr_in *in_addr;
674 376 : bool ret = false;
675 : uint8_t outbuf[10];
676 :
677 376 : if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
678 0 : return false;
679 : }
680 :
681 376 : trim_name = talloc_strdup(talloc_tos(), name);
682 376 : if (trim_name == NULL) {
683 0 : goto fail;
684 : }
685 376 : trim_char(trim_name, ' ', ' ');
686 :
687 376 : trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
688 : name_type);
689 376 : if (trim_name_type == NULL) {
690 0 : goto fail;
691 : }
692 :
693 376 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
694 : trim_name_type, NULL);
695 376 : if (retarget_parm == NULL) {
696 376 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
697 : trim_name, NULL);
698 : }
699 376 : if (retarget_parm == NULL) {
700 376 : goto fail;
701 : }
702 :
703 0 : retarget = talloc_strdup(trim_name, retarget_parm);
704 0 : if (retarget == NULL) {
705 0 : goto fail;
706 : }
707 :
708 0 : DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
709 :
710 0 : p = strchr(retarget, ':');
711 0 : if (p != NULL) {
712 0 : *p++ = '\0';
713 0 : retarget_port = atoi(p);
714 : }
715 :
716 0 : p = strchr_m(retarget, '#');
717 0 : if (p != NULL) {
718 0 : *p++ = '\0';
719 0 : if (sscanf(p, "%x", &retarget_type) != 1) {
720 0 : goto fail;
721 : }
722 : }
723 :
724 0 : ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
725 0 : if (!ret) {
726 0 : DEBUG(10, ("could not resolve %s\n", retarget));
727 0 : goto fail;
728 : }
729 :
730 0 : if (retarget_addr.ss_family != AF_INET) {
731 0 : DEBUG(10, ("Retarget target not an IPv4 addr\n"));
732 0 : goto fail;
733 : }
734 :
735 0 : in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
736 :
737 0 : _smb_setlen(outbuf, 6);
738 0 : SCVAL(outbuf, 0, 0x84);
739 0 : *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
740 0 : *(uint16_t *)(outbuf+8) = htons(retarget_port);
741 :
742 0 : if (!smb1_srv_send(xconn, (char *)outbuf, false, 0, false,
743 : NULL)) {
744 0 : exit_server_cleanly("netbios_session_retarget: smb1_srv_send "
745 : "failed.");
746 : }
747 :
748 0 : ret = true;
749 376 : fail:
750 376 : TALLOC_FREE(trim_name);
751 376 : return ret;
752 : }
753 :
754 0 : static void reply_called_name_not_present(char *outbuf)
755 : {
756 0 : smb_setlen(outbuf, 1);
757 0 : SCVAL(outbuf, 0, 0x83);
758 0 : SCVAL(outbuf, 4, 0x82);
759 0 : }
760 :
761 : /****************************************************************************
762 : Reply to a (netbios-level) special message.
763 : ****************************************************************************/
764 :
765 376 : void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
766 : {
767 376 : struct smbd_server_connection *sconn = xconn->client->sconn;
768 376 : int msg_type = CVAL(inbuf,0);
769 376 : int msg_flags = CVAL(inbuf,1);
770 : /*
771 : * We only really use 4 bytes of the outbuf, but for the smb_setlen
772 : * calculation & friends (smb1_srv_send uses that) we need the full smb
773 : * header.
774 : */
775 : char outbuf[smb_size];
776 :
777 376 : memset(outbuf, '\0', sizeof(outbuf));
778 :
779 376 : smb_setlen(outbuf,0);
780 :
781 376 : switch (msg_type) {
782 376 : case NBSSrequest: /* session request */
783 : {
784 : /* inbuf_size is guarenteed to be at least 4. */
785 : fstring name1,name2;
786 : int name_type1, name_type2;
787 : int name_len1, name_len2;
788 :
789 376 : *name1 = *name2 = 0;
790 :
791 376 : if (xconn->transport.nbt.got_session) {
792 0 : exit_server_cleanly("multiple session request not permitted");
793 : }
794 :
795 376 : SCVAL(outbuf,0,NBSSpositive);
796 376 : SCVAL(outbuf,3,0);
797 :
798 : /* inbuf_size is guaranteed to be at least 4. */
799 376 : name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
800 376 : if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
801 0 : DEBUG(0,("Invalid name length in session request\n"));
802 0 : reply_called_name_not_present(outbuf);
803 0 : break;
804 : }
805 376 : name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
806 376 : if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
807 0 : DEBUG(0,("Invalid name length in session request\n"));
808 0 : reply_called_name_not_present(outbuf);
809 0 : break;
810 : }
811 :
812 376 : name_type1 = name_extract((unsigned char *)inbuf,
813 : inbuf_size,(unsigned int)4,name1);
814 376 : name_type2 = name_extract((unsigned char *)inbuf,
815 376 : inbuf_size,(unsigned int)(4 + name_len1),name2);
816 :
817 376 : if (name_type1 == -1 || name_type2 == -1) {
818 0 : DEBUG(0,("Invalid name type in session request\n"));
819 0 : reply_called_name_not_present(outbuf);
820 0 : break;
821 : }
822 :
823 376 : DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
824 : name1, name_type1, name2, name_type2));
825 :
826 376 : if (netbios_session_retarget(xconn, name1, name_type1)) {
827 0 : exit_server_cleanly("retargeted client");
828 : }
829 :
830 : /*
831 : * Windows NT/2k uses "*SMBSERVER" and XP uses
832 : * "*SMBSERV" arrggg!!!
833 : */
834 376 : if (strequal(name1, "*SMBSERVER ")
835 376 : || strequal(name1, "*SMBSERV ")) {
836 : char *raddr;
837 :
838 0 : raddr = tsocket_address_inet_addr_string(sconn->remote_address,
839 : talloc_tos());
840 0 : if (raddr == NULL) {
841 0 : exit_server_cleanly("could not allocate raddr");
842 : }
843 :
844 0 : fstrcpy(name1, raddr);
845 : }
846 :
847 376 : set_local_machine_name(name1, True);
848 376 : set_remote_machine_name(name2, True);
849 :
850 376 : if (is_ipaddress(sconn->remote_hostname)) {
851 376 : char *p = discard_const_p(char, sconn->remote_hostname);
852 :
853 376 : talloc_free(p);
854 :
855 376 : sconn->remote_hostname = talloc_strdup(sconn,
856 : get_remote_machine_name());
857 376 : if (sconn->remote_hostname == NULL) {
858 0 : exit_server_cleanly("could not copy remote name");
859 : }
860 376 : xconn->remote_hostname = sconn->remote_hostname;
861 : }
862 :
863 376 : DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
864 : get_local_machine_name(), get_remote_machine_name(),
865 : name_type2));
866 :
867 376 : if (name_type2 == 'R') {
868 : /* We are being asked for a pathworks session ---
869 : no thanks! */
870 0 : reply_called_name_not_present(outbuf);
871 0 : break;
872 : }
873 :
874 376 : reload_services(sconn, conn_snum_used, true);
875 376 : reopen_logs();
876 :
877 376 : xconn->transport.nbt.got_session = true;
878 376 : break;
879 : }
880 :
881 0 : case 0x89: /* session keepalive request
882 : (some old clients produce this?) */
883 0 : SCVAL(outbuf,0,NBSSkeepalive);
884 0 : SCVAL(outbuf,3,0);
885 0 : break;
886 :
887 0 : case NBSSpositive: /* positive session response */
888 : case NBSSnegative: /* negative session response */
889 : case NBSSretarget: /* retarget session response */
890 0 : DEBUG(0,("Unexpected session response\n"));
891 0 : break;
892 :
893 0 : case NBSSkeepalive: /* session keepalive */
894 : default:
895 0 : return;
896 : }
897 :
898 376 : DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
899 : msg_type, msg_flags));
900 :
901 376 : if (!smb1_srv_send(xconn, outbuf, false, 0, false, NULL)) {
902 13 : exit_server_cleanly("reply_special: smb1_srv_send failed.");
903 : }
904 :
905 363 : if (CVAL(outbuf, 0) != 0x82) {
906 0 : exit_server_cleanly("invalid netbios session");
907 : }
908 363 : return;
909 : }
910 :
911 : /*******************************************************************
912 : * unlink a file with all relevant access checks
913 : *******************************************************************/
914 :
915 0 : NTSTATUS unlink_internals(connection_struct *conn,
916 : struct smb_request *req,
917 : uint32_t dirtype,
918 : struct files_struct *dirfsp,
919 : struct smb_filename *smb_fname)
920 : {
921 : uint32_t fattr;
922 : files_struct *fsp;
923 0 : uint32_t dirtype_orig = dirtype;
924 : NTSTATUS status;
925 : int ret;
926 0 : struct smb2_create_blobs *posx = NULL;
927 :
928 0 : if (dirtype == 0) {
929 0 : dirtype = FILE_ATTRIBUTE_NORMAL;
930 : }
931 :
932 0 : DBG_DEBUG("%s, dirtype = %d\n",
933 : smb_fname_str_dbg(smb_fname),
934 : dirtype);
935 :
936 0 : if (!CAN_WRITE(conn)) {
937 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
938 : }
939 :
940 0 : ret = vfs_stat(conn, smb_fname);
941 0 : if (ret != 0) {
942 0 : return map_nt_error_from_unix(errno);
943 : }
944 :
945 0 : fattr = fdos_mode(smb_fname->fsp);
946 :
947 0 : if (dirtype & FILE_ATTRIBUTE_NORMAL) {
948 0 : dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
949 : }
950 :
951 0 : dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
952 0 : if (!dirtype) {
953 0 : return NT_STATUS_NO_SUCH_FILE;
954 : }
955 :
956 0 : if (!dir_check_ftype(fattr, dirtype)) {
957 0 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
958 0 : return NT_STATUS_FILE_IS_A_DIRECTORY;
959 : }
960 0 : return NT_STATUS_NO_SUCH_FILE;
961 : }
962 :
963 0 : if (dirtype_orig & 0x8000) {
964 : /* These will never be set for POSIX. */
965 0 : return NT_STATUS_NO_SUCH_FILE;
966 : }
967 :
968 : #if 0
969 : if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
970 : return NT_STATUS_FILE_IS_A_DIRECTORY;
971 : }
972 :
973 : if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
974 : return NT_STATUS_NO_SUCH_FILE;
975 : }
976 :
977 : if (dirtype & 0xFF00) {
978 : /* These will never be set for POSIX. */
979 : return NT_STATUS_NO_SUCH_FILE;
980 : }
981 :
982 : dirtype &= 0xFF;
983 : if (!dirtype) {
984 : return NT_STATUS_NO_SUCH_FILE;
985 : }
986 :
987 : /* Can't delete a directory. */
988 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
989 : return NT_STATUS_FILE_IS_A_DIRECTORY;
990 : }
991 : #endif
992 :
993 : #if 0 /* JRATEST */
994 : else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
995 : return NT_STATUS_OBJECT_NAME_INVALID;
996 : #endif /* JRATEST */
997 :
998 0 : if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
999 0 : status = make_smb2_posix_create_ctx(
1000 : talloc_tos(), &posx, 0777);
1001 0 : if (!NT_STATUS_IS_OK(status)) {
1002 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
1003 : nt_errstr(status));
1004 0 : return status;
1005 : }
1006 : }
1007 :
1008 : /* On open checks the open itself will check the share mode, so
1009 : don't do it here as we'll get it wrong. */
1010 :
1011 0 : status = SMB_VFS_CREATE_FILE
1012 : (conn, /* conn */
1013 : req, /* req */
1014 : dirfsp, /* dirfsp */
1015 : smb_fname, /* fname */
1016 : DELETE_ACCESS, /* access_mask */
1017 : FILE_SHARE_NONE, /* share_access */
1018 : FILE_OPEN, /* create_disposition*/
1019 : FILE_NON_DIRECTORY_FILE, /* create_options */
1020 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
1021 : 0, /* oplock_request */
1022 : NULL, /* lease */
1023 : 0, /* allocation_size */
1024 : 0, /* private_flags */
1025 : NULL, /* sd */
1026 : NULL, /* ea_list */
1027 : &fsp, /* result */
1028 : NULL, /* pinfo */
1029 : posx, /* in_context_blobs */
1030 : NULL); /* out_context_blobs */
1031 :
1032 0 : TALLOC_FREE(posx);
1033 :
1034 0 : if (!NT_STATUS_IS_OK(status)) {
1035 0 : DBG_DEBUG("SMB_VFS_CREATEFILE failed: %s\n",
1036 : nt_errstr(status));
1037 0 : return status;
1038 : }
1039 :
1040 0 : status = can_set_delete_on_close(fsp, fattr);
1041 0 : if (!NT_STATUS_IS_OK(status)) {
1042 0 : DBG_DEBUG("can_set_delete_on_close for file %s - "
1043 : "(%s)\n",
1044 : smb_fname_str_dbg(smb_fname),
1045 : nt_errstr(status));
1046 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
1047 0 : return status;
1048 : }
1049 :
1050 : /* The set is across all open files on this dev/inode pair. */
1051 0 : if (!set_delete_on_close(fsp, True,
1052 0 : conn->session_info->security_token,
1053 0 : conn->session_info->unix_token)) {
1054 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
1055 0 : return NT_STATUS_ACCESS_DENIED;
1056 : }
1057 :
1058 0 : return close_file_free(req, &fsp, NORMAL_CLOSE);
1059 : }
1060 :
1061 : /****************************************************************************
1062 : Fake (read/write) sendfile. Returns -1 on read or write fail.
1063 : ****************************************************************************/
1064 :
1065 0 : ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
1066 : off_t startpos, size_t nread)
1067 : {
1068 : size_t bufsize;
1069 0 : size_t tosend = nread;
1070 : char *buf;
1071 :
1072 0 : if (nread == 0) {
1073 0 : return 0;
1074 : }
1075 :
1076 0 : bufsize = MIN(nread, 65536);
1077 :
1078 0 : if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
1079 0 : return -1;
1080 : }
1081 :
1082 0 : while (tosend > 0) {
1083 : ssize_t ret;
1084 : size_t cur_read;
1085 :
1086 0 : cur_read = MIN(tosend, bufsize);
1087 0 : ret = read_file(fsp,buf,startpos,cur_read);
1088 0 : if (ret == -1) {
1089 0 : SAFE_FREE(buf);
1090 0 : return -1;
1091 : }
1092 :
1093 : /* If we had a short read, fill with zeros. */
1094 0 : if (ret < cur_read) {
1095 0 : memset(buf + ret, '\0', cur_read - ret);
1096 : }
1097 :
1098 0 : ret = write_data(xconn->transport.sock, buf, cur_read);
1099 0 : if (ret != cur_read) {
1100 0 : int saved_errno = errno;
1101 : /*
1102 : * Try and give an error message saying what
1103 : * client failed.
1104 : */
1105 0 : DEBUG(0, ("write_data failed for client %s. "
1106 : "Error %s\n",
1107 : smbXsrv_connection_dbg(xconn),
1108 : strerror(saved_errno)));
1109 0 : SAFE_FREE(buf);
1110 0 : errno = saved_errno;
1111 0 : return -1;
1112 : }
1113 0 : tosend -= cur_read;
1114 0 : startpos += cur_read;
1115 : }
1116 :
1117 0 : SAFE_FREE(buf);
1118 0 : return (ssize_t)nread;
1119 : }
1120 :
1121 : /****************************************************************************
1122 : Deal with the case of sendfile reading less bytes from the file than
1123 : requested. Fill with zeros (all we can do). Returns 0 on success
1124 : ****************************************************************************/
1125 :
1126 0 : ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
1127 : files_struct *fsp,
1128 : ssize_t nread,
1129 : size_t headersize,
1130 : size_t smb_maxcnt)
1131 : {
1132 : #define SHORT_SEND_BUFSIZE 1024
1133 0 : if (nread < headersize) {
1134 0 : DEBUG(0,("sendfile_short_send: sendfile failed to send "
1135 : "header for file %s (%s). Terminating\n",
1136 : fsp_str_dbg(fsp), strerror(errno)));
1137 0 : return -1;
1138 : }
1139 :
1140 0 : nread -= headersize;
1141 :
1142 0 : if (nread < smb_maxcnt) {
1143 0 : char buf[SHORT_SEND_BUFSIZE] = { 0 };
1144 :
1145 0 : DEBUG(0,("sendfile_short_send: filling truncated file %s "
1146 : "with zeros !\n", fsp_str_dbg(fsp)));
1147 :
1148 0 : while (nread < smb_maxcnt) {
1149 : /*
1150 : * We asked for the real file size and told sendfile
1151 : * to not go beyond the end of the file. But it can
1152 : * happen that in between our fstat call and the
1153 : * sendfile call the file was truncated. This is very
1154 : * bad because we have already announced the larger
1155 : * number of bytes to the client.
1156 : *
1157 : * The best we can do now is to send 0-bytes, just as
1158 : * a read from a hole in a sparse file would do.
1159 : *
1160 : * This should happen rarely enough that I don't care
1161 : * about efficiency here :-)
1162 : */
1163 : size_t to_write;
1164 : ssize_t ret;
1165 :
1166 0 : to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
1167 0 : ret = write_data(xconn->transport.sock, buf, to_write);
1168 0 : if (ret != to_write) {
1169 0 : int saved_errno = errno;
1170 : /*
1171 : * Try and give an error message saying what
1172 : * client failed.
1173 : */
1174 0 : DEBUG(0, ("write_data failed for client %s. "
1175 : "Error %s\n",
1176 : smbXsrv_connection_dbg(xconn),
1177 : strerror(saved_errno)));
1178 0 : errno = saved_errno;
1179 0 : return -1;
1180 : }
1181 0 : nread += to_write;
1182 : }
1183 : }
1184 :
1185 0 : return 0;
1186 : }
1187 :
1188 : /*******************************************************************
1189 : Check if a user is allowed to rename a file.
1190 : ********************************************************************/
1191 :
1192 20 : static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
1193 : uint16_t dirtype)
1194 : {
1195 20 : if (!CAN_WRITE(conn)) {
1196 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
1197 : }
1198 :
1199 20 : if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
1200 : (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1201 : /* Only bother to read the DOS attribute if we might deny the
1202 : rename on the grounds of attribute mismatch. */
1203 0 : uint32_t fmode = fdos_mode(fsp);
1204 0 : if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1205 0 : return NT_STATUS_NO_SUCH_FILE;
1206 : }
1207 : }
1208 :
1209 20 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1210 4 : if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
1211 0 : return NT_STATUS_OK;
1212 : }
1213 :
1214 : /* If no pathnames are open below this
1215 : directory, allow the rename. */
1216 :
1217 4 : if (lp_strict_rename(SNUM(conn))) {
1218 : /*
1219 : * Strict rename, check open file db.
1220 : */
1221 4 : if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
1222 0 : return NT_STATUS_ACCESS_DENIED;
1223 : }
1224 0 : } else if (file_find_subpath(fsp)) {
1225 : /*
1226 : * No strict rename, just look in local process.
1227 : */
1228 0 : return NT_STATUS_ACCESS_DENIED;
1229 : }
1230 4 : return NT_STATUS_OK;
1231 : }
1232 :
1233 16 : if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
1234 16 : return NT_STATUS_OK;
1235 : }
1236 :
1237 0 : return NT_STATUS_ACCESS_DENIED;
1238 : }
1239 :
1240 : /****************************************************************************
1241 : Ensure open files have their names updated. Updated to notify other smbd's
1242 : asynchronously.
1243 : ****************************************************************************/
1244 :
1245 20 : static void rename_open_files(connection_struct *conn,
1246 : struct share_mode_lock *lck,
1247 : struct file_id id,
1248 : uint32_t orig_name_hash,
1249 : const struct smb_filename *smb_fname_dst)
1250 : {
1251 : files_struct *fsp;
1252 20 : bool did_rename = False;
1253 : NTSTATUS status;
1254 20 : uint32_t new_name_hash = 0;
1255 :
1256 50 : for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
1257 20 : fsp = file_find_di_next(fsp, false)) {
1258 : SMB_STRUCT_STAT fsp_orig_sbuf;
1259 : struct file_id_buf idbuf;
1260 : /* fsp_name is a relative path under the fsp. To change this for other
1261 : sharepaths we need to manipulate relative paths. */
1262 : /* TODO - create the absolute path and manipulate the newname
1263 : relative to the sharepath. */
1264 20 : if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
1265 0 : continue;
1266 : }
1267 20 : if (fsp->name_hash != orig_name_hash) {
1268 0 : continue;
1269 : }
1270 20 : DBG_DEBUG("renaming file %s "
1271 : "(file_id %s) from %s -> %s\n",
1272 : fsp_fnum_dbg(fsp),
1273 : file_id_str_buf(fsp->file_id, &idbuf),
1274 : fsp_str_dbg(fsp),
1275 : smb_fname_str_dbg(smb_fname_dst));
1276 :
1277 : /*
1278 : * The incoming smb_fname_dst here has an
1279 : * invalid stat struct (it must not have
1280 : * existed for the rename to succeed).
1281 : * Preserve the existing stat from the
1282 : * open fsp after fsp_set_smb_fname()
1283 : * overwrites with the invalid stat.
1284 : *
1285 : * We will do an fstat before returning
1286 : * any of this metadata to the client anyway.
1287 : */
1288 20 : fsp_orig_sbuf = fsp->fsp_name->st;
1289 20 : status = fsp_set_smb_fname(fsp, smb_fname_dst);
1290 20 : if (NT_STATUS_IS_OK(status)) {
1291 20 : did_rename = True;
1292 20 : new_name_hash = fsp->name_hash;
1293 : /* Restore existing stat. */
1294 20 : fsp->fsp_name->st = fsp_orig_sbuf;
1295 : }
1296 : }
1297 :
1298 20 : if (!did_rename) {
1299 : struct file_id_buf idbuf;
1300 0 : DBG_DEBUG("no open files on file_id %s "
1301 : "for %s\n",
1302 : file_id_str_buf(id, &idbuf),
1303 : smb_fname_str_dbg(smb_fname_dst));
1304 : }
1305 :
1306 : /* Send messages to all smbd's (not ourself) that the name has changed. */
1307 20 : rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
1308 : orig_name_hash, new_name_hash,
1309 : smb_fname_dst);
1310 :
1311 20 : }
1312 :
1313 : /****************************************************************************
1314 : We need to check if the source path is a parent directory of the destination
1315 : (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
1316 : refuse the rename with a sharing violation. Under UNIX the above call can
1317 : *succeed* if /foo/bar/baz is a symlink to another area in the share. We
1318 : probably need to check that the client is a Windows one before disallowing
1319 : this as a UNIX client (one with UNIX extensions) can know the source is a
1320 : symlink and make this decision intelligently. Found by an excellent bug
1321 : report from <AndyLiebman@aol.com>.
1322 : ****************************************************************************/
1323 :
1324 20 : static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
1325 : const struct smb_filename *smb_fname_dst)
1326 : {
1327 20 : const char *psrc = smb_fname_src->base_name;
1328 20 : const char *pdst = smb_fname_dst->base_name;
1329 : size_t slen;
1330 :
1331 20 : if (psrc[0] == '.' && psrc[1] == '/') {
1332 0 : psrc += 2;
1333 : }
1334 20 : if (pdst[0] == '.' && pdst[1] == '/') {
1335 0 : pdst += 2;
1336 : }
1337 20 : if ((slen = strlen(psrc)) > strlen(pdst)) {
1338 4 : return False;
1339 : }
1340 16 : return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
1341 : }
1342 :
1343 : /*
1344 : * Do the notify calls from a rename
1345 : */
1346 :
1347 20 : static void notify_rename(connection_struct *conn, bool is_dir,
1348 : const struct smb_filename *smb_fname_src,
1349 : const struct smb_filename *smb_fname_dst)
1350 : {
1351 20 : char *parent_dir_src = NULL;
1352 20 : char *parent_dir_dst = NULL;
1353 : uint32_t mask;
1354 :
1355 20 : mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
1356 20 : : FILE_NOTIFY_CHANGE_FILE_NAME;
1357 :
1358 20 : if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
1359 20 : &parent_dir_src, NULL) ||
1360 20 : !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
1361 : &parent_dir_dst, NULL)) {
1362 0 : goto out;
1363 : }
1364 :
1365 20 : if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
1366 16 : notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
1367 16 : smb_fname_src->base_name);
1368 16 : notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
1369 16 : smb_fname_dst->base_name);
1370 : }
1371 : else {
1372 4 : notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
1373 4 : smb_fname_src->base_name);
1374 4 : notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
1375 4 : smb_fname_dst->base_name);
1376 : }
1377 :
1378 : /* this is a strange one. w2k3 gives an additional event for
1379 : CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
1380 : files, but not directories */
1381 20 : if (!is_dir) {
1382 16 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1383 : FILE_NOTIFY_CHANGE_ATTRIBUTES
1384 : |FILE_NOTIFY_CHANGE_CREATION,
1385 16 : smb_fname_dst->base_name);
1386 : }
1387 14 : out:
1388 20 : TALLOC_FREE(parent_dir_src);
1389 20 : TALLOC_FREE(parent_dir_dst);
1390 20 : }
1391 :
1392 : /****************************************************************************
1393 : Returns an error if the parent directory for a filename is open in an
1394 : incompatible way.
1395 : ****************************************************************************/
1396 :
1397 21 : static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
1398 : const struct smb_filename *smb_fname_dst_in)
1399 : {
1400 21 : struct smb_filename *smb_fname_parent = NULL;
1401 : struct file_id id;
1402 21 : files_struct *fsp = NULL;
1403 : int ret;
1404 : NTSTATUS status;
1405 :
1406 21 : status = SMB_VFS_PARENT_PATHNAME(conn,
1407 : talloc_tos(),
1408 : smb_fname_dst_in,
1409 : &smb_fname_parent,
1410 : NULL);
1411 21 : if (!NT_STATUS_IS_OK(status)) {
1412 0 : return status;
1413 : }
1414 :
1415 21 : ret = vfs_stat(conn, smb_fname_parent);
1416 21 : if (ret == -1) {
1417 0 : return map_nt_error_from_unix(errno);
1418 : }
1419 :
1420 : /*
1421 : * We're only checking on this smbd here, mostly good
1422 : * enough.. and will pass tests.
1423 : */
1424 :
1425 21 : id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
1426 32 : for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
1427 0 : fsp = file_find_di_next(fsp, true)) {
1428 0 : if (fsp->access_mask & DELETE_ACCESS) {
1429 0 : return NT_STATUS_SHARING_VIOLATION;
1430 : }
1431 : }
1432 21 : return NT_STATUS_OK;
1433 : }
1434 :
1435 : /****************************************************************************
1436 : Rename an open file - given an fsp.
1437 : ****************************************************************************/
1438 :
1439 21 : NTSTATUS rename_internals_fsp(connection_struct *conn,
1440 : files_struct *fsp,
1441 : struct files_struct *dst_dirfsp,
1442 : struct smb_filename *smb_fname_dst_in,
1443 : const char *dst_original_lcomp,
1444 : uint32_t attrs,
1445 : bool replace_if_exists)
1446 : {
1447 21 : TALLOC_CTX *ctx = talloc_tos();
1448 21 : struct smb_filename *parent_dir_fname_dst = NULL;
1449 21 : struct smb_filename *parent_dir_fname_dst_atname = NULL;
1450 21 : struct smb_filename *parent_dir_fname_src = NULL;
1451 21 : struct smb_filename *parent_dir_fname_src_atname = NULL;
1452 21 : struct smb_filename *smb_fname_dst = NULL;
1453 21 : NTSTATUS status = NT_STATUS_OK;
1454 21 : struct share_mode_lock *lck = NULL;
1455 21 : uint32_t access_mask = SEC_DIR_ADD_FILE;
1456 : bool dst_exists, old_is_stream, new_is_stream;
1457 : int ret;
1458 42 : bool case_sensitive = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1459 21 : true : conn->case_sensitive;
1460 42 : bool case_preserve = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1461 21 : true : conn->case_preserve;
1462 :
1463 21 : status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
1464 21 : if (!NT_STATUS_IS_OK(status)) {
1465 0 : return status;
1466 : }
1467 :
1468 21 : if (file_has_open_streams(fsp)) {
1469 0 : return NT_STATUS_ACCESS_DENIED;
1470 : }
1471 :
1472 : /* Make a copy of the dst smb_fname structs */
1473 :
1474 21 : smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
1475 21 : if (smb_fname_dst == NULL) {
1476 0 : status = NT_STATUS_NO_MEMORY;
1477 0 : goto out;
1478 : }
1479 :
1480 : /*
1481 : * Check for special case with case preserving and not
1482 : * case sensitive. If the new last component differs from the original
1483 : * last component only by case, then we should allow
1484 : * the rename (user is trying to change the case of the
1485 : * filename).
1486 : */
1487 42 : if (!case_sensitive && case_preserve &&
1488 21 : strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1489 0 : strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
1490 0 : char *fname_dst_parent = NULL;
1491 0 : const char *fname_dst_lcomp = NULL;
1492 0 : char *orig_lcomp_path = NULL;
1493 0 : char *orig_lcomp_stream = NULL;
1494 0 : bool ok = true;
1495 :
1496 : /*
1497 : * Split off the last component of the processed
1498 : * destination name. We will compare this to
1499 : * the split components of dst_original_lcomp.
1500 : */
1501 0 : if (!parent_dirname(ctx,
1502 0 : smb_fname_dst->base_name,
1503 : &fname_dst_parent,
1504 : &fname_dst_lcomp)) {
1505 0 : status = NT_STATUS_NO_MEMORY;
1506 0 : goto out;
1507 : }
1508 :
1509 : /*
1510 : * The dst_original_lcomp component contains
1511 : * the last_component of the path + stream
1512 : * name (if a stream exists).
1513 : *
1514 : * Split off the stream name so we
1515 : * can check them separately.
1516 : */
1517 :
1518 0 : if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
1519 : /* POSIX - no stream component. */
1520 0 : orig_lcomp_path = talloc_strdup(ctx,
1521 : dst_original_lcomp);
1522 0 : if (orig_lcomp_path == NULL) {
1523 0 : ok = false;
1524 : }
1525 : } else {
1526 0 : ok = split_stream_filename(ctx,
1527 : dst_original_lcomp,
1528 : &orig_lcomp_path,
1529 : &orig_lcomp_stream);
1530 : }
1531 :
1532 0 : if (!ok) {
1533 0 : TALLOC_FREE(fname_dst_parent);
1534 0 : status = NT_STATUS_NO_MEMORY;
1535 0 : goto out;
1536 : }
1537 :
1538 : /* If the base names only differ by case, use original. */
1539 0 : if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
1540 : char *tmp;
1541 : /*
1542 : * Replace the modified last component with the
1543 : * original.
1544 : */
1545 0 : if (!ISDOT(fname_dst_parent)) {
1546 0 : tmp = talloc_asprintf(smb_fname_dst,
1547 : "%s/%s",
1548 : fname_dst_parent,
1549 : orig_lcomp_path);
1550 : } else {
1551 0 : tmp = talloc_strdup(smb_fname_dst,
1552 : orig_lcomp_path);
1553 : }
1554 0 : if (tmp == NULL) {
1555 0 : status = NT_STATUS_NO_MEMORY;
1556 0 : TALLOC_FREE(fname_dst_parent);
1557 0 : TALLOC_FREE(orig_lcomp_path);
1558 0 : TALLOC_FREE(orig_lcomp_stream);
1559 0 : goto out;
1560 : }
1561 0 : TALLOC_FREE(smb_fname_dst->base_name);
1562 0 : smb_fname_dst->base_name = tmp;
1563 : }
1564 :
1565 : /* If the stream_names only differ by case, use original. */
1566 0 : if(!strcsequal(smb_fname_dst->stream_name,
1567 : orig_lcomp_stream)) {
1568 : /* Use the original stream. */
1569 0 : char *tmp = talloc_strdup(smb_fname_dst,
1570 : orig_lcomp_stream);
1571 0 : if (tmp == NULL) {
1572 0 : status = NT_STATUS_NO_MEMORY;
1573 0 : TALLOC_FREE(fname_dst_parent);
1574 0 : TALLOC_FREE(orig_lcomp_path);
1575 0 : TALLOC_FREE(orig_lcomp_stream);
1576 0 : goto out;
1577 : }
1578 0 : TALLOC_FREE(smb_fname_dst->stream_name);
1579 0 : smb_fname_dst->stream_name = tmp;
1580 : }
1581 0 : TALLOC_FREE(fname_dst_parent);
1582 0 : TALLOC_FREE(orig_lcomp_path);
1583 0 : TALLOC_FREE(orig_lcomp_stream);
1584 : }
1585 :
1586 : /*
1587 : * If the src and dest names are identical - including case,
1588 : * don't do the rename, just return success.
1589 : */
1590 :
1591 21 : if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1592 0 : strcsequal(fsp->fsp_name->stream_name,
1593 0 : smb_fname_dst->stream_name)) {
1594 0 : DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
1595 : "- returning success\n",
1596 : smb_fname_str_dbg(smb_fname_dst)));
1597 0 : status = NT_STATUS_OK;
1598 0 : goto out;
1599 : }
1600 :
1601 21 : old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
1602 21 : new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
1603 :
1604 : /* Return the correct error code if both names aren't streams. */
1605 21 : if (!old_is_stream && new_is_stream) {
1606 0 : status = NT_STATUS_OBJECT_NAME_INVALID;
1607 0 : goto out;
1608 : }
1609 :
1610 21 : if (old_is_stream && !new_is_stream) {
1611 0 : status = NT_STATUS_INVALID_PARAMETER;
1612 0 : goto out;
1613 : }
1614 :
1615 21 : dst_exists = vfs_stat(conn, smb_fname_dst) == 0;
1616 :
1617 21 : if(!replace_if_exists && dst_exists) {
1618 1 : DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
1619 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
1620 : smb_fname_str_dbg(smb_fname_dst)));
1621 1 : status = NT_STATUS_OBJECT_NAME_COLLISION;
1622 1 : goto out;
1623 : }
1624 :
1625 : /*
1626 : * Drop the pathref fsp on the destination otherwise we trip upon in in
1627 : * the below check for open files check.
1628 : */
1629 20 : if (smb_fname_dst_in->fsp != NULL) {
1630 0 : fd_close(smb_fname_dst_in->fsp);
1631 0 : file_free(NULL, smb_fname_dst_in->fsp);
1632 0 : SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
1633 : }
1634 :
1635 20 : if (dst_exists) {
1636 0 : struct file_id fileid = vfs_file_id_from_sbuf(conn,
1637 0 : &smb_fname_dst->st);
1638 0 : files_struct *dst_fsp = file_find_di_first(conn->sconn,
1639 : fileid, true);
1640 : /* The file can be open when renaming a stream */
1641 0 : if (dst_fsp && !new_is_stream) {
1642 0 : DEBUG(3, ("rename_internals_fsp: Target file open\n"));
1643 0 : status = NT_STATUS_ACCESS_DENIED;
1644 0 : goto out;
1645 : }
1646 : }
1647 :
1648 : /* Ensure we have a valid stat struct for the source. */
1649 20 : status = vfs_stat_fsp(fsp);
1650 20 : if (!NT_STATUS_IS_OK(status)) {
1651 0 : goto out;
1652 : }
1653 :
1654 20 : status = can_rename(conn, fsp, attrs);
1655 :
1656 20 : if (!NT_STATUS_IS_OK(status)) {
1657 0 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
1658 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
1659 : smb_fname_str_dbg(smb_fname_dst)));
1660 0 : if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
1661 0 : status = NT_STATUS_ACCESS_DENIED;
1662 0 : goto out;
1663 : }
1664 :
1665 20 : if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
1666 0 : status = NT_STATUS_ACCESS_DENIED;
1667 0 : goto out;
1668 : }
1669 :
1670 : /* Do we have rights to move into the destination ? */
1671 20 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1672 : /* We're moving a directory. */
1673 4 : access_mask = SEC_DIR_ADD_SUBDIR;
1674 : }
1675 :
1676 : /*
1677 : * Get a pathref on the destination parent directory, so
1678 : * we can call check_parent_access_fsp().
1679 : */
1680 20 : status = parent_pathref(ctx,
1681 : conn->cwd_fsp,
1682 : smb_fname_dst,
1683 : &parent_dir_fname_dst,
1684 : &parent_dir_fname_dst_atname);
1685 20 : if (!NT_STATUS_IS_OK(status)) {
1686 0 : goto out;
1687 : }
1688 :
1689 20 : status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
1690 : access_mask);
1691 20 : if (!NT_STATUS_IS_OK(status)) {
1692 0 : DBG_INFO("check_parent_access_fsp on "
1693 : "dst %s returned %s\n",
1694 : smb_fname_str_dbg(smb_fname_dst),
1695 : nt_errstr(status));
1696 0 : goto out;
1697 : }
1698 :
1699 : /*
1700 : * If the target existed, make sure the destination
1701 : * atname has the same stat struct.
1702 : */
1703 20 : parent_dir_fname_dst_atname->st = smb_fname_dst->st;
1704 :
1705 : /*
1706 : * It's very common that source and
1707 : * destination directories are the same.
1708 : * Optimize by not opening the
1709 : * second parent_pathref if we know
1710 : * this is the case.
1711 : */
1712 :
1713 20 : status = SMB_VFS_PARENT_PATHNAME(conn,
1714 : ctx,
1715 : fsp->fsp_name,
1716 : &parent_dir_fname_src,
1717 : &parent_dir_fname_src_atname);
1718 20 : if (!NT_STATUS_IS_OK(status)) {
1719 0 : goto out;
1720 : }
1721 :
1722 : /*
1723 : * We do a case-sensitive string comparison. We want to be *sure*
1724 : * this is the same path. The worst that can happen if
1725 : * the case doesn't match is we lose out on the optimization,
1726 : * the code still works.
1727 : *
1728 : * We can ignore twrp fields here. Rename is not allowed on
1729 : * shadow copy handles.
1730 : */
1731 :
1732 20 : if (strcmp(parent_dir_fname_src->base_name,
1733 20 : parent_dir_fname_dst->base_name) == 0) {
1734 : /*
1735 : * parent directory is the same for source
1736 : * and destination.
1737 : */
1738 : /* Reparent the src_atname to the parent_dir_dest fname. */
1739 16 : parent_dir_fname_src_atname = talloc_move(
1740 : parent_dir_fname_dst,
1741 : &parent_dir_fname_src_atname);
1742 : /* Free the unneeded duplicate parent name. */
1743 16 : TALLOC_FREE(parent_dir_fname_src);
1744 : /*
1745 : * And make the source parent name a copy of the
1746 : * destination parent name.
1747 : */
1748 16 : parent_dir_fname_src = parent_dir_fname_dst;
1749 : } else {
1750 : /*
1751 : * source and destination parent directories are
1752 : * different.
1753 : *
1754 : * Get a pathref on the source parent directory, so
1755 : * we can do a relative rename.
1756 : */
1757 4 : TALLOC_FREE(parent_dir_fname_src);
1758 4 : status = parent_pathref(ctx,
1759 : conn->cwd_fsp,
1760 4 : fsp->fsp_name,
1761 : &parent_dir_fname_src,
1762 : &parent_dir_fname_src_atname);
1763 4 : if (!NT_STATUS_IS_OK(status)) {
1764 0 : goto out;
1765 : }
1766 : }
1767 :
1768 : /*
1769 : * Some modules depend on the source smb_fname having a valid stat.
1770 : * The parent_dir_fname_src_atname is the relative name of the
1771 : * currently open file, so just copy the stat from the open fsp.
1772 : */
1773 20 : parent_dir_fname_src_atname->st = fsp->fsp_name->st;
1774 :
1775 20 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1776 :
1777 : /*
1778 : * We have the file open ourselves, so not being able to get the
1779 : * corresponding share mode lock is a fatal error.
1780 : */
1781 :
1782 20 : SMB_ASSERT(lck != NULL);
1783 :
1784 20 : ret = SMB_VFS_RENAMEAT(conn,
1785 : parent_dir_fname_src->fsp,
1786 : parent_dir_fname_src_atname,
1787 : parent_dir_fname_dst->fsp,
1788 : parent_dir_fname_dst_atname);
1789 20 : if (ret == 0) {
1790 20 : uint32_t create_options = fh_get_private_options(fsp->fh);
1791 :
1792 20 : DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
1793 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
1794 : smb_fname_str_dbg(smb_fname_dst)));
1795 :
1796 20 : notify_rename(conn,
1797 20 : fsp->fsp_flags.is_directory,
1798 20 : fsp->fsp_name,
1799 : smb_fname_dst);
1800 :
1801 20 : rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
1802 : smb_fname_dst);
1803 :
1804 28 : if (!fsp->fsp_flags.is_directory &&
1805 32 : !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
1806 16 : (lp_map_archive(SNUM(conn)) ||
1807 0 : lp_store_dos_attributes(SNUM(conn))))
1808 : {
1809 : /*
1810 : * We must set the archive bit on the newly renamed
1811 : * file.
1812 : */
1813 16 : status = vfs_stat_fsp(fsp);
1814 16 : if (NT_STATUS_IS_OK(status)) {
1815 : uint32_t old_dosmode;
1816 16 : old_dosmode = fdos_mode(fsp);
1817 : /*
1818 : * We can use fsp->fsp_name here as it has
1819 : * already been changed to the new name.
1820 : */
1821 16 : SMB_ASSERT(fsp->fsp_name->fsp == fsp);
1822 16 : file_set_dosmode(conn,
1823 : fsp->fsp_name,
1824 : old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
1825 : NULL,
1826 : true);
1827 : }
1828 : }
1829 :
1830 : /*
1831 : * A rename acts as a new file create w.r.t. allowing an initial delete
1832 : * on close, probably because in Windows there is a new handle to the
1833 : * new file. If initial delete on close was requested but not
1834 : * originally set, we need to set it here. This is probably not 100% correct,
1835 : * but will work for the CIFSFS client which in non-posix mode
1836 : * depends on these semantics. JRA.
1837 : */
1838 :
1839 20 : if (create_options & FILE_DELETE_ON_CLOSE) {
1840 0 : status = can_set_delete_on_close(fsp, 0);
1841 :
1842 0 : if (NT_STATUS_IS_OK(status)) {
1843 : /* Note that here we set the *initial* delete on close flag,
1844 : * not the regular one. The magic gets handled in close. */
1845 0 : fsp->fsp_flags.initial_delete_on_close = true;
1846 : }
1847 : }
1848 20 : TALLOC_FREE(lck);
1849 20 : status = NT_STATUS_OK;
1850 20 : goto out;
1851 : }
1852 :
1853 0 : TALLOC_FREE(lck);
1854 :
1855 0 : if (errno == ENOTDIR || errno == EISDIR) {
1856 0 : status = NT_STATUS_OBJECT_NAME_COLLISION;
1857 : } else {
1858 0 : status = map_nt_error_from_unix(errno);
1859 : }
1860 :
1861 0 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
1862 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
1863 : smb_fname_str_dbg(smb_fname_dst)));
1864 :
1865 21 : out:
1866 :
1867 : /*
1868 : * parent_dir_fname_src may be a copy of parent_dir_fname_dst.
1869 : * See the optimization for same source and destination directory
1870 : * above. Only free one in that case.
1871 : */
1872 21 : if (parent_dir_fname_src != parent_dir_fname_dst) {
1873 4 : TALLOC_FREE(parent_dir_fname_src);
1874 : }
1875 21 : TALLOC_FREE(parent_dir_fname_dst);
1876 21 : TALLOC_FREE(smb_fname_dst);
1877 :
1878 21 : return status;
1879 : }
1880 :
1881 : /****************************************************************************
1882 : The guts of the rename command, split out so it may be called by the NT SMB
1883 : code.
1884 : ****************************************************************************/
1885 :
1886 0 : NTSTATUS rename_internals(TALLOC_CTX *ctx,
1887 : connection_struct *conn,
1888 : struct smb_request *req,
1889 : struct files_struct *src_dirfsp,
1890 : struct smb_filename *smb_fname_src,
1891 : struct files_struct *dst_dirfsp,
1892 : struct smb_filename *smb_fname_dst,
1893 : const char *dst_original_lcomp,
1894 : uint32_t attrs,
1895 : bool replace_if_exists,
1896 : uint32_t access_mask)
1897 : {
1898 0 : NTSTATUS status = NT_STATUS_OK;
1899 0 : int create_options = 0;
1900 0 : struct smb2_create_blobs *posx = NULL;
1901 0 : struct files_struct *fsp = NULL;
1902 0 : bool posix_pathname = (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH);
1903 0 : bool case_sensitive = posix_pathname ? true : conn->case_sensitive;
1904 0 : bool case_preserve = posix_pathname ? true : conn->case_preserve;
1905 0 : bool short_case_preserve = posix_pathname ? true :
1906 0 : conn->short_case_preserve;
1907 :
1908 0 : if (posix_pathname) {
1909 0 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
1910 0 : if (!NT_STATUS_IS_OK(status)) {
1911 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
1912 : nt_errstr(status));
1913 0 : goto out;
1914 : }
1915 : }
1916 :
1917 0 : DBG_NOTICE("case_sensitive = %d, "
1918 : "case_preserve = %d, short case preserve = %d, "
1919 : "directory = %s, newname = %s, "
1920 : "last_component_dest = %s\n",
1921 : case_sensitive, case_preserve,
1922 : short_case_preserve,
1923 : smb_fname_str_dbg(smb_fname_src),
1924 : smb_fname_str_dbg(smb_fname_dst),
1925 : dst_original_lcomp);
1926 :
1927 0 : ZERO_STRUCT(smb_fname_src->st);
1928 :
1929 0 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1930 0 : if (!NT_STATUS_IS_OK(status)) {
1931 0 : if (!NT_STATUS_EQUAL(status,
1932 : NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1933 0 : goto out;
1934 : }
1935 : /*
1936 : * Possible symlink src.
1937 : */
1938 0 : if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
1939 0 : goto out;
1940 : }
1941 0 : if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
1942 0 : goto out;
1943 : }
1944 : }
1945 :
1946 0 : if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
1947 0 : create_options |= FILE_DIRECTORY_FILE;
1948 : }
1949 :
1950 0 : status = SMB_VFS_CREATE_FILE(
1951 : conn, /* conn */
1952 : req, /* req */
1953 : src_dirfsp, /* dirfsp */
1954 : smb_fname_src, /* fname */
1955 : access_mask, /* access_mask */
1956 : (FILE_SHARE_READ | /* share_access */
1957 : FILE_SHARE_WRITE),
1958 : FILE_OPEN, /* create_disposition*/
1959 : create_options, /* create_options */
1960 : 0, /* file_attributes */
1961 : 0, /* oplock_request */
1962 : NULL, /* lease */
1963 : 0, /* allocation_size */
1964 : 0, /* private_flags */
1965 : NULL, /* sd */
1966 : NULL, /* ea_list */
1967 : &fsp, /* result */
1968 : NULL, /* pinfo */
1969 : posx, /* in_context_blobs */
1970 : NULL); /* out_context_blobs */
1971 :
1972 0 : if (!NT_STATUS_IS_OK(status)) {
1973 0 : DBG_NOTICE("Could not open rename source %s: %s\n",
1974 : smb_fname_str_dbg(smb_fname_src),
1975 : nt_errstr(status));
1976 0 : goto out;
1977 : }
1978 :
1979 0 : status = rename_internals_fsp(conn,
1980 : fsp,
1981 : dst_dirfsp,
1982 : smb_fname_dst,
1983 : dst_original_lcomp,
1984 : attrs,
1985 : replace_if_exists);
1986 :
1987 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
1988 :
1989 0 : DBG_NOTICE("Error %s rename %s -> %s\n",
1990 : nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
1991 : smb_fname_str_dbg(smb_fname_dst));
1992 :
1993 0 : out:
1994 0 : TALLOC_FREE(posx);
1995 0 : return status;
1996 : }
1997 :
1998 : /*******************************************************************
1999 : Copy a file as part of a reply_copy.
2000 : ******************************************************************/
2001 :
2002 : /*
2003 : * TODO: check error codes on all callers
2004 : */
2005 :
2006 0 : NTSTATUS copy_file(TALLOC_CTX *ctx,
2007 : connection_struct *conn,
2008 : struct smb_filename *smb_fname_src,
2009 : struct smb_filename *smb_fname_dst,
2010 : uint32_t new_create_disposition)
2011 : {
2012 0 : struct smb_filename *smb_fname_dst_tmp = NULL;
2013 0 : off_t ret=-1;
2014 : files_struct *fsp1,*fsp2;
2015 : uint32_t dosattrs;
2016 : NTSTATUS status;
2017 :
2018 :
2019 0 : smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
2020 0 : if (smb_fname_dst_tmp == NULL) {
2021 0 : return NT_STATUS_NO_MEMORY;
2022 : }
2023 :
2024 0 : status = vfs_file_exist(conn, smb_fname_src);
2025 0 : if (!NT_STATUS_IS_OK(status)) {
2026 0 : goto out;
2027 : }
2028 :
2029 0 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
2030 0 : if (!NT_STATUS_IS_OK(status)) {
2031 0 : goto out;
2032 : }
2033 :
2034 : /* Open the src file for reading. */
2035 0 : status = SMB_VFS_CREATE_FILE(
2036 : conn, /* conn */
2037 : NULL, /* req */
2038 : NULL, /* dirfsp */
2039 : smb_fname_src, /* fname */
2040 : FILE_GENERIC_READ, /* access_mask */
2041 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2042 : FILE_OPEN, /* create_disposition*/
2043 : 0, /* create_options */
2044 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2045 : INTERNAL_OPEN_ONLY, /* oplock_request */
2046 : NULL, /* lease */
2047 : 0, /* allocation_size */
2048 : 0, /* private_flags */
2049 : NULL, /* sd */
2050 : NULL, /* ea_list */
2051 : &fsp1, /* result */
2052 : NULL, /* psbuf */
2053 : NULL, NULL); /* create context */
2054 :
2055 0 : if (!NT_STATUS_IS_OK(status)) {
2056 0 : goto out;
2057 : }
2058 :
2059 0 : dosattrs = fdos_mode(fsp1);
2060 :
2061 0 : if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
2062 0 : ZERO_STRUCTP(&smb_fname_dst_tmp->st);
2063 : }
2064 :
2065 0 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
2066 0 : if (!NT_STATUS_IS_OK(status) &&
2067 0 : !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
2068 : {
2069 0 : goto out;
2070 : }
2071 :
2072 : /* Open the dst file for writing. */
2073 0 : status = SMB_VFS_CREATE_FILE(
2074 : conn, /* conn */
2075 : NULL, /* req */
2076 : NULL, /* dirfsp */
2077 : smb_fname_dst, /* fname */
2078 : FILE_GENERIC_WRITE, /* access_mask */
2079 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2080 : new_create_disposition, /* create_disposition*/
2081 : 0, /* create_options */
2082 : dosattrs, /* file_attributes */
2083 : INTERNAL_OPEN_ONLY, /* oplock_request */
2084 : NULL, /* lease */
2085 : 0, /* allocation_size */
2086 : 0, /* private_flags */
2087 : NULL, /* sd */
2088 : NULL, /* ea_list */
2089 : &fsp2, /* result */
2090 : NULL, /* psbuf */
2091 : NULL, NULL); /* create context */
2092 :
2093 0 : if (!NT_STATUS_IS_OK(status)) {
2094 0 : close_file_free(NULL, &fsp1, ERROR_CLOSE);
2095 0 : goto out;
2096 : }
2097 :
2098 : /* Do the actual copy. */
2099 0 : if (smb_fname_src->st.st_ex_size) {
2100 0 : ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
2101 : } else {
2102 0 : ret = 0;
2103 : }
2104 :
2105 0 : close_file_free(NULL, &fsp1, NORMAL_CLOSE);
2106 :
2107 : /* Ensure the modtime is set correctly on the destination file. */
2108 0 : set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
2109 :
2110 : /*
2111 : * As we are opening fsp1 read-only we only expect
2112 : * an error on close on fsp2 if we are out of space.
2113 : * Thus we don't look at the error return from the
2114 : * close of fsp1.
2115 : */
2116 0 : status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
2117 :
2118 0 : if (!NT_STATUS_IS_OK(status)) {
2119 0 : goto out;
2120 : }
2121 :
2122 0 : if (ret != (off_t)smb_fname_src->st.st_ex_size) {
2123 0 : status = NT_STATUS_DISK_FULL;
2124 0 : goto out;
2125 : }
2126 :
2127 0 : status = NT_STATUS_OK;
2128 :
2129 0 : out:
2130 0 : TALLOC_FREE(smb_fname_dst_tmp);
2131 0 : return status;
2132 : }
2133 :
2134 : /****************************************************************************
2135 : Get a lock offset, dealing with large offset requests.
2136 : ****************************************************************************/
2137 :
2138 0 : uint64_t get_lock_offset(const uint8_t *data, int data_offset,
2139 : bool large_file_format)
2140 : {
2141 0 : uint64_t offset = 0;
2142 :
2143 0 : if(!large_file_format) {
2144 0 : offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
2145 : } else {
2146 : /*
2147 : * No BVAL, this is reversed!
2148 : */
2149 0 : offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
2150 0 : ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
2151 : }
2152 :
2153 0 : return offset;
2154 : }
2155 :
2156 : struct smbd_do_unlocking_state {
2157 : struct files_struct *fsp;
2158 : uint16_t num_ulocks;
2159 : struct smbd_lock_element *ulocks;
2160 : NTSTATUS status;
2161 : };
2162 :
2163 8 : static void smbd_do_unlocking_fn(
2164 : const uint8_t *buf,
2165 : size_t buflen,
2166 : bool *pmodified_dependent,
2167 : void *private_data)
2168 : {
2169 8 : struct smbd_do_unlocking_state *state = private_data;
2170 8 : struct files_struct *fsp = state->fsp;
2171 : uint16_t i;
2172 :
2173 12 : for (i = 0; i < state->num_ulocks; i++) {
2174 8 : struct smbd_lock_element *e = &state->ulocks[i];
2175 :
2176 8 : DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
2177 : "pid %"PRIu64", file %s\n",
2178 : e->offset,
2179 : e->count,
2180 : e->smblctx,
2181 : fsp_str_dbg(fsp));
2182 :
2183 8 : if (e->brltype != UNLOCK_LOCK) {
2184 : /* this can only happen with SMB2 */
2185 0 : state->status = NT_STATUS_INVALID_PARAMETER;
2186 0 : return;
2187 : }
2188 :
2189 8 : state->status = do_unlock(
2190 : fsp, e->smblctx, e->count, e->offset, e->lock_flav);
2191 :
2192 8 : DBG_DEBUG("do_unlock returned %s\n",
2193 : nt_errstr(state->status));
2194 :
2195 8 : if (!NT_STATUS_IS_OK(state->status)) {
2196 4 : return;
2197 : }
2198 : }
2199 :
2200 4 : *pmodified_dependent = true;
2201 : }
2202 :
2203 8 : NTSTATUS smbd_do_unlocking(struct smb_request *req,
2204 : files_struct *fsp,
2205 : uint16_t num_ulocks,
2206 : struct smbd_lock_element *ulocks)
2207 : {
2208 8 : struct smbd_do_unlocking_state state = {
2209 : .fsp = fsp,
2210 : .num_ulocks = num_ulocks,
2211 : .ulocks = ulocks,
2212 : };
2213 : NTSTATUS status;
2214 :
2215 8 : DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
2216 :
2217 8 : status = share_mode_do_locked(
2218 : fsp->file_id, smbd_do_unlocking_fn, &state);
2219 :
2220 8 : if (!NT_STATUS_IS_OK(status)) {
2221 0 : DBG_DEBUG("share_mode_do_locked failed: %s\n",
2222 : nt_errstr(status));
2223 0 : return status;
2224 : }
2225 8 : if (!NT_STATUS_IS_OK(state.status)) {
2226 4 : DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
2227 : nt_errstr(status));
2228 4 : return state.status;
2229 : }
2230 :
2231 4 : return NT_STATUS_OK;
2232 : }
|