LCOV - code coverage report
Current view: top level - source3/smbd - reply.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 2609 4406 59.2 %
Date: 2021-09-23 10:06:22 Functions: 95 119 79.8 %

          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 "fake_file.h"
      35             : #include "rpc_client/rpc_client.h"
      36             : #include "../librpc/gen_ndr/ndr_spoolss_c.h"
      37             : #include "rpc_client/cli_spoolss.h"
      38             : #include "rpc_client/init_spoolss.h"
      39             : #include "rpc_server/rpc_ncacn_np.h"
      40             : #include "libcli/security/security.h"
      41             : #include "libsmb/nmblib.h"
      42             : #include "auth.h"
      43             : #include "smbprofile.h"
      44             : #include "../lib/tsocket/tsocket.h"
      45             : #include "lib/util/tevent_ntstatus.h"
      46             : #include "libcli/smb/smb_signing.h"
      47             : #include "lib/util/sys_rw_data.h"
      48             : #include "librpc/gen_ndr/open_files.h"
      49             : #include "smb1_utils.h"
      50             : #include "libcli/smb/smb2_posix.h"
      51             : #include "lib/util/string_wrappers.h"
      52             : #include "source3/printing/rap_jobid.h"
      53             : 
      54             : /****************************************************************************
      55             :  Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
      56             :  path or anything including wildcards.
      57             :  We're assuming here that '/' is not the second byte in any multibyte char
      58             :  set (a safe assumption). '\\' *may* be the second byte in a multibyte char
      59             :  set.
      60             : ****************************************************************************/
      61             : 
      62             : /* Custom version for processing POSIX paths. */
      63             : #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
      64             : 
      65      597771 : static NTSTATUS check_path_syntax_internal(char *path,
      66             :                                            bool posix_path)
      67             : {
      68      597771 :         char *d = path;
      69      597771 :         const char *s = path;
      70      597771 :         NTSTATUS ret = NT_STATUS_OK;
      71      597771 :         bool start_of_name_component = True;
      72      597771 :         bool stream_started = false;
      73      597771 :         bool last_component_contains_wcard = false;
      74             : 
      75    15838869 :         while (*s) {
      76    14736271 :                 if (stream_started) {
      77       94662 :                         switch (*s) {
      78          24 :                         case '/':
      79             :                         case '\\':
      80          32 :                                 return NT_STATUS_OBJECT_NAME_INVALID;
      81        4920 :                         case ':':
      82        4920 :                                 if (s[1] == '\0') {
      83          36 :                                         return NT_STATUS_OBJECT_NAME_INVALID;
      84             :                                 }
      85        4884 :                                 if (strchr_m(&s[1], ':')) {
      86          12 :                                         return NT_STATUS_OBJECT_NAME_INVALID;
      87             :                                 }
      88        4871 :                                 break;
      89             :                         }
      90             :                 }
      91             : 
      92    14736199 :                 if ((*s == ':') && !posix_path && !stream_started) {
      93        6432 :                         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        6420 :                         stream_started = true;
     103        6420 :                         start_of_name_component = false;
     104        6420 :                         posix_path = true;
     105             : 
     106        6420 :                         if (s[1] == '\0') {
     107           8 :                                 return NT_STATUS_OBJECT_NAME_INVALID;
     108             :                         }
     109             :                 }
     110             : 
     111    14736179 :                 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     2594581 :                         while (IS_PATH_SEP(*s,posix_path)) {
     118      925807 :                                 s++;
     119             :                         }
     120      925351 :                         if ((d != path) && (*s != '\0')) {
     121             :                                 /* We only care about non-leading or trailing '/' or '\\' */
     122      788591 :                                 *d++ = '/';
     123             :                         }
     124             : 
     125      925351 :                         start_of_name_component = True;
     126             :                         /* New component. */
     127      925351 :                         last_component_contains_wcard = false;
     128      925351 :                         continue;
     129             :                 }
     130             : 
     131    13810828 :                 if (start_of_name_component) {
     132     1380686 :                         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         181 :                                 if ((d > path) && (*(d-1) == '/')) {
     141         104 :                                         *(d-1) = '\0';
     142         104 :                                         d--;
     143             :                                 }
     144             : 
     145             :                                 /* Are we at the start ? Can't go back further if so. */
     146         181 :                                 if (d <= path) {
     147          76 :                                         ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
     148          76 :                                         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         512 :                                 for (d--; d > path; d--) {
     155         488 :                                         if (*d == '/')
     156          80 :                                                 break;
     157             :                                 }
     158         104 :                                 s += 2; /* Else go past the .. */
     159             :                                 /* We're still at the start of a name component, just the previous one. */
     160         104 :                                 continue;
     161             : 
     162     1380505 :                         } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
     163         458 :                                 if (posix_path) {
     164             :                                         /* Eat the '.' */
     165           4 :                                         s++;
     166           4 :                                         continue;
     167             :                                 }
     168             :                         }
     169             : 
     170             :                 }
     171             : 
     172    13810643 :                 if (!(*s & 0x80)) {
     173    13679417 :                         if (!posix_path) {
     174    13551223 :                                 if (*s <= 0x1f || *s == '|') {
     175         769 :                                         return NT_STATUS_OBJECT_NAME_INVALID;
     176             :                                 }
     177    13363091 :                                 switch (*s) {
     178       12062 :                                         case '*':
     179             :                                         case '?':
     180             :                                         case '<':
     181             :                                         case '>':
     182             :                                         case '"':
     183       12062 :                                                 last_component_contains_wcard = true;
     184       12062 :                                                 break;
     185    13351029 :                                         default:
     186    13351029 :                                                 break;
     187             :                                 }
     188      121055 :                         }
     189    13678648 :                         *d++ = *s++;
     190             :                 } else {
     191             :                         size_t siz;
     192             :                         /* Get the size of the next MB character. */
     193      131226 :                         next_codepoint(s,&siz);
     194      131226 :                         switch(siz) {
     195           0 :                                 case 5:
     196           0 :                                         *d++ = *s++;
     197             :                                         FALL_THROUGH;
     198           0 :                                 case 4:
     199           0 :                                         *d++ = *s++;
     200             :                                         FALL_THROUGH;
     201      131166 :                                 case 3:
     202      131166 :                                         *d++ = *s++;
     203             :                                         FALL_THROUGH;
     204      131226 :                                 case 2:
     205      131226 :                                         *d++ = *s++;
     206             :                                         FALL_THROUGH;
     207      131226 :                                 case 1:
     208      131226 :                                         *d++ = *s++;
     209      131226 :                                         break;
     210           0 :                                 default:
     211           0 :                                         DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
     212           0 :                                         *d = '\0';
     213           0 :                                         return NT_STATUS_INVALID_PARAMETER;
     214             :                         }
     215             :                 }
     216    13622496 :                 start_of_name_component = False;
     217             :         }
     218             : 
     219      596910 :         *d = '\0';
     220             : 
     221      596910 :         return ret;
     222             : }
     223             : 
     224             : /****************************************************************************
     225             :  Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
     226             :  No wildcards allowed.
     227             : ****************************************************************************/
     228             : 
     229      596141 : NTSTATUS check_path_syntax(char *path)
     230             : {
     231      596141 :         return check_path_syntax_internal(path, false);
     232             : }
     233             : 
     234             : /****************************************************************************
     235             :  Check the path for a POSIX client.
     236             :  We're assuming here that '/' is not the second byte in any multibyte char
     237             :  set (a safe assumption).
     238             : ****************************************************************************/
     239             : 
     240        1630 : NTSTATUS check_path_syntax_posix(char *path)
     241             : {
     242        1630 :         return check_path_syntax_internal(path, true);
     243             : }
     244             : 
     245             : /****************************************************************************
     246             :  Pull a string and check the path allowing a wildcard - provide for error return.
     247             :  Passes in posix flag.
     248             : ****************************************************************************/
     249             : 
     250      144975 : static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
     251             :                         const char *base_ptr,
     252             :                         uint16_t smb_flags2,
     253             :                         char **pp_dest,
     254             :                         const char *src,
     255             :                         size_t src_len,
     256             :                         int flags,
     257             :                         bool posix_pathnames,
     258             :                         NTSTATUS *err)
     259             : {
     260             :         size_t ret;
     261             : 
     262      144975 :         *pp_dest = NULL;
     263             : 
     264      144975 :         ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
     265             :                                  src_len, flags);
     266             : 
     267      144975 :         if (!*pp_dest) {
     268           0 :                 *err = NT_STATUS_INVALID_PARAMETER;
     269           0 :                 return ret;
     270             :         }
     271             : 
     272      144975 :         if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
     273             :                 /*
     274             :                  * For a DFS path the function parse_dfs_path()
     275             :                  * will do the path processing, just make a copy.
     276             :                  */
     277         140 :                 *err = NT_STATUS_OK;
     278         140 :                 return ret;
     279             :         }
     280             : 
     281      144835 :         if (posix_pathnames) {
     282        1630 :                 *err = check_path_syntax_posix(*pp_dest);
     283             :         } else {
     284      143205 :                 *err = check_path_syntax(*pp_dest);
     285             :         }
     286             : 
     287      134687 :         return ret;
     288             : }
     289             : 
     290             : /****************************************************************************
     291             :  Pull a string and check the path - provide for error return.
     292             : ****************************************************************************/
     293             : 
     294       19593 : size_t srvstr_get_path(TALLOC_CTX *ctx,
     295             :                         const char *base_ptr,
     296             :                         uint16_t smb_flags2,
     297             :                         char **pp_dest,
     298             :                         const char *src,
     299             :                         size_t src_len,
     300             :                         int flags,
     301             :                         NTSTATUS *err)
     302             : {
     303       19593 :         return srvstr_get_path_internal(ctx,
     304             :                         base_ptr,
     305             :                         smb_flags2,
     306             :                         pp_dest,
     307             :                         src,
     308             :                         src_len,
     309             :                         flags,
     310             :                         false,
     311             :                         err);
     312             : }
     313             : 
     314             : /****************************************************************************
     315             :  Pull a string and check the path - provide for error return.
     316             :  posix_pathnames version.
     317             : ****************************************************************************/
     318             : 
     319        1442 : size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
     320             :                         const char *base_ptr,
     321             :                         uint16_t smb_flags2,
     322             :                         char **pp_dest,
     323             :                         const char *src,
     324             :                         size_t src_len,
     325             :                         int flags,
     326             :                         NTSTATUS *err)
     327             : {
     328        1442 :         return srvstr_get_path_internal(ctx,
     329             :                         base_ptr,
     330             :                         smb_flags2,
     331             :                         pp_dest,
     332             :                         src,
     333             :                         src_len,
     334             :                         flags,
     335             :                         true,
     336             :                         err);
     337             : }
     338             : 
     339             : 
     340      123940 : size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
     341             :                                  char **pp_dest, const char *src, int flags,
     342             :                                  NTSTATUS *err)
     343             : {
     344      123940 :         ssize_t bufrem = smbreq_bufrem(req, src);
     345             : 
     346      123940 :         if (bufrem < 0) {
     347           0 :                 *err = NT_STATUS_INVALID_PARAMETER;
     348           0 :                 return 0;
     349             :         }
     350             : 
     351      123940 :         if (req->posix_pathnames) {
     352         564 :                 return srvstr_get_path_internal(mem_ctx,
     353         188 :                                 (const char *)req->inbuf,
     354         188 :                                 req->flags2,
     355             :                                 pp_dest,
     356             :                                 src,
     357             :                                 bufrem,
     358             :                                 flags,
     359             :                                 true,
     360             :                                 err);
     361             :         } else {
     362      329912 :                 return srvstr_get_path_internal(mem_ctx,
     363      123752 :                                 (const char *)req->inbuf,
     364      123752 :                                 req->flags2,
     365             :                                 pp_dest,
     366             :                                 src,
     367             :                                 bufrem,
     368             :                                 flags,
     369             :                                 false,
     370             :                                 err);
     371             :         }
     372             : }
     373             : 
     374             : /**
     375             :  * pull a string from the smb_buf part of a packet. In this case the
     376             :  * string can either be null terminated or it can be terminated by the
     377             :  * end of the smbbuf area
     378             :  */
     379       41354 : size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
     380             :                               char **dest, const uint8_t *src, int flags)
     381             : {
     382       41354 :         ssize_t bufrem = smbreq_bufrem(req, src);
     383             : 
     384       41354 :         if (bufrem < 0) {
     385           0 :                 return 0;
     386             :         }
     387             : 
     388       41354 :         return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
     389             :                                   bufrem, flags);
     390             : }
     391             : 
     392             : /****************************************************************************
     393             :  Check if we have a correct fsp pointing to a file. Basic check for open fsp.
     394             : ****************************************************************************/
     395             : 
     396      193549 : bool check_fsp_open(connection_struct *conn, struct smb_request *req,
     397             :                     files_struct *fsp)
     398             : {
     399      193549 :         if ((fsp == NULL) || (conn == NULL)) {
     400        2718 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     401        2718 :                 return False;
     402             :         }
     403      190831 :         if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
     404          39 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     405          39 :                 return False;
     406             :         }
     407      189593 :         return True;
     408             : }
     409             : 
     410             : /****************************************************************************
     411             :  Check if we have a correct fsp pointing to a file.
     412             : ****************************************************************************/
     413             : 
     414      148975 : bool check_fsp(connection_struct *conn, struct smb_request *req,
     415             :                files_struct *fsp)
     416             : {
     417      148975 :         if (!check_fsp_open(conn, req, fsp)) {
     418          96 :                 return False;
     419             :         }
     420      148865 :         if (fsp->fsp_flags.is_directory) {
     421           6 :                 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
     422           6 :                 return False;
     423             :         }
     424      148859 :         if (fsp_get_pathref_fd(fsp) == -1) {
     425           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
     426           0 :                 return False;
     427             :         }
     428      148859 :         fsp->num_smb_operations++;
     429      148859 :         return True;
     430             : }
     431             : 
     432             : /****************************************************************************
     433             :  Check if we have a correct fsp pointing to a quota fake file. Replacement for
     434             :  the CHECK_NTQUOTA_HANDLE_OK macro.
     435             : ****************************************************************************/
     436             : 
     437          24 : bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
     438             :                               files_struct *fsp)
     439             : {
     440          24 :         if (!check_fsp_open(conn, req, fsp)) {
     441           0 :                 return false;
     442             :         }
     443             : 
     444          24 :         if (fsp->fsp_flags.is_directory) {
     445           4 :                 return false;
     446             :         }
     447             : 
     448          20 :         if (fsp->fake_file_handle == NULL) {
     449           0 :                 return false;
     450             :         }
     451             : 
     452          20 :         if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
     453           0 :                 return false;
     454             :         }
     455             : 
     456          20 :         if (fsp->fake_file_handle->private_data == NULL) {
     457           0 :                 return false;
     458             :         }
     459             : 
     460          20 :         return true;
     461             : }
     462             : 
     463             : /****************************************************************************
     464             :  Return the port number we've bound to on a socket.
     465             : ****************************************************************************/
     466             : 
     467        1082 : static int get_socket_port(int fd)
     468             : {
     469        1082 :         struct samba_sockaddr saddr = {
     470             :                 .sa_socklen = sizeof(struct sockaddr_storage),
     471             :         };
     472             : 
     473        1082 :         if (fd == -1) {
     474           0 :                 return -1;
     475             :         }
     476             : 
     477        1082 :         if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
     478           0 :                 int level = (errno == ENOTCONN) ? 2 : 0;
     479           0 :                 DEBUG(level, ("getsockname failed. Error was %s\n",
     480             :                                strerror(errno)));
     481           0 :                 return -1;
     482             :         }
     483             : 
     484             : #if defined(HAVE_IPV6)
     485        1082 :         if (saddr.u.sa.sa_family == AF_INET6) {
     486          85 :                 return ntohs(saddr.u.in6.sin6_port);
     487             :         }
     488             : #endif
     489         997 :         if (saddr.u.sa.sa_family == AF_INET) {
     490         997 :                 return ntohs(saddr.u.in.sin_port);
     491             :         }
     492           0 :         return -1;
     493             : }
     494             : 
     495        1082 : static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
     496             :                                      const char *name, int name_type)
     497             : {
     498             :         char *trim_name;
     499             :         char *trim_name_type;
     500             :         const char *retarget_parm;
     501             :         char *retarget;
     502             :         char *p;
     503        1082 :         int retarget_type = 0x20;
     504        1082 :         int retarget_port = NBT_SMB_PORT;
     505             :         struct sockaddr_storage retarget_addr;
     506             :         struct sockaddr_in *in_addr;
     507        1082 :         bool ret = false;
     508             :         uint8_t outbuf[10];
     509             : 
     510        1082 :         if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
     511           0 :                 return false;
     512             :         }
     513             : 
     514        1082 :         trim_name = talloc_strdup(talloc_tos(), name);
     515        1082 :         if (trim_name == NULL) {
     516           0 :                 goto fail;
     517             :         }
     518        1082 :         trim_char(trim_name, ' ', ' ');
     519             : 
     520        1082 :         trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
     521             :                                          name_type);
     522        1082 :         if (trim_name_type == NULL) {
     523           0 :                 goto fail;
     524             :         }
     525             : 
     526        1082 :         retarget_parm = lp_parm_const_string(-1, "netbios retarget",
     527             :                                              trim_name_type, NULL);
     528        1082 :         if (retarget_parm == NULL) {
     529        1082 :                 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
     530             :                                                      trim_name, NULL);
     531             :         }
     532        1082 :         if (retarget_parm == NULL) {
     533        1082 :                 goto fail;
     534             :         }
     535             : 
     536           0 :         retarget = talloc_strdup(trim_name, retarget_parm);
     537           0 :         if (retarget == NULL) {
     538           0 :                 goto fail;
     539             :         }
     540             : 
     541           0 :         DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
     542             : 
     543           0 :         p = strchr(retarget, ':');
     544           0 :         if (p != NULL) {
     545           0 :                 *p++ = '\0';
     546           0 :                 retarget_port = atoi(p);
     547             :         }
     548             : 
     549           0 :         p = strchr_m(retarget, '#');
     550           0 :         if (p != NULL) {
     551           0 :                 *p++ = '\0';
     552           0 :                 if (sscanf(p, "%x", &retarget_type) != 1) {
     553           0 :                         goto fail;
     554             :                 }
     555             :         }
     556             : 
     557           0 :         ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
     558           0 :         if (!ret) {
     559           0 :                 DEBUG(10, ("could not resolve %s\n", retarget));
     560           0 :                 goto fail;
     561             :         }
     562             : 
     563           0 :         if (retarget_addr.ss_family != AF_INET) {
     564           0 :                 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
     565           0 :                 goto fail;
     566             :         }
     567             : 
     568           0 :         in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
     569             : 
     570           0 :         _smb_setlen(outbuf, 6);
     571           0 :         SCVAL(outbuf, 0, 0x84);
     572           0 :         *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
     573           0 :         *(uint16_t *)(outbuf+8) = htons(retarget_port);
     574             : 
     575           0 :         if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
     576             :                           NULL)) {
     577           0 :                 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
     578             :                                     "failed.");
     579             :         }
     580             : 
     581           0 :         ret = true;
     582        1082 :  fail:
     583        1082 :         TALLOC_FREE(trim_name);
     584        1082 :         return ret;
     585             : }
     586             : 
     587           4 : static void reply_called_name_not_present(char *outbuf)
     588             : {
     589           4 :         smb_setlen(outbuf, 1);
     590           4 :         SCVAL(outbuf, 0, 0x83);
     591           4 :         SCVAL(outbuf, 4, 0x82);
     592           4 : }
     593             : 
     594             : /****************************************************************************
     595             :  Reply to a (netbios-level) special message. 
     596             : ****************************************************************************/
     597             : 
     598        1086 : void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
     599             : {
     600        1086 :         struct smbd_server_connection *sconn = xconn->client->sconn;
     601        1086 :         int msg_type = CVAL(inbuf,0);
     602        1086 :         int msg_flags = CVAL(inbuf,1);
     603             :         /*
     604             :          * We only really use 4 bytes of the outbuf, but for the smb_setlen
     605             :          * calculation & friends (srv_send_smb uses that) we need the full smb
     606             :          * header.
     607             :          */
     608             :         char outbuf[smb_size];
     609             : 
     610        1086 :         memset(outbuf, '\0', sizeof(outbuf));
     611             : 
     612        1086 :         smb_setlen(outbuf,0);
     613             : 
     614        1086 :         switch (msg_type) {
     615        1086 :         case NBSSrequest: /* session request */
     616             :         {
     617             :                 /* inbuf_size is guarenteed to be at least 4. */
     618             :                 fstring name1,name2;
     619             :                 int name_type1, name_type2;
     620             :                 int name_len1, name_len2;
     621             : 
     622        1086 :                 *name1 = *name2 = 0;
     623             : 
     624        1086 :                 if (xconn->transport.nbt.got_session) {
     625           0 :                         exit_server_cleanly("multiple session request not permitted");
     626             :                 }
     627             : 
     628        1086 :                 SCVAL(outbuf,0,NBSSpositive);
     629        1086 :                 SCVAL(outbuf,3,0);
     630             : 
     631             :                 /* inbuf_size is guaranteed to be at least 4. */
     632        1086 :                 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
     633        1086 :                 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
     634           0 :                         DEBUG(0,("Invalid name length in session request\n"));
     635           0 :                         reply_called_name_not_present(outbuf);
     636           0 :                         break;
     637             :                 }
     638        1086 :                 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
     639        1086 :                 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
     640           4 :                         DEBUG(0,("Invalid name length in session request\n"));
     641           4 :                         reply_called_name_not_present(outbuf);
     642           4 :                         break;
     643             :                 }
     644             : 
     645        1082 :                 name_type1 = name_extract((unsigned char *)inbuf,
     646             :                                 inbuf_size,(unsigned int)4,name1);
     647        1082 :                 name_type2 = name_extract((unsigned char *)inbuf,
     648        1082 :                                 inbuf_size,(unsigned int)(4 + name_len1),name2);
     649             : 
     650        1082 :                 if (name_type1 == -1 || name_type2 == -1) {
     651           0 :                         DEBUG(0,("Invalid name type in session request\n"));
     652           0 :                         reply_called_name_not_present(outbuf);
     653           0 :                         break;
     654             :                 }
     655             : 
     656        1082 :                 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
     657             :                          name1, name_type1, name2, name_type2));
     658             : 
     659        1082 :                 if (netbios_session_retarget(xconn, name1, name_type1)) {
     660           0 :                         exit_server_cleanly("retargeted client");
     661             :                 }
     662             : 
     663             :                 /*
     664             :                  * Windows NT/2k uses "*SMBSERVER" and XP uses
     665             :                  * "*SMBSERV" arrggg!!!
     666             :                  */
     667        1082 :                 if (strequal(name1, "*SMBSERVER     ")
     668        1082 :                     || strequal(name1, "*SMBSERV       "))  {
     669             :                         char *raddr;
     670             : 
     671           0 :                         raddr = tsocket_address_inet_addr_string(sconn->remote_address,
     672             :                                                                  talloc_tos());
     673           0 :                         if (raddr == NULL) {
     674           0 :                                 exit_server_cleanly("could not allocate raddr");
     675             :                         }
     676             : 
     677           0 :                         fstrcpy(name1, raddr);
     678             :                 }
     679             : 
     680        1082 :                 set_local_machine_name(name1, True);
     681        1082 :                 set_remote_machine_name(name2, True);
     682             : 
     683        1082 :                 if (is_ipaddress(sconn->remote_hostname)) {
     684        1082 :                         char *p = discard_const_p(char, sconn->remote_hostname);
     685             : 
     686        1082 :                         talloc_free(p);
     687             : 
     688        1082 :                         sconn->remote_hostname = talloc_strdup(sconn,
     689             :                                                 get_remote_machine_name());
     690        1082 :                         if (sconn->remote_hostname == NULL) {
     691           0 :                                 exit_server_cleanly("could not copy remote name");
     692             :                         }
     693        1082 :                         xconn->remote_hostname = sconn->remote_hostname;
     694             :                 }
     695             : 
     696        1082 :                 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
     697             :                          get_local_machine_name(), get_remote_machine_name(),
     698             :                          name_type2));
     699             : 
     700        1082 :                 if (name_type2 == 'R') {
     701             :                         /* We are being asked for a pathworks session --- 
     702             :                            no thanks! */
     703           0 :                         reply_called_name_not_present(outbuf);
     704           0 :                         break;
     705             :                 }
     706             : 
     707        1082 :                 reload_services(sconn, conn_snum_used, true);
     708        1082 :                 reopen_logs();
     709             : 
     710        1082 :                 xconn->transport.nbt.got_session = true;
     711        1082 :                 break;
     712             :         }
     713             : 
     714           0 :         case 0x89: /* session keepalive request 
     715             :                       (some old clients produce this?) */
     716           0 :                 SCVAL(outbuf,0,NBSSkeepalive);
     717           0 :                 SCVAL(outbuf,3,0);
     718           0 :                 break;
     719             : 
     720           0 :         case NBSSpositive: /* positive session response */
     721             :         case NBSSnegative: /* negative session response */
     722             :         case NBSSretarget: /* retarget session response */
     723           0 :                 DEBUG(0,("Unexpected session response\n"));
     724           0 :                 break;
     725             : 
     726           0 :         case NBSSkeepalive: /* session keepalive */
     727             :         default:
     728           0 :                 return;
     729             :         }
     730             : 
     731        1086 :         DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
     732             :                     msg_type, msg_flags));
     733             : 
     734        1086 :         if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
     735          63 :                 exit_server_cleanly("reply_special: srv_send_smb failed.");
     736             :         }
     737             : 
     738        1023 :         if (CVAL(outbuf, 0) != 0x82) {
     739           4 :                 exit_server_cleanly("invalid netbios session");
     740             :         }
     741        1019 :         return;
     742             : }
     743             : 
     744             : /****************************************************************************
     745             :  Reply to a tcon.
     746             :  conn POINTER CAN BE NULL HERE !
     747             : ****************************************************************************/
     748             : 
     749           0 : void reply_tcon(struct smb_request *req)
     750             : {
     751           0 :         connection_struct *conn = req->conn;
     752             :         const char *service;
     753           0 :         char *service_buf = NULL;
     754           0 :         char *password = NULL;
     755           0 :         char *dev = NULL;
     756           0 :         int pwlen=0;
     757             :         NTSTATUS nt_status;
     758             :         const uint8_t *p;
     759             :         const char *p2;
     760           0 :         TALLOC_CTX *ctx = talloc_tos();
     761           0 :         struct smbXsrv_connection *xconn = req->xconn;
     762           0 :         NTTIME now = timeval_to_nttime(&req->request_time);
     763             : 
     764           0 :         START_PROFILE(SMBtcon);
     765             : 
     766           0 :         if (req->buflen < 4) {
     767           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     768           0 :                 END_PROFILE(SMBtcon);
     769           0 :                 return;
     770             :         }
     771             : 
     772           0 :         p = req->buf + 1;
     773           0 :         p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
     774           0 :         p += 1;
     775           0 :         pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
     776           0 :         p += pwlen+1;
     777           0 :         p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
     778           0 :         p += 1;
     779             : 
     780           0 :         if (service_buf == NULL || password == NULL || dev == NULL) {
     781           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     782           0 :                 END_PROFILE(SMBtcon);
     783           0 :                 return;
     784             :         }
     785           0 :         p2 = strrchr_m(service_buf,'\\');
     786           0 :         if (p2) {
     787           0 :                 service = p2+1;
     788             :         } else {
     789           0 :                 service = service_buf;
     790             :         }
     791             : 
     792           0 :         conn = make_connection(req, now, service, dev,
     793             :                                req->vuid,&nt_status);
     794           0 :         req->conn = conn;
     795             : 
     796           0 :         if (!conn) {
     797           0 :                 reply_nterror(req, nt_status);
     798           0 :                 END_PROFILE(SMBtcon);
     799           0 :                 return;
     800             :         }
     801             : 
     802           0 :         reply_outbuf(req, 2, 0);
     803           0 :         SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
     804           0 :         SSVAL(req->outbuf,smb_vwv1,conn->cnum);
     805           0 :         SSVAL(req->outbuf,smb_tid,conn->cnum);
     806             : 
     807           0 :         DEBUG(3,("tcon service=%s cnum=%d\n",
     808             :                  service, conn->cnum));
     809             : 
     810           0 :         END_PROFILE(SMBtcon);
     811           0 :         return;
     812             : }
     813             : 
     814             : /****************************************************************************
     815             :  Reply to a tcon and X.
     816             :  conn POINTER CAN BE NULL HERE !
     817             : ****************************************************************************/
     818             : 
     819        7594 : void reply_tcon_and_X(struct smb_request *req)
     820             : {
     821        7246 :         const struct loadparm_substitution *lp_sub =
     822         348 :                 loadparm_s3_global_substitution();
     823        7594 :         connection_struct *conn = req->conn;
     824        7594 :         const char *service = NULL;
     825        7594 :         TALLOC_CTX *ctx = talloc_tos();
     826             :         /* what the client thinks the device is */
     827        7594 :         char *client_devicetype = NULL;
     828             :         /* what the server tells the client the share represents */
     829             :         const char *server_devicetype;
     830             :         NTSTATUS nt_status;
     831             :         int passlen;
     832        7594 :         char *path = NULL;
     833             :         const uint8_t *p;
     834             :         const char *q;
     835             :         uint16_t tcon_flags;
     836        7594 :         struct smbXsrv_session *session = NULL;
     837        7594 :         NTTIME now = timeval_to_nttime(&req->request_time);
     838        7594 :         bool session_key_updated = false;
     839        7594 :         uint16_t optional_support = 0;
     840        7594 :         struct smbXsrv_connection *xconn = req->xconn;
     841             : 
     842        7594 :         START_PROFILE(SMBtconX);
     843             : 
     844        7594 :         if (req->wct < 4) {
     845           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     846           0 :                 END_PROFILE(SMBtconX);
     847          58 :                 return;
     848             :         }
     849             : 
     850        7594 :         passlen = SVAL(req->vwv+3, 0);
     851        7594 :         tcon_flags = SVAL(req->vwv+2, 0);
     852             : 
     853             :         /* we might have to close an old one */
     854        7594 :         if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
     855             :                 struct smbXsrv_tcon *tcon;
     856             :                 NTSTATUS status;
     857             : 
     858           0 :                 tcon = conn->tcon;
     859           0 :                 req->conn = NULL;
     860           0 :                 conn = NULL;
     861             : 
     862             :                 /*
     863             :                  * TODO: cancel all outstanding requests on the tcon
     864             :                  */
     865           0 :                 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
     866           0 :                 if (!NT_STATUS_IS_OK(status)) {
     867           0 :                         DEBUG(0, ("reply_tcon_and_X: "
     868             :                                   "smbXsrv_tcon_disconnect() failed: %s\n",
     869             :                                   nt_errstr(status)));
     870             :                         /*
     871             :                          * If we hit this case, there is something completely
     872             :                          * wrong, so we better disconnect the transport connection.
     873             :                          */
     874           0 :                         END_PROFILE(SMBtconX);
     875           0 :                         exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
     876             :                         return;
     877             :                 }
     878             : 
     879           0 :                 TALLOC_FREE(tcon);
     880             :                 /*
     881             :                  * This tree id is gone. Make sure we can't re-use it
     882             :                  * by accident.
     883             :                  */
     884           0 :                 req->tid = 0;
     885             :         }
     886             : 
     887        7594 :         if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
     888           0 :                 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
     889           0 :                 END_PROFILE(SMBtconX);
     890           0 :                 return;
     891             :         }
     892             : 
     893        7594 :         if (xconn->smb1.negprot.encrypted_passwords) {
     894        7594 :                 p = req->buf + passlen;
     895             :         } else {
     896           0 :                 p = req->buf + passlen + 1;
     897             :         }
     898             : 
     899        7594 :         p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
     900             : 
     901        7594 :         if (path == NULL) {
     902           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     903           0 :                 END_PROFILE(SMBtconX);
     904           0 :                 return;
     905             :         }
     906             : 
     907             :         /*
     908             :          * the service name can be either: \\server\share
     909             :          * or share directly like on the DELL PowerVault 705
     910             :          */
     911        7594 :         if (*path=='\\') {
     912        7433 :                 q = strchr_m(path+2,'\\');
     913        7433 :                 if (!q) {
     914           0 :                         reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
     915           0 :                         END_PROFILE(SMBtconX);
     916           0 :                         return;
     917             :                 }
     918        7433 :                 service = q+1;
     919             :         } else {
     920         150 :                 service = path;
     921             :         }
     922             : 
     923        7594 :         p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
     924             :                                 &client_devicetype, p,
     925             :                                 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
     926             : 
     927        7594 :         if (client_devicetype == NULL) {
     928           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     929           0 :                 END_PROFILE(SMBtconX);
     930           0 :                 return;
     931             :         }
     932             : 
     933        7594 :         DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
     934             : 
     935        7594 :         nt_status = smb1srv_session_lookup(xconn,
     936        7594 :                                            req->vuid, now, &session);
     937        7594 :         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
     938           0 :                 reply_force_doserror(req, ERRSRV, ERRbaduid);
     939           0 :                 END_PROFILE(SMBtconX);
     940           0 :                 return;
     941             :         }
     942        7594 :         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
     943           0 :                 reply_nterror(req, nt_status);
     944           0 :                 END_PROFILE(SMBtconX);
     945           0 :                 return;
     946             :         }
     947        7594 :         if (!NT_STATUS_IS_OK(nt_status)) {
     948           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     949           0 :                 END_PROFILE(SMBtconX);
     950           0 :                 return;
     951             :         }
     952             : 
     953        7594 :         if (session->global->auth_session_info == NULL) {
     954           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     955           0 :                 END_PROFILE(SMBtconX);
     956           0 :                 return;
     957             :         }
     958             : 
     959             :         /*
     960             :          * If there is no application key defined yet
     961             :          * we create one.
     962             :          *
     963             :          * This means we setup the application key on the
     964             :          * first tcon that happens via the given session.
     965             :          *
     966             :          * Once the application key is defined, it does not
     967             :          * change any more.
     968             :          */
     969       12434 :         if (session->global->application_key_blob.length == 0 &&
     970        4840 :             smb2_signing_key_valid(session->global->signing_key))
     971             :         {
     972        4764 :                 struct smbXsrv_session *x = session;
     973        4764 :                 struct auth_session_info *session_info =
     974        4764 :                         session->global->auth_session_info;
     975             :                 uint8_t session_key[16];
     976             : 
     977        4764 :                 ZERO_STRUCT(session_key);
     978        4896 :                 memcpy(session_key, x->global->signing_key->blob.data,
     979        4764 :                        MIN(x->global->signing_key->blob.length, sizeof(session_key)));
     980             : 
     981             :                 /*
     982             :                  * The application key is truncated/padded to 16 bytes
     983             :                  */
     984        4764 :                 x->global->application_key_blob = data_blob_talloc(x->global,
     985             :                                                              session_key,
     986             :                                                              sizeof(session_key));
     987        4764 :                 ZERO_STRUCT(session_key);
     988        4764 :                 if (x->global->application_key_blob.data == NULL) {
     989           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
     990           0 :                         END_PROFILE(SMBtconX);
     991           0 :                         return;
     992             :                 }
     993        4764 :                 talloc_keep_secret(x->global->application_key_blob.data);
     994             : 
     995        4764 :                 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
     996             :                         NTSTATUS status;
     997             : 
     998        9078 :                         status = smb_key_derivation(x->global->application_key_blob.data,
     999        4630 :                                                     x->global->application_key_blob.length,
    1000        4762 :                                                     x->global->application_key_blob.data);
    1001        4762 :                         if (!NT_STATUS_IS_OK(status)) {
    1002           0 :                                 DBG_ERR("smb_key_derivation failed: %s\n",
    1003             :                                         nt_errstr(status));
    1004           0 :                                 END_PROFILE(SMBtconX);
    1005           0 :                                 return;
    1006             :                         }
    1007        4762 :                         optional_support |= SMB_EXTENDED_SIGNATURES;
    1008             :                 }
    1009             : 
    1010             :                 /*
    1011             :                  * Place the application key into the session_info
    1012             :                  */
    1013        4764 :                 data_blob_clear_free(&session_info->session_key);
    1014        4764 :                 session_info->session_key = data_blob_dup_talloc(session_info,
    1015             :                                                 x->global->application_key_blob);
    1016        4764 :                 if (session_info->session_key.data == NULL) {
    1017           0 :                         data_blob_clear_free(&x->global->application_key_blob);
    1018           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1019           0 :                         END_PROFILE(SMBtconX);
    1020           0 :                         return;
    1021             :                 }
    1022        4764 :                 talloc_keep_secret(session_info->session_key.data);
    1023        4764 :                 session_key_updated = true;
    1024             :         }
    1025             : 
    1026        7594 :         conn = make_connection(req, now, service, client_devicetype,
    1027             :                                req->vuid, &nt_status);
    1028        7594 :         req->conn =conn;
    1029             : 
    1030        7594 :         if (!conn) {
    1031          66 :                 if (session_key_updated) {
    1032           4 :                         struct smbXsrv_session *x = session;
    1033           4 :                         struct auth_session_info *session_info =
    1034           4 :                                 session->global->auth_session_info;
    1035           4 :                         data_blob_clear_free(&x->global->application_key_blob);
    1036           4 :                         data_blob_clear_free(&session_info->session_key);
    1037             :                 }
    1038          66 :                 reply_nterror(req, nt_status);
    1039          66 :                 END_PROFILE(SMBtconX);
    1040          60 :                 return;
    1041             :         }
    1042             : 
    1043        7528 :         if ( IS_IPC(conn) )
    1044        2828 :                 server_devicetype = "IPC";
    1045        4690 :         else if ( IS_PRINT(conn) )
    1046           2 :                 server_devicetype = "LPT1:";
    1047             :         else
    1048        4688 :                 server_devicetype = "A:";
    1049             : 
    1050        7528 :         if (get_Protocol() < PROTOCOL_NT1) {
    1051          22 :                 reply_outbuf(req, 2, 0);
    1052          22 :                 if (message_push_string(&req->outbuf, server_devicetype,
    1053             :                                         STR_TERMINATE|STR_ASCII) == -1) {
    1054           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1055           0 :                         END_PROFILE(SMBtconX);
    1056           0 :                         return;
    1057             :                 }
    1058             :         } else {
    1059             :                 /* NT sets the fstype of IPC$ to the null string */
    1060        7506 :                 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
    1061             : 
    1062        7506 :                 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
    1063             :                         /* Return permissions. */
    1064        7506 :                         uint32_t perm1 = 0;
    1065        7506 :                         uint32_t perm2 = 0;
    1066             : 
    1067        7506 :                         reply_outbuf(req, 7, 0);
    1068             : 
    1069        7506 :                         if (IS_IPC(conn)) {
    1070        2828 :                                 perm1 = FILE_ALL_ACCESS;
    1071        2828 :                                 perm2 = FILE_ALL_ACCESS;
    1072             :                         } else {
    1073        4668 :                                 perm1 = conn->share_access;
    1074             :                         }
    1075             : 
    1076        7506 :                         SIVAL(req->outbuf, smb_vwv3, perm1);
    1077        7506 :                         SIVAL(req->outbuf, smb_vwv5, perm2);
    1078             :                 } else {
    1079           0 :                         reply_outbuf(req, 3, 0);
    1080             :                 }
    1081             : 
    1082        7506 :                 if ((message_push_string(&req->outbuf, server_devicetype,
    1083             :                                          STR_TERMINATE|STR_ASCII) == -1)
    1084        7506 :                     || (message_push_string(&req->outbuf, fstype,
    1085             :                                             STR_TERMINATE) == -1)) {
    1086           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1087           0 :                         END_PROFILE(SMBtconX);
    1088           0 :                         return;
    1089             :                 }
    1090             : 
    1091             :                 /* what does setting this bit do? It is set by NT4 and
    1092             :                    may affect the ability to autorun mounted cdroms */
    1093        7506 :                 optional_support |= SMB_SUPPORT_SEARCH_BITS;
    1094        7506 :                 optional_support |=
    1095        7506 :                         (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
    1096             : 
    1097        7506 :                 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
    1098          26 :                         DEBUG(2,("Serving %s as a Dfs root\n",
    1099             :                                  lp_servicename(ctx, lp_sub, SNUM(conn)) ));
    1100          26 :                         optional_support |= SMB_SHARE_IN_DFS;
    1101             :                 }
    1102             : 
    1103        7506 :                 SSVAL(req->outbuf, smb_vwv2, optional_support);
    1104             :         }
    1105             : 
    1106        7528 :         SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
    1107        7528 :         SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
    1108             : 
    1109        7528 :         DEBUG(3,("tconX service=%s \n",
    1110             :                  service));
    1111             : 
    1112             :         /* set the incoming and outgoing tid to the just created one */
    1113        7528 :         SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
    1114        7528 :         SSVAL(req->outbuf,smb_tid,conn->cnum);
    1115             : 
    1116        7528 :         END_PROFILE(SMBtconX);
    1117             : 
    1118        7528 :         req->tid = conn->cnum;
    1119             : }
    1120             : 
    1121             : /****************************************************************************
    1122             :  Reply to an unknown type.
    1123             : ****************************************************************************/
    1124             : 
    1125           0 : void reply_unknown_new(struct smb_request *req, uint8_t type)
    1126             : {
    1127           0 :         DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
    1128             :                   smb_fn_name(type), type, type));
    1129           0 :         reply_force_doserror(req, ERRSRV, ERRunknownsmb);
    1130           0 :         return;
    1131             : }
    1132             : 
    1133             : /****************************************************************************
    1134             :  Reply to an ioctl.
    1135             :  conn POINTER CAN BE NULL HERE !
    1136             : ****************************************************************************/
    1137             : 
    1138      262152 : void reply_ioctl(struct smb_request *req)
    1139             : {
    1140      262152 :         const struct loadparm_substitution *lp_sub =
    1141           0 :                 loadparm_s3_global_substitution();
    1142      262152 :         connection_struct *conn = req->conn;
    1143             :         uint16_t device;
    1144             :         uint16_t function;
    1145             :         uint32_t ioctl_code;
    1146             :         int replysize;
    1147             :         char *p;
    1148             : 
    1149      262152 :         START_PROFILE(SMBioctl);
    1150             : 
    1151      262152 :         if (req->wct < 3) {
    1152           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1153           0 :                 END_PROFILE(SMBioctl);
    1154           0 :                 return;
    1155             :         }
    1156             : 
    1157      262152 :         device     = SVAL(req->vwv+1, 0);
    1158      262152 :         function   = SVAL(req->vwv+2, 0);
    1159      262152 :         ioctl_code = (device << 16) + function;
    1160             : 
    1161      262152 :         DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
    1162             : 
    1163      262152 :         switch (ioctl_code) {
    1164           8 :             case IOCTL_QUERY_JOB_INFO:
    1165           8 :                     replysize = 32;
    1166           8 :                     break;
    1167      262144 :             default:
    1168      262144 :                     reply_force_doserror(req, ERRSRV, ERRnosupport);
    1169      262144 :                     END_PROFILE(SMBioctl);
    1170      262144 :                     return;
    1171             :         }
    1172             : 
    1173           8 :         reply_outbuf(req, 8, replysize+1);
    1174           8 :         SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
    1175           8 :         SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
    1176           8 :         SSVAL(req->outbuf,smb_vwv6,52);        /* Offset to data */
    1177           8 :         p = smb_buf(req->outbuf);
    1178           8 :         memset(p, '\0', replysize+1); /* valgrind-safe. */
    1179           8 :         p += 1;          /* Allow for alignment */
    1180             : 
    1181           8 :         switch (ioctl_code) {
    1182           8 :                 case IOCTL_QUERY_JOB_INFO:                  
    1183             :                 {
    1184             :                         NTSTATUS status;
    1185           8 :                         size_t len = 0;
    1186           8 :                         files_struct *fsp = file_fsp(
    1187           8 :                                 req, SVAL(req->vwv+0, 0));
    1188           8 :                         if (!fsp) {
    1189           0 :                                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
    1190           0 :                                 END_PROFILE(SMBioctl);
    1191           0 :                                 return;
    1192             :                         }
    1193             :                         /* Job number */
    1194           8 :                         SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
    1195             : 
    1196           8 :                         status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
    1197             :                                     lp_netbios_name(), 15,
    1198             :                                     STR_TERMINATE|STR_ASCII, &len);
    1199           8 :                         if (!NT_STATUS_IS_OK(status)) {
    1200           0 :                                 reply_nterror(req, status);
    1201           0 :                                 END_PROFILE(SMBioctl);
    1202           0 :                                 return;
    1203             :                         }
    1204           8 :                         if (conn) {
    1205           8 :                                 status = srvstr_push((char *)req->outbuf, req->flags2,
    1206             :                                             p+18,
    1207             :                                             lp_servicename(talloc_tos(),
    1208             :                                                            lp_sub,
    1209             :                                                            SNUM(conn)),
    1210             :                                             13, STR_TERMINATE|STR_ASCII, &len);
    1211           8 :                                 if (!NT_STATUS_IS_OK(status)) {
    1212           0 :                                         reply_nterror(req, status);
    1213           0 :                                         END_PROFILE(SMBioctl);
    1214           0 :                                         return;
    1215             :                                 }
    1216             :                         } else {
    1217           0 :                                 memset(p+18, 0, 13);
    1218             :                         }
    1219           8 :                         break;
    1220             :                 }
    1221             :         }
    1222             : 
    1223           8 :         END_PROFILE(SMBioctl);
    1224           8 :         return;
    1225             : }
    1226             : 
    1227             : /****************************************************************************
    1228             :  Strange checkpath NTSTATUS mapping.
    1229             : ****************************************************************************/
    1230             : 
    1231        1966 : static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
    1232             : {
    1233             :         /* Strange DOS error code semantics only for checkpath... */
    1234        1970 :         if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
    1235          32 :                 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
    1236             :                         /* We need to map to ERRbadpath */
    1237          20 :                         return NT_STATUS_OBJECT_PATH_NOT_FOUND;
    1238             :                 }
    1239             :         }
    1240        1946 :         return status;
    1241             : }
    1242             : 
    1243             : /****************************************************************************
    1244             :  Reply to a checkpath.
    1245             : ****************************************************************************/
    1246             : 
    1247        1999 : void reply_checkpath(struct smb_request *req)
    1248             : {
    1249        1999 :         connection_struct *conn = req->conn;
    1250        1999 :         struct smb_filename *smb_fname = NULL;
    1251        1999 :         char *name = NULL;
    1252             :         NTSTATUS status;
    1253        1999 :         uint32_t ucf_flags = ucf_flags_from_smb_request(req);
    1254        1999 :         TALLOC_CTX *ctx = talloc_tos();
    1255             : 
    1256        1999 :         START_PROFILE(SMBcheckpath);
    1257             : 
    1258        1999 :         srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
    1259             :                             STR_TERMINATE, &status);
    1260             : 
    1261        1999 :         if (!NT_STATUS_IS_OK(status)) {
    1262         172 :                 status = map_checkpath_error(req->flags2, status);
    1263         172 :                 reply_nterror(req, status);
    1264         172 :                 END_PROFILE(SMBcheckpath);
    1265         172 :                 return;
    1266             :         }
    1267             : 
    1268        1827 :         DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
    1269             : 
    1270        1827 :         status = filename_convert(ctx,
    1271             :                                 conn,
    1272             :                                 name,
    1273             :                                 ucf_flags,
    1274             :                                 0,
    1275             :                                 &smb_fname);
    1276             : 
    1277        1827 :         if (!NT_STATUS_IS_OK(status)) {
    1278         197 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    1279           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    1280             :                                         ERRSRV, ERRbadpath);
    1281           0 :                         END_PROFILE(SMBcheckpath);
    1282           0 :                         return;
    1283             :                 }
    1284         196 :                 goto path_err;
    1285             :         }
    1286             : 
    1287        2047 :         if (!VALID_STAT(smb_fname->st) &&
    1288         417 :             (SMB_VFS_STAT(conn, smb_fname) != 0)) {
    1289         417 :                 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
    1290             :                         smb_fname_str_dbg(smb_fname), strerror(errno)));
    1291         417 :                 status = map_nt_error_from_unix(errno);
    1292         417 :                 goto path_err;
    1293             :         }
    1294             : 
    1295        1213 :         if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
    1296          29 :                 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
    1297             :                                 ERRDOS, ERRbadpath);
    1298          29 :                 goto out;
    1299             :         }
    1300             : 
    1301        1184 :         reply_outbuf(req, 0, 0);
    1302             : 
    1303        1798 :  path_err:
    1304             :         /* We special case this - as when a Windows machine
    1305             :                 is parsing a path is steps through the components
    1306             :                 one at a time - if a component fails it expects
    1307             :                 ERRbadpath, not ERRbadfile.
    1308             :         */
    1309        1802 :         status = map_checkpath_error(req->flags2, status);
    1310        1798 :         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
    1311             :                 /*
    1312             :                  * Windows returns different error codes if
    1313             :                  * the parent directory is valid but not the
    1314             :                  * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
    1315             :                  * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
    1316             :                  * if the path is invalid.
    1317             :                  */
    1318         417 :                 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
    1319             :                                 ERRDOS, ERRbadpath);
    1320         417 :                 goto out;
    1321             :         }
    1322             : 
    1323        1381 :         reply_nterror(req, status);
    1324             : 
    1325        1827 :  out:
    1326        1827 :         TALLOC_FREE(smb_fname);
    1327        1827 :         END_PROFILE(SMBcheckpath);
    1328        1822 :         return;
    1329             : }
    1330             : 
    1331             : /****************************************************************************
    1332             :  Reply to a getatr.
    1333             : ****************************************************************************/
    1334             : 
    1335        1412 : void reply_getatr(struct smb_request *req)
    1336             : {
    1337        1412 :         connection_struct *conn = req->conn;
    1338        1412 :         struct smb_filename *smb_fname = NULL;
    1339        1412 :         char *fname = NULL;
    1340        1412 :         int mode=0;
    1341        1412 :         off_t size=0;
    1342        1412 :         time_t mtime=0;
    1343             :         const char *p;
    1344             :         NTSTATUS status;
    1345        1412 :         TALLOC_CTX *ctx = talloc_tos();
    1346        1412 :         bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
    1347             : 
    1348        1412 :         START_PROFILE(SMBgetatr);
    1349             : 
    1350        1412 :         p = (const char *)req->buf + 1;
    1351        1412 :         p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
    1352        1412 :         if (!NT_STATUS_IS_OK(status)) {
    1353          24 :                 reply_nterror(req, status);
    1354          24 :                 goto out;
    1355             :         }
    1356             : 
    1357             :         /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
    1358             :                 under WfWg - weird! */
    1359        1388 :         if (*fname == '\0') {
    1360           0 :                 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
    1361           0 :                 if (!CAN_WRITE(conn)) {
    1362           0 :                         mode |= FILE_ATTRIBUTE_READONLY;
    1363             :                 }
    1364           0 :                 size = 0;
    1365           0 :                 mtime = 0;
    1366             :         } else {
    1367        1388 :                 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
    1368        1388 :                 status = filename_convert(ctx,
    1369             :                                 conn,
    1370             :                                 fname,
    1371             :                                 ucf_flags,
    1372             :                                 0,
    1373             :                                 &smb_fname);
    1374        1388 :                 if (!NT_STATUS_IS_OK(status)) {
    1375          24 :                         if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    1376           0 :                                 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    1377             :                                                 ERRSRV, ERRbadpath);
    1378           0 :                                 goto out;
    1379             :                         }
    1380          24 :                         reply_nterror(req, status);
    1381          24 :                         goto out;
    1382             :                 }
    1383        1436 :                 if (!VALID_STAT(smb_fname->st) &&
    1384          72 :                     (SMB_VFS_STAT(conn, smb_fname) != 0)) {
    1385          72 :                         DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
    1386             :                                  smb_fname_str_dbg(smb_fname),
    1387             :                                  strerror(errno)));
    1388          72 :                         reply_nterror(req,  map_nt_error_from_unix(errno));
    1389          72 :                         goto out;
    1390             :                 }
    1391             : 
    1392        1292 :                 mode = fdos_mode(smb_fname->fsp);
    1393        1292 :                 size = smb_fname->st.st_ex_size;
    1394             : 
    1395        1292 :                 if (ask_sharemode) {
    1396             :                         struct timespec write_time_ts;
    1397             :                         struct file_id fileid;
    1398             : 
    1399        1292 :                         ZERO_STRUCT(write_time_ts);
    1400        1292 :                         fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
    1401        1292 :                         get_file_infos(fileid, 0, NULL, &write_time_ts);
    1402        1292 :                         if (!is_omit_timespec(&write_time_ts)) {
    1403          12 :                                 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
    1404             :                         }
    1405             :                 }
    1406             : 
    1407        1292 :                 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
    1408        1292 :                 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
    1409          48 :                         size = 0;
    1410             :                 }
    1411             :         }
    1412             : 
    1413        1292 :         reply_outbuf(req, 10, 0);
    1414             : 
    1415        1292 :         SSVAL(req->outbuf,smb_vwv0,mode);
    1416        1292 :         if(lp_dos_filetime_resolution(SNUM(conn)) ) {
    1417           0 :                 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
    1418             :         } else {
    1419        1292 :                 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
    1420             :         }
    1421        1292 :         SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
    1422             : 
    1423        1292 :         if (get_Protocol() >= PROTOCOL_NT1) {
    1424        1292 :                 SSVAL(req->outbuf, smb_flg2,
    1425             :                       SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
    1426             :         }
    1427             : 
    1428        1292 :         DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
    1429             :                  smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
    1430             : 
    1431        1412 :  out:
    1432        1412 :         TALLOC_FREE(smb_fname);
    1433        1412 :         TALLOC_FREE(fname);
    1434        1412 :         END_PROFILE(SMBgetatr);
    1435        1412 :         return;
    1436             : }
    1437             : 
    1438             : /****************************************************************************
    1439             :  Reply to a setatr.
    1440             : ****************************************************************************/
    1441             : 
    1442        2169 : void reply_setatr(struct smb_request *req)
    1443             : {
    1444             :         struct smb_file_time ft;
    1445        2169 :         connection_struct *conn = req->conn;
    1446        2169 :         struct smb_filename *smb_fname = NULL;
    1447        2169 :         char *fname = NULL;
    1448             :         int mode;
    1449             :         time_t mtime;
    1450             :         const char *p;
    1451             :         NTSTATUS status;
    1452        2169 :         uint32_t ucf_flags = ucf_flags_from_smb_request(req);
    1453        2169 :         TALLOC_CTX *ctx = talloc_tos();
    1454             : 
    1455        2169 :         START_PROFILE(SMBsetatr);
    1456        2169 :         init_smb_file_time(&ft);
    1457             : 
    1458        2169 :         if (req->wct < 2) {
    1459           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1460           0 :                 goto out;
    1461             :         }
    1462             : 
    1463        2169 :         p = (const char *)req->buf + 1;
    1464        2169 :         p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
    1465        2169 :         if (!NT_STATUS_IS_OK(status)) {
    1466         155 :                 reply_nterror(req, status);
    1467         155 :                 goto out;
    1468             :         }
    1469             : 
    1470        2014 :         status = filename_convert(ctx,
    1471             :                                 conn,
    1472             :                                 fname,
    1473             :                                 ucf_flags,
    1474             :                                 0,
    1475             :                                 &smb_fname);
    1476        2014 :         if (!NT_STATUS_IS_OK(status)) {
    1477           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    1478           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    1479             :                                         ERRSRV, ERRbadpath);
    1480           0 :                         goto out;
    1481             :                 }
    1482           0 :                 reply_nterror(req, status);
    1483           0 :                 goto out;
    1484             :         }
    1485             : 
    1486        2014 :         if (ISDOT(smb_fname->base_name)) {
    1487             :                 /*
    1488             :                  * Not sure here is the right place to catch this
    1489             :                  * condition. Might be moved to somewhere else later -- vl
    1490             :                  */
    1491           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    1492           0 :                 goto out;
    1493             :         }
    1494             : 
    1495        2014 :         if (smb_fname->fsp == NULL) {
    1496             :                 /* Can't set access rights on a symlink. */
    1497         535 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    1498         535 :                 goto out;
    1499             :         }
    1500             : 
    1501        1479 :         mode = SVAL(req->vwv+0, 0);
    1502        1479 :         mtime = srv_make_unix_date3(req->vwv+1);
    1503             : 
    1504        1479 :         if (mode != FILE_ATTRIBUTE_NORMAL) {
    1505         739 :                 if (VALID_STAT_OF_DIR(smb_fname->st))
    1506          34 :                         mode |= FILE_ATTRIBUTE_DIRECTORY;
    1507             :                 else
    1508         705 :                         mode &= ~FILE_ATTRIBUTE_DIRECTORY;
    1509             : 
    1510         739 :                 status = smbd_check_access_rights_fsp(conn->cwd_fsp,
    1511         712 :                                         smb_fname->fsp,
    1512             :                                         false,
    1513             :                                         FILE_WRITE_ATTRIBUTES);
    1514         739 :                 if (!NT_STATUS_IS_OK(status)) {
    1515           0 :                         reply_nterror(req, status);
    1516           0 :                         goto out;
    1517             :                 }
    1518             : 
    1519         739 :                 if (file_set_dosmode(conn, smb_fname, mode, NULL,
    1520             :                                      false) != 0) {
    1521           0 :                         reply_nterror(req, map_nt_error_from_unix(errno));
    1522           0 :                         goto out;
    1523             :                 }
    1524             :         }
    1525             : 
    1526        1479 :         ft.mtime = time_t_to_full_timespec(mtime);
    1527             : 
    1528        1479 :         status = smb_set_file_time(conn, smb_fname->fsp, smb_fname, &ft, true);
    1529        1479 :         if (!NT_STATUS_IS_OK(status)) {
    1530           0 :                 reply_nterror(req, status);
    1531           0 :                 goto out;
    1532             :         }
    1533             : 
    1534        1479 :         reply_outbuf(req, 0, 0);
    1535             : 
    1536        1479 :         DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
    1537             :                  mode));
    1538        2169 :  out:
    1539        2169 :         TALLOC_FREE(smb_fname);
    1540        2169 :         END_PROFILE(SMBsetatr);
    1541        2169 :         return;
    1542             : }
    1543             : 
    1544             : /****************************************************************************
    1545             :  Reply to a dskattr.
    1546             : ****************************************************************************/
    1547             : 
    1548           0 : void reply_dskattr(struct smb_request *req)
    1549             : {
    1550           0 :         connection_struct *conn = req->conn;
    1551             :         uint64_t ret;
    1552             :         uint64_t dfree,dsize,bsize;
    1553             :         struct smb_filename smb_fname;
    1554           0 :         START_PROFILE(SMBdskattr);
    1555             : 
    1556           0 :         ZERO_STRUCT(smb_fname);
    1557           0 :         smb_fname.base_name = discard_const_p(char, ".");
    1558             : 
    1559           0 :         if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
    1560           0 :                 reply_nterror(req, map_nt_error_from_unix(errno));
    1561           0 :                 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
    1562           0 :                 END_PROFILE(SMBdskattr);
    1563           0 :                 return;
    1564             :         }
    1565             : 
    1566           0 :         ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
    1567           0 :         if (ret == (uint64_t)-1) {
    1568           0 :                 reply_nterror(req, map_nt_error_from_unix(errno));
    1569           0 :                 END_PROFILE(SMBdskattr);
    1570           0 :                 return;
    1571             :         }
    1572             : 
    1573             :         /*
    1574             :          * Force max to fit in 16 bit fields.
    1575             :          */
    1576           0 :         while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
    1577           0 :                 dfree /= 2;
    1578           0 :                 dsize /= 2;
    1579           0 :                 bsize *= 2;
    1580           0 :                 if (bsize > (WORDMAX*512)) {
    1581           0 :                         bsize = (WORDMAX*512);
    1582           0 :                         if (dsize > WORDMAX)
    1583           0 :                                 dsize = WORDMAX;
    1584           0 :                         if (dfree >  WORDMAX)
    1585           0 :                                 dfree = WORDMAX;
    1586           0 :                         break;
    1587             :                 }
    1588             :         }
    1589             : 
    1590           0 :         reply_outbuf(req, 5, 0);
    1591             : 
    1592           0 :         if (get_Protocol() <= PROTOCOL_LANMAN2) {
    1593             :                 double total_space, free_space;
    1594             :                 /* we need to scale this to a number that DOS6 can handle. We
    1595             :                    use floating point so we can handle large drives on systems
    1596             :                    that don't have 64 bit integers 
    1597             : 
    1598             :                    we end up displaying a maximum of 2G to DOS systems
    1599             :                 */
    1600           0 :                 total_space = dsize * (double)bsize;
    1601           0 :                 free_space = dfree * (double)bsize;
    1602             : 
    1603           0 :                 dsize = (uint64_t)((total_space+63*512) / (64*512));
    1604           0 :                 dfree = (uint64_t)((free_space+63*512) / (64*512));
    1605             : 
    1606           0 :                 if (dsize > 0xFFFF) dsize = 0xFFFF;
    1607           0 :                 if (dfree > 0xFFFF) dfree = 0xFFFF;
    1608             : 
    1609           0 :                 SSVAL(req->outbuf,smb_vwv0,dsize);
    1610           0 :                 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
    1611           0 :                 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
    1612           0 :                 SSVAL(req->outbuf,smb_vwv3,dfree);
    1613             :         } else {
    1614           0 :                 SSVAL(req->outbuf,smb_vwv0,dsize);
    1615           0 :                 SSVAL(req->outbuf,smb_vwv1,bsize/512);
    1616           0 :                 SSVAL(req->outbuf,smb_vwv2,512);
    1617           0 :                 SSVAL(req->outbuf,smb_vwv3,dfree);
    1618             :         }
    1619             : 
    1620           0 :         DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
    1621             : 
    1622           0 :         END_PROFILE(SMBdskattr);
    1623           0 :         return;
    1624             : }
    1625             : 
    1626             : /*
    1627             :  * Utility function to split the filename from the directory.
    1628             :  */
    1629       20029 : static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
    1630             :                                      char **fname_dir_out,
    1631             :                                      char **fname_mask_out)
    1632             : {
    1633       20029 :         const char *p = NULL;
    1634       20029 :         char *fname_dir = NULL;
    1635       20029 :         char *fname_mask = NULL;
    1636             : 
    1637       20029 :         p = strrchr_m(fname_in, '/');
    1638       20029 :         if (!p) {
    1639        4611 :                 fname_dir = talloc_strdup(ctx, ".");
    1640        4611 :                 fname_mask = talloc_strdup(ctx, fname_in);
    1641             :         } else {
    1642       15418 :                 fname_dir = talloc_strndup(ctx, fname_in,
    1643       15418 :                     PTR_DIFF(p, fname_in));
    1644       15418 :                 fname_mask = talloc_strdup(ctx, p+1);
    1645             :         }
    1646             : 
    1647       20029 :         if (!fname_dir || !fname_mask) {
    1648           0 :                 TALLOC_FREE(fname_dir);
    1649           0 :                 TALLOC_FREE(fname_mask);
    1650           0 :                 return NT_STATUS_NO_MEMORY;
    1651             :         }
    1652             : 
    1653       20029 :         *fname_dir_out = fname_dir;
    1654       20029 :         *fname_mask_out = fname_mask;
    1655       20029 :         return NT_STATUS_OK;
    1656             : }
    1657             : 
    1658             : /****************************************************************************
    1659             :  Make a dir struct.
    1660             : ****************************************************************************/
    1661             : 
    1662       20594 : static bool make_dir_struct(TALLOC_CTX *ctx,
    1663             :                             char *buf,
    1664             :                             const char *mask,
    1665             :                             const char *fname,
    1666             :                             off_t size,
    1667             :                             uint32_t mode,
    1668             :                             time_t date,
    1669             :                             bool uc)
    1670             : {
    1671             :         char *p;
    1672       20594 :         char *mask2 = talloc_strdup(ctx, mask);
    1673             : 
    1674       20594 :         if (!mask2) {
    1675           0 :                 return False;
    1676             :         }
    1677             : 
    1678       20594 :         if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
    1679        8016 :                 size = 0;
    1680             :         }
    1681             : 
    1682       20594 :         memset(buf+1,' ',11);
    1683       20594 :         if ((p = strchr_m(mask2,'.')) != NULL) {
    1684        4578 :                 *p = 0;
    1685        4578 :                 push_ascii(buf+1,mask2,8, 0);
    1686        4578 :                 push_ascii(buf+9,p+1,3, 0);
    1687        4578 :                 *p = '.';
    1688             :         } else {
    1689       16016 :                 push_ascii(buf+1,mask2,11, 0);
    1690             :         }
    1691             : 
    1692       20594 :         memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
    1693       20594 :         SCVAL(buf,21,mode);
    1694       20594 :         srv_put_dos_date(buf,22,date);
    1695       20594 :         SSVAL(buf,26,size & 0xFFFF);
    1696       20594 :         SSVAL(buf,28,(size >> 16)&0xFFFF);
    1697             :         /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
    1698             :            Strange, but verified on W2K3. Needed for OS/2. JRA. */
    1699       20594 :         push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
    1700       20594 :         DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
    1701       20594 :         return True;
    1702             : }
    1703             : 
    1704             : /****************************************************************************
    1705             :  Reply to a search.
    1706             :  Can be called from SMBsearch, SMBffirst or SMBfunique.
    1707             : ****************************************************************************/
    1708             : 
    1709         496 : void reply_search(struct smb_request *req)
    1710             : {
    1711         496 :         connection_struct *conn = req->conn;
    1712         496 :         char *path = NULL;
    1713         496 :         char *mask = NULL;
    1714         496 :         char *directory = NULL;
    1715         496 :         struct smb_filename *smb_fname = NULL;
    1716         496 :         char *fname = NULL;
    1717             :         off_t size;
    1718             :         uint32_t mode;
    1719             :         struct timespec date;
    1720             :         uint32_t dirtype;
    1721         496 :         unsigned int numentries = 0;
    1722         496 :         unsigned int maxentries = 0;
    1723         496 :         bool finished = False;
    1724             :         const char *p;
    1725             :         int status_len;
    1726             :         char status[21];
    1727         496 :         int dptr_num= -1;
    1728         496 :         bool check_descend = False;
    1729         496 :         bool expect_close = False;
    1730             :         NTSTATUS nt_status;
    1731         496 :         bool mask_contains_wcard = False;
    1732         496 :         bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
    1733         496 :         TALLOC_CTX *ctx = talloc_tos();
    1734         496 :         bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
    1735         496 :         struct smbXsrv_connection *xconn = req->xconn;
    1736         496 :         struct smbd_server_connection *sconn = req->sconn;
    1737         496 :         files_struct *fsp = NULL;
    1738         409 :         const struct loadparm_substitution *lp_sub =
    1739          87 :                 loadparm_s3_global_substitution();
    1740             : 
    1741         496 :         START_PROFILE(SMBsearch);
    1742             : 
    1743         496 :         if (req->wct < 2) {
    1744           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1745           0 :                 goto out;
    1746             :         }
    1747             : 
    1748         496 :         if (req->posix_pathnames) {
    1749           0 :                 reply_unknown_new(req, req->cmd);
    1750           0 :                 goto out;
    1751             :         }
    1752             : 
    1753             :         /* If we were called as SMBffirst then we must expect close. */
    1754         496 :         if(req->cmd == SMBffirst) {
    1755          12 :                 expect_close = True;
    1756             :         }
    1757             : 
    1758         496 :         reply_outbuf(req, 1, 3);
    1759         496 :         maxentries = SVAL(req->vwv+0, 0);
    1760         496 :         dirtype = SVAL(req->vwv+1, 0);
    1761         496 :         p = (const char *)req->buf + 1;
    1762         496 :         p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
    1763             :                                        &nt_status);
    1764         496 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1765           0 :                 reply_nterror(req, nt_status);
    1766           0 :                 goto out;
    1767             :         }
    1768             : 
    1769         496 :         if (smbreq_bufrem(req, p) < 3) {
    1770           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1771           0 :                 goto out;
    1772             :         }
    1773             : 
    1774         496 :         p++;
    1775         496 :         status_len = SVAL(p, 0);
    1776         496 :         p += 2;
    1777             : 
    1778             :         /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
    1779             : 
    1780         496 :         if (status_len == 0) {
    1781             :                 int ret;
    1782         174 :                 struct smb_filename *smb_dname = NULL;
    1783         174 :                 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
    1784         174 :                         ucf_flags_from_smb_request(req);
    1785         174 :                 nt_status = filename_convert(ctx, conn,
    1786             :                                              path,
    1787             :                                              ucf_flags,
    1788             :                                              0,
    1789             :                                              &smb_fname);
    1790         174 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    1791           0 :                         if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
    1792           0 :                                 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    1793             :                                                 ERRSRV, ERRbadpath);
    1794           0 :                                 goto out;
    1795             :                         }
    1796           0 :                         reply_nterror(req, nt_status);
    1797           0 :                         goto out;
    1798             :                 }
    1799             : 
    1800         174 :                 directory = smb_fname->base_name;
    1801             : 
    1802         174 :                 p = strrchr_m(directory,'/');
    1803         174 :                 if ((p != NULL) && (*directory != '/')) {
    1804         138 :                         mask = talloc_strdup(ctx, p + 1);
    1805         138 :                         directory = talloc_strndup(ctx, directory,
    1806         138 :                                                    PTR_DIFF(p, directory));
    1807             :                 } else {
    1808          36 :                         mask = talloc_strdup(ctx, directory);
    1809          36 :                         directory = talloc_strdup(ctx,".");
    1810             :                 }
    1811             : 
    1812         174 :                 if (!directory) {
    1813           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1814           0 :                         goto out;
    1815             :                 }
    1816             : 
    1817         174 :                 memset((char *)status,'\0',21);
    1818         174 :                 SCVAL(status,0,(dirtype & 0x1F));
    1819             : 
    1820         318 :                 smb_dname = synthetic_smb_fname(talloc_tos(),
    1821             :                                         directory,
    1822             :                                         NULL,
    1823             :                                         NULL,
    1824         174 :                                         smb_fname->twrp,
    1825         174 :                                         smb_fname->flags);
    1826         174 :                 if (smb_dname == NULL) {
    1827           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1828           0 :                         goto out;
    1829             :                 }
    1830             : 
    1831             :                 /*
    1832             :                  * As we've cut off the last component from
    1833             :                  * smb_fname we need to re-stat smb_dname
    1834             :                  * so FILE_OPEN disposition knows the directory
    1835             :                  * exists.
    1836             :                  */
    1837         174 :                 ret = vfs_stat(conn, smb_dname);
    1838         174 :                 if (ret == -1) {
    1839           0 :                         nt_status = map_nt_error_from_unix(errno);
    1840           0 :                         reply_nterror(req, nt_status);
    1841           0 :                         goto out;
    1842             :                 }
    1843             : 
    1844         174 :                 nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
    1845         174 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    1846           0 :                         reply_nterror(req, nt_status);
    1847           0 :                         goto out;
    1848             :                 }
    1849             : 
    1850             :                 /*
    1851             :                  * Open an fsp on this directory for the dptr.
    1852             :                  */
    1853         174 :                 nt_status = SMB_VFS_CREATE_FILE(
    1854             :                                 conn, /* conn */
    1855             :                                 req, /* req */
    1856             :                                 smb_dname, /* dname */
    1857             :                                 FILE_LIST_DIRECTORY, /* access_mask */
    1858             :                                 FILE_SHARE_READ|
    1859             :                                 FILE_SHARE_WRITE, /* share_access */
    1860             :                                 FILE_OPEN, /* create_disposition*/
    1861             :                                 FILE_DIRECTORY_FILE, /* create_options */
    1862             :                                 FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
    1863             :                                 NO_OPLOCK, /* oplock_request */
    1864             :                                 NULL, /* lease */
    1865             :                                 0, /* allocation_size */
    1866             :                                 0, /* private_flags */
    1867             :                                 NULL, /* sd */
    1868             :                                 NULL, /* ea_list */
    1869             :                                 &fsp, /* result */
    1870             :                                 NULL, /* pinfo */
    1871             :                                 NULL, /* in_context */
    1872             :                                 NULL);/* out_context */
    1873             : 
    1874         174 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    1875           0 :                         DBG_ERR("failed to open directory %s\n",
    1876             :                                 smb_fname_str_dbg(smb_dname));
    1877           0 :                         reply_nterror(req, nt_status);
    1878           0 :                         goto out;
    1879             :                 }
    1880             : 
    1881         318 :                 nt_status = dptr_create(conn,
    1882             :                                         NULL, /* req */
    1883             :                                         fsp, /* fsp */
    1884             :                                         True,
    1885             :                                         expect_close,
    1886         174 :                                         req->smbpid,
    1887             :                                         mask,
    1888             :                                         dirtype,
    1889         174 :                                         &fsp->dptr);
    1890             : 
    1891         174 :                 TALLOC_FREE(smb_dname);
    1892             : 
    1893         174 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    1894             :                         /*
    1895             :                          * Use NULL here for the first parameter (req)
    1896             :                          * as this is not a client visible handle so
    1897             :                          * can'tbe part of an SMB1 chain.
    1898             :                          */
    1899           0 :                         close_file(NULL, fsp, NORMAL_CLOSE);
    1900           0 :                         fsp = NULL;
    1901           0 :                         reply_nterror(req, nt_status);
    1902           0 :                         goto out;
    1903             :                 }
    1904             : 
    1905         174 :                 dptr_num = dptr_dnum(fsp->dptr);
    1906             : 
    1907             :         } else {
    1908             :                 int status_dirtype;
    1909             :                 const char *dirpath;
    1910             : 
    1911         322 :                 if (smbreq_bufrem(req, p) < 21) {
    1912           0 :                         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1913           0 :                         goto out;
    1914             :                 }
    1915             : 
    1916         322 :                 memcpy(status,p,21);
    1917         322 :                 status_dirtype = CVAL(status,0) & 0x1F;
    1918         322 :                 if (status_dirtype != (dirtype & 0x1F)) {
    1919           0 :                         dirtype = status_dirtype;
    1920             :                 }
    1921             : 
    1922         322 :                 fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
    1923         322 :                 if (fsp == NULL) {
    1924           0 :                         goto SearchEmpty;
    1925             :                 }
    1926         322 :                 dirpath = dptr_path(sconn, dptr_num);
    1927         322 :                 directory = talloc_strdup(ctx, dirpath);
    1928         322 :                 if (!directory) {
    1929           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1930           0 :                         goto out;
    1931             :                 }
    1932             : 
    1933         322 :                 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
    1934         322 :                 if (!mask) {
    1935           0 :                         goto SearchEmpty;
    1936             :                 }
    1937         322 :                 dirtype = dptr_attr(sconn, dptr_num);
    1938             :         }
    1939             : 
    1940         496 :         mask_contains_wcard = dptr_has_wild(fsp->dptr);
    1941             : 
    1942         496 :         DEBUG(4,("dptr_num is %d\n",dptr_num));
    1943             : 
    1944         496 :         if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
    1945             :                 char buf[DIR_STRUCT_SIZE];
    1946           0 :                 memcpy(buf,status,21);
    1947           0 :                 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
    1948           0 :                                 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
    1949           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1950           0 :                         goto out;
    1951             :                 }
    1952           0 :                 dptr_fill(sconn, buf+12,dptr_num);
    1953           0 :                 if (dptr_zero(buf+12) && (status_len==0)) {
    1954           0 :                         numentries = 1;
    1955             :                 } else {
    1956           0 :                         numentries = 0;
    1957             :                 }
    1958           0 :                 if (message_push_blob(&req->outbuf,
    1959             :                                       data_blob_const(buf, sizeof(buf)))
    1960             :                     == -1) {
    1961           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    1962           0 :                         goto out;
    1963             :                 }
    1964             :         } else {
    1965             :                 unsigned int i;
    1966         496 :                 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
    1967         496 :                 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
    1968             : 
    1969         496 :                 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
    1970             : 
    1971         496 :                 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
    1972             :                          directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
    1973         496 :                 if (in_list(directory, lp_dont_descend(ctx, lp_sub, SNUM(conn)),True)) {
    1974           0 :                         check_descend = True;
    1975             :                 }
    1976             : 
    1977       37016 :                 for (i=numentries;(i<maxentries) && !finished;i++) {
    1978       57138 :                         finished = !get_dir_entry(ctx,
    1979       20638 :                                                   fsp->dptr,
    1980             :                                                   mask,
    1981             :                                                   dirtype,
    1982             :                                                   &fname,
    1983             :                                                   &size,
    1984             :                                                   &mode,
    1985             :                                                   &date,
    1986             :                                                   check_descend,
    1987       20638 :                                                   ask_sharemode);
    1988       20638 :                         if (!finished) {
    1989             :                                 char buf[DIR_STRUCT_SIZE];
    1990       20594 :                                 memcpy(buf,status,21);
    1991       20594 :                                 if (!make_dir_struct(ctx,
    1992             :                                                 buf,
    1993             :                                                 mask,
    1994             :                                                 fname,
    1995             :                                                 size,
    1996             :                                                 mode,
    1997             :                                                 convert_timespec_to_time_t(date),
    1998       20594 :                                                 !allow_long_path_components)) {
    1999           0 :                                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    2000           0 :                                         goto out;
    2001             :                                 }
    2002       20594 :                                 if (!dptr_fill(sconn, buf+12,dptr_num)) {
    2003           0 :                                         break;
    2004             :                                 }
    2005       20594 :                                 if (message_push_blob(&req->outbuf,
    2006             :                                                       data_blob_const(buf, sizeof(buf)))
    2007             :                                     == -1) {
    2008           0 :                                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    2009           0 :                                         goto out;
    2010             :                                 }
    2011       20594 :                                 numentries++;
    2012             :                         }
    2013             :                 }
    2014             :         }
    2015             : 
    2016         496 :   SearchEmpty:
    2017             : 
    2018             :         /* If we were called as SMBffirst with smb_search_id == NULL
    2019             :                 and no entries were found then return error and close fsp->dptr
    2020             :                 (X/Open spec) */
    2021             : 
    2022         496 :         if (numentries == 0) {
    2023          36 :                 dptr_num = -1;
    2024          36 :                 if (fsp != NULL) {
    2025          36 :                         close_file(NULL, fsp, NORMAL_CLOSE);
    2026          36 :                         fsp = NULL;
    2027             :                 }
    2028         460 :         } else if(expect_close && status_len == 0) {
    2029             :                 /* Close the dptr - we know it's gone */
    2030           6 :                 dptr_num = -1;
    2031           6 :                 if (fsp != NULL) {
    2032           6 :                         close_file(NULL, fsp, NORMAL_CLOSE);
    2033           6 :                         fsp = NULL;
    2034             :                 }
    2035             :         }
    2036             : 
    2037             :         /* If we were called as SMBfunique, then we can close the fsp->dptr now ! */
    2038         496 :         if(dptr_num >= 0 && req->cmd == SMBfunique) {
    2039           6 :                 dptr_num = -1;
    2040             :                 /* fsp may have been closed above. */
    2041           6 :                 if (fsp != NULL) {
    2042           6 :                         close_file(NULL, fsp, NORMAL_CLOSE);
    2043           6 :                         fsp = NULL;
    2044             :                 }
    2045             :         }
    2046             : 
    2047         496 :         if ((numentries == 0) && !mask_contains_wcard) {
    2048          18 :                 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
    2049          18 :                 goto out;
    2050             :         }
    2051             : 
    2052         478 :         SSVAL(req->outbuf,smb_vwv0,numentries);
    2053         478 :         SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
    2054         478 :         SCVAL(smb_buf(req->outbuf),0,5);
    2055         478 :         SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
    2056             : 
    2057             :         /* The replies here are never long name. */
    2058         478 :         SSVAL(req->outbuf, smb_flg2,
    2059             :               SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
    2060         478 :         if (!allow_long_path_components) {
    2061           0 :                 SSVAL(req->outbuf, smb_flg2,
    2062             :                       SVAL(req->outbuf, smb_flg2)
    2063             :                       & (~FLAGS2_LONG_PATH_COMPONENTS));
    2064             :         }
    2065             : 
    2066             :         /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
    2067         478 :         SSVAL(req->outbuf, smb_flg2,
    2068             :               (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
    2069             : 
    2070         478 :         DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
    2071             :                 smb_fn_name(req->cmd),
    2072             :                 mask,
    2073             :                 directory,
    2074             :                 dirtype,
    2075             :                 numentries,
    2076             :                 maxentries ));
    2077         496 :  out:
    2078         496 :         TALLOC_FREE(directory);
    2079         496 :         TALLOC_FREE(mask);
    2080         496 :         TALLOC_FREE(smb_fname);
    2081         496 :         END_PROFILE(SMBsearch);
    2082         496 :         return;
    2083             : }
    2084             : 
    2085             : /****************************************************************************
    2086             :  Reply to a fclose (stop directory search).
    2087             : ****************************************************************************/
    2088             : 
    2089           6 : void reply_fclose(struct smb_request *req)
    2090             : {
    2091             :         int status_len;
    2092             :         char status[21];
    2093           6 :         int dptr_num= -2;
    2094             :         const char *p;
    2095           6 :         char *path = NULL;
    2096             :         NTSTATUS err;
    2097           6 :         TALLOC_CTX *ctx = talloc_tos();
    2098           6 :         struct smbd_server_connection *sconn = req->sconn;
    2099           6 :         files_struct *fsp = NULL;
    2100             : 
    2101           6 :         START_PROFILE(SMBfclose);
    2102             : 
    2103           6 :         if (req->posix_pathnames) {
    2104           0 :                 reply_unknown_new(req, req->cmd);
    2105           0 :                 END_PROFILE(SMBfclose);
    2106           0 :                 return;
    2107             :         }
    2108             : 
    2109           6 :         p = (const char *)req->buf + 1;
    2110           6 :         p += srvstr_get_path_req(ctx, req, &path, p, STR_TERMINATE,
    2111             :                                        &err);
    2112           6 :         if (!NT_STATUS_IS_OK(err)) {
    2113           0 :                 reply_nterror(req, err);
    2114           0 :                 END_PROFILE(SMBfclose);
    2115           0 :                 return;
    2116             :         }
    2117             : 
    2118           6 :         if (smbreq_bufrem(req, p) < 3) {
    2119           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    2120           0 :                 END_PROFILE(SMBfclose);
    2121           0 :                 return;
    2122             :         }
    2123             : 
    2124           6 :         p++;
    2125           6 :         status_len = SVAL(p,0);
    2126           6 :         p += 2;
    2127             : 
    2128           6 :         if (status_len == 0) {
    2129           0 :                 reply_force_doserror(req, ERRSRV, ERRsrverror);
    2130           0 :                 END_PROFILE(SMBfclose);
    2131           0 :                 return;
    2132             :         }
    2133             : 
    2134           6 :         if (smbreq_bufrem(req, p) < 21) {
    2135           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    2136           0 :                 END_PROFILE(SMBfclose);
    2137           0 :                 return;
    2138             :         }
    2139             : 
    2140           6 :         memcpy(status,p,21);
    2141             : 
    2142           6 :         fsp = dptr_fetch_fsp(sconn, status+12,&dptr_num);
    2143           6 :         if(fsp != NULL) {
    2144             :                 /*  Close the file - we know it's gone */
    2145           0 :                 close_file(NULL, fsp, NORMAL_CLOSE);
    2146           0 :                 fsp = NULL;
    2147           0 :                 dptr_num = -1;
    2148             :         }
    2149             : 
    2150           6 :         reply_outbuf(req, 1, 0);
    2151           6 :         SSVAL(req->outbuf,smb_vwv0,0);
    2152             : 
    2153           6 :         DEBUG(3,("search close\n"));
    2154             : 
    2155           6 :         END_PROFILE(SMBfclose);
    2156           6 :         return;
    2157             : }
    2158             : 
    2159             : /****************************************************************************
    2160             :  Reply to an open.
    2161             : ****************************************************************************/
    2162             : 
    2163          55 : void reply_open(struct smb_request *req)
    2164             : {
    2165          55 :         connection_struct *conn = req->conn;
    2166          55 :         struct smb_filename *smb_fname = NULL;
    2167          55 :         char *fname = NULL;
    2168          55 :         uint32_t fattr=0;
    2169          55 :         off_t size = 0;
    2170          55 :         time_t mtime=0;
    2171             :         int info;
    2172             :         files_struct *fsp;
    2173             :         int oplock_request;
    2174             :         int deny_mode;
    2175             :         uint32_t dos_attr;
    2176             :         uint32_t access_mask;
    2177             :         uint32_t share_mode;
    2178             :         uint32_t create_disposition;
    2179          55 :         uint32_t create_options = 0;
    2180          55 :         uint32_t private_flags = 0;
    2181             :         NTSTATUS status;
    2182             :         uint32_t ucf_flags;
    2183          55 :         TALLOC_CTX *ctx = talloc_tos();
    2184             : 
    2185          55 :         START_PROFILE(SMBopen);
    2186             : 
    2187          55 :         if (req->wct < 2) {
    2188           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    2189           0 :                 goto out;
    2190             :         }
    2191             : 
    2192          55 :         oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
    2193          55 :         deny_mode = SVAL(req->vwv+0, 0);
    2194          55 :         dos_attr = SVAL(req->vwv+1, 0);
    2195             : 
    2196          55 :         srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
    2197             :                             STR_TERMINATE, &status);
    2198          55 :         if (!NT_STATUS_IS_OK(status)) {
    2199           0 :                 reply_nterror(req, status);
    2200           0 :                 goto out;
    2201             :         }
    2202             : 
    2203          55 :         if (!map_open_params_to_ntcreate(fname, deny_mode,
    2204             :                                          OPENX_FILE_EXISTS_OPEN, &access_mask,
    2205             :                                          &share_mode, &create_disposition,
    2206             :                                          &create_options, &private_flags)) {
    2207           0 :                 reply_force_doserror(req, ERRDOS, ERRbadaccess);
    2208           0 :                 goto out;
    2209             :         }
    2210             : 
    2211          55 :         ucf_flags = filename_create_ucf_flags(req, create_disposition);
    2212             : 
    2213          55 :         status = filename_convert(ctx,
    2214             :                                 conn,
    2215             :                                 fname,
    2216             :                                 ucf_flags,
    2217             :                                 0,
    2218             :                                 &smb_fname);
    2219          55 :         if (!NT_STATUS_IS_OK(status)) {
    2220           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    2221           0 :                         reply_botherror(req,
    2222             :                                         NT_STATUS_PATH_NOT_COVERED,
    2223             :                                         ERRSRV, ERRbadpath);
    2224           0 :                         goto out;
    2225             :                 }
    2226           0 :                 reply_nterror(req, status);
    2227           0 :                 goto out;
    2228             :         }
    2229             : 
    2230          55 :         status = SMB_VFS_CREATE_FILE(
    2231             :                 conn,                                   /* conn */
    2232             :                 req,                                    /* req */
    2233             :                 smb_fname,                              /* fname */
    2234             :                 access_mask,                            /* access_mask */
    2235             :                 share_mode,                             /* share_access */
    2236             :                 create_disposition,                     /* create_disposition*/
    2237             :                 create_options,                         /* create_options */
    2238             :                 dos_attr,                               /* file_attributes */
    2239             :                 oplock_request,                         /* oplock_request */
    2240             :                 NULL,                                   /* lease */
    2241             :                 0,                                      /* allocation_size */
    2242             :                 private_flags,
    2243             :                 NULL,                                   /* sd */
    2244             :                 NULL,                                   /* ea_list */
    2245             :                 &fsp,                                       /* result */
    2246             :                 &info,                                      /* pinfo */
    2247             :                 NULL, NULL);                            /* create context */
    2248             : 
    2249          55 :         if (!NT_STATUS_IS_OK(status)) {
    2250          20 :                 if (open_was_deferred(req->xconn, req->mid)) {
    2251             :                         /* We have re-scheduled this call. */
    2252           0 :                         goto out;
    2253             :                 }
    2254             : 
    2255          20 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
    2256           5 :                         reply_openerror(req, status);
    2257           5 :                         goto out;
    2258             :                 }
    2259             : 
    2260          15 :                 fsp = fcb_or_dos_open(
    2261             :                         req,
    2262             :                         smb_fname,
    2263             :                         access_mask,
    2264             :                         create_options,
    2265             :                         private_flags);
    2266          15 :                 if (fsp == NULL) {
    2267          10 :                         bool ok = defer_smb1_sharing_violation(req);
    2268          10 :                         if (ok) {
    2269           4 :                                 goto out;
    2270             :                         }
    2271           5 :                         reply_openerror(req, status);
    2272           5 :                         goto out;
    2273             :                 }
    2274             :         }
    2275             : 
    2276             :         /* Ensure we're pointing at the correct stat struct. */
    2277          40 :         TALLOC_FREE(smb_fname);
    2278          40 :         smb_fname = fsp->fsp_name;
    2279             : 
    2280          40 :         size = smb_fname->st.st_ex_size;
    2281          40 :         fattr = fdos_mode(fsp);
    2282             : 
    2283          40 :         mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
    2284             : 
    2285          40 :         if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
    2286           0 :                 DEBUG(3,("attempt to open a directory %s\n",
    2287             :                          fsp_str_dbg(fsp)));
    2288           0 :                 close_file(req, fsp, ERROR_CLOSE);
    2289           0 :                 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
    2290             :                         ERRDOS, ERRnoaccess);
    2291           0 :                 goto out;
    2292             :         }
    2293             : 
    2294          40 :         reply_outbuf(req, 7, 0);
    2295          40 :         SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
    2296          40 :         SSVAL(req->outbuf,smb_vwv1,fattr);
    2297          40 :         if(lp_dos_filetime_resolution(SNUM(conn)) ) {
    2298           0 :                 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
    2299             :         } else {
    2300          40 :                 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
    2301             :         }
    2302          40 :         SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
    2303          40 :         SSVAL(req->outbuf,smb_vwv6,deny_mode);
    2304             : 
    2305          40 :         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
    2306           0 :                 SCVAL(req->outbuf,smb_flg,
    2307             :                       CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    2308             :         }
    2309             : 
    2310          40 :         if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
    2311           0 :                 SCVAL(req->outbuf,smb_flg,
    2312             :                       CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    2313             :         }
    2314          85 :  out:
    2315          55 :         END_PROFILE(SMBopen);
    2316          55 :         return;
    2317             : }
    2318             : 
    2319             : /****************************************************************************
    2320             :  Reply to an open and X.
    2321             : ****************************************************************************/
    2322             : 
    2323       23332 : void reply_open_and_X(struct smb_request *req)
    2324             : {
    2325       23332 :         connection_struct *conn = req->conn;
    2326       23332 :         struct smb_filename *smb_fname = NULL;
    2327       23332 :         char *fname = NULL;
    2328             :         uint16_t open_flags;
    2329             :         int deny_mode;
    2330             :         uint32_t smb_attr;
    2331             :         /* Breakout the oplock request bits so we can set the
    2332             :                 reply bits separately. */
    2333             :         int ex_oplock_request;
    2334             :         int core_oplock_request;
    2335             :         int oplock_request;
    2336             : #if 0
    2337             :         int smb_sattr = SVAL(req->vwv+4, 0);
    2338             :         uint32_t smb_time = make_unix_date3(req->vwv+6);
    2339             : #endif
    2340             :         int smb_ofun;
    2341       23332 :         uint32_t fattr=0;
    2342       23332 :         int mtime=0;
    2343       23332 :         int smb_action = 0;
    2344             :         files_struct *fsp;
    2345             :         NTSTATUS status;
    2346             :         uint64_t allocation_size;
    2347       23332 :         ssize_t retval = -1;
    2348             :         uint32_t access_mask;
    2349             :         uint32_t share_mode;
    2350             :         uint32_t create_disposition;
    2351       23332 :         uint32_t create_options = 0;
    2352       23332 :         uint32_t private_flags = 0;
    2353             :         uint32_t ucf_flags;
    2354       23332 :         TALLOC_CTX *ctx = talloc_tos();
    2355             : 
    2356       23332 :         START_PROFILE(SMBopenX);
    2357             : 
    2358       23332 :         if (req->wct < 15) {
    2359           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    2360           0 :                 goto out;
    2361             :         }
    2362             : 
    2363       23332 :         open_flags = SVAL(req->vwv+2, 0);
    2364       23332 :         deny_mode = SVAL(req->vwv+3, 0);
    2365       23332 :         smb_attr = SVAL(req->vwv+5, 0);
    2366       23332 :         ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
    2367       23332 :         core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
    2368       23332 :         oplock_request = ex_oplock_request | core_oplock_request;
    2369       23332 :         smb_ofun = SVAL(req->vwv+8, 0);
    2370       23332 :         allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
    2371             : 
    2372             :         /* If it's an IPC, pass off the pipe handler. */
    2373       23332 :         if (IS_IPC(conn)) {
    2374          40 :                 if (lp_nt_pipe_support()) {
    2375          40 :                         reply_open_pipe_and_X(conn, req);
    2376             :                 } else {
    2377           0 :                         reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
    2378             :                 }
    2379          40 :                 goto out;
    2380             :         }
    2381             : 
    2382             :         /* XXXX we need to handle passed times, sattr and flags */
    2383       23292 :         srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
    2384             :                         STR_TERMINATE, &status);
    2385       23292 :         if (!NT_STATUS_IS_OK(status)) {
    2386          32 :                 reply_nterror(req, status);
    2387          32 :                 goto out;
    2388             :         }
    2389             : 
    2390       23260 :         if (!map_open_params_to_ntcreate(fname, deny_mode,
    2391             :                                          smb_ofun,
    2392             :                                          &access_mask, &share_mode,
    2393             :                                          &create_disposition,
    2394             :                                          &create_options,
    2395             :                                          &private_flags)) {
    2396          18 :                 reply_force_doserror(req, ERRDOS, ERRbadaccess);
    2397          18 :                 goto out;
    2398             :         }
    2399             : 
    2400       23242 :         ucf_flags = filename_create_ucf_flags(req, create_disposition);
    2401             : 
    2402       23242 :         status = filename_convert(ctx,
    2403             :                                 conn,
    2404             :                                 fname,
    2405             :                                 ucf_flags,
    2406             :                                 0,
    2407             :                                 &smb_fname);
    2408       23242 :         if (!NT_STATUS_IS_OK(status)) {
    2409          40 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    2410           0 :                         reply_botherror(req,
    2411             :                                         NT_STATUS_PATH_NOT_COVERED,
    2412             :                                         ERRSRV, ERRbadpath);
    2413           0 :                         goto out;
    2414             :                 }
    2415          40 :                 reply_nterror(req, status);
    2416          40 :                 goto out;
    2417             :         }
    2418             : 
    2419       23202 :         status = SMB_VFS_CREATE_FILE(
    2420             :                 conn,                                   /* conn */
    2421             :                 req,                                    /* req */
    2422             :                 smb_fname,                              /* fname */
    2423             :                 access_mask,                            /* access_mask */
    2424             :                 share_mode,                             /* share_access */
    2425             :                 create_disposition,                     /* create_disposition*/
    2426             :                 create_options,                         /* create_options */
    2427             :                 smb_attr,                               /* file_attributes */
    2428             :                 oplock_request,                         /* oplock_request */
    2429             :                 NULL,                                   /* lease */
    2430             :                 0,                                      /* allocation_size */
    2431             :                 private_flags,
    2432             :                 NULL,                                   /* sd */
    2433             :                 NULL,                                   /* ea_list */
    2434             :                 &fsp,                                       /* result */
    2435             :                 &smb_action,                                /* pinfo */
    2436             :                 NULL, NULL);                            /* create context */
    2437             : 
    2438       23202 :         if (!NT_STATUS_IS_OK(status)) {
    2439        4609 :                 if (open_was_deferred(req->xconn, req->mid)) {
    2440             :                         /* We have re-scheduled this call. */
    2441          24 :                         goto out;
    2442             :                 }
    2443             : 
    2444        4585 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
    2445         185 :                         reply_openerror(req, status);
    2446         185 :                         goto out;
    2447             :                 }
    2448             : 
    2449        4400 :                 fsp = fcb_or_dos_open(
    2450             :                         req,
    2451             :                         smb_fname,
    2452             :                         access_mask,
    2453             :                         create_options,
    2454             :                         private_flags);
    2455        4400 :                 if (fsp == NULL) {
    2456        4292 :                         bool ok = defer_smb1_sharing_violation(req);
    2457        4292 :                         if (ok) {
    2458        2144 :                                 goto out;
    2459             :                         }
    2460        2146 :                         reply_openerror(req, status);
    2461        2146 :                         goto out;
    2462             :                 }
    2463             : 
    2464             : 
    2465         108 :                 smb_action = FILE_WAS_OPENED;
    2466             :         }
    2467             : 
    2468             :         /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
    2469             :            if the file is truncated or created. */
    2470       18701 :         if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
    2471          44 :                 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
    2472          44 :                 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
    2473           0 :                         close_file(req, fsp, ERROR_CLOSE);
    2474           0 :                         reply_nterror(req, NT_STATUS_DISK_FULL);
    2475           0 :                         goto out;
    2476             :                 }
    2477          44 :                 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
    2478          44 :                 if (retval < 0) {
    2479           0 :                         close_file(req, fsp, ERROR_CLOSE);
    2480           0 :                         reply_nterror(req, NT_STATUS_DISK_FULL);
    2481           0 :                         goto out;
    2482             :                 }
    2483          44 :                 status = vfs_stat_fsp(fsp);
    2484          44 :                 if (!NT_STATUS_IS_OK(status)) {
    2485           0 :                         close_file(req, fsp, ERROR_CLOSE);
    2486           0 :                         reply_nterror(req, status);
    2487           0 :                         goto out;
    2488             :                 }
    2489             :         }
    2490             : 
    2491       18701 :         fattr = fdos_mode(fsp);
    2492       18701 :         if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
    2493           0 :                 close_file(req, fsp, ERROR_CLOSE);
    2494           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    2495           0 :                 goto out;
    2496             :         }
    2497       18701 :         mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
    2498             : 
    2499             :         /* If the caller set the extended oplock request bit
    2500             :                 and we granted one (by whatever means) - set the
    2501             :                 correct bit for extended oplock reply.
    2502             :         */
    2503             : 
    2504       18701 :         if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
    2505           0 :                 smb_action |= EXTENDED_OPLOCK_GRANTED;
    2506             :         }
    2507             : 
    2508       18701 :         if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
    2509          16 :                 smb_action |= EXTENDED_OPLOCK_GRANTED;
    2510             :         }
    2511             : 
    2512             :         /* If the caller set the core oplock request bit
    2513             :                 and we granted one (by whatever means) - set the
    2514             :                 correct bit for core oplock reply.
    2515             :         */
    2516             : 
    2517       18701 :         if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
    2518           5 :                 reply_outbuf(req, 19, 0);
    2519             :         } else {
    2520       18696 :                 reply_outbuf(req, 15, 0);
    2521             :         }
    2522             : 
    2523       18701 :         SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
    2524       18701 :         SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
    2525             : 
    2526       18701 :         if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
    2527           0 :                 SCVAL(req->outbuf, smb_flg,
    2528             :                       CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    2529             :         }
    2530             : 
    2531       18701 :         if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
    2532          16 :                 SCVAL(req->outbuf, smb_flg,
    2533             :                       CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    2534             :         }
    2535             : 
    2536       18701 :         SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
    2537       18701 :         SSVAL(req->outbuf,smb_vwv3,fattr);
    2538       18701 :         if(lp_dos_filetime_resolution(SNUM(conn)) ) {
    2539           0 :                 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
    2540             :         } else {
    2541       18701 :                 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
    2542             :         }
    2543       18701 :         SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
    2544       18701 :         SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
    2545       18701 :         SSVAL(req->outbuf,smb_vwv11,smb_action);
    2546             : 
    2547       18701 :         if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
    2548           5 :                 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
    2549             :         }
    2550             : 
    2551       39631 :  out:
    2552       23332 :         TALLOC_FREE(smb_fname);
    2553       23332 :         END_PROFILE(SMBopenX);
    2554       23332 :         return;
    2555             : }
    2556             : 
    2557             : /****************************************************************************
    2558             :  Reply to a SMBulogoffX.
    2559             : ****************************************************************************/
    2560             : 
    2561             : static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
    2562             :                                 struct smbXsrv_session *session);
    2563             : static void reply_ulogoffX_done(struct tevent_req *req);
    2564             : 
    2565          12 : void reply_ulogoffX(struct smb_request *smb1req)
    2566             : {
    2567          12 :         struct timeval now = timeval_current();
    2568          12 :         struct smbXsrv_session *session = NULL;
    2569             :         struct tevent_req *req;
    2570             :         NTSTATUS status;
    2571             : 
    2572             :         /*
    2573             :          * Don't setup the profile charge here, take
    2574             :          * it in reply_ulogoffX_done(). Not strictly correct
    2575             :          * but better than the other SMB1 async
    2576             :          * code that double-charges at the moment.
    2577             :          */
    2578             : 
    2579          23 :         status = smb1srv_session_lookup(smb1req->xconn,
    2580          12 :                                         smb1req->vuid,
    2581             :                                         timeval_to_nttime(&now),
    2582             :                                         &session);
    2583          12 :         if (!NT_STATUS_IS_OK(status)) {
    2584             :                 /* Not going async, profile here. */
    2585           0 :                 START_PROFILE(SMBulogoffX);
    2586           0 :                 DBG_WARNING("ulogoff, vuser id %llu does not map to user.\n",
    2587             :                          (unsigned long long)smb1req->vuid);
    2588             : 
    2589           0 :                 smb1req->vuid = UID_FIELD_INVALID;
    2590           0 :                 reply_force_doserror(smb1req, ERRSRV, ERRbaduid);
    2591           0 :                 END_PROFILE(SMBulogoffX);
    2592           0 :                 return;
    2593             :         }
    2594             : 
    2595          12 :         req = reply_ulogoffX_send(smb1req, session);
    2596          12 :         if (req == NULL) {
    2597             :                 /* Not going async, profile here. */
    2598           0 :                 START_PROFILE(SMBulogoffX);
    2599           0 :                 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
    2600           0 :                 END_PROFILE(SMBulogoffX);
    2601           0 :                 return;
    2602             :         }
    2603             : 
    2604             :         /* We're async. This will complete later. */
    2605          12 :         tevent_req_set_callback(req, reply_ulogoffX_done, smb1req);
    2606          12 :         return;
    2607             : }
    2608             : 
    2609             : struct reply_ulogoffX_state {
    2610             :         struct tevent_queue *wait_queue;
    2611             :         struct smbXsrv_session *session;
    2612             : };
    2613             : 
    2614             : static void reply_ulogoffX_wait_done(struct tevent_req *subreq);
    2615             : 
    2616             : /****************************************************************************
    2617             :  Async SMB1 ulogoffX.
    2618             :  Note, on failure here we deallocate and return NULL to allow the caller to
    2619             :  SMB1 return an error of ERRnomem immediately.
    2620             : ****************************************************************************/
    2621             : 
    2622          12 : static struct tevent_req *reply_ulogoffX_send(struct smb_request *smb1req,
    2623             :                                         struct smbXsrv_session *session)
    2624             : {
    2625             :         struct tevent_req *req;
    2626             :         struct reply_ulogoffX_state *state;
    2627             :         struct tevent_req *subreq;
    2628             :         files_struct *fsp;
    2629          12 :         struct smbd_server_connection *sconn = session->client->sconn;
    2630          12 :         uint64_t vuid = session->global->session_wire_id;
    2631             : 
    2632          12 :         req = tevent_req_create(smb1req, &state,
    2633             :                         struct reply_ulogoffX_state);
    2634          12 :         if (req == NULL) {
    2635           0 :                 return NULL;
    2636             :         }
    2637          12 :         state->wait_queue = tevent_queue_create(state,
    2638             :                                 "reply_ulogoffX_wait_queue");
    2639          12 :         if (tevent_req_nomem(state->wait_queue, req)) {
    2640           0 :                 TALLOC_FREE(req);
    2641           0 :                 return NULL;
    2642             :         }
    2643          12 :         state->session = session;
    2644             : 
    2645             :         /*
    2646             :          * Make sure that no new request will be able to use this session.
    2647             :          * This ensures that once all outstanding fsp->aio_requests
    2648             :          * on this session are done, we are safe to close it.
    2649             :          */
    2650          12 :         session->status = NT_STATUS_USER_SESSION_DELETED;
    2651             : 
    2652          20 :         for (fsp = sconn->files; fsp; fsp = fsp->next) {
    2653           8 :                 if (fsp->vuid != vuid) {
    2654           0 :                         continue;
    2655             :                 }
    2656             :                 /*
    2657             :                  * Flag the file as close in progress.
    2658             :                  * This will prevent any more IO being
    2659             :                  * done on it.
    2660             :                  */
    2661           8 :                 fsp->fsp_flags.closing = true;
    2662             : 
    2663           8 :                 if (fsp->num_aio_requests > 0) {
    2664             :                         /*
    2665             :                          * Now wait until all aio requests on this fsp are
    2666             :                          * finished.
    2667             :                          *
    2668             :                          * We don't set a callback, as we just want to block the
    2669             :                          * wait queue and the talloc_free() of fsp->aio_request
    2670             :                          * will remove the item from the wait queue.
    2671             :                          */
    2672           0 :                         subreq = tevent_queue_wait_send(fsp->aio_requests,
    2673             :                                                 sconn->ev_ctx,
    2674           0 :                                                 state->wait_queue);
    2675           0 :                         if (tevent_req_nomem(subreq, req)) {
    2676           0 :                                 TALLOC_FREE(req);
    2677           0 :                                 return NULL;
    2678             :                         }
    2679             :                 }
    2680             :         }
    2681             : 
    2682             :         /*
    2683             :          * Now we add our own waiter to the end of the queue,
    2684             :          * this way we get notified when all pending requests are finished
    2685             :          * and reply to the outstanding SMB1 request.
    2686             :          */
    2687          12 :         subreq = tevent_queue_wait_send(state,
    2688             :                                 sconn->ev_ctx,
    2689          12 :                                 state->wait_queue);
    2690          12 :         if (tevent_req_nomem(subreq, req)) {
    2691           0 :                 TALLOC_FREE(req);
    2692           0 :                 return NULL;
    2693             :         }
    2694             : 
    2695             :         /*
    2696             :          * We're really going async - move the SMB1 request from
    2697             :          * a talloc stackframe above us to the sconn talloc-context.
    2698             :          * We need this to stick around until the wait_done
    2699             :          * callback is invoked.
    2700             :          */
    2701          12 :         smb1req = talloc_move(sconn, &smb1req);
    2702             : 
    2703          12 :         tevent_req_set_callback(subreq, reply_ulogoffX_wait_done, req);
    2704             : 
    2705          12 :         return req;
    2706             : }
    2707             : 
    2708          12 : static void reply_ulogoffX_wait_done(struct tevent_req *subreq)
    2709             : {
    2710          12 :         struct tevent_req *req = tevent_req_callback_data(
    2711             :                 subreq, struct tevent_req);
    2712             : 
    2713          12 :         tevent_queue_wait_recv(subreq);
    2714          12 :         TALLOC_FREE(subreq);
    2715          12 :         tevent_req_done(req);
    2716          12 : }
    2717             : 
    2718          12 : static NTSTATUS reply_ulogoffX_recv(struct tevent_req *req)
    2719             : {
    2720          12 :         return tevent_req_simple_recv_ntstatus(req);
    2721             : }
    2722             : 
    2723          12 : static void reply_ulogoffX_done(struct tevent_req *req)
    2724             : {
    2725          12 :         struct smb_request *smb1req = tevent_req_callback_data(
    2726             :                 req, struct smb_request);
    2727          12 :         struct reply_ulogoffX_state *state = tevent_req_data(req,
    2728             :                                                 struct reply_ulogoffX_state);
    2729          12 :         struct smbXsrv_session *session = state->session;
    2730             :         NTSTATUS status;
    2731             : 
    2732             :         /*
    2733             :          * Take the profile charge here. Not strictly
    2734             :          * correct but better than the other SMB1 async
    2735             :          * code that double-charges at the moment.
    2736             :          */
    2737          12 :         START_PROFILE(SMBulogoffX);
    2738             : 
    2739          12 :         status = reply_ulogoffX_recv(req);
    2740          12 :         TALLOC_FREE(req);
    2741          12 :         if (!NT_STATUS_IS_OK(status)) {
    2742           0 :                 TALLOC_FREE(smb1req);
    2743           0 :                 END_PROFILE(SMBulogoffX);
    2744           0 :                 exit_server(__location__ ": reply_ulogoffX_recv failed");
    2745             :                 return;
    2746             :         }
    2747             : 
    2748          12 :         status = smbXsrv_session_logoff(session);
    2749          12 :         if (!NT_STATUS_IS_OK(status)) {
    2750           0 :                 TALLOC_FREE(smb1req);
    2751           0 :                 END_PROFILE(SMBulogoffX);
    2752           0 :                 exit_server(__location__ ": smbXsrv_session_logoff failed");
    2753             :                 return;
    2754             :         }
    2755             : 
    2756          12 :         TALLOC_FREE(session);
    2757             : 
    2758          12 :         reply_outbuf(smb1req, 2, 0);
    2759          12 :         SSVAL(smb1req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
    2760          12 :         SSVAL(smb1req->outbuf, smb_vwv1, 0);    /* no andx offset */
    2761             : 
    2762          12 :         DBG_NOTICE("ulogoffX vuid=%llu\n",
    2763             :                   (unsigned long long)smb1req->vuid);
    2764             : 
    2765          12 :         smb1req->vuid = UID_FIELD_INVALID;
    2766             :         /*
    2767             :          * The following call is needed to push the
    2768             :          * reply data back out the socket after async
    2769             :          * return. Plus it frees smb1req.
    2770             :          */
    2771          12 :         smb_request_done(smb1req);
    2772          12 :         END_PROFILE(SMBulogoffX);
    2773          11 : }
    2774             : 
    2775             : /****************************************************************************
    2776             :  Reply to a mknew or a create.
    2777             : ****************************************************************************/
    2778             : 
    2779          40 : void reply_mknew(struct smb_request *req)
    2780             : {
    2781          40 :         connection_struct *conn = req->conn;
    2782          40 :         struct smb_filename *smb_fname = NULL;
    2783          40 :         char *fname = NULL;
    2784          40 :         uint32_t fattr = 0;
    2785             :         struct smb_file_time ft;
    2786             :         files_struct *fsp;
    2787          40 :         int oplock_request = 0;
    2788             :         NTSTATUS status;
    2789          40 :         uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
    2790          40 :         uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
    2791             :         uint32_t create_disposition;
    2792          40 :         uint32_t create_options = 0;
    2793             :         uint32_t ucf_flags;
    2794          40 :         TALLOC_CTX *ctx = talloc_tos();
    2795             : 
    2796          40 :         START_PROFILE(SMBcreate);
    2797          40 :         init_smb_file_time(&ft);
    2798             : 
    2799          40 :         if (req->wct < 3) {
    2800           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    2801           0 :                 goto out;
    2802             :         }
    2803             : 
    2804          40 :         fattr = SVAL(req->vwv+0, 0);
    2805          40 :         oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
    2806             : 
    2807          40 :         if (req->cmd == SMBmknew) {
    2808             :                 /* We should fail if file exists. */
    2809          16 :                 create_disposition = FILE_CREATE;
    2810             :         } else {
    2811             :                 /* Create if file doesn't exist, truncate if it does. */
    2812          20 :                 create_disposition = FILE_OVERWRITE_IF;
    2813             :         }
    2814             : 
    2815             :         /* mtime. */
    2816          40 :         ft.mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+1));
    2817             : 
    2818          40 :         srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
    2819             :                             STR_TERMINATE, &status);
    2820          40 :         if (!NT_STATUS_IS_OK(status)) {
    2821           0 :                 reply_nterror(req, status);
    2822           0 :                 goto out;
    2823             :         }
    2824             : 
    2825          40 :         ucf_flags = filename_create_ucf_flags(req, create_disposition);
    2826          40 :         status = filename_convert(ctx,
    2827             :                                 conn,
    2828             :                                 fname,
    2829             :                                 ucf_flags,
    2830             :                                 0,
    2831             :                                 &smb_fname);
    2832          40 :         if (!NT_STATUS_IS_OK(status)) {
    2833           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    2834           0 :                         reply_botherror(req,
    2835             :                                         NT_STATUS_PATH_NOT_COVERED,
    2836             :                                         ERRSRV, ERRbadpath);
    2837           0 :                         goto out;
    2838             :                 }
    2839           0 :                 reply_nterror(req, status);
    2840           0 :                 goto out;
    2841             :         }
    2842             : 
    2843          40 :         if (fattr & FILE_ATTRIBUTE_VOLUME) {
    2844           0 :                 DEBUG(0,("Attempt to create file (%s) with volid set - "
    2845             :                          "please report this\n",
    2846             :                          smb_fname_str_dbg(smb_fname)));
    2847             :         }
    2848             : 
    2849          40 :         status = SMB_VFS_CREATE_FILE(
    2850             :                 conn,                                   /* conn */
    2851             :                 req,                                    /* req */
    2852             :                 smb_fname,                              /* fname */
    2853             :                 access_mask,                            /* access_mask */
    2854             :                 share_mode,                             /* share_access */
    2855             :                 create_disposition,                     /* create_disposition*/
    2856             :                 create_options,                         /* create_options */
    2857             :                 fattr,                                  /* file_attributes */
    2858             :                 oplock_request,                         /* oplock_request */
    2859             :                 NULL,                                   /* lease */
    2860             :                 0,                                      /* allocation_size */
    2861             :                 0,                                      /* private_flags */
    2862             :                 NULL,                                   /* sd */
    2863             :                 NULL,                                   /* ea_list */
    2864             :                 &fsp,                                       /* result */
    2865             :                 NULL,                                   /* pinfo */
    2866             :                 NULL, NULL);                            /* create context */
    2867             : 
    2868          40 :         if (!NT_STATUS_IS_OK(status)) {
    2869           5 :                 if (open_was_deferred(req->xconn, req->mid)) {
    2870             :                         /* We have re-scheduled this call. */
    2871           0 :                         goto out;
    2872             :                 }
    2873           5 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
    2874           0 :                         bool ok = defer_smb1_sharing_violation(req);
    2875           0 :                         if (ok) {
    2876           0 :                                 goto out;
    2877             :                         }
    2878             :                 }
    2879           5 :                 reply_openerror(req, status);
    2880           5 :                 goto out;
    2881             :         }
    2882             : 
    2883          35 :         ft.atime = smb_fname->st.st_ex_atime; /* atime. */
    2884          35 :         status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
    2885          35 :         if (!NT_STATUS_IS_OK(status)) {
    2886           0 :                 END_PROFILE(SMBcreate);
    2887           0 :                 goto out;
    2888             :         }
    2889             : 
    2890          35 :         reply_outbuf(req, 1, 0);
    2891          35 :         SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
    2892             : 
    2893          35 :         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
    2894           0 :                 SCVAL(req->outbuf,smb_flg,
    2895             :                                 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    2896             :         }
    2897             : 
    2898          35 :         if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
    2899           0 :                 SCVAL(req->outbuf,smb_flg,
    2900             :                                 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    2901             :         }
    2902             : 
    2903          35 :         DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
    2904          35 :         DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
    2905             :                   smb_fname_str_dbg(smb_fname), fsp_get_io_fd(fsp),
    2906             :                   (unsigned int)fattr));
    2907             : 
    2908          40 :  out:
    2909          40 :         TALLOC_FREE(smb_fname);
    2910          40 :         END_PROFILE(SMBcreate);
    2911          40 :         return;
    2912             : }
    2913             : 
    2914             : /****************************************************************************
    2915             :  Reply to a create temporary file.
    2916             : ****************************************************************************/
    2917             : 
    2918          14 : void reply_ctemp(struct smb_request *req)
    2919             : {
    2920          14 :         connection_struct *conn = req->conn;
    2921          14 :         struct smb_filename *smb_fname = NULL;
    2922          14 :         char *wire_name = NULL;
    2923          14 :         char *fname = NULL;
    2924             :         uint32_t fattr;
    2925             :         files_struct *fsp;
    2926             :         int oplock_request;
    2927             :         char *s;
    2928             :         NTSTATUS status;
    2929             :         int i;
    2930             :         uint32_t ucf_flags;
    2931          14 :         TALLOC_CTX *ctx = talloc_tos();
    2932             : 
    2933          14 :         START_PROFILE(SMBctemp);
    2934             : 
    2935          14 :         if (req->wct < 3) {
    2936           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    2937           0 :                 goto out;
    2938             :         }
    2939             : 
    2940          14 :         fattr = SVAL(req->vwv+0, 0);
    2941          14 :         oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
    2942             : 
    2943          14 :         srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
    2944             :                             STR_TERMINATE, &status);
    2945          14 :         if (!NT_STATUS_IS_OK(status)) {
    2946           0 :                 reply_nterror(req, status);
    2947           0 :                 goto out;
    2948             :         }
    2949             : 
    2950          24 :         for (i = 0; i < 10; i++) {
    2951          14 :                 if (*wire_name) {
    2952           5 :                         fname = talloc_asprintf(ctx,
    2953             :                                         "%s/TMP%s",
    2954             :                                         wire_name,
    2955             :                                         generate_random_str_list(ctx, 5, "0123456789"));
    2956             :                 } else {
    2957           9 :                         fname = talloc_asprintf(ctx,
    2958             :                                         "TMP%s",
    2959             :                                         generate_random_str_list(ctx, 5, "0123456789"));
    2960             :                 }
    2961             : 
    2962          14 :                 if (!fname) {
    2963           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    2964           0 :                         goto out;
    2965             :                 }
    2966             : 
    2967          14 :                 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
    2968          14 :                 status = filename_convert(ctx, conn,
    2969             :                                 fname,
    2970             :                                 ucf_flags,
    2971             :                                 0,
    2972             :                                 &smb_fname);
    2973          14 :                 if (!NT_STATUS_IS_OK(status)) {
    2974           0 :                         if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    2975           0 :                                 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    2976             :                                         ERRSRV, ERRbadpath);
    2977           0 :                                 goto out;
    2978             :                         }
    2979           0 :                         reply_nterror(req, status);
    2980           0 :                         goto out;
    2981             :                 }
    2982             : 
    2983             :                 /* Create the file. */
    2984          14 :                 status = SMB_VFS_CREATE_FILE(
    2985             :                         conn,                                   /* conn */
    2986             :                         req,                                    /* req */
    2987             :                         smb_fname,                              /* fname */
    2988             :                         FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
    2989             :                         FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
    2990             :                         FILE_CREATE,                            /* create_disposition*/
    2991             :                         0,                                      /* create_options */
    2992             :                         fattr,                                  /* file_attributes */
    2993             :                         oplock_request,                         /* oplock_request */
    2994             :                         NULL,                                   /* lease */
    2995             :                         0,                                      /* allocation_size */
    2996             :                         0,                                      /* private_flags */
    2997             :                         NULL,                                   /* sd */
    2998             :                         NULL,                                   /* ea_list */
    2999             :                         &fsp,                                       /* result */
    3000             :                         NULL,                                   /* pinfo */
    3001             :                         NULL, NULL);                            /* create context */
    3002             : 
    3003          14 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
    3004           0 :                         TALLOC_FREE(fname);
    3005           0 :                         TALLOC_FREE(smb_fname);
    3006           0 :                         continue;
    3007             :                 }
    3008             : 
    3009          14 :                 if (!NT_STATUS_IS_OK(status)) {
    3010           0 :                         if (open_was_deferred(req->xconn, req->mid)) {
    3011             :                                 /* We have re-scheduled this call. */
    3012           0 :                                 goto out;
    3013             :                         }
    3014           0 :                         if (NT_STATUS_EQUAL(
    3015             :                                     status, NT_STATUS_SHARING_VIOLATION)) {
    3016           0 :                                 bool ok = defer_smb1_sharing_violation(req);
    3017           0 :                                 if (ok) {
    3018           0 :                                         goto out;
    3019             :                                 }
    3020             :                         }
    3021           0 :                         reply_openerror(req, status);
    3022           0 :                         goto out;
    3023             :                 }
    3024             : 
    3025          12 :                 break;
    3026             :         }
    3027             : 
    3028          14 :         if (i == 10) {
    3029             :                 /* Collision after 10 times... */
    3030           0 :                 reply_nterror(req, status);
    3031           0 :                 goto out;
    3032             :         }
    3033             : 
    3034          14 :         reply_outbuf(req, 1, 0);
    3035          14 :         SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
    3036             : 
    3037             :         /* the returned filename is relative to the directory */
    3038          14 :         s = strrchr_m(fsp->fsp_name->base_name, '/');
    3039          14 :         if (!s) {
    3040           9 :                 s = fsp->fsp_name->base_name;
    3041             :         } else {
    3042           5 :                 s++;
    3043             :         }
    3044             : 
    3045             : #if 0
    3046             :         /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
    3047             :            thing in the byte section. JRA */
    3048             :         SSVALS(p, 0, -1); /* what is this? not in spec */
    3049             : #endif
    3050          14 :         if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
    3051             :             == -1) {
    3052           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    3053           0 :                 goto out;
    3054             :         }
    3055             : 
    3056          14 :         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
    3057           0 :                 SCVAL(req->outbuf, smb_flg,
    3058             :                       CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    3059             :         }
    3060             : 
    3061          14 :         if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
    3062           0 :                 SCVAL(req->outbuf, smb_flg,
    3063             :                       CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
    3064             :         }
    3065             : 
    3066          14 :         DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
    3067          14 :         DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
    3068             :                     fsp_get_io_fd(fsp), (unsigned int)smb_fname->st.st_ex_mode));
    3069          14 :  out:
    3070          14 :         TALLOC_FREE(smb_fname);
    3071          14 :         TALLOC_FREE(wire_name);
    3072          14 :         END_PROFILE(SMBctemp);
    3073          14 :         return;
    3074             : }
    3075             : 
    3076             : /*******************************************************************
    3077             :  Check if a user is allowed to rename a file.
    3078             : ********************************************************************/
    3079             : 
    3080         614 : static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
    3081             :                         uint16_t dirtype)
    3082             : {
    3083         614 :         if (!CAN_WRITE(conn)) {
    3084           0 :                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
    3085             :         }
    3086             : 
    3087         614 :         if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
    3088             :                         (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
    3089             :                 /* Only bother to read the DOS attribute if we might deny the
    3090             :                    rename on the grounds of attribute mismatch. */
    3091         175 :                 uint32_t fmode = fdos_mode(fsp);
    3092         175 :                 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
    3093          10 :                         return NT_STATUS_NO_SUCH_FILE;
    3094             :                 }
    3095             :         }
    3096             : 
    3097         604 :         if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
    3098         267 :                 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
    3099           8 :                         return NT_STATUS_OK;
    3100             :                 }
    3101             : 
    3102             :                 /* If no pathnames are open below this
    3103             :                    directory, allow the rename. */
    3104             : 
    3105         259 :                 if (lp_strict_rename(SNUM(conn))) {
    3106             :                         /*
    3107             :                          * Strict rename, check open file db.
    3108             :                          */
    3109         180 :                         if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
    3110          12 :                                 return NT_STATUS_ACCESS_DENIED;
    3111             :                         }
    3112          79 :                 } else if (file_find_subpath(fsp)) {
    3113             :                         /*
    3114             :                          * No strict rename, just look in local process.
    3115             :                          */
    3116           5 :                         return NT_STATUS_ACCESS_DENIED;
    3117             :                 }
    3118         242 :                 return NT_STATUS_OK;
    3119             :         }
    3120             : 
    3121         337 :         if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
    3122         337 :                 return NT_STATUS_OK;
    3123             :         }
    3124             : 
    3125           0 :         return NT_STATUS_ACCESS_DENIED;
    3126             : }
    3127             : 
    3128             : /*******************************************************************
    3129             :  * unlink a file with all relevant access checks
    3130             :  *******************************************************************/
    3131             : 
    3132       26949 : static NTSTATUS do_unlink(connection_struct *conn,
    3133             :                         struct smb_request *req,
    3134             :                         struct smb_filename *smb_fname,
    3135             :                         uint32_t dirtype)
    3136             : {
    3137             :         uint32_t fattr;
    3138             :         files_struct *fsp;
    3139       26949 :         uint32_t dirtype_orig = dirtype;
    3140             :         NTSTATUS status;
    3141             :         int ret;
    3142       26949 :         struct smb2_create_blobs *posx = NULL;
    3143             : 
    3144       26949 :         DEBUG(10,("do_unlink: %s, dirtype = %d\n",
    3145             :                   smb_fname_str_dbg(smb_fname),
    3146             :                   dirtype));
    3147             : 
    3148       26949 :         if (!CAN_WRITE(conn)) {
    3149           0 :                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
    3150             :         }
    3151             : 
    3152       26949 :         ret = vfs_stat(conn, smb_fname);
    3153       26949 :         if (ret != 0) {
    3154        2599 :                 return map_nt_error_from_unix(errno);
    3155             :         }
    3156             : 
    3157       24350 :         fattr = fdos_mode(smb_fname->fsp);
    3158             : 
    3159       24350 :         if (dirtype & FILE_ATTRIBUTE_NORMAL) {
    3160          84 :                 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
    3161             :         }
    3162             : 
    3163       24350 :         dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
    3164       24350 :         if (!dirtype) {
    3165           0 :                 return NT_STATUS_NO_SUCH_FILE;
    3166             :         }
    3167             : 
    3168       24350 :         if (!dir_check_ftype(fattr, dirtype)) {
    3169         115 :                 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
    3170         111 :                         return NT_STATUS_FILE_IS_A_DIRECTORY;
    3171             :                 }
    3172           4 :                 return NT_STATUS_NO_SUCH_FILE;
    3173             :         }
    3174             : 
    3175       24235 :         if (dirtype_orig & 0x8000) {
    3176             :                 /* These will never be set for POSIX. */
    3177           0 :                 return NT_STATUS_NO_SUCH_FILE;
    3178             :         }
    3179             : 
    3180             : #if 0
    3181             :         if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
    3182             :                 return NT_STATUS_FILE_IS_A_DIRECTORY;
    3183             :         }
    3184             : 
    3185             :         if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
    3186             :                 return NT_STATUS_NO_SUCH_FILE;
    3187             :         }
    3188             : 
    3189             :         if (dirtype & 0xFF00) {
    3190             :                 /* These will never be set for POSIX. */
    3191             :                 return NT_STATUS_NO_SUCH_FILE;
    3192             :         }
    3193             : 
    3194             :         dirtype &= 0xFF;
    3195             :         if (!dirtype) {
    3196             :                 return NT_STATUS_NO_SUCH_FILE;
    3197             :         }
    3198             : 
    3199             :         /* Can't delete a directory. */
    3200             :         if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
    3201             :                 return NT_STATUS_FILE_IS_A_DIRECTORY;
    3202             :         }
    3203             : #endif
    3204             : 
    3205             : #if 0 /* JRATEST */
    3206             :         else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
    3207             :                 return NT_STATUS_OBJECT_NAME_INVALID;
    3208             : #endif /* JRATEST */
    3209             : 
    3210       24235 :         if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
    3211           6 :                 status = make_smb2_posix_create_ctx(
    3212             :                         talloc_tos(), &posx, 0777);
    3213           6 :                 if (!NT_STATUS_IS_OK(status)) {
    3214           0 :                         DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
    3215             :                                     nt_errstr(status));
    3216           0 :                         return status;
    3217             :                 }
    3218             :         }
    3219             : 
    3220             :         /* On open checks the open itself will check the share mode, so
    3221             :            don't do it here as we'll get it wrong. */
    3222             : 
    3223       24235 :         status = SMB_VFS_CREATE_FILE
    3224             :                 (conn,                  /* conn */
    3225             :                  req,                   /* req */
    3226             :                  smb_fname,             /* fname */
    3227             :                  DELETE_ACCESS,         /* access_mask */
    3228             :                  FILE_SHARE_NONE,       /* share_access */
    3229             :                  FILE_OPEN,             /* create_disposition*/
    3230             :                  FILE_NON_DIRECTORY_FILE, /* create_options */
    3231             :                  FILE_ATTRIBUTE_NORMAL, /* file_attributes */
    3232             :                  0,                     /* oplock_request */
    3233             :                  NULL,                  /* lease */
    3234             :                  0,                     /* allocation_size */
    3235             :                  0,                     /* private_flags */
    3236             :                  NULL,                  /* sd */
    3237             :                  NULL,                  /* ea_list */
    3238             :                  &fsp,                      /* result */
    3239             :                  NULL,                  /* pinfo */
    3240             :                  posx,                  /* in_context_blobs */
    3241             :                  NULL);                 /* out_context_blobs */
    3242             : 
    3243       24235 :         TALLOC_FREE(posx);
    3244             : 
    3245       24235 :         if (!NT_STATUS_IS_OK(status)) {
    3246        1045 :                 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
    3247             :                            nt_errstr(status)));
    3248        1045 :                 return status;
    3249             :         }
    3250             : 
    3251       23190 :         status = can_set_delete_on_close(fsp, fattr);
    3252       23190 :         if (!NT_STATUS_IS_OK(status)) {
    3253           8 :                 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
    3254             :                         "(%s)\n",
    3255             :                         smb_fname_str_dbg(smb_fname),
    3256             :                         nt_errstr(status)));
    3257           8 :                 close_file(req, fsp, NORMAL_CLOSE);
    3258           8 :                 return status;
    3259             :         }
    3260             : 
    3261             :         /* The set is across all open files on this dev/inode pair. */
    3262       23182 :         if (!set_delete_on_close(fsp, True,
    3263       23182 :                                 conn->session_info->security_token,
    3264       23182 :                                 conn->session_info->unix_token)) {
    3265           0 :                 close_file(req, fsp, NORMAL_CLOSE);
    3266           0 :                 return NT_STATUS_ACCESS_DENIED;
    3267             :         }
    3268             : 
    3269       23182 :         return close_file(req, fsp, NORMAL_CLOSE);
    3270             : }
    3271             : 
    3272             : /****************************************************************************
    3273             :  The guts of the unlink command, split out so it may be called by the NT SMB
    3274             :  code.
    3275             : ****************************************************************************/
    3276             : 
    3277       19573 : NTSTATUS unlink_internals(connection_struct *conn,
    3278             :                         struct smb_request *req,
    3279             :                         uint32_t dirtype,
    3280             :                         struct smb_filename *smb_fname,
    3281             :                         bool has_wild)
    3282             : {
    3283       19573 :         char *fname_dir = NULL;
    3284       19573 :         char *fname_mask = NULL;
    3285       19573 :         int count=0;
    3286       19573 :         NTSTATUS status = NT_STATUS_OK;
    3287       19573 :         struct smb_filename *smb_fname_dir = NULL;
    3288       19573 :         TALLOC_CTX *ctx = talloc_tos();
    3289             :         int ret;
    3290             : 
    3291             :         /* Split up the directory from the filename/mask. */
    3292       19573 :         status = split_fname_dir_mask(ctx, smb_fname->base_name,
    3293             :                                       &fname_dir, &fname_mask);
    3294       19573 :         if (!NT_STATUS_IS_OK(status)) {
    3295           0 :                 goto out;
    3296             :         }
    3297             : 
    3298             :         /*
    3299             :          * We should only check the mangled cache
    3300             :          * here if unix_convert failed. This means
    3301             :          * that the path in 'mask' doesn't exist
    3302             :          * on the file system and so we need to look
    3303             :          * for a possible mangle. This patch from
    3304             :          * Tine Smukavec <valentin.smukavec@hermes.si>.
    3305             :          */
    3306             : 
    3307       27268 :         if (!VALID_STAT(smb_fname->st) &&
    3308        7695 :             mangle_is_mangled(fname_mask, conn->params)) {
    3309           0 :                 char *new_mask = NULL;
    3310           0 :                 mangle_lookup_name_from_8_3(ctx, fname_mask,
    3311           0 :                                             &new_mask, conn->params);
    3312           0 :                 if (new_mask) {
    3313           0 :                         TALLOC_FREE(fname_mask);
    3314           0 :                         fname_mask = new_mask;
    3315             :                 }
    3316             :         }
    3317             : 
    3318       19573 :         if (!has_wild) {
    3319             : 
    3320             :                 /*
    3321             :                  * Only one file needs to be unlinked. Append the mask back
    3322             :                  * onto the directory.
    3323             :                  */
    3324       14477 :                 TALLOC_FREE(smb_fname->base_name);
    3325       14477 :                 if (ISDOT(fname_dir)) {
    3326             :                         /* Ensure we use canonical names on open. */
    3327        4534 :                         smb_fname->base_name = talloc_asprintf(smb_fname,
    3328             :                                                         "%s",
    3329             :                                                         fname_mask);
    3330             :                 } else {
    3331        9943 :                         smb_fname->base_name = talloc_asprintf(smb_fname,
    3332             :                                                         "%s/%s",
    3333             :                                                         fname_dir,
    3334             :                                                         fname_mask);
    3335             :                 }
    3336       14477 :                 if (!smb_fname->base_name) {
    3337           0 :                         status = NT_STATUS_NO_MEMORY;
    3338           0 :                         goto out;
    3339             :                 }
    3340       14477 :                 if (dirtype == 0) {
    3341          92 :                         dirtype = FILE_ATTRIBUTE_NORMAL;
    3342             :                 }
    3343             : 
    3344       14477 :                 status = check_name(conn, smb_fname);
    3345       14477 :                 if (!NT_STATUS_IS_OK(status)) {
    3346           0 :                         goto out;
    3347             :                 }
    3348             : 
    3349       14477 :                 status = do_unlink(conn, req, smb_fname, dirtype);
    3350       14477 :                 if (!NT_STATUS_IS_OK(status)) {
    3351        3390 :                         goto out;
    3352             :                 }
    3353             : 
    3354       10744 :                 count++;
    3355             :         } else {
    3356        5096 :                 struct smb_Dir *dir_hnd = NULL;
    3357        5096 :                 long offset = 0;
    3358        5096 :                 const char *dname = NULL;
    3359        5096 :                 char *talloced = NULL;
    3360             : 
    3361        5096 :                 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
    3362          20 :                         status = NT_STATUS_OBJECT_NAME_INVALID;
    3363         141 :                         goto out;
    3364             :                 }
    3365        5076 :                 if (dirtype == 0) {
    3366          20 :                         dirtype = FILE_ATTRIBUTE_NORMAL;
    3367             :                 }
    3368             : 
    3369        5076 :                 if (strequal(fname_mask,"????????.???")) {
    3370           0 :                         TALLOC_FREE(fname_mask);
    3371           0 :                         fname_mask = talloc_strdup(ctx, "*");
    3372           0 :                         if (!fname_mask) {
    3373           0 :                                 status = NT_STATUS_NO_MEMORY;
    3374           0 :                                 goto out;
    3375             :                         }
    3376             :                 }
    3377             : 
    3378        5076 :                 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
    3379             :                                         fname_dir,
    3380             :                                         NULL,
    3381             :                                         NULL,
    3382             :                                         smb_fname->twrp,
    3383             :                                         smb_fname->flags);
    3384        5076 :                 if (smb_fname_dir == NULL) {
    3385           0 :                         status = NT_STATUS_NO_MEMORY;
    3386           0 :                         goto out;
    3387             :                 }
    3388             : 
    3389        5076 :                 status = check_name(conn, smb_fname_dir);
    3390        5076 :                 if (!NT_STATUS_IS_OK(status)) {
    3391           0 :                         goto out;
    3392             :                 }
    3393             : 
    3394        5076 :                 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
    3395             :                                   dirtype);
    3396        5076 :                 if (dir_hnd == NULL) {
    3397           0 :                         status = map_nt_error_from_unix(errno);
    3398           0 :                         goto out;
    3399             :                 }
    3400             : 
    3401             :                 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
    3402             :                    the pattern matches against the long name, otherwise the short name 
    3403             :                    We don't implement this yet XXXX
    3404             :                 */
    3405             : 
    3406        5028 :                 status = NT_STATUS_NO_SUCH_FILE;
    3407             : 
    3408       31469 :                 while ((dname = ReadDirName(dir_hnd, &offset,
    3409             :                                             &smb_fname->st, &talloced))) {
    3410       22632 :                         TALLOC_CTX *frame = talloc_stackframe();
    3411       22632 :                         char *p = NULL;
    3412       22632 :                         struct smb_filename *f = NULL;
    3413             : 
    3414             :                         /* Quick check for "." and ".." */
    3415       22632 :                         if (ISDOT(dname) || ISDOTDOT(dname)) {
    3416       10152 :                                 TALLOC_FREE(frame);
    3417       10152 :                                 TALLOC_FREE(talloced);
    3418       10152 :                                 continue;
    3419             :                         }
    3420             : 
    3421       12480 :                         if (IS_VETO_PATH(conn, dname)) {
    3422           0 :                                 TALLOC_FREE(frame);
    3423           0 :                                 TALLOC_FREE(talloced);
    3424           0 :                                 continue;
    3425             :                         }
    3426             : 
    3427       12480 :                         if(!mask_match(dname, fname_mask,
    3428       12480 :                                        conn->case_sensitive)) {
    3429           8 :                                 TALLOC_FREE(frame);
    3430           8 :                                 TALLOC_FREE(talloced);
    3431           8 :                                 continue;
    3432             :                         }
    3433             : 
    3434       12472 :                         if (ISDOT(fname_dir)) {
    3435             :                                 /* Ensure we use canonical names on open. */
    3436           0 :                                 p = talloc_asprintf(smb_fname, "%s", dname);
    3437             :                         } else {
    3438       12472 :                                 p = talloc_asprintf(smb_fname, "%s/%s",
    3439             :                                                     fname_dir, dname);
    3440             :                         }
    3441       12472 :                         if (p == NULL) {
    3442           0 :                                 TALLOC_FREE(dir_hnd);
    3443           0 :                                 status = NT_STATUS_NO_MEMORY;
    3444           0 :                                 TALLOC_FREE(frame);
    3445           0 :                                 TALLOC_FREE(talloced);
    3446           0 :                                 goto out;
    3447             :                         }
    3448       22298 :                         f = synthetic_smb_fname(frame,
    3449             :                                                 p,
    3450             :                                                 NULL,
    3451       12432 :                                                 &smb_fname->st,
    3452             :                                                 smb_fname->twrp,
    3453             :                                                 smb_fname->flags);
    3454       12472 :                         if (f == NULL) {
    3455           0 :                                 TALLOC_FREE(dir_hnd);
    3456           0 :                                 status = NT_STATUS_NO_MEMORY;
    3457           0 :                                 TALLOC_FREE(frame);
    3458           0 :                                 TALLOC_FREE(talloced);
    3459           0 :                                 goto out;
    3460             :                         }
    3461             : 
    3462       12472 :                         ret = vfs_stat(conn, f);
    3463       12472 :                         if (ret != 0) {
    3464           0 :                                 status = map_nt_error_from_unix(errno);
    3465           0 :                                 TALLOC_FREE(dir_hnd);
    3466           0 :                                 TALLOC_FREE(frame);
    3467           0 :                                 TALLOC_FREE(talloced);
    3468           0 :                                 goto out;
    3469             :                         }
    3470             : 
    3471       12472 :                         status = openat_pathref_fsp(conn->cwd_fsp, f);
    3472       12472 :                         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
    3473           0 :                             (f->flags & SMB_FILENAME_POSIX_PATH) &&
    3474           0 :                             S_ISLNK(f->st.st_ex_mode))
    3475             :                         {
    3476           0 :                                 status = NT_STATUS_OK;
    3477             :                         }
    3478       12472 :                         if (!NT_STATUS_IS_OK(status)) {
    3479           0 :                                 TALLOC_FREE(dir_hnd);
    3480           0 :                                 TALLOC_FREE(frame);
    3481           0 :                                 TALLOC_FREE(talloced);
    3482           0 :                                 goto out;
    3483             :                         }
    3484             : 
    3485       12472 :                         if (!is_visible_fsp(f->fsp)) {
    3486           0 :                                 TALLOC_FREE(frame);
    3487           0 :                                 TALLOC_FREE(talloced);
    3488           0 :                                 continue;
    3489             :                         }
    3490             : 
    3491       12472 :                         status = check_name(conn, f);
    3492       12472 :                         if (!NT_STATUS_IS_OK(status)) {
    3493           0 :                                 TALLOC_FREE(dir_hnd);
    3494           0 :                                 TALLOC_FREE(frame);
    3495           0 :                                 TALLOC_FREE(talloced);
    3496           0 :                                 goto out;
    3497             :                         }
    3498             : 
    3499       12472 :                         status = do_unlink(conn, req, f, dirtype);
    3500       12472 :                         if (!NT_STATUS_IS_OK(status)) {
    3501         135 :                                 TALLOC_FREE(dir_hnd);
    3502         135 :                                 TALLOC_FREE(frame);
    3503         135 :                                 TALLOC_FREE(talloced);
    3504         126 :                                 goto out;
    3505             :                         }
    3506             : 
    3507       12337 :                         count++;
    3508       12337 :                         DBG_DEBUG("successful unlink [%s]\n",
    3509             :                                   smb_fname_str_dbg(f));
    3510             : 
    3511       12337 :                         TALLOC_FREE(frame);
    3512       12337 :                         TALLOC_FREE(talloced);
    3513             :                 }
    3514        4941 :                 TALLOC_FREE(dir_hnd);
    3515             :         }
    3516             : 
    3517       19011 :         if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
    3518           0 :                 status = map_nt_error_from_unix(errno);
    3519             :         }
    3520             : 
    3521       32648 :  out:
    3522       19573 :         TALLOC_FREE(smb_fname_dir);
    3523       19573 :         TALLOC_FREE(fname_dir);
    3524       19573 :         TALLOC_FREE(fname_mask);
    3525       19573 :         return status;
    3526             : }
    3527             : 
    3528             : /****************************************************************************
    3529             :  Reply to a unlink
    3530             : ****************************************************************************/
    3531             : 
    3532       19971 : void reply_unlink(struct smb_request *req)
    3533             : {
    3534       19971 :         connection_struct *conn = req->conn;
    3535       19971 :         char *name = NULL;
    3536       19971 :         struct smb_filename *smb_fname = NULL;
    3537             :         uint32_t dirtype;
    3538             :         NTSTATUS status;
    3539       19971 :         uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
    3540       19971 :                         ucf_flags_from_smb_request(req);
    3541       19971 :         TALLOC_CTX *ctx = talloc_tos();
    3542       19971 :         bool has_wild = false;
    3543             : 
    3544       19971 :         START_PROFILE(SMBunlink);
    3545             : 
    3546       19971 :         if (req->wct < 1) {
    3547           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    3548           0 :                 goto out;
    3549             :         }
    3550             : 
    3551       19971 :         dirtype = SVAL(req->vwv+0, 0);
    3552             : 
    3553       19971 :         srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
    3554             :                                   STR_TERMINATE, &status);
    3555       19971 :         if (!NT_STATUS_IS_OK(status)) {
    3556         167 :                 reply_nterror(req, status);
    3557         167 :                 goto out;
    3558             :         }
    3559             : 
    3560       19804 :         status = filename_convert(ctx, conn,
    3561             :                                   name,
    3562             :                                   ucf_flags,
    3563             :                                   0,
    3564             :                                   &smb_fname);
    3565       19804 :         if (!NT_STATUS_IS_OK(status)) {
    3566         231 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    3567           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    3568             :                                         ERRSRV, ERRbadpath);
    3569           0 :                         goto out;
    3570             :                 }
    3571         231 :                 reply_nterror(req, status);
    3572         231 :                 goto out;
    3573             :         }
    3574             : 
    3575       19573 :         if (!req->posix_pathnames) {
    3576       19565 :                 char *lcomp = get_original_lcomp(ctx,
    3577             :                                         conn,
    3578             :                                         name,
    3579             :                                         ucf_flags);
    3580       19565 :                 if (lcomp == NULL) {
    3581           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    3582           0 :                         goto out;
    3583             :                 }
    3584       19565 :                 has_wild = ms_has_wild(lcomp);
    3585       19565 :                 TALLOC_FREE(lcomp);
    3586             :         }
    3587             : 
    3588       19573 :         DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
    3589             : 
    3590       19573 :         status = unlink_internals(conn, req, dirtype, smb_fname, has_wild);
    3591       19573 :         if (!NT_STATUS_IS_OK(status)) {
    3592        8158 :                 if (open_was_deferred(req->xconn, req->mid)) {
    3593             :                         /* We have re-scheduled this call. */
    3594          18 :                         goto out;
    3595             :                 }
    3596        8140 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
    3597         182 :                         bool ok = defer_smb1_sharing_violation(req);
    3598         182 :                         if (ok) {
    3599          82 :                                 goto out;
    3600             :                         }
    3601             :                 }
    3602        8051 :                 reply_nterror(req, status);
    3603        8051 :                 goto out;
    3604             :         }
    3605             : 
    3606       11415 :         reply_outbuf(req, 0, 0);
    3607       19978 :  out:
    3608       19971 :         TALLOC_FREE(smb_fname);
    3609       19971 :         END_PROFILE(SMBunlink);
    3610       19971 :         return;
    3611             : }
    3612             : 
    3613             : /****************************************************************************
    3614             :  Fail for readbraw.
    3615             : ****************************************************************************/
    3616             : 
    3617           0 : static void fail_readraw(void)
    3618             : {
    3619           0 :         const char *errstr = talloc_asprintf(talloc_tos(),
    3620             :                         "FAIL ! reply_readbraw: socket write fail (%s)",
    3621           0 :                         strerror(errno));
    3622           0 :         if (!errstr) {
    3623           0 :                 errstr = "";
    3624             :         }
    3625           0 :         exit_server_cleanly(errstr);
    3626             : }
    3627             : 
    3628             : /****************************************************************************
    3629             :  Fake (read/write) sendfile. Returns -1 on read or write fail.
    3630             : ****************************************************************************/
    3631             : 
    3632          12 : ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
    3633             :                       off_t startpos, size_t nread)
    3634             : {
    3635             :         size_t bufsize;
    3636          12 :         size_t tosend = nread;
    3637             :         char *buf;
    3638             : 
    3639          12 :         if (nread == 0) {
    3640           0 :                 return 0;
    3641             :         }
    3642             : 
    3643          12 :         bufsize = MIN(nread, 65536);
    3644             : 
    3645          12 :         if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
    3646           0 :                 return -1;
    3647             :         }
    3648             : 
    3649        1728 :         while (tosend > 0) {
    3650             :                 ssize_t ret;
    3651             :                 size_t cur_read;
    3652             : 
    3653        1704 :                 cur_read = MIN(tosend, bufsize);
    3654        1704 :                 ret = read_file(fsp,buf,startpos,cur_read);
    3655        1704 :                 if (ret == -1) {
    3656           0 :                         SAFE_FREE(buf);
    3657           0 :                         return -1;
    3658             :                 }
    3659             : 
    3660             :                 /* If we had a short read, fill with zeros. */
    3661        1704 :                 if (ret < cur_read) {
    3662           0 :                         memset(buf + ret, '\0', cur_read - ret);
    3663             :                 }
    3664             : 
    3665        1704 :                 ret = write_data(xconn->transport.sock, buf, cur_read);
    3666        1704 :                 if (ret != cur_read) {
    3667           0 :                         int saved_errno = errno;
    3668             :                         /*
    3669             :                          * Try and give an error message saying what
    3670             :                          * client failed.
    3671             :                          */
    3672           0 :                         DEBUG(0, ("write_data failed for client %s. "
    3673             :                                   "Error %s\n",
    3674             :                                   smbXsrv_connection_dbg(xconn),
    3675             :                                   strerror(saved_errno)));
    3676           0 :                         SAFE_FREE(buf);
    3677           0 :                         errno = saved_errno;
    3678           0 :                         return -1;
    3679             :                 }
    3680        1704 :                 tosend -= cur_read;
    3681        1704 :                 startpos += cur_read;
    3682             :         }
    3683             : 
    3684          12 :         SAFE_FREE(buf);
    3685          12 :         return (ssize_t)nread;
    3686             : }
    3687             : 
    3688             : /****************************************************************************
    3689             :  Deal with the case of sendfile reading less bytes from the file than
    3690             :  requested. Fill with zeros (all we can do). Returns 0 on success
    3691             : ****************************************************************************/
    3692             : 
    3693           0 : ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
    3694             :                             files_struct *fsp,
    3695             :                             ssize_t nread,
    3696             :                             size_t headersize,
    3697             :                             size_t smb_maxcnt)
    3698             : {
    3699             : #define SHORT_SEND_BUFSIZE 1024
    3700           0 :         if (nread < headersize) {
    3701           0 :                 DEBUG(0,("sendfile_short_send: sendfile failed to send "
    3702             :                         "header for file %s (%s). Terminating\n",
    3703             :                         fsp_str_dbg(fsp), strerror(errno)));
    3704           0 :                 return -1;
    3705             :         }
    3706             : 
    3707           0 :         nread -= headersize;
    3708             : 
    3709           0 :         if (nread < smb_maxcnt) {
    3710           0 :                 char buf[SHORT_SEND_BUFSIZE] = { 0 };
    3711             : 
    3712           0 :                 DEBUG(0,("sendfile_short_send: filling truncated file %s "
    3713             :                         "with zeros !\n", fsp_str_dbg(fsp)));
    3714             : 
    3715           0 :                 while (nread < smb_maxcnt) {
    3716             :                         /*
    3717             :                          * We asked for the real file size and told sendfile
    3718             :                          * to not go beyond the end of the file. But it can
    3719             :                          * happen that in between our fstat call and the
    3720             :                          * sendfile call the file was truncated. This is very
    3721             :                          * bad because we have already announced the larger
    3722             :                          * number of bytes to the client.
    3723             :                          *
    3724             :                          * The best we can do now is to send 0-bytes, just as
    3725             :                          * a read from a hole in a sparse file would do.
    3726             :                          *
    3727             :                          * This should happen rarely enough that I don't care
    3728             :                          * about efficiency here :-)
    3729             :                          */
    3730             :                         size_t to_write;
    3731             :                         ssize_t ret;
    3732             : 
    3733           0 :                         to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
    3734           0 :                         ret = write_data(xconn->transport.sock, buf, to_write);
    3735           0 :                         if (ret != to_write) {
    3736           0 :                                 int saved_errno = errno;
    3737             :                                 /*
    3738             :                                  * Try and give an error message saying what
    3739             :                                  * client failed.
    3740             :                                  */
    3741           0 :                                 DEBUG(0, ("write_data failed for client %s. "
    3742             :                                           "Error %s\n",
    3743             :                                           smbXsrv_connection_dbg(xconn),
    3744             :                                           strerror(saved_errno)));
    3745           0 :                                 errno = saved_errno;
    3746           0 :                                 return -1;
    3747             :                         }
    3748           0 :                         nread += to_write;
    3749             :                 }
    3750             :         }
    3751             : 
    3752           0 :         return 0;
    3753             : }
    3754             : 
    3755             : /****************************************************************************
    3756             :  Return a readbraw error (4 bytes of zero).
    3757             : ****************************************************************************/
    3758             : 
    3759          16 : static void reply_readbraw_error(struct smbXsrv_connection *xconn)
    3760             : {
    3761             :         char header[4];
    3762             : 
    3763          16 :         SIVAL(header,0,0);
    3764             : 
    3765          16 :         smbd_lock_socket(xconn);
    3766          16 :         if (write_data(xconn->transport.sock,header,4) != 4) {
    3767           0 :                 int saved_errno = errno;
    3768             :                 /*
    3769             :                  * Try and give an error message saying what
    3770             :                  * client failed.
    3771             :                  */
    3772           0 :                 DEBUG(0, ("write_data failed for client %s. "
    3773             :                           "Error %s\n",
    3774             :                           smbXsrv_connection_dbg(xconn),
    3775             :                           strerror(saved_errno)));
    3776           0 :                 errno = saved_errno;
    3777             : 
    3778           0 :                 fail_readraw();
    3779             :         }
    3780          16 :         smbd_unlock_socket(xconn);
    3781          16 : }
    3782             : 
    3783             : /*******************************************************************
    3784             :  Ensure we don't use sendfile if server smb signing is active.
    3785             : ********************************************************************/
    3786             : 
    3787          47 : static bool lp_use_sendfile(int snum, struct smb_signing_state *signing_state)
    3788             : {
    3789          47 :         bool sign_active = false;
    3790             : 
    3791             :         /* Using sendfile blows the brains out of any DOS or Win9x TCP stack... JRA. */
    3792          47 :         if (get_Protocol() < PROTOCOL_NT1) {
    3793           0 :                 return false;
    3794             :         }
    3795          47 :         if (signing_state) {
    3796          47 :                 sign_active = smb_signing_is_active(signing_state);
    3797             :         }
    3798          47 :         return (lp__use_sendfile(snum) &&
    3799          47 :                         (get_remote_arch() != RA_WIN95) &&
    3800           0 :                         !sign_active);
    3801             : }
    3802             : /****************************************************************************
    3803             :  Use sendfile in readbraw.
    3804             : ****************************************************************************/
    3805             : 
    3806          32 : static void send_file_readbraw(connection_struct *conn,
    3807             :                                struct smb_request *req,
    3808             :                                files_struct *fsp,
    3809             :                                off_t startpos,
    3810             :                                size_t nread,
    3811             :                                ssize_t mincount)
    3812             : {
    3813          32 :         struct smbXsrv_connection *xconn = req->xconn;
    3814          32 :         char *outbuf = NULL;
    3815          32 :         ssize_t ret=0;
    3816             : 
    3817             :         /*
    3818             :          * We can only use sendfile on a non-chained packet 
    3819             :          * but we can use on a non-oplocked file. tridge proved this
    3820             :          * on a train in Germany :-). JRA.
    3821             :          * reply_readbraw has already checked the length.
    3822             :          */
    3823             : 
    3824          72 :         if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
    3825          20 :             lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
    3826           0 :                 ssize_t sendfile_read = -1;
    3827             :                 char header[4];
    3828             :                 DATA_BLOB header_blob;
    3829             : 
    3830           0 :                 _smb_setlen(header,nread);
    3831           0 :                 header_blob = data_blob_const(header, 4);
    3832             : 
    3833           0 :                 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
    3834             :                                                  &header_blob, startpos,
    3835             :                                                  nread);
    3836           0 :                 if (sendfile_read == -1) {
    3837             :                         /* Returning ENOSYS means no data at all was sent.
    3838             :                          * Do this as a normal read. */
    3839           0 :                         if (errno == ENOSYS) {
    3840           0 :                                 goto normal_readbraw;
    3841             :                         }
    3842             : 
    3843             :                         /*
    3844             :                          * Special hack for broken Linux with no working sendfile. If we
    3845             :                          * return EINTR we sent the header but not the rest of the data.
    3846             :                          * Fake this up by doing read/write calls.
    3847             :                          */
    3848           0 :                         if (errno == EINTR) {
    3849             :                                 /* Ensure we don't do this again. */
    3850           0 :                                 set_use_sendfile(SNUM(conn), False);
    3851           0 :                                 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
    3852             : 
    3853           0 :                                 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
    3854           0 :                                         DEBUG(0,("send_file_readbraw: "
    3855             :                                                  "fake_sendfile failed for "
    3856             :                                                  "file %s (%s).\n",
    3857             :                                                  fsp_str_dbg(fsp),
    3858             :                                                  strerror(errno)));
    3859           0 :                                         exit_server_cleanly("send_file_readbraw fake_sendfile failed");
    3860             :                                 }
    3861           0 :                                 return;
    3862             :                         }
    3863             : 
    3864           0 :                         DEBUG(0,("send_file_readbraw: sendfile failed for "
    3865             :                                  "file %s (%s). Terminating\n",
    3866             :                                  fsp_str_dbg(fsp), strerror(errno)));
    3867           0 :                         exit_server_cleanly("send_file_readbraw sendfile failed");
    3868           0 :                 } else if (sendfile_read == 0) {
    3869             :                         /*
    3870             :                          * Some sendfile implementations return 0 to indicate
    3871             :                          * that there was a short read, but nothing was
    3872             :                          * actually written to the socket.  In this case,
    3873             :                          * fallback to the normal read path so the header gets
    3874             :                          * the correct byte count.
    3875             :                          */
    3876           0 :                         DEBUG(3, ("send_file_readbraw: sendfile sent zero "
    3877             :                                   "bytes falling back to the normal read: "
    3878             :                                   "%s\n", fsp_str_dbg(fsp)));
    3879           0 :                         goto normal_readbraw;
    3880             :                 }
    3881             : 
    3882             :                 /* Deal with possible short send. */
    3883           0 :                 if (sendfile_read != 4+nread) {
    3884           0 :                         ret = sendfile_short_send(xconn, fsp,
    3885             :                                                   sendfile_read, 4, nread);
    3886           0 :                         if (ret == -1) {
    3887           0 :                                 fail_readraw();
    3888             :                         }
    3889             :                 }
    3890           0 :                 return;
    3891             :         }
    3892             : 
    3893          32 : normal_readbraw:
    3894             : 
    3895          32 :         outbuf = talloc_array(NULL, char, nread+4);
    3896          32 :         if (!outbuf) {
    3897           0 :                 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
    3898             :                         (unsigned)(nread+4)));
    3899           0 :                 reply_readbraw_error(xconn);
    3900           0 :                 return;
    3901             :         }
    3902             : 
    3903          32 :         if (nread > 0) {
    3904          20 :                 ret = read_file(fsp,outbuf+4,startpos,nread);
    3905             : #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
    3906             :                 if (ret < mincount)
    3907             :                         ret = 0;
    3908             : #else
    3909          20 :                 if (ret < nread)
    3910           0 :                         ret = 0;
    3911             : #endif
    3912             :         }
    3913             : 
    3914          32 :         _smb_setlen(outbuf,ret);
    3915          32 :         if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
    3916           0 :                 int saved_errno = errno;
    3917             :                 /*
    3918             :                  * Try and give an error message saying what
    3919             :                  * client failed.
    3920             :                  */
    3921           0 :                 DEBUG(0, ("write_data failed for client %s. Error %s\n",
    3922             :                           smbXsrv_connection_dbg(xconn),
    3923             :                           strerror(saved_errno)));
    3924           0 :                 errno = saved_errno;
    3925             : 
    3926           0 :                 fail_readraw();
    3927             :         }
    3928             : 
    3929          32 :         TALLOC_FREE(outbuf);
    3930             : }
    3931             : 
    3932             : /****************************************************************************
    3933             :  Reply to a readbraw (core+ protocol).
    3934             : ****************************************************************************/
    3935             : 
    3936          48 : void reply_readbraw(struct smb_request *req)
    3937             : {
    3938          48 :         connection_struct *conn = req->conn;
    3939          48 :         struct smbXsrv_connection *xconn = req->xconn;
    3940             :         ssize_t maxcount,mincount;
    3941          48 :         size_t nread = 0;
    3942             :         off_t startpos;
    3943             :         files_struct *fsp;
    3944             :         struct lock_struct lock;
    3945          48 :         off_t size = 0;
    3946             :         NTSTATUS status;
    3947             : 
    3948          48 :         START_PROFILE(SMBreadbraw);
    3949             : 
    3950          48 :         if (srv_is_signing_active(xconn) || req->encrypted) {
    3951           0 :                 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
    3952             :                         "raw reads/writes are disallowed.");
    3953             :         }
    3954             : 
    3955          48 :         if (req->wct < 8) {
    3956           0 :                 reply_readbraw_error(xconn);
    3957           0 :                 END_PROFILE(SMBreadbraw);
    3958           0 :                 return;
    3959             :         }
    3960             : 
    3961          48 :         if (xconn->smb1.echo_handler.trusted_fde) {
    3962           0 :                 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
    3963             :                          "'async smb echo handler = yes'\n"));
    3964           0 :                 reply_readbraw_error(xconn);
    3965           0 :                 END_PROFILE(SMBreadbraw);
    3966           0 :                 return;
    3967             :         }
    3968             : 
    3969             :         /*
    3970             :          * Special check if an oplock break has been issued
    3971             :          * and the readraw request croses on the wire, we must
    3972             :          * return a zero length response here.
    3973             :          */
    3974             : 
    3975          48 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    3976             : 
    3977             :         /*
    3978             :          * We have to do a check_fsp by hand here, as
    3979             :          * we must always return 4 zero bytes on error,
    3980             :          * not a NTSTATUS.
    3981             :          */
    3982             : 
    3983          48 :         if (fsp == NULL ||
    3984          44 :             conn == NULL ||
    3985          88 :             conn != fsp->conn ||
    3986          88 :             req->vuid != fsp->vuid ||
    3987          44 :             fsp->fsp_flags.is_directory ||
    3988          44 :             fsp_get_io_fd(fsp) == -1)
    3989             :         {
    3990             :                 /*
    3991             :                  * fsp could be NULL here so use the value from the packet. JRA.
    3992             :                  */
    3993           4 :                 DEBUG(3,("reply_readbraw: fnum %d not valid "
    3994             :                         "- cache prime?\n",
    3995             :                         (int)SVAL(req->vwv+0, 0)));
    3996           4 :                 reply_readbraw_error(xconn);
    3997           4 :                 END_PROFILE(SMBreadbraw);
    3998           4 :                 return;
    3999             :         }
    4000             : 
    4001             :         /* Do a "by hand" version of CHECK_READ. */
    4002          44 :         if (!(fsp->fsp_flags.can_read ||
    4003           0 :                         ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
    4004           0 :                                 (fsp->access_mask & FILE_EXECUTE)))) {
    4005           0 :                 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
    4006             :                                 (int)SVAL(req->vwv+0, 0)));
    4007           0 :                 reply_readbraw_error(xconn);
    4008           0 :                 END_PROFILE(SMBreadbraw);
    4009           0 :                 return;
    4010             :         }
    4011             : 
    4012          44 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
    4013          44 :         if(req->wct == 10) {
    4014             :                 /*
    4015             :                  * This is a large offset (64 bit) read.
    4016             :                  */
    4017             : 
    4018          44 :                 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
    4019             : 
    4020          44 :                 if(startpos < 0) {
    4021           4 :                         DEBUG(0,("reply_readbraw: negative 64 bit "
    4022             :                                 "readraw offset (%.0f) !\n",
    4023             :                                 (double)startpos ));
    4024           4 :                         reply_readbraw_error(xconn);
    4025           4 :                         END_PROFILE(SMBreadbraw);
    4026           4 :                         return;
    4027             :                 }
    4028             :         }
    4029             : 
    4030          40 :         maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
    4031          40 :         mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
    4032             : 
    4033             :         /* ensure we don't overrun the packet size */
    4034          40 :         maxcount = MIN(65535,maxcount);
    4035             : 
    4036          40 :         init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    4037             :             (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
    4038             :             &lock);
    4039             : 
    4040          40 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    4041           8 :                 reply_readbraw_error(xconn);
    4042           8 :                 END_PROFILE(SMBreadbraw);
    4043           8 :                 return;
    4044             :         }
    4045             : 
    4046          32 :         status = vfs_stat_fsp(fsp);
    4047          32 :         if (NT_STATUS_IS_OK(status)) {
    4048          32 :                 size = fsp->fsp_name->st.st_ex_size;
    4049             :         }
    4050             : 
    4051          32 :         if (startpos >= size) {
    4052          12 :                 nread = 0;
    4053             :         } else {
    4054          20 :                 nread = MIN(maxcount,(size - startpos));
    4055             :         }
    4056             : 
    4057             : #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
    4058             :         if (nread < mincount)
    4059             :                 nread = 0;
    4060             : #endif
    4061             : 
    4062          32 :         DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
    4063             :                 "min=%lu nread=%lu\n",
    4064             :                 fsp_fnum_dbg(fsp), (double)startpos,
    4065             :                 (unsigned long)maxcount,
    4066             :                 (unsigned long)mincount,
    4067             :                 (unsigned long)nread ) );
    4068             : 
    4069          32 :         send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
    4070             : 
    4071          32 :         DEBUG(5,("reply_readbraw finished\n"));
    4072             : 
    4073          32 :         END_PROFILE(SMBreadbraw);
    4074          32 :         return;
    4075             : }
    4076             : 
    4077             : #undef DBGC_CLASS
    4078             : #define DBGC_CLASS DBGC_LOCKING
    4079             : 
    4080             : /****************************************************************************
    4081             :  Reply to a lockread (core+ protocol).
    4082             : ****************************************************************************/
    4083             : 
    4084             : static void reply_lockread_locked(struct tevent_req *subreq);
    4085             : 
    4086          91 : void reply_lockread(struct smb_request *req)
    4087             : {
    4088          91 :         struct tevent_req *subreq = NULL;
    4089          91 :         connection_struct *conn = req->conn;
    4090             :         files_struct *fsp;
    4091          91 :         struct smbd_lock_element *lck = NULL;
    4092             : 
    4093          91 :         START_PROFILE(SMBlockread);
    4094             : 
    4095          91 :         if (req->wct < 5) {
    4096           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    4097           0 :                 END_PROFILE(SMBlockread);
    4098           5 :                 return;
    4099             :         }
    4100             : 
    4101          91 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    4102             : 
    4103          91 :         if (!check_fsp(conn, req, fsp)) {
    4104           7 :                 END_PROFILE(SMBlockread);
    4105           6 :                 return;
    4106             :         }
    4107             : 
    4108          84 :         if (!CHECK_READ(fsp,req)) {
    4109           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    4110           0 :                 END_PROFILE(SMBlockread);
    4111           0 :                 return;
    4112             :         }
    4113             : 
    4114          84 :         lck = talloc(req, struct smbd_lock_element);
    4115          84 :         if (lck == NULL) {
    4116           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    4117           0 :                 END_PROFILE(SMBlockread);
    4118           0 :                 return;
    4119             :         }
    4120             : 
    4121             :         /*
    4122             :          * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
    4123             :          * protocol request that predates the read/write lock concept. 
    4124             :          * Thus instead of asking for a read lock here we need to ask
    4125             :          * for a write lock. JRA.
    4126             :          * Note that the requested lock size is unaffected by max_send.
    4127             :          */
    4128             : 
    4129          84 :         *lck = (struct smbd_lock_element) {
    4130          84 :                 .req_guid = smbd_request_guid(req, 0),
    4131          84 :                 .smblctx = req->smbpid,
    4132             :                 .brltype = WRITE_LOCK,
    4133          84 :                 .count = SVAL(req->vwv+1, 0),
    4134          84 :                 .offset = IVAL_TO_SMB_OFF_T(req->vwv+2, 0),
    4135             :         };
    4136             : 
    4137          84 :         subreq = smbd_smb1_do_locks_send(
    4138             :                 fsp,
    4139          84 :                 req->sconn->ev_ctx,
    4140             :                 &req,
    4141             :                 fsp,
    4142             :                 0,
    4143             :                 false,          /* large_offset */
    4144             :                 WINDOWS_LOCK,
    4145             :                 1,
    4146             :                 lck);
    4147          84 :         if (subreq == NULL) {
    4148           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    4149           0 :                 END_PROFILE(SMBlockread);
    4150           0 :                 return;
    4151             :         }
    4152          84 :         tevent_req_set_callback(subreq, reply_lockread_locked, NULL);
    4153          84 :         END_PROFILE(SMBlockread);
    4154             : }
    4155             : 
    4156          84 : static void reply_lockread_locked(struct tevent_req *subreq)
    4157             : {
    4158          84 :         struct smb_request *req = NULL;
    4159          84 :         ssize_t nread = -1;
    4160          84 :         char *data = NULL;
    4161             :         NTSTATUS status;
    4162             :         bool ok;
    4163             :         off_t startpos;
    4164             :         size_t numtoread, maxtoread;
    4165          84 :         struct files_struct *fsp = NULL;
    4166          84 :         char *p = NULL;
    4167             : 
    4168          84 :         START_PROFILE(SMBlockread);
    4169             : 
    4170          84 :         ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
    4171          84 :         SMB_ASSERT(ok);
    4172             : 
    4173          84 :         status = smbd_smb1_do_locks_recv(subreq);
    4174          84 :         TALLOC_FREE(subreq);
    4175             : 
    4176          84 :         if (!NT_STATUS_IS_OK(status)) {
    4177          42 :                 reply_nterror(req, status);
    4178          42 :                 goto send;
    4179             :         }
    4180             : 
    4181          42 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    4182          42 :         if (fsp == NULL) {
    4183           0 :                 reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
    4184           0 :                 goto send;
    4185             :         }
    4186             : 
    4187          42 :         numtoread = SVAL(req->vwv+1, 0);
    4188          42 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
    4189             : 
    4190             :         /*
    4191             :          * However the requested READ size IS affected by max_send. Insanity.... JRA.
    4192             :          */
    4193          42 :         maxtoread = req->xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
    4194             : 
    4195          42 :         if (numtoread > maxtoread) {
    4196           7 :                 DBG_WARNING("requested read size (%zu) is greater than "
    4197             :                             "maximum allowed (%zu/%d). "
    4198             :                             "Returning short read of maximum allowed for "
    4199             :                             "compatibility with Windows 2000.\n",
    4200             :                             numtoread,
    4201             :                             maxtoread,
    4202             :                             req->xconn->smb1.sessions.max_send);
    4203           6 :                 numtoread = maxtoread;
    4204             :         }
    4205             : 
    4206          42 :         reply_outbuf(req, 5, numtoread + 3);
    4207             : 
    4208          42 :         data = smb_buf(req->outbuf) + 3;
    4209             : 
    4210          42 :         nread = read_file(fsp,data,startpos,numtoread);
    4211             : 
    4212          42 :         if (nread < 0) {
    4213           0 :                 reply_nterror(req, map_nt_error_from_unix(errno));
    4214           0 :                 goto send;
    4215             :         }
    4216             : 
    4217          42 :         srv_set_message((char *)req->outbuf, 5, nread+3, False);
    4218             : 
    4219          42 :         SSVAL(req->outbuf,smb_vwv0,nread);
    4220          42 :         SSVAL(req->outbuf,smb_vwv5,nread+3);
    4221          42 :         p = smb_buf(req->outbuf);
    4222          42 :         SCVAL(p,0,0); /* pad byte. */
    4223          42 :         SSVAL(p,1,nread);
    4224             : 
    4225          42 :         DEBUG(3,("lockread %s num=%d nread=%d\n",
    4226             :                  fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
    4227             : 
    4228          84 : send:
    4229         228 :         ok = srv_send_smb(req->xconn,
    4230          84 :                           (char *)req->outbuf,
    4231             :                           true,
    4232          84 :                           req->seqnum+1,
    4233          84 :                           IS_CONN_ENCRYPTED(req->conn),
    4234             :                           NULL);
    4235          84 :         if (!ok) {
    4236           0 :                 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
    4237             :         }
    4238          84 :         TALLOC_FREE(req);
    4239          84 :         END_PROFILE(SMBlockread);
    4240          84 :         return;
    4241             : }
    4242             : 
    4243             : #undef DBGC_CLASS
    4244             : #define DBGC_CLASS DBGC_ALL
    4245             : 
    4246             : /****************************************************************************
    4247             :  Reply to a read.
    4248             : ****************************************************************************/
    4249             : 
    4250          56 : void reply_read(struct smb_request *req)
    4251             : {
    4252          56 :         connection_struct *conn = req->conn;
    4253             :         size_t numtoread;
    4254             :         size_t maxtoread;
    4255          56 :         ssize_t nread = 0;
    4256             :         char *data;
    4257             :         off_t startpos;
    4258             :         files_struct *fsp;
    4259             :         struct lock_struct lock;
    4260          56 :         struct smbXsrv_connection *xconn = req->xconn;
    4261             : 
    4262          56 :         START_PROFILE(SMBread);
    4263             : 
    4264          56 :         if (req->wct < 3) {
    4265           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    4266           0 :                 END_PROFILE(SMBread);
    4267           0 :                 return;
    4268             :         }
    4269             : 
    4270          56 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    4271             : 
    4272          56 :         if (!check_fsp(conn, req, fsp)) {
    4273           7 :                 END_PROFILE(SMBread);
    4274           6 :                 return;
    4275             :         }
    4276             : 
    4277          49 :         if (!CHECK_READ(fsp,req)) {
    4278           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    4279           0 :                 END_PROFILE(SMBread);
    4280           0 :                 return;
    4281             :         }
    4282             : 
    4283          49 :         numtoread = SVAL(req->vwv+1, 0);
    4284          49 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
    4285             : 
    4286             :         /*
    4287             :          * The requested read size cannot be greater than max_send. JRA.
    4288             :          */
    4289          49 :         maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
    4290             : 
    4291          49 :         if (numtoread > maxtoread) {
    4292          14 :                 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
    4293             : Returning short read of maximum allowed for compatibility with Windows 2000.\n",
    4294             :                         (unsigned int)numtoread, (unsigned int)maxtoread,
    4295             :                         (unsigned int)xconn->smb1.sessions.max_send));
    4296          12 :                 numtoread = maxtoread;
    4297             :         }
    4298             : 
    4299          49 :         reply_outbuf(req, 5, numtoread+3);
    4300             : 
    4301          49 :         data = smb_buf(req->outbuf) + 3;
    4302             : 
    4303          49 :         init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    4304             :             (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
    4305             :             &lock);
    4306             : 
    4307          49 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    4308           7 :                 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    4309           7 :                 END_PROFILE(SMBread);
    4310           6 :                 return;
    4311             :         }
    4312             : 
    4313          42 :         if (numtoread > 0)
    4314          35 :                 nread = read_file(fsp,data,startpos,numtoread);
    4315             : 
    4316          41 :         if (nread < 0) {
    4317           0 :                 reply_nterror(req, map_nt_error_from_unix(errno));
    4318           0 :                 goto out;
    4319             :         }
    4320             : 
    4321          42 :         srv_set_message((char *)req->outbuf, 5, nread+3, False);
    4322             : 
    4323          42 :         SSVAL(req->outbuf,smb_vwv0,nread);
    4324          42 :         SSVAL(req->outbuf,smb_vwv5,nread+3);
    4325          42 :         SCVAL(smb_buf(req->outbuf),0,1);
    4326          42 :         SSVAL(smb_buf(req->outbuf),1,nread);
    4327             : 
    4328          42 :         DEBUG(3, ("read %s num=%d nread=%d\n",
    4329             :                   fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
    4330             : 
    4331          42 : out:
    4332          42 :         END_PROFILE(SMBread);
    4333          36 :         return;
    4334             : }
    4335             : 
    4336             : /****************************************************************************
    4337             :  Setup readX header.
    4338             : ****************************************************************************/
    4339             : 
    4340        9401 : size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
    4341             : {
    4342             :         size_t outsize;
    4343             : 
    4344        9401 :         outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
    4345             :                                   False);
    4346             : 
    4347        9446 :         memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
    4348             : 
    4349        9401 :         SCVAL(outbuf,smb_vwv0,0xFF);
    4350        9401 :         SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
    4351        9401 :         SSVAL(outbuf,smb_vwv5,smb_maxcnt);
    4352        9401 :         SSVAL(outbuf,smb_vwv6,
    4353             :               (smb_wct - 4)     /* offset from smb header to wct */
    4354             :               + 1               /* the wct field */
    4355             :               + 12 * sizeof(uint16_t) /* vwv */
    4356             :               + 2               /* the buflen field */
    4357             :               + 1);             /* padding byte */
    4358        9401 :         SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
    4359        9401 :         SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
    4360             :         /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
    4361        9401 :         _smb_setlen_large(outbuf,
    4362             :                           smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
    4363        9401 :         return outsize;
    4364             : }
    4365             : 
    4366             : /****************************************************************************
    4367             :  Reply to a read and X - possibly using sendfile.
    4368             : ****************************************************************************/
    4369             : 
    4370          65 : static void send_file_readX(connection_struct *conn, struct smb_request *req,
    4371             :                             files_struct *fsp, off_t startpos,
    4372             :                             size_t smb_maxcnt)
    4373             : {
    4374          65 :         struct smbXsrv_connection *xconn = req->xconn;
    4375          65 :         ssize_t nread = -1;
    4376             :         struct lock_struct lock;
    4377          65 :         int saved_errno = 0;
    4378             :         NTSTATUS status;
    4379             : 
    4380          65 :         init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    4381             :             (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
    4382             :             &lock);
    4383             : 
    4384          65 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    4385           0 :                 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    4386           0 :                 return;
    4387             :         }
    4388             : 
    4389             :         /*
    4390             :          * We can only use sendfile on a non-chained packet
    4391             :          * but we can use on a non-oplocked file. tridge proved this
    4392             :          * on a train in Germany :-). JRA.
    4393             :          */
    4394             : 
    4395         112 :         if (!req_is_in_chain(req) &&
    4396         102 :             !req->encrypted &&
    4397          82 :             (fsp->base_fsp == NULL) &&
    4398          27 :             lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
    4399             :                 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
    4400             :                 DATA_BLOB header;
    4401             : 
    4402           0 :                 status = vfs_stat_fsp(fsp);
    4403           0 :                 if (!NT_STATUS_IS_OK(status)) {
    4404           0 :                         reply_nterror(req, status);
    4405           0 :                         goto out;
    4406             :                 }
    4407             : 
    4408           0 :                 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
    4409           0 :                     (startpos > fsp->fsp_name->st.st_ex_size) ||
    4410           0 :                     (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
    4411             :                         /*
    4412             :                          * We already know that we would do a short read, so don't
    4413             :                          * try the sendfile() path.
    4414             :                          */
    4415           0 :                         goto nosendfile_read;
    4416             :                 }
    4417             : 
    4418             :                 /*
    4419             :                  * Set up the packet header before send. We
    4420             :                  * assume here the sendfile will work (get the
    4421             :                  * correct amount of data).
    4422             :                  */
    4423             : 
    4424           0 :                 header = data_blob_const(headerbuf, sizeof(headerbuf));
    4425             : 
    4426           0 :                 construct_reply_common_req(req, (char *)headerbuf);
    4427           0 :                 setup_readX_header((char *)headerbuf, smb_maxcnt);
    4428             : 
    4429           0 :                 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
    4430             :                                          startpos, smb_maxcnt);
    4431           0 :                 if (nread == -1) {
    4432           0 :                         saved_errno = errno;
    4433             : 
    4434             :                         /* Returning ENOSYS means no data at all was sent.
    4435             :                            Do this as a normal read. */
    4436           0 :                         if (errno == ENOSYS) {
    4437           0 :                                 goto normal_read;
    4438             :                         }
    4439             : 
    4440             :                         /*
    4441             :                          * Special hack for broken Linux with no working sendfile. If we
    4442             :                          * return EINTR we sent the header but not the rest of the data.
    4443             :                          * Fake this up by doing read/write calls.
    4444             :                          */
    4445             : 
    4446           0 :                         if (errno == EINTR) {
    4447             :                                 /* Ensure we don't do this again. */
    4448           0 :                                 set_use_sendfile(SNUM(conn), False);
    4449           0 :                                 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
    4450           0 :                                 nread = fake_sendfile(xconn, fsp, startpos,
    4451             :                                                       smb_maxcnt);
    4452           0 :                                 if (nread == -1) {
    4453           0 :                                         saved_errno = errno;
    4454           0 :                                         DEBUG(0,("send_file_readX: "
    4455             :                                                  "fake_sendfile failed for "
    4456             :                                                  "file %s (%s) for client %s. "
    4457             :                                                  "Terminating\n",
    4458             :                                                  fsp_str_dbg(fsp),
    4459             :                                                  smbXsrv_connection_dbg(xconn),
    4460             :                                                  strerror(saved_errno)));
    4461           0 :                                         errno = saved_errno;
    4462           0 :                                         exit_server_cleanly("send_file_readX: fake_sendfile failed");
    4463             :                                 }
    4464           0 :                                 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
    4465             :                                           fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
    4466             :                                 /* No outbuf here means successful sendfile. */
    4467           0 :                                 goto out;
    4468             :                         }
    4469             : 
    4470           0 :                         DEBUG(0,("send_file_readX: sendfile failed for file "
    4471             :                                  "%s (%s). Terminating\n", fsp_str_dbg(fsp),
    4472             :                                  strerror(errno)));
    4473           0 :                         exit_server_cleanly("send_file_readX sendfile failed");
    4474           0 :                 } else if (nread == 0) {
    4475             :                         /*
    4476             :                          * Some sendfile implementations return 0 to indicate
    4477             :                          * that there was a short read, but nothing was
    4478             :                          * actually written to the socket.  In this case,
    4479             :                          * fallback to the normal read path so the header gets
    4480             :                          * the correct byte count.
    4481             :                          */
    4482           0 :                         DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
    4483             :                                   "falling back to the normal read: %s\n",
    4484             :                                   fsp_str_dbg(fsp)));
    4485           0 :                         goto normal_read;
    4486             :                 }
    4487             : 
    4488           0 :                 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
    4489             :                           fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
    4490             : 
    4491             :                 /* Deal with possible short send. */
    4492           0 :                 if (nread != smb_maxcnt + sizeof(headerbuf)) {
    4493             :                         ssize_t ret;
    4494             : 
    4495           0 :                         ret = sendfile_short_send(xconn, fsp, nread,
    4496             :                                                   sizeof(headerbuf), smb_maxcnt);
    4497           0 :                         if (ret == -1) {
    4498             :                                 const char *r;
    4499           0 :                                 r = "send_file_readX: sendfile_short_send failed";
    4500           0 :                                 DEBUG(0,("%s for file %s (%s).\n",
    4501             :                                          r, fsp_str_dbg(fsp), strerror(errno)));
    4502           0 :                                 exit_server_cleanly(r);
    4503             :                         }
    4504             :                 }
    4505             :                 /* No outbuf here means successful sendfile. */
    4506           0 :                 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
    4507           0 :                 SMB_PERFCOUNT_END(&req->pcd);
    4508           0 :                 goto out;
    4509             :         }
    4510             : 
    4511         117 : normal_read:
    4512             : 
    4513          65 :         if ((smb_maxcnt & 0xFF0000) > 0x10000) {
    4514             :                 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
    4515             :                 ssize_t ret;
    4516             : 
    4517          24 :                 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
    4518          24 :                     (startpos > fsp->fsp_name->st.st_ex_size) ||
    4519          12 :                     (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
    4520             :                         /*
    4521             :                          * We already know that we would do a short
    4522             :                          * read, so don't try the sendfile() path.
    4523             :                          */
    4524           0 :                         goto nosendfile_read;
    4525             :                 }
    4526             : 
    4527          12 :                 construct_reply_common_req(req, (char *)headerbuf);
    4528          12 :                 setup_readX_header((char *)headerbuf, smb_maxcnt);
    4529             : 
    4530             :                 /* Send out the header. */
    4531          12 :                 ret = write_data(xconn->transport.sock, (char *)headerbuf,
    4532             :                                  sizeof(headerbuf));
    4533          12 :                 if (ret != sizeof(headerbuf)) {
    4534           0 :                         saved_errno = errno;
    4535             :                         /*
    4536             :                          * Try and give an error message saying what
    4537             :                          * client failed.
    4538             :                          */
    4539           0 :                         DEBUG(0,("send_file_readX: write_data failed for file "
    4540             :                                  "%s (%s) for client %s. Terminating\n",
    4541             :                                  fsp_str_dbg(fsp),
    4542             :                                  smbXsrv_connection_dbg(xconn),
    4543             :                                  strerror(saved_errno)));
    4544           0 :                         errno = saved_errno;
    4545           0 :                         exit_server_cleanly("send_file_readX sendfile failed");
    4546             :                 }
    4547          12 :                 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
    4548          12 :                 if (nread == -1) {
    4549           0 :                         saved_errno = errno;
    4550           0 :                         DEBUG(0,("send_file_readX: fake_sendfile failed for file "
    4551             :                                  "%s (%s) for client %s. Terminating\n",
    4552             :                                  fsp_str_dbg(fsp),
    4553             :                                  smbXsrv_connection_dbg(xconn),
    4554             :                                  strerror(saved_errno)));
    4555           0 :                         errno = saved_errno;
    4556           0 :                         exit_server_cleanly("send_file_readX: fake_sendfile failed");
    4557             :                 }
    4558          12 :                 goto out;
    4559             :         }
    4560             : 
    4561          93 : nosendfile_read:
    4562             : 
    4563          53 :         reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
    4564          53 :         SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
    4565          53 :         SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
    4566             : 
    4567          53 :         nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
    4568             :                           startpos, smb_maxcnt);
    4569          53 :         saved_errno = errno;
    4570             : 
    4571          53 :         if (nread < 0) {
    4572           0 :                 reply_nterror(req, map_nt_error_from_unix(saved_errno));
    4573           0 :                 return;
    4574             :         }
    4575             : 
    4576          53 :         setup_readX_header((char *)req->outbuf, nread);
    4577             : 
    4578          53 :         DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
    4579             :                   fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
    4580          50 :         return;
    4581             : 
    4582          12 : out:
    4583          12 :         TALLOC_FREE(req->outbuf);
    4584          12 :         return;
    4585             : }
    4586             : 
    4587             : /****************************************************************************
    4588             :  Work out how much space we have for a read return.
    4589             : ****************************************************************************/
    4590             : 
    4591        9422 : static size_t calc_max_read_pdu(const struct smb_request *req)
    4592             : {
    4593        9422 :         struct smbXsrv_connection *xconn = req->xconn;
    4594             : 
    4595        9422 :         if (xconn->protocol < PROTOCOL_NT1) {
    4596           0 :                 return xconn->smb1.sessions.max_send;
    4597             :         }
    4598             : 
    4599        9422 :         if (!lp_large_readwrite()) {
    4600           0 :                 return xconn->smb1.sessions.max_send;
    4601             :         }
    4602             : 
    4603        9422 :         if (req_is_in_chain(req)) {
    4604          10 :                 return xconn->smb1.sessions.max_send;
    4605             :         }
    4606             : 
    4607        9412 :         if (req->encrypted) {
    4608             :                 /*
    4609             :                  * Don't take encrypted traffic up to the
    4610             :                  * limit. There are padding considerations
    4611             :                  * that make that tricky.
    4612             :                  */
    4613        3001 :                 return xconn->smb1.sessions.max_send;
    4614             :         }
    4615             : 
    4616        6411 :         if (srv_is_signing_active(xconn)) {
    4617         909 :                 return 0x1FFFF;
    4618             :         }
    4619             : 
    4620        5458 :         if (!lp_unix_extensions()) {
    4621           0 :                 return 0x1FFFF;
    4622             :         }
    4623             : 
    4624             :         /*
    4625             :          * We can do ultra-large POSIX reads.
    4626             :          */
    4627        5458 :         return 0xFFFFFF;
    4628             : }
    4629             : 
    4630             : /****************************************************************************
    4631             :  Calculate how big a read can be. Copes with all clients. It's always
    4632             :  safe to return a short read - Windows does this.
    4633             : ****************************************************************************/
    4634             : 
    4635        9422 : static size_t calc_read_size(const struct smb_request *req,
    4636             :                              size_t upper_size,
    4637             :                              size_t lower_size)
    4638             : {
    4639        9422 :         struct smbXsrv_connection *xconn = req->xconn;
    4640        9422 :         size_t max_pdu = calc_max_read_pdu(req);
    4641        9422 :         size_t total_size = 0;
    4642        9422 :         size_t hdr_len = MIN_SMB_SIZE + VWV(12);
    4643        9422 :         size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
    4644             : 
    4645             :         /*
    4646             :          * Windows explicitly ignores upper size of 0xFFFF.
    4647             :          * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
    4648             :          * We must do the same as these will never fit even in
    4649             :          * an extended size NetBIOS packet.
    4650             :          */
    4651        9422 :         if (upper_size == 0xFFFF) {
    4652           6 :                 upper_size = 0;
    4653             :         }
    4654             : 
    4655        9422 :         if (xconn->protocol < PROTOCOL_NT1) {
    4656           0 :                 upper_size = 0;
    4657             :         }
    4658             : 
    4659        9422 :         total_size = ((upper_size<<16) | lower_size);
    4660             : 
    4661             :         /*
    4662             :          * LARGE_READX test shows it's always safe to return
    4663             :          * a short read. Windows does so.
    4664             :          */
    4665        9422 :         return MIN(total_size, max_len);
    4666             : }
    4667             : 
    4668             : /****************************************************************************
    4669             :  Reply to a read and X.
    4670             : ****************************************************************************/
    4671             : 
    4672        9836 : void reply_read_and_X(struct smb_request *req)
    4673             : {
    4674        9836 :         connection_struct *conn = req->conn;
    4675             :         files_struct *fsp;
    4676             :         off_t startpos;
    4677             :         size_t smb_maxcnt;
    4678             :         size_t upper_size;
    4679        9836 :         bool big_readX = False;
    4680             : #if 0
    4681             :         size_t smb_mincnt = SVAL(req->vwv+6, 0);
    4682             : #endif
    4683             : 
    4684        9836 :         START_PROFILE(SMBreadX);
    4685             : 
    4686        9836 :         if ((req->wct != 10) && (req->wct != 12)) {
    4687           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    4688           0 :                 return;
    4689             :         }
    4690             : 
    4691        9836 :         fsp = file_fsp(req, SVAL(req->vwv+2, 0));
    4692        9836 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
    4693        9836 :         smb_maxcnt = SVAL(req->vwv+5, 0);
    4694             : 
    4695             :         /* If it's an IPC, pass off the pipe handler. */
    4696        9836 :         if (IS_IPC(conn)) {
    4697          28 :                 reply_pipe_read_and_X(req);
    4698          28 :                 END_PROFILE(SMBreadX);
    4699          28 :                 return;
    4700             :         }
    4701             : 
    4702        9808 :         if (!check_fsp(conn, req, fsp)) {
    4703          39 :                 END_PROFILE(SMBreadX);
    4704          38 :                 return;
    4705             :         }
    4706             : 
    4707        9769 :         if (!CHECK_READ(fsp,req)) {
    4708         347 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    4709         347 :                 END_PROFILE(SMBreadX);
    4710         345 :                 return;
    4711             :         }
    4712             : 
    4713        9422 :         upper_size = SVAL(req->vwv+7, 0);
    4714        9422 :         smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
    4715        9422 :         if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
    4716             :                 /*
    4717             :                  * This is a heuristic to avoid keeping large
    4718             :                  * outgoing buffers around over long-lived aio
    4719             :                  * requests.
    4720             :                  */
    4721          12 :                 big_readX = True;
    4722             :         }
    4723             : 
    4724        9422 :         if (req->wct == 12) {
    4725             :                 /*
    4726             :                  * This is a large offset (64 bit) read.
    4727             :                  */
    4728        9422 :                 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
    4729             : 
    4730             :         }
    4731             : 
    4732        9422 :         if (!big_readX) {
    4733        9410 :                 NTSTATUS status = schedule_aio_read_and_X(conn,
    4734             :                                         req,
    4735             :                                         fsp,
    4736             :                                         startpos,
    4737             :                                         smb_maxcnt);
    4738        9410 :                 if (NT_STATUS_IS_OK(status)) {
    4739             :                         /* Read scheduled - we're done. */
    4740        9294 :                         goto out;
    4741             :                 }
    4742          74 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
    4743             :                         /* Real error - report to client. */
    4744          21 :                         END_PROFILE(SMBreadX);
    4745          21 :                         reply_nterror(req, status);
    4746          21 :                         return;
    4747             :                 }
    4748             :                 /* NT_STATUS_RETRY - fall back to sync read. */
    4749             :         }
    4750             : 
    4751          65 :         smbd_lock_socket(req->xconn);
    4752          65 :         send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
    4753          65 :         smbd_unlock_socket(req->xconn);
    4754             : 
    4755        9401 :  out:
    4756        9401 :         END_PROFILE(SMBreadX);
    4757        9356 :         return;
    4758             : }
    4759             : 
    4760             : /****************************************************************************
    4761             :  Error replies to writebraw must have smb_wct == 1. Fix this up.
    4762             : ****************************************************************************/
    4763             : 
    4764           0 : void error_to_writebrawerr(struct smb_request *req)
    4765             : {
    4766           0 :         uint8_t *old_outbuf = req->outbuf;
    4767             : 
    4768           0 :         reply_outbuf(req, 1, 0);
    4769             : 
    4770           0 :         memcpy(req->outbuf, old_outbuf, smb_size);
    4771           0 :         TALLOC_FREE(old_outbuf);
    4772           0 : }
    4773             : 
    4774             : /****************************************************************************
    4775             :  Read 4 bytes of a smb packet and return the smb length of the packet.
    4776             :  Store the result in the buffer. This version of the function will
    4777             :  never return a session keepalive (length of zero).
    4778             :  Timeout is in milliseconds.
    4779             : ****************************************************************************/
    4780             : 
    4781           0 : static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
    4782             :                                 size_t *len)
    4783             : {
    4784           0 :         uint8_t msgtype = NBSSkeepalive;
    4785             : 
    4786           0 :         while (msgtype == NBSSkeepalive) {
    4787             :                 NTSTATUS status;
    4788             : 
    4789           0 :                 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
    4790             :                                                           len);
    4791           0 :                 if (!NT_STATUS_IS_OK(status)) {
    4792             :                         char addr[INET6_ADDRSTRLEN];
    4793             :                         /* Try and give an error message
    4794             :                          * saying what client failed. */
    4795           0 :                         DEBUG(0, ("read_smb_length_return_keepalive failed for "
    4796             :                                   "client %s read error = %s.\n",
    4797             :                                   get_peer_addr(fd,addr,sizeof(addr)),
    4798             :                                   nt_errstr(status)));
    4799           0 :                         return status;
    4800             :                 }
    4801             : 
    4802           0 :                 msgtype = CVAL(inbuf, 0);
    4803             :         }
    4804             : 
    4805           0 :         DEBUG(10,("read_smb_length: got smb length of %lu\n",
    4806             :                   (unsigned long)len));
    4807             : 
    4808           0 :         return NT_STATUS_OK;
    4809             : }
    4810             : 
    4811             : /****************************************************************************
    4812             :  Reply to a writebraw (core+ or LANMAN1.0 protocol).
    4813             : ****************************************************************************/
    4814             : 
    4815           0 : void reply_writebraw(struct smb_request *req)
    4816             : {
    4817           0 :         connection_struct *conn = req->conn;
    4818           0 :         struct smbXsrv_connection *xconn = req->xconn;
    4819           0 :         char *buf = NULL;
    4820           0 :         ssize_t nwritten=0;
    4821           0 :         ssize_t total_written=0;
    4822           0 :         size_t numtowrite=0;
    4823             :         size_t tcount;
    4824             :         off_t startpos;
    4825           0 :         const char *data=NULL;
    4826             :         bool write_through;
    4827             :         files_struct *fsp;
    4828             :         struct lock_struct lock;
    4829             :         NTSTATUS status;
    4830             : 
    4831           0 :         START_PROFILE(SMBwritebraw);
    4832             : 
    4833             :         /*
    4834             :          * If we ever reply with an error, it must have the SMB command
    4835             :          * type of SMBwritec, not SMBwriteBraw, as this tells the client
    4836             :          * we're finished.
    4837             :          */
    4838           0 :         SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
    4839             : 
    4840           0 :         if (srv_is_signing_active(xconn)) {
    4841           0 :                 END_PROFILE(SMBwritebraw);
    4842           0 :                 exit_server_cleanly("reply_writebraw: SMB signing is active - "
    4843             :                                 "raw reads/writes are disallowed.");
    4844             :         }
    4845             : 
    4846           0 :         if (req->wct < 12) {
    4847           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    4848           0 :                 error_to_writebrawerr(req);
    4849           0 :                 END_PROFILE(SMBwritebraw);
    4850           0 :                 return;
    4851             :         }
    4852             : 
    4853           0 :         if (xconn->smb1.echo_handler.trusted_fde) {
    4854           0 :                 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
    4855             :                          "'async smb echo handler = yes'\n"));
    4856           0 :                 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
    4857           0 :                 error_to_writebrawerr(req);
    4858           0 :                 END_PROFILE(SMBwritebraw);
    4859           0 :                 return;
    4860             :         }
    4861             : 
    4862           0 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    4863           0 :         if (!check_fsp(conn, req, fsp)) {
    4864           0 :                 error_to_writebrawerr(req);
    4865           0 :                 END_PROFILE(SMBwritebraw);
    4866           0 :                 return;
    4867             :         }
    4868             : 
    4869           0 :         if (!CHECK_WRITE(fsp)) {
    4870           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    4871           0 :                 error_to_writebrawerr(req);
    4872           0 :                 END_PROFILE(SMBwritebraw);
    4873           0 :                 return;
    4874             :         }
    4875             : 
    4876           0 :         tcount = IVAL(req->vwv+1, 0);
    4877           0 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
    4878           0 :         write_through = BITSETW(req->vwv+7,0);
    4879             : 
    4880             :         /* We have to deal with slightly different formats depending
    4881             :                 on whether we are using the core+ or lanman1.0 protocol */
    4882             : 
    4883           0 :         if(get_Protocol() <= PROTOCOL_COREPLUS) {
    4884           0 :                 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
    4885           0 :                 data = smb_buf_const(req->inbuf);
    4886             :         } else {
    4887           0 :                 numtowrite = SVAL(req->vwv+10, 0);
    4888           0 :                 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
    4889             :         }
    4890             : 
    4891             :         /* Ensure we don't write bytes past the end of this packet. */
    4892             :         /*
    4893             :          * This already protects us against CVE-2017-12163.
    4894             :          */
    4895           0 :         if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
    4896           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    4897           0 :                 error_to_writebrawerr(req);
    4898           0 :                 END_PROFILE(SMBwritebraw);
    4899           0 :                 return;
    4900             :         }
    4901             : 
    4902           0 :         if (!fsp->print_file) {
    4903           0 :                 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    4904             :                     (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
    4905             :                     &lock);
    4906             : 
    4907           0 :                 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    4908           0 :                         reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    4909           0 :                         error_to_writebrawerr(req);
    4910           0 :                         END_PROFILE(SMBwritebraw);
    4911           0 :                         return;
    4912             :                 }
    4913             :         }
    4914             : 
    4915           0 :         if (numtowrite>0) {
    4916           0 :                 nwritten = write_file(req,fsp,data,startpos,numtowrite);
    4917             :         }
    4918             : 
    4919           0 :         DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
    4920             :                         "wrote=%d sync=%d\n",
    4921             :                 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
    4922             :                 (int)nwritten, (int)write_through));
    4923             : 
    4924           0 :         if (nwritten < (ssize_t)numtowrite)  {
    4925           0 :                 reply_nterror(req, NT_STATUS_DISK_FULL);
    4926           0 :                 error_to_writebrawerr(req);
    4927           0 :                 goto out;
    4928             :         }
    4929             : 
    4930           0 :         total_written = nwritten;
    4931             : 
    4932             :         /* Allocate a buffer of 64k + length. */
    4933           0 :         buf = talloc_array(NULL, char, 65540);
    4934           0 :         if (!buf) {
    4935           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    4936           0 :                 error_to_writebrawerr(req);
    4937           0 :                 goto out;
    4938             :         }
    4939             : 
    4940             :         /* Return a SMBwritebraw message to the redirector to tell
    4941             :          * it to send more bytes */
    4942             : 
    4943           0 :         memcpy(buf, req->inbuf, smb_size);
    4944           0 :         srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
    4945           0 :         SCVAL(buf,smb_com,SMBwritebraw);
    4946           0 :         SSVALS(buf,smb_vwv0,0xFFFF);
    4947           0 :         show_msg(buf);
    4948           0 :         if (!srv_send_smb(req->xconn,
    4949             :                           buf,
    4950             :                           false, 0, /* no signing */
    4951           0 :                           IS_CONN_ENCRYPTED(conn),
    4952             :                           &req->pcd)) {
    4953           0 :                 exit_server_cleanly("reply_writebraw: srv_send_smb "
    4954             :                         "failed.");
    4955             :         }
    4956             : 
    4957             :         /* Now read the raw data into the buffer and write it */
    4958           0 :         status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
    4959             :                                  &numtowrite);
    4960           0 :         if (!NT_STATUS_IS_OK(status)) {
    4961           0 :                 exit_server_cleanly("secondary writebraw failed");
    4962             :         }
    4963             : 
    4964             :         /* Set up outbuf to return the correct size */
    4965           0 :         reply_outbuf(req, 1, 0);
    4966             : 
    4967           0 :         if (numtowrite != 0) {
    4968             : 
    4969           0 :                 if (numtowrite > 0xFFFF) {
    4970           0 :                         DEBUG(0,("reply_writebraw: Oversize secondary write "
    4971             :                                 "raw requested (%u). Terminating\n",
    4972             :                                 (unsigned int)numtowrite ));
    4973           0 :                         exit_server_cleanly("secondary writebraw failed");
    4974             :                 }
    4975             : 
    4976           0 :                 if (tcount > nwritten+numtowrite) {
    4977           0 :                         DEBUG(3,("reply_writebraw: Client overestimated the "
    4978             :                                 "write %d %d %d\n",
    4979             :                                 (int)tcount,(int)nwritten,(int)numtowrite));
    4980             :                 }
    4981             : 
    4982           0 :                 status = read_data_ntstatus(xconn->transport.sock, buf+4,
    4983             :                                             numtowrite);
    4984             : 
    4985           0 :                 if (!NT_STATUS_IS_OK(status)) {
    4986             :                         /* Try and give an error message
    4987             :                          * saying what client failed. */
    4988           0 :                         DEBUG(0, ("reply_writebraw: Oversize secondary write "
    4989             :                                   "raw read failed (%s) for client %s. "
    4990             :                                   "Terminating\n", nt_errstr(status),
    4991             :                                   smbXsrv_connection_dbg(xconn)));
    4992           0 :                         exit_server_cleanly("secondary writebraw failed");
    4993             :                 }
    4994             : 
    4995             :                 /*
    4996             :                  * We are not vulnerable to CVE-2017-12163
    4997             :                  * here as we are guaranteed to have numtowrite
    4998             :                  * bytes available - we just read from the client.
    4999             :                  */
    5000           0 :                 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
    5001           0 :                 if (nwritten == -1) {
    5002           0 :                         TALLOC_FREE(buf);
    5003           0 :                         reply_nterror(req, map_nt_error_from_unix(errno));
    5004           0 :                         error_to_writebrawerr(req);
    5005           0 :                         goto out;
    5006             :                 }
    5007             : 
    5008           0 :                 if (nwritten < (ssize_t)numtowrite) {
    5009           0 :                         SCVAL(req->outbuf,smb_rcls,ERRHRD);
    5010           0 :                         SSVAL(req->outbuf,smb_err,ERRdiskfull);
    5011             :                 }
    5012             : 
    5013           0 :                 if (nwritten > 0) {
    5014           0 :                         total_written += nwritten;
    5015             :                 }
    5016             :         }
    5017             : 
    5018           0 :         TALLOC_FREE(buf);
    5019           0 :         SSVAL(req->outbuf,smb_vwv0,total_written);
    5020             : 
    5021           0 :         status = sync_file(conn, fsp, write_through);
    5022           0 :         if (!NT_STATUS_IS_OK(status)) {
    5023           0 :                 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
    5024             :                          fsp_str_dbg(fsp), nt_errstr(status)));
    5025           0 :                 reply_nterror(req, status);
    5026           0 :                 error_to_writebrawerr(req);
    5027           0 :                 goto out;
    5028             :         }
    5029             : 
    5030           0 :         DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
    5031             :                 "wrote=%d\n",
    5032             :                 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
    5033             :                 (int)total_written));
    5034             : 
    5035             :         /* We won't return a status if write through is not selected - this
    5036             :          * follows what WfWg does */
    5037           0 :         END_PROFILE(SMBwritebraw);
    5038             : 
    5039           0 :         if (!write_through && total_written==tcount) {
    5040             : 
    5041             : #if RABBIT_PELLET_FIX
    5042             :                 /*
    5043             :                  * Fix for "rabbit pellet" mode, trigger an early TCP ack by
    5044             :                  * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
    5045             :                  * JRA.
    5046             :                  */
    5047           0 :                 if (!send_keepalive(xconn->transport.sock)) {
    5048           0 :                         exit_server_cleanly("reply_writebraw: send of "
    5049             :                                 "keepalive failed");
    5050             :                 }
    5051             : #endif
    5052           0 :                 TALLOC_FREE(req->outbuf);
    5053             :         }
    5054           0 :         return;
    5055             : 
    5056           0 : out:
    5057           0 :         END_PROFILE(SMBwritebraw);
    5058           0 :         return;
    5059             : }
    5060             : 
    5061             : #undef DBGC_CLASS
    5062             : #define DBGC_CLASS DBGC_LOCKING
    5063             : 
    5064             : /****************************************************************************
    5065             :  Reply to a writeunlock (core+).
    5066             : ****************************************************************************/
    5067             : 
    5068          35 : void reply_writeunlock(struct smb_request *req)
    5069             : {
    5070          35 :         connection_struct *conn = req->conn;
    5071          35 :         ssize_t nwritten = -1;
    5072             :         size_t numtowrite;
    5073             :         size_t remaining;
    5074             :         off_t startpos;
    5075             :         const char *data;
    5076          35 :         NTSTATUS status = NT_STATUS_OK;
    5077             :         files_struct *fsp;
    5078             :         struct lock_struct lock;
    5079          35 :         int saved_errno = 0;
    5080             : 
    5081          35 :         START_PROFILE(SMBwriteunlock);
    5082             : 
    5083          35 :         if (req->wct < 5) {
    5084           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5085           0 :                 END_PROFILE(SMBwriteunlock);
    5086           0 :                 return;
    5087             :         }
    5088             : 
    5089          35 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    5090             : 
    5091          35 :         if (!check_fsp(conn, req, fsp)) {
    5092           5 :                 END_PROFILE(SMBwriteunlock);
    5093           4 :                 return;
    5094             :         }
    5095             : 
    5096          30 :         if (!CHECK_WRITE(fsp)) {
    5097           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    5098           0 :                 END_PROFILE(SMBwriteunlock);
    5099           0 :                 return;
    5100             :         }
    5101             : 
    5102          30 :         numtowrite = SVAL(req->vwv+1, 0);
    5103          30 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
    5104          30 :         data = (const char *)req->buf + 3;
    5105             : 
    5106             :         /*
    5107             :          * Ensure client isn't asking us to write more than
    5108             :          * they sent. CVE-2017-12163.
    5109             :          */
    5110          30 :         remaining = smbreq_bufrem(req, data);
    5111          30 :         if (numtowrite > remaining) {
    5112           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5113           0 :                 END_PROFILE(SMBwriteunlock);
    5114           0 :                 return;
    5115             :         }
    5116             : 
    5117          30 :         if (!fsp->print_file && numtowrite > 0) {
    5118          25 :                 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    5119             :                     (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
    5120             :                     &lock);
    5121             : 
    5122          25 :                 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    5123           0 :                         reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    5124           0 :                         END_PROFILE(SMBwriteunlock);
    5125           0 :                         return;
    5126             :                 }
    5127             :         }
    5128             : 
    5129             :         /* The special X/Open SMB protocol handling of
    5130             :            zero length writes is *NOT* done for
    5131             :            this call */
    5132          30 :         if(numtowrite == 0) {
    5133           4 :                 nwritten = 0;
    5134             :         } else {
    5135          25 :                 nwritten = write_file(req,fsp,data,startpos,numtowrite);
    5136          25 :                 saved_errno = errno;
    5137             :         }
    5138             : 
    5139          30 :         status = sync_file(conn, fsp, False /* write through */);
    5140          30 :         if (!NT_STATUS_IS_OK(status)) {
    5141           0 :                 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
    5142             :                          fsp_str_dbg(fsp), nt_errstr(status)));
    5143           0 :                 reply_nterror(req, status);
    5144           0 :                 goto out;
    5145             :         }
    5146             : 
    5147          30 :         if(nwritten < 0) {
    5148           0 :                 reply_nterror(req, map_nt_error_from_unix(saved_errno));
    5149           0 :                 goto out;
    5150             :         }
    5151             : 
    5152          30 :         if((nwritten < numtowrite) && (numtowrite != 0)) {
    5153           0 :                 reply_nterror(req, NT_STATUS_DISK_FULL);
    5154           0 :                 goto out;
    5155             :         }
    5156             : 
    5157          30 :         if (numtowrite && !fsp->print_file) {
    5158          45 :                 struct smbd_lock_element l = {
    5159           5 :                         .req_guid = smbd_request_guid(req, 0),
    5160          25 :                         .smblctx = req->smbpid,
    5161             :                         .brltype = UNLOCK_LOCK,
    5162             :                         .offset = startpos,
    5163             :                         .count = numtowrite,
    5164             :                 };
    5165          25 :                 status = smbd_do_unlocking(req, fsp, 1, &l, WINDOWS_LOCK);
    5166          25 :                 if (NT_STATUS_V(status)) {
    5167          10 :                         reply_nterror(req, status);
    5168          10 :                         goto out;
    5169             :                 }
    5170             :         }
    5171             : 
    5172          20 :         reply_outbuf(req, 1, 0);
    5173             : 
    5174          20 :         SSVAL(req->outbuf,smb_vwv0,nwritten);
    5175             : 
    5176          20 :         DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
    5177             :                   fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
    5178             : 
    5179          30 : out:
    5180          30 :         END_PROFILE(SMBwriteunlock);
    5181          24 :         return;
    5182             : }
    5183             : 
    5184             : #undef DBGC_CLASS
    5185             : #define DBGC_CLASS DBGC_ALL
    5186             : 
    5187             : /****************************************************************************
    5188             :  Reply to a write.
    5189             : ****************************************************************************/
    5190             : 
    5191         199 : void reply_write(struct smb_request *req)
    5192             : {
    5193         199 :         connection_struct *conn = req->conn;
    5194             :         size_t numtowrite;
    5195             :         size_t remaining;
    5196         199 :         ssize_t nwritten = -1;
    5197             :         off_t startpos;
    5198             :         const char *data;
    5199             :         files_struct *fsp;
    5200             :         struct lock_struct lock;
    5201             :         NTSTATUS status;
    5202         199 :         int saved_errno = 0;
    5203             : 
    5204         199 :         START_PROFILE(SMBwrite);
    5205             : 
    5206         199 :         if (req->wct < 5) {
    5207           0 :                 END_PROFILE(SMBwrite);
    5208           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5209           0 :                 return;
    5210             :         }
    5211             : 
    5212             :         /* If it's an IPC, pass off the pipe handler. */
    5213         199 :         if (IS_IPC(conn)) {
    5214           0 :                 reply_pipe_write(req);
    5215           0 :                 END_PROFILE(SMBwrite);
    5216           0 :                 return;
    5217             :         }
    5218             : 
    5219         199 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    5220             : 
    5221         199 :         if (!check_fsp(conn, req, fsp)) {
    5222           5 :                 END_PROFILE(SMBwrite);
    5223           4 :                 return;
    5224             :         }
    5225             : 
    5226         194 :         if (!CHECK_WRITE(fsp)) {
    5227           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    5228           0 :                 END_PROFILE(SMBwrite);
    5229           0 :                 return;
    5230             :         }
    5231             : 
    5232         194 :         numtowrite = SVAL(req->vwv+1, 0);
    5233         194 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
    5234         194 :         data = (const char *)req->buf + 3;
    5235             : 
    5236             :         /*
    5237             :          * Ensure client isn't asking us to write more than
    5238             :          * they sent. CVE-2017-12163.
    5239             :          */
    5240         194 :         remaining = smbreq_bufrem(req, data);
    5241         194 :         if (numtowrite > remaining) {
    5242           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5243           0 :                 END_PROFILE(SMBwrite);
    5244           0 :                 return;
    5245             :         }
    5246             : 
    5247         194 :         if (!fsp->print_file) {
    5248         194 :                 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    5249             :                         (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
    5250             :                         &lock);
    5251             : 
    5252         194 :                 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    5253           4 :                         reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    5254           4 :                         END_PROFILE(SMBwrite);
    5255           4 :                         return;
    5256             :                 }
    5257             :         }
    5258             : 
    5259             :         /*
    5260             :          * X/Open SMB protocol says that if smb_vwv1 is
    5261             :          * zero then the file size should be extended or
    5262             :          * truncated to the size given in smb_vwv[2-3].
    5263             :          */
    5264             : 
    5265         190 :         if(numtowrite == 0) {
    5266             :                 /*
    5267             :                  * This is actually an allocate call, and set EOF. JRA.
    5268             :                  */
    5269          57 :                 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
    5270          57 :                 if (nwritten < 0) {
    5271           0 :                         reply_nterror(req, NT_STATUS_DISK_FULL);
    5272           0 :                         goto out;
    5273             :                 }
    5274          57 :                 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
    5275          57 :                 if (nwritten < 0) {
    5276           0 :                         reply_nterror(req, NT_STATUS_DISK_FULL);
    5277           0 :                         goto out;
    5278             :                 }
    5279          57 :                 trigger_write_time_update_immediate(fsp);
    5280             :         } else {
    5281         133 :                 nwritten = write_file(req,fsp,data,startpos,numtowrite);
    5282             :         }
    5283             : 
    5284         190 :         status = sync_file(conn, fsp, False);
    5285         190 :         if (!NT_STATUS_IS_OK(status)) {
    5286           0 :                 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
    5287             :                          fsp_str_dbg(fsp), nt_errstr(status)));
    5288           0 :                 reply_nterror(req, status);
    5289           0 :                 goto out;
    5290             :         }
    5291             : 
    5292         190 :         if(nwritten < 0) {
    5293           0 :                 reply_nterror(req, map_nt_error_from_unix(saved_errno));
    5294           0 :                 goto out;
    5295             :         }
    5296             : 
    5297         190 :         if((nwritten == 0) && (numtowrite != 0)) {
    5298           0 :                 reply_nterror(req, NT_STATUS_DISK_FULL);
    5299           0 :                 goto out;
    5300             :         }
    5301             : 
    5302         190 :         reply_outbuf(req, 1, 0);
    5303             : 
    5304         190 :         SSVAL(req->outbuf,smb_vwv0,nwritten);
    5305             : 
    5306         190 :         if (nwritten < (ssize_t)numtowrite) {
    5307           0 :                 SCVAL(req->outbuf,smb_rcls,ERRHRD);
    5308           0 :                 SSVAL(req->outbuf,smb_err,ERRdiskfull);
    5309             :         }
    5310             : 
    5311         190 :         DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
    5312             : 
    5313         190 : out:
    5314         190 :         END_PROFILE(SMBwrite);
    5315         186 :         return;
    5316             : }
    5317             : 
    5318             : /****************************************************************************
    5319             :  Ensure a buffer is a valid writeX for recvfile purposes.
    5320             : ****************************************************************************/
    5321             : 
    5322             : #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
    5323             :                                                 (2*14) + /* word count (including bcc) */ \
    5324             :                                                 1 /* pad byte */)
    5325             : 
    5326           0 : bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
    5327             :                             const uint8_t *inbuf)
    5328             : {
    5329             :         size_t numtowrite;
    5330           0 :         unsigned int doff = 0;
    5331           0 :         size_t len = smb_len_large(inbuf);
    5332             :         uint16_t fnum;
    5333           0 :         struct smbXsrv_open *op = NULL;
    5334           0 :         struct files_struct *fsp = NULL;
    5335             :         NTSTATUS status;
    5336             : 
    5337           0 :         if (is_encrypted_packet(inbuf)) {
    5338             :                 /* Can't do this on encrypted
    5339             :                  * connections. */
    5340           0 :                 return false;
    5341             :         }
    5342             : 
    5343           0 :         if (CVAL(inbuf,smb_com) != SMBwriteX) {
    5344           0 :                 return false;
    5345             :         }
    5346             : 
    5347           0 :         if (CVAL(inbuf,smb_vwv0) != 0xFF ||
    5348           0 :                         CVAL(inbuf,smb_wct) != 14) {
    5349           0 :                 DEBUG(10,("is_valid_writeX_buffer: chained or "
    5350             :                         "invalid word length.\n"));
    5351           0 :                 return false;
    5352             :         }
    5353             : 
    5354           0 :         fnum = SVAL(inbuf, smb_vwv2);
    5355           0 :         status = smb1srv_open_lookup(xconn,
    5356             :                                      fnum,
    5357             :                                      0, /* now */
    5358             :                                      &op);
    5359           0 :         if (!NT_STATUS_IS_OK(status)) {
    5360           0 :                 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
    5361           0 :                 return false;
    5362             :         }
    5363           0 :         fsp = op->compat;
    5364           0 :         if (fsp == NULL) {
    5365           0 :                 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
    5366           0 :                 return false;
    5367             :         }
    5368           0 :         if (fsp->conn == NULL) {
    5369           0 :                 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
    5370           0 :                 return false;
    5371             :         }
    5372             : 
    5373           0 :         if (IS_IPC(fsp->conn)) {
    5374           0 :                 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
    5375           0 :                 return false;
    5376             :         }
    5377           0 :         if (IS_PRINT(fsp->conn)) {
    5378           0 :                 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
    5379           0 :                 return false;
    5380             :         }
    5381           0 :         if (fsp->base_fsp != NULL) {
    5382           0 :                 DEBUG(10,("is_valid_writeX_buffer: stream fsp\n"));
    5383           0 :                 return false;
    5384             :         }
    5385           0 :         doff = SVAL(inbuf,smb_vwv11);
    5386             : 
    5387           0 :         numtowrite = SVAL(inbuf,smb_vwv10);
    5388             : 
    5389           0 :         if (len > doff && len - doff > 0xFFFF) {
    5390           0 :                 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
    5391             :         }
    5392             : 
    5393           0 :         if (numtowrite == 0) {
    5394           0 :                 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
    5395           0 :                 return false;
    5396             :         }
    5397             : 
    5398             :         /* Ensure the sizes match up. */
    5399           0 :         if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
    5400             :                 /* no pad byte...old smbclient :-( */
    5401           0 :                 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
    5402             :                         (unsigned int)doff,
    5403             :                         (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
    5404           0 :                 return false;
    5405             :         }
    5406             : 
    5407           0 :         if (len - doff != numtowrite) {
    5408           0 :                 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
    5409             :                         "len = %u, doff = %u, numtowrite = %u\n",
    5410             :                         (unsigned int)len,
    5411             :                         (unsigned int)doff,
    5412             :                         (unsigned int)numtowrite ));
    5413           0 :                 return false;
    5414             :         }
    5415             : 
    5416           0 :         DEBUG(10,("is_valid_writeX_buffer: true "
    5417             :                 "len = %u, doff = %u, numtowrite = %u\n",
    5418             :                 (unsigned int)len,
    5419             :                 (unsigned int)doff,
    5420             :                 (unsigned int)numtowrite ));
    5421             : 
    5422           0 :         return true;
    5423             : }
    5424             : 
    5425             : /****************************************************************************
    5426             :  Reply to a write and X.
    5427             : ****************************************************************************/
    5428             : 
    5429      132900 : void reply_write_and_X(struct smb_request *req)
    5430             : {
    5431      132900 :         connection_struct *conn = req->conn;
    5432      132900 :         struct smbXsrv_connection *xconn = req->xconn;
    5433             :         files_struct *fsp;
    5434             :         struct lock_struct lock;
    5435             :         off_t startpos;
    5436             :         size_t numtowrite;
    5437             :         bool write_through;
    5438             :         ssize_t nwritten;
    5439             :         unsigned int smb_doff;
    5440             :         unsigned int smblen;
    5441             :         const char *data;
    5442             :         NTSTATUS status;
    5443      132900 :         int saved_errno = 0;
    5444             : 
    5445      132900 :         START_PROFILE(SMBwriteX);
    5446             : 
    5447      132900 :         if ((req->wct != 12) && (req->wct != 14)) {
    5448           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5449           0 :                 goto out;
    5450             :         }
    5451             : 
    5452      132900 :         numtowrite = SVAL(req->vwv+10, 0);
    5453      132900 :         smb_doff = SVAL(req->vwv+11, 0);
    5454      132900 :         smblen = smb_len(req->inbuf);
    5455             : 
    5456      132900 :         if (req->unread_bytes > 0xFFFF ||
    5457      132895 :                         (smblen > smb_doff &&
    5458      132895 :                                 smblen - smb_doff > 0xFFFF)) {
    5459        1367 :                 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
    5460             :         }
    5461             : 
    5462      132900 :         if (req->unread_bytes) {
    5463             :                 /* Can't do a recvfile write on IPC$ */
    5464           0 :                 if (IS_IPC(conn)) {
    5465           0 :                         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5466           0 :                         goto out;
    5467             :                 }
    5468           0 :                 if (numtowrite != req->unread_bytes) {
    5469           0 :                         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5470           0 :                         goto out;
    5471             :                 }
    5472             :         } else {
    5473             :                 /*
    5474             :                  * This already protects us against CVE-2017-12163.
    5475             :                  */
    5476      265508 :                 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
    5477      132900 :                                 smb_doff + numtowrite > smblen) {
    5478           0 :                         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5479           0 :                         goto out;
    5480             :                 }
    5481             :         }
    5482             : 
    5483             :         /* If it's an IPC, pass off the pipe handler. */
    5484      132900 :         if (IS_IPC(conn)) {
    5485           8 :                 if (req->unread_bytes) {
    5486           0 :                         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5487           0 :                         goto out;
    5488             :                 }
    5489           8 :                 reply_pipe_write_and_X(req);
    5490           8 :                 goto out;
    5491             :         }
    5492             : 
    5493      132892 :         fsp = file_fsp(req, SVAL(req->vwv+2, 0));
    5494      132892 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
    5495      132892 :         write_through = BITSETW(req->vwv+7,0);
    5496             : 
    5497      132892 :         if (!check_fsp(conn, req, fsp)) {
    5498          12 :                 goto out;
    5499             :         }
    5500             : 
    5501      132878 :         if (!CHECK_WRITE(fsp)) {
    5502         294 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    5503         294 :                 goto out;
    5504             :         }
    5505             : 
    5506      132584 :         data = smb_base(req->inbuf) + smb_doff;
    5507             : 
    5508      132584 :         if(req->wct == 14) {
    5509             :                 /*
    5510             :                  * This is a large offset (64 bit) write.
    5511             :                  */
    5512      132584 :                 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
    5513             : 
    5514             :         }
    5515             : 
    5516             :         /* X/Open SMB protocol says that, unlike SMBwrite
    5517             :         if the length is zero then NO truncation is
    5518             :         done, just a write of zero. To truncate a file,
    5519             :         use SMBwrite. */
    5520             : 
    5521      132584 :         if(numtowrite == 0) {
    5522           4 :                 nwritten = 0;
    5523             :         } else {
    5524      132579 :                 if (req->unread_bytes == 0) {
    5525      132579 :                         status = schedule_aio_write_and_X(conn,
    5526             :                                                 req,
    5527             :                                                 fsp,
    5528             :                                                 data,
    5529             :                                                 startpos,
    5530             :                                                 numtowrite);
    5531             : 
    5532      132579 :                         if (NT_STATUS_IS_OK(status)) {
    5533             :                                 /* write scheduled - we're done. */
    5534      132442 :                                 goto out;
    5535             :                         }
    5536          85 :                         if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
    5537             :                                 /* Real error - report to client. */
    5538          45 :                                 reply_nterror(req, status);
    5539          45 :                                 goto out;
    5540             :                         }
    5541             :                         /* NT_STATUS_RETRY - fall through to sync write. */
    5542             :                 }
    5543             : 
    5544          40 :                 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    5545             :                     (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
    5546             :                     &lock);
    5547             : 
    5548          40 :                 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    5549           0 :                         reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    5550           0 :                         goto out;
    5551             :                 }
    5552             : 
    5553          40 :                 nwritten = write_file(req,fsp,data,startpos,numtowrite);
    5554          40 :                 saved_errno = errno;
    5555             :         }
    5556             : 
    5557          44 :         if(nwritten < 0) {
    5558           0 :                 reply_nterror(req, map_nt_error_from_unix(saved_errno));
    5559           0 :                 goto out;
    5560             :         }
    5561             : 
    5562          45 :         if((nwritten == 0) && (numtowrite != 0)) {
    5563           0 :                 reply_nterror(req, NT_STATUS_DISK_FULL);
    5564           0 :                 goto out;
    5565             :         }
    5566             : 
    5567          45 :         reply_outbuf(req, 6, 0);
    5568          45 :         SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
    5569          45 :         SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
    5570          45 :         SSVAL(req->outbuf,smb_vwv2,nwritten);
    5571          45 :         SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
    5572             : 
    5573          45 :         DEBUG(3,("writeX %s num=%d wrote=%d\n",
    5574             :                 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
    5575             : 
    5576          45 :         status = sync_file(conn, fsp, write_through);
    5577          45 :         if (!NT_STATUS_IS_OK(status)) {
    5578           0 :                 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
    5579             :                          fsp_str_dbg(fsp), nt_errstr(status)));
    5580           0 :                 reply_nterror(req, status);
    5581           0 :                 goto out;
    5582             :         }
    5583             : 
    5584          45 :         END_PROFILE(SMBwriteX);
    5585          44 :         return;
    5586             : 
    5587      132909 : out:
    5588      132855 :         if (req->unread_bytes) {
    5589             :                 /* writeX failed. drain socket. */
    5590           0 :                 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
    5591           0 :                                 req->unread_bytes) {
    5592           0 :                         smb_panic("failed to drain pending bytes");
    5593             :                 }
    5594           0 :                 req->unread_bytes = 0;
    5595             :         }
    5596             : 
    5597      132855 :         END_PROFILE(SMBwriteX);
    5598      132797 :         return;
    5599             : }
    5600             : 
    5601             : /****************************************************************************
    5602             :  Reply to a lseek.
    5603             : ****************************************************************************/
    5604             : 
    5605          40 : void reply_lseek(struct smb_request *req)
    5606             : {
    5607          40 :         connection_struct *conn = req->conn;
    5608             :         off_t startpos;
    5609          40 :         off_t res= -1;
    5610             :         int mode,umode;
    5611             :         files_struct *fsp;
    5612             :         NTSTATUS status;
    5613             : 
    5614          40 :         START_PROFILE(SMBlseek);
    5615             : 
    5616          40 :         if (req->wct < 4) {
    5617           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5618           0 :                 END_PROFILE(SMBlseek);
    5619           0 :                 return;
    5620             :         }
    5621             : 
    5622          40 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    5623             : 
    5624          40 :         if (!check_fsp(conn, req, fsp)) {
    5625           4 :                 return;
    5626             :         }
    5627             : 
    5628          35 :         mode = SVAL(req->vwv+1, 0) & 3;
    5629             :         /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
    5630          35 :         startpos = (off_t)IVALS(req->vwv+2, 0);
    5631             : 
    5632          35 :         switch (mode) {
    5633           8 :                 case 0:
    5634           8 :                         umode = SEEK_SET;
    5635           8 :                         res = startpos;
    5636           8 :                         break;
    5637          20 :                 case 1:
    5638          20 :                         umode = SEEK_CUR;
    5639          20 :                         res = fh_get_pos(fsp->fh) + startpos;
    5640          16 :                         break;
    5641           4 :                 case 2:
    5642           5 :                         umode = SEEK_END;
    5643           4 :                         break;
    5644           0 :                 default:
    5645           0 :                         umode = SEEK_SET;
    5646           0 :                         res = startpos;
    5647           0 :                         break;
    5648             :         }
    5649             : 
    5650          28 :         if (umode == SEEK_END) {
    5651           5 :                 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
    5652           0 :                         if(errno == EINVAL) {
    5653           0 :                                 off_t current_pos = startpos;
    5654             : 
    5655           0 :                                 status = vfs_stat_fsp(fsp);
    5656           0 :                                 if (!NT_STATUS_IS_OK(status)) {
    5657           0 :                                         reply_nterror(req, status);
    5658           0 :                                         END_PROFILE(SMBlseek);
    5659           0 :                                         return;
    5660             :                                 }
    5661             : 
    5662           0 :                                 current_pos += fsp->fsp_name->st.st_ex_size;
    5663           0 :                                 if(current_pos < 0)
    5664           0 :                                         res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
    5665             :                         }
    5666             :                 }
    5667             : 
    5668           5 :                 if(res == -1) {
    5669           0 :                         reply_nterror(req, map_nt_error_from_unix(errno));
    5670           0 :                         END_PROFILE(SMBlseek);
    5671           0 :                         return;
    5672             :                 }
    5673             :         }
    5674             : 
    5675          35 :         fh_set_pos(fsp->fh, res);
    5676             : 
    5677          35 :         reply_outbuf(req, 2, 0);
    5678          35 :         SIVAL(req->outbuf,smb_vwv0,res);
    5679             : 
    5680          35 :         DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
    5681             :                 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
    5682             : 
    5683          35 :         END_PROFILE(SMBlseek);
    5684          28 :         return;
    5685             : }
    5686             : 
    5687           0 : static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
    5688             :                                              void *private_data)
    5689             : {
    5690           0 :         connection_struct *conn = talloc_get_type_abort(
    5691             :                 private_data, connection_struct);
    5692             : 
    5693           0 :         if (conn != fsp->conn) {
    5694           0 :                 return NULL;
    5695             :         }
    5696           0 :         if (fsp_get_io_fd(fsp) == -1) {
    5697           0 :                 return NULL;
    5698             :         }
    5699           0 :         sync_file(conn, fsp, True /* write through */);
    5700             : 
    5701           0 :         if (fsp->fsp_flags.modified) {
    5702           0 :                 trigger_write_time_update_immediate(fsp);
    5703             :         }
    5704             : 
    5705           0 :         return NULL;
    5706             : }
    5707             : 
    5708             : /****************************************************************************
    5709             :  Reply to a flush.
    5710             : ****************************************************************************/
    5711             : 
    5712          22 : void reply_flush(struct smb_request *req)
    5713             : {
    5714          22 :         connection_struct *conn = req->conn;
    5715             :         uint16_t fnum;
    5716             :         files_struct *fsp;
    5717             : 
    5718          22 :         START_PROFILE(SMBflush);
    5719             : 
    5720          22 :         if (req->wct < 1) {
    5721           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    5722           0 :                 return;
    5723             :         }
    5724             : 
    5725          22 :         fnum = SVAL(req->vwv+0, 0);
    5726          22 :         fsp = file_fsp(req, fnum);
    5727             : 
    5728          22 :         if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
    5729           8 :                 return;
    5730             :         }
    5731             : 
    5732          12 :         if (!fsp) {
    5733           5 :                 files_forall(req->sconn, file_sync_one_fn, conn);
    5734             :         } else {
    5735           7 :                 NTSTATUS status = sync_file(conn, fsp, True);
    5736           7 :                 if (!NT_STATUS_IS_OK(status)) {
    5737           0 :                         DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
    5738             :                                 fsp_str_dbg(fsp), nt_errstr(status)));
    5739           0 :                         reply_nterror(req, status);
    5740           0 :                         END_PROFILE(SMBflush);
    5741           0 :                         return;
    5742             :                 }
    5743           7 :                 if (fsp->fsp_flags.modified) {
    5744           7 :                         trigger_write_time_update_immediate(fsp);
    5745             :                 }
    5746             :         }
    5747             : 
    5748          12 :         reply_outbuf(req, 0, 0);
    5749             : 
    5750          12 :         DEBUG(3,("flush\n"));
    5751          12 :         END_PROFILE(SMBflush);
    5752          10 :         return;
    5753             : }
    5754             : 
    5755             : /****************************************************************************
    5756             :  Reply to a exit.
    5757             :  conn POINTER CAN BE NULL HERE !
    5758             : ****************************************************************************/
    5759             : 
    5760             : static struct tevent_req *reply_exit_send(struct smb_request *smb1req);
    5761             : static void reply_exit_done(struct tevent_req *req);
    5762             : 
    5763        1787 : void reply_exit(struct smb_request *smb1req)
    5764             : {
    5765             :         struct tevent_req *req;
    5766             : 
    5767             :         /*
    5768             :          * Don't setup the profile charge here, take
    5769             :          * it in reply_exit_done(). Not strictly correct
    5770             :          * but better than the other SMB1 async
    5771             :          * code that double-charges at the moment.
    5772             :          */
    5773        1787 :         req = reply_exit_send(smb1req);
    5774        1787 :         if (req == NULL) {
    5775             :                 /* Not going async, profile here. */
    5776           0 :                 START_PROFILE(SMBexit);
    5777           0 :                 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
    5778           0 :                 END_PROFILE(SMBexit);
    5779           0 :                 return;
    5780             :         }
    5781             : 
    5782             :         /* We're async. This will complete later. */
    5783        1787 :         tevent_req_set_callback(req, reply_exit_done, smb1req);
    5784        1787 :         return;
    5785             : }
    5786             : 
    5787             : struct reply_exit_state {
    5788             :         struct tevent_queue *wait_queue;
    5789             : };
    5790             : 
    5791             : static void reply_exit_wait_done(struct tevent_req *subreq);
    5792             : 
    5793             : /****************************************************************************
    5794             :  Async SMB1 exit.
    5795             :  Note, on failure here we deallocate and return NULL to allow the caller to
    5796             :  SMB1 return an error of ERRnomem immediately.
    5797             : ****************************************************************************/
    5798             : 
    5799        1787 : static struct tevent_req *reply_exit_send(struct smb_request *smb1req)
    5800             : {
    5801             :         struct tevent_req *req;
    5802             :         struct reply_exit_state *state;
    5803             :         struct tevent_req *subreq;
    5804             :         files_struct *fsp;
    5805        1787 :         struct smbd_server_connection *sconn = smb1req->sconn;
    5806             : 
    5807        1787 :         req = tevent_req_create(smb1req, &state,
    5808             :                         struct reply_exit_state);
    5809        1787 :         if (req == NULL) {
    5810           0 :                 return NULL;
    5811             :         }
    5812        1787 :         state->wait_queue = tevent_queue_create(state,
    5813             :                                 "reply_exit_wait_queue");
    5814        1787 :         if (tevent_req_nomem(state->wait_queue, req)) {
    5815           0 :                 TALLOC_FREE(req);
    5816           0 :                 return NULL;
    5817             :         }
    5818             : 
    5819        2069 :         for (fsp = sconn->files; fsp; fsp = fsp->next) {
    5820         282 :                 if (fsp->file_pid != smb1req->smbpid) {
    5821          36 :                         continue;
    5822             :                 }
    5823         246 :                 if (fsp->vuid != smb1req->vuid) {
    5824           0 :                         continue;
    5825             :                 }
    5826             :                 /*
    5827             :                  * Flag the file as close in progress.
    5828             :                  * This will prevent any more IO being
    5829             :                  * done on it.
    5830             :                  */
    5831         246 :                 fsp->fsp_flags.closing = true;
    5832             : 
    5833         246 :                 if (fsp->num_aio_requests > 0) {
    5834             :                         /*
    5835             :                          * Now wait until all aio requests on this fsp are
    5836             :                          * finished.
    5837             :                          *
    5838             :                          * We don't set a callback, as we just want to block the
    5839             :                          * wait queue and the talloc_free() of fsp->aio_request
    5840             :                          * will remove the item from the wait queue.
    5841             :                          */
    5842           0 :                         subreq = tevent_queue_wait_send(fsp->aio_requests,
    5843             :                                                 sconn->ev_ctx,
    5844           0 :                                                 state->wait_queue);
    5845           0 :                         if (tevent_req_nomem(subreq, req)) {
    5846           0 :                                 TALLOC_FREE(req);
    5847           0 :                                 return NULL;
    5848             :                         }
    5849             :                 }
    5850             :         }
    5851             : 
    5852             :         /*
    5853             :          * Now we add our own waiter to the end of the queue,
    5854             :          * this way we get notified when all pending requests are finished
    5855             :          * and reply to the outstanding SMB1 request.
    5856             :          */
    5857        1787 :         subreq = tevent_queue_wait_send(state,
    5858             :                                 sconn->ev_ctx,
    5859        1787 :                                 state->wait_queue);
    5860        1787 :         if (tevent_req_nomem(subreq, req)) {
    5861           0 :                 TALLOC_FREE(req);
    5862           0 :                 return NULL;
    5863             :         }
    5864             : 
    5865             :         /*
    5866             :          * We're really going async - move the SMB1 request from
    5867             :          * a talloc stackframe above us to the conn talloc-context.
    5868             :          * We need this to stick around until the wait_done
    5869             :          * callback is invoked.
    5870             :          */
    5871        1787 :         smb1req = talloc_move(sconn, &smb1req);
    5872             : 
    5873        1787 :         tevent_req_set_callback(subreq, reply_exit_wait_done, req);
    5874             : 
    5875        1787 :         return req;
    5876             : }
    5877             : 
    5878        1787 : static void reply_exit_wait_done(struct tevent_req *subreq)
    5879             : {
    5880        1787 :         struct tevent_req *req = tevent_req_callback_data(
    5881             :                 subreq, struct tevent_req);
    5882             : 
    5883        1787 :         tevent_queue_wait_recv(subreq);
    5884        1787 :         TALLOC_FREE(subreq);
    5885        1787 :         tevent_req_done(req);
    5886        1787 : }
    5887             : 
    5888        1660 : static NTSTATUS reply_exit_recv(struct tevent_req *req)
    5889             : {
    5890        1787 :         return tevent_req_simple_recv_ntstatus(req);
    5891             : }
    5892             : 
    5893        1787 : static void reply_exit_done(struct tevent_req *req)
    5894             : {
    5895        1787 :         struct smb_request *smb1req = tevent_req_callback_data(
    5896             :                 req, struct smb_request);
    5897        1787 :         struct smbd_server_connection *sconn = smb1req->sconn;
    5898        1787 :         struct smbXsrv_connection *xconn = smb1req->xconn;
    5899        1787 :         NTTIME now = timeval_to_nttime(&smb1req->request_time);
    5900        1787 :         struct smbXsrv_session *session = NULL;
    5901             :         files_struct *fsp, *next;
    5902             :         NTSTATUS status;
    5903             : 
    5904             :         /*
    5905             :          * Take the profile charge here. Not strictly
    5906             :          * correct but better than the other SMB1 async
    5907             :          * code that double-charges at the moment.
    5908             :          */
    5909        1787 :         START_PROFILE(SMBexit);
    5910             : 
    5911        1787 :         status = reply_exit_recv(req);
    5912        1787 :         TALLOC_FREE(req);
    5913        1787 :         if (!NT_STATUS_IS_OK(status)) {
    5914           0 :                 TALLOC_FREE(smb1req);
    5915           0 :                 END_PROFILE(SMBexit);
    5916           0 :                 exit_server(__location__ ": reply_exit_recv failed");
    5917             :                 return;
    5918             :         }
    5919             : 
    5920             :         /*
    5921             :          * Ensure the session is still valid.
    5922             :          */
    5923        1787 :         status = smb1srv_session_lookup(xconn,
    5924        1787 :                                         smb1req->vuid,
    5925             :                                         now,
    5926             :                                         &session);
    5927        1787 :         if (!NT_STATUS_IS_OK(status)) {
    5928           0 :                 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
    5929           0 :                 smb_request_done(smb1req);
    5930           0 :                 END_PROFILE(SMBexit);
    5931             :         }
    5932             : 
    5933             :         /*
    5934             :          * Ensure the vuid is still valid - no one
    5935             :          * called reply_ulogoffX() in the meantime.
    5936             :          * reply_exit() doesn't have AS_USER set, so
    5937             :          * use set_current_user_info() directly.
    5938             :          * This is the same logic as in switch_message().
    5939             :          */
    5940        1787 :         if (session->global->auth_session_info != NULL) {
    5941        4810 :                 set_current_user_info(
    5942        1660 :                         session->global->auth_session_info->unix_info->sanitized_username,
    5943        1787 :                         session->global->auth_session_info->unix_info->unix_name,
    5944        1787 :                         session->global->auth_session_info->info->domain_name);
    5945             :         }
    5946             : 
    5947             :         /* No more aio - do the actual closes. */
    5948        2196 :         for (fsp = sconn->files; fsp; fsp = next) {
    5949             :                 bool ok;
    5950         282 :                 next = fsp->next;
    5951             : 
    5952         282 :                 if (fsp->file_pid != smb1req->smbpid) {
    5953          36 :                         continue;
    5954             :                 }
    5955         246 :                 if (fsp->vuid != smb1req->vuid) {
    5956           0 :                         continue;
    5957             :                 }
    5958         246 :                 if (!fsp->fsp_flags.closing) {
    5959           0 :                         continue;
    5960             :                 }
    5961             : 
    5962             :                 /*
    5963             :                  * reply_exit() has the DO_CHDIR flag set.
    5964             :                  */
    5965         246 :                 ok = chdir_current_service(fsp->conn);
    5966         246 :                 if (!ok) {
    5967           0 :                         reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
    5968           0 :                         smb_request_done(smb1req);
    5969           0 :                         END_PROFILE(SMBexit);
    5970             :                 }
    5971         246 :                 close_file(NULL, fsp, SHUTDOWN_CLOSE);
    5972             :         }
    5973             : 
    5974        1787 :         reply_outbuf(smb1req, 0, 0);
    5975             :         /*
    5976             :          * The following call is needed to push the
    5977             :          * reply data back out the socket after async
    5978             :          * return. Plus it frees smb1req.
    5979             :          */
    5980        1787 :         smb_request_done(smb1req);
    5981        1787 :         DBG_INFO("reply_exit complete\n");
    5982        1787 :         END_PROFILE(SMBexit);
    5983        1787 :         return;
    5984             : }
    5985             : 
    5986             : static struct tevent_req *reply_close_send(struct smb_request *smb1req,
    5987             :                                 files_struct *fsp);
    5988             : static void reply_close_done(struct tevent_req *req);
    5989             : 
    5990       35414 : void reply_close(struct smb_request *smb1req)
    5991             : {
    5992       35414 :         connection_struct *conn = smb1req->conn;
    5993       35414 :         NTSTATUS status = NT_STATUS_OK;
    5994       35414 :         files_struct *fsp = NULL;
    5995       35414 :         START_PROFILE(SMBclose);
    5996             : 
    5997       35414 :         if (smb1req->wct < 3) {
    5998           0 :                 reply_nterror(smb1req, NT_STATUS_INVALID_PARAMETER);
    5999           0 :                 END_PROFILE(SMBclose);
    6000           0 :                 return;
    6001             :         }
    6002             : 
    6003       35414 :         fsp = file_fsp(smb1req, SVAL(smb1req->vwv+0, 0));
    6004             : 
    6005             :         /*
    6006             :          * We can only use check_fsp if we know it's not a directory.
    6007             :          */
    6008             : 
    6009       35414 :         if (!check_fsp_open(conn, smb1req, fsp)) {
    6010        2503 :                 reply_nterror(smb1req, NT_STATUS_INVALID_HANDLE);
    6011        2503 :                 END_PROFILE(SMBclose);
    6012        2458 :                 return;
    6013             :         }
    6014             : 
    6015       32911 :         DBG_NOTICE("Close %s fd=%d %s (numopen=%d)\n",
    6016             :                   fsp->fsp_flags.is_directory ?
    6017             :                   "directory" : "file",
    6018             :                   fsp_get_pathref_fd(fsp), fsp_fnum_dbg(fsp),
    6019             :                   conn->num_files_open);
    6020             : 
    6021       32911 :         if (!fsp->fsp_flags.is_directory) {
    6022             :                 time_t t;
    6023             : 
    6024             :                 /*
    6025             :                  * Take care of any time sent in the close.
    6026             :                  */
    6027             : 
    6028       30827 :                 t = srv_make_unix_date3(smb1req->vwv+1);
    6029       30827 :                 set_close_write_time(fsp, time_t_to_full_timespec(t));
    6030             :         }
    6031             : 
    6032       32911 :         if (fsp->num_aio_requests != 0) {
    6033             :                 struct tevent_req *req;
    6034             : 
    6035           0 :                 req = reply_close_send(smb1req, fsp);
    6036           0 :                 if (req == NULL) {
    6037           0 :                         status = NT_STATUS_NO_MEMORY;
    6038           0 :                         goto done;
    6039             :                 }
    6040             :                 /* We're async. This will complete later. */
    6041           0 :                 tevent_req_set_callback(req, reply_close_done, smb1req);
    6042           0 :                 END_PROFILE(SMBclose);
    6043           0 :                 return;
    6044             :         }
    6045             : 
    6046             :         /*
    6047             :          * close_file() returns the unix errno if an error was detected on
    6048             :          * close - normally this is due to a disk full error. If not then it
    6049             :          * was probably an I/O error.
    6050             :          */
    6051             : 
    6052       32911 :         status = close_file(smb1req, fsp, NORMAL_CLOSE);
    6053       32911 : done:
    6054       32911 :         if (!NT_STATUS_IS_OK(status)) {
    6055           0 :                 reply_nterror(smb1req, status);
    6056           0 :                 END_PROFILE(SMBclose);
    6057           0 :                 return;
    6058             :         }
    6059             : 
    6060       32911 :         reply_outbuf(smb1req, 0, 0);
    6061       32911 :         END_PROFILE(SMBclose);
    6062       32603 :         return;
    6063             : }
    6064             : 
    6065             : struct reply_close_state {
    6066             :         files_struct *fsp;
    6067             :         struct tevent_queue *wait_queue;
    6068             : };
    6069             : 
    6070             : static void reply_close_wait_done(struct tevent_req *subreq);
    6071             : 
    6072             : /****************************************************************************
    6073             :  Async SMB1 close.
    6074             :  Note, on failure here we deallocate and return NULL to allow the caller to
    6075             :  SMB1 return an error of ERRnomem immediately.
    6076             : ****************************************************************************/
    6077             : 
    6078           0 : static struct tevent_req *reply_close_send(struct smb_request *smb1req,
    6079             :                                 files_struct *fsp)
    6080             : {
    6081             :         struct tevent_req *req;
    6082             :         struct reply_close_state *state;
    6083             :         struct tevent_req *subreq;
    6084           0 :         struct smbd_server_connection *sconn = smb1req->sconn;
    6085             : 
    6086           0 :         req = tevent_req_create(smb1req, &state,
    6087             :                         struct reply_close_state);
    6088           0 :         if (req == NULL) {
    6089           0 :                 return NULL;
    6090             :         }
    6091           0 :         state->wait_queue = tevent_queue_create(state,
    6092             :                                 "reply_close_wait_queue");
    6093           0 :         if (tevent_req_nomem(state->wait_queue, req)) {
    6094           0 :                 TALLOC_FREE(req);
    6095           0 :                 return NULL;
    6096             :         }
    6097             : 
    6098             :         /*
    6099             :          * Flag the file as close in progress.
    6100             :          * This will prevent any more IO being
    6101             :          * done on it.
    6102             :          */
    6103           0 :         fsp->fsp_flags.closing = true;
    6104             : 
    6105             :         /*
    6106             :          * Now wait until all aio requests on this fsp are
    6107             :          * finished.
    6108             :          *
    6109             :          * We don't set a callback, as we just want to block the
    6110             :          * wait queue and the talloc_free() of fsp->aio_request
    6111             :          * will remove the item from the wait queue.
    6112             :          */
    6113           0 :         subreq = tevent_queue_wait_send(fsp->aio_requests,
    6114             :                                         sconn->ev_ctx,
    6115           0 :                                         state->wait_queue);
    6116           0 :         if (tevent_req_nomem(subreq, req)) {
    6117           0 :                 TALLOC_FREE(req);
    6118           0 :                 return NULL;
    6119             :         }
    6120             : 
    6121             :         /*
    6122             :          * Now we add our own waiter to the end of the queue,
    6123             :          * this way we get notified when all pending requests are finished
    6124             :          * and reply to the outstanding SMB1 request.
    6125             :          */
    6126           0 :         subreq = tevent_queue_wait_send(state,
    6127             :                                 sconn->ev_ctx,
    6128           0 :                                 state->wait_queue);
    6129           0 :         if (tevent_req_nomem(subreq, req)) {
    6130           0 :                 TALLOC_FREE(req);
    6131           0 :                 return NULL;
    6132             :         }
    6133             : 
    6134             :         /*
    6135             :          * We're really going async - move the SMB1 request from
    6136             :          * a talloc stackframe above us to the conn talloc-context.
    6137             :          * We need this to stick around until the wait_done
    6138             :          * callback is invoked.
    6139             :          */
    6140           0 :         smb1req = talloc_move(sconn, &smb1req);
    6141             : 
    6142           0 :         tevent_req_set_callback(subreq, reply_close_wait_done, req);
    6143             : 
    6144           0 :         return req;
    6145             : }
    6146             : 
    6147           0 : static void reply_close_wait_done(struct tevent_req *subreq)
    6148             : {
    6149           0 :         struct tevent_req *req = tevent_req_callback_data(
    6150             :                 subreq, struct tevent_req);
    6151             : 
    6152           0 :         tevent_queue_wait_recv(subreq);
    6153           0 :         TALLOC_FREE(subreq);
    6154           0 :         tevent_req_done(req);
    6155           0 : }
    6156             : 
    6157           0 : static NTSTATUS reply_close_recv(struct tevent_req *req)
    6158             : {
    6159           0 :         return tevent_req_simple_recv_ntstatus(req);
    6160             : }
    6161             : 
    6162           0 : static void reply_close_done(struct tevent_req *req)
    6163             : {
    6164           0 :         struct smb_request *smb1req = tevent_req_callback_data(
    6165             :                         req, struct smb_request);
    6166           0 :         struct reply_close_state *state = tevent_req_data(req,
    6167             :                                                 struct reply_close_state);
    6168             :         NTSTATUS status;
    6169             : 
    6170           0 :         status = reply_close_recv(req);
    6171           0 :         TALLOC_FREE(req);
    6172           0 :         if (!NT_STATUS_IS_OK(status)) {
    6173           0 :                 TALLOC_FREE(smb1req);
    6174           0 :                 exit_server(__location__ ": reply_close_recv failed");
    6175             :                 return;
    6176             :         }
    6177             : 
    6178           0 :         status = close_file(smb1req, state->fsp, NORMAL_CLOSE);
    6179           0 :         if (NT_STATUS_IS_OK(status)) {
    6180           0 :                 reply_outbuf(smb1req, 0, 0);
    6181             :         } else {
    6182           0 :                 reply_nterror(smb1req, status);
    6183             :         }
    6184             :         /*
    6185             :          * The following call is needed to push the
    6186             :          * reply data back out the socket after async
    6187             :          * return. Plus it frees smb1req.
    6188             :          */
    6189           0 :         smb_request_done(smb1req);
    6190           0 : }
    6191             : 
    6192             : /****************************************************************************
    6193             :  Reply to a writeclose (Core+ protocol).
    6194             : ****************************************************************************/
    6195             : 
    6196          45 : void reply_writeclose(struct smb_request *req)
    6197             : {
    6198          45 :         connection_struct *conn = req->conn;
    6199             :         size_t numtowrite;
    6200             :         size_t remaining;
    6201          45 :         ssize_t nwritten = -1;
    6202          45 :         NTSTATUS close_status = NT_STATUS_OK;
    6203             :         off_t startpos;
    6204             :         const char *data;
    6205             :         struct timespec mtime;
    6206             :         files_struct *fsp;
    6207             :         struct lock_struct lock;
    6208             : 
    6209          45 :         START_PROFILE(SMBwriteclose);
    6210             : 
    6211          45 :         if (req->wct < 6) {
    6212           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6213           0 :                 END_PROFILE(SMBwriteclose);
    6214           0 :                 return;
    6215             :         }
    6216             : 
    6217          45 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    6218             : 
    6219          45 :         if (!check_fsp(conn, req, fsp)) {
    6220          15 :                 END_PROFILE(SMBwriteclose);
    6221          12 :                 return;
    6222             :         }
    6223          30 :         if (!CHECK_WRITE(fsp)) {
    6224           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    6225           0 :                 END_PROFILE(SMBwriteclose);
    6226           0 :                 return;
    6227             :         }
    6228             : 
    6229          30 :         numtowrite = SVAL(req->vwv+1, 0);
    6230          30 :         startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
    6231          30 :         mtime = time_t_to_full_timespec(srv_make_unix_date3(req->vwv+4));
    6232          30 :         data = (const char *)req->buf + 1;
    6233             : 
    6234             :         /*
    6235             :          * Ensure client isn't asking us to write more than
    6236             :          * they sent. CVE-2017-12163.
    6237             :          */
    6238          30 :         remaining = smbreq_bufrem(req, data);
    6239          30 :         if (numtowrite > remaining) {
    6240           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6241           0 :                 END_PROFILE(SMBwriteclose);
    6242           0 :                 return;
    6243             :         }
    6244             : 
    6245          30 :         if (fsp->print_file == NULL) {
    6246          30 :                 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
    6247             :                     (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
    6248             :                     &lock);
    6249             : 
    6250          30 :                 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
    6251           0 :                         reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    6252           0 :                         END_PROFILE(SMBwriteclose);
    6253           0 :                         return;
    6254             :                 }
    6255             :         }
    6256             : 
    6257          30 :         nwritten = write_file(req,fsp,data,startpos,numtowrite);
    6258             : 
    6259          30 :         set_close_write_time(fsp, mtime);
    6260             : 
    6261             :         /*
    6262             :          * More insanity. W2K only closes the file if writelen > 0.
    6263             :          * JRA.
    6264             :          */
    6265             : 
    6266          30 :         DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
    6267             :                 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
    6268             :                 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
    6269             : 
    6270          30 :         if (numtowrite) {
    6271          20 :                 DEBUG(3,("reply_writeclose: zero length write doesn't close "
    6272             :                          "file %s\n", fsp_str_dbg(fsp)));
    6273          20 :                 close_status = close_file(req, fsp, NORMAL_CLOSE);
    6274          20 :                 fsp = NULL;
    6275             :         }
    6276             : 
    6277          30 :         if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
    6278           0 :                 reply_nterror(req, NT_STATUS_DISK_FULL);
    6279           0 :                 goto out;
    6280             :         }
    6281             : 
    6282          30 :         if(!NT_STATUS_IS_OK(close_status)) {
    6283           0 :                 reply_nterror(req, close_status);
    6284           0 :                 goto out;
    6285             :         }
    6286             : 
    6287          30 :         reply_outbuf(req, 1, 0);
    6288             : 
    6289          30 :         SSVAL(req->outbuf,smb_vwv0,nwritten);
    6290             : 
    6291          30 : out:
    6292             : 
    6293          30 :         END_PROFILE(SMBwriteclose);
    6294          24 :         return;
    6295             : }
    6296             : 
    6297             : #undef DBGC_CLASS
    6298             : #define DBGC_CLASS DBGC_LOCKING
    6299             : 
    6300             : /****************************************************************************
    6301             :  Reply to a lock.
    6302             : ****************************************************************************/
    6303             : 
    6304             : static void reply_lock_done(struct tevent_req *subreq);
    6305             : 
    6306          22 : void reply_lock(struct smb_request *req)
    6307             : {
    6308          22 :         struct tevent_req *subreq = NULL;
    6309          22 :         connection_struct *conn = req->conn;
    6310             :         files_struct *fsp;
    6311          22 :         struct smbd_lock_element *lck = NULL;
    6312             : 
    6313          22 :         START_PROFILE(SMBlock);
    6314             : 
    6315          22 :         if (req->wct < 5) {
    6316           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6317           0 :                 END_PROFILE(SMBlock);
    6318           0 :                 return;
    6319             :         }
    6320             : 
    6321          22 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    6322             : 
    6323          22 :         if (!check_fsp(conn, req, fsp)) {
    6324           0 :                 END_PROFILE(SMBlock);
    6325           0 :                 return;
    6326             :         }
    6327             : 
    6328          22 :         lck = talloc(req, struct smbd_lock_element);
    6329          22 :         if (lck == NULL) {
    6330           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    6331           0 :                 END_PROFILE(SMBlock);
    6332           0 :                 return;
    6333             :         }
    6334             : 
    6335          22 :         *lck = (struct smbd_lock_element) {
    6336          22 :                 .req_guid = smbd_request_guid(req, 0),
    6337          22 :                 .smblctx = req->smbpid,
    6338             :                 .brltype = WRITE_LOCK,
    6339          22 :                 .count = IVAL(req->vwv+1, 0),
    6340          22 :                 .offset = IVAL(req->vwv+3, 0),
    6341             :         };
    6342             : 
    6343          22 :         DBG_NOTICE("lock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
    6344             :                    fsp_get_io_fd(fsp),
    6345             :                    fsp_fnum_dbg(fsp),
    6346             :                    lck->offset,
    6347             :                    lck->count);
    6348             : 
    6349          22 :         subreq = smbd_smb1_do_locks_send(
    6350             :                 fsp,
    6351          22 :                 req->sconn->ev_ctx,
    6352             :                 &req,
    6353             :                 fsp,
    6354             :                 0,
    6355             :                 false,          /* large_offset */
    6356             :                 WINDOWS_LOCK,
    6357             :                 1,
    6358             :                 lck);
    6359          22 :         if (subreq == NULL) {
    6360           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    6361           0 :                 END_PROFILE(SMBlock);
    6362           0 :                 return;
    6363             :         }
    6364          22 :         tevent_req_set_callback(subreq, reply_lock_done, NULL);
    6365          22 :         END_PROFILE(SMBlock);
    6366             : }
    6367             : 
    6368          22 : static void reply_lock_done(struct tevent_req *subreq)
    6369             : {
    6370          22 :         struct smb_request *req = NULL;
    6371             :         NTSTATUS status;
    6372             :         bool ok;
    6373             : 
    6374          22 :         START_PROFILE(SMBlock);
    6375             : 
    6376          22 :         ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
    6377          22 :         SMB_ASSERT(ok);
    6378             : 
    6379          22 :         status = smbd_smb1_do_locks_recv(subreq);
    6380          22 :         TALLOC_FREE(subreq);
    6381             : 
    6382          22 :         if (NT_STATUS_IS_OK(status)) {
    6383          14 :                 reply_outbuf(req, 0, 0);
    6384             :         } else {
    6385           8 :                 reply_nterror(req, status);
    6386             :         }
    6387             : 
    6388          66 :         ok = srv_send_smb(req->xconn,
    6389          22 :                           (char *)req->outbuf,
    6390             :                           true,
    6391          22 :                           req->seqnum+1,
    6392          22 :                           IS_CONN_ENCRYPTED(req->conn),
    6393             :                           NULL);
    6394          22 :         if (!ok) {
    6395           0 :                 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
    6396             :         }
    6397          22 :         TALLOC_FREE(req);
    6398          22 :         END_PROFILE(SMBlock);
    6399          22 : }
    6400             : 
    6401             : /****************************************************************************
    6402             :  Reply to a unlock.
    6403             : ****************************************************************************/
    6404             : 
    6405          22 : void reply_unlock(struct smb_request *req)
    6406             : {
    6407          22 :         connection_struct *conn = req->conn;
    6408             :         NTSTATUS status;
    6409             :         files_struct *fsp;
    6410             :         struct smbd_lock_element lck;
    6411             : 
    6412          22 :         START_PROFILE(SMBunlock);
    6413             : 
    6414          22 :         if (req->wct < 5) {
    6415           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6416           0 :                 END_PROFILE(SMBunlock);
    6417           0 :                 return;
    6418             :         }
    6419             : 
    6420          22 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    6421             : 
    6422          22 :         if (!check_fsp(conn, req, fsp)) {
    6423           0 :                 END_PROFILE(SMBunlock);
    6424           0 :                 return;
    6425             :         }
    6426             : 
    6427          22 :         lck = (struct smbd_lock_element) {
    6428          22 :                 .req_guid = smbd_request_guid(req, 0),
    6429          22 :                 .smblctx = req->smbpid,
    6430             :                 .brltype = UNLOCK_LOCK,
    6431          22 :                 .offset = IVAL(req->vwv+3, 0),
    6432          22 :                 .count = IVAL(req->vwv+1, 0),
    6433             :         };
    6434             : 
    6435          22 :         status = smbd_do_unlocking(req, fsp, 1, &lck, WINDOWS_LOCK);
    6436             : 
    6437          22 :         if (!NT_STATUS_IS_OK(status)) {
    6438          10 :                 reply_nterror(req, status);
    6439          10 :                 END_PROFILE(SMBunlock);
    6440          10 :                 return;
    6441             :         }
    6442             : 
    6443          12 :         DBG_NOTICE("unlock fd=%d %s offset=%"PRIu64" count=%"PRIu64"\n",
    6444             :                    fsp_get_io_fd(fsp),
    6445             :                    fsp_fnum_dbg(fsp),
    6446             :                    lck.offset,
    6447             :                    lck.count);
    6448             : 
    6449          12 :         reply_outbuf(req, 0, 0);
    6450             : 
    6451          12 :         END_PROFILE(SMBunlock);
    6452          12 :         return;
    6453             : }
    6454             : 
    6455             : #undef DBGC_CLASS
    6456             : #define DBGC_CLASS DBGC_ALL
    6457             : 
    6458             : /****************************************************************************
    6459             :  Reply to a tdis.
    6460             :  conn POINTER CAN BE NULL HERE !
    6461             : ****************************************************************************/
    6462             : 
    6463             : static struct tevent_req *reply_tdis_send(struct smb_request *smb1req);
    6464             : static void reply_tdis_done(struct tevent_req *req);
    6465             : 
    6466        5501 : void reply_tdis(struct smb_request *smb1req)
    6467             : {
    6468        5501 :         connection_struct *conn = smb1req->conn;
    6469             :         struct tevent_req *req;
    6470             : 
    6471             :         /*
    6472             :          * Don't setup the profile charge here, take
    6473             :          * it in reply_tdis_done(). Not strictly correct
    6474             :          * but better than the other SMB1 async
    6475             :          * code that double-charges at the moment.
    6476             :          */
    6477             : 
    6478        5501 :         if (conn == NULL) {
    6479             :                 /* Not going async, profile here. */
    6480          16 :                 START_PROFILE(SMBtdis);
    6481          16 :                 DBG_INFO("Invalid connection in tdis\n");
    6482          16 :                 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
    6483          16 :                 END_PROFILE(SMBtdis);
    6484          16 :                 return;
    6485             :         }
    6486             : 
    6487        5485 :         req = reply_tdis_send(smb1req);
    6488        5485 :         if (req == NULL) {
    6489             :                 /* Not going async, profile here. */
    6490           0 :                 START_PROFILE(SMBtdis);
    6491           0 :                 reply_force_doserror(smb1req, ERRDOS, ERRnomem);
    6492           0 :                 END_PROFILE(SMBtdis);
    6493           0 :                 return;
    6494             :         }
    6495             :         /* We're async. This will complete later. */
    6496        5485 :         tevent_req_set_callback(req, reply_tdis_done, smb1req);
    6497        5485 :         return;
    6498             : }
    6499             : 
    6500             : struct reply_tdis_state {
    6501             :         struct tevent_queue *wait_queue;
    6502             : };
    6503             : 
    6504             : static void reply_tdis_wait_done(struct tevent_req *subreq);
    6505             : 
    6506             : /****************************************************************************
    6507             :  Async SMB1 tdis.
    6508             :  Note, on failure here we deallocate and return NULL to allow the caller to
    6509             :  SMB1 return an error of ERRnomem immediately.
    6510             : ****************************************************************************/
    6511             : 
    6512        5485 : static struct tevent_req *reply_tdis_send(struct smb_request *smb1req)
    6513             : {
    6514             :         struct tevent_req *req;
    6515             :         struct reply_tdis_state *state;
    6516             :         struct tevent_req *subreq;
    6517        5485 :         connection_struct *conn = smb1req->conn;
    6518             :         files_struct *fsp;
    6519             : 
    6520        5485 :         req = tevent_req_create(smb1req, &state,
    6521             :                         struct reply_tdis_state);
    6522        5485 :         if (req == NULL) {
    6523           0 :                 return NULL;
    6524             :         }
    6525        5485 :         state->wait_queue = tevent_queue_create(state, "reply_tdis_wait_queue");
    6526        5485 :         if (tevent_req_nomem(state->wait_queue, req)) {
    6527           0 :                 TALLOC_FREE(req);
    6528           0 :                 return NULL;
    6529             :         }
    6530             : 
    6531             :         /*
    6532             :          * Make sure that no new request will be able to use this tcon.
    6533             :          * This ensures that once all outstanding fsp->aio_requests
    6534             :          * on this tcon are done, we are safe to close it.
    6535             :          */
    6536        5485 :         conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
    6537             : 
    6538        5570 :         for (fsp = conn->sconn->files; fsp; fsp = fsp->next) {
    6539          85 :                 if (fsp->conn != conn) {
    6540           4 :                         continue;
    6541             :                 }
    6542             :                 /*
    6543             :                  * Flag the file as close in progress.
    6544             :                  * This will prevent any more IO being
    6545             :                  * done on it. Not strictly needed, but
    6546             :                  * doesn't hurt to flag it as closing.
    6547             :                  */
    6548          81 :                 fsp->fsp_flags.closing = true;
    6549             : 
    6550          81 :                 if (fsp->num_aio_requests > 0) {
    6551             :                         /*
    6552             :                          * Now wait until all aio requests on this fsp are
    6553             :                          * finished.
    6554             :                          *
    6555             :                          * We don't set a callback, as we just want to block the
    6556             :                          * wait queue and the talloc_free() of fsp->aio_request
    6557             :                          * will remove the item from the wait queue.
    6558             :                          */
    6559           0 :                         subreq = tevent_queue_wait_send(fsp->aio_requests,
    6560           0 :                                                 conn->sconn->ev_ctx,
    6561           0 :                                                 state->wait_queue);
    6562           0 :                         if (tevent_req_nomem(subreq, req)) {
    6563           0 :                                 TALLOC_FREE(req);
    6564           0 :                                 return NULL;
    6565             :                         }
    6566             :                 }
    6567             :         }
    6568             : 
    6569             :         /*
    6570             :          * Now we add our own waiter to the end of the queue,
    6571             :          * this way we get notified when all pending requests are finished
    6572             :          * and reply to the outstanding SMB1 request.
    6573             :          */
    6574       10922 :         subreq = tevent_queue_wait_send(state,
    6575        5485 :                                 conn->sconn->ev_ctx,
    6576        5485 :                                 state->wait_queue);
    6577        5485 :         if (tevent_req_nomem(subreq, req)) {
    6578           0 :                 TALLOC_FREE(req);
    6579           0 :                 return NULL;
    6580             :         }
    6581             : 
    6582             :         /*
    6583             :          * We're really going async - move the SMB1 request from
    6584             :          * a talloc stackframe above us to the sconn talloc-context.
    6585             :          * We need this to stick around until the wait_done
    6586             :          * callback is invoked.
    6587             :          */
    6588        5485 :         smb1req = talloc_move(smb1req->sconn, &smb1req);
    6589             : 
    6590        5485 :         tevent_req_set_callback(subreq, reply_tdis_wait_done, req);
    6591             : 
    6592        5485 :         return req;
    6593             : }
    6594             : 
    6595        5485 : static void reply_tdis_wait_done(struct tevent_req *subreq)
    6596             : {
    6597        5485 :         struct tevent_req *req = tevent_req_callback_data(
    6598             :                 subreq, struct tevent_req);
    6599             : 
    6600        5485 :         tevent_queue_wait_recv(subreq);
    6601        5485 :         TALLOC_FREE(subreq);
    6602        5485 :         tevent_req_done(req);
    6603        5485 : }
    6604             : 
    6605        5469 : static NTSTATUS reply_tdis_recv(struct tevent_req *req)
    6606             : {
    6607        5485 :         return tevent_req_simple_recv_ntstatus(req);
    6608             : }
    6609             : 
    6610        5485 : static void reply_tdis_done(struct tevent_req *req)
    6611             : {
    6612        5485 :         struct smb_request *smb1req = tevent_req_callback_data(
    6613             :                 req, struct smb_request);
    6614             :         NTSTATUS status;
    6615        5485 :         struct smbXsrv_tcon *tcon = smb1req->conn->tcon;
    6616             :         bool ok;
    6617             : 
    6618             :         /*
    6619             :          * Take the profile charge here. Not strictly
    6620             :          * correct but better than the other SMB1 async
    6621             :          * code that double-charges at the moment.
    6622             :          */
    6623        5485 :         START_PROFILE(SMBtdis);
    6624             : 
    6625        5485 :         status = reply_tdis_recv(req);
    6626        5485 :         TALLOC_FREE(req);
    6627        5485 :         if (!NT_STATUS_IS_OK(status)) {
    6628           0 :                 TALLOC_FREE(smb1req);
    6629           0 :                 END_PROFILE(SMBtdis);
    6630           0 :                 exit_server(__location__ ": reply_tdis_recv failed");
    6631             :                 return;
    6632             :         }
    6633             : 
    6634             :         /*
    6635             :          * As we've been awoken, we may have changed
    6636             :          * directory in the meantime.
    6637             :          * reply_tdis() has the DO_CHDIR flag set.
    6638             :          */
    6639        5485 :         ok = chdir_current_service(smb1req->conn);
    6640        5485 :         if (!ok) {
    6641           0 :                 reply_force_doserror(smb1req, ERRSRV, ERRinvnid);
    6642           0 :                 smb_request_done(smb1req);
    6643           0 :                 END_PROFILE(SMBtdis);
    6644             :         }
    6645             : 
    6646        5485 :         status = smbXsrv_tcon_disconnect(tcon,
    6647             :                                          smb1req->vuid);
    6648        5485 :         if (!NT_STATUS_IS_OK(status)) {
    6649           0 :                 TALLOC_FREE(smb1req);
    6650           0 :                 END_PROFILE(SMBtdis);
    6651           0 :                 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
    6652             :                 return;
    6653             :         }
    6654             : 
    6655             :         /* smbXsrv_tcon_disconnect frees smb1req->conn. */
    6656        5485 :         smb1req->conn = NULL;
    6657             : 
    6658        5485 :         TALLOC_FREE(tcon);
    6659             : 
    6660        5485 :         reply_outbuf(smb1req, 0, 0);
    6661             :         /*
    6662             :          * The following call is needed to push the
    6663             :          * reply data back out the socket after async
    6664             :          * return. Plus it frees smb1req.
    6665             :          */
    6666        5485 :         smb_request_done(smb1req);
    6667        5485 :         END_PROFILE(SMBtdis);
    6668        5437 : }
    6669             : 
    6670             : /****************************************************************************
    6671             :  Reply to a echo.
    6672             :  conn POINTER CAN BE NULL HERE !
    6673             : ****************************************************************************/
    6674             : 
    6675          23 : void reply_echo(struct smb_request *req)
    6676             : {
    6677          23 :         connection_struct *conn = req->conn;
    6678             :         struct smb_perfcount_data local_pcd;
    6679             :         struct smb_perfcount_data *cur_pcd;
    6680             :         int smb_reverb;
    6681             :         int seq_num;
    6682             : 
    6683          23 :         START_PROFILE(SMBecho);
    6684             : 
    6685          23 :         smb_init_perfcount_data(&local_pcd);
    6686             : 
    6687          23 :         if (req->wct < 1) {
    6688           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6689           0 :                 END_PROFILE(SMBecho);
    6690           0 :                 return;
    6691             :         }
    6692             : 
    6693          23 :         smb_reverb = SVAL(req->vwv+0, 0);
    6694             : 
    6695          23 :         reply_outbuf(req, 1, req->buflen);
    6696             : 
    6697             :         /* copy any incoming data back out */
    6698          23 :         if (req->buflen > 0) {
    6699          21 :                 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
    6700             :         }
    6701             : 
    6702          23 :         if (smb_reverb > 100) {
    6703           0 :                 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
    6704           0 :                 smb_reverb = 100;
    6705             :         }
    6706             : 
    6707          46 :         for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
    6708             : 
    6709             :                 /* this makes sure we catch the request pcd */
    6710          23 :                 if (seq_num == smb_reverb) {
    6711          23 :                         cur_pcd = &req->pcd;
    6712             :                 } else {
    6713           0 :                         SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
    6714           0 :                         cur_pcd = &local_pcd;
    6715             :                 }
    6716             : 
    6717          23 :                 SSVAL(req->outbuf,smb_vwv0,seq_num);
    6718             : 
    6719          23 :                 show_msg((char *)req->outbuf);
    6720          67 :                 if (!srv_send_smb(req->xconn,
    6721          23 :                                 (char *)req->outbuf,
    6722          23 :                                 true, req->seqnum+1,
    6723          23 :                                 IS_CONN_ENCRYPTED(conn)||req->encrypted,
    6724             :                                 cur_pcd))
    6725           0 :                         exit_server_cleanly("reply_echo: srv_send_smb failed.");
    6726             :         }
    6727             : 
    6728          23 :         DEBUG(3,("echo %d times\n", smb_reverb));
    6729             : 
    6730          23 :         TALLOC_FREE(req->outbuf);
    6731             : 
    6732          23 :         END_PROFILE(SMBecho);
    6733          23 :         return;
    6734             : }
    6735             : 
    6736             : /****************************************************************************
    6737             :  Reply to a printopen.
    6738             : ****************************************************************************/
    6739             : 
    6740           0 : void reply_printopen(struct smb_request *req)
    6741             : {
    6742           0 :         connection_struct *conn = req->conn;
    6743             :         files_struct *fsp;
    6744             :         NTSTATUS status;
    6745             : 
    6746           0 :         START_PROFILE(SMBsplopen);
    6747             : 
    6748           0 :         if (req->wct < 2) {
    6749           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6750           0 :                 END_PROFILE(SMBsplopen);
    6751           0 :                 return;
    6752             :         }
    6753             : 
    6754           0 :         if (!CAN_PRINT(conn)) {
    6755           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    6756           0 :                 END_PROFILE(SMBsplopen);
    6757           0 :                 return;
    6758             :         }
    6759             : 
    6760           0 :         status = file_new(req, conn, &fsp);
    6761           0 :         if(!NT_STATUS_IS_OK(status)) {
    6762           0 :                 reply_nterror(req, status);
    6763           0 :                 END_PROFILE(SMBsplopen);
    6764           0 :                 return;
    6765             :         }
    6766             : 
    6767             :         /* Open for exclusive use, write only. */
    6768           0 :         status = print_spool_open(fsp, NULL, req->vuid);
    6769             : 
    6770           0 :         if (!NT_STATUS_IS_OK(status)) {
    6771           0 :                 file_free(req, fsp);
    6772           0 :                 reply_nterror(req, status);
    6773           0 :                 END_PROFILE(SMBsplopen);
    6774           0 :                 return;
    6775             :         }
    6776             : 
    6777           0 :         reply_outbuf(req, 1, 0);
    6778           0 :         SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
    6779             : 
    6780           0 :         DEBUG(3,("openprint fd=%d %s\n",
    6781             :                  fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
    6782             : 
    6783           0 :         END_PROFILE(SMBsplopen);
    6784           0 :         return;
    6785             : }
    6786             : 
    6787             : /****************************************************************************
    6788             :  Reply to a printclose.
    6789             : ****************************************************************************/
    6790             : 
    6791           5 : void reply_printclose(struct smb_request *req)
    6792             : {
    6793           5 :         connection_struct *conn = req->conn;
    6794             :         files_struct *fsp;
    6795             :         NTSTATUS status;
    6796             : 
    6797           5 :         START_PROFILE(SMBsplclose);
    6798             : 
    6799           5 :         if (req->wct < 1) {
    6800           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6801           0 :                 END_PROFILE(SMBsplclose);
    6802           0 :                 return;
    6803             :         }
    6804             : 
    6805           5 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    6806             : 
    6807           5 :         if (!check_fsp(conn, req, fsp)) {
    6808           0 :                 END_PROFILE(SMBsplclose);
    6809           0 :                 return;
    6810             :         }
    6811             : 
    6812           5 :         if (!CAN_PRINT(conn)) {
    6813           5 :                 reply_force_doserror(req, ERRSRV, ERRerror);
    6814           5 :                 END_PROFILE(SMBsplclose);
    6815           4 :                 return;
    6816             :         }
    6817             : 
    6818           0 :         DEBUG(3,("printclose fd=%d %s\n",
    6819             :                  fsp_get_io_fd(fsp), fsp_fnum_dbg(fsp)));
    6820             : 
    6821           0 :         status = close_file(req, fsp, NORMAL_CLOSE);
    6822             : 
    6823           0 :         if(!NT_STATUS_IS_OK(status)) {
    6824           0 :                 reply_nterror(req, status);
    6825           0 :                 END_PROFILE(SMBsplclose);
    6826           0 :                 return;
    6827             :         }
    6828             : 
    6829           0 :         reply_outbuf(req, 0, 0);
    6830             : 
    6831           0 :         END_PROFILE(SMBsplclose);
    6832           0 :         return;
    6833             : }
    6834             : 
    6835             : /****************************************************************************
    6836             :  Reply to a printqueue.
    6837             : ****************************************************************************/
    6838             : 
    6839           0 : void reply_printqueue(struct smb_request *req)
    6840             : {
    6841           0 :         const struct loadparm_substitution *lp_sub =
    6842           0 :                 loadparm_s3_global_substitution();
    6843           0 :         connection_struct *conn = req->conn;
    6844             :         int max_count;
    6845             :         int start_index;
    6846             : 
    6847           0 :         START_PROFILE(SMBsplretq);
    6848             : 
    6849           0 :         if (req->wct < 2) {
    6850           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    6851           0 :                 END_PROFILE(SMBsplretq);
    6852           0 :                 return;
    6853             :         }
    6854             : 
    6855           0 :         max_count = SVAL(req->vwv+0, 0);
    6856           0 :         start_index = SVAL(req->vwv+1, 0);
    6857             : 
    6858             :         /* we used to allow the client to get the cnum wrong, but that
    6859             :            is really quite gross and only worked when there was only
    6860             :            one printer - I think we should now only accept it if they
    6861             :            get it right (tridge) */
    6862           0 :         if (!CAN_PRINT(conn)) {
    6863           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    6864           0 :                 END_PROFILE(SMBsplretq);
    6865           0 :                 return;
    6866             :         }
    6867             : 
    6868           0 :         reply_outbuf(req, 2, 3);
    6869           0 :         SSVAL(req->outbuf,smb_vwv0,0);
    6870           0 :         SSVAL(req->outbuf,smb_vwv1,0);
    6871           0 :         SCVAL(smb_buf(req->outbuf),0,1);
    6872           0 :         SSVAL(smb_buf(req->outbuf),1,0);
    6873             : 
    6874           0 :         DEBUG(3,("printqueue start_index=%d max_count=%d\n",
    6875             :                  start_index, max_count));
    6876             : 
    6877             :         {
    6878           0 :                 TALLOC_CTX *mem_ctx = talloc_tos();
    6879             :                 NTSTATUS status;
    6880             :                 WERROR werr;
    6881           0 :                 const char *sharename = lp_servicename(mem_ctx, lp_sub, SNUM(conn));
    6882           0 :                 struct rpc_pipe_client *cli = NULL;
    6883           0 :                 struct dcerpc_binding_handle *b = NULL;
    6884             :                 struct policy_handle handle;
    6885             :                 struct spoolss_DevmodeContainer devmode_ctr;
    6886             :                 union spoolss_JobInfo *info;
    6887             :                 uint32_t count;
    6888             :                 uint32_t num_to_get;
    6889             :                 uint32_t first;
    6890             :                 uint32_t i;
    6891             : 
    6892           0 :                 ZERO_STRUCT(handle);
    6893             : 
    6894           0 :                 status = rpc_pipe_open_interface(mem_ctx,
    6895             :                                                  &ndr_table_spoolss,
    6896           0 :                                                  conn->session_info,
    6897           0 :                                                  conn->sconn->remote_address,
    6898           0 :                                                  conn->sconn->local_address,
    6899           0 :                                                  conn->sconn->msg_ctx,
    6900             :                                                  &cli);
    6901           0 :                 if (!NT_STATUS_IS_OK(status)) {
    6902           0 :                         DEBUG(0, ("reply_printqueue: "
    6903             :                                   "could not connect to spoolss: %s\n",
    6904             :                                   nt_errstr(status)));
    6905           0 :                         reply_nterror(req, status);
    6906           0 :                         goto out;
    6907             :                 }
    6908           0 :                 b = cli->binding_handle;
    6909             : 
    6910           0 :                 ZERO_STRUCT(devmode_ctr);
    6911             : 
    6912           0 :                 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
    6913             :                                                 sharename,
    6914             :                                                 NULL, devmode_ctr,
    6915             :                                                 SEC_FLAG_MAXIMUM_ALLOWED,
    6916             :                                                 &handle,
    6917             :                                                 &werr);
    6918           0 :                 if (!NT_STATUS_IS_OK(status)) {
    6919           0 :                         reply_nterror(req, status);
    6920           0 :                         goto out;
    6921             :                 }
    6922           0 :                 if (!W_ERROR_IS_OK(werr)) {
    6923           0 :                         reply_nterror(req, werror_to_ntstatus(werr));
    6924           0 :                         goto out;
    6925             :                 }
    6926             : 
    6927           0 :                 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
    6928             :                                                &handle,
    6929             :                                                0, /* firstjob */
    6930             :                                                0xff, /* numjobs */
    6931             :                                                2, /* level */
    6932             :                                                0, /* offered */
    6933             :                                                &count,
    6934             :                                                &info);
    6935           0 :                 if (!W_ERROR_IS_OK(werr)) {
    6936           0 :                         reply_nterror(req, werror_to_ntstatus(werr));
    6937           0 :                         goto out;
    6938             :                 }
    6939             : 
    6940           0 :                 if (max_count > 0) {
    6941           0 :                         first = start_index;
    6942             :                 } else {
    6943           0 :                         first = start_index + max_count + 1;
    6944             :                 }
    6945             : 
    6946           0 :                 if (first >= count) {
    6947           0 :                         num_to_get = first;
    6948             :                 } else {
    6949           0 :                         num_to_get = first + MIN(ABS(max_count), count - first);
    6950             :                 }
    6951             : 
    6952           0 :                 for (i = first; i < num_to_get; i++) {
    6953             :                         char blob[28];
    6954           0 :                         char *p = blob;
    6955           0 :                         time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
    6956             :                         int qstatus;
    6957           0 :                         size_t len = 0;
    6958           0 :                         uint16_t qrapjobid = pjobid_to_rap(sharename,
    6959           0 :                                                         info[i].info2.job_id);
    6960             : 
    6961           0 :                         if (info[i].info2.status == JOB_STATUS_PRINTING) {
    6962           0 :                                 qstatus = 2;
    6963             :                         } else {
    6964           0 :                                 qstatus = 3;
    6965             :                         }
    6966             : 
    6967           0 :                         srv_put_dos_date2(p, 0, qtime);
    6968           0 :                         SCVAL(p, 4, qstatus);
    6969           0 :                         SSVAL(p, 5, qrapjobid);
    6970           0 :                         SIVAL(p, 7, info[i].info2.size);
    6971           0 :                         SCVAL(p, 11, 0);
    6972           0 :                         status = srvstr_push(blob, req->flags2, p+12,
    6973             :                                     info[i].info2.notify_name, 16, STR_ASCII, &len);
    6974           0 :                         if (!NT_STATUS_IS_OK(status)) {
    6975           0 :                                 reply_nterror(req, status);
    6976           0 :                                 goto out;
    6977             :                         }
    6978           0 :                         if (message_push_blob(
    6979             :                                     &req->outbuf,
    6980             :                                     data_blob_const(
    6981             :                                             blob, sizeof(blob))) == -1) {
    6982           0 :                                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    6983           0 :                                 goto out;
    6984             :                         }
    6985             :                 }
    6986             : 
    6987           0 :                 if (count > 0) {
    6988           0 :                         SSVAL(req->outbuf,smb_vwv0,count);
    6989           0 :                         SSVAL(req->outbuf,smb_vwv1,
    6990             :                               (max_count>0?first+count:first-1));
    6991           0 :                         SCVAL(smb_buf(req->outbuf),0,1);
    6992           0 :                         SSVAL(smb_buf(req->outbuf),1,28*count);
    6993             :                 }
    6994             : 
    6995             : 
    6996           0 :                 DEBUG(3, ("%u entries returned in queue\n",
    6997             :                           (unsigned)count));
    6998             : 
    6999           0 : out:
    7000           0 :                 if (b && is_valid_policy_hnd(&handle)) {
    7001           0 :                         dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
    7002             :                 }
    7003             : 
    7004             :         }
    7005             : 
    7006           0 :         END_PROFILE(SMBsplretq);
    7007           0 :         return;
    7008             : }
    7009             : 
    7010             : /****************************************************************************
    7011             :  Reply to a printwrite.
    7012             : ****************************************************************************/
    7013             : 
    7014           0 : void reply_printwrite(struct smb_request *req)
    7015             : {
    7016           0 :         connection_struct *conn = req->conn;
    7017             :         int numtowrite;
    7018             :         const char *data;
    7019             :         files_struct *fsp;
    7020             : 
    7021           0 :         START_PROFILE(SMBsplwr);
    7022             : 
    7023           0 :         if (req->wct < 1) {
    7024           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    7025           0 :                 END_PROFILE(SMBsplwr);
    7026           0 :                 return;
    7027             :         }
    7028             : 
    7029           0 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    7030             : 
    7031           0 :         if (!check_fsp(conn, req, fsp)) {
    7032           0 :                 END_PROFILE(SMBsplwr);
    7033           0 :                 return;
    7034             :         }
    7035             : 
    7036           0 :         if (!fsp->print_file) {
    7037           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    7038           0 :                 END_PROFILE(SMBsplwr);
    7039           0 :                 return;
    7040             :         }
    7041             : 
    7042           0 :         if (!CHECK_WRITE(fsp)) {
    7043           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    7044           0 :                 END_PROFILE(SMBsplwr);
    7045           0 :                 return;
    7046             :         }
    7047             : 
    7048           0 :         numtowrite = SVAL(req->buf, 1);
    7049             : 
    7050             :         /*
    7051             :          * This already protects us against CVE-2017-12163.
    7052             :          */
    7053           0 :         if (req->buflen < numtowrite + 3) {
    7054           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    7055           0 :                 END_PROFILE(SMBsplwr);
    7056           0 :                 return;
    7057             :         }
    7058             : 
    7059           0 :         data = (const char *)req->buf + 3;
    7060             : 
    7061           0 :         if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
    7062           0 :                 reply_nterror(req, map_nt_error_from_unix(errno));
    7063           0 :                 END_PROFILE(SMBsplwr);
    7064           0 :                 return;
    7065             :         }
    7066             : 
    7067           0 :         DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
    7068             : 
    7069           0 :         reply_outbuf(req, 0, 0);
    7070             : 
    7071           0 :         END_PROFILE(SMBsplwr);
    7072           0 :         return;
    7073             : }
    7074             : 
    7075             : /****************************************************************************
    7076             :  Reply to a mkdir.
    7077             : ****************************************************************************/
    7078             : 
    7079        5643 : void reply_mkdir(struct smb_request *req)
    7080             : {
    7081        5643 :         connection_struct *conn = req->conn;
    7082        5643 :         struct smb_filename *smb_dname = NULL;
    7083        5643 :         char *directory = NULL;
    7084             :         NTSTATUS status;
    7085             :         uint32_t ucf_flags;
    7086        5643 :         TALLOC_CTX *ctx = talloc_tos();
    7087             : 
    7088        5643 :         START_PROFILE(SMBmkdir);
    7089             : 
    7090        5643 :         srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
    7091             :                             STR_TERMINATE, &status);
    7092        5643 :         if (!NT_STATUS_IS_OK(status)) {
    7093           5 :                 reply_nterror(req, status);
    7094           5 :                 goto out;
    7095             :         }
    7096             : 
    7097        5638 :         ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
    7098        5638 :         status = filename_convert(ctx, conn,
    7099             :                                  directory,
    7100             :                                  ucf_flags,
    7101             :                                  0,
    7102             :                                  &smb_dname);
    7103        5638 :         if (!NT_STATUS_IS_OK(status)) {
    7104           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    7105           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    7106             :                                         ERRSRV, ERRbadpath);
    7107           0 :                         goto out;
    7108             :                 }
    7109           0 :                 reply_nterror(req, status);
    7110           0 :                 goto out;
    7111             :         }
    7112             : 
    7113        5638 :         status = create_directory(conn, req, smb_dname);
    7114             : 
    7115        5638 :         DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
    7116             : 
    7117        5638 :         if (!NT_STATUS_IS_OK(status)) {
    7118             : 
    7119          18 :                 if (!use_nt_status()
    7120           4 :                     && NT_STATUS_EQUAL(status,
    7121             :                                        NT_STATUS_OBJECT_NAME_COLLISION)) {
    7122             :                         /*
    7123             :                          * Yes, in the DOS error code case we get a
    7124             :                          * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
    7125             :                          * samba4 torture test.
    7126             :                          */
    7127           4 :                         status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
    7128             :                 }
    7129             : 
    7130          18 :                 reply_nterror(req, status);
    7131          18 :                 goto out;
    7132             :         }
    7133             : 
    7134        5620 :         reply_outbuf(req, 0, 0);
    7135             : 
    7136        5620 :         DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
    7137        5643 :  out:
    7138        5643 :         TALLOC_FREE(smb_dname);
    7139        5643 :         END_PROFILE(SMBmkdir);
    7140        5643 :         return;
    7141             : }
    7142             : 
    7143             : /****************************************************************************
    7144             :  Reply to a rmdir.
    7145             : ****************************************************************************/
    7146             : 
    7147        6675 : void reply_rmdir(struct smb_request *req)
    7148             : {
    7149        6675 :         connection_struct *conn = req->conn;
    7150        6675 :         struct smb_filename *smb_dname = NULL;
    7151        6675 :         char *directory = NULL;
    7152             :         NTSTATUS status;
    7153        6675 :         TALLOC_CTX *ctx = talloc_tos();
    7154        6675 :         files_struct *fsp = NULL;
    7155        6675 :         int info = 0;
    7156        6675 :         uint32_t ucf_flags = ucf_flags_from_smb_request(req);
    7157             : 
    7158        6675 :         START_PROFILE(SMBrmdir);
    7159             : 
    7160        6675 :         srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
    7161             :                             STR_TERMINATE, &status);
    7162        6675 :         if (!NT_STATUS_IS_OK(status)) {
    7163           0 :                 reply_nterror(req, status);
    7164           0 :                 goto out;
    7165             :         }
    7166             : 
    7167        6675 :         status = filename_convert(ctx, conn,
    7168             :                                  directory,
    7169             :                                  ucf_flags,
    7170             :                                  0,
    7171             :                                  &smb_dname);
    7172        6675 :         if (!NT_STATUS_IS_OK(status)) {
    7173          11 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    7174           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    7175             :                                         ERRSRV, ERRbadpath);
    7176           0 :                         goto out;
    7177             :                 }
    7178          11 :                 reply_nterror(req, status);
    7179          11 :                 goto out;
    7180             :         }
    7181             : 
    7182        6664 :         if (is_ntfs_stream_smb_fname(smb_dname)) {
    7183           0 :                 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
    7184           0 :                 goto out;
    7185             :         }
    7186             : 
    7187        6664 :         status = SMB_VFS_CREATE_FILE(
    7188             :                 conn,                                   /* conn */
    7189             :                 req,                                    /* req */
    7190             :                 smb_dname,                              /* fname */
    7191             :                 DELETE_ACCESS,                          /* access_mask */
    7192             :                 (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
    7193             :                         FILE_SHARE_DELETE),
    7194             :                 FILE_OPEN,                              /* create_disposition*/
    7195             :                 FILE_DIRECTORY_FILE,                    /* create_options */
    7196             :                 FILE_ATTRIBUTE_DIRECTORY,               /* file_attributes */
    7197             :                 0,                                      /* oplock_request */
    7198             :                 NULL,                                   /* lease */
    7199             :                 0,                                      /* allocation_size */
    7200             :                 0,                                      /* private_flags */
    7201             :                 NULL,                                   /* sd */
    7202             :                 NULL,                                   /* ea_list */
    7203             :                 &fsp,                                   /* result */
    7204             :                 &info,                                  /* pinfo */
    7205             :                 NULL, NULL);                            /* create context */
    7206             : 
    7207        6664 :         if (!NT_STATUS_IS_OK(status)) {
    7208         243 :                 if (open_was_deferred(req->xconn, req->mid)) {
    7209             :                         /* We have re-scheduled this call. */
    7210           0 :                         goto out;
    7211             :                 }
    7212         243 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
    7213          32 :                         bool ok = defer_smb1_sharing_violation(req);
    7214          32 :                         if (ok) {
    7215          16 :                                 goto out;
    7216             :                         }
    7217             :                 }
    7218         227 :                 reply_nterror(req, status);
    7219         227 :                 goto out;
    7220             :         }
    7221             : 
    7222        6421 :         status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
    7223        6421 :         if (!NT_STATUS_IS_OK(status)) {
    7224          38 :                 close_file(req, fsp, ERROR_CLOSE);
    7225          38 :                 reply_nterror(req, status);
    7226          38 :                 goto out;
    7227             :         }
    7228             : 
    7229        6383 :         if (!set_delete_on_close(fsp, true,
    7230        6383 :                         conn->session_info->security_token,
    7231        6383 :                         conn->session_info->unix_token)) {
    7232           0 :                 close_file(req, fsp, ERROR_CLOSE);
    7233           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    7234           0 :                 goto out;
    7235             :         }
    7236             : 
    7237        6383 :         status = close_file(req, fsp, NORMAL_CLOSE);
    7238        6383 :         if (!NT_STATUS_IS_OK(status)) {
    7239           0 :                 reply_nterror(req, status);
    7240             :         } else {
    7241        6383 :                 reply_outbuf(req, 0, 0);
    7242             :         }
    7243             : 
    7244        6383 :         DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
    7245        6675 :  out:
    7246        6675 :         TALLOC_FREE(smb_dname);
    7247        6675 :         END_PROFILE(SMBrmdir);
    7248        6675 :         return;
    7249             : }
    7250             : 
    7251             : /*******************************************************************
    7252             :  Resolve wildcards in a filename rename.
    7253             : ********************************************************************/
    7254             : 
    7255          29 : static bool resolve_wildcards(TALLOC_CTX *ctx,
    7256             :                                 const char *name1,
    7257             :                                 const char *name2,
    7258             :                                 char **pp_newname)
    7259             : {
    7260          29 :         char *name2_copy = NULL;
    7261          29 :         char *root1 = NULL;
    7262          29 :         char *root2 = NULL;
    7263          29 :         char *ext1 = NULL;
    7264          29 :         char *ext2 = NULL;
    7265             :         char *p,*p2, *pname1, *pname2;
    7266             : 
    7267          29 :         name2_copy = talloc_strdup(ctx, name2);
    7268          29 :         if (!name2_copy) {
    7269           0 :                 return False;
    7270             :         }
    7271             : 
    7272          29 :         pname1 = strrchr_m(name1,'/');
    7273          29 :         pname2 = strrchr_m(name2_copy,'/');
    7274             : 
    7275          29 :         if (!pname1 || !pname2) {
    7276           0 :                 return False;
    7277             :         }
    7278             : 
    7279             :         /* Truncate the copy of name2 at the last '/' */
    7280          29 :         *pname2 = '\0';
    7281             : 
    7282             :         /* Now go past the '/' */
    7283          29 :         pname1++;
    7284          29 :         pname2++;
    7285             : 
    7286          29 :         root1 = talloc_strdup(ctx, pname1);
    7287          29 :         root2 = talloc_strdup(ctx, pname2);
    7288             : 
    7289          29 :         if (!root1 || !root2) {
    7290           0 :                 return False;
    7291             :         }
    7292             : 
    7293          29 :         p = strrchr_m(root1,'.');
    7294          29 :         if (p) {
    7295          25 :                 *p = 0;
    7296          25 :                 ext1 = talloc_strdup(ctx, p+1);
    7297             :         } else {
    7298           4 :                 ext1 = talloc_strdup(ctx, "");
    7299             :         }
    7300          29 :         p = strrchr_m(root2,'.');
    7301          29 :         if (p) {
    7302          25 :                 *p = 0;
    7303          25 :                 ext2 = talloc_strdup(ctx, p+1);
    7304             :         } else {
    7305           4 :                 ext2 = talloc_strdup(ctx, "");
    7306             :         }
    7307             : 
    7308          29 :         if (!ext1 || !ext2) {
    7309           0 :                 return False;
    7310             :         }
    7311             : 
    7312          24 :         p = root1;
    7313          24 :         p2 = root2;
    7314         106 :         while (*p2) {
    7315          77 :                 if (*p2 == '?') {
    7316             :                         /* Hmmm. Should this be mb-aware ? */
    7317           0 :                         *p2 = *p;
    7318           0 :                         p2++;
    7319          77 :                 } else if (*p2 == '*') {
    7320          19 :                         *p2 = '\0';
    7321          19 :                         root2 = talloc_asprintf(ctx, "%s%s",
    7322             :                                                 root2,
    7323             :                                                 p);
    7324          19 :                         if (!root2) {
    7325           0 :                                 return False;
    7326             :                         }
    7327          16 :                         break;
    7328             :                 } else {
    7329          58 :                         p2++;
    7330             :                 }
    7331          58 :                 if (*p) {
    7332          58 :                         p++;
    7333             :                 }
    7334             :         }
    7335             : 
    7336          29 :         p = ext1;
    7337          29 :         p2 = ext2;
    7338         128 :         while (*p2) {
    7339          75 :                 if (*p2 == '?') {
    7340             :                         /* Hmmm. Should this be mb-aware ? */
    7341           0 :                         *p2 = *p;
    7342           0 :                         p2++;
    7343          75 :                 } else if (*p2 == '*') {
    7344           0 :                         *p2 = '\0';
    7345           0 :                         ext2 = talloc_asprintf(ctx, "%s%s",
    7346             :                                                 ext2,
    7347             :                                                 p);
    7348           0 :                         if (!ext2) {
    7349           0 :                                 return False;
    7350             :                         }
    7351           0 :                         break;
    7352             :                 } else {
    7353          75 :                         p2++;
    7354             :                 }
    7355          75 :                 if (*p) {
    7356          75 :                         p++;
    7357             :                 }
    7358             :         }
    7359             : 
    7360          29 :         if (*ext2) {
    7361          25 :                 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
    7362             :                                 name2_copy,
    7363             :                                 root2,
    7364             :                                 ext2);
    7365             :         } else {
    7366           4 :                 *pp_newname = talloc_asprintf(ctx, "%s/%s",
    7367             :                                 name2_copy,
    7368             :                                 root2);
    7369             :         }
    7370             : 
    7371          29 :         if (!*pp_newname) {
    7372           0 :                 return False;
    7373             :         }
    7374             : 
    7375          29 :         return True;
    7376             : }
    7377             : 
    7378             : /****************************************************************************
    7379             :  Ensure open files have their names updated. Updated to notify other smbd's
    7380             :  asynchronously.
    7381             : ****************************************************************************/
    7382             : 
    7383         577 : static void rename_open_files(connection_struct *conn,
    7384             :                               struct share_mode_lock *lck,
    7385             :                               struct file_id id,
    7386             :                               uint32_t orig_name_hash,
    7387             :                               const struct smb_filename *smb_fname_dst)
    7388             : {
    7389             :         files_struct *fsp;
    7390         577 :         bool did_rename = False;
    7391             :         NTSTATUS status;
    7392         577 :         uint32_t new_name_hash = 0;
    7393             : 
    7394        1710 :         for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
    7395         634 :             fsp = file_find_di_next(fsp, false)) {
    7396             :                 struct file_id_buf idbuf;
    7397             :                 /* fsp_name is a relative path under the fsp. To change this for other
    7398             :                    sharepaths we need to manipulate relative paths. */
    7399             :                 /* TODO - create the absolute path and manipulate the newname
    7400             :                    relative to the sharepath. */
    7401         634 :                 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
    7402           0 :                         continue;
    7403             :                 }
    7404         634 :                 if (fsp->name_hash != orig_name_hash) {
    7405           0 :                         continue;
    7406             :                 }
    7407         634 :                 DBG_DEBUG("renaming file %s "
    7408             :                           "(file_id %s) from %s -> %s\n",
    7409             :                           fsp_fnum_dbg(fsp),
    7410             :                           file_id_str_buf(fsp->file_id, &idbuf),
    7411             :                           fsp_str_dbg(fsp),
    7412             :                           smb_fname_str_dbg(smb_fname_dst));
    7413             : 
    7414         634 :                 status = fsp_set_smb_fname(fsp, smb_fname_dst);
    7415         634 :                 if (NT_STATUS_IS_OK(status)) {
    7416         634 :                         did_rename = True;
    7417         634 :                         new_name_hash = fsp->name_hash;
    7418             :                 }
    7419             :         }
    7420             : 
    7421         577 :         if (!did_rename) {
    7422             :                 struct file_id_buf idbuf;
    7423           0 :                 DBG_DEBUG("no open files on file_id %s "
    7424             :                           "for %s\n",
    7425             :                           file_id_str_buf(id, &idbuf),
    7426             :                           smb_fname_str_dbg(smb_fname_dst));
    7427             :         }
    7428             : 
    7429             :         /* Send messages to all smbd's (not ourself) that the name has changed. */
    7430         577 :         rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
    7431             :                               orig_name_hash, new_name_hash,
    7432             :                               smb_fname_dst);
    7433             : 
    7434         577 : }
    7435             : 
    7436             : /****************************************************************************
    7437             :  We need to check if the source path is a parent directory of the destination
    7438             :  (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
    7439             :  refuse the rename with a sharing violation. Under UNIX the above call can
    7440             :  *succeed* if /foo/bar/baz is a symlink to another area in the share. We
    7441             :  probably need to check that the client is a Windows one before disallowing
    7442             :  this as a UNIX client (one with UNIX extensions) can know the source is a
    7443             :  symlink and make this decision intelligently. Found by an excellent bug
    7444             :  report from <AndyLiebman@aol.com>.
    7445             : ****************************************************************************/
    7446             : 
    7447         587 : static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
    7448             :                                      const struct smb_filename *smb_fname_dst)
    7449             : {
    7450         587 :         const char *psrc = smb_fname_src->base_name;
    7451         587 :         const char *pdst = smb_fname_dst->base_name;
    7452             :         size_t slen;
    7453             : 
    7454         587 :         if (psrc[0] == '.' && psrc[1] == '/') {
    7455           0 :                 psrc += 2;
    7456             :         }
    7457         587 :         if (pdst[0] == '.' && pdst[1] == '/') {
    7458           0 :                 pdst += 2;
    7459             :         }
    7460         587 :         if ((slen = strlen(psrc)) > strlen(pdst)) {
    7461          36 :                 return False;
    7462             :         }
    7463         547 :         return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
    7464             : }
    7465             : 
    7466             : /*
    7467             :  * Do the notify calls from a rename
    7468             :  */
    7469             : 
    7470         577 : static void notify_rename(connection_struct *conn, bool is_dir,
    7471             :                           const struct smb_filename *smb_fname_src,
    7472             :                           const struct smb_filename *smb_fname_dst)
    7473             : {
    7474         577 :         char *parent_dir_src = NULL;
    7475         577 :         char *parent_dir_dst = NULL;
    7476             :         uint32_t mask;
    7477             : 
    7478         577 :         mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
    7479         577 :                 : FILE_NOTIFY_CHANGE_FILE_NAME;
    7480             : 
    7481         577 :         if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
    7482         577 :                             &parent_dir_src, NULL) ||
    7483         577 :             !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
    7484             :                             &parent_dir_dst, NULL)) {
    7485           0 :                 goto out;
    7486             :         }
    7487             : 
    7488         577 :         if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
    7489         549 :                 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
    7490         549 :                              smb_fname_src->base_name);
    7491         549 :                 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
    7492         549 :                              smb_fname_dst->base_name);
    7493             :         }
    7494             :         else {
    7495          28 :                 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
    7496          28 :                              smb_fname_src->base_name);
    7497          28 :                 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
    7498          28 :                              smb_fname_dst->base_name);
    7499             :         }
    7500             : 
    7501             :         /* this is a strange one. w2k3 gives an additional event for
    7502             :            CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
    7503             :            files, but not directories */
    7504         577 :         if (!is_dir) {
    7505         331 :                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
    7506             :                              FILE_NOTIFY_CHANGE_ATTRIBUTES
    7507             :                              |FILE_NOTIFY_CHANGE_CREATION,
    7508         331 :                              smb_fname_dst->base_name);
    7509             :         }
    7510         745 :  out:
    7511         577 :         TALLOC_FREE(parent_dir_src);
    7512         577 :         TALLOC_FREE(parent_dir_dst);
    7513         577 : }
    7514             : 
    7515             : /****************************************************************************
    7516             :  Returns an error if the parent directory for a filename is open in an
    7517             :  incompatible way.
    7518             : ****************************************************************************/
    7519             : 
    7520         730 : static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
    7521             :                                         const struct smb_filename *smb_fname_dst_in)
    7522             : {
    7523         730 :         struct smb_filename *smb_fname_parent = NULL;
    7524             :         struct file_id id;
    7525         730 :         files_struct *fsp = NULL;
    7526             :         int ret;
    7527             :         NTSTATUS status;
    7528             : 
    7529         730 :         status = SMB_VFS_PARENT_PATHNAME(conn,
    7530             :                                          talloc_tos(),
    7531             :                                          smb_fname_dst_in,
    7532             :                                          &smb_fname_parent,
    7533             :                                          NULL);
    7534         730 :         if (!NT_STATUS_IS_OK(status)) {
    7535           0 :                 return status;
    7536             :         }
    7537             : 
    7538         730 :         ret = SMB_VFS_LSTAT(conn, smb_fname_parent);
    7539         730 :         if (ret == -1) {
    7540           0 :                 return map_nt_error_from_unix(errno);
    7541             :         }
    7542             : 
    7543             :         /*
    7544             :          * We're only checking on this smbd here, mostly good
    7545             :          * enough.. and will pass tests.
    7546             :          */
    7547             : 
    7548         730 :         id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
    7549        1377 :         for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
    7550          20 :                         fsp = file_find_di_next(fsp, true)) {
    7551          50 :                 if (fsp->access_mask & DELETE_ACCESS) {
    7552          30 :                         return NT_STATUS_SHARING_VIOLATION;
    7553             :                 }
    7554             :         }
    7555         700 :         return NT_STATUS_OK;
    7556             : }
    7557             : 
    7558             : /****************************************************************************
    7559             :  Rename an open file - given an fsp.
    7560             : ****************************************************************************/
    7561             : 
    7562         730 : NTSTATUS rename_internals_fsp(connection_struct *conn,
    7563             :                         files_struct *fsp,
    7564             :                         struct smb_filename *smb_fname_dst_in,
    7565             :                         const char *dst_original_lcomp,
    7566             :                         uint32_t attrs,
    7567             :                         bool replace_if_exists)
    7568             : {
    7569         730 :         TALLOC_CTX *ctx = talloc_tos();
    7570         730 :         struct smb_filename *parent_dir_fname_dst = NULL;
    7571         730 :         struct smb_filename *parent_dir_fname_dst_atname = NULL;
    7572         730 :         struct smb_filename *parent_dir_fname_src = NULL;
    7573         730 :         struct smb_filename *parent_dir_fname_src_atname = NULL;
    7574         730 :         struct smb_filename *smb_fname_dst = NULL;
    7575         730 :         NTSTATUS status = NT_STATUS_OK;
    7576         730 :         struct share_mode_lock *lck = NULL;
    7577         730 :         uint32_t access_mask = SEC_DIR_ADD_FILE;
    7578             :         bool dst_exists, old_is_stream, new_is_stream;
    7579             :         int ret;
    7580             : 
    7581         730 :         status = check_name(conn, smb_fname_dst_in);
    7582         730 :         if (!NT_STATUS_IS_OK(status)) {
    7583           0 :                 return status;
    7584             :         }
    7585             : 
    7586         730 :         status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
    7587         730 :         if (!NT_STATUS_IS_OK(status)) {
    7588          30 :                 return status;
    7589             :         }
    7590             : 
    7591         700 :         if (file_has_open_streams(fsp)) {
    7592          16 :                 return NT_STATUS_ACCESS_DENIED;
    7593             :         }
    7594             : 
    7595             :         /* Make a copy of the dst smb_fname structs */
    7596             : 
    7597         684 :         smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
    7598         684 :         if (smb_fname_dst == NULL) {
    7599           0 :                 status = NT_STATUS_NO_MEMORY;
    7600           0 :                 goto out;
    7601             :         }
    7602             : 
    7603             :         /*
    7604             :          * Check for special case with case preserving and not
    7605             :          * case sensitive. If the new last component differs from the original
    7606             :          * last component only by case, then we should allow
    7607             :          * the rename (user is trying to change the case of the
    7608             :          * filename).
    7609             :          */
    7610        1368 :         if (!conn->case_sensitive && conn->case_preserve &&
    7611         757 :             strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
    7612          73 :             strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
    7613          33 :                 char *fname_dst_parent = NULL;
    7614          33 :                 const char *fname_dst_lcomp = NULL;
    7615          33 :                 char *orig_lcomp_path = NULL;
    7616          33 :                 char *orig_lcomp_stream = NULL;
    7617          33 :                 bool ok = true;
    7618             : 
    7619             :                 /*
    7620             :                  * Split off the last component of the processed
    7621             :                  * destination name. We will compare this to
    7622             :                  * the split components of dst_original_lcomp.
    7623             :                  */
    7624          33 :                 if (!parent_dirname(ctx,
    7625          33 :                                 smb_fname_dst->base_name,
    7626             :                                 &fname_dst_parent,
    7627             :                                 &fname_dst_lcomp)) {
    7628           0 :                         status = NT_STATUS_NO_MEMORY;
    7629           0 :                         goto out;
    7630             :                 }
    7631             : 
    7632             :                 /*
    7633             :                  * The dst_original_lcomp component contains
    7634             :                  * the last_component of the path + stream
    7635             :                  * name (if a stream exists).
    7636             :                  *
    7637             :                  * Split off the stream name so we
    7638             :                  * can check them separately.
    7639             :                  */
    7640             : 
    7641          33 :                 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
    7642             :                         /* POSIX - no stream component. */
    7643           0 :                         orig_lcomp_path = talloc_strdup(ctx,
    7644             :                                                 dst_original_lcomp);
    7645           0 :                         if (orig_lcomp_path == NULL) {
    7646           0 :                                 ok = false;
    7647             :                         }
    7648             :                 } else {
    7649          33 :                         ok = split_stream_filename(ctx,
    7650             :                                         dst_original_lcomp,
    7651             :                                         &orig_lcomp_path,
    7652             :                                         &orig_lcomp_stream);
    7653             :                 }
    7654             : 
    7655          33 :                 if (!ok) {
    7656           0 :                         TALLOC_FREE(fname_dst_parent);
    7657           0 :                         status = NT_STATUS_NO_MEMORY;
    7658           0 :                         goto out;
    7659             :                 }
    7660             : 
    7661             :                 /* If the base names only differ by case, use original. */
    7662          33 :                 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
    7663             :                         char *tmp;
    7664             :                         /*
    7665             :                          * Replace the modified last component with the
    7666             :                          * original.
    7667             :                          */
    7668          10 :                         if (!ISDOT(fname_dst_parent)) {
    7669          10 :                                 tmp = talloc_asprintf(smb_fname_dst,
    7670             :                                         "%s/%s",
    7671             :                                         fname_dst_parent,
    7672             :                                         orig_lcomp_path);
    7673             :                         } else {
    7674           0 :                                 tmp = talloc_strdup(smb_fname_dst,
    7675             :                                         orig_lcomp_path);
    7676             :                         }
    7677          10 :                         if (tmp == NULL) {
    7678           0 :                                 status = NT_STATUS_NO_MEMORY;
    7679           0 :                                 TALLOC_FREE(fname_dst_parent);
    7680           0 :                                 TALLOC_FREE(orig_lcomp_path);
    7681           0 :                                 TALLOC_FREE(orig_lcomp_stream);
    7682           0 :                                 goto out;
    7683             :                         }
    7684          10 :                         TALLOC_FREE(smb_fname_dst->base_name);
    7685          10 :                         smb_fname_dst->base_name = tmp;
    7686             :                 }
    7687             : 
    7688             :                 /* If the stream_names only differ by case, use original. */
    7689          33 :                 if(!strcsequal(smb_fname_dst->stream_name,
    7690             :                                orig_lcomp_stream)) {
    7691             :                         /* Use the original stream. */
    7692           0 :                         char *tmp = talloc_strdup(smb_fname_dst,
    7693             :                                             orig_lcomp_stream);
    7694           0 :                         if (tmp == NULL) {
    7695           0 :                                 status = NT_STATUS_NO_MEMORY;
    7696           0 :                                 TALLOC_FREE(fname_dst_parent);
    7697           0 :                                 TALLOC_FREE(orig_lcomp_path);
    7698           0 :                                 TALLOC_FREE(orig_lcomp_stream);
    7699           0 :                                 goto out;
    7700             :                         }
    7701           0 :                         TALLOC_FREE(smb_fname_dst->stream_name);
    7702           0 :                         smb_fname_dst->stream_name = tmp;
    7703             :                 }
    7704          33 :                 TALLOC_FREE(fname_dst_parent);
    7705          33 :                 TALLOC_FREE(orig_lcomp_path);
    7706          33 :                 TALLOC_FREE(orig_lcomp_stream);
    7707             :         }
    7708             : 
    7709             :         /*
    7710             :          * If the src and dest names are identical - including case,
    7711             :          * don't do the rename, just return success.
    7712             :          */
    7713             : 
    7714         747 :         if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
    7715          63 :             strcsequal(fsp->fsp_name->stream_name,
    7716          63 :                        smb_fname_dst->stream_name)) {
    7717          23 :                 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
    7718             :                           "- returning success\n",
    7719             :                           smb_fname_str_dbg(smb_fname_dst)));
    7720          20 :                 status = NT_STATUS_OK;
    7721          20 :                 goto out;
    7722             :         }
    7723             : 
    7724         661 :         old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
    7725         661 :         new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
    7726             : 
    7727             :         /* Return the correct error code if both names aren't streams. */
    7728         661 :         if (!old_is_stream && new_is_stream) {
    7729           4 :                 status = NT_STATUS_OBJECT_NAME_INVALID;
    7730           4 :                 goto out;
    7731             :         }
    7732             : 
    7733         657 :         if (old_is_stream && !new_is_stream) {
    7734           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    7735           0 :                 goto out;
    7736             :         }
    7737             : 
    7738         657 :         dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
    7739             : 
    7740         657 :         if(!replace_if_exists && dst_exists) {
    7741          35 :                 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
    7742             :                           "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
    7743             :                           smb_fname_str_dbg(smb_fname_dst)));
    7744          35 :                 status = NT_STATUS_OBJECT_NAME_COLLISION;
    7745          35 :                 goto out;
    7746             :         }
    7747             : 
    7748             :         /*
    7749             :          * Drop the pathref fsp on the destination otherwise we trip upon in in
    7750             :          * the below check for open files check.
    7751             :          */
    7752         622 :         if (smb_fname_dst_in->fsp != NULL) {
    7753          26 :                 fd_close(smb_fname_dst_in->fsp);
    7754          26 :                 file_free(NULL, smb_fname_dst_in->fsp);
    7755          26 :                 SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
    7756             :         }
    7757             : 
    7758         622 :         if (dst_exists) {
    7759          32 :                 struct file_id fileid = vfs_file_id_from_sbuf(conn,
    7760          32 :                     &smb_fname_dst->st);
    7761          32 :                 files_struct *dst_fsp = file_find_di_first(conn->sconn,
    7762             :                                                            fileid, true);
    7763             :                 /* The file can be open when renaming a stream */
    7764          32 :                 if (dst_fsp && !new_is_stream) {
    7765           8 :                         DEBUG(3, ("rename_internals_fsp: Target file open\n"));
    7766           8 :                         status = NT_STATUS_ACCESS_DENIED;
    7767           8 :                         goto out;
    7768             :                 }
    7769             :         }
    7770             : 
    7771             :         /* Ensure we have a valid stat struct for the source. */
    7772         614 :         status = vfs_stat_fsp(fsp);
    7773         614 :         if (!NT_STATUS_IS_OK(status)) {
    7774           0 :                 goto out;
    7775             :         }
    7776             : 
    7777         614 :         status = can_rename(conn, fsp, attrs);
    7778             : 
    7779         614 :         if (!NT_STATUS_IS_OK(status)) {
    7780          27 :                 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
    7781             :                           nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
    7782             :                           smb_fname_str_dbg(smb_fname_dst)));
    7783          27 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
    7784           0 :                         status = NT_STATUS_ACCESS_DENIED;
    7785          24 :                 goto out;
    7786             :         }
    7787             : 
    7788         587 :         if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
    7789           0 :                 status = NT_STATUS_ACCESS_DENIED;
    7790           0 :                 goto out;
    7791             :         }
    7792             : 
    7793             :         /* Do we have rights to move into the destination ? */
    7794         587 :         if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
    7795             :                 /* We're moving a directory. */
    7796         250 :                 access_mask = SEC_DIR_ADD_SUBDIR;
    7797             :         }
    7798             : 
    7799             :         /*
    7800             :          * Get a pathref on the destination parent directory, so
    7801             :          * we can call check_parent_access_fsp().
    7802             :          */
    7803         587 :         status = parent_pathref(ctx,
    7804             :                                 conn->cwd_fsp,
    7805             :                                 smb_fname_dst,
    7806             :                                 &parent_dir_fname_dst,
    7807             :                                 &parent_dir_fname_dst_atname);
    7808         587 :         if (!NT_STATUS_IS_OK(status)) {
    7809           0 :                 goto out;
    7810             :         }
    7811             : 
    7812         587 :         status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
    7813             :                                 access_mask);
    7814         587 :         if (!NT_STATUS_IS_OK(status)) {
    7815          10 :                 DBG_INFO("check_parent_access_fsp on "
    7816             :                         "dst %s returned %s\n",
    7817             :                         smb_fname_str_dbg(smb_fname_dst),
    7818             :                         nt_errstr(status));
    7819          10 :                 goto out;
    7820             :         }
    7821             : 
    7822             :         /*
    7823             :          * If the target existed, make sure the destination
    7824             :          * atname has the same stat struct.
    7825             :          */
    7826         577 :         parent_dir_fname_dst_atname->st = smb_fname_dst->st;
    7827             : 
    7828             :         /*
    7829             :          * It's very common that source and
    7830             :          * destination directories are the same.
    7831             :          * Optimize by not opening the
    7832             :          * second parent_pathref if we know
    7833             :          * this is the case.
    7834             :          */
    7835             : 
    7836         577 :         status = SMB_VFS_PARENT_PATHNAME(conn,
    7837             :                                          ctx,
    7838             :                                          fsp->fsp_name,
    7839             :                                          &parent_dir_fname_src,
    7840             :                                          &parent_dir_fname_src_atname);
    7841         577 :         if (!NT_STATUS_IS_OK(status)) {
    7842           0 :                 goto out;
    7843             :         }
    7844             : 
    7845             :         /*
    7846             :          * We do a case-sensitive string comparison. We want to be *sure*
    7847             :          * this is the same path. The worst that can happen if
    7848             :          * the case doesn't match is we lose out on the optimization,
    7849             :          * the code still works.
    7850             :          *
    7851             :          * We can ignore twrp fields here. Rename is not allowed on
    7852             :          * shadow copy handles.
    7853             :          */
    7854             : 
    7855         577 :         if (strcmp(parent_dir_fname_src->base_name,
    7856         577 :                    parent_dir_fname_dst->base_name) == 0) {
    7857             :                 /*
    7858             :                  * parent directory is the same for source
    7859             :                  * and destination.
    7860             :                  */
    7861             :                 /* Reparent the src_atname to the parent_dir_dest fname. */
    7862         549 :                 parent_dir_fname_src_atname = talloc_move(
    7863             :                                                 parent_dir_fname_dst,
    7864             :                                                 &parent_dir_fname_src_atname);
    7865             :                 /* Free the unneeded duplicate parent name. */
    7866         549 :                 TALLOC_FREE(parent_dir_fname_src);
    7867             :                 /*
    7868             :                  * And make the source parent name a copy of the
    7869             :                  * destination parent name.
    7870             :                  */
    7871         549 :                 parent_dir_fname_src = parent_dir_fname_dst;
    7872             :         } else {
    7873             :                 /*
    7874             :                  * source and destingation parent directories are
    7875             :                  * different.
    7876             :                  *
    7877             :                  * Get a pathref on the source parent directory, so
    7878             :                  * we can do a relative rename.
    7879             :                  */
    7880          28 :                 TALLOC_FREE(parent_dir_fname_src);
    7881          28 :                 status = parent_pathref(ctx,
    7882             :                                 conn->cwd_fsp,
    7883          28 :                                 fsp->fsp_name,
    7884             :                                 &parent_dir_fname_src,
    7885             :                                 &parent_dir_fname_src_atname);
    7886          28 :                 if (!NT_STATUS_IS_OK(status)) {
    7887           0 :                         goto out;
    7888             :                 }
    7889             :         }
    7890             : 
    7891             :         /*
    7892             :          * Some modules depend on the source smb_fname having a valid stat.
    7893             :          * The parent_dir_fname_src_atname is the relative name of the
    7894             :          * currently open file, so just copy the stat from the open fsp.
    7895             :          */
    7896         577 :         parent_dir_fname_src_atname->st = fsp->fsp_name->st;
    7897             : 
    7898         577 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
    7899             : 
    7900             :         /*
    7901             :          * We have the file open ourselves, so not being able to get the
    7902             :          * corresponding share mode lock is a fatal error.
    7903             :          */
    7904             : 
    7905         577 :         SMB_ASSERT(lck != NULL);
    7906             : 
    7907         577 :         ret = SMB_VFS_RENAMEAT(conn,
    7908             :                         parent_dir_fname_src->fsp,
    7909             :                         parent_dir_fname_src_atname,
    7910             :                         parent_dir_fname_dst->fsp,
    7911             :                         parent_dir_fname_dst_atname);
    7912         577 :         if (ret == 0) {
    7913         577 :                 uint32_t create_options = fh_get_private_options(fsp->fh);
    7914             : 
    7915         577 :                 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
    7916             :                           "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
    7917             :                           smb_fname_str_dbg(smb_fname_dst)));
    7918             : 
    7919         577 :                 notify_rename(conn,
    7920         577 :                               fsp->fsp_flags.is_directory,
    7921         577 :                               fsp->fsp_name,
    7922             :                               smb_fname_dst);
    7923             : 
    7924         577 :                 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
    7925             :                                   smb_fname_dst);
    7926             : 
    7927         867 :                 if (!fsp->fsp_flags.is_directory &&
    7928         654 :                     !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
    7929         412 :                     (lp_map_archive(SNUM(conn)) ||
    7930          89 :                     lp_store_dos_attributes(SNUM(conn))))
    7931             :                 {
    7932             :                         /*
    7933             :                          * We must set the archive bit on the newly renamed
    7934             :                          * file.
    7935             :                          */
    7936         323 :                         ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
    7937         323 :                         if (ret == 0) {
    7938             :                                 uint32_t old_dosmode;
    7939         323 :                                 old_dosmode = fdos_mode(fsp);
    7940             :                                 /*
    7941             :                                  * We can use fsp->fsp_name here as it has
    7942             :                                  * already been changed to the new name.
    7943             :                                  */
    7944         323 :                                 SMB_ASSERT(fsp->fsp_name->fsp == fsp);
    7945         323 :                                 file_set_dosmode(conn,
    7946             :                                                 fsp->fsp_name,
    7947             :                                                 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
    7948             :                                                 NULL,
    7949             :                                                 true);
    7950             :                         }
    7951             :                 }
    7952             : 
    7953             :                 /*
    7954             :                  * A rename acts as a new file create w.r.t. allowing an initial delete
    7955             :                  * on close, probably because in Windows there is a new handle to the
    7956             :                  * new file. If initial delete on close was requested but not
    7957             :                  * originally set, we need to set it here. This is probably not 100% correct,
    7958             :                  * but will work for the CIFSFS client which in non-posix mode
    7959             :                  * depends on these semantics. JRA.
    7960             :                  */
    7961             : 
    7962         577 :                 if (create_options & FILE_DELETE_ON_CLOSE) {
    7963           0 :                         status = can_set_delete_on_close(fsp, 0);
    7964             : 
    7965           0 :                         if (NT_STATUS_IS_OK(status)) {
    7966             :                                 /* Note that here we set the *initial* delete on close flag,
    7967             :                                  * not the regular one. The magic gets handled in close. */
    7968           0 :                                 fsp->fsp_flags.initial_delete_on_close = true;
    7969             :                         }
    7970             :                 }
    7971         577 :                 TALLOC_FREE(lck);
    7972         577 :                 status = NT_STATUS_OK;
    7973         577 :                 goto out;
    7974             :         }
    7975             : 
    7976           0 :         TALLOC_FREE(lck);
    7977             : 
    7978           0 :         if (errno == ENOTDIR || errno == EISDIR) {
    7979           0 :                 status = NT_STATUS_OBJECT_NAME_COLLISION;
    7980             :         } else {
    7981           0 :                 status = map_nt_error_from_unix(errno);
    7982             :         }
    7983             : 
    7984           0 :         DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
    7985             :                   nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
    7986             :                   smb_fname_str_dbg(smb_fname_dst)));
    7987             : 
    7988         684 :  out:
    7989             : 
    7990             :         /*
    7991             :          * parent_dir_fname_src may be a copy of parent_dir_fname_dst.
    7992             :          * See the optimization for same source and destination directory
    7993             :          * above. Only free one in that case.
    7994             :          */
    7995         684 :         if (parent_dir_fname_src != parent_dir_fname_dst) {
    7996          38 :                 TALLOC_FREE(parent_dir_fname_src);
    7997             :         }
    7998         684 :         TALLOC_FREE(parent_dir_fname_dst);
    7999         684 :         TALLOC_FREE(smb_fname_dst);
    8000             : 
    8001         684 :         return status;
    8002             : }
    8003             : 
    8004             : /****************************************************************************
    8005             :  The guts of the rename command, split out so it may be called by the NT SMB
    8006             :  code.
    8007             : ****************************************************************************/
    8008             : 
    8009         456 : NTSTATUS rename_internals(TALLOC_CTX *ctx,
    8010             :                         connection_struct *conn,
    8011             :                         struct smb_request *req,
    8012             :                         struct smb_filename *smb_fname_src,
    8013             :                         const char *src_original_lcomp,
    8014             :                         struct smb_filename *smb_fname_dst,
    8015             :                         const char *dst_original_lcomp,
    8016             :                         uint32_t attrs,
    8017             :                         bool replace_if_exists,
    8018             :                         uint32_t access_mask)
    8019             : {
    8020         456 :         char *fname_src_dir = NULL;
    8021         456 :         struct smb_filename *smb_fname_src_dir = NULL;
    8022         456 :         char *fname_src_mask = NULL;
    8023         456 :         int count=0;
    8024         456 :         NTSTATUS status = NT_STATUS_OK;
    8025         456 :         struct smb_Dir *dir_hnd = NULL;
    8026         456 :         const char *dname = NULL;
    8027         456 :         char *talloced = NULL;
    8028         456 :         long offset = 0;
    8029         456 :         int create_options = 0;
    8030         456 :         struct smb2_create_blobs *posx = NULL;
    8031             :         int rc;
    8032         456 :         bool src_has_wild = false;
    8033         456 :         bool dest_has_wild = false;
    8034             : 
    8035             :         /*
    8036             :          * Split the old name into directory and last component
    8037             :          * strings. Note that unix_convert may have stripped off a
    8038             :          * leading ./ from both name and newname if the rename is
    8039             :          * at the root of the share. We need to make sure either both
    8040             :          * name and newname contain a / character or neither of them do
    8041             :          * as this is checked in resolve_wildcards().
    8042             :          */
    8043             : 
    8044             :         /* Split up the directory from the filename/mask. */
    8045         456 :         status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
    8046             :                                       &fname_src_dir, &fname_src_mask);
    8047         456 :         if (!NT_STATUS_IS_OK(status)) {
    8048           0 :                 status = NT_STATUS_NO_MEMORY;
    8049           0 :                 goto out;
    8050             :         }
    8051             : 
    8052         456 :         if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
    8053             :                 /*
    8054             :                  * Check the wildcard mask *before*
    8055             :                  * unmangling. As mangling is done
    8056             :                  * for names that can't be returned
    8057             :                  * to Windows the unmangled name may
    8058             :                  * contain Windows wildcard characters.
    8059             :                  */
    8060         448 :                 if (src_original_lcomp != NULL) {
    8061         347 :                         src_has_wild = ms_has_wild(src_original_lcomp);
    8062             :                 }
    8063         448 :                 dest_has_wild = ms_has_wild(dst_original_lcomp);
    8064             :         }
    8065             : 
    8066             :         /*
    8067             :          * We should only check the mangled cache
    8068             :          * here if unix_convert failed. This means
    8069             :          * that the path in 'mask' doesn't exist
    8070             :          * on the file system and so we need to look
    8071             :          * for a possible mangle. This patch from
    8072             :          * Tine Smukavec <valentin.smukavec@hermes.si>.
    8073             :          */
    8074             : 
    8075         486 :         if (!VALID_STAT(smb_fname_src->st) &&
    8076          30 :             mangle_is_mangled(fname_src_mask, conn->params)) {
    8077           0 :                 char *new_mask = NULL;
    8078           0 :                 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
    8079           0 :                                             conn->params);
    8080           0 :                 if (new_mask) {
    8081           0 :                         TALLOC_FREE(fname_src_mask);
    8082           0 :                         fname_src_mask = new_mask;
    8083             :                 }
    8084             :         }
    8085             : 
    8086         456 :         if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
    8087           8 :                 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
    8088           8 :                 if (!NT_STATUS_IS_OK(status)) {
    8089           0 :                         DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
    8090             :                                     nt_errstr(status));
    8091           0 :                         goto out;
    8092             :                 }
    8093             :         }
    8094             : 
    8095         456 :         if (!src_has_wild) {
    8096             :                 files_struct *fsp;
    8097             : 
    8098             :                 /*
    8099             :                  * Only one file needs to be renamed. Append the mask back
    8100             :                  * onto the directory.
    8101             :                  */
    8102         436 :                 TALLOC_FREE(smb_fname_src->base_name);
    8103         436 :                 if (ISDOT(fname_src_dir)) {
    8104             :                         /* Ensure we use canonical names on open. */
    8105          77 :                         smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
    8106             :                                                         "%s",
    8107             :                                                         fname_src_mask);
    8108             :                 } else {
    8109         359 :                         smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
    8110             :                                                         "%s/%s",
    8111             :                                                         fname_src_dir,
    8112             :                                                         fname_src_mask);
    8113             :                 }
    8114         436 :                 if (!smb_fname_src->base_name) {
    8115           0 :                         status = NT_STATUS_NO_MEMORY;
    8116           0 :                         goto out;
    8117             :                 }
    8118             : 
    8119         436 :                 DEBUG(3, ("rename_internals: case_sensitive = %d, "
    8120             :                           "case_preserve = %d, short case preserve = %d, "
    8121             :                           "directory = %s, newname = %s, "
    8122             :                           "last_component_dest = %s\n",
    8123             :                           conn->case_sensitive, conn->case_preserve,
    8124             :                           conn->short_case_preserve,
    8125             :                           smb_fname_str_dbg(smb_fname_src),
    8126             :                           smb_fname_str_dbg(smb_fname_dst),
    8127             :                           dst_original_lcomp));
    8128             : 
    8129             :                 /* The dest name still may have wildcards. */
    8130         436 :                 if (dest_has_wild) {
    8131          14 :                         char *fname_dst_mod = NULL;
    8132          14 :                         if (!resolve_wildcards(smb_fname_dst,
    8133          14 :                                                smb_fname_src->base_name,
    8134          14 :                                                smb_fname_dst->base_name,
    8135             :                                                &fname_dst_mod)) {
    8136           0 :                                 DEBUG(6, ("rename_internals: resolve_wildcards "
    8137             :                                           "%s %s failed\n",
    8138             :                                           smb_fname_src->base_name,
    8139             :                                           smb_fname_dst->base_name));
    8140           0 :                                 status = NT_STATUS_NO_MEMORY;
    8141           0 :                                 goto out;
    8142             :                         }
    8143          14 :                         TALLOC_FREE(smb_fname_dst->base_name);
    8144          14 :                         smb_fname_dst->base_name = fname_dst_mod;
    8145             :                 }
    8146             : 
    8147         436 :                 ZERO_STRUCT(smb_fname_src->st);
    8148             : 
    8149         436 :                 rc = vfs_stat(conn, smb_fname_src);
    8150         436 :                 if (rc == -1) {
    8151          10 :                         status = map_nt_error_from_unix_common(errno);
    8152          10 :                         goto out;
    8153             :                 }
    8154             : 
    8155         426 :                 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
    8156         426 :                 if (!NT_STATUS_IS_OK(status)) {
    8157           8 :                         if (!NT_STATUS_EQUAL(status,
    8158             :                                         NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
    8159           0 :                                 goto out;
    8160             :                         }
    8161             :                         /*
    8162             :                          * Possible symlink src.
    8163             :                          */
    8164           8 :                         if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
    8165           0 :                                 goto out;
    8166             :                         }
    8167           8 :                         if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
    8168           0 :                                 goto out;
    8169             :                         }
    8170             :                 }
    8171             : 
    8172         426 :                 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
    8173         107 :                         create_options |= FILE_DIRECTORY_FILE;
    8174             :                 }
    8175             : 
    8176         426 :                 status = SMB_VFS_CREATE_FILE(
    8177             :                         conn,                           /* conn */
    8178             :                         req,                            /* req */
    8179             :                         smb_fname_src,                  /* fname */
    8180             :                         access_mask,                    /* access_mask */
    8181             :                         (FILE_SHARE_READ |              /* share_access */
    8182             :                             FILE_SHARE_WRITE),
    8183             :                         FILE_OPEN,                      /* create_disposition*/
    8184             :                         create_options,                 /* create_options */
    8185             :                         0,                              /* file_attributes */
    8186             :                         0,                              /* oplock_request */
    8187             :                         NULL,                           /* lease */
    8188             :                         0,                              /* allocation_size */
    8189             :                         0,                              /* private_flags */
    8190             :                         NULL,                           /* sd */
    8191             :                         NULL,                           /* ea_list */
    8192             :                         &fsp,                               /* result */
    8193             :                         NULL,                           /* pinfo */
    8194             :                         posx,                           /* in_context_blobs */
    8195             :                         NULL);                          /* out_context_blobs */
    8196             : 
    8197         426 :                 if (!NT_STATUS_IS_OK(status)) {
    8198          72 :                         DEBUG(3, ("Could not open rename source %s: %s\n",
    8199             :                                   smb_fname_str_dbg(smb_fname_src),
    8200             :                                   nt_errstr(status)));
    8201          68 :                         goto out;
    8202             :                 }
    8203             : 
    8204         354 :                 status = rename_internals_fsp(conn,
    8205             :                                         fsp,
    8206             :                                         smb_fname_dst,
    8207             :                                         dst_original_lcomp,
    8208             :                                         attrs,
    8209             :                                         replace_if_exists);
    8210             : 
    8211         354 :                 close_file(req, fsp, NORMAL_CLOSE);
    8212             : 
    8213         354 :                 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
    8214             :                           nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
    8215             :                           smb_fname_str_dbg(smb_fname_dst)));
    8216             : 
    8217         334 :                 goto out;
    8218             :         }
    8219             : 
    8220             :         /*
    8221             :          * Wildcards - process each file that matches.
    8222             :          */
    8223          20 :         if (strequal(fname_src_mask, "????????.???")) {
    8224           0 :                 TALLOC_FREE(fname_src_mask);
    8225           0 :                 fname_src_mask = talloc_strdup(ctx, "*");
    8226           0 :                 if (!fname_src_mask) {
    8227           0 :                         status = NT_STATUS_NO_MEMORY;
    8228           0 :                         goto out;
    8229             :                 }
    8230             :         }
    8231             : 
    8232          20 :         smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
    8233             :                                 fname_src_dir,
    8234             :                                 NULL,
    8235             :                                 NULL,
    8236             :                                 smb_fname_src->twrp,
    8237             :                                 smb_fname_src->flags);
    8238          20 :         if (smb_fname_src_dir == NULL) {
    8239           0 :                 status = NT_STATUS_NO_MEMORY;
    8240           0 :                 goto out;
    8241             :         }
    8242             : 
    8243          20 :         status = check_name(conn, smb_fname_src_dir);
    8244          20 :         if (!NT_STATUS_IS_OK(status)) {
    8245           0 :                 goto out;
    8246             :         }
    8247             : 
    8248          20 :         dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
    8249             :                           attrs);
    8250          20 :         if (dir_hnd == NULL) {
    8251           0 :                 status = map_nt_error_from_unix(errno);
    8252           0 :                 goto out;
    8253             :         }
    8254             : 
    8255          16 :         status = NT_STATUS_NO_SUCH_FILE;
    8256             :         /*
    8257             :          * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
    8258             :          * - gentest fix. JRA
    8259             :          */
    8260             : 
    8261          92 :         while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
    8262             :                                     &talloced))) {
    8263          60 :                 files_struct *fsp = NULL;
    8264          60 :                 char *destname = NULL;
    8265          60 :                 bool sysdir_entry = False;
    8266             : 
    8267             :                 /* Quick check for "." and ".." */
    8268          60 :                 if (ISDOT(dname) || ISDOTDOT(dname)) {
    8269          40 :                         if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
    8270           0 :                                 sysdir_entry = True;
    8271             :                         } else {
    8272          40 :                                 TALLOC_FREE(talloced);
    8273          77 :                                 continue;
    8274             :                         }
    8275             :                 }
    8276             : 
    8277          20 :                 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
    8278           5 :                         TALLOC_FREE(talloced);
    8279           5 :                         continue;
    8280             :                 }
    8281             : 
    8282          15 :                 if (sysdir_entry) {
    8283           0 :                         status = NT_STATUS_OBJECT_NAME_INVALID;
    8284           0 :                         break;
    8285             :                 }
    8286             : 
    8287          15 :                 TALLOC_FREE(smb_fname_src->base_name);
    8288          15 :                 if (ISDOT(fname_src_dir)) {
    8289             :                         /* Ensure we use canonical names on open. */
    8290           0 :                         smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
    8291             :                                                         "%s",
    8292             :                                                         dname);
    8293             :                 } else {
    8294          15 :                         smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
    8295             :                                                         "%s/%s",
    8296             :                                                         fname_src_dir,
    8297             :                                                         dname);
    8298             :                 }
    8299          15 :                 if (!smb_fname_src->base_name) {
    8300           0 :                         status = NT_STATUS_NO_MEMORY;
    8301           0 :                         goto out;
    8302             :                 }
    8303             : 
    8304          15 :                 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
    8305          15 :                                        smb_fname_dst->base_name,
    8306             :                                        &destname)) {
    8307           0 :                         DEBUG(6, ("resolve_wildcards %s %s failed\n",
    8308             :                                   smb_fname_src->base_name, destname));
    8309           0 :                         TALLOC_FREE(talloced);
    8310           0 :                         continue;
    8311             :                 }
    8312          15 :                 if (!destname) {
    8313           0 :                         status = NT_STATUS_NO_MEMORY;
    8314           0 :                         goto out;
    8315             :                 }
    8316             : 
    8317          15 :                 TALLOC_FREE(smb_fname_dst->base_name);
    8318          15 :                 smb_fname_dst->base_name = destname;
    8319             : 
    8320          15 :                 ZERO_STRUCT(smb_fname_src->st);
    8321          15 :                 vfs_stat(conn, smb_fname_src);
    8322             : 
    8323          15 :                 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
    8324          15 :                 if (!NT_STATUS_IS_OK(status)) {
    8325           0 :                         DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
    8326             :                                  smb_fname_str_dbg(smb_fname_src),
    8327             :                                  nt_errstr(status));
    8328           0 :                         break;
    8329             :                 }
    8330             : 
    8331          15 :                 if (!is_visible_fsp(smb_fname_src->fsp)) {
    8332           0 :                         TALLOC_FREE(talloced);
    8333           0 :                         continue;
    8334             :                 }
    8335             : 
    8336          15 :                 create_options = 0;
    8337             : 
    8338          15 :                 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
    8339           0 :                         create_options |= FILE_DIRECTORY_FILE;
    8340             :                 }
    8341             : 
    8342          15 :                 status = SMB_VFS_CREATE_FILE(
    8343             :                         conn,                           /* conn */
    8344             :                         req,                            /* req */
    8345             :                         smb_fname_src,                  /* fname */
    8346             :                         access_mask,                    /* access_mask */
    8347             :                         (FILE_SHARE_READ |              /* share_access */
    8348             :                             FILE_SHARE_WRITE),
    8349             :                         FILE_OPEN,                      /* create_disposition*/
    8350             :                         create_options,                 /* create_options */
    8351             :                         0,                              /* file_attributes */
    8352             :                         0,                              /* oplock_request */
    8353             :                         NULL,                           /* lease */
    8354             :                         0,                              /* allocation_size */
    8355             :                         0,                              /* private_flags */
    8356             :                         NULL,                           /* sd */
    8357             :                         NULL,                           /* ea_list */
    8358             :                         &fsp,                               /* result */
    8359             :                         NULL,                           /* pinfo */
    8360             :                         posx,                           /* in_context_blobs */
    8361             :                         NULL);                          /* out_context_blobs */
    8362             : 
    8363          15 :                 if (!NT_STATUS_IS_OK(status)) {
    8364           0 :                         DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
    8365             :                                  "returned %s rename %s -> %s\n",
    8366             :                                  nt_errstr(status),
    8367             :                                  smb_fname_str_dbg(smb_fname_src),
    8368             :                                  smb_fname_str_dbg(smb_fname_dst)));
    8369           0 :                         break;
    8370             :                 }
    8371             : 
    8372          15 :                 dst_original_lcomp = talloc_strdup(smb_fname_dst, dname);
    8373          15 :                 if (dst_original_lcomp == NULL) {
    8374           0 :                         status = NT_STATUS_NO_MEMORY;
    8375           0 :                         goto out;
    8376             :                 }
    8377             : 
    8378          15 :                 status = rename_internals_fsp(conn,
    8379             :                                         fsp,
    8380             :                                         smb_fname_dst,
    8381             :                                         dst_original_lcomp,
    8382             :                                         attrs,
    8383             :                                         replace_if_exists);
    8384             : 
    8385          15 :                 close_file(req, fsp, NORMAL_CLOSE);
    8386             : 
    8387          15 :                 if (!NT_STATUS_IS_OK(status)) {
    8388           0 :                         DEBUG(3, ("rename_internals_fsp returned %s for "
    8389             :                                   "rename %s -> %s\n", nt_errstr(status),
    8390             :                                   smb_fname_str_dbg(smb_fname_src),
    8391             :                                   smb_fname_str_dbg(smb_fname_dst)));
    8392           0 :                         break;
    8393             :                 }
    8394             : 
    8395          15 :                 count++;
    8396             : 
    8397          15 :                 DEBUG(3,("rename_internals: doing rename on %s -> "
    8398             :                          "%s\n", smb_fname_str_dbg(smb_fname_src),
    8399             :                          smb_fname_str_dbg(smb_fname_src)));
    8400          15 :                 TALLOC_FREE(talloced);
    8401             :         }
    8402          20 :         TALLOC_FREE(dir_hnd);
    8403             : 
    8404          24 :         if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
    8405           0 :                 status = map_nt_error_from_unix(errno);
    8406             :         }
    8407             : 
    8408         430 :  out:
    8409         456 :         TALLOC_FREE(posx);
    8410         456 :         TALLOC_FREE(talloced);
    8411         456 :         TALLOC_FREE(smb_fname_src_dir);
    8412         456 :         TALLOC_FREE(fname_src_dir);
    8413         456 :         TALLOC_FREE(fname_src_mask);
    8414         456 :         return status;
    8415             : }
    8416             : 
    8417             : /****************************************************************************
    8418             :  Reply to a mv.
    8419             : ****************************************************************************/
    8420             : 
    8421         355 : void reply_mv(struct smb_request *req)
    8422             : {
    8423         355 :         connection_struct *conn = req->conn;
    8424         355 :         char *name = NULL;
    8425         355 :         char *newname = NULL;
    8426             :         const char *p;
    8427             :         uint32_t attrs;
    8428             :         NTSTATUS status;
    8429         355 :         TALLOC_CTX *ctx = talloc_tos();
    8430         355 :         struct smb_filename *smb_fname_src = NULL;
    8431         355 :         const char *src_original_lcomp = NULL;
    8432         355 :         struct smb_filename *smb_fname_dst = NULL;
    8433         355 :         const char *dst_original_lcomp = NULL;
    8434         682 :         uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
    8435         355 :                 (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
    8436         682 :         uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
    8437         355 :                 (!req->posix_pathnames ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
    8438         355 :         bool stream_rename = false;
    8439             : 
    8440         355 :         START_PROFILE(SMBmv);
    8441             : 
    8442         355 :         if (req->wct < 1) {
    8443           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    8444           0 :                 goto out;
    8445             :         }
    8446             : 
    8447         355 :         attrs = SVAL(req->vwv+0, 0);
    8448             : 
    8449         355 :         p = (const char *)req->buf + 1;
    8450         355 :         p += srvstr_get_path_req(ctx, req, &name, p, STR_TERMINATE,
    8451             :                                        &status);
    8452         355 :         if (!NT_STATUS_IS_OK(status)) {
    8453           0 :                 reply_nterror(req, status);
    8454           0 :                 goto out;
    8455             :         }
    8456         355 :         p++;
    8457         355 :         p += srvstr_get_path_req(ctx, req, &newname, p, STR_TERMINATE,
    8458             :                                        &status);
    8459         355 :         if (!NT_STATUS_IS_OK(status)) {
    8460           0 :                 reply_nterror(req, status);
    8461           0 :                 goto out;
    8462             :         }
    8463             : 
    8464         355 :         if (!req->posix_pathnames) {
    8465             :                 /* The newname must begin with a ':' if the
    8466             :                    name contains a ':'. */
    8467         347 :                 if (strchr_m(name, ':')) {
    8468           4 :                         if (newname[0] != ':') {
    8469           0 :                                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    8470           0 :                                 goto out;
    8471             :                         }
    8472           4 :                         stream_rename = true;
    8473             :                 }
    8474             :         }
    8475             : 
    8476         355 :         status = filename_convert(ctx,
    8477             :                                   conn,
    8478             :                                   name,
    8479             :                                   src_ucf_flags,
    8480             :                                   0,
    8481             :                                   &smb_fname_src);
    8482             : 
    8483         355 :         if (!NT_STATUS_IS_OK(status)) {
    8484           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    8485           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    8486             :                                         ERRSRV, ERRbadpath);
    8487           0 :                         goto out;
    8488             :                 }
    8489           0 :                 reply_nterror(req, status);
    8490           0 :                 goto out;
    8491             :         }
    8492             : 
    8493             :         /* Get the last component of the source for rename_internals(). */
    8494         355 :         src_original_lcomp = get_original_lcomp(ctx,
    8495             :                                         conn,
    8496             :                                         name,
    8497             :                                         dst_ucf_flags);
    8498         355 :         if (src_original_lcomp == NULL) {
    8499           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    8500           0 :                 goto out;
    8501             :         }
    8502             : 
    8503         355 :         status = filename_convert(ctx,
    8504             :                                   conn,
    8505             :                                   newname,
    8506             :                                   dst_ucf_flags,
    8507             :                                   0,
    8508             :                                   &smb_fname_dst);
    8509             : 
    8510         355 :         if (!NT_STATUS_IS_OK(status)) {
    8511           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    8512           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    8513             :                                         ERRSRV, ERRbadpath);
    8514           0 :                         goto out;
    8515             :                 }
    8516           0 :                 reply_nterror(req, status);
    8517           0 :                 goto out;
    8518             :         }
    8519             : 
    8520             :         /* Get the last component of the destination for rename_internals(). */
    8521         355 :         dst_original_lcomp = get_original_lcomp(ctx,
    8522             :                                         conn,
    8523             :                                         newname,
    8524             :                                         dst_ucf_flags);
    8525         355 :         if (dst_original_lcomp == NULL) {
    8526           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    8527           0 :                 goto out;
    8528             :         }
    8529             : 
    8530         355 :         if (stream_rename) {
    8531             :                 /* smb_fname_dst->base_name must be the same as
    8532             :                    smb_fname_src->base_name. */
    8533           4 :                 TALLOC_FREE(smb_fname_dst->base_name);
    8534           5 :                 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
    8535           4 :                                                 smb_fname_src->base_name);
    8536           4 :                 if (!smb_fname_dst->base_name) {
    8537           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    8538           0 :                         goto out;
    8539             :                 }
    8540             :         }
    8541             : 
    8542         355 :         DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
    8543             :                  smb_fname_str_dbg(smb_fname_dst)));
    8544             : 
    8545         355 :         status = rename_internals(ctx,
    8546             :                                 conn,
    8547             :                                 req,
    8548             :                                 smb_fname_src,
    8549             :                                 src_original_lcomp,
    8550             :                                 smb_fname_dst,
    8551             :                                 dst_original_lcomp,
    8552             :                                 attrs,
    8553             :                                 false,
    8554             :                                 DELETE_ACCESS);
    8555         355 :         if (!NT_STATUS_IS_OK(status)) {
    8556          86 :                 if (open_was_deferred(req->xconn, req->mid)) {
    8557             :                         /* We have re-scheduled this call. */
    8558           4 :                         goto out;
    8559             :                 }
    8560          82 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
    8561          46 :                         bool ok = defer_smb1_sharing_violation(req);
    8562          46 :                         if (ok) {
    8563          22 :                                 goto out;
    8564             :                         }
    8565             :                 }
    8566          59 :                 reply_nterror(req, status);
    8567          59 :                 goto out;
    8568             :         }
    8569             : 
    8570         269 :         reply_outbuf(req, 0, 0);
    8571         356 :  out:
    8572         355 :         TALLOC_FREE(smb_fname_src);
    8573         355 :         TALLOC_FREE(smb_fname_dst);
    8574         355 :         END_PROFILE(SMBmv);
    8575         355 :         return;
    8576             : }
    8577             : 
    8578             : /*******************************************************************
    8579             :  Copy a file as part of a reply_copy.
    8580             : ******************************************************************/
    8581             : 
    8582             : /*
    8583             :  * TODO: check error codes on all callers
    8584             :  */
    8585             : 
    8586          16 : NTSTATUS copy_file(TALLOC_CTX *ctx,
    8587             :                         connection_struct *conn,
    8588             :                         struct smb_filename *smb_fname_src,
    8589             :                         struct smb_filename *smb_fname_dst,
    8590             :                         int ofun,
    8591             :                         int count,
    8592             :                         bool target_is_directory)
    8593             : {
    8594          16 :         struct smb_filename *smb_fname_dst_tmp = NULL;
    8595          16 :         off_t ret=-1;
    8596             :         files_struct *fsp1,*fsp2;
    8597             :         uint32_t dosattrs;
    8598             :         uint32_t new_create_disposition;
    8599             :         NTSTATUS status;
    8600             : 
    8601             : 
    8602          16 :         smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
    8603          16 :         if (smb_fname_dst_tmp == NULL) {
    8604           0 :                 return NT_STATUS_NO_MEMORY;
    8605             :         }
    8606             : 
    8607             :         /*
    8608             :          * If the target is a directory, extract the last component from the
    8609             :          * src filename and append it to the dst filename
    8610             :          */
    8611          16 :         if (target_is_directory) {
    8612             :                 const char *p;
    8613             : 
    8614             :                 /* dest/target can't be a stream if it's a directory. */
    8615           0 :                 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
    8616             : 
    8617           0 :                 p = strrchr_m(smb_fname_src->base_name,'/');
    8618           0 :                 if (p) {
    8619           0 :                         p++;
    8620             :                 } else {
    8621           0 :                         p = smb_fname_src->base_name;
    8622             :                 }
    8623           0 :                 smb_fname_dst_tmp->base_name =
    8624           0 :                     talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
    8625             :                                            p);
    8626           0 :                 if (!smb_fname_dst_tmp->base_name) {
    8627           0 :                         status = NT_STATUS_NO_MEMORY;
    8628           0 :                         goto out;
    8629             :                 }
    8630             :         }
    8631             : 
    8632          16 :         status = vfs_file_exist(conn, smb_fname_src);
    8633          16 :         if (!NT_STATUS_IS_OK(status)) {
    8634           0 :                 goto out;
    8635             :         }
    8636             : 
    8637          16 :         status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
    8638          16 :         if (!NT_STATUS_IS_OK(status)) {
    8639           0 :                 goto out;
    8640             :         }
    8641             : 
    8642          16 :         if (!target_is_directory && count) {
    8643           0 :                 new_create_disposition = FILE_OPEN;
    8644             :         } else {
    8645          16 :                 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
    8646             :                                                  0, ofun,
    8647             :                                                  NULL, NULL,
    8648             :                                                  &new_create_disposition,
    8649             :                                                  NULL,
    8650             :                                                  NULL)) {
    8651           0 :                         status = NT_STATUS_INVALID_PARAMETER;
    8652           0 :                         goto out;
    8653             :                 }
    8654             :         }
    8655             : 
    8656             :         /* Open the src file for reading. */
    8657          16 :         status = SMB_VFS_CREATE_FILE(
    8658             :                 conn,                                   /* conn */
    8659             :                 NULL,                                   /* req */
    8660             :                 smb_fname_src,                          /* fname */
    8661             :                 FILE_GENERIC_READ,                      /* access_mask */
    8662             :                 FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
    8663             :                 FILE_OPEN,                              /* create_disposition*/
    8664             :                 0,                                      /* create_options */
    8665             :                 FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
    8666             :                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
    8667             :                 NULL,                                   /* lease */
    8668             :                 0,                                      /* allocation_size */
    8669             :                 0,                                      /* private_flags */
    8670             :                 NULL,                                   /* sd */
    8671             :                 NULL,                                   /* ea_list */
    8672             :                 &fsp1,                                      /* result */
    8673             :                 NULL,                                   /* psbuf */
    8674             :                 NULL, NULL);                            /* create context */
    8675             : 
    8676          16 :         if (!NT_STATUS_IS_OK(status)) {
    8677           0 :                 goto out;
    8678             :         }
    8679             : 
    8680          16 :         dosattrs = fdos_mode(fsp1);
    8681             : 
    8682          16 :         if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
    8683          16 :                 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
    8684             :         }
    8685             : 
    8686          16 :         status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
    8687          32 :         if (!NT_STATUS_IS_OK(status) &&
    8688          16 :             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
    8689             :         {
    8690           0 :                 goto out;
    8691             :         }
    8692             : 
    8693             :         /* Open the dst file for writing. */
    8694          16 :         status = SMB_VFS_CREATE_FILE(
    8695             :                 conn,                                   /* conn */
    8696             :                 NULL,                                   /* req */
    8697             :                 smb_fname_dst,                          /* fname */
    8698             :                 FILE_GENERIC_WRITE,                     /* access_mask */
    8699             :                 FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
    8700             :                 new_create_disposition,                 /* create_disposition*/
    8701             :                 0,                                      /* create_options */
    8702             :                 dosattrs,                               /* file_attributes */
    8703             :                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
    8704             :                 NULL,                                   /* lease */
    8705             :                 0,                                      /* allocation_size */
    8706             :                 0,                                      /* private_flags */
    8707             :                 NULL,                                   /* sd */
    8708             :                 NULL,                                   /* ea_list */
    8709             :                 &fsp2,                                      /* result */
    8710             :                 NULL,                                   /* psbuf */
    8711             :                 NULL, NULL);                            /* create context */
    8712             : 
    8713          16 :         if (!NT_STATUS_IS_OK(status)) {
    8714           0 :                 close_file(NULL, fsp1, ERROR_CLOSE);
    8715           0 :                 goto out;
    8716             :         }
    8717             : 
    8718          16 :         if (ofun & OPENX_FILE_EXISTS_OPEN) {
    8719           0 :                 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
    8720           0 :                 if (ret == -1) {
    8721           0 :                         DEBUG(0, ("error - vfs lseek returned error %s\n",
    8722             :                                 strerror(errno)));
    8723           0 :                         status = map_nt_error_from_unix(errno);
    8724           0 :                         close_file(NULL, fsp1, ERROR_CLOSE);
    8725           0 :                         close_file(NULL, fsp2, ERROR_CLOSE);
    8726           0 :                         goto out;
    8727             :                 }
    8728             :         }
    8729             : 
    8730             :         /* Do the actual copy. */
    8731          16 :         if (smb_fname_src->st.st_ex_size) {
    8732          16 :                 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
    8733             :         } else {
    8734           0 :                 ret = 0;
    8735             :         }
    8736             : 
    8737          16 :         close_file(NULL, fsp1, NORMAL_CLOSE);
    8738             : 
    8739             :         /* Ensure the modtime is set correctly on the destination file. */
    8740          16 :         set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
    8741             : 
    8742             :         /*
    8743             :          * As we are opening fsp1 read-only we only expect
    8744             :          * an error on close on fsp2 if we are out of space.
    8745             :          * Thus we don't look at the error return from the
    8746             :          * close of fsp1.
    8747             :          */
    8748          16 :         status = close_file(NULL, fsp2, NORMAL_CLOSE);
    8749             : 
    8750          16 :         if (!NT_STATUS_IS_OK(status)) {
    8751           0 :                 goto out;
    8752             :         }
    8753             : 
    8754          16 :         if (ret != (off_t)smb_fname_src->st.st_ex_size) {
    8755           0 :                 status = NT_STATUS_DISK_FULL;
    8756           0 :                 goto out;
    8757             :         }
    8758             : 
    8759          16 :         status = NT_STATUS_OK;
    8760             : 
    8761          16 :  out:
    8762          16 :         TALLOC_FREE(smb_fname_dst_tmp);
    8763          16 :         return status;
    8764             : }
    8765             : 
    8766             : /****************************************************************************
    8767             :  Reply to a file copy.
    8768             : ****************************************************************************/
    8769             : 
    8770           0 : void reply_copy(struct smb_request *req)
    8771             : {
    8772           0 :         connection_struct *conn = req->conn;
    8773           0 :         struct smb_filename *smb_fname_src = NULL;
    8774           0 :         struct smb_filename *smb_fname_src_dir = NULL;
    8775           0 :         struct smb_filename *smb_fname_dst = NULL;
    8776           0 :         char *fname_src = NULL;
    8777           0 :         char *fname_dst = NULL;
    8778           0 :         char *fname_src_mask = NULL;
    8779           0 :         char *fname_src_dir = NULL;
    8780             :         const char *p;
    8781           0 :         int count=0;
    8782           0 :         int error = ERRnoaccess;
    8783             :         int tid2;
    8784             :         int ofun;
    8785             :         int flags;
    8786           0 :         bool target_is_directory=False;
    8787           0 :         bool source_has_wild = False;
    8788           0 :         bool dest_has_wild = False;
    8789             :         NTSTATUS status;
    8790           0 :         uint32_t ucf_flags_src = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
    8791           0 :                 ucf_flags_from_smb_request(req);
    8792           0 :         uint32_t ucf_flags_dst = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
    8793           0 :                 ucf_flags_from_smb_request(req);
    8794           0 :         TALLOC_CTX *ctx = talloc_tos();
    8795             : 
    8796           0 :         START_PROFILE(SMBcopy);
    8797             : 
    8798           0 :         if (req->wct < 3) {
    8799           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    8800           0 :                 goto out;
    8801             :         }
    8802             : 
    8803           0 :         tid2 = SVAL(req->vwv+0, 0);
    8804           0 :         ofun = SVAL(req->vwv+1, 0);
    8805           0 :         flags = SVAL(req->vwv+2, 0);
    8806             : 
    8807           0 :         p = (const char *)req->buf;
    8808           0 :         p += srvstr_get_path_req(ctx, req, &fname_src, p, STR_TERMINATE,
    8809             :                                        &status);
    8810           0 :         if (!NT_STATUS_IS_OK(status)) {
    8811           0 :                 reply_nterror(req, status);
    8812           0 :                 goto out;
    8813             :         }
    8814           0 :         p += srvstr_get_path_req(ctx, req, &fname_dst, p, STR_TERMINATE,
    8815             :                                        &status);
    8816           0 :         if (!NT_STATUS_IS_OK(status)) {
    8817           0 :                 reply_nterror(req, status);
    8818           0 :                 goto out;
    8819             :         }
    8820             : 
    8821           0 :         DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
    8822             : 
    8823           0 :         if (tid2 != conn->cnum) {
    8824             :                 /* can't currently handle inter share copies XXXX */
    8825           0 :                 DEBUG(3,("Rejecting inter-share copy\n"));
    8826           0 :                 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
    8827           0 :                 goto out;
    8828             :         }
    8829             : 
    8830           0 :         status = filename_convert(ctx, conn,
    8831             :                                   fname_src,
    8832             :                                   ucf_flags_src,
    8833             :                                   0,
    8834             :                                   &smb_fname_src);
    8835           0 :         if (!NT_STATUS_IS_OK(status)) {
    8836           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    8837           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    8838             :                                         ERRSRV, ERRbadpath);
    8839           0 :                         goto out;
    8840             :                 }
    8841           0 :                 reply_nterror(req, status);
    8842           0 :                 goto out;
    8843             :         }
    8844             : 
    8845           0 :         status = filename_convert(ctx, conn,
    8846             :                                   fname_dst,
    8847             :                                   ucf_flags_dst,
    8848             :                                   0,
    8849             :                                   &smb_fname_dst);
    8850           0 :         if (!NT_STATUS_IS_OK(status)) {
    8851           0 :                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
    8852           0 :                         reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
    8853             :                                         ERRSRV, ERRbadpath);
    8854           0 :                         goto out;
    8855             :                 }
    8856           0 :                 reply_nterror(req, status);
    8857           0 :                 goto out;
    8858             :         }
    8859             : 
    8860           0 :         target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
    8861             : 
    8862           0 :         if ((flags&1) && target_is_directory) {
    8863           0 :                 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
    8864           0 :                 goto out;
    8865             :         }
    8866             : 
    8867           0 :         if ((flags&2) && !target_is_directory) {
    8868           0 :                 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
    8869           0 :                 goto out;
    8870             :         }
    8871             : 
    8872           0 :         if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
    8873             :                 /* wants a tree copy! XXXX */
    8874           0 :                 DEBUG(3,("Rejecting tree copy\n"));
    8875           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    8876           0 :                 goto out;
    8877             :         }
    8878             : 
    8879             :         /* Split up the directory from the filename/mask. */
    8880           0 :         status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
    8881             :                                       &fname_src_dir, &fname_src_mask);
    8882           0 :         if (!NT_STATUS_IS_OK(status)) {
    8883           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    8884           0 :                 goto out;
    8885             :         }
    8886             : 
    8887           0 :         if (!req->posix_pathnames) {
    8888           0 :                 char *orig_src_lcomp = NULL;
    8889           0 :                 char *orig_dst_lcomp = NULL;
    8890             :                 /*
    8891             :                  * Check the wildcard mask *before*
    8892             :                  * unmangling. As mangling is done
    8893             :                  * for names that can't be returned
    8894             :                  * to Windows the unmangled name may
    8895             :                  * contain Windows wildcard characters.
    8896             :                  */
    8897           0 :                 orig_src_lcomp = get_original_lcomp(ctx,
    8898             :                                         conn,
    8899             :                                         fname_src,
    8900             :                                         ucf_flags_src);
    8901           0 :                 if (orig_src_lcomp == NULL) {
    8902           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    8903           0 :                         goto out;
    8904             :                 }
    8905           0 :                 orig_dst_lcomp = get_original_lcomp(ctx,
    8906             :                                         conn,
    8907             :                                         fname_dst,
    8908             :                                         ucf_flags_dst);
    8909           0 :                 if (orig_dst_lcomp == NULL) {
    8910           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    8911           0 :                         goto out;
    8912             :                 }
    8913           0 :                 source_has_wild = ms_has_wild(orig_src_lcomp);
    8914           0 :                 dest_has_wild = ms_has_wild(orig_dst_lcomp);
    8915           0 :                 TALLOC_FREE(orig_src_lcomp);
    8916           0 :                 TALLOC_FREE(orig_dst_lcomp);
    8917             :         }
    8918             : 
    8919             :         /*
    8920             :          * We should only check the mangled cache
    8921             :          * here if unix_convert failed. This means
    8922             :          * that the path in 'mask' doesn't exist
    8923             :          * on the file system and so we need to look
    8924             :          * for a possible mangle. This patch from
    8925             :          * Tine Smukavec <valentin.smukavec@hermes.si>.
    8926             :          */
    8927           0 :         if (!VALID_STAT(smb_fname_src->st) &&
    8928           0 :             mangle_is_mangled(fname_src_mask, conn->params)) {
    8929           0 :                 char *new_mask = NULL;
    8930           0 :                 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
    8931           0 :                                             &new_mask, conn->params);
    8932             : 
    8933             :                 /* Use demangled name if one was successfully found. */
    8934           0 :                 if (new_mask) {
    8935           0 :                         TALLOC_FREE(fname_src_mask);
    8936           0 :                         fname_src_mask = new_mask;
    8937             :                 }
    8938             :         }
    8939             : 
    8940           0 :         if (!source_has_wild) {
    8941             : 
    8942             :                 /*
    8943             :                  * Only one file needs to be copied. Append the mask back onto
    8944             :                  * the directory.
    8945             :                  */
    8946           0 :                 TALLOC_FREE(smb_fname_src->base_name);
    8947           0 :                 if (ISDOT(fname_src_dir)) {
    8948             :                         /* Ensure we use canonical names on open. */
    8949           0 :                         smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
    8950             :                                                         "%s",
    8951             :                                                         fname_src_mask);
    8952             :                 } else {
    8953           0 :                         smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
    8954             :                                                         "%s/%s",
    8955             :                                                         fname_src_dir,
    8956             :                                                         fname_src_mask);
    8957             :                 }
    8958           0 :                 if (!smb_fname_src->base_name) {
    8959           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    8960           0 :                         goto out;
    8961             :                 }
    8962             : 
    8963           0 :                 if (dest_has_wild) {
    8964           0 :                         char *fname_dst_mod = NULL;
    8965           0 :                         if (!resolve_wildcards(smb_fname_dst,
    8966           0 :                                                smb_fname_src->base_name,
    8967           0 :                                                smb_fname_dst->base_name,
    8968             :                                                &fname_dst_mod)) {
    8969           0 :                                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    8970           0 :                                 goto out;
    8971             :                         }
    8972           0 :                         TALLOC_FREE(smb_fname_dst->base_name);
    8973           0 :                         smb_fname_dst->base_name = fname_dst_mod;
    8974             :                 }
    8975             : 
    8976           0 :                 status = check_name(conn, smb_fname_src);
    8977           0 :                 if (!NT_STATUS_IS_OK(status)) {
    8978           0 :                         reply_nterror(req, status);
    8979           0 :                         goto out;
    8980             :                 }
    8981             : 
    8982           0 :                 status = check_name(conn, smb_fname_dst);
    8983           0 :                 if (!NT_STATUS_IS_OK(status)) {
    8984           0 :                         reply_nterror(req, status);
    8985           0 :                         goto out;
    8986             :                 }
    8987             : 
    8988           0 :                 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
    8989             :                                    ofun, count, target_is_directory);
    8990             : 
    8991           0 :                 if(!NT_STATUS_IS_OK(status)) {
    8992           0 :                         reply_nterror(req, status);
    8993           0 :                         goto out;
    8994             :                 } else {
    8995           0 :                         count++;
    8996             :                 }
    8997             :         } else {
    8998           0 :                 struct smb_Dir *dir_hnd = NULL;
    8999           0 :                 const char *dname = NULL;
    9000           0 :                 char *talloced = NULL;
    9001           0 :                 long offset = 0;
    9002             : 
    9003             :                 /*
    9004             :                  * There is a wildcard that requires us to actually read the
    9005             :                  * src dir and copy each file matching the mask to the dst.
    9006             :                  * Right now streams won't be copied, but this could
    9007             :                  * presumably be added with a nested loop for reach dir entry.
    9008             :                  */
    9009           0 :                 SMB_ASSERT(!smb_fname_src->stream_name);
    9010           0 :                 SMB_ASSERT(!smb_fname_dst->stream_name);
    9011             : 
    9012           0 :                 smb_fname_src->stream_name = NULL;
    9013           0 :                 smb_fname_dst->stream_name = NULL;
    9014             : 
    9015           0 :                 if (strequal(fname_src_mask,"????????.???")) {
    9016           0 :                         TALLOC_FREE(fname_src_mask);
    9017           0 :                         fname_src_mask = talloc_strdup(ctx, "*");
    9018           0 :                         if (!fname_src_mask) {
    9019           0 :                                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    9020           0 :                                 goto out;
    9021             :                         }
    9022             :                 }
    9023             : 
    9024           0 :                 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
    9025             :                                         fname_src_dir,
    9026             :                                         NULL,
    9027             :                                         NULL,
    9028           0 :                                         smb_fname_src->twrp,
    9029           0 :                                         smb_fname_src->flags);
    9030           0 :                 if (smb_fname_src_dir == NULL) {
    9031           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    9032           0 :                         goto out;
    9033             :                 }
    9034             : 
    9035           0 :                 status = check_name(conn, smb_fname_src_dir);
    9036           0 :                 if (!NT_STATUS_IS_OK(status)) {
    9037           0 :                         reply_nterror(req, status);
    9038           0 :                         goto out;
    9039             :                 }
    9040             : 
    9041           0 :                 dir_hnd = OpenDir(ctx,
    9042             :                                 conn,
    9043             :                                 smb_fname_src_dir,
    9044             :                                 fname_src_mask,
    9045             :                                 0);
    9046           0 :                 if (dir_hnd == NULL) {
    9047           0 :                         status = map_nt_error_from_unix(errno);
    9048           0 :                         reply_nterror(req, status);
    9049           0 :                         goto out;
    9050             :                 }
    9051             : 
    9052           0 :                 error = ERRbadfile;
    9053             : 
    9054             :                 /* Iterate over the src dir copying each entry to the dst. */
    9055           0 :                 while ((dname = ReadDirName(dir_hnd, &offset,
    9056           0 :                                             &smb_fname_src->st, &talloced))) {
    9057           0 :                         char *destname = NULL;
    9058             : 
    9059           0 :                         if (ISDOT(dname) || ISDOTDOT(dname)) {
    9060           0 :                                 TALLOC_FREE(talloced);
    9061           0 :                                 continue;
    9062             :                         }
    9063             : 
    9064           0 :                         if (IS_VETO_PATH(conn, dname)) {
    9065           0 :                                 TALLOC_FREE(talloced);
    9066           0 :                                 continue;
    9067             :                         }
    9068             : 
    9069           0 :                         if(!mask_match(dname, fname_src_mask,
    9070           0 :                                        conn->case_sensitive)) {
    9071           0 :                                 TALLOC_FREE(talloced);
    9072           0 :                                 continue;
    9073             :                         }
    9074             : 
    9075           0 :                         error = ERRnoaccess;
    9076             : 
    9077             :                         /* Get the src smb_fname struct setup. */
    9078           0 :                         TALLOC_FREE(smb_fname_src->base_name);
    9079           0 :                         if (ISDOT(fname_src_dir)) {
    9080             :                                 /* Ensure we use canonical names on open. */
    9081           0 :                                 smb_fname_src->base_name =
    9082           0 :                                         talloc_asprintf(smb_fname_src, "%s",
    9083             :                                                 dname);
    9084             :                         } else {
    9085           0 :                                 smb_fname_src->base_name =
    9086           0 :                                         talloc_asprintf(smb_fname_src, "%s/%s",
    9087             :                                                 fname_src_dir, dname);
    9088             :                         }
    9089             : 
    9090           0 :                         if (!smb_fname_src->base_name) {
    9091           0 :                                 TALLOC_FREE(dir_hnd);
    9092           0 :                                 TALLOC_FREE(talloced);
    9093           0 :                                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    9094           0 :                                 goto out;
    9095             :                         }
    9096             : 
    9097           0 :                         if (!resolve_wildcards(ctx, smb_fname_src->base_name,
    9098           0 :                                                smb_fname_dst->base_name,
    9099             :                                                &destname)) {
    9100           0 :                                 TALLOC_FREE(talloced);
    9101           0 :                                 continue;
    9102             :                         }
    9103           0 :                         if (!destname) {
    9104           0 :                                 TALLOC_FREE(dir_hnd);
    9105           0 :                                 TALLOC_FREE(talloced);
    9106           0 :                                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    9107           0 :                                 goto out;
    9108             :                         }
    9109             : 
    9110           0 :                         TALLOC_FREE(smb_fname_dst->base_name);
    9111           0 :                         smb_fname_dst->base_name = destname;
    9112             : 
    9113           0 :                         ZERO_STRUCT(smb_fname_src->st);
    9114           0 :                         vfs_stat(conn, smb_fname_src);
    9115             : 
    9116           0 :                         status = openat_pathref_fsp(conn->cwd_fsp,
    9117             :                                                     smb_fname_src);
    9118           0 :                         if (!NT_STATUS_IS_OK(status)) {
    9119           0 :                                 DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
    9120             :                                         smb_fname_str_dbg(smb_fname_src),
    9121             :                                         nt_errstr(status));
    9122           0 :                                 break;
    9123             :                         }
    9124             : 
    9125           0 :                         if (!is_visible_fsp(smb_fname_src->fsp)) {
    9126           0 :                                 TALLOC_FREE(talloced);
    9127           0 :                                 continue;
    9128             :                         }
    9129             : 
    9130           0 :                         status = check_name(conn, smb_fname_src);
    9131           0 :                         if (!NT_STATUS_IS_OK(status)) {
    9132           0 :                                 TALLOC_FREE(dir_hnd);
    9133           0 :                                 TALLOC_FREE(talloced);
    9134           0 :                                 reply_nterror(req, status);
    9135           0 :                                 goto out;
    9136             :                         }
    9137             : 
    9138           0 :                         status = check_name(conn, smb_fname_dst);
    9139           0 :                         if (!NT_STATUS_IS_OK(status)) {
    9140           0 :                                 TALLOC_FREE(dir_hnd);
    9141           0 :                                 TALLOC_FREE(talloced);
    9142           0 :                                 reply_nterror(req, status);
    9143           0 :                                 goto out;
    9144             :                         }
    9145             : 
    9146           0 :                         DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
    9147             :                                 smb_fname_src->base_name,
    9148             :                                 smb_fname_dst->base_name));
    9149             : 
    9150           0 :                         status = copy_file(ctx, conn, smb_fname_src,
    9151             :                                            smb_fname_dst, ofun, count,
    9152             :                                            target_is_directory);
    9153           0 :                         if (NT_STATUS_IS_OK(status)) {
    9154           0 :                                 count++;
    9155             :                         }
    9156             : 
    9157           0 :                         TALLOC_FREE(talloced);
    9158             :                 }
    9159           0 :                 TALLOC_FREE(dir_hnd);
    9160             :         }
    9161             : 
    9162           0 :         if (count == 0) {
    9163           0 :                 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
    9164           0 :                 goto out;
    9165             :         }
    9166             : 
    9167           0 :         reply_outbuf(req, 1, 0);
    9168           0 :         SSVAL(req->outbuf,smb_vwv0,count);
    9169           0 :  out:
    9170           0 :         TALLOC_FREE(smb_fname_src);
    9171           0 :         TALLOC_FREE(smb_fname_src_dir);
    9172           0 :         TALLOC_FREE(smb_fname_dst);
    9173           0 :         TALLOC_FREE(fname_src);
    9174           0 :         TALLOC_FREE(fname_dst);
    9175           0 :         TALLOC_FREE(fname_src_mask);
    9176           0 :         TALLOC_FREE(fname_src_dir);
    9177             : 
    9178           0 :         END_PROFILE(SMBcopy);
    9179           0 :         return;
    9180             : }
    9181             : 
    9182             : #undef DBGC_CLASS
    9183             : #define DBGC_CLASS DBGC_LOCKING
    9184             : 
    9185             : /****************************************************************************
    9186             :  Get a lock pid, dealing with large count requests.
    9187             : ****************************************************************************/
    9188             : 
    9189        5671 : uint64_t get_lock_pid(const uint8_t *data, int data_offset,
    9190             :                     bool large_file_format)
    9191             : {
    9192        5671 :         if(!large_file_format)
    9193        5151 :                 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
    9194             :         else
    9195         520 :                 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
    9196             : }
    9197             : 
    9198             : /****************************************************************************
    9199             :  Get a lock count, dealing with large count requests.
    9200             : ****************************************************************************/
    9201             : 
    9202        5671 : uint64_t get_lock_count(const uint8_t *data, int data_offset,
    9203             :                         bool large_file_format)
    9204             : {
    9205        5671 :         uint64_t count = 0;
    9206             : 
    9207        5671 :         if(!large_file_format) {
    9208        5151 :                 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
    9209             :         } else {
    9210             :                 /*
    9211             :                  * No BVAL, this is reversed!
    9212             :                  */
    9213        1036 :                 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
    9214         520 :                         ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
    9215             :         }
    9216             : 
    9217        5671 :         return count;
    9218             : }
    9219             : 
    9220             : /****************************************************************************
    9221             :  Get a lock offset, dealing with large offset requests.
    9222             : ****************************************************************************/
    9223             : 
    9224        5671 : uint64_t get_lock_offset(const uint8_t *data, int data_offset,
    9225             :                          bool large_file_format)
    9226             : {
    9227        5671 :         uint64_t offset = 0;
    9228             : 
    9229        5671 :         if(!large_file_format) {
    9230        5151 :                 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
    9231             :         } else {
    9232             :                 /*
    9233             :                  * No BVAL, this is reversed!
    9234             :                  */
    9235        1036 :                 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
    9236         520 :                                 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
    9237             :         }
    9238             : 
    9239        5671 :         return offset;
    9240             : }
    9241             : 
    9242             : struct smbd_do_unlocking_state {
    9243             :         struct files_struct *fsp;
    9244             :         uint16_t num_ulocks;
    9245             :         struct smbd_lock_element *ulocks;
    9246             :         enum brl_flavour lock_flav;
    9247             :         NTSTATUS status;
    9248             : };
    9249             : 
    9250        2286 : static void smbd_do_unlocking_fn(
    9251             :         const uint8_t *buf,
    9252             :         size_t buflen,
    9253             :         bool *pmodified_dependent,
    9254             :         void *private_data)
    9255             : {
    9256        2286 :         struct smbd_do_unlocking_state *state = private_data;
    9257        2286 :         struct files_struct *fsp = state->fsp;
    9258        2286 :         enum brl_flavour lock_flav = state->lock_flav;
    9259             :         uint16_t i;
    9260             : 
    9261        4404 :         for (i = 0; i < state->num_ulocks; i++) {
    9262        2328 :                 struct smbd_lock_element *e = &state->ulocks[i];
    9263             : 
    9264        2328 :                 DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
    9265             :                           "pid %"PRIu64", file %s\n",
    9266             :                           e->offset,
    9267             :                           e->count,
    9268             :                           e->smblctx,
    9269             :                           fsp_str_dbg(fsp));
    9270             : 
    9271        2328 :                 if (e->brltype != UNLOCK_LOCK) {
    9272             :                         /* this can only happen with SMB2 */
    9273           8 :                         state->status = NT_STATUS_INVALID_PARAMETER;
    9274           8 :                         return;
    9275             :                 }
    9276             : 
    9277        2320 :                 state->status = do_unlock(
    9278             :                         fsp, e->smblctx, e->count, e->offset, lock_flav);
    9279             : 
    9280        2320 :                 DBG_DEBUG("do_unlock returned %s\n",
    9281             :                           nt_errstr(state->status));
    9282             : 
    9283        2320 :                 if (!NT_STATUS_IS_OK(state->status)) {
    9284         200 :                         return;
    9285             :                 }
    9286             :         }
    9287             : 
    9288        2076 :         *pmodified_dependent = true;
    9289             : }
    9290             : 
    9291        2286 : NTSTATUS smbd_do_unlocking(struct smb_request *req,
    9292             :                            files_struct *fsp,
    9293             :                            uint16_t num_ulocks,
    9294             :                            struct smbd_lock_element *ulocks,
    9295             :                            enum brl_flavour lock_flav)
    9296             : {
    9297        2286 :         struct smbd_do_unlocking_state state = {
    9298             :                 .fsp = fsp,
    9299             :                 .num_ulocks = num_ulocks,
    9300             :                 .ulocks = ulocks,
    9301             :                 .lock_flav = lock_flav,
    9302             :         };
    9303             :         NTSTATUS status;
    9304             : 
    9305        2286 :         DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
    9306             : 
    9307        2286 :         status = share_mode_do_locked(
    9308             :                 fsp->file_id, smbd_do_unlocking_fn, &state);
    9309             : 
    9310        2286 :         if (!NT_STATUS_IS_OK(status)) {
    9311           0 :                 DBG_DEBUG("share_mode_do_locked failed: %s\n",
    9312             :                           nt_errstr(status));
    9313           0 :                 return status;
    9314             :         }
    9315        2286 :         if (!NT_STATUS_IS_OK(state.status)) {
    9316         210 :                 DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
    9317             :                           nt_errstr(status));
    9318         210 :                 return state.status;
    9319             :         }
    9320             : 
    9321        2076 :         return NT_STATUS_OK;
    9322             : }
    9323             : 
    9324             : /****************************************************************************
    9325             :  Reply to a lockingX request.
    9326             : ****************************************************************************/
    9327             : 
    9328             : static void reply_lockingx_done(struct tevent_req *subreq);
    9329             : 
    9330        5733 : void reply_lockingX(struct smb_request *req)
    9331             : {
    9332        5733 :         connection_struct *conn = req->conn;
    9333             :         files_struct *fsp;
    9334             :         unsigned char locktype;
    9335             :         enum brl_type brltype;
    9336             :         unsigned char oplocklevel;
    9337             :         uint16_t num_ulocks;
    9338             :         uint16_t num_locks;
    9339             :         int32_t lock_timeout;
    9340             :         uint16_t i;
    9341             :         const uint8_t *data;
    9342             :         bool large_file_format;
    9343        5733 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
    9344        5733 :         struct smbd_lock_element *locks = NULL;
    9345        5733 :         struct tevent_req *subreq = NULL;
    9346             : 
    9347        5733 :         START_PROFILE(SMBlockingX);
    9348             : 
    9349        5733 :         if (req->wct < 8) {
    9350           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    9351           0 :                 END_PROFILE(SMBlockingX);
    9352         199 :                 return;
    9353             :         }
    9354             : 
    9355        5733 :         fsp = file_fsp(req, SVAL(req->vwv+2, 0));
    9356        5733 :         locktype = CVAL(req->vwv+3, 0);
    9357        5733 :         oplocklevel = CVAL(req->vwv+3, 1);
    9358        5733 :         num_ulocks = SVAL(req->vwv+6, 0);
    9359        5733 :         num_locks = SVAL(req->vwv+7, 0);
    9360        5733 :         lock_timeout = IVAL(req->vwv+4, 0);
    9361        5733 :         large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
    9362             : 
    9363        5733 :         if (!check_fsp(conn, req, fsp)) {
    9364           4 :                 END_PROFILE(SMBlockingX);
    9365           4 :                 return;
    9366             :         }
    9367             : 
    9368        5729 :         data = req->buf;
    9369             : 
    9370        5729 :         if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
    9371             :                 /* we don't support these - and CANCEL_LOCK makes w2k
    9372             :                    and XP reboot so I don't really want to be
    9373             :                    compatible! (tridge) */
    9374           8 :                 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
    9375           8 :                 END_PROFILE(SMBlockingX);
    9376           8 :                 return;
    9377             :         }
    9378             : 
    9379             :         /* Check if this is an oplock break on a file
    9380             :            we have granted an oplock on.
    9381             :         */
    9382        5721 :         if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
    9383             :                 /* Client can insist on breaking to none. */
    9384          96 :                 bool break_to_none = (oplocklevel == 0);
    9385             :                 bool result;
    9386             : 
    9387          96 :                 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
    9388             :                          "for %s\n", (unsigned int)oplocklevel,
    9389             :                          fsp_fnum_dbg(fsp)));
    9390             : 
    9391             :                 /*
    9392             :                  * Make sure we have granted an exclusive or batch oplock on
    9393             :                  * this file.
    9394             :                  */
    9395             : 
    9396          96 :                 if (fsp->oplock_type == 0) {
    9397             : 
    9398             :                         /* The Samba4 nbench simulator doesn't understand
    9399             :                            the difference between break to level2 and break
    9400             :                            to none from level2 - it sends oplock break
    9401             :                            replies in both cases. Don't keep logging an error
    9402             :                            message here - just ignore it. JRA. */
    9403             : 
    9404          26 :                         DEBUG(5,("reply_lockingX: Error : oplock break from "
    9405             :                                  "client for %s (oplock=%d) and no "
    9406             :                                  "oplock granted on this file (%s).\n",
    9407             :                                  fsp_fnum_dbg(fsp), fsp->oplock_type,
    9408             :                                  fsp_str_dbg(fsp)));
    9409             : 
    9410             :                         /* if this is a pure oplock break request then don't
    9411             :                          * send a reply */
    9412          26 :                         if (num_locks == 0 && num_ulocks == 0) {
    9413          26 :                                 END_PROFILE(SMBlockingX);
    9414          26 :                                 return;
    9415             :                         }
    9416             : 
    9417           0 :                         END_PROFILE(SMBlockingX);
    9418           0 :                         reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
    9419           0 :                         return;
    9420             :                 }
    9421             : 
    9422          70 :                 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
    9423             :                     (break_to_none)) {
    9424          24 :                         result = remove_oplock(fsp);
    9425             :                 } else {
    9426          46 :                         result = downgrade_oplock(fsp);
    9427             :                 }
    9428             : 
    9429          70 :                 if (!result) {
    9430           0 :                         DEBUG(0, ("reply_lockingX: error in removing "
    9431             :                                   "oplock on file %s\n", fsp_str_dbg(fsp)));
    9432             :                         /* Hmmm. Is this panic justified? */
    9433           0 :                         smb_panic("internal tdb error");
    9434             :                 }
    9435             : 
    9436             :                 /* if this is a pure oplock break request then don't send a
    9437             :                  * reply */
    9438          70 :                 if (num_locks == 0 && num_ulocks == 0) {
    9439             :                         /* Sanity check - ensure a pure oplock break is not a
    9440             :                            chained request. */
    9441          70 :                         if (CVAL(req->vwv+0, 0) != 0xff) {
    9442           0 :                                 DEBUG(0,("reply_lockingX: Error : pure oplock "
    9443             :                                          "break is a chained %d request !\n",
    9444             :                                          (unsigned int)CVAL(req->vwv+0, 0)));
    9445             :                         }
    9446          70 :                         END_PROFILE(SMBlockingX);
    9447          70 :                         return;
    9448             :                 }
    9449             :         }
    9450             : 
    9451       11250 :         if (req->buflen <
    9452        5625 :             (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
    9453           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    9454           0 :                 END_PROFILE(SMBlockingX);
    9455           0 :                 return;
    9456             :         }
    9457             : 
    9458        5625 :         if (num_ulocks != 0) {
    9459        1569 :                 struct smbd_lock_element *ulocks = NULL;
    9460             :                 bool ok;
    9461             : 
    9462        1569 :                 ulocks = talloc_array(
    9463             :                         req, struct smbd_lock_element, num_ulocks);
    9464        1569 :                 if (ulocks == NULL) {
    9465           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
    9466           0 :                         END_PROFILE(SMBlockingX);
    9467           0 :                         return;
    9468             :                 }
    9469             : 
    9470             :                 /*
    9471             :                  * Data now points at the beginning of the list of
    9472             :                  * smb_unlkrng structs
    9473             :                  */
    9474        3145 :                 for (i = 0; i < num_ulocks; i++) {
    9475        1581 :                         ulocks[i].req_guid = smbd_request_guid(req,
    9476        1581 :                                 UINT16_MAX - i),
    9477        1581 :                         ulocks[i].smblctx = get_lock_pid(
    9478             :                                 data, i, large_file_format);
    9479        1581 :                         ulocks[i].count = get_lock_count(
    9480             :                                 data, i, large_file_format);
    9481        1581 :                         ulocks[i].offset = get_lock_offset(
    9482             :                                 data, i, large_file_format);
    9483        1581 :                         ulocks[i].brltype = UNLOCK_LOCK;
    9484             :                 }
    9485             : 
    9486             :                 /*
    9487             :                  * Unlock cancels pending locks
    9488             :                  */
    9489             : 
    9490        1569 :                 ok = smbd_smb1_brl_finish_by_lock(
    9491             :                         fsp,
    9492             :                         large_file_format,
    9493             :                         WINDOWS_LOCK,
    9494             :                         ulocks[0],
    9495        1569 :                         NT_STATUS_OK);
    9496        1569 :                 if (ok) {
    9497           2 :                         reply_outbuf(req, 2, 0);
    9498           2 :                         SSVAL(req->outbuf, smb_vwv0, 0xff);
    9499           2 :                         SSVAL(req->outbuf, smb_vwv1, 0);
    9500           2 :                         END_PROFILE(SMBlockingX);
    9501           2 :                         return;
    9502             :                 }
    9503             : 
    9504        1567 :                 status = smbd_do_unlocking(
    9505             :                         req, fsp, num_ulocks, ulocks, WINDOWS_LOCK);
    9506        1567 :                 TALLOC_FREE(ulocks);
    9507        1567 :                 if (!NT_STATUS_IS_OK(status)) {
    9508          66 :                         END_PROFILE(SMBlockingX);
    9509          66 :                         reply_nterror(req, status);
    9510          66 :                         return;
    9511             :                 }
    9512             :         }
    9513             : 
    9514             :         /* Now do any requested locks */
    9515        5557 :         data += ((large_file_format ? 20 : 10)*num_ulocks);
    9516             : 
    9517             :         /* Data now points at the beginning of the list
    9518             :            of smb_lkrng structs */
    9519             : 
    9520        5557 :         if (locktype & LOCKING_ANDX_SHARED_LOCK) {
    9521         216 :                 brltype = READ_LOCK;
    9522             :         } else {
    9523        5341 :                 brltype = WRITE_LOCK;
    9524             :         }
    9525             : 
    9526        5557 :         locks = talloc_array(req, struct smbd_lock_element, num_locks);
    9527        5557 :         if (locks == NULL) {
    9528           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    9529           0 :                 END_PROFILE(SMBlockingX);
    9530           0 :                 return;
    9531             :         }
    9532             : 
    9533        9632 :         for (i = 0; i < num_locks; i++) {
    9534        4090 :                 locks[i].req_guid = smbd_request_guid(req, i),
    9535        4090 :                 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
    9536        4090 :                 locks[i].count = get_lock_count(data, i, large_file_format);
    9537        4090 :                 locks[i].offset = get_lock_offset(data, i, large_file_format);
    9538        4090 :                 locks[i].brltype = brltype;
    9539             :         }
    9540             : 
    9541        5557 :         if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
    9542             : 
    9543             :                 bool ok;
    9544             : 
    9545          24 :                 if (num_locks == 0) {
    9546             :                         /* See smbtorture3 lock11 test */
    9547           4 :                         reply_outbuf(req, 2, 0);
    9548             :                         /* andx chain ends */
    9549           4 :                         SSVAL(req->outbuf, smb_vwv0, 0xff);
    9550           4 :                         SSVAL(req->outbuf, smb_vwv1, 0);
    9551           4 :                         END_PROFILE(SMBlockingX);
    9552           4 :                         return;
    9553             :                 }
    9554             : 
    9555          20 :                 ok = smbd_smb1_brl_finish_by_lock(
    9556             :                         fsp,
    9557             :                         large_file_format,
    9558             :                         WINDOWS_LOCK,
    9559             :                         locks[0], /* Windows only cancels the first lock */
    9560          20 :                         NT_STATUS_FILE_LOCK_CONFLICT);
    9561             : 
    9562          20 :                 if (!ok) {
    9563          10 :                         reply_force_doserror(req, ERRDOS, ERRcancelviolation);
    9564          10 :                         END_PROFILE(SMBlockingX);
    9565          10 :                         return;
    9566             :                 }
    9567             : 
    9568          10 :                 reply_outbuf(req, 2, 0);
    9569          10 :                 SSVAL(req->outbuf, smb_vwv0, 0xff);
    9570          10 :                 SSVAL(req->outbuf, smb_vwv1, 0);
    9571          10 :                 END_PROFILE(SMBlockingX);
    9572          10 :                 return;
    9573             :         }
    9574             : 
    9575       11029 :         subreq = smbd_smb1_do_locks_send(
    9576             :                 fsp,
    9577        5533 :                 req->sconn->ev_ctx,
    9578             :                 &req,
    9579             :                 fsp,
    9580             :                 lock_timeout,
    9581             :                 large_file_format,
    9582             :                 WINDOWS_LOCK,
    9583             :                 num_locks,
    9584             :                 locks);
    9585        5533 :         if (subreq == NULL) {
    9586           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
    9587           0 :                 END_PROFILE(SMBlockingX);
    9588           0 :                 return;
    9589             :         }
    9590        5533 :         tevent_req_set_callback(subreq, reply_lockingx_done, NULL);
    9591        5533 :         END_PROFILE(SMBlockingX);
    9592             : }
    9593             : 
    9594        5533 : static void reply_lockingx_done(struct tevent_req *subreq)
    9595             : {
    9596        5533 :         struct smb_request *req = NULL;
    9597             :         NTSTATUS status;
    9598             :         bool ok;
    9599             : 
    9600        5533 :         START_PROFILE(SMBlockingX);
    9601             : 
    9602        5533 :         ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
    9603        5533 :         SMB_ASSERT(ok);
    9604             : 
    9605        5533 :         status = smbd_smb1_do_locks_recv(subreq);
    9606        5533 :         TALLOC_FREE(subreq);
    9607             : 
    9608        5533 :         DBG_DEBUG("smbd_smb1_do_locks_recv returned %s\n", nt_errstr(status));
    9609             : 
    9610        5533 :         if (NT_STATUS_IS_OK(status)) {
    9611        3381 :                 reply_outbuf(req, 2, 0);
    9612        3381 :                 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
    9613        3381 :                 SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
    9614             :         } else {
    9615        2152 :                 reply_nterror(req, status);
    9616             :         }
    9617             : 
    9618       16525 :         ok = srv_send_smb(req->xconn,
    9619        5533 :                           (char *)req->outbuf,
    9620             :                           true,
    9621        5533 :                           req->seqnum+1,
    9622        5533 :                           IS_CONN_ENCRYPTED(req->conn),
    9623             :                           NULL);
    9624        5533 :         if (!ok) {
    9625           0 :                 exit_server_cleanly("reply_lock_done: srv_send_smb failed.");
    9626             :         }
    9627        5533 :         TALLOC_FREE(req);
    9628        5533 :         END_PROFILE(SMBlockingX);
    9629        5533 : }
    9630             : 
    9631             : #undef DBGC_CLASS
    9632             : #define DBGC_CLASS DBGC_ALL
    9633             : 
    9634             : /****************************************************************************
    9635             :  Reply to a SMBreadbmpx (read block multiplex) request.
    9636             :  Always reply with an error, if someone has a platform really needs this,
    9637             :  please contact vl@samba.org
    9638             : ****************************************************************************/
    9639             : 
    9640           0 : void reply_readbmpx(struct smb_request *req)
    9641             : {
    9642           0 :         START_PROFILE(SMBreadBmpx);
    9643           0 :         reply_force_doserror(req, ERRSRV, ERRuseSTD);
    9644           0 :         END_PROFILE(SMBreadBmpx);
    9645           0 :         return;
    9646             : }
    9647             : 
    9648             : /****************************************************************************
    9649             :  Reply to a SMBreadbs (read block multiplex secondary) request.
    9650             :  Always reply with an error, if someone has a platform really needs this,
    9651             :  please contact vl@samba.org
    9652             : ****************************************************************************/
    9653             : 
    9654           0 : void reply_readbs(struct smb_request *req)
    9655             : {
    9656           0 :         START_PROFILE(SMBreadBs);
    9657           0 :         reply_force_doserror(req, ERRSRV, ERRuseSTD);
    9658           0 :         END_PROFILE(SMBreadBs);
    9659           0 :         return;
    9660             : }
    9661             : 
    9662             : /****************************************************************************
    9663             :  Reply to a SMBsetattrE.
    9664             : ****************************************************************************/
    9665             : 
    9666           0 : void reply_setattrE(struct smb_request *req)
    9667             : {
    9668           0 :         connection_struct *conn = req->conn;
    9669             :         struct smb_file_time ft;
    9670             :         files_struct *fsp;
    9671             :         NTSTATUS status;
    9672             : 
    9673           0 :         START_PROFILE(SMBsetattrE);
    9674           0 :         init_smb_file_time(&ft);
    9675             : 
    9676           0 :         if (req->wct < 7) {
    9677           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    9678           0 :                 goto out;
    9679             :         }
    9680             : 
    9681           0 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    9682             : 
    9683           0 :         if(!fsp || (fsp->conn != conn)) {
    9684           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
    9685           0 :                 goto out;
    9686             :         }
    9687             : 
    9688             :         /*
    9689             :          * Convert the DOS times into unix times.
    9690             :          */
    9691             : 
    9692           0 :         ft.atime = time_t_to_full_timespec(
    9693           0 :             srv_make_unix_date2(req->vwv+3));
    9694           0 :         ft.mtime = time_t_to_full_timespec(
    9695           0 :             srv_make_unix_date2(req->vwv+5));
    9696           0 :         ft.create_time = time_t_to_full_timespec(
    9697           0 :             srv_make_unix_date2(req->vwv+1));
    9698             : 
    9699           0 :         reply_outbuf(req, 0, 0);
    9700             : 
    9701             :         /* 
    9702             :          * Patch from Ray Frush <frush@engr.colostate.edu>
    9703             :          * Sometimes times are sent as zero - ignore them.
    9704             :          */
    9705             : 
    9706             :         /* Ensure we have a valid stat struct for the source. */
    9707           0 :         status = vfs_stat_fsp(fsp);
    9708           0 :         if (!NT_STATUS_IS_OK(status)) {
    9709           0 :                 reply_nterror(req, status);
    9710           0 :                 goto out;
    9711             :         }
    9712             : 
    9713           0 :         if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
    9714           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
    9715           0 :                 goto out;
    9716             :         }
    9717             : 
    9718           0 :         status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
    9719           0 :         if (!NT_STATUS_IS_OK(status)) {
    9720           0 :                 reply_nterror(req, status);
    9721           0 :                 goto out;
    9722             :         }
    9723             : 
    9724           0 :         if (fsp->fsp_flags.modified) {
    9725           0 :                 trigger_write_time_update_immediate(fsp);
    9726             :         }
    9727             : 
    9728           0 :         DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
    9729             :                " createtime=%u\n",
    9730             :                 fsp_fnum_dbg(fsp),
    9731             :                 (unsigned int)ft.atime.tv_sec,
    9732             :                 (unsigned int)ft.mtime.tv_sec,
    9733             :                 (unsigned int)ft.create_time.tv_sec
    9734             :                 ));
    9735           0 :  out:
    9736           0 :         END_PROFILE(SMBsetattrE);
    9737           0 :         return;
    9738             : }
    9739             : 
    9740             : 
    9741             : /* Back from the dead for OS/2..... JRA. */
    9742             : 
    9743             : /****************************************************************************
    9744             :  Reply to a SMBwritebmpx (write block multiplex primary) request.
    9745             :  Always reply with an error, if someone has a platform really needs this,
    9746             :  please contact vl@samba.org
    9747             : ****************************************************************************/
    9748             : 
    9749           0 : void reply_writebmpx(struct smb_request *req)
    9750             : {
    9751           0 :         START_PROFILE(SMBwriteBmpx);
    9752           0 :         reply_force_doserror(req, ERRSRV, ERRuseSTD);
    9753           0 :         END_PROFILE(SMBwriteBmpx);
    9754           0 :         return;
    9755             : }
    9756             : 
    9757             : /****************************************************************************
    9758             :  Reply to a SMBwritebs (write block multiplex secondary) request.
    9759             :  Always reply with an error, if someone has a platform really needs this,
    9760             :  please contact vl@samba.org
    9761             : ****************************************************************************/
    9762             : 
    9763           0 : void reply_writebs(struct smb_request *req)
    9764             : {
    9765           0 :         START_PROFILE(SMBwriteBs);
    9766           0 :         reply_force_doserror(req, ERRSRV, ERRuseSTD);
    9767           0 :         END_PROFILE(SMBwriteBs);
    9768           0 :         return;
    9769             : }
    9770             : 
    9771             : /****************************************************************************
    9772             :  Reply to a SMBgetattrE.
    9773             : ****************************************************************************/
    9774             : 
    9775          10 : void reply_getattrE(struct smb_request *req)
    9776             : {
    9777          10 :         connection_struct *conn = req->conn;
    9778             :         int mode;
    9779             :         files_struct *fsp;
    9780             :         struct timespec create_ts;
    9781             :         NTSTATUS status;
    9782             : 
    9783          10 :         START_PROFILE(SMBgetattrE);
    9784             : 
    9785          10 :         if (req->wct < 1) {
    9786           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
    9787           0 :                 END_PROFILE(SMBgetattrE);
    9788           0 :                 return;
    9789             :         }
    9790             : 
    9791          10 :         fsp = file_fsp(req, SVAL(req->vwv+0, 0));
    9792             : 
    9793          10 :         if(!fsp || (fsp->conn != conn)) {
    9794           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
    9795           0 :                 END_PROFILE(SMBgetattrE);
    9796           0 :                 return;
    9797             :         }
    9798             : 
    9799             :         /* Do an fstat on this file */
    9800          10 :         status = vfs_stat_fsp(fsp);
    9801          10 :         if (!NT_STATUS_IS_OK(status)) {
    9802           0 :                 reply_nterror(req, status);
    9803           0 :                 END_PROFILE(SMBgetattrE);
    9804           0 :                 return;
    9805             :         }
    9806             : 
    9807          10 :         mode = fdos_mode(fsp);
    9808             : 
    9809             :         /*
    9810             :          * Convert the times into dos times. Set create
    9811             :          * date to be last modify date as UNIX doesn't save
    9812             :          * this.
    9813             :          */
    9814             : 
    9815          10 :         reply_outbuf(req, 11, 0);
    9816             : 
    9817          10 :         create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
    9818          10 :         srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
    9819          10 :         srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
    9820          10 :                           convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
    9821             :         /* Should we check pending modtime here ? JRA */
    9822          10 :         srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
    9823          10 :                           convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
    9824             : 
    9825          10 :         if (mode & FILE_ATTRIBUTE_DIRECTORY) {
    9826           0 :                 SIVAL(req->outbuf, smb_vwv6, 0);
    9827           0 :                 SIVAL(req->outbuf, smb_vwv8, 0);
    9828             :         } else {
    9829          10 :                 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
    9830          10 :                 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
    9831          10 :                 SIVAL(req->outbuf, smb_vwv8, allocation_size);
    9832             :         }
    9833          10 :         SSVAL(req->outbuf,smb_vwv10, mode);
    9834             : 
    9835          10 :         DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
    9836             : 
    9837          10 :         END_PROFILE(SMBgetattrE);
    9838           8 :         return;
    9839             : }

Generated by: LCOV version 1.13