LCOV - code coverage report
Current view: top level - source4/auth/gensec - gensec_tstream.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 231 266 86.8 %
Date: 2023-11-21 12:31:41 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       50817 : _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         244 :         struct tstream_context *gensec_stream;
      60         244 :         struct tstream_gensec *tgss;
      61             : 
      62       50817 :         gensec_stream = tstream_context_create(mem_ctx,
      63             :                                                &tstream_gensec_ops,
      64             :                                                &tgss,
      65             :                                                struct tstream_gensec,
      66             :                                                location);
      67       50817 :         if (gensec_stream == NULL) {
      68           0 :                 return NT_STATUS_NO_MEMORY;
      69             :         }
      70             : 
      71       50817 :         tgss->plain_stream = plain_stream;
      72       50817 :         tgss->gensec_security = gensec_security;
      73       50817 :         tgss->error = 0;
      74             : 
      75       50817 :         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       50817 :         tgss->write.max_unwrapped_size = gensec_max_input_size(gensec_security);
      82       50817 :         tgss->write.max_wrapped_size = gensec_max_wrapped_size(gensec_security);
      83             : 
      84       50817 :         ZERO_STRUCT(tgss->read);
      85             : 
      86       50817 :         *_gensec_stream = gensec_stream;
      87       50817 :         return NT_STATUS_OK;
      88             : }
      89             : 
      90         104 : static ssize_t tstream_gensec_pending_bytes(struct tstream_context *stream)
      91             : {
      92           0 :         struct tstream_gensec *tgss =
      93         104 :                 tstream_context_data(stream,
      94             :                 struct tstream_gensec);
      95             : 
      96         104 :         if (tgss->error != 0) {
      97           0 :                 errno = tgss->error;
      98           0 :                 return -1;
      99             :         }
     100             : 
     101         104 :         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     3583976 : 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        2552 :         struct tstream_gensec *tgss =
     130     3583976 :                 tstream_context_data(stream,
     131             :                 struct tstream_gensec);
     132        2552 :         struct tevent_req *req;
     133        2552 :         struct tstream_gensec_readv_state *state;
     134             : 
     135     3583976 :         req = tevent_req_create(mem_ctx, &state,
     136             :                                 struct tstream_gensec_readv_state);
     137     3583976 :         if (!req) {
     138           0 :                 return NULL;
     139             :         }
     140             : 
     141     3583976 :         if (tgss->error != 0) {
     142           0 :                 tevent_req_error(req, tgss->error);
     143           0 :                 return tevent_req_post(req, ev);
     144             :         }
     145             : 
     146     3583976 :         state->ev = ev;
     147     3583976 :         state->stream = stream;
     148     3583976 :         state->ret = 0;
     149             : 
     150             :         /*
     151             :          * we make a copy of the vector so we can change the structure
     152             :          */
     153     3583976 :         state->vector = talloc_array(state, struct iovec, count);
     154     3583976 :         if (tevent_req_nomem(state->vector, req)) {
     155           0 :                 return tevent_req_post(req, ev);
     156             :         }
     157     3583976 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     158     3583976 :         state->count = count;
     159             : 
     160     3583976 :         tstream_gensec_readv_wrapped_next(req);
     161     3583976 :         if (!tevent_req_is_in_progress(req)) {
     162     2480206 :                 return tevent_req_post(req, ev);
     163             :         }
     164             : 
     165     1102718 :         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     4687660 : static void tstream_gensec_readv_wrapped_next(struct tevent_req *req)
     176             : {
     177        3482 :         struct tstream_gensec_readv_state *state =
     178     4687660 :                 tevent_req_data(req,
     179             :                 struct tstream_gensec_readv_state);
     180        3482 :         struct tstream_gensec *tgss =
     181     4687660 :                 tstream_context_data(state->stream,
     182             :                 struct tstream_gensec);
     183        3482 :         struct tevent_req *subreq;
     184             : 
     185             :         /*
     186             :          * copy the pending buffer first
     187             :          */
     188     8273019 :         while (tgss->read.left > 0 && state->count > 0) {
     189     3585359 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     190     3585359 :                 size_t len = MIN(tgss->read.left, state->vector[0].iov_len);
     191             : 
     192     3585359 :                 memcpy(base, tgss->read.unwrapped.data + tgss->read.ofs, len);
     193             : 
     194     3585359 :                 base += len;
     195     3585359 :                 state->vector[0].iov_base = (char *) base;
     196     3585359 :                 state->vector[0].iov_len -= len;
     197             : 
     198     3585359 :                 tgss->read.ofs += len;
     199     3585359 :                 tgss->read.left -= len;
     200             : 
     201     3585359 :                 if (state->vector[0].iov_len == 0) {
     202     3558388 :                         state->vector += 1;
     203     3558388 :                         state->count -= 1;
     204             :                 }
     205             : 
     206     3585359 :                 state->ret += len;
     207             :         }
     208             : 
     209     4687660 :         if (state->count == 0) {
     210     3558388 :                 tevent_req_done(req);
     211     3558388 :                 return;
     212             :         }
     213             : 
     214     1129272 :         data_blob_free(&tgss->read.unwrapped);
     215     1129272 :         ZERO_STRUCT(state->wrapped);
     216             : 
     217     1129272 :         subreq = tstream_readv_pdu_send(state, state->ev,
     218             :                                         tgss->plain_stream,
     219             :                                         tstream_gensec_readv_next_vector,
     220             :                                         state);
     221     1129272 :         if (tevent_req_nomem(subreq, req)) {
     222           0 :                 return;
     223             :         }
     224     1129272 :         tevent_req_set_callback(subreq, tstream_gensec_readv_wrapped_done, req);
     225             : }
     226             : 
     227     3336640 : 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        2912 :         struct tstream_gensec_readv_state *state =
     234     3336640 :                 talloc_get_type_abort(private_data,
     235             :                 struct tstream_gensec_readv_state);
     236        2912 :         struct iovec *vector;
     237     3336640 :         size_t count = 1;
     238             : 
     239             :         /* we need to get a message header */
     240     3336640 :         vector = talloc_array(mem_ctx, struct iovec, count);
     241     3336640 :         if (!vector) {
     242           0 :                 return -1;
     243             :         }
     244             : 
     245     3336640 :         if (!state->wrapped.asked_for_hdr) {
     246     1129272 :                 state->wrapped.asked_for_hdr = true;
     247     1129272 :                 vector[0].iov_base = (char *)state->wrapped.hdr;
     248     1129272 :                 vector[0].iov_len = sizeof(state->wrapped.hdr);
     249     2207368 :         } else if (!state->wrapped.asked_for_blob) {
     250         930 :                 uint32_t msg_len;
     251             : 
     252     1103684 :                 state->wrapped.asked_for_blob = true;
     253             : 
     254     1103684 :                 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     1103684 :                 if (msg_len > 0x0FFFFFFF) {
     261           0 :                         errno = EMSGSIZE;
     262           0 :                         return -1;
     263             :                 }
     264             : 
     265     1103684 :                 if (msg_len == 0) {
     266           0 :                         errno = EMSGSIZE;
     267           0 :                         return -1;
     268             :                 }
     269             : 
     270     1103684 :                 state->wrapped.blob = data_blob_talloc(state, NULL, msg_len);
     271     1103684 :                 if (state->wrapped.blob.data == NULL) {
     272           0 :                         return -1;
     273             :                 }
     274             : 
     275     1103684 :                 vector[0].iov_base = (char *)state->wrapped.blob.data;
     276     1103684 :                 vector[0].iov_len = state->wrapped.blob.length;
     277             :         } else {
     278     1103684 :                 *_vector = NULL;
     279     1103684 :                 *_count = 0;
     280     1103684 :                 return 0;
     281             :         }
     282             : 
     283     2232956 :         *_vector = vector;
     284     2232956 :         *_count = count;
     285     2232956 :         return 0;
     286             : }
     287             : 
     288     1129267 : static void tstream_gensec_readv_wrapped_done(struct tevent_req *subreq)
     289             : {
     290        1052 :         struct tevent_req *req =
     291     1129267 :                 tevent_req_callback_data(subreq,
     292             :                 struct tevent_req);
     293        1052 :         struct tstream_gensec_readv_state *state =
     294     1129267 :                 tevent_req_data(req,
     295             :                 struct tstream_gensec_readv_state);
     296        1052 :         struct tstream_gensec *tgss =
     297     1129267 :                 tstream_context_data(state->stream,
     298             :                 struct tstream_gensec);
     299        1052 :         int ret;
     300        1052 :         int sys_errno;
     301        1052 :         NTSTATUS status;
     302             : 
     303     1129267 :         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
     304     1129267 :         TALLOC_FREE(subreq);
     305     1129267 :         if (ret == -1) {
     306       25583 :                 tgss->error = sys_errno;
     307       25583 :                 tevent_req_error(req, sys_errno);
     308       25705 :                 return;
     309             :         }
     310             : 
     311     1103684 :         status = gensec_unwrap(tgss->gensec_security,
     312             :                                state,
     313     1103684 :                                &state->wrapped.blob,
     314             :                                &tgss->read.unwrapped);
     315     1103684 :         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     1103684 :         data_blob_free(&state->wrapped.blob);
     322             : 
     323     1103684 :         talloc_steal(tgss, tgss->read.unwrapped.data);
     324     1103684 :         tgss->read.left = tgss->read.unwrapped.length;
     325     1103684 :         tgss->read.ofs = 0;
     326             : 
     327     1103684 :         tstream_gensec_readv_wrapped_next(req);
     328             : }
     329             : 
     330     3583971 : static int tstream_gensec_readv_recv(struct tevent_req *req, int *perrno)
     331             : {
     332        2552 :         struct tstream_gensec_readv_state *state =
     333     3583971 :                 tevent_req_data(req,
     334             :                 struct tstream_gensec_readv_state);
     335        2552 :         int ret;
     336             : 
     337     3583971 :         ret = tsocket_simple_int_recv(req, perrno);
     338     3583971 :         if (ret == 0) {
     339     3558388 :                 ret = state->ret;
     340             :         }
     341             : 
     342     3583971 :         tevent_req_received(req);
     343     3583971 :         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     1076700 : 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         930 :         struct tstream_gensec *tgss =
     377     1076700 :                 tstream_context_data(stream,
     378             :                 struct tstream_gensec);
     379         930 :         struct tevent_req *req;
     380         930 :         struct tstream_gensec_writev_state *state;
     381         930 :         size_t i;
     382         930 :         int total;
     383         930 :         int chunk;
     384             : 
     385     1076700 :         req = tevent_req_create(mem_ctx, &state,
     386             :                                 struct tstream_gensec_writev_state);
     387     1076700 :         if (req == NULL) {
     388           0 :                 return NULL;
     389             :         }
     390             : 
     391     1076700 :         if (tgss->error != 0) {
     392           0 :                 tevent_req_error(req, tgss->error);
     393           0 :                 return tevent_req_post(req, ev);
     394             :         }
     395             : 
     396     1076700 :         state->ev = ev;
     397     1076700 :         state->stream = stream;
     398     1076700 :         state->ret = 0;
     399             : 
     400             :         /*
     401             :          * we make a copy of the vector so we can change the structure
     402             :          */
     403     1076700 :         state->vector = talloc_array(state, struct iovec, count);
     404     1076700 :         if (tevent_req_nomem(state->vector, req)) {
     405           0 :                 return tevent_req_post(req, ev);
     406             :         }
     407     1076700 :         memcpy(state->vector, vector, sizeof(struct iovec) * count);
     408     1076700 :         state->count = count;
     409             : 
     410     1076700 :         total = 0;
     411     2859812 :         for (i = 0; i < count; i++) {
     412             :                 /*
     413             :                  * the generic tstream code makes sure that
     414             :                  * this never wraps.
     415             :                  */
     416     1783112 :                 total += vector[i].iov_len;
     417             :         }
     418             : 
     419             :         /*
     420             :          * We may need to send data in chunks.
     421             :          */
     422     1076700 :         chunk = MIN(total, tgss->write.max_unwrapped_size);
     423             : 
     424     1076700 :         state->unwrapped.blob = data_blob_talloc(state, NULL, chunk);
     425     1076700 :         if (tevent_req_nomem(state->unwrapped.blob.data, req)) {
     426           0 :                 return tevent_req_post(req, ev);
     427             :         }
     428             : 
     429     1076700 :         tstream_gensec_writev_wrapped_next(req);
     430     1076700 :         if (!tevent_req_is_in_progress(req)) {
     431           0 :                 return tevent_req_post(req, ev);
     432             :         }
     433             : 
     434     1075770 :         return req;
     435             : }
     436             : 
     437             : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq);
     438             : 
     439     2180370 : static void tstream_gensec_writev_wrapped_next(struct tevent_req *req)
     440             : {
     441        1860 :         struct tstream_gensec_writev_state *state =
     442     2180370 :                 tevent_req_data(req,
     443             :                 struct tstream_gensec_writev_state);
     444        1860 :         struct tstream_gensec *tgss =
     445     2180370 :                 tstream_context_data(state->stream,
     446             :                 struct tstream_gensec);
     447        1860 :         struct tevent_req *subreq;
     448        1860 :         NTSTATUS status;
     449             : 
     450     2180370 :         data_blob_free(&state->wrapped.blob);
     451             : 
     452     2180370 :         state->unwrapped.left = state->unwrapped.blob.length;
     453     2180370 :         state->unwrapped.ofs = 0;
     454             : 
     455             :         /*
     456             :          * first fill our buffer
     457             :          */
     458     3990453 :         while (state->unwrapped.left > 0 && state->count > 0) {
     459     1810083 :                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
     460     1810083 :                 size_t len = MIN(state->unwrapped.left, state->vector[0].iov_len);
     461             : 
     462     1810083 :                 memcpy(state->unwrapped.blob.data + state->unwrapped.ofs, base, len);
     463             : 
     464     1810083 :                 base += len;
     465     1810083 :                 state->vector[0].iov_base = (char *) base;
     466     1810083 :                 state->vector[0].iov_len -= len;
     467             : 
     468     1810083 :                 state->unwrapped.ofs += len;
     469     1810083 :                 state->unwrapped.left -= len;
     470             : 
     471     1810083 :                 if (state->vector[0].iov_len == 0) {
     472     1783112 :                         state->vector += 1;
     473     1783112 :                         state->count -= 1;
     474             :                 }
     475             : 
     476     1810083 :                 state->ret += len;
     477             :         }
     478             : 
     479     2180370 :         if (state->unwrapped.ofs == 0) {
     480     1076699 :                 tevent_req_done(req);
     481     1077629 :                 return;
     482             :         }
     483             : 
     484     1103671 :         state->unwrapped.blob.length = state->unwrapped.ofs;
     485             : 
     486     1103671 :         status = gensec_wrap(tgss->gensec_security,
     487             :                              state,
     488     1103671 :                              &state->unwrapped.blob,
     489             :                              &state->wrapped.blob);
     490     1103671 :         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     1103671 :         RSIVAL(state->wrapped.hdr, 0, state->wrapped.blob.length);
     497             : 
     498     1103671 :         state->wrapped.iov[0].iov_base = (void *)state->wrapped.hdr;
     499     1103671 :         state->wrapped.iov[0].iov_len = sizeof(state->wrapped.hdr);
     500     1103671 :         state->wrapped.iov[1].iov_base = (void *)state->wrapped.blob.data;
     501     1103671 :         state->wrapped.iov[1].iov_len = state->wrapped.blob.length;
     502             : 
     503     1104601 :         subreq = tstream_writev_send(state, state->ev,
     504             :                                       tgss->plain_stream,
     505     1103671 :                                       state->wrapped.iov, 2);
     506     1103671 :         if (tevent_req_nomem(subreq, req)) {
     507           0 :                 return;
     508             :         }
     509     1103671 :         tevent_req_set_callback(subreq,
     510             :                                 tstream_gensec_writev_wrapped_done,
     511             :                                 req);
     512             : }
     513             : 
     514     1103670 : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq)
     515             : {
     516         930 :         struct tevent_req *req =
     517     1103670 :                 tevent_req_callback_data(subreq,
     518             :                 struct tevent_req);
     519         930 :         struct tstream_gensec_writev_state *state =
     520     1103670 :                 tevent_req_data(req,
     521             :                 struct tstream_gensec_writev_state);
     522         930 :         struct tstream_gensec *tgss =
     523     1103670 :                 tstream_context_data(state->stream,
     524             :                 struct tstream_gensec);
     525         930 :         int sys_errno;
     526         930 :         int ret;
     527             : 
     528     1103670 :         ret = tstream_writev_recv(subreq, &sys_errno);
     529     1103670 :         TALLOC_FREE(subreq);
     530     1103670 :         if (ret == -1) {
     531           0 :                 tgss->error = sys_errno;
     532           0 :                 tevent_req_error(req, sys_errno);
     533           0 :                 return;
     534             :         }
     535             : 
     536     1103670 :         tstream_gensec_writev_wrapped_next(req);
     537             : }
     538             : 
     539     1076699 : static int tstream_gensec_writev_recv(struct tevent_req *req,
     540             :                                    int *perrno)
     541             : {
     542         930 :         struct tstream_gensec_writev_state *state =
     543     1076699 :                 tevent_req_data(req,
     544             :                 struct tstream_gensec_writev_state);
     545         930 :         int ret;
     546             : 
     547     1076699 :         ret = tsocket_simple_int_recv(req, perrno);
     548     1076699 :         if (ret == 0) {
     549     1076699 :                 ret = state->ret;
     550             :         }
     551             : 
     552     1076699 :         tevent_req_received(req);
     553     1076699 :         return ret;
     554             : }
     555             : 
     556             : struct tstream_gensec_disconnect_state {
     557             :         uint8_t _dummy;
     558             : };
     559             : 
     560       25599 : static struct tevent_req *tstream_gensec_disconnect_send(TALLOC_CTX *mem_ctx,
     561             :                                                          struct tevent_context *ev,
     562             :                                                          struct tstream_context *stream)
     563             : {
     564         122 :         struct tstream_gensec *tgss =
     565       25599 :                 tstream_context_data(stream,
     566             :                 struct tstream_gensec);
     567         122 :         struct tevent_req *req;
     568         122 :         struct tstream_gensec_disconnect_state *state;
     569             : 
     570       25599 :         req = tevent_req_create(mem_ctx, &state,
     571             :                                 struct tstream_gensec_disconnect_state);
     572       25599 :         if (req == NULL) {
     573           0 :                 return NULL;
     574             :         }
     575             : 
     576       25599 :         if (tgss->error != 0) {
     577       25583 :                 tevent_req_error(req, tgss->error);
     578       25583 :                 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          16 :         tgss->plain_stream = NULL;
     586          16 :         tgss->error = ENOTCONN;
     587             : 
     588          16 :         tevent_req_done(req);
     589          16 :         return tevent_req_post(req, ev);
     590             : }
     591             : 
     592       25599 : static int tstream_gensec_disconnect_recv(struct tevent_req *req,
     593             :                                        int *perrno)
     594             : {
     595         122 :         int ret;
     596             : 
     597       25599 :         ret = tsocket_simple_int_recv(req, perrno);
     598             : 
     599       25599 :         tevent_req_received(req);
     600       25599 :         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.14