LCOV - code coverage report
Current view: top level - librpc/rpc - binding_handle.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 162 225 72.0 %
Date: 2024-06-13 04:01:37 Functions: 15 18 83.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    dcerpc binding handle functions
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2010
       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 <tevent.h>
      24             : #include "../lib/util/tevent_ntstatus.h"
      25             : #include "librpc/rpc/dcerpc.h"
      26             : #include "rpc_common.h"
      27             : 
      28             : struct dcerpc_binding_handle {
      29             :         void *private_data;
      30             :         const struct dcerpc_binding_handle_ops *ops;
      31             :         const char *location;
      32             :         const struct GUID *object;
      33             :         const struct ndr_interface_table *table;
      34             :         struct tevent_context *sync_ev;
      35             : };
      36             : 
      37       23355 : static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
      38             : {
      39       23355 :         return 0;
      40             : }
      41             : 
      42       23947 : struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
      43             :                                         const struct dcerpc_binding_handle_ops *ops,
      44             :                                         const struct GUID *object,
      45             :                                         const struct ndr_interface_table *table,
      46             :                                         void *pstate,
      47             :                                         size_t psize,
      48             :                                         const char *type,
      49             :                                         const char *location)
      50             : {
      51             :         struct dcerpc_binding_handle *h;
      52       23947 :         void **ppstate = (void **)pstate;
      53             :         void *state;
      54             : 
      55       23947 :         h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
      56       23947 :         if (h == NULL) {
      57           0 :                 return NULL;
      58             :         }
      59       23947 :         h->ops               = ops;
      60       23947 :         h->location  = location;
      61       23947 :         h->object    = object;
      62       23947 :         h->table     = table;
      63             : 
      64       23947 :         state = talloc_zero_size(h, psize);
      65       23947 :         if (state == NULL) {
      66           0 :                 talloc_free(h);
      67           0 :                 return NULL;
      68             :         }
      69       23947 :         talloc_set_name_const(state, type);
      70             : 
      71       23947 :         h->private_data = state;
      72             : 
      73       23947 :         talloc_set_destructor(h, dcerpc_binding_handle_destructor);
      74             : 
      75       23947 :         *ppstate = state;
      76       23947 :         return h;
      77             : }
      78             : 
      79     1509449 : void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
      80             : {
      81     1509449 :         return h->private_data;
      82             : }
      83             : 
      84       14511 : void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
      85             :                                        struct tevent_context *ev)
      86             : {
      87       14511 :         h->sync_ev = ev;
      88       14511 : }
      89             : 
      90        5579 : bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
      91             : {
      92        5579 :         return h->ops->is_connected(h);
      93             : }
      94             : 
      95        4852 : uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
      96             :                                            uint32_t timeout)
      97             : {
      98        4852 :         return h->ops->set_timeout(h, timeout);
      99             : }
     100             : 
     101         804 : void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
     102             :                                      enum dcerpc_AuthType *auth_type,
     103             :                                      enum dcerpc_AuthLevel *auth_level)
     104             : {
     105             :         enum dcerpc_AuthType _auth_type;
     106             :         enum dcerpc_AuthLevel _auth_level;
     107             : 
     108         804 :         if (auth_type == NULL) {
     109         468 :                 auth_type = &_auth_type;
     110             :         }
     111             : 
     112         804 :         if (auth_level == NULL) {
     113           0 :                 auth_level = &_auth_level;
     114             :         }
     115             : 
     116         804 :         *auth_type = DCERPC_AUTH_TYPE_NONE;
     117         804 :         *auth_level = DCERPC_AUTH_LEVEL_NONE;
     118             : 
     119         804 :         if (h->ops->auth_info == NULL) {
     120           0 :                 return;
     121             :         }
     122             : 
     123         804 :         h->ops->auth_info(h, auth_type, auth_level);
     124             : }
     125             : 
     126             : struct dcerpc_binding_handle_raw_call_state {
     127             :         const struct dcerpc_binding_handle_ops *ops;
     128             :         uint8_t *out_data;
     129             :         size_t out_length;
     130             :         uint32_t out_flags;
     131             : };
     132             : 
     133             : static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
     134             : 
     135      198898 : struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
     136             :                                                 struct tevent_context *ev,
     137             :                                                 struct dcerpc_binding_handle *h,
     138             :                                                 const struct GUID *object,
     139             :                                                 uint32_t opnum,
     140             :                                                 uint32_t in_flags,
     141             :                                                 const uint8_t *in_data,
     142             :                                                 size_t in_length)
     143             : {
     144             :         struct tevent_req *req;
     145             :         struct dcerpc_binding_handle_raw_call_state *state;
     146             :         struct tevent_req *subreq;
     147             : 
     148      198898 :         req = tevent_req_create(mem_ctx, &state,
     149             :                                 struct dcerpc_binding_handle_raw_call_state);
     150      198898 :         if (req == NULL) {
     151           0 :                 return NULL;
     152             :         }
     153      198898 :         state->ops = h->ops;
     154      198898 :         state->out_data = NULL;
     155      198898 :         state->out_length = 0;
     156      198898 :         state->out_flags = 0;
     157             : 
     158      198898 :         if (h->object != NULL) {
     159             :                 /*
     160             :                  * If an object is set on the binding handle,
     161             :                  * per request object passing is not allowed.
     162             :                  */
     163           0 :                 if (object != NULL) {
     164           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
     165           0 :                         return tevent_req_post(req, ev);
     166             :                 }
     167             : 
     168             :                 /*
     169             :                  * We use the object from the binding handle
     170             :                  */
     171           0 :                 object = h->object;
     172             :         }
     173             : 
     174      198898 :         subreq = state->ops->raw_call_send(state, ev, h,
     175             :                                            object, opnum,
     176             :                                            in_flags, in_data, in_length);
     177      198898 :         if (tevent_req_nomem(subreq, req)) {
     178           0 :                 return tevent_req_post(req, ev);
     179             :         }
     180      198898 :         tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
     181             : 
     182      198898 :         return req;
     183             : }
     184             : 
     185      194235 : static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
     186             : {
     187      194235 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     188             :                                  struct tevent_req);
     189      156894 :         struct dcerpc_binding_handle_raw_call_state *state =
     190      194235 :                 tevent_req_data(req,
     191             :                 struct dcerpc_binding_handle_raw_call_state);
     192             :         NTSTATUS error;
     193             : 
     194      194235 :         error = state->ops->raw_call_recv(subreq, state,
     195             :                                           &state->out_data,
     196             :                                           &state->out_length,
     197             :                                           &state->out_flags);
     198      194235 :         TALLOC_FREE(subreq);
     199      194235 :         if (tevent_req_nterror(req, error)) {
     200       15032 :                 return;
     201             :         }
     202             : 
     203      179203 :         tevent_req_done(req);
     204             : }
     205             : 
     206      194235 : NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
     207             :                                              TALLOC_CTX *mem_ctx,
     208             :                                              uint8_t **out_data,
     209             :                                              size_t *out_length,
     210             :                                              uint32_t *out_flags)
     211             : {
     212      156894 :         struct dcerpc_binding_handle_raw_call_state *state =
     213      194235 :                 tevent_req_data(req,
     214             :                 struct dcerpc_binding_handle_raw_call_state);
     215             :         NTSTATUS error;
     216             : 
     217      194235 :         if (tevent_req_is_nterror(req, &error)) {
     218       15032 :                 tevent_req_received(req);
     219       15032 :                 return error;
     220             :         }
     221             : 
     222      179203 :         *out_data = talloc_move(mem_ctx, &state->out_data);
     223      179203 :         *out_length = state->out_length;
     224      179203 :         *out_flags = state->out_flags;
     225      179203 :         tevent_req_received(req);
     226      179203 :         return NT_STATUS_OK;
     227             : }
     228             : 
     229           7 : NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
     230             :                                         const struct GUID *object,
     231             :                                         uint32_t opnum,
     232             :                                         uint32_t in_flags,
     233             :                                         const uint8_t *in_data,
     234             :                                         size_t in_length,
     235             :                                         TALLOC_CTX *mem_ctx,
     236             :                                         uint8_t **out_data,
     237             :                                         size_t *out_length,
     238             :                                         uint32_t *out_flags)
     239             : {
     240           7 :         TALLOC_CTX *frame = talloc_stackframe();
     241             :         struct tevent_context *ev;
     242             :         struct tevent_req *subreq;
     243           7 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     244             : 
     245             :         /*
     246             :          * TODO: allow only one sync call
     247             :          */
     248             : 
     249           7 :         if (h->sync_ev) {
     250           7 :                 ev = h->sync_ev;
     251             :         } else {
     252           0 :                 ev = samba_tevent_context_init(frame);
     253             :         }
     254           7 :         if (ev == NULL) {
     255           0 :                 goto fail;
     256             :         }
     257             : 
     258           7 :         subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
     259             :                                                      h, object, opnum,
     260             :                                                      in_flags,
     261             :                                                      in_data,
     262             :                                                      in_length);
     263           7 :         if (subreq == NULL) {
     264           0 :                 goto fail;
     265             :         }
     266             : 
     267           7 :         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
     268           0 :                 goto fail;
     269             :         }
     270             : 
     271           7 :         status = dcerpc_binding_handle_raw_call_recv(subreq,
     272             :                                                      mem_ctx,
     273             :                                                      out_data,
     274             :                                                      out_length,
     275             :                                                      out_flags);
     276           7 : fail:
     277           7 :         TALLOC_FREE(frame);
     278           7 :         return status;
     279             : }
     280             : 
     281             : struct dcerpc_binding_handle_disconnect_state {
     282             :         const struct dcerpc_binding_handle_ops *ops;
     283             : };
     284             : 
     285             : static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
     286             : 
     287           0 : struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
     288             :                                                 struct tevent_context *ev,
     289             :                                                 struct dcerpc_binding_handle *h)
     290             : {
     291             :         struct tevent_req *req;
     292             :         struct dcerpc_binding_handle_disconnect_state *state;
     293             :         struct tevent_req *subreq;
     294             : 
     295           0 :         req = tevent_req_create(mem_ctx, &state,
     296             :                                 struct dcerpc_binding_handle_disconnect_state);
     297           0 :         if (req == NULL) {
     298           0 :                 return NULL;
     299             :         }
     300             : 
     301           0 :         state->ops = h->ops;
     302             : 
     303           0 :         subreq = state->ops->disconnect_send(state, ev, h);
     304           0 :         if (tevent_req_nomem(subreq, req)) {
     305           0 :                 return tevent_req_post(req, ev);
     306             :         }
     307           0 :         tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
     308             : 
     309           0 :         return req;
     310             : }
     311             : 
     312           0 : static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
     313             : {
     314           0 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     315             :                                  struct tevent_req);
     316           0 :         struct dcerpc_binding_handle_disconnect_state *state =
     317           0 :                 tevent_req_data(req,
     318             :                 struct dcerpc_binding_handle_disconnect_state);
     319             :         NTSTATUS error;
     320             : 
     321           0 :         error = state->ops->disconnect_recv(subreq);
     322           0 :         TALLOC_FREE(subreq);
     323           0 :         if (tevent_req_nterror(req, error)) {
     324           0 :                 return;
     325             :         }
     326             : 
     327           0 :         tevent_req_done(req);
     328             : }
     329             : 
     330           0 : NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
     331             : {
     332             :         NTSTATUS error;
     333             : 
     334           0 :         if (tevent_req_is_nterror(req, &error)) {
     335           0 :                 tevent_req_received(req);
     336           0 :                 return error;
     337             :         }
     338             : 
     339           0 :         tevent_req_received(req);
     340           0 :         return NT_STATUS_OK;
     341             : }
     342             : 
     343             : struct dcerpc_binding_handle_call_state {
     344             :         struct dcerpc_binding_handle *h;
     345             :         const struct ndr_interface_call *call;
     346             :         TALLOC_CTX *r_mem;
     347             :         void *r_ptr;
     348             :         struct ndr_push *push;
     349             :         DATA_BLOB request;
     350             :         DATA_BLOB response;
     351             :         struct ndr_pull *pull;
     352             : };
     353             : 
     354             : static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
     355             : 
     356      198933 : struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
     357             :                                         struct tevent_context *ev,
     358             :                                         struct dcerpc_binding_handle *h,
     359             :                                         const struct GUID *object,
     360             :                                         const struct ndr_interface_table *table,
     361             :                                         uint32_t opnum,
     362             :                                         TALLOC_CTX *r_mem,
     363             :                                         void *r_ptr)
     364             : {
     365             :         struct tevent_req *req;
     366             :         struct dcerpc_binding_handle_call_state *state;
     367             :         struct tevent_req *subreq;
     368             :         enum ndr_err_code ndr_err;
     369             : 
     370      198933 :         req = tevent_req_create(mem_ctx, &state,
     371             :                                 struct dcerpc_binding_handle_call_state);
     372      198933 :         if (req == NULL) {
     373           0 :                 return NULL;
     374             :         }
     375             : 
     376      198933 :         if (table != h->table) {
     377           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
     378           0 :                 return tevent_req_post(req, ev);
     379             :         }
     380             : 
     381      198933 :         if (opnum >= table->num_calls) {
     382           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     383           0 :                 return tevent_req_post(req, ev);
     384             :         }
     385             : 
     386      198933 :         state->h = h;
     387      198933 :         state->call = &table->calls[opnum];
     388             : 
     389      198933 :         state->r_mem = r_mem;
     390      198933 :         state->r_ptr = r_ptr;
     391             : 
     392             :         /* setup for a ndr_push_* call */
     393      198933 :         state->push = ndr_push_init_ctx(state);
     394      198933 :         if (tevent_req_nomem(state->push, req)) {
     395           0 :                 return tevent_req_post(req, ev);
     396             :         }
     397             : 
     398      198933 :         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
     399       54816 :                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
     400             :         }
     401             : 
     402      198933 :         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
     403       21510 :                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
     404             :         }
     405             : 
     406      198933 :         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
     407           0 :                 state->push->flags |= LIBNDR_FLAG_NDR64;
     408             :         }
     409             : 
     410      198933 :         if (h->ops->do_ndr_print) {
     411      498545 :                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
     412      344733 :                                      state->r_ptr, state->call);
     413             :         }
     414             : 
     415             :         /* push the structure into a blob */
     416      198933 :         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
     417      198933 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     418             :                 NTSTATUS error;
     419          42 :                 error = ndr_map_error2ntstatus(ndr_err);
     420          42 :                 if (h->ops->ndr_push_failed) {
     421         126 :                         h->ops->ndr_push_failed(h, error,
     422          42 :                                                 state->r_ptr,
     423          42 :                                                 state->call);
     424             :                 }
     425          42 :                 tevent_req_nterror(req, error);
     426          42 :                 return tevent_req_post(req, ev);
     427             :         }
     428             : 
     429             :         /* retrieve the blob */
     430      198891 :         state->request = ndr_push_blob(state->push);
     431             : 
     432      198891 :         if (h->ops->ndr_validate_in) {
     433             :                 NTSTATUS error;
     434      426954 :                 error = h->ops->ndr_validate_in(h, state,
     435      161142 :                                                 &state->request,
     436      161142 :                                                 state->call);
     437      161142 :                 if (!NT_STATUS_IS_OK(error)) {
     438           0 :                         tevent_req_nterror(req, error);
     439           0 :                         return tevent_req_post(req, ev);
     440             :                 }
     441             :         }
     442             : 
     443      359933 :         subreq = dcerpc_binding_handle_raw_call_send(state, ev,
     444             :                                                      h, object, opnum,
     445      198891 :                                                      state->push->flags,
     446      198891 :                                                      state->request.data,
     447      198891 :                                                      state->request.length);
     448      198891 :         if (tevent_req_nomem(subreq, req)) {
     449           0 :                 return tevent_req_post(req, ev);
     450             :         }
     451      198891 :         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
     452             : 
     453      198891 :         return req;
     454             : }
     455             : 
     456      194228 : static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
     457             : {
     458      194228 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     459             :                                  struct tevent_req);
     460      156887 :         struct dcerpc_binding_handle_call_state *state =
     461      194228 :                 tevent_req_data(req,
     462             :                 struct dcerpc_binding_handle_call_state);
     463      194228 :         struct dcerpc_binding_handle *h = state->h;
     464             :         NTSTATUS error;
     465      194228 :         uint32_t out_flags = 0;
     466             :         enum ndr_err_code ndr_err;
     467             : 
     468      194228 :         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
     469             :                                                     &state->response.data,
     470             :                                                     &state->response.length,
     471             :                                                     &out_flags);
     472      194228 :         TALLOC_FREE(subreq);
     473      194228 :         if (tevent_req_nterror(req, error)) {
     474       30027 :                 return;
     475             :         }
     476             : 
     477      179196 :         state->pull = ndr_pull_init_blob(&state->response, state);
     478      179196 :         if (tevent_req_nomem(state->pull, req)) {
     479           0 :                 return;
     480             :         }
     481      179196 :         state->pull->flags = state->push->flags;
     482             : 
     483      179196 :         if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
     484           0 :                 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
     485             :         } else {
     486      179196 :                 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
     487             :         }
     488             : 
     489      179196 :         state->pull->current_mem_ctx = state->r_mem;
     490             : 
     491             :         /* pull the structure from the blob */
     492      179196 :         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
     493      179196 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     494           0 :                 error = ndr_map_error2ntstatus(ndr_err);
     495           0 :                 if (h->ops->ndr_pull_failed) {
     496           0 :                         h->ops->ndr_pull_failed(h, error,
     497           0 :                                                 &state->response,
     498             :                                                 state->call);
     499             :                 }
     500           0 :                 tevent_req_nterror(req, error);
     501           0 :                 return;
     502             :         }
     503             : 
     504      179196 :         if (h->ops->do_ndr_print) {
     505      314788 :                 h->ops->do_ndr_print(h, NDR_OUT,
     506      175934 :                                      state->r_ptr, state->call);
     507             :         }
     508             : 
     509      179196 :         if (h->ops->ndr_validate_out) {
     510      264263 :                 error = h->ops->ndr_validate_out(h,
     511             :                                                  state->pull,
     512      146236 :                                                  state->r_ptr,
     513             :                                                  state->call);
     514      146236 :                 if (!NT_STATUS_IS_OK(error)) {
     515           0 :                         tevent_req_nterror(req, error);
     516           0 :                         return;
     517             :                 }
     518             :         }
     519             : 
     520      179196 :         tevent_req_done(req);
     521             : }
     522             : 
     523      194270 : NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
     524             : {
     525      194270 :         return tevent_req_simple_recv_ntstatus(req);
     526             : }
     527             : 
     528      152381 : NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
     529             :                                     const struct GUID *object,
     530             :                                     const struct ndr_interface_table *table,
     531             :                                     uint32_t opnum,
     532             :                                     TALLOC_CTX *r_mem,
     533             :                                     void *r_ptr)
     534             : {
     535      152381 :         TALLOC_CTX *frame = talloc_stackframe();
     536             :         struct tevent_context *ev;
     537             :         struct tevent_req *subreq;
     538      152381 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     539             : 
     540             :         /*
     541             :          * TODO: allow only one sync call
     542             :          */
     543             : 
     544      152381 :         if (h->sync_ev) {
     545      146373 :                 ev = h->sync_ev;
     546             :         } else {
     547        6008 :                 ev = samba_tevent_context_init(frame);
     548             :         }
     549      152381 :         if (ev == NULL) {
     550           0 :                 goto fail;
     551             :         }
     552             : 
     553      152381 :         subreq = dcerpc_binding_handle_call_send(frame, ev,
     554             :                                                  h, object, table,
     555             :                                                  opnum, r_mem, r_ptr);
     556      152381 :         if (subreq == NULL) {
     557           0 :                 goto fail;
     558             :         }
     559             : 
     560      152381 :         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
     561           0 :                 goto fail;
     562             :         }
     563             : 
     564      152381 :         status = dcerpc_binding_handle_call_recv(subreq);
     565      152381 : fail:
     566      152381 :         TALLOC_FREE(frame);
     567      152381 :         return status;
     568             : }

Generated by: LCOV version 1.13