LCOV - code coverage report
Current view: top level - source4/libcli/smb2 - create.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 186 264 70.5 %
Date: 2024-02-28 12: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      640204 : struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create *io)
      33             : {
      34         363 :         struct smb2_request *req;
      35         363 :         NTSTATUS status;
      36         363 :         DATA_BLOB blob;
      37         363 :         struct smb2_create_blobs blobs;
      38         363 :         int i;
      39             : 
      40      640204 :         ZERO_STRUCT(blobs);
      41             : 
      42      640204 :         req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, true, 0);
      43      640204 :         if (req == NULL) return NULL;
      44             : 
      45      640204 :         SCVAL(req->out.body, 0x02, io->in.security_flags);
      46      640204 :         SCVAL(req->out.body, 0x03, io->in.oplock_level);
      47      640204 :         SIVAL(req->out.body, 0x04, io->in.impersonation_level);
      48      640204 :         SBVAL(req->out.body, 0x08, io->in.create_flags);
      49      640204 :         SBVAL(req->out.body, 0x10, io->in.reserved);
      50      640204 :         SIVAL(req->out.body, 0x18, io->in.desired_access);
      51      640204 :         SIVAL(req->out.body, 0x1C, io->in.file_attributes);
      52      640204 :         SIVAL(req->out.body, 0x20, io->in.share_access);
      53      640204 :         SIVAL(req->out.body, 0x24, io->in.create_disposition);
      54      640204 :         SIVAL(req->out.body, 0x28, io->in.create_options);
      55             : 
      56      640204 :         status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname);
      57      640204 :         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      640204 :         if (io->in.eas.num_eas != 0) {
      64         231 :                 DATA_BLOB b = data_blob_talloc(req, NULL, 
      65             :                                                ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas, 4));
      66         231 :                 ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas, 4);
      67         231 :                 status = smb2_create_blob_add(req, &blobs,
      68             :                                               SMB2_CREATE_TAG_EXTA, b);
      69         231 :                 if (!NT_STATUS_IS_OK(status)) {
      70           0 :                         talloc_free(req);
      71           0 :                         return NULL;
      72             :                 }
      73         231 :                 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      640204 :         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      640204 :         if (io->in.alloc_size != 0) {
      90           0 :                 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      640204 :         if (io->in.durable_open) {
     101         338 :                 status = smb2_create_blob_add(req, &blobs,
     102             :                                               SMB2_CREATE_TAG_DHNQ, data_blob_talloc_zero(req, 16));
     103         338 :                 if (!NT_STATUS_IS_OK(status)) {
     104           0 :                         talloc_free(req);
     105           0 :                         return NULL;
     106             :                 }
     107             :         }
     108             : 
     109      640204 :         if (io->in.durable_open_v2) {
     110           0 :                 uint8_t data[32];
     111        1050 :                 uint32_t flags = 0;
     112        1050 :                 struct GUID_ndr_buf guid_buf = { .buf = {0}, };
     113             : 
     114        1050 :                 SIVAL(data, 0, io->in.timeout);
     115        1050 :                 if (io->in.persistent_open) {
     116         208 :                         flags = SMB2_DHANDLE_FLAG_PERSISTENT;
     117             :                 }
     118        1050 :                 SIVAL(data, 4, flags);
     119        1050 :                 SBVAL(data, 8, 0x0); /* reserved */
     120        1050 :                 status = GUID_to_ndr_buf(&io->in.create_guid, &guid_buf);
     121        1050 :                 if (!NT_STATUS_IS_OK(status)) {
     122           0 :                         talloc_free(req);
     123           0 :                         return NULL;
     124             :                 }
     125        1050 :                 memcpy(data+16, guid_buf.buf, sizeof(guid_buf.buf));
     126             : 
     127        1050 :                 status = smb2_create_blob_add(req, &blobs,
     128             :                                               SMB2_CREATE_TAG_DH2Q,
     129             :                                               data_blob_const(data, 32));
     130        1050 :                 if (!NT_STATUS_IS_OK(status)) {
     131           0 :                         talloc_free(req);
     132           0 :                         return NULL;
     133             :                 }
     134             :         }
     135             : 
     136      640204 :         if (io->in.durable_handle) {
     137           0 :                 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      640204 :         if (io->in.durable_handle_v2) {
     148           0 :                 uint8_t data[36];
     149         126 :                 struct GUID_ndr_buf guid_buf = { .buf = {0}, };
     150         126 :                 uint32_t flags = 0;
     151             : 
     152         126 :                 smb2_push_handle(data, io->in.durable_handle_v2);
     153         126 :                 status = GUID_to_ndr_buf(&io->in.create_guid, &guid_buf);
     154         126 :                 if (!NT_STATUS_IS_OK(status)) {
     155           0 :                         talloc_free(req);
     156           0 :                         return NULL;
     157             :                 }
     158         126 :                 memcpy(data+16, guid_buf.buf, sizeof(guid_buf.buf));
     159         126 :                 if (io->in.persistent_open) {
     160           0 :                         flags = SMB2_DHANDLE_FLAG_PERSISTENT;
     161             :                 }
     162         126 :                 SIVAL(data, 32, flags);
     163             : 
     164         126 :                 status = smb2_create_blob_add(req, &blobs,
     165             :                                               SMB2_CREATE_TAG_DH2C,
     166             :                                               data_blob_const(data, 36));
     167         126 :                 if (!NT_STATUS_IS_OK(status)) {
     168           0 :                         talloc_free(req);
     169           0 :                         return NULL;
     170             :                 }
     171             :         }
     172             : 
     173      640204 :         if (io->in.timewarp) {
     174           0 :                 uint8_t data[8];
     175          40 :                 SBVAL(data, 0, io->in.timewarp);             
     176          40 :                 status = smb2_create_blob_add(req, &blobs,
     177             :                                               SMB2_CREATE_TAG_TWRP, data_blob_const(data, 8));
     178          40 :                 if (!NT_STATUS_IS_OK(status)) {
     179           0 :                         talloc_free(req);
     180           0 :                         return NULL;
     181             :                 }
     182             :         }
     183             : 
     184      640204 :         if (io->in.sec_desc) {
     185           0 :                 enum ndr_err_code ndr_err;
     186           0 :                 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      640204 :         if (io->in.query_on_disk_id) {
     202          54 :                 status = smb2_create_blob_add(req, &blobs,
     203             :                                               SMB2_CREATE_TAG_QFID, data_blob(NULL, 0));
     204          54 :                 if (!NT_STATUS_IS_OK(status)) {
     205           0 :                         talloc_free(req);
     206           0 :                         return NULL;
     207             :                 }
     208             :         }
     209             : 
     210      640204 :         if (io->in.lease_request) {
     211           0 :                 uint8_t data[32];
     212             : 
     213         952 :                 if (!smb2_lease_push(io->in.lease_request, data,
     214             :                                      sizeof(data))) {
     215           0 :                         TALLOC_FREE(req);
     216           0 :                         return NULL;
     217             :                 }
     218             : 
     219         952 :                 status = smb2_create_blob_add(
     220             :                         req, &blobs, SMB2_CREATE_TAG_RQLS,
     221             :                         data_blob_const(data, sizeof(data)));
     222         952 :                 if (!NT_STATUS_IS_OK(status)) {
     223           0 :                         talloc_free(req);
     224           0 :                         return NULL;
     225             :                 }
     226             :         }
     227             : 
     228      640204 :         if (io->in.lease_request_v2) {
     229           0 :                 uint8_t data[52];
     230             : 
     231         196 :                 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         196 :                 status = smb2_create_blob_add(
     238             :                         req, &blobs, SMB2_CREATE_TAG_RQLS,
     239             :                         data_blob_const(data, sizeof(data)));
     240         196 :                 if (!NT_STATUS_IS_OK(status)) {
     241           0 :                         talloc_free(req);
     242           0 :                         return NULL;
     243             :                 }
     244             :         }
     245             : 
     246      640204 :         if (io->in.app_instance_id) {
     247           0 :                 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      640345 :         for (i=0;i<io->in.blobs.num_blobs;i++) {
     271         141 :                 status = smb2_create_blob_add(req, &blobs,
     272         141 :                                               io->in.blobs.blobs[i].tag, 
     273         141 :                                               io->in.blobs.blobs[i].data);
     274         141 :                 if (!NT_STATUS_IS_OK(status)) {
     275           0 :                         talloc_free(req);
     276           0 :                         return NULL;
     277             :                 }
     278             :         }
     279             : 
     280             : 
     281      640204 :         status = smb2_create_blob_push(req, &blob, blobs);
     282      640204 :         if (!NT_STATUS_IS_OK(status)) {
     283           0 :                 talloc_free(req);
     284           0 :                 return NULL;
     285             :         }
     286             : 
     287      640204 :         status = smb2_push_o32s32_blob(&req->out, 0x30, blob);
     288      640204 :         if (!NT_STATUS_IS_OK(status)) {
     289           0 :                 talloc_free(req);
     290           0 :                 return NULL;
     291             :         }
     292             : 
     293      640204 :         if (((io->in.fname == NULL) || (strlen(io->in.fname) == 0)) &&
     294       31424 :             (blob.length == 0)) {
     295       31278 :                 struct smb2_request_buffer *buf = &req->out;
     296             : 
     297       31278 :                 status = smb2_grow_buffer(buf, 1);
     298       31278 :                 if (!NT_STATUS_IS_OK(status)) {
     299           0 :                         talloc_free(req);
     300           0 :                         return NULL;
     301             :                 }
     302       31278 :                 buf->dynamic[0] = 0;
     303       31278 :                 buf->dynamic += 1;
     304       31278 :                 buf->body_size += 1;
     305       31278 :                 buf->size += 1;
     306             :         }
     307             : 
     308      640204 :         data_blob_free(&blob);
     309             : 
     310      640204 :         smb2_transport_send(req);
     311             : 
     312      640204 :         return req;
     313             : }
     314             : 
     315             : 
     316             : /*
     317             :   recv a create reply
     318             : */
     319      640131 : NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io)
     320             : {
     321         363 :         NTSTATUS status;
     322         363 :         DATA_BLOB blob;
     323         363 :         int i;
     324             : 
     325      640494 :         if (!smb2_request_receive(req) || 
     326      640107 :             !smb2_request_is_ok(req)) {
     327      169560 :                 return smb2_request_destroy(req);
     328             :         }
     329             : 
     330      470571 :         SMB2_CHECK_PACKET_RECV(req, 0x58, true);
     331      470571 :         ZERO_STRUCT(io->out);
     332      470571 :         io->out.oplock_level   = CVAL(req->in.body, 0x02);
     333      470571 :         io->out.reserved       = CVAL(req->in.body, 0x03);
     334      470571 :         io->out.create_action  = IVAL(req->in.body, 0x04);
     335      470571 :         io->out.create_time    = smbcli_pull_nttime(req->in.body, 0x08);
     336      470571 :         io->out.access_time    = smbcli_pull_nttime(req->in.body, 0x10);
     337      470571 :         io->out.write_time     = smbcli_pull_nttime(req->in.body, 0x18);
     338      470571 :         io->out.change_time    = smbcli_pull_nttime(req->in.body, 0x20);
     339      470571 :         io->out.alloc_size     = BVAL(req->in.body, 0x28);
     340      470571 :         io->out.size           = BVAL(req->in.body, 0x30);
     341      470571 :         io->out.file_attr      = IVAL(req->in.body, 0x38);
     342      470571 :         io->out.reserved2      = IVAL(req->in.body, 0x3C);
     343      470571 :         smb2_pull_handle(req->in.body+0x40, &io->out.file.handle);
     344      470571 :         status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &blob);
     345      470571 :         if (!NT_STATUS_IS_OK(status)) {
     346           0 :                 smb2_request_destroy(req);
     347           0 :                 return status;
     348             :         }
     349             : 
     350      470571 :         status = smb2_create_blob_parse(mem_ctx, blob, &io->out.blobs);
     351      470571 :         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      472386 :         for (i=0;i<io->out.blobs.num_blobs;i++) {
     358        1815 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) {
     359          35 :                         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          35 :                         io->out.maximal_access_status =
     364          35 :                                 IVAL(io->out.blobs.blobs[i].data.data, 0);
     365          35 :                         io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 4);
     366             :                 }
     367        1815 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) {
     368          50 :                         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          50 :                         memcpy(io->out.on_disk_id, io->out.blobs.blobs[i].data.data, 32);
     373             :                 }
     374        1815 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_RQLS) == 0) {
     375        1010 :                         struct smb2_lease *ls = NULL;
     376           0 :                         uint8_t *data;
     377             : 
     378        1010 :                         ZERO_STRUCT(io->out.lease_response);
     379        1010 :                         ZERO_STRUCT(io->out.lease_response_v2);
     380             : 
     381        1010 :                         switch (io->out.blobs.blobs[i].data.length) {
     382         878 :                         case 32:
     383         878 :                                 ls = &io->out.lease_response;
     384         878 :                                 ls->lease_version = 1;
     385         878 :                                 break;
     386         132 :                         case 52:
     387         132 :                                 ls = &io->out.lease_response_v2;
     388         132 :                                 ls->lease_version = 2;
     389         132 :                                 break;
     390           0 :                         default:
     391           0 :                                 smb2_request_destroy(req);
     392           0 :                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     393             :                         }
     394             : 
     395        1010 :                         data = io->out.blobs.blobs[i].data.data;
     396        1010 :                         memcpy(&ls->lease_key, data, 16);
     397        1010 :                         ls->lease_state = IVAL(data, 16);
     398        1010 :                         ls->lease_flags = IVAL(data, 20);
     399        1010 :                         ls->lease_duration = BVAL(data, 24);
     400             : 
     401        1010 :                         if (io->out.blobs.blobs[i].data.length == 52) {
     402         132 :                                 memcpy(&ls->parent_lease_key, data+32, 16);
     403         132 :                                 ls->lease_epoch = SVAL(data, 48);
     404             :                         }
     405             :                 }
     406        1815 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNQ) == 0) {
     407         154 :                         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         154 :                         io->out.durable_open = true;
     412             :                 }
     413        1815 :                 if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_DH2Q) == 0) {
     414           0 :                         uint32_t flags;
     415           0 :                         uint8_t *data;
     416             : 
     417         438 :                         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         438 :                         io->out.durable_open = false;
     423         438 :                         io->out.durable_open_v2 = true;
     424             : 
     425         438 :                         data = io->out.blobs.blobs[i].data.data;
     426         438 :                         io->out.timeout = IVAL(data, 0);
     427         438 :                         flags = IVAL(data, 4);
     428         438 :                         if ((flags & SMB2_DHANDLE_FLAG_PERSISTENT) != 0) {
     429           0 :                                 io->out.persistent_open = true;
     430             :                         }
     431             :                 }
     432             :         }
     433             : 
     434      470571 :         data_blob_free(&blob);
     435             : 
     436      470571 :         return smb2_request_destroy(req);
     437             : }
     438             : 
     439             : /*
     440             :   sync create request
     441             : */
     442      235044 : NTSTATUS smb2_create(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, struct smb2_create *io)
     443             : {
     444      235044 :         struct smb2_request *req = smb2_create_send(tree, io);
     445      235044 :         return smb2_create_recv(req, mem_ctx, io);
     446             : }

Generated by: LCOV version 1.14