LCOV - code coverage report
Current view: top level - source4/auth/gensec - gensec_tstream.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 207 241 85.9 %
Date: 2021-08-25 13:27:56 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    tstream based generic authentication interface
       5             : 
       6             :    Copyright (c) 2010 Stefan Metzmacher
       7             :    Copyright (c) 2010 Andreas Schneider <asn@redhat.com>
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "system/network.h"
      25             : #include "auth/gensec/gensec.h"
      26             : #include "auth/gensec/gensec_proto.h"
      27             : #include "auth/gensec/gensec_tstream.h"
      28             : #include "lib/tsocket/tsocket.h"
      29             : #include "lib/tsocket/tsocket_internal.h"
      30             : #include "auth/gensec/gensec_toplevel_proto.h"
      31             : 
      32             : static const struct tstream_context_ops tstream_gensec_ops;
      33             : 
      34             : struct tstream_gensec {
      35             :         struct tstream_context *plain_stream;
      36             : 
      37             :         struct gensec_security *gensec_security;
      38             : 
      39             :         int error;
      40             : 
      41             :         struct {
      42             :                 size_t max_unwrapped_size;
      43             :                 size_t max_wrapped_size;
      44             :         } write;
      45             : 
      46             :         struct {
      47             :                 off_t ofs;
      48             :                 size_t left;
      49             :                 DATA_BLOB unwrapped;
      50             :         } read;
      51             : };
      52             : 
      53       35176 : _PUBLIC_ NTSTATUS _gensec_create_tstream(TALLOC_CTX *mem_ctx,
      54             :                                          struct gensec_security *gensec_security,
      55             :                                          struct tstream_context *plain_stream,
      56             :                                          struct tstream_context **_gensec_stream,
      57             :                                          const char *location)
      58             : {
      59             :         struct tstream_context *gensec_stream;
      60             :         struct tstream_gensec *tgss;
      61             : 
      62       35176 :         gensec_stream = tstream_context_create(mem_ctx,
      63             :                                                &tstream_gensec_ops,
      64             :                                                &tgss,
      65             :                                                struct tstream_gensec,
      66             :                                                location);
      67       35176 :         if (gensec_stream == NULL) {
      68           0 :                 return NT_STATUS_NO_MEMORY;
      69             :         }
      70             : 
      71       35176 :         tgss->plain_stream = plain_stream;
      72       35176 :         tgss->gensec_security = gensec_security;
      73       35176 :         tgss->error = 0;
      74             : 
      75       35176 :         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN) &&
      76           0 :             !gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
      77           0 :                 talloc_free(gensec_stream);
      78           0 :                 return NT_STATUS_INVALID_PARAMETER;
      79             :         }
      80             : 
      81       35176 :         tgss->write.max_unwrapped_size = gensec_max_input_size(gensec_security);
      82       35176 :         tgss->write.max_wrapped_size = gensec_max_wrapped_size(gensec_security);
      83             : 
      84       35176 :         ZERO_STRUCT(tgss->read);
      85             : 
      86       35176 :         *_gensec_stream = gensec_stream;
      87       35176 :         return NT_STATUS_OK;
      88             : }
      89             : 
      90          98 : static ssize_t tstream_gensec_pending_bytes(struct tstream_context *stream)
      91             : {
      92          98 :         struct tstream_gensec *tgss =
      93          98 :                 tstream_context_data(stream,
      94             :                 struct tstream_gensec);
      95             : 
      96          98 :         if (tgss->error != 0) {
      97           0 :                 errno = tgss->error;
      98           0 :                 return -1;
      99             :         }
     100             : 
     101          98 :         return tgss->read.left;
     102             : }
     103             : 
     104             : struct tstream_gensec_readv_state {
     105             :         struct tevent_context *ev;
     106             :         struct tstream_context *stream;
     107             : 
     108             :         struct iovec *vector;
     109             :         int count;
     110             : 
     111             :         struct {
     112             :                 bool asked_for_hdr;
     113             :                 uint8_t hdr[4];
     114             :                 bool asked_for_blob;
     115             :                 DATA_BLOB blob;
     116             :         } wrapped;
     117             : 
     118             :         int ret;
     119             : };
     120             : 
     121             : static void tstream_gensec_readv_wrapped_next(struct tevent_req *req);
     122             : 
     123     2802061 : static struct tevent_req *tstream_gensec_readv_send(TALLOC_CTX *mem_ctx,
     124             :                                                     struct tevent_context *ev,
     125             :                                                     struct tstream_context *stream,
     126             :                                                     struct iovec *vector,
     127             :                                                     size_t count)
     128             : {
     129     2802061 :         struct tstream_gensec *tgss =
     130     2802061 :                 tstream_context_data(stream,
     131             :                 struct tstream_gensec);
     132             :         struct tevent_req *req;
     133             :         struct tstream_gensec_readv_state *state;
     134             : 
     135     2802061 :         req = tevent_req_create(mem_ctx, &state,
     136             :                                 struct tstream_gensec_readv_state);
     137     2802061 :         if (!req) {
     138           0 :                 return NULL;
     139             :         }
     140             : 
     141     2802061 :         if (tgss->error != 0) {
     142           0 :                 tevent_req_error(req, tgss->error);
     143           0 :                 return tevent_req_post(req, ev);
     144             :         }
     145             : 
     146     2802061 :         state->ev = ev;
     147     2802061 :         state->stream = stream;
     148     2802061 :         state->ret = 0;
     149             : 
     150             :         /*
     151             :          * we make a copy of the vector so we can change the structure
     152             :          */
     153     2802061 :         state->vector = talloc_array(state, struct iovec, count);
     154     2802061 :         if (tevent_req_nomem(state->vector, req)) {
     155           0 :                 return tevent_req_post(req, ev);
     156             :         }
     157     2804613 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     158     2802061 :         state->count = count;
     159             : 
     160     2802061 :         tstream_gensec_readv_wrapped_next(req);
     161     2802061 :         if (!tevent_req_is_in_progress(req)) {
     162     1986466 :                 return tevent_req_post(req, ev);
     163             :         }
     164             : 
     165      814543 :         return req;
     166             : }
     167             : 
     168             : static int tstream_gensec_readv_next_vector(struct tstream_context *unix_stream,
     169             :                                             void *private_data,
     170             :                                             TALLOC_CTX *mem_ctx,
     171             :                                             struct iovec **_vector,
     172             :                                             size_t *_count);
     173             : static void tstream_gensec_readv_wrapped_done(struct tevent_req *subreq);
     174             : 
     175     3634863 : static void tstream_gensec_readv_wrapped_next(struct tevent_req *req)
     176             : {
     177     3634863 :         struct tstream_gensec_readv_state *state =
     178     3634863 :                 tevent_req_data(req,
     179             :                 struct tstream_gensec_readv_state);
     180     3634863 :         struct tstream_gensec *tgss =
     181     3634863 :                 tstream_context_data(state->stream,
     182             :                 struct tstream_gensec);
     183             :         struct tevent_req *subreq;
     184             : 
     185             :         /*
     186             :          * copy the pending buffer first
     187             :          */
     188    10090802 :         while (tgss->read.left > 0 && state->count > 0) {
     189     2821076 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     190     2821076 :                 size_t len = MIN(tgss->read.left, state->vector[0].iov_len);
     191             : 
     192     2823506 :                 memcpy(base, tgss->read.unwrapped.data + tgss->read.ofs, len);
     193             : 
     194     2821076 :                 base += len;
     195     2821076 :                 state->vector[0].iov_base = (char *) base;
     196     2821076 :                 state->vector[0].iov_len -= len;
     197             : 
     198     2821076 :                 tgss->read.ofs += len;
     199     2821076 :                 tgss->read.left -= len;
     200             : 
     201     2821076 :                 if (state->vector[0].iov_len == 0) {
     202     2784566 :                         state->vector += 1;
     203     2784566 :                         state->count -= 1;
     204             :                 }
     205             : 
     206     2821076 :                 state->ret += len;
     207             :         }
     208             : 
     209     3634863 :         if (state->count == 0) {
     210     2784566 :                 tevent_req_done(req);
     211     2784566 :                 return;
     212             :         }
     213             : 
     214      850297 :         data_blob_free(&tgss->read.unwrapped);
     215      850297 :         ZERO_STRUCT(state->wrapped);
     216             : 
     217      850297 :         subreq = tstream_readv_pdu_send(state, state->ev,
     218             :                                         tgss->plain_stream,
     219             :                                         tstream_gensec_readv_next_vector,
     220             :                                         state);
     221      850297 :         if (tevent_req_nomem(subreq, req)) {
     222           0 :                 return;
     223             :         }
     224      850297 :         tevent_req_set_callback(subreq, tstream_gensec_readv_wrapped_done, req);
     225             : }
     226             : 
     227     2515901 : static int tstream_gensec_readv_next_vector(struct tstream_context *unix_stream,
     228             :                                             void *private_data,
     229             :                                             TALLOC_CTX *mem_ctx,
     230             :                                             struct iovec **_vector,
     231             :                                             size_t *_count)
     232             : {
     233     2515901 :         struct tstream_gensec_readv_state *state =
     234             :                 talloc_get_type_abort(private_data,
     235             :                 struct tstream_gensec_readv_state);
     236             :         struct iovec *vector;
     237     2515901 :         size_t count = 1;
     238             : 
     239             :         /* we need to get a message header */
     240     2515901 :         vector = talloc_array(mem_ctx, struct iovec, count);
     241     2515901 :         if (!vector) {
     242           0 :                 return -1;
     243             :         }
     244             : 
     245     2515901 :         if (!state->wrapped.asked_for_hdr) {
     246      850297 :                 state->wrapped.asked_for_hdr = true;
     247      850297 :                 vector[0].iov_base = (char *)state->wrapped.hdr;
     248      850297 :                 vector[0].iov_len = sizeof(state->wrapped.hdr);
     249     1665604 :         } else if (!state->wrapped.asked_for_blob) {
     250             :                 uint32_t msg_len;
     251             : 
     252      832802 :                 state->wrapped.asked_for_blob = true;
     253             : 
     254      832802 :                 msg_len = RIVAL(state->wrapped.hdr, 0);
     255             : 
     256             :                 /*
     257             :                  * I got a Windows 2012R2 server responding with
     258             :                  * a message of 0x1b28a33.
     259             :                  */
     260      832802 :                 if (msg_len > 0x0FFFFFFF) {
     261           0 :                         errno = EMSGSIZE;
     262           0 :                         return -1;
     263             :                 }
     264             : 
     265      832802 :                 if (msg_len == 0) {
     266           0 :                         errno = EMSGSIZE;
     267           0 :                         return -1;
     268             :                 }
     269             : 
     270      832802 :                 state->wrapped.blob = data_blob_talloc(state, NULL, msg_len);
     271      832802 :                 if (state->wrapped.blob.data == NULL) {
     272           0 :                         return -1;
     273             :                 }
     274             : 
     275      832802 :                 vector[0].iov_base = (char *)state->wrapped.blob.data;
     276      832802 :                 vector[0].iov_len = state->wrapped.blob.length;
     277             :         } else {
     278      832802 :                 *_vector = NULL;
     279      832802 :                 *_count = 0;
     280      832802 :                 return 0;
     281             :         }
     282             : 
     283     1683099 :         *_vector = vector;
     284     1683099 :         *_count = count;
     285     1683099 :         return 0;
     286             : }
     287             : 
     288      850293 : static void tstream_gensec_readv_wrapped_done(struct tevent_req *subreq)
     289             : {
     290      850293 :         struct tevent_req *req =
     291      850293 :                 tevent_req_callback_data(subreq,
     292             :                 struct tevent_req);
     293      850293 :         struct tstream_gensec_readv_state *state =
     294      850293 :                 tevent_req_data(req,
     295             :                 struct tstream_gensec_readv_state);
     296      850293 :         struct tstream_gensec *tgss =
     297      850293 :                 tstream_context_data(state->stream,
     298             :                 struct tstream_gensec);
     299             :         int ret;
     300             :         int sys_errno;
     301             :         NTSTATUS status;
     302             : 
     303      850293 :         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
     304      850293 :         TALLOC_FREE(subreq);
     305      850293 :         if (ret == -1) {
     306       17491 :                 tgss->error = sys_errno;
     307       17491 :                 tevent_req_error(req, sys_errno);
     308       17491 :                 return;
     309             :         }
     310             : 
     311     1665604 :         status = gensec_unwrap(tgss->gensec_security,
     312             :                                state,
     313      832802 :                                &state->wrapped.blob,
     314             :                                &tgss->read.unwrapped);
     315      832802 :         if (!NT_STATUS_IS_OK(status)) {
     316           0 :                 tgss->error = EIO;
     317           0 :                 tevent_req_error(req, tgss->error);
     318           0 :                 return;
     319             :         }
     320             : 
     321      832802 :         data_blob_free(&state->wrapped.blob);
     322             : 
     323      832802 :         talloc_steal(tgss, tgss->read.unwrapped.data);
     324      832802 :         tgss->read.left = tgss->read.unwrapped.length;
     325      832802 :         tgss->read.ofs = 0;
     326             : 
     327      832802 :         tstream_gensec_readv_wrapped_next(req);
     328             : }
     329             : 
     330     2802057 : static int tstream_gensec_readv_recv(struct tevent_req *req, int *perrno)
     331             : {
     332     2802057 :         struct tstream_gensec_readv_state *state =
     333     2802057 :                 tevent_req_data(req,
     334             :                 struct tstream_gensec_readv_state);
     335             :         int ret;
     336             : 
     337     2802057 :         ret = tsocket_simple_int_recv(req, perrno);
     338     2802057 :         if (ret == 0) {
     339     2784566 :                 ret = state->ret;
     340             :         }
     341             : 
     342     2802057 :         tevent_req_received(req);
     343     2802057 :         return ret;
     344             : }
     345             : 
     346             : struct tstream_gensec_writev_state {
     347             :         struct tevent_context *ev;
     348             :         struct tstream_context *stream;
     349             : 
     350             :         struct iovec *vector;
     351             :         int count;
     352             : 
     353             :         struct {
     354             :                 off_t ofs;
     355             :                 size_t left;
     356             :                 DATA_BLOB blob;
     357             :         } unwrapped;
     358             : 
     359             :         struct {
     360             :                 uint8_t hdr[4];
     361             :                 DATA_BLOB blob;
     362             :                 struct iovec iov[2];
     363             :         } wrapped;
     364             : 
     365             :         int ret;
     366             : };
     367             : 
     368             : static void tstream_gensec_writev_wrapped_next(struct tevent_req *req);
     369             : 
     370      796022 : static struct tevent_req *tstream_gensec_writev_send(TALLOC_CTX *mem_ctx,
     371             :                                         struct tevent_context *ev,
     372             :                                         struct tstream_context *stream,
     373             :                                         const struct iovec *vector,
     374             :                                         size_t count)
     375             : {
     376      796022 :         struct tstream_gensec *tgss =
     377      796022 :                 tstream_context_data(stream,
     378             :                 struct tstream_gensec);
     379             :         struct tevent_req *req;
     380             :         struct tstream_gensec_writev_state *state;
     381             :         int i;
     382             :         int total;
     383             :         int chunk;
     384             : 
     385      796022 :         req = tevent_req_create(mem_ctx, &state,
     386             :                                 struct tstream_gensec_writev_state);
     387      796022 :         if (req == NULL) {
     388           0 :                 return NULL;
     389             :         }
     390             : 
     391      796022 :         if (tgss->error != 0) {
     392           0 :                 tevent_req_error(req, tgss->error);
     393           0 :                 return tevent_req_post(req, ev);
     394             :         }
     395             : 
     396      796022 :         state->ev = ev;
     397      796022 :         state->stream = stream;
     398      796022 :         state->ret = 0;
     399             : 
     400             :         /*
     401             :          * we make a copy of the vector so we can change the structure
     402             :          */
     403      796022 :         state->vector = talloc_array(state, struct iovec, count);
     404      796022 :         if (tevent_req_nomem(state->vector, req)) {
     405           0 :                 return tevent_req_post(req, ev);
     406             :         }
     407      796952 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     408      796022 :         state->count = count;
     409             : 
     410      796022 :         total = 0;
     411     2189417 :         for (i = 0; i < count; i++) {
     412             :                 /*
     413             :                  * the generic tstream code makes sure that
     414             :                  * this never wraps.
     415             :                  */
     416     1393395 :                 total += vector[i].iov_len;
     417             :         }
     418             : 
     419             :         /*
     420             :          * We may need to send data in chunks.
     421             :          */
     422      796022 :         chunk = MIN(total, tgss->write.max_unwrapped_size);
     423             : 
     424      796022 :         state->unwrapped.blob = data_blob_talloc(state, NULL, chunk);
     425      796022 :         if (tevent_req_nomem(state->unwrapped.blob.data, req)) {
     426           0 :                 return tevent_req_post(req, ev);
     427             :         }
     428             : 
     429      796022 :         tstream_gensec_writev_wrapped_next(req);
     430      796022 :         if (!tevent_req_is_in_progress(req)) {
     431           0 :                 return tevent_req_post(req, ev);
     432             :         }
     433             : 
     434      795092 :         return req;
     435             : }
     436             : 
     437             : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq);
     438             : 
     439     1628553 : static void tstream_gensec_writev_wrapped_next(struct tevent_req *req)
     440             : {
     441     1628553 :         struct tstream_gensec_writev_state *state =
     442     1628553 :                 tevent_req_data(req,
     443             :                 struct tstream_gensec_writev_state);
     444     1628553 :         struct tstream_gensec *tgss =
     445     1628553 :                 tstream_context_data(state->stream,
     446             :                 struct tstream_gensec);
     447             :         struct tevent_req *subreq;
     448             :         NTSTATUS status;
     449             : 
     450     1628553 :         data_blob_free(&state->wrapped.blob);
     451             : 
     452     1628553 :         state->unwrapped.left = state->unwrapped.blob.length;
     453     1628553 :         state->unwrapped.ofs = 0;
     454             : 
     455             :         /*
     456             :          * first fill our buffer
     457             :          */
     458     4687011 :         while (state->unwrapped.left > 0 && state->count > 0) {
     459     1429905 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     460     1429905 :                 size_t len = MIN(state->unwrapped.left, state->vector[0].iov_len);
     461             : 
     462     1431120 :                 memcpy(state->unwrapped.blob.data + state->unwrapped.ofs, base, len);
     463             : 
     464     1429905 :                 base += len;
     465     1429905 :                 state->vector[0].iov_base = (char *) base;
     466     1429905 :                 state->vector[0].iov_len -= len;
     467             : 
     468     1429905 :                 state->unwrapped.ofs += len;
     469     1429905 :                 state->unwrapped.left -= len;
     470             : 
     471     1429905 :                 if (state->vector[0].iov_len == 0) {
     472     1393395 :                         state->vector += 1;
     473     1393395 :                         state->count -= 1;
     474             :                 }
     475             : 
     476     1429905 :                 state->ret += len;
     477             :         }
     478             : 
     479     1628553 :         if (state->unwrapped.ofs == 0) {
     480      796021 :                 tevent_req_done(req);
     481      796021 :                 return;
     482             :         }
     483             : 
     484      832532 :         state->unwrapped.blob.length = state->unwrapped.ofs;
     485             : 
     486     1664134 :         status = gensec_wrap(tgss->gensec_security,
     487             :                              state,
     488      832532 :                              &state->unwrapped.blob,
     489             :                              &state->wrapped.blob);
     490      832532 :         if (!NT_STATUS_IS_OK(status)) {
     491           0 :                 tgss->error = EIO;
     492           0 :                 tevent_req_error(req, tgss->error);
     493           0 :                 return;
     494             :         }
     495             : 
     496      832532 :         RSIVAL(state->wrapped.hdr, 0, state->wrapped.blob.length);
     497             : 
     498      832532 :         state->wrapped.iov[0].iov_base = (void *)state->wrapped.hdr;
     499      832532 :         state->wrapped.iov[0].iov_len = sizeof(state->wrapped.hdr);
     500      832532 :         state->wrapped.iov[1].iov_base = (void *)state->wrapped.blob.data;
     501      832532 :         state->wrapped.iov[1].iov_len = state->wrapped.blob.length;
     502             : 
     503      832532 :         subreq = tstream_writev_send(state, state->ev,
     504             :                                       tgss->plain_stream,
     505      832532 :                                       state->wrapped.iov, 2);
     506      832532 :         if (tevent_req_nomem(subreq, req)) {
     507           0 :                 return;
     508             :         }
     509      832532 :         tevent_req_set_callback(subreq,
     510             :                                 tstream_gensec_writev_wrapped_done,
     511             :                                 req);
     512             : }
     513             : 
     514      832531 : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq)
     515             : {
     516      832531 :         struct tevent_req *req =
     517      832531 :                 tevent_req_callback_data(subreq,
     518             :                 struct tevent_req);
     519      832531 :         struct tstream_gensec_writev_state *state =
     520      832531 :                 tevent_req_data(req,
     521             :                 struct tstream_gensec_writev_state);
     522      832531 :         struct tstream_gensec *tgss =
     523      832531 :                 tstream_context_data(state->stream,
     524             :                 struct tstream_gensec);
     525             :         int sys_errno;
     526             :         int ret;
     527             : 
     528      832531 :         ret = tstream_writev_recv(subreq, &sys_errno);
     529      832531 :         TALLOC_FREE(subreq);
     530      832531 :         if (ret == -1) {
     531           0 :                 tgss->error = sys_errno;
     532           0 :                 tevent_req_error(req, sys_errno);
     533           0 :                 return;
     534             :         }
     535             : 
     536      832531 :         tstream_gensec_writev_wrapped_next(req);
     537             : }
     538             : 
     539      796021 : static int tstream_gensec_writev_recv(struct tevent_req *req,
     540             :                                    int *perrno)
     541             : {
     542      796021 :         struct tstream_gensec_writev_state *state =
     543      796021 :                 tevent_req_data(req,
     544             :                 struct tstream_gensec_writev_state);
     545             :         int ret;
     546             : 
     547      796021 :         ret = tsocket_simple_int_recv(req, perrno);
     548      796021 :         if (ret == 0) {
     549      796021 :                 ret = state->ret;
     550             :         }
     551             : 
     552      796021 :         tevent_req_received(req);
     553      796021 :         return ret;
     554             : }
     555             : 
     556             : struct tstream_gensec_disconnect_state {
     557             :         uint8_t _dummy;
     558             : };
     559             : 
     560       17763 : static struct tevent_req *tstream_gensec_disconnect_send(TALLOC_CTX *mem_ctx,
     561             :                                                          struct tevent_context *ev,
     562             :                                                          struct tstream_context *stream)
     563             : {
     564       17763 :         struct tstream_gensec *tgss =
     565       17763 :                 tstream_context_data(stream,
     566             :                 struct tstream_gensec);
     567             :         struct tevent_req *req;
     568             :         struct tstream_gensec_disconnect_state *state;
     569             : 
     570       17763 :         req = tevent_req_create(mem_ctx, &state,
     571             :                                 struct tstream_gensec_disconnect_state);
     572       17763 :         if (req == NULL) {
     573           0 :                 return NULL;
     574             :         }
     575             : 
     576       17763 :         if (tgss->error != 0) {
     577       17491 :                 tevent_req_error(req, tgss->error);
     578       17491 :                 return tevent_req_post(req, ev);
     579             :         }
     580             : 
     581             :         /*
     582             :          * The caller is responsible to do the real disconnect
     583             :          * on the plain stream!
     584             :          */
     585         272 :         tgss->plain_stream = NULL;
     586         272 :         tgss->error = ENOTCONN;
     587             : 
     588         272 :         tevent_req_done(req);
     589         272 :         return tevent_req_post(req, ev);
     590             : }
     591             : 
     592       17763 : static int tstream_gensec_disconnect_recv(struct tevent_req *req,
     593             :                                        int *perrno)
     594             : {
     595             :         int ret;
     596             : 
     597       17763 :         ret = tsocket_simple_int_recv(req, perrno);
     598             : 
     599       17763 :         tevent_req_received(req);
     600       17763 :         return ret;
     601             : }
     602             : 
     603             : static const struct tstream_context_ops tstream_gensec_ops = {
     604             :         .name                   = "gensec",
     605             : 
     606             :         .pending_bytes          = tstream_gensec_pending_bytes,
     607             : 
     608             :         .readv_send             = tstream_gensec_readv_send,
     609             :         .readv_recv             = tstream_gensec_readv_recv,
     610             : 
     611             :         .writev_send            = tstream_gensec_writev_send,
     612             :         .writev_recv            = tstream_gensec_writev_recv,
     613             : 
     614             :         .disconnect_send        = tstream_gensec_disconnect_send,
     615             :         .disconnect_recv        = tstream_gensec_disconnect_recv,
     616             : };

Generated by: LCOV version 1.13