LCOV - code coverage report
Current view: top level - source3/smbd - smb2_reply.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 323 804 40.2 %
Date: 2024-06-13 04:01:37 Functions: 18 31 58.1 %

          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             : }

Generated by: LCOV version 1.13