LCOV - code coverage report
Current view: top level - source4/libcli/smb2 - create.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 178 243 73.3 %
Date: 2021-09-23 10:06:22 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB2 client tree handling
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2005
       7             :    
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "libcli/raw/libcliraw.h"
      24             : #include "libcli/raw/raw_proto.h"
      25             : #include "libcli/smb2/smb2.h"
      26             : #include "libcli/smb2/smb2_calls.h"
      27             : #include "librpc/gen_ndr/ndr_security.h"
      28             : 
      29             : /*
      30             :   send a create request
      31             : */
      32      613418 : struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create *io)
      33             : {
      34             :         struct smb2_request *req;
      35             :         NTSTATUS status;
      36             :         DATA_BLOB blob;
      37             :         struct smb2_create_blobs blobs;
      38             :         int i;
      39             : 
      40      613418 :         ZERO_STRUCT(blobs);
      41             : 
      42      613418 :         req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, true, 0);
      43      613418 :         if (req == NULL) return NULL;
      44             : 
      45      613418 :         SCVAL(req->out.body, 0x02, io->in.security_flags);
      46      613418 :         SCVAL(req->out.body, 0x03, io->in.oplock_level);
      47      613418 :         SIVAL(req->out.body, 0x04, io->in.impersonation_level);
      48      613418 :         SBVAL(req->out.body, 0x08, io->in.create_flags);
      49      613418 :         SBVAL(req->out.body, 0x10, io->in.reserved);
      50      613418 :         SIVAL(req->out.body, 0x18, io->in.desired_access);
      51      613418 :         SIVAL(req->out.body, 0x1C, io->in.file_attributes);
      52      613418 :         SIVAL(req->out.body, 0x20, io->in.share_access);
      53      613418 :         SIVAL(req->out.body, 0x24, io->in.create_disposition);
      54      613418 :         SIVAL(req->out.body, 0x28, io->in.create_options);
      55             : 
      56      613418 :         status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname);
      57      613418 :         if (!NT_STATUS_IS_OK(status)) {
      58           0 :                 talloc_free(req);
      59           0 :                 return NULL;
      60             :         }
      61             : 
      62             :         /* now add all the optional blobs */
      63      613418 :         if (io->in.eas.num_eas != 0) {
      64         226 :                 DATA_BLOB b = data_blob_talloc(req, NULL, 
      65             :                                                ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas, 4));
      66         226 :                 ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas, 4);
      67         226 :                 status = smb2_create_blob_add(req, &blobs,
      68             :                                               SMB2_CREATE_TAG_EXTA, b);
      69         226 :                 if (!NT_STATUS_IS_OK(status)) {
      70           0 :                         talloc_free(req);
      71           0 :                         return NULL;
      72             :                 }
      73         226 :                 data_blob_free(&b);
      74             :         }
      75             : 
      76             :         /* an empty MxAc tag seems to be used to ask the server to
      77             :            return the maximum access mask allowed on the file */
      78      613418 :         if (io->in.query_maximal_access) {
      79             :                 /* TODO: MS-SMB2 2.2.13.2.5 says this can contain a timestamp? What to do
      80             :                    with that if it doesn't match? */
      81          45 :                 status = smb2_create_blob_add(req, &blobs,
      82             :                                               SMB2_CREATE_TAG_MXAC, data_blob(NULL, 0));
      83          45 :                 if (!NT_STATUS_IS_OK(status)) {
      84           0 :                         talloc_free(req);
      85           0 :                         return NULL;
      86             :                 }
      87             :         }
      88             : 
      89      613418 :         if (io->in.alloc_size != 0) {
      90             :                 uint8_t data[8];
      91         181 :                 SBVAL(data, 0, io->in.alloc_size);
      92         181 :                 status = smb2_create_blob_add(req, &blobs,
      93             :                                               SMB2_CREATE_TAG_ALSI, data_blob_const(data, 8));
      94         181 :                 if (!NT_STATUS_IS_OK(status)) {
      95           0 :                         talloc_free(req);
      96           0 :                         return NULL;
      97             :                 }
      98             :         }
      99             : 
     100      613418 :         if (io->in.durable_open) {
     101         334 :                 status = smb2_create_blob_add(req, &blobs,
     102             :                                               SMB2_CREATE_TAG_DHNQ, data_blob_talloc_zero(req, 16));
     103         334 :                 if (!NT_STATUS_IS_OK(status)) {
     104           0 :                         talloc_free(req);
     105           0 :                         return NULL;
     106             :                 }
     107             :         }
     108             : 
     109      613418 :         if (io->in.durable_open_v2) {
     110             :                 uint8_t data[32];
     111        1048 :                 uint32_t flags = 0;
     112        1048 :                 struct GUID_ndr_buf guid_buf = { .buf = {0}, };
     113             : 
     114        1048 :                 SIVAL(data, 0, io->in.timeout);
     115        1048 :                 if (io->in.persistent_open) {
     116         208 :                         flags = SMB2_DHANDLE_FLAG_PERSISTENT;
     117             :                 }
     118        1048 :                 SIVAL(data, 4, flags);
     119        1048 :                 SBVAL(data, 8, 0x0); /* reserved */
     120        1048 :                 status = GUID_to_ndr_buf(&io->in.create_guid, &guid_buf);
     121        1048 :                 if (!NT_STATUS_IS_OK(status)) {
     122           0 :                         talloc_free(req);
     123           0 :                         return NULL;
     124             :                 }
     125        1048 :                 memcpy(data+16, guid_buf.buf, sizeof(guid_buf.buf));
     126             : 
     127        1048 :                 status = smb2_create_blob_add(req, &blobs,
     128             :                                               SMB2_CREATE_TAG_DH2Q,
     129             :                                               data_blob_const(data, 32));
     130        1048 :                 if (!NT_STATUS_IS_OK(status)) {
     131           0 :                         talloc_free(req);
     132           0 :                         return NULL;
     133             :                 }
     134             :         }
     135             : 
     136      613418 :         if (io->in.durable_handle) {
     137             :                 uint8_t data[16];
     138         138 :                 smb2_push_handle(data, io->in.durable_handle);
     139         138 :                 status = smb2_create_blob_add(req, &blobs,
     140             :                                               SMB2_CREATE_TAG_DHNC, data_blob_const(data, 16));
     141         138 :                 if (!NT_STATUS_IS_OK(status)) {
     142           0 :                         talloc_free(req);
     143           0 :                         return NULL;
     144             :                 }
     145             :         }
     146             : 
     147      613418 :         if (io->in.durable_handle_v2) {
     148             :                 uint8_t data[36];
     149         124 :                 struct GUID_ndr_buf guid_buf = { .buf = {0}, };
     150         124 :                 uint32_t flags = 0;
     151             : 
     152         124 :                 smb2_push_handle(data, io->in.durable_handle_v2);
     153         124 :                 status = GUID_to_ndr_buf(&io->in.create_guid, &guid_buf);
     154         124 :                 if (!NT_STATUS_IS_OK(status)) {
     155           0 :                         talloc_free(req);
     156           0 :                         return NULL;
     157             :                 }
     158         124 :                 memcpy(data+16, guid_buf.buf, sizeof(guid_buf.buf));
     159         124 :                 if (io->in.persistent_open) {
     160           0 :                         flags = SMB2_DHANDLE_FLAG_PERSISTENT;
     161             :                 }
     162         124 :                 SIVAL(data, 32, flags);
     163             : 
     164         124 :                 status = smb2_create_blob_add(req, &blobs,
     165             :                                               SMB2_CREATE_TAG_DH2C,
     166             :                                               data_blob_const(data, 36));
     167         124 :                 if (!NT_STATUS_IS_OK(status)) {
     168           0 :                         talloc_free(req);
     169           0 :                         return NULL;
     170             :                 }
     171             :         }
     172             : 
     173      613418 :         if (io->in.timewarp) {
     174             :                 uint8_t data[8];
     175          14 :                 SBVAL(data, 0, io->in.timewarp);             
     176          14 :                 status = smb2_create_blob_add(req, &blobs,
     177             :                                               SMB2_CREATE_TAG_TWRP, data_blob_const(data, 8));
     178          14 :                 if (!NT_STATUS_IS_OK(status)) {
     179           0 :                         talloc_free(req);
     180           0 :                         return NULL;
     181             :                 }
     182             :         }
     183             : 
     184      613418 :         if (io->in.sec_desc) {
     185             :                 enum ndr_err_code ndr_err;
     186             :                 DATA_BLOB sd_blob;
     187         105 :                 ndr_err = ndr_push_struct_blob(&sd_blob, req, io->in.sec_desc,
     188             :                                                (ndr_push_flags_fn_t)ndr_push_security_descriptor);
     189         105 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     190           0 :                         talloc_free(req);
     191           0 :                         return NULL;
     192             :                 }
     193         105 :                 status = smb2_create_blob_add(req, &blobs,
     194             :                                               SMB2_CREATE_TAG_SECD, sd_blob);
     195         105 :                 if (!NT_STATUS_IS_OK(status)) {
     196           0 :                         talloc_free(req);
     197           0 :                         return NULL;
     198             :                 }
     199             :         }
     200             : 
     201      613418 :         if (io->in.query_on_disk_id) {
     202          50 :                 status = smb2_create_blob_add(req, &blobs,
     203             :                                               SMB2_CREATE_TAG_QFID, data_blob(NULL, 0));
     204          50 :                 if (!NT_STATUS_IS_OK(status)) {
     205           0 :                         talloc_free(req);
     206           0 :                         return NULL;
     207             :                 }
     208             :         }
     209             : 
     210      613418 :         if (io->in.lease_request) {
     211             :                 uint8_t data[32];
     212             : 
     213         936 :                 if (!smb2_lease_push(io->in.lease_request, data,
     214             :                                      sizeof(data))) {
     215           0 :                         TALLOC_FREE(req);
     216           0 :                         return NULL;
     217             :                 }
     218             : 
     219         936 :                 status = smb2_create_blob_add(
     220             :                         req, &blobs, SMB2_CREATE_TAG_RQLS,
     221             :                         data_blob_const(data, sizeof(data)));
     222         936 :                 if (!NT_STATUS_IS_OK(status)) {
     223           0 :                         talloc_free(req);
     224           0 :                         return NULL;
     225             :                 }
     226             :         }
     227             : 
     228      613418 :         if (io->in.lease_request_v2) {
     229             :                 uint8_t data[52];
     230             : 
     231         188 :                 if (!smb2_lease_push(io->in.lease_request_v2, data,
     232             :                                      sizeof(data))) {
     233           0 :                         TALLOC_FREE(req);
     234           0 :                         return NULL;
     235             :                 }
     236             : 
     237         188 :                 status = smb2_create_blob_add(
     238             :                         req, &blobs, SMB2_CREATE_TAG_RQLS,
     239             :                         data_blob_const(data, sizeof(data)));
     240         188 :                 if (!NT_STATUS_IS_OK(status)) {
     241           0 :                         talloc_free(req);
     242           0 :                         return NULL;
     243             :                 }
     244             :         }
     245             : 
     246      613418 :         if (io->in.app_instance_id) {
     247             :                 uint8_t data[20];
     248           8 :                 struct GUID_ndr_buf guid_buf = { .buf = {0}, };
     249             : 
     250           8 :                 SSVAL(data, 0, 20); /* structure size */
     251           8 :                 SSVAL(data, 2, 0);  /* reserved */
     252             : 
     253           8 :                 status = GUID_to_ndr_buf(io->in.app_instance_id, &guid_buf);
     254           8 :                 if (!NT_STATUS_IS_OK(status)) {
     255           0 :                         talloc_free(req);
     256           0 :                         return NULL;
     257             :                 }
     258           8 :                 memcpy(data+4, guid_buf.buf, sizeof(guid_buf.buf));
     259             : 
     260           8 :                 status = smb2_create_blob_add(req, &blobs,
     261             :                                               SMB2_CREATE_TAG_APP_INSTANCE_ID,
     262             :                                               data_blob_const(data, 20));
     263           8 :                 if (!NT_STATUS_IS_OK(status)) {
     264           0 :                         talloc_free(req);
     265           0 :                         return NULL;
     266             :                 }
     267             :         }
     268             : 
     269             :         /* and any custom blobs */
     270      613551 :         for (i=0;i<io->in.blobs.num_blobs;i++) {
     271         133 :                 status = smb2_create_blob_add(req, &blobs,
     272         133 :                                               io->in.blobs.blobs[i].tag, 
     273         133 :                                               io->in.blobs.blobs[i].data);
     274         133 :                 if (!NT_STATUS_IS_OK(status)) {
     275           0 :                         talloc_free(req);
     276           0 :                         return NULL;
     277             :                 }
     278             :         }
     279             : 
     280             : 
     281      613418 :         status = smb2_create_blob_push(req, &blob, blobs);
     282      613418 :         if (!NT_STATUS_IS_OK(status)) {
     283           0 :                 talloc_free(req);
     284           0 :                 return NULL;
     285             :         }
     286             : 
     287      613418 :         status = smb2_push_o32s32_blob(&req->out, 0x30, blob);
     288      613418 :         if (!NT_STATUS_IS_OK(status)) {
     289           0 :                 talloc_free(req);
     290           0 :                 return NULL;
     291             :         }
     292             : 
     293      613624 :         if (((io->in.fname == NULL) || (strlen(io->in.fname) == 0)) &&
     294         246 :             (blob.length == 0)) {
     295         108 :                 struct smb2_request_buffer *buf = &req->out;
     296             : 
     297         108 :                 status = smb2_grow_buffer(buf, 1);
     298         108 :                 if (!NT_STATUS_IS_OK(status)) {
     299           0 :                         talloc_free(req);
     300           0 :                         return NULL;
     301             :                 }
     302         108 :                 buf->dynamic[0] = 0;
     303         108 :                 buf->dynamic += 1;
     304         108 :                 buf->body_size += 1;
     305         108 :                 buf->size += 1;
     306             :         }
     307             : 
     308      613418 :         data_blob_free(&blob);
     309             : 
     310      613418 :         smb2_transport_send(req);
     311             : 
     312      613418 :         return req;
     313             : }
     314             : 
     315             : 
     316             : /*
     317             :   recv a create reply
     318             : */
     319      613358 : NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io)
     320             : {
     321             :         NTSTATUS status;
     322             :         DATA_BLOB blob;
     323             :         int i;
     324             : 
     325     1160792 :         if (!smb2_request_receive(req) || 
     326      613334 :             !smb2_request_is_ok(req)) {
     327      165791 :                 return smb2_request_destroy(req);
     328             :         }
     329             : 
     330      447567 :         SMB2_CHECK_PACKET_RECV(req, 0x58, true);
     331      447567 :         ZERO_STRUCT(io->out);
     332      447567 :         io->out.oplock_level   = CVAL(req->in.body, 0x02);
     333      447567 :         io->out.reserved       = CVAL(req->in.body, 0x03);
     334      447567 :         io->out.create_action  = IVAL(req->in.body, 0x04);
     335      447567 :         io->out.create_time    = smbcli_pull_nttime(req->in.body, 0x08);
     336      447567 :         io->out.access_time    = smbcli_pull_nttime(req->in.body, 0x10);
     337      447567 :         io->out.write_time     = smbcli_pull_nttime(req->in.body, 0x18);
     338      447567 :         io->out.change_time    = smbcli_pull_nttime(req->in.body, 0x20);
     339      447567 :         io->out.alloc_size     = BVAL(req->in.body, 0x28);
     340      447567 :         io->out.size           = BVAL(req->in.body, 0x30);
     341      447567 :         io->out.file_attr      = IVAL(req->in.body, 0x38);
     342      447567 :         io->out.reserved2      = IVAL(req->in.body, 0x3C);
     343      447567 :         smb2_pull_handle(req->in.body+0x40, &io->out.file.handle);
     344      447567 :         status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &blob);
     345      447567 :         if (!NT_STATUS_IS_OK(status)) {
     346           0 :                 smb2_request_destroy(req);
     347           0 :                 return status;
     348             :         }
     349             : 
     350      447567 :         status = smb2_create_blob_parse(mem_ctx, blob, &io->out.blobs);
     351      447567 :         if (!NT_STATUS_IS_OK(status)) {
     352           0 :                 smb2_request_destroy(req);
     353           0 :                 return status;
     354             :         }
     355             : 
     356             :         /* pull out the parsed blobs */
     357      449353 :         for (i=0;i<io->out.blobs.num_blobs;i++) {
     358        1786 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) {
     359          40 :                         if (io->out.blobs.blobs[i].data.length != 8) {
     360           0 :                                 smb2_request_destroy(req);
     361           0 :                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     362             :                         }
     363          40 :                         io->out.maximal_access_status =
     364          40 :                                 IVAL(io->out.blobs.blobs[i].data.data, 0);
     365          40 :                         io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 4);
     366             :                 }
     367        1786 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) {
     368          46 :                         if (io->out.blobs.blobs[i].data.length != 32) {
     369           0 :                                 smb2_request_destroy(req);
     370           0 :                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     371             :                         }
     372          46 :                         memcpy(io->out.on_disk_id, io->out.blobs.blobs[i].data.data, 32);
     373             :                 }
     374        1786 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_RQLS) == 0) {
     375         992 :                         struct smb2_lease *ls = NULL;
     376             :                         uint8_t *data;
     377             : 
     378         992 :                         ZERO_STRUCT(io->out.lease_response);
     379         992 :                         ZERO_STRUCT(io->out.lease_response_v2);
     380             : 
     381         992 :                         switch (io->out.blobs.blobs[i].data.length) {
     382         868 :                         case 32:
     383         868 :                                 ls = &io->out.lease_response;
     384         868 :                                 ls->lease_version = 1;
     385         868 :                                 break;
     386         124 :                         case 52:
     387         124 :                                 ls = &io->out.lease_response_v2;
     388         124 :                                 ls->lease_version = 2;
     389         124 :                                 break;
     390           0 :                         default:
     391           0 :                                 smb2_request_destroy(req);
     392           0 :                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     393             :                         }
     394             : 
     395         992 :                         data = io->out.blobs.blobs[i].data.data;
     396         992 :                         memcpy(&ls->lease_key, data, 16);
     397         992 :                         ls->lease_state = IVAL(data, 16);
     398         992 :                         ls->lease_flags = IVAL(data, 20);
     399         992 :                         ls->lease_duration = BVAL(data, 24);
     400             : 
     401         992 :                         if (io->out.blobs.blobs[i].data.length == 52) {
     402         124 :                                 memcpy(&ls->parent_lease_key, data+32, 16);
     403         124 :                                 ls->lease_epoch = SVAL(data, 48);
     404             :                         }
     405             :                 }
     406        1786 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNQ) == 0) {
     407         152 :                         if (io->out.blobs.blobs[i].data.length != 8) {
     408           0 :                                 smb2_request_destroy(req);
     409           0 :                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     410             :                         }
     411         152 :                         io->out.durable_open = true;
     412             :                 }
     413        1786 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_DH2Q) == 0) {
     414             :                         uint32_t flags;
     415             :                         uint8_t *data;
     416             : 
     417         436 :                         if (io->out.blobs.blobs[i].data.length != 8) {
     418           0 :                                 smb2_request_destroy(req);
     419           0 :                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     420             :                         }
     421             : 
     422         436 :                         io->out.durable_open = false;
     423         436 :                         io->out.durable_open_v2 = true;
     424             : 
     425         436 :                         data = io->out.blobs.blobs[i].data.data;
     426         436 :                         io->out.timeout = IVAL(data, 0);
     427         436 :                         flags = IVAL(data, 4);
     428         436 :                         if ((flags & SMB2_DHANDLE_FLAG_PERSISTENT) != 0) {
     429           0 :                                 io->out.persistent_open = true;
     430             :                         }
     431             :                 }
     432             :         }
     433             : 
     434      447567 :         data_blob_free(&blob);
     435             : 
     436      447567 :         return smb2_request_destroy(req);
     437             : }
     438             : 
     439             : /*
     440             :   sync create request
     441             : */
     442      238091 : NTSTATUS smb2_create(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, struct smb2_create *io)
     443             : {
     444      238091 :         struct smb2_request *req = smb2_create_send(tree, io);
     445      238091 :         return smb2_create_recv(req, mem_ctx, io);
     446             : }

Generated by: LCOV version 1.13