LCOV - code coverage report
Current view: top level - source4/smb_server/smb - nttrans.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 282 396 71.2 %
Date: 2021-09-23 10:06:22 Functions: 15 19 78.9 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    NT transaction handling
       4             :    Copyright (C) Andrew Tridgell 2003
       5             :    Copyright (C) James J Myers 2003 <myersjj@samba.org>
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : /*
      21             :    This file handles the parsing of transact2 requests
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "smb_server/smb_server.h"
      26             : #include "ntvfs/ntvfs.h"
      27             : #include "libcli/raw/libcliraw.h"
      28             : #include "libcli/raw/raw_proto.h"
      29             : #include "librpc/gen_ndr/ndr_security.h"
      30             : 
      31             : /*
      32             :   hold the state of a nttrans op while in progress. Needed to allow for async backend
      33             :   functions.
      34             : */
      35             : struct nttrans_op {
      36             :         struct smb_nttrans *trans;
      37             :         NTSTATUS (*send_fn)(struct nttrans_op *);
      38             :         void *op_info;
      39             : };
      40             : 
      41             : 
      42             : /* setup a nttrans reply, given the data and params sizes */
      43         709 : static NTSTATUS nttrans_setup_reply(struct nttrans_op *op, 
      44             :                                     struct smb_nttrans *trans,
      45             :                                     uint32_t param_size, uint32_t data_size,
      46             :                                     uint8_t setup_count)
      47             : {
      48         709 :         trans->out.setup_count = setup_count;
      49         709 :         if (setup_count != 0) {
      50           5 :                 trans->out.setup = talloc_zero_array(op, uint8_t, setup_count*2);
      51           5 :                 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
      52             :         }
      53         709 :         trans->out.params = data_blob_talloc(op, NULL, param_size);
      54         709 :         if (param_size != 0) {
      55         698 :                 NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
      56             :         }
      57         709 :         trans->out.data = data_blob_talloc(op, NULL, data_size);
      58         709 :         if (data_size != 0) {
      59           0 :                 NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
      60             :         }
      61         709 :         return NT_STATUS_OK;
      62             : }
      63             : 
      64             : /*
      65             :   send a nttrans create reply
      66             : */
      67          60 : static NTSTATUS nttrans_create_send(struct nttrans_op *op)
      68             : {
      69          60 :         union smb_open *io = talloc_get_type(op->op_info, union smb_open);
      70             :         uint8_t *params;
      71             :         NTSTATUS status;
      72             : 
      73          60 :         status = nttrans_setup_reply(op, op->trans, 69, 0, 0);
      74          60 :         NT_STATUS_NOT_OK_RETURN(status);
      75          60 :         params = op->trans->out.params.data;
      76             : 
      77          60 :         SSVAL(params,        0, io->ntcreatex.out.oplock_level);
      78          60 :         smbsrv_push_fnum(params, 2, io->ntcreatex.out.file.ntvfs);
      79          60 :         SIVAL(params,        4, io->ntcreatex.out.create_action);
      80          60 :         SIVAL(params,        8, 0); /* ea error offset */
      81          60 :         push_nttime(params, 12, io->ntcreatex.out.create_time);
      82          60 :         push_nttime(params, 20, io->ntcreatex.out.access_time);
      83          60 :         push_nttime(params, 28, io->ntcreatex.out.write_time);
      84          60 :         push_nttime(params, 36, io->ntcreatex.out.change_time);
      85          60 :         SIVAL(params,       44, io->ntcreatex.out.attrib);
      86          60 :         SBVAL(params,       48, io->ntcreatex.out.alloc_size);
      87          60 :         SBVAL(params,       56, io->ntcreatex.out.size);
      88          60 :         SSVAL(params,       64, io->ntcreatex.out.file_type);
      89          60 :         SSVAL(params,       66, io->ntcreatex.out.ipc_state);
      90          60 :         SCVAL(params,       68, io->ntcreatex.out.is_directory);
      91             : 
      92          60 :         return NT_STATUS_OK;
      93             : }
      94             : 
      95             : /* 
      96             :    parse NTTRANS_CREATE request
      97             :  */
      98          85 : static NTSTATUS nttrans_create(struct smbsrv_request *req, 
      99             :                                struct nttrans_op *op)
     100             : {
     101          85 :         struct smb_nttrans *trans = op->trans;
     102             :         union smb_open *io;
     103             :         uint16_t fname_len;
     104             :         uint32_t sd_length, ea_length;
     105             :         NTSTATUS status;
     106             :         uint8_t *params;
     107             :         enum ndr_err_code ndr_err;
     108             : 
     109          85 :         if (trans->in.params.length < 54) {
     110           0 :                 return NT_STATUS_INVALID_PARAMETER;
     111             :         }
     112             : 
     113             :         /* parse the request */
     114          85 :         io = talloc(op, union smb_open);
     115          85 :         NT_STATUS_HAVE_NO_MEMORY(io);
     116             : 
     117          85 :         io->ntcreatex.level = RAW_OPEN_NTTRANS_CREATE;
     118             : 
     119          85 :         params = trans->in.params.data;
     120             : 
     121          85 :         io->ntcreatex.in.flags            = IVAL(params,  0);
     122          85 :         io->ntcreatex.in.root_fid.ntvfs   = smbsrv_pull_fnum(req, params, 4);
     123          85 :         io->ntcreatex.in.access_mask      = IVAL(params,  8);
     124          85 :         io->ntcreatex.in.alloc_size       = BVAL(params, 12);
     125          85 :         io->ntcreatex.in.file_attr        = IVAL(params, 20);
     126          85 :         io->ntcreatex.in.share_access     = IVAL(params, 24);
     127          85 :         io->ntcreatex.in.open_disposition = IVAL(params, 28);
     128          85 :         io->ntcreatex.in.create_options   = IVAL(params, 32);
     129          85 :         sd_length                         = IVAL(params, 36);
     130          85 :         ea_length                         = IVAL(params, 40);
     131          85 :         fname_len                         = IVAL(params, 44);
     132          85 :         io->ntcreatex.in.impersonation    = IVAL(params, 48);
     133          85 :         io->ntcreatex.in.security_flags   = CVAL(params, 52);
     134          85 :         io->ntcreatex.in.sec_desc         = NULL;
     135          85 :         io->ntcreatex.in.ea_list          = NULL;
     136          85 :         io->ntcreatex.in.query_maximal_access = false;
     137          85 :         io->ntcreatex.in.query_on_disk_id = false;
     138          85 :         io->ntcreatex.in.private_flags    = 0;
     139             : 
     140         170 :         req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, 
     141          85 :                         params + 53, 
     142          85 :                         MIN(fname_len+1, trans->in.params.length - 53),
     143             :                         STR_NO_RANGE_CHECK | STR_TERMINATE);
     144          85 :         if (!io->ntcreatex.in.fname) {
     145           0 :                 return NT_STATUS_INVALID_PARAMETER;
     146             :         }
     147             : 
     148         170 :         if (sd_length > trans->in.data.length ||
     149         170 :             ea_length > trans->in.data.length ||
     150          85 :             (sd_length+ea_length) > trans->in.data.length) {
     151           0 :                 return NT_STATUS_INVALID_PARAMETER;
     152             :         }
     153             : 
     154             :         /* this call has an optional security descriptor */
     155          85 :         if (sd_length != 0) {
     156             :                 DATA_BLOB blob;
     157          19 :                 blob.data = trans->in.data.data;
     158          19 :                 blob.length = sd_length;
     159          19 :                 io->ntcreatex.in.sec_desc = talloc(io, struct security_descriptor);
     160          19 :                 if (io->ntcreatex.in.sec_desc == NULL) {
     161           0 :                         return NT_STATUS_NO_MEMORY;
     162             :                 }
     163          19 :                 ndr_err = ndr_pull_struct_blob(&blob, io, 
     164          19 :                                                io->ntcreatex.in.sec_desc,
     165             :                                                (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
     166          19 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     167           0 :                         return ndr_map_error2ntstatus(ndr_err);
     168             :                 }
     169             :         }
     170             : 
     171             :         /* and an optional ea_list */
     172          85 :         if (ea_length > 4) {
     173             :                 DATA_BLOB blob;
     174           0 :                 blob.data = trans->in.data.data + sd_length;
     175           0 :                 blob.length = ea_length;
     176           0 :                 io->ntcreatex.in.ea_list = talloc(io, struct smb_ea_list);
     177           0 :                 if (io->ntcreatex.in.ea_list == NULL) {
     178           0 :                         return NT_STATUS_NO_MEMORY;
     179             :                 }
     180             : 
     181           0 :                 status = ea_pull_list_chained(&blob, io, 
     182           0 :                                               &io->ntcreatex.in.ea_list->num_eas,
     183           0 :                                               &io->ntcreatex.in.ea_list->eas);
     184           0 :                 if (!NT_STATUS_IS_OK(status)) {
     185           0 :                         return status;
     186             :                 }
     187             :         }
     188             : 
     189          85 :         op->send_fn = nttrans_create_send;
     190          85 :         op->op_info = io;
     191             : 
     192          85 :         return ntvfs_open(req->ntvfs, io);
     193             : }
     194             : 
     195             : 
     196             : /* 
     197             :    send NTTRANS_QUERY_SEC_DESC reply
     198             :  */
     199         572 : static NTSTATUS nttrans_query_sec_desc_send(struct nttrans_op *op)
     200             : {
     201         572 :         union smb_fileinfo *io = talloc_get_type(op->op_info, union smb_fileinfo);
     202             :         uint8_t *params;
     203             :         NTSTATUS status;
     204             :         enum ndr_err_code ndr_err;
     205             : 
     206         572 :         status = nttrans_setup_reply(op, op->trans, 4, 0, 0);
     207         572 :         NT_STATUS_NOT_OK_RETURN(status);
     208         572 :         params = op->trans->out.params.data;
     209             : 
     210         572 :         ndr_err = ndr_push_struct_blob(&op->trans->out.data, op, 
     211         572 :                                        io->query_secdesc.out.sd,
     212             :                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
     213         572 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     214           0 :                 return ndr_map_error2ntstatus(ndr_err);
     215             :         }
     216             : 
     217         572 :         SIVAL(params, 0, op->trans->out.data.length);
     218             : 
     219         572 :         return NT_STATUS_OK;
     220             : }
     221             : 
     222             : /* 
     223             :    parse NTTRANS_QUERY_SEC_DESC request
     224             :  */
     225         572 : static NTSTATUS nttrans_query_sec_desc(struct smbsrv_request *req, 
     226             :                                        struct nttrans_op *op)
     227             : {
     228         572 :         struct smb_nttrans *trans = op->trans;
     229             :         union smb_fileinfo *io;
     230             : 
     231         572 :         if (trans->in.params.length < 8) {
     232           0 :                 return NT_STATUS_INVALID_PARAMETER;
     233             :         }
     234             : 
     235             :         /* parse the request */
     236         572 :         io = talloc(op, union smb_fileinfo);
     237         572 :         NT_STATUS_HAVE_NO_MEMORY(io);
     238             : 
     239         572 :         io->query_secdesc.level            = RAW_FILEINFO_SEC_DESC;
     240         572 :         io->query_secdesc.in.file.ntvfs    = smbsrv_pull_fnum(req, trans->in.params.data, 0);
     241         572 :         io->query_secdesc.in.secinfo_flags = IVAL(trans->in.params.data, 4);
     242             : 
     243         572 :         op->op_info = io;
     244         572 :         op->send_fn = nttrans_query_sec_desc_send;
     245             : 
     246         572 :         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->query_secdesc.in.file.ntvfs);
     247         572 :         return ntvfs_qfileinfo(req->ntvfs, io);
     248             : }
     249             : 
     250             : 
     251             : /* 
     252             :    parse NTTRANS_SET_SEC_DESC request
     253             :  */
     254         531 : static NTSTATUS nttrans_set_sec_desc(struct smbsrv_request *req, 
     255             :                                      struct nttrans_op *op)
     256             : {
     257         531 :         struct smb_nttrans *trans = op->trans;
     258             :         union smb_setfileinfo *io;
     259             :         enum ndr_err_code ndr_err;
     260             : 
     261         531 :         if (trans->in.params.length < 8) {
     262           0 :                 return NT_STATUS_INVALID_PARAMETER;
     263             :         }
     264             : 
     265             :         /* parse the request */
     266         531 :         io = talloc(req, union smb_setfileinfo);
     267         531 :         NT_STATUS_HAVE_NO_MEMORY(io);
     268             : 
     269         531 :         io->set_secdesc.level            = RAW_SFILEINFO_SEC_DESC;
     270         531 :         io->set_secdesc.in.file.ntvfs    = smbsrv_pull_fnum(req, trans->in.params.data, 0);
     271         531 :         io->set_secdesc.in.secinfo_flags = IVAL(trans->in.params.data, 4);
     272             : 
     273         531 :         io->set_secdesc.in.sd = talloc(io, struct security_descriptor);
     274         531 :         NT_STATUS_HAVE_NO_MEMORY(io->set_secdesc.in.sd);
     275             : 
     276         531 :         ndr_err = ndr_pull_struct_blob(&trans->in.data, req, 
     277         531 :                                        io->set_secdesc.in.sd,
     278             :                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
     279         531 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     280           0 :                 return ndr_map_error2ntstatus(ndr_err);
     281             :         }
     282             : 
     283         531 :         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->set_secdesc.in.file.ntvfs);
     284         530 :         return ntvfs_setfileinfo(req->ntvfs, io);
     285             : }
     286             : 
     287             : 
     288             : /* parse NTTRANS_RENAME request
     289             :  */
     290           2 : static NTSTATUS nttrans_rename(struct smbsrv_request *req, 
     291             :                                struct nttrans_op *op)
     292             : {
     293           2 :         struct smb_nttrans *trans = op->trans;
     294             :         union smb_rename *io;
     295             : 
     296           2 :         if (trans->in.params.length < 5) {
     297           0 :                 return NT_STATUS_INVALID_PARAMETER;
     298             :         }
     299             : 
     300             :         /* parse the request */
     301           2 :         io = talloc(req, union smb_rename);
     302           2 :         NT_STATUS_HAVE_NO_MEMORY(io);
     303             : 
     304           2 :         io->nttrans.level            = RAW_RENAME_NTTRANS;
     305           2 :         io->nttrans.in.file.ntvfs    = smbsrv_pull_fnum(req, trans->in.params.data, 0);
     306           2 :         io->nttrans.in.flags         = SVAL(trans->in.params.data, 2);
     307             : 
     308           2 :         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4,
     309             :                                 &io->nttrans.in.new_name,
     310             :                                 STR_TERMINATE);
     311           2 :         if (!io->nttrans.in.new_name) {
     312           0 :                 return NT_STATUS_INVALID_PARAMETER;
     313             :         }
     314             : 
     315           2 :         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->nttrans.in.file.ntvfs);
     316           1 :         return ntvfs_rename(req->ntvfs, io);
     317             : }
     318             : 
     319             : /* 
     320             :    parse NTTRANS_IOCTL send
     321             :  */
     322           5 : static NTSTATUS nttrans_ioctl_send(struct nttrans_op *op)
     323             : {
     324           5 :         union smb_ioctl *info = talloc_get_type(op->op_info, union smb_ioctl);
     325             :         NTSTATUS status;
     326             : 
     327             :         /* 
     328             :          * we pass 0 as data_count here,
     329             :          * because we reuse the DATA_BLOB from the smb_ioctl
     330             :          * struct
     331             :          */
     332           5 :         status = nttrans_setup_reply(op, op->trans, 0, 0, 1);
     333           5 :         NT_STATUS_NOT_OK_RETURN(status);
     334             : 
     335           5 :         op->trans->out.setup[0]           = 0;
     336           5 :         op->trans->out.data               = info->ntioctl.out.blob;
     337             : 
     338           5 :         return NT_STATUS_OK;
     339             : }
     340             : 
     341             : 
     342             : /* 
     343             :    parse NTTRANS_IOCTL request
     344             :  */
     345          10 : static NTSTATUS nttrans_ioctl(struct smbsrv_request *req, 
     346             :                               struct nttrans_op *op)
     347             : {
     348          10 :         struct smb_nttrans *trans = op->trans;
     349             :         union smb_ioctl *nt;
     350             : 
     351             :         /* should have at least 4 setup words */
     352          10 :         if (trans->in.setup_count != 4) {
     353           0 :                 return NT_STATUS_INVALID_PARAMETER;
     354             :         }
     355             : 
     356          10 :         nt = talloc(op, union smb_ioctl);
     357          10 :         NT_STATUS_HAVE_NO_MEMORY(nt);
     358             :         
     359          10 :         nt->ntioctl.level            = RAW_IOCTL_NTIOCTL;
     360          10 :         nt->ntioctl.in.function              = IVAL(trans->in.setup, 0);
     361          10 :         nt->ntioctl.in.file.ntvfs    = smbsrv_pull_fnum(req, (uint8_t *)trans->in.setup, 4);
     362          10 :         nt->ntioctl.in.fsctl         = CVAL(trans->in.setup, 6);
     363          10 :         nt->ntioctl.in.filter                = CVAL(trans->in.setup, 7);
     364          10 :         nt->ntioctl.in.max_data              = trans->in.max_data;
     365          10 :         nt->ntioctl.in.blob          = trans->in.data;
     366             : 
     367          10 :         op->op_info = nt;
     368          10 :         op->send_fn = nttrans_ioctl_send;
     369             : 
     370          10 :         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(nt->ntioctl.in.file.ntvfs);
     371           9 :         return ntvfs_ioctl(req->ntvfs, nt);
     372             : }
     373             : 
     374             : 
     375             : /* 
     376             :    send NTTRANS_NOTIFY_CHANGE reply
     377             :  */
     378          72 : static NTSTATUS nttrans_notify_change_send(struct nttrans_op *op)
     379             : {
     380          72 :         union smb_notify *info = talloc_get_type(op->op_info, union smb_notify);
     381          72 :         size_t size = 0;
     382             :         int i;
     383             :         NTSTATUS status;
     384             :         uint8_t *p;
     385             : #define MAX_BYTES_PER_CHAR 3
     386             :         
     387             :         /* work out how big the reply buffer could be */
     388         371 :         for (i=0;i<info->nttrans.out.num_changes;i++) {
     389         299 :                 size += 12 + 3 + (1+strlen(info->nttrans.out.changes[i].name.s)) * MAX_BYTES_PER_CHAR;
     390             :         }
     391             : 
     392          72 :         status = nttrans_setup_reply(op, op->trans, size, 0, 0);
     393          72 :         NT_STATUS_NOT_OK_RETURN(status);
     394          72 :         p = op->trans->out.params.data;
     395             : 
     396             :         /* construct the changes buffer */
     397         371 :         for (i=0;i<info->nttrans.out.num_changes;i++) {
     398             :                 uint32_t ofs;
     399             :                 ssize_t len;
     400             : 
     401         299 :                 SIVAL(p, 4, info->nttrans.out.changes[i].action);
     402         299 :                 len = push_string(p + 12, info->nttrans.out.changes[i].name.s, 
     403         299 :                                   op->trans->out.params.length - 
     404         299 :                                   (p+12 - op->trans->out.params.data), STR_UNICODE);
     405         299 :                 SIVAL(p, 8, len);
     406             : 
     407         299 :                 ofs = len + 12;
     408             : 
     409         299 :                 if (ofs & 3) {
     410         121 :                         int pad = 4 - (ofs & 3);
     411         121 :                         memset(p+ofs, 0, pad);
     412         121 :                         ofs += pad;
     413             :                 }
     414             : 
     415         299 :                 if (i == info->nttrans.out.num_changes-1) {
     416          66 :                         SIVAL(p, 0, 0);
     417             :                 } else {
     418         233 :                         SIVAL(p, 0, ofs);
     419             :                 }
     420             : 
     421         299 :                 p += ofs;
     422             :         }
     423             : 
     424          72 :         op->trans->out.params.length = p - op->trans->out.params.data;
     425             : 
     426          72 :         return NT_STATUS_OK;
     427             : }
     428             : 
     429             : /* 
     430             :    parse NTTRANS_NOTIFY_CHANGE request
     431             :  */
     432         611 : static NTSTATUS nttrans_notify_change(struct smbsrv_request *req, 
     433             :                                       struct nttrans_op *op)
     434             : {
     435         611 :         struct smb_nttrans *trans = op->trans;
     436             :         union smb_notify *info;
     437             : 
     438             :         /* should have at least 4 setup words */
     439         611 :         if (trans->in.setup_count != 4) {
     440           0 :                 return NT_STATUS_INVALID_PARAMETER;
     441             :         }
     442             : 
     443         611 :         info = talloc(op, union smb_notify);
     444         611 :         NT_STATUS_HAVE_NO_MEMORY(info);
     445             : 
     446         611 :         info->nttrans.level                  = RAW_NOTIFY_NTTRANS;
     447         611 :         info->nttrans.in.completion_filter   = IVAL(trans->in.setup, 0);
     448         611 :         info->nttrans.in.file.ntvfs          = smbsrv_pull_fnum(req, (uint8_t *)trans->in.setup, 4);
     449         611 :         info->nttrans.in.recursive           = SVAL(trans->in.setup, 6);
     450         611 :         info->nttrans.in.buffer_size         = trans->in.max_param;
     451             : 
     452         611 :         op->op_info = info;
     453         611 :         op->send_fn = nttrans_notify_change_send;
     454             : 
     455         611 :         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(info->nttrans.in.file.ntvfs);
     456         603 :         return ntvfs_notify(req->ntvfs, info);
     457             : }
     458             : 
     459             : /*
     460             :   backend for nttrans requests
     461             : */
     462        1811 : static NTSTATUS nttrans_backend(struct smbsrv_request *req, 
     463             :                                 struct nttrans_op *op)
     464             : {
     465             :         /* the nttrans command is in function */
     466        1811 :         switch (op->trans->in.function) {
     467          85 :         case NT_TRANSACT_CREATE:
     468          85 :                 return nttrans_create(req, op);
     469          10 :         case NT_TRANSACT_IOCTL:
     470          10 :                 return nttrans_ioctl(req, op);
     471           2 :         case NT_TRANSACT_RENAME:
     472           2 :                 return nttrans_rename(req, op);
     473         572 :         case NT_TRANSACT_QUERY_SECURITY_DESC:
     474         572 :                 return nttrans_query_sec_desc(req, op);
     475         531 :         case NT_TRANSACT_SET_SECURITY_DESC:
     476         531 :                 return nttrans_set_sec_desc(req, op);
     477         611 :         case NT_TRANSACT_NOTIFY_CHANGE:
     478         611 :                 return nttrans_notify_change(req, op);
     479             :         }
     480             : 
     481             :         /* an unknown nttrans command */
     482           0 :         return NT_STATUS_DOS(ERRSRV, ERRerror);
     483             : }
     484             : 
     485             : 
     486        1811 : static void reply_nttrans_send(struct ntvfs_request *ntvfs)
     487             : {
     488             :         struct smbsrv_request *req;
     489             :         uint32_t params_left, data_left;
     490             :         uint8_t *params, *data;
     491             :         struct smb_nttrans *trans;
     492             :         struct nttrans_op *op;
     493             : 
     494        1811 :         SMBSRV_CHECK_ASYNC_STATUS(op, struct nttrans_op);
     495             : 
     496        1240 :         trans = op->trans;
     497             : 
     498             :         /* if this function needs work to form the nttrans reply buffer, then
     499             :            call that now */
     500        1240 :         if (op->send_fn != NULL) {
     501             :                 NTSTATUS status;
     502         709 :                 status = op->send_fn(op);
     503         709 :                 if (!NT_STATUS_IS_OK(status)) {
     504           0 :                         smbsrv_send_error(req, status);
     505           0 :                         return;
     506             :                 }
     507             :         }
     508             : 
     509        1240 :         smbsrv_setup_reply(req, 18 + trans->out.setup_count, 0);
     510             : 
     511             :         /* note that we don't check the max_setup count (matching w2k3
     512             :            behaviour) */
     513             : 
     514        1240 :         if (trans->out.params.length > trans->in.max_param) {
     515           0 :                 smbsrv_setup_error(req, NT_STATUS_BUFFER_TOO_SMALL);
     516           0 :                 trans->out.params.length = trans->in.max_param;
     517             :         }
     518        1240 :         if (trans->out.data.length > trans->in.max_data) {
     519           0 :                 smbsrv_setup_error(req, NT_STATUS_BUFFER_TOO_SMALL);
     520           0 :                 trans->out.data.length = trans->in.max_data;
     521             :         }
     522             : 
     523        1240 :         params_left = trans->out.params.length;
     524        1240 :         data_left   = trans->out.data.length;
     525        1240 :         params      = trans->out.params.data;
     526        1240 :         data        = trans->out.data.data;
     527             : 
     528             :         /* we need to divide up the reply into chunks that fit into
     529             :            the negotiated buffer size */
     530             :         do {
     531             :                 uint32_t this_data, this_param, max_bytes;
     532        1240 :                 unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
     533             :                 struct smbsrv_request *this_req;
     534             : 
     535        1240 :                 max_bytes = req_max_data(req) - (align1 + align2);
     536             : 
     537        1240 :                 this_param = params_left;
     538        1240 :                 if (this_param > max_bytes) {
     539           0 :                         this_param = max_bytes;
     540             :                 }
     541        1240 :                 max_bytes -= this_param;
     542             : 
     543        1240 :                 this_data = data_left;
     544        1240 :                 if (this_data > max_bytes) {
     545           0 :                         this_data = max_bytes;
     546             :                 }
     547             : 
     548             :                 /* don't destroy unless this is the last chunk */
     549        1240 :                 if (params_left - this_param != 0 || 
     550           0 :                     data_left - this_data != 0) {
     551           0 :                         this_req = smbsrv_setup_secondary_request(req);
     552             :                 } else {
     553        1240 :                         this_req = req;
     554             :                 }
     555             : 
     556        1240 :                 req_grow_data(this_req, this_param + this_data + (align1 + align2));
     557             : 
     558        1240 :                 SSVAL(this_req->out.vwv, 0, 0); /* reserved */
     559        1240 :                 SCVAL(this_req->out.vwv, 2, 0); /* reserved */
     560        1240 :                 SIVAL(this_req->out.vwv, 3, trans->out.params.length);
     561        1240 :                 SIVAL(this_req->out.vwv, 7, trans->out.data.length);
     562             : 
     563        1240 :                 SIVAL(this_req->out.vwv, 11, this_param);
     564        1240 :                 SIVAL(this_req->out.vwv, 15, align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
     565        1240 :                 SIVAL(this_req->out.vwv, 19, PTR_DIFF(params, trans->out.params.data));
     566             : 
     567        1240 :                 SIVAL(this_req->out.vwv, 23, this_data);
     568        1240 :                 SIVAL(this_req->out.vwv, 27, align1 + align2 + 
     569             :                       PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
     570        1240 :                 SIVAL(this_req->out.vwv, 31, PTR_DIFF(data, trans->out.data.data));
     571             : 
     572        1240 :                 SCVAL(this_req->out.vwv, 35, trans->out.setup_count);
     573        1240 :                 if (trans->out.setup_count > 0) {
     574          10 :                         memcpy((char *)(this_req->out.vwv) + VWV(18),
     575           5 :                                trans->out.setup,
     576           5 :                                sizeof(uint16_t) * trans->out.setup_count);
     577             :                 }
     578        1240 :                 memset(this_req->out.data, 0, align1);
     579        1240 :                 if (this_param != 0) {
     580         698 :                         memcpy(this_req->out.data + align1, params, this_param);
     581             :                 }
     582        1240 :                 memset(this_req->out.data+this_param+align1, 0, align2);
     583        1240 :                 if (this_data != 0) {
     584         572 :                         memcpy(this_req->out.data+this_param+align1+align2, 
     585             :                                data, this_data);
     586             :                 }
     587             : 
     588        1240 :                 params_left -= this_param;
     589        1240 :                 data_left -= this_data;
     590        1240 :                 params += this_param;
     591        1240 :                 data += this_data;
     592             : 
     593        1240 :                 smbsrv_send_reply(this_req);
     594        1240 :         } while (params_left != 0 || data_left != 0);
     595             : }
     596             : 
     597             : /*
     598             :   send a continue request
     599             : */
     600           0 : static void reply_nttrans_continue(struct smbsrv_request *req, struct smb_nttrans *trans)
     601             : {
     602             :         struct smbsrv_request *req2;
     603             :         struct smbsrv_trans_partial *tp;
     604             :         int count;
     605             : 
     606             :         /* make sure they don't flood us */
     607           0 :         for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
     608           0 :         if (count > 100) {
     609           0 :                 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
     610           0 :                 return;
     611             :         }
     612             : 
     613           0 :         tp = talloc(req, struct smbsrv_trans_partial);
     614             : 
     615           0 :         tp->req = req;
     616           0 :         tp->u.nttrans = trans;
     617           0 :         tp->command = SMBnttrans;
     618             : 
     619           0 :         DLIST_ADD(req->smb_conn->trans_partial, tp);
     620           0 :         talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
     621             : 
     622           0 :         req2 = smbsrv_setup_secondary_request(req);
     623             : 
     624             :         /* send a 'please continue' reply */
     625           0 :         smbsrv_setup_reply(req2, 0, 0);
     626           0 :         smbsrv_send_reply(req2);
     627             : }
     628             : 
     629             : 
     630             : /*
     631             :   answer a reconstructed trans request
     632             : */
     633        1811 : static void reply_nttrans_complete(struct smbsrv_request *req, struct smb_nttrans *trans)
     634             : {
     635             :         struct nttrans_op *op;
     636             : 
     637        1811 :         SMBSRV_TALLOC_IO_PTR(op, struct nttrans_op);
     638        1811 :         SMBSRV_SETUP_NTVFS_REQUEST(reply_nttrans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
     639             : 
     640        1811 :         op->trans    = trans;
     641        1811 :         op->op_info  = NULL;
     642        1811 :         op->send_fn  = NULL;
     643             : 
     644             :         /* its a full request, give it to the backend */
     645        1811 :         ZERO_STRUCT(trans->out);
     646        1811 :         SMBSRV_CALL_NTVFS_BACKEND(nttrans_backend(req, op));
     647             : }
     648             : 
     649             : 
     650             : /****************************************************************************
     651             :  Reply to an SMBnttrans request
     652             : ****************************************************************************/
     653        1811 : void smbsrv_reply_nttrans(struct smbsrv_request *req)
     654             : {
     655             :         struct smb_nttrans *trans;
     656             :         uint32_t param_ofs, data_ofs;
     657             :         uint32_t param_count, data_count;
     658             :         uint32_t param_total, data_total;
     659             : 
     660             :         /* parse request */
     661        1811 :         if (req->in.wct < 19) {
     662           0 :                 smbsrv_send_error(req, NT_STATUS_FOOBAR);
     663           0 :                 return;
     664             :         }
     665             : 
     666        1811 :         trans = talloc(req, struct smb_nttrans);
     667        1811 :         if (trans == NULL) {
     668           0 :                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
     669           0 :                 return;
     670             :         }
     671             : 
     672        1811 :         trans->in.max_setup  = CVAL(req->in.vwv, 0);
     673        1811 :         param_total          = IVAL(req->in.vwv, 3);
     674        1811 :         data_total           = IVAL(req->in.vwv, 7);
     675        1811 :         trans->in.max_param  = IVAL(req->in.vwv, 11);
     676        1811 :         trans->in.max_data   = IVAL(req->in.vwv, 15);
     677        1811 :         param_count          = IVAL(req->in.vwv, 19);
     678        1811 :         param_ofs            = IVAL(req->in.vwv, 23);
     679        1811 :         data_count           = IVAL(req->in.vwv, 27);
     680        1811 :         data_ofs             = IVAL(req->in.vwv, 31);
     681        1811 :         trans->in.setup_count= CVAL(req->in.vwv, 35);
     682        1811 :         trans->in.function   = SVAL(req->in.vwv, 36);
     683             : 
     684        1811 :         if (req->in.wct != 19 + trans->in.setup_count) {
     685           0 :                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
     686           0 :                 return;
     687             :         }
     688             : 
     689             :         /* parse out the setup words */
     690        1811 :         trans->in.setup = talloc_array(req, uint8_t, trans->in.setup_count*2);
     691        1811 :         if (!trans->in.setup) {
     692           0 :                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
     693           0 :                 return;
     694             :         }
     695        1811 :         memcpy(trans->in.setup, (char *)(req->in.vwv) + VWV(19),
     696        1811 :                sizeof(uint16_t) * trans->in.setup_count);
     697             : 
     698        3621 :         if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
     699        1811 :             !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
     700           0 :                 smbsrv_send_error(req, NT_STATUS_FOOBAR);
     701           0 :                 return;
     702             :         }
     703             : 
     704             :         /* is it a partial request? if so, then send a 'send more' message */
     705        1811 :         if (param_total > param_count || data_total > data_count) {
     706           0 :                 reply_nttrans_continue(req, trans);
     707           0 :                 return;
     708             :         }
     709             : 
     710        1811 :         reply_nttrans_complete(req, trans);
     711             : }
     712             : 
     713             : 
     714             : /****************************************************************************
     715             :  Reply to an SMBnttranss request
     716             : ****************************************************************************/
     717           0 : void smbsrv_reply_nttranss(struct smbsrv_request *req)
     718             : {
     719             :         struct smbsrv_trans_partial *tp;
     720           0 :         struct smb_nttrans *trans = NULL;
     721             :         uint32_t param_ofs, data_ofs;
     722             :         uint32_t param_count, data_count;
     723             :         uint32_t param_disp, data_disp;
     724             :         uint32_t param_total, data_total;
     725             :         DATA_BLOB params, data;
     726             : 
     727             :         /* parse request */
     728           0 :         if (req->in.wct != 18) {
     729           0 :                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
     730           0 :                 return;
     731             :         }
     732             : 
     733           0 :         for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
     734           0 :                 if (tp->command == SMBnttrans &&
     735           0 :                     SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
     736             : /* TODO: check the VUID, PID and TID too? */
     737           0 :                         break;
     738             :                 }
     739             :         }
     740             : 
     741           0 :         if (tp == NULL) {
     742           0 :                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
     743           0 :                 return;
     744             :         }
     745             : 
     746           0 :         trans = tp->u.nttrans;
     747             : 
     748           0 :         param_total           = IVAL(req->in.vwv, 3);
     749           0 :         data_total            = IVAL(req->in.vwv, 7);
     750           0 :         param_count           = IVAL(req->in.vwv, 11);
     751           0 :         param_ofs             = IVAL(req->in.vwv, 15);
     752           0 :         param_disp            = IVAL(req->in.vwv, 19);
     753           0 :         data_count            = IVAL(req->in.vwv, 23);
     754           0 :         data_ofs              = IVAL(req->in.vwv, 27);
     755           0 :         data_disp             = IVAL(req->in.vwv, 31);
     756             : 
     757           0 :         if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &params) ||
     758           0 :             !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
     759           0 :                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
     760           0 :                 return;
     761             :         }
     762             : 
     763             :         /* only allow contiguous requests */
     764           0 :         if ((param_count != 0 &&
     765           0 :              param_disp != trans->in.params.length) ||
     766           0 :             (data_count != 0 &&
     767           0 :              data_disp != trans->in.data.length)) {
     768           0 :                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
     769           0 :                 return;
     770             :         }
     771             : 
     772             :         /* add to the existing request */
     773           0 :         if (param_count != 0) {
     774           0 :                 trans->in.params.data = talloc_realloc(trans,
     775             :                                                        trans->in.params.data,
     776             :                                                        uint8_t,
     777             :                                                        param_disp + param_count);
     778           0 :                 if (trans->in.params.data == NULL) {
     779           0 :                         smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
     780           0 :                         return;
     781             :                 }
     782           0 :                 trans->in.params.length = param_disp + param_count;
     783             :         }
     784             : 
     785           0 :         if (data_count != 0) {
     786           0 :                 trans->in.data.data = talloc_realloc(trans,
     787             :                                                      trans->in.data.data,
     788             :                                                      uint8_t,
     789             :                                                      data_disp + data_count);
     790           0 :                 if (trans->in.data.data == NULL) {
     791           0 :                         smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
     792           0 :                         return;
     793             :                 }
     794           0 :                 trans->in.data.length = data_disp + data_count;
     795             :         }
     796             : 
     797           0 :         memcpy(trans->in.params.data + param_disp, params.data, params.length);
     798           0 :         memcpy(trans->in.data.data + data_disp, data.data, data.length);
     799             : 
     800             :         /* the sequence number of the reply is taken from the last secondary
     801             :            response */
     802           0 :         tp->req->seq_num = req->seq_num;
     803             : 
     804             :         /* we don't reply to Transs2 requests */
     805           0 :         talloc_free(req);
     806             : 
     807           0 :         if (trans->in.params.length == param_total &&
     808           0 :             trans->in.data.length == data_total) {
     809             :                 /* its now complete */
     810           0 :                 req = tp->req;
     811           0 :                 talloc_free(tp);
     812           0 :                 reply_nttrans_complete(req, trans);
     813             :         }
     814           0 :         return;
     815             : }

Generated by: LCOV version 1.13