LCOV - code coverage report
Current view: top level - libcli/smb - smb2cli_ioctl.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 136 232 58.6 %
Date: 2024-04-21 15:09:00 Functions: 4 8 50.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    smb2 lib
       4             :    Copyright (C) Stefan Metzmacher 2011
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/network.h"
      22             : #include "lib/util/tevent_ntstatus.h"
      23             : #include "smb_common.h"
      24             : #include "smbXcli_base.h"
      25             : #include "librpc/gen_ndr/ndr_ioctl.h"
      26             : 
      27             : struct smb2cli_ioctl_state {
      28             :         uint8_t fixed[0x38];
      29             :         uint8_t dyn_pad[1];
      30             :         uint32_t max_input_length;
      31             :         uint32_t max_output_length;
      32             :         struct iovec *recv_iov;
      33             :         bool out_valid;
      34             :         DATA_BLOB out_input_buffer;
      35             :         DATA_BLOB out_output_buffer;
      36             :         uint32_t ctl_code;
      37             : };
      38             : 
      39             : static void smb2cli_ioctl_done(struct tevent_req *subreq);
      40             : 
      41      380469 : struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx,
      42             :                                       struct tevent_context *ev,
      43             :                                       struct smbXcli_conn *conn,
      44             :                                       uint32_t timeout_msec,
      45             :                                       struct smbXcli_session *session,
      46             :                                       struct smbXcli_tcon *tcon,
      47             :                                       uint64_t in_fid_persistent,
      48             :                                       uint64_t in_fid_volatile,
      49             :                                       uint32_t in_ctl_code,
      50             :                                       uint32_t in_max_input_length,
      51             :                                       const DATA_BLOB *in_input_buffer,
      52             :                                       uint32_t in_max_output_length,
      53             :                                       const DATA_BLOB *in_output_buffer,
      54             :                                       uint32_t in_flags)
      55             : {
      56        7044 :         struct tevent_req *req, *subreq;
      57        7044 :         struct smb2cli_ioctl_state *state;
      58        7044 :         uint8_t *fixed;
      59        7044 :         uint8_t *dyn;
      60        7044 :         size_t dyn_len;
      61      380469 :         uint32_t input_buffer_offset = 0;
      62      380469 :         uint32_t input_buffer_length = 0;
      63      380469 :         uint32_t output_buffer_offset = 0;
      64      380469 :         uint32_t output_buffer_length = 0;
      65      380469 :         uint32_t pad_length = 0;
      66        7044 :         uint64_t tmp64;
      67      380469 :         uint32_t max_dyn_len = 0;
      68             : 
      69      380469 :         req = tevent_req_create(mem_ctx, &state,
      70             :                                 struct smb2cli_ioctl_state);
      71      380469 :         if (req == NULL) {
      72           0 :                 return NULL;
      73             :         }
      74      380469 :         state->ctl_code = in_ctl_code;
      75      380469 :         state->max_input_length = in_max_input_length;
      76      380469 :         state->max_output_length = in_max_output_length;
      77             : 
      78      380469 :         tmp64 = in_max_input_length;
      79      380469 :         tmp64 += in_max_output_length;
      80      380469 :         if (tmp64 > UINT32_MAX) {
      81           0 :                 max_dyn_len = UINT32_MAX;
      82             :         } else {
      83      380469 :                 max_dyn_len = tmp64;
      84             :         }
      85             : 
      86      380469 :         if (in_input_buffer) {
      87      378759 :                 input_buffer_offset = SMB2_HDR_BODY+0x38;
      88      378759 :                 input_buffer_length = in_input_buffer->length;
      89             :         }
      90             : 
      91      380469 :         if (in_output_buffer) {
      92      378745 :                 output_buffer_offset = SMB2_HDR_BODY+0x38;
      93      378745 :                 output_buffer_length = in_output_buffer->length;
      94      378745 :                 if (input_buffer_length > 0 && output_buffer_length > 0) {
      95           0 :                         uint32_t tmp;
      96           0 :                         output_buffer_offset += input_buffer_length;
      97           0 :                         tmp = output_buffer_offset;
      98           0 :                         output_buffer_offset = NDR_ROUND(output_buffer_offset, 8);
      99           0 :                         pad_length = output_buffer_offset - tmp;
     100             :                 }
     101             :         }
     102             : 
     103      380469 :         fixed = state->fixed;
     104             : 
     105      380469 :         SSVAL(fixed, 0x00, 0x39);
     106      380469 :         SSVAL(fixed, 0x02, 0); /* reserved */
     107      380469 :         SIVAL(fixed, 0x04, in_ctl_code);
     108      380469 :         SBVAL(fixed, 0x08, in_fid_persistent);
     109      380469 :         SBVAL(fixed, 0x10, in_fid_volatile);
     110      380469 :         SIVAL(fixed, 0x18, input_buffer_offset);
     111      380469 :         SIVAL(fixed, 0x1C, input_buffer_length);
     112      380469 :         SIVAL(fixed, 0x20, in_max_input_length);
     113      380469 :         SIVAL(fixed, 0x24, output_buffer_offset);
     114      380469 :         SIVAL(fixed, 0x28, output_buffer_length);
     115      380469 :         SIVAL(fixed, 0x2C, in_max_output_length);
     116      380469 :         SIVAL(fixed, 0x30, in_flags);
     117      380469 :         SIVAL(fixed, 0x34, 0); /* reserved */
     118             : 
     119      380469 :         if (input_buffer_length > 0 && output_buffer_length > 0) {
     120           0 :                 size_t avail = UINT32_MAX - (input_buffer_length + pad_length);
     121           0 :                 size_t ofs = output_buffer_offset - input_buffer_offset;
     122             : 
     123           0 :                 if (avail < output_buffer_length) {
     124           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
     125           0 :                         return tevent_req_post(req, ev);
     126             :                 }
     127             : 
     128           0 :                 dyn_len = input_buffer_length + output_buffer_length + pad_length;
     129             : 
     130           0 :                 dyn = talloc_zero_array(state, uint8_t, dyn_len);
     131           0 :                 if (tevent_req_nomem(dyn, req)) {
     132           0 :                         return tevent_req_post(req, ev);
     133             :                 }
     134           0 :                 memcpy(dyn, in_input_buffer->data,
     135           0 :                        in_input_buffer->length);
     136        7044 :                 memcpy(dyn + ofs, in_output_buffer->data,
     137           0 :                        in_output_buffer->length);
     138      380469 :         } else if (input_buffer_length > 0) {
     139      378366 :                 dyn = in_input_buffer->data;
     140      378366 :                 dyn_len = in_input_buffer->length;
     141        2103 :         } else if (output_buffer_length > 0) {
     142           0 :                 dyn = in_output_buffer->data;
     143           0 :                 dyn_len = in_output_buffer->length;
     144             :         } else {
     145        2103 :                 dyn = state->dyn_pad;
     146        2103 :                 dyn_len = sizeof(state->dyn_pad);
     147             :         }
     148             : 
     149      387513 :         subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_IOCTL,
     150             :                                   0, 0, /* flags */
     151             :                                   timeout_msec,
     152             :                                   tcon,
     153             :                                   session,
     154      380469 :                                   state->fixed, sizeof(state->fixed),
     155             :                                   dyn, dyn_len,
     156             :                                   max_dyn_len);
     157      380469 :         if (tevent_req_nomem(subreq, req)) {
     158           0 :                 return tevent_req_post(req, ev);
     159             :         }
     160      380469 :         tevent_req_set_callback(subreq, smb2cli_ioctl_done, req);
     161      380469 :         return req;
     162             : }
     163             : 
     164      380469 : static void smb2cli_ioctl_done(struct tevent_req *subreq)
     165             : {
     166        7044 :         struct tevent_req *req =
     167      380469 :                 tevent_req_callback_data(subreq,
     168             :                 struct tevent_req);
     169        7044 :         struct smb2cli_ioctl_state *state =
     170      380469 :                 tevent_req_data(req,
     171             :                 struct smb2cli_ioctl_state);
     172        7044 :         NTSTATUS status;
     173        7044 :         NTSTATUS error;
     174        7044 :         struct iovec *iov;
     175        7044 :         uint8_t *fixed;
     176      380469 :         DATA_BLOB dyn_buffer = data_blob_null;
     177      380469 :         uint32_t dyn_ofs = SMB2_HDR_BODY + 0x30;
     178        7044 :         uint32_t input_min_offset;
     179        7044 :         uint32_t input_buffer_offset;
     180        7044 :         uint32_t input_buffer_length;
     181        7044 :         uint32_t input_next_offset;
     182        7044 :         uint32_t output_min_offset;
     183        7044 :         uint32_t output_buffer_offset;
     184        7044 :         uint32_t output_buffer_length;
     185        7044 :         uint32_t output_next_offset;
     186        7044 :         static const struct smb2cli_req_expected_response expected[] = {
     187             :         {
     188             :                 .status = NT_STATUS_OK,
     189             :                 .body_size = 0x31
     190             :         },
     191             :         {
     192             :                 .status = STATUS_BUFFER_OVERFLOW,
     193             :                 .body_size = 0x31
     194             :         },
     195             :         {
     196             :                 /*
     197             :                  * We need to make sure that
     198             :                  * a response with NT_STATUS_FILE_CLOSED
     199             :                  * without signing generates NT_STATUS_ACCESS_DENIED
     200             :                  * if the request was signed.
     201             :                  */
     202             :                 .status = NT_STATUS_FILE_CLOSED,
     203             :                 .body_size = 0x09,
     204             :         },
     205             :         {
     206             :                 /*
     207             :                  * a normal error
     208             :                  */
     209             :                 .status = NT_STATUS_INVALID_PARAMETER,
     210             :                 .body_size = 0x09
     211             :         },
     212             :         {
     213             :                 /*
     214             :                  * a special case for FSCTL_SRV_COPYCHUNK_*
     215             :                  */
     216             :                 .status = NT_STATUS_INVALID_PARAMETER,
     217             :                 .body_size = 0x31
     218             :         },
     219             :         };
     220             : 
     221      380469 :         status = smb2cli_req_recv(subreq, state, &iov,
     222             :                                   expected, ARRAY_SIZE(expected));
     223      380469 :         TALLOC_FREE(subreq);
     224      380469 :         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
     225          28 :                 switch (state->ctl_code) {
     226           0 :                 case FSCTL_SRV_COPYCHUNK:
     227             :                 case FSCTL_SRV_COPYCHUNK_WRITE:
     228           0 :                         break;
     229          28 :                 default:
     230          28 :                         tevent_req_nterror(req, status);
     231        8173 :                         return;
     232             :                 }
     233             : 
     234           0 :                 if (iov[1].iov_len != 0x30) {
     235           0 :                         tevent_req_nterror(req,
     236             :                                         NT_STATUS_INVALID_NETWORK_RESPONSE);
     237           0 :                         return;
     238             :                 }
     239      380441 :         } else if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
     240             :                 /* no error */
     241             :         } else {
     242      380441 :                 if (tevent_req_nterror(req, status)) {
     243        8145 :                         return;
     244             :                 }
     245             :         }
     246             : 
     247             :         /*
     248             :          * At this stage we're sure that got a body size of 0x31,
     249             :          * either with NT_STATUS_OK, STATUS_BUFFER_OVERFLOW or
     250             :          * NT_STATUS_INVALID_PARAMETER.
     251             :          */
     252             : 
     253      372293 :         state->recv_iov = iov;
     254      372293 :         fixed = (uint8_t *)iov[1].iov_base;
     255      372293 :         dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
     256      365252 :                                      iov[2].iov_len);
     257             : 
     258      372293 :         input_buffer_offset = IVAL(fixed, 0x18);
     259      372293 :         input_buffer_length = IVAL(fixed, 0x1C);
     260      372293 :         output_buffer_offset = IVAL(fixed, 0x20);
     261      372293 :         output_buffer_length = IVAL(fixed, 0x24);
     262             : 
     263      372293 :         input_min_offset = dyn_ofs;
     264      372293 :         input_next_offset = dyn_ofs;
     265      372293 :         error = smb2cli_parse_dyn_buffer(dyn_ofs,
     266             :                                          dyn_buffer,
     267             :                                          input_min_offset,
     268             :                                          input_buffer_offset,
     269             :                                          input_buffer_length,
     270             :                                          state->max_input_length,
     271             :                                          &input_next_offset,
     272             :                                          &state->out_input_buffer);
     273      372293 :         if (tevent_req_nterror(req, error)) {
     274           0 :                 return;
     275             :         }
     276             : 
     277             :         /*
     278             :          * If output data is returned, the output offset MUST be set to
     279             :          * InputOffset + InputCount rounded up to a multiple of 8.
     280             :          */
     281      372293 :         output_min_offset = NDR_ROUND(input_next_offset, 8);
     282      372293 :         output_next_offset = 0; /* this variable is completely ignored */
     283      372293 :         error = smb2cli_parse_dyn_buffer(dyn_ofs,
     284             :                                          dyn_buffer,
     285             :                                          output_min_offset,
     286             :                                          output_buffer_offset,
     287             :                                          output_buffer_length,
     288             :                                          state->max_output_length,
     289             :                                          &output_next_offset,
     290             :                                          &state->out_output_buffer);
     291      372293 :         if (tevent_req_nterror(req, error)) {
     292           0 :                 return;
     293             :         }
     294             : 
     295      372293 :         state->out_valid = true;
     296             : 
     297      372293 :         if (tevent_req_nterror(req, status)) {
     298           0 :                 return;
     299             :         }
     300             : 
     301      372293 :         tevent_req_done(req);
     302             : }
     303             : 
     304      380469 : NTSTATUS smb2cli_ioctl_recv(struct tevent_req *req,
     305             :                             TALLOC_CTX *mem_ctx,
     306             :                             DATA_BLOB *out_input_buffer,
     307             :                             DATA_BLOB *out_output_buffer)
     308             : {
     309        7044 :         struct smb2cli_ioctl_state *state =
     310      380469 :                 tevent_req_data(req,
     311             :                 struct smb2cli_ioctl_state);
     312      380469 :         NTSTATUS status = NT_STATUS_OK;
     313             : 
     314      380469 :         if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
     315        8176 :                 if (out_input_buffer) {
     316        8162 :                         *out_input_buffer = data_blob_null;
     317             :                 }
     318        8176 :                 if (out_output_buffer) {
     319        8176 :                         *out_output_buffer = data_blob_null;
     320             :                 }
     321        8176 :                 tevent_req_received(req);
     322        8176 :                 return status;
     323             :         }
     324             : 
     325      372293 :         talloc_steal(mem_ctx, state->recv_iov);
     326      372293 :         if (out_input_buffer) {
     327      372293 :                 *out_input_buffer = state->out_input_buffer;
     328             :         }
     329      372293 :         if (out_output_buffer) {
     330      372293 :                 *out_output_buffer = state->out_output_buffer;
     331             :         }
     332             : 
     333      372293 :         tevent_req_received(req);
     334      372293 :         return status;
     335             : }
     336             : 
     337       11113 : NTSTATUS smb2cli_ioctl(struct smbXcli_conn *conn,
     338             :                        uint32_t timeout_msec,
     339             :                        struct smbXcli_session *session,
     340             :                        struct smbXcli_tcon *tcon,
     341             :                        uint64_t in_fid_persistent,
     342             :                        uint64_t in_fid_volatile,
     343             :                        uint32_t in_ctl_code,
     344             :                        uint32_t in_max_input_length,
     345             :                        const DATA_BLOB *in_input_buffer,
     346             :                        uint32_t in_max_output_length,
     347             :                        const DATA_BLOB *in_output_buffer,
     348             :                        uint32_t in_flags,
     349             :                        TALLOC_CTX *mem_ctx,
     350             :                        DATA_BLOB *out_input_buffer,
     351             :                        DATA_BLOB *out_output_buffer)
     352             : {
     353       11113 :         TALLOC_CTX *frame = talloc_stackframe();
     354           0 :         struct tevent_context *ev;
     355           0 :         struct tevent_req *req;
     356       11113 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     357             : 
     358       11113 :         if (smbXcli_conn_has_async_calls(conn)) {
     359             :                 /*
     360             :                  * Can't use sync call while an async call is in flight
     361             :                  */
     362           0 :                 status = NT_STATUS_INVALID_PARAMETER_MIX;
     363           0 :                 goto fail;
     364             :         }
     365       11113 :         ev = samba_tevent_context_init(frame);
     366       11113 :         if (ev == NULL) {
     367           0 :                 goto fail;
     368             :         }
     369       11113 :         req = smb2cli_ioctl_send(frame, ev, conn, timeout_msec,
     370             :                                  session, tcon,
     371             :                                  in_fid_persistent,
     372             :                                  in_fid_volatile,
     373             :                                  in_ctl_code,
     374             :                                  in_max_input_length,
     375             :                                  in_input_buffer,
     376             :                                  in_max_output_length,
     377             :                                  in_output_buffer,
     378             :                                  in_flags);
     379       11113 :         if (req == NULL) {
     380           0 :                 goto fail;
     381             :         }
     382       11113 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     383           0 :                 goto fail;
     384             :         }
     385       11113 :         status = smb2cli_ioctl_recv(req, mem_ctx,
     386             :                                     out_input_buffer,
     387             :                                     out_output_buffer);
     388       11113 :  fail:
     389       11113 :         TALLOC_FREE(frame);
     390       11113 :         return status;
     391             : }
     392             : 
     393             : struct smb2cli_ioctl_pipe_wait_state {
     394             :         DATA_BLOB in_blob;
     395             :         DATA_BLOB out_blob;
     396             : };
     397             : 
     398             : static void smb2cli_ioctl_pipe_wait_done(struct tevent_req *subreq);
     399             : 
     400           0 : struct tevent_req *smb2cli_ioctl_pipe_wait_send(TALLOC_CTX *mem_ctx,
     401             :                                                 struct tevent_context *ev,
     402             :                                                 struct smbXcli_conn *conn,
     403             :                                                 uint32_t timeout_msec,
     404             :                                                 struct smbXcli_session *session,
     405             :                                                 struct smbXcli_tcon *tcon,
     406             :                                                 const char *pipe_name,
     407             :                                                 uint64_t pipe_wait_timeout)
     408             : {
     409           0 :         struct tevent_req *req = NULL;
     410           0 :         struct tevent_req *subreq = NULL;
     411           0 :         struct smb2cli_ioctl_pipe_wait_state *state = NULL;
     412           0 :         struct fsctl_pipe_wait fsctl = {0};
     413           0 :         enum ndr_err_code err;
     414             : 
     415           0 :         req = tevent_req_create(mem_ctx, &state,
     416             :                                 struct smb2cli_ioctl_pipe_wait_state);
     417           0 :         if (req == NULL) {
     418           0 :                 return NULL;
     419             :         }
     420             : 
     421           0 :         state->out_blob = data_blob_string_const("");
     422             : 
     423           0 :         fsctl.pipe_name = pipe_name;
     424           0 :         fsctl.timeout = pipe_wait_timeout;
     425           0 :         fsctl.timeout_specified = pipe_wait_timeout > 0 ? 1 : 0;
     426             : 
     427           0 :         err = ndr_push_struct_blob(&state->in_blob, mem_ctx, &fsctl,
     428             :                                    (ndr_push_flags_fn_t)ndr_push_fsctl_pipe_wait);
     429           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
     430           0 :                 return NULL;
     431             :         }
     432             : 
     433           0 :         subreq = smb2cli_ioctl_send(mem_ctx, ev, conn, timeout_msec,
     434             :                                     session, tcon,
     435             :                                     UINT64_MAX, UINT64_MAX,
     436             :                                     FSCTL_PIPE_WAIT,
     437           0 :                                     0, &state->in_blob,
     438           0 :                                     0, &state->out_blob,
     439             :                                     SMB2_IOCTL_FLAG_IS_FSCTL);
     440           0 :         if (tevent_req_nomem(subreq, req)) {
     441           0 :                 return tevent_req_post(subreq, ev);
     442             :         }
     443           0 :         tevent_req_set_callback(subreq, smb2cli_ioctl_pipe_wait_done, req);
     444             : 
     445           0 :         return req;
     446             : }
     447             : 
     448           0 : static void smb2cli_ioctl_pipe_wait_done(struct tevent_req *subreq)
     449             : {
     450           0 :         struct tevent_req *req = tevent_req_callback_data(
     451             :                 subreq, struct tevent_req);
     452           0 :         struct smb2cli_ioctl_pipe_wait_state *state = tevent_req_data(
     453             :                 req, struct smb2cli_ioctl_pipe_wait_state);
     454           0 :         NTSTATUS status;
     455             : 
     456           0 :         status = smb2cli_ioctl_recv(subreq, state, NULL, NULL);
     457           0 :         TALLOC_FREE(subreq);
     458           0 :         if (tevent_req_nterror(req, status)) {
     459           0 :                 return;
     460             :         }
     461             : 
     462           0 :         tevent_req_done(req);
     463             : }
     464             : 
     465             : 
     466           0 : NTSTATUS smb2cli_ioctl_pipe_wait_recv(struct tevent_req *req)
     467             : {
     468           0 :         NTSTATUS status;
     469             : 
     470           0 :         if (tevent_req_is_nterror(req, &status)) {
     471           0 :                 tevent_req_received(req);
     472           0 :                 return status;
     473             :         }
     474             : 
     475           0 :         tevent_req_received(req);
     476           0 :         return NT_STATUS_OK;
     477             : }
     478             : 
     479           0 : NTSTATUS smb2cli_ioctl_pipe_wait(struct smbXcli_conn *conn,
     480             :                                  uint32_t timeout_msec,
     481             :                                  struct smbXcli_session *session,
     482             :                                  struct smbXcli_tcon *tcon,
     483             :                                  const char *pipe_name,
     484             :                                  uint64_t pipe_wait_timeout)
     485             : {
     486           0 :         TALLOC_CTX *frame = talloc_stackframe();
     487           0 :         struct tevent_context *ev = NULL;
     488           0 :         struct tevent_req *req = NULL;
     489           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     490             : 
     491           0 :         if (smbXcli_conn_has_async_calls(conn)) {
     492             :                 /*
     493             :                  * Can't use sync call while an async call is in flight
     494             :                  */
     495           0 :                 status = NT_STATUS_INVALID_PARAMETER_MIX;
     496           0 :                 goto fail;
     497             :         }
     498             : 
     499           0 :         ev = samba_tevent_context_init(frame);
     500           0 :         if (ev == NULL) {
     501           0 :                 goto fail;
     502             :         }
     503             : 
     504           0 :         req = smb2cli_ioctl_pipe_wait_send(frame, ev, conn, timeout_msec,
     505             :                                            session, tcon,
     506             :                                            pipe_name, pipe_wait_timeout);
     507           0 :         if (req == NULL) {
     508           0 :                 goto fail;
     509             :         }
     510           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     511           0 :                 goto fail;
     512             :         }
     513             : 
     514           0 :         status = smb2cli_ioctl_pipe_wait_recv(req);
     515             : 
     516           0 : fail:
     517           0 :         TALLOC_FREE(frame);
     518           0 :         return status;
     519             : }

Generated by: LCOV version 1.14