LCOV - code coverage report
Current view: top level - source3/smbd - smb2_reply.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 620 838 74.0 %
Date: 2023-11-21 12:31:41 Functions: 25 26 96.2 %

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

Generated by: LCOV version 1.14