LCOV - code coverage report
Current view: top level - nsswitch - wb_reqtrans.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 150 178 84.3 %
Date: 2021-09-23 10:06:22 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Async transfer of winbindd_request and _response structs
       5             : 
       6             :    Copyright (C) Volker Lendecke 2008
       7             : 
       8             :      ** NOTE! The following LGPL license applies to the wbclient
       9             :      ** library. This does NOT imply that all of Samba is released
      10             :      ** under the LGPL
      11             : 
      12             :    This library is free software; you can redistribute it and/or
      13             :    modify it under the terms of the GNU Lesser General Public
      14             :    License as published by the Free Software Foundation; either
      15             :    version 3 of the License, or (at your option) any later version.
      16             : 
      17             :    This library is distributed in the hope that it will be useful,
      18             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      20             :    Library General Public License for more details.
      21             : 
      22             :    You should have received a copy of the GNU Lesser General Public License
      23             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : 
      26             : #include "replace.h"
      27             : #include "system/filesys.h"
      28             : #include "system/network.h"
      29             : #include <talloc.h>
      30             : #include <tevent.h>
      31             : #include "lib/async_req/async_sock.h"
      32             : #include "lib/util/tevent_unix.h"
      33             : #include "nsswitch/winbind_struct_protocol.h"
      34             : #include "nsswitch/libwbclient/wbclient.h"
      35             : #include "nsswitch/wb_reqtrans.h"
      36             : 
      37             : /* can't use DEBUG here... */
      38             : #define DEBUG(a,b)
      39             : 
      40             : struct req_read_state {
      41             :         struct winbindd_request *wb_req;
      42             :         size_t max_extra_data;
      43             :         ssize_t ret;
      44             : };
      45             : 
      46             : static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data);
      47             : static void wb_req_read_done(struct tevent_req *subreq);
      48             : 
      49      202914 : struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
      50             :                                     struct tevent_context *ev,
      51             :                                     int fd, size_t max_extra_data)
      52             : {
      53             :         struct tevent_req *req, *subreq;
      54             :         struct req_read_state *state;
      55             : 
      56      202914 :         req = tevent_req_create(mem_ctx, &state, struct req_read_state);
      57      202914 :         if (req == NULL) {
      58           0 :                 return NULL;
      59             :         }
      60      202914 :         state->max_extra_data = max_extra_data;
      61             : 
      62      202914 :         subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
      63      202914 :         if (tevent_req_nomem(subreq, req)) {
      64           0 :                 return tevent_req_post(req, ev);
      65             :         }
      66      202914 :         tevent_req_set_callback(subreq, wb_req_read_done, req);
      67      202914 :         return req;
      68             : }
      69             : 
      70      409625 : static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
      71             : {
      72      409625 :         struct req_read_state *state = talloc_get_type_abort(
      73             :                 private_data, struct req_read_state);
      74      409625 :         struct winbindd_request *req = (struct winbindd_request *)buf;
      75             : 
      76      409625 :         if (buflen == 4) {
      77      193292 :                 if (req->length != sizeof(struct winbindd_request)) {
      78             :                         DEBUG(0, ("wb_req_read_len: Invalid request size "
      79             :                                   "received: %d (expected %d)\n",
      80             :                                   (int)req->length,
      81             :                                   (int)sizeof(struct winbindd_request)));
      82           0 :                         return -1;
      83             :                 }
      84      193292 :                 return sizeof(struct winbindd_request) - 4;
      85             :         }
      86             : 
      87      216333 :         if (buflen > sizeof(struct winbindd_request)) {
      88             :                 /* We've been here, we're done */
      89       23039 :                 return 0;
      90             :         }
      91             : 
      92      193292 :         if ((state->max_extra_data != 0)
      93      193292 :             && (req->extra_len > state->max_extra_data)) {
      94             :                 DEBUG(3, ("Got request with %d bytes extra data on "
      95             :                           "unprivileged socket\n", (int)req->extra_len));
      96           0 :                 return -1;
      97             :         }
      98             : 
      99      193292 :         return req->extra_len;
     100             : }
     101             : 
     102      202724 : static void wb_req_read_done(struct tevent_req *subreq)
     103             : {
     104      202724 :         struct tevent_req *req = tevent_req_callback_data(
     105             :                 subreq, struct tevent_req);
     106      202724 :         struct req_read_state *state = tevent_req_data(
     107             :                 req, struct req_read_state);
     108             :         int err;
     109             :         uint8_t *buf;
     110             : 
     111      202724 :         state->ret = read_packet_recv(subreq, state, &buf, &err);
     112      202724 :         TALLOC_FREE(subreq);
     113      202724 :         if (state->ret == -1) {
     114        9432 :                 tevent_req_error(req, err);
     115        9432 :                 return;
     116             :         }
     117             : 
     118      193292 :         state->wb_req = (struct winbindd_request *)buf;
     119             : 
     120      193292 :         if (state->wb_req->extra_len != 0) {
     121       45703 :                 state->wb_req->extra_data.data =
     122       45703 :                         (char *)buf + sizeof(struct winbindd_request);
     123             :         } else {
     124      170251 :                 state->wb_req->extra_data.data = NULL;
     125             :         }
     126      193292 :         tevent_req_done(req);
     127             : }
     128             : 
     129      202724 : ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     130             :                          struct winbindd_request **preq, int *err)
     131             : {
     132      202724 :         struct req_read_state *state = tevent_req_data(
     133             :                 req, struct req_read_state);
     134             : 
     135      202724 :         if (tevent_req_is_unix_error(req, err)) {
     136        9430 :                 return -1;
     137             :         }
     138      193292 :         *preq = talloc_move(mem_ctx, &state->wb_req);
     139      193292 :         return state->ret;
     140             : }
     141             : 
     142             : struct req_write_state {
     143             :         struct iovec iov[2];
     144             :         ssize_t ret;
     145             : };
     146             : 
     147             : static void wb_req_write_done(struct tevent_req *subreq);
     148             : 
     149       91020 : struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
     150             :                                      struct tevent_context *ev,
     151             :                                      struct tevent_queue *queue, int fd,
     152             :                                      struct winbindd_request *wb_req)
     153             : {
     154             :         struct tevent_req *req, *subreq;
     155             :         struct req_write_state *state;
     156       91020 :         int count = 1;
     157             : 
     158       91020 :         req = tevent_req_create(mem_ctx, &state, struct req_write_state);
     159       91020 :         if (req == NULL) {
     160           0 :                 return NULL;
     161             :         }
     162             : 
     163       91020 :         state->iov[0].iov_base = (void *)wb_req;
     164       91020 :         state->iov[0].iov_len = sizeof(struct winbindd_request);
     165             : 
     166       91020 :         if (wb_req->extra_len != 0) {
     167       87804 :                 state->iov[1].iov_base = (void *)wb_req->extra_data.data;
     168       87804 :                 state->iov[1].iov_len = wb_req->extra_len;
     169       87804 :                 count = 2;
     170             :         }
     171             : 
     172       91020 :         subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
     173       91020 :         if (tevent_req_nomem(subreq, req)) {
     174           0 :                 return tevent_req_post(req, ev);
     175             :         }
     176       91020 :         tevent_req_set_callback(subreq, wb_req_write_done, req);
     177       91020 :         return req;
     178             : }
     179             : 
     180       91019 : static void wb_req_write_done(struct tevent_req *subreq)
     181             : {
     182       91019 :         struct tevent_req *req = tevent_req_callback_data(
     183             :                 subreq, struct tevent_req);
     184       91019 :         struct req_write_state *state = tevent_req_data(
     185             :                 req, struct req_write_state);
     186             :         int err;
     187             : 
     188       91019 :         state->ret = writev_recv(subreq, &err);
     189       91019 :         TALLOC_FREE(subreq);
     190       91019 :         if (state->ret < 0) {
     191           0 :                 tevent_req_error(req, err);
     192           0 :                 return;
     193             :         }
     194       91019 :         tevent_req_done(req);
     195             : }
     196             : 
     197       91019 : ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
     198             : {
     199       91019 :         struct req_write_state *state = tevent_req_data(
     200             :                 req, struct req_write_state);
     201             : 
     202       91019 :         if (tevent_req_is_unix_error(req, err)) {
     203           0 :                 return -1;
     204             :         }
     205       91019 :         return state->ret;
     206             : }
     207             : 
     208             : struct resp_read_state {
     209             :         struct winbindd_response *wb_resp;
     210             :         ssize_t ret;
     211             : };
     212             : 
     213             : static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
     214             : static void wb_resp_read_done(struct tevent_req *subreq);
     215             : 
     216       91019 : struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
     217             :                                      struct tevent_context *ev, int fd)
     218             : {
     219             :         struct tevent_req *req, *subreq;
     220             :         struct resp_read_state *state;
     221             : 
     222       91019 :         req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
     223       91019 :         if (req == NULL) {
     224           0 :                 return NULL;
     225             :         }
     226             : 
     227       91019 :         subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
     228       91019 :         if (tevent_req_nomem(subreq, req)) {
     229           0 :                 return tevent_req_post(req, ev);
     230             :         }
     231       91019 :         tevent_req_set_callback(subreq, wb_resp_read_done, req);
     232       91019 :         return req;
     233             : }
     234             : 
     235      182038 : static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
     236             : {
     237      182038 :         struct winbindd_response *resp = (struct winbindd_response *)buf;
     238             : 
     239      182038 :         if (buflen == 4) {
     240       91019 :                 if (resp->length < sizeof(struct winbindd_response)) {
     241             :                         DEBUG(0, ("wb_resp_read_len: Invalid response size "
     242             :                                   "received: %d (expected at least%d)\n",
     243             :                                   (int)resp->length,
     244             :                                   (int)sizeof(struct winbindd_response)));
     245           0 :                         return -1;
     246             :                 }
     247             :         }
     248      182038 :         return resp->length - buflen;
     249             : }
     250             : 
     251       91019 : static void wb_resp_read_done(struct tevent_req *subreq)
     252             : {
     253       91019 :         struct tevent_req *req = tevent_req_callback_data(
     254             :                 subreq, struct tevent_req);
     255       91019 :         struct resp_read_state *state = tevent_req_data(
     256             :                 req, struct resp_read_state);
     257             :         uint8_t *buf;
     258             :         int err;
     259             : 
     260       91019 :         state->ret = read_packet_recv(subreq, state, &buf, &err);
     261       91019 :         TALLOC_FREE(subreq);
     262       91019 :         if (state->ret == -1) {
     263           0 :                 tevent_req_error(req, err);
     264           0 :                 return;
     265             :         }
     266             : 
     267       91019 :         state->wb_resp = (struct winbindd_response *)buf;
     268             : 
     269       91019 :         if (state->wb_resp->length > sizeof(struct winbindd_response)) {
     270      178019 :                 state->wb_resp->extra_data.data =
     271      178019 :                         (char *)buf + sizeof(struct winbindd_response);
     272             :         } else {
     273         981 :                 state->wb_resp->extra_data.data = NULL;
     274             :         }
     275       91019 :         tevent_req_done(req);
     276             : }
     277             : 
     278       91019 : ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     279             :                           struct winbindd_response **presp, int *err)
     280             : {
     281       91019 :         struct resp_read_state *state = tevent_req_data(
     282             :                 req, struct resp_read_state);
     283             : 
     284       91019 :         if (tevent_req_is_unix_error(req, err)) {
     285           0 :                 return -1;
     286             :         }
     287       91019 :         *presp = talloc_move(mem_ctx, &state->wb_resp);
     288       91019 :         return state->ret;
     289             : }
     290             : 
     291             : struct resp_write_state {
     292             :         struct iovec iov[2];
     293             :         ssize_t ret;
     294             : };
     295             : 
     296             : static void wb_resp_write_done(struct tevent_req *subreq);
     297             : 
     298      193277 : struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
     299             :                                       struct tevent_context *ev,
     300             :                                       struct tevent_queue *queue, int fd,
     301             :                                       struct winbindd_response *wb_resp)
     302             : {
     303             :         struct tevent_req *req, *subreq;
     304             :         struct resp_write_state *state;
     305      193277 :         int count = 1;
     306             : 
     307      193277 :         req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
     308      193277 :         if (req == NULL) {
     309           0 :                 return NULL;
     310             :         }
     311             : 
     312      193277 :         state->iov[0].iov_base = (void *)wb_resp;
     313      193277 :         state->iov[0].iov_len = sizeof(struct winbindd_response);
     314             : 
     315      193277 :         if (wb_resp->length > sizeof(struct winbindd_response)) {
     316       25386 :                 state->iov[1].iov_base = (void *)wb_resp->extra_data.data;
     317       49884 :                 state->iov[1].iov_len =
     318       49884 :                         wb_resp->length - sizeof(struct winbindd_response);
     319       25386 :                 count = 2;
     320             :         }
     321             : 
     322      193277 :         subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
     323      193277 :         if (tevent_req_nomem(subreq, req)) {
     324           0 :                 return tevent_req_post(req, ev);
     325             :         }
     326      193277 :         tevent_req_set_callback(subreq, wb_resp_write_done, req);
     327      193277 :         return req;
     328             : }
     329             : 
     330      193277 : static void wb_resp_write_done(struct tevent_req *subreq)
     331             : {
     332      193277 :         struct tevent_req *req = tevent_req_callback_data(
     333             :                 subreq, struct tevent_req);
     334      193277 :         struct resp_write_state *state = tevent_req_data(
     335             :                 req, struct resp_write_state);
     336             :         int err;
     337             : 
     338      193277 :         state->ret = writev_recv(subreq, &err);
     339      193277 :         TALLOC_FREE(subreq);
     340      193277 :         if (state->ret < 0) {
     341           0 :                 tevent_req_error(req, err);
     342           0 :                 return;
     343             :         }
     344      193277 :         tevent_req_done(req);
     345             : }
     346             : 
     347      193277 : ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
     348             : {
     349      193277 :         struct resp_write_state *state = tevent_req_data(
     350             :                 req, struct resp_write_state);
     351             : 
     352      193277 :         if (tevent_req_is_unix_error(req, err)) {
     353           0 :                 return -1;
     354             :         }
     355      193277 :         return state->ret;
     356             : }
     357             : 
     358             : struct wb_simple_trans_state {
     359             :         struct tevent_context *ev;
     360             :         int fd;
     361             :         struct winbindd_response *wb_resp;
     362             : };
     363             : 
     364             : static void wb_simple_trans_write_done(struct tevent_req *subreq);
     365             : static void wb_simple_trans_read_done(struct tevent_req *subreq);
     366             : 
     367       91020 : struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx,
     368             :                                         struct tevent_context *ev,
     369             :                                         struct tevent_queue *queue, int fd,
     370             :                                         struct winbindd_request *wb_req)
     371             : {
     372             :         struct tevent_req *req, *subreq;
     373             :         struct wb_simple_trans_state *state;
     374             : 
     375       91020 :         req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
     376       91020 :         if (req == NULL) {
     377           0 :                 return NULL;
     378             :         }
     379             : 
     380       91020 :         wb_req->length = sizeof(struct winbindd_request);
     381             : 
     382       91020 :         state->ev = ev;
     383       91020 :         state->fd = fd;
     384             : 
     385       91020 :         subreq = wb_req_write_send(state, ev, queue, fd, wb_req);
     386       91020 :         if (tevent_req_nomem(subreq, req)) {
     387           0 :                 return tevent_req_post(req, ev);
     388             :         }
     389       91020 :         tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
     390             : 
     391       91020 :         return req;
     392             : }
     393             : 
     394       91019 : static void wb_simple_trans_write_done(struct tevent_req *subreq)
     395             : {
     396       91019 :         struct tevent_req *req = tevent_req_callback_data(
     397             :                 subreq, struct tevent_req);
     398       91019 :         struct wb_simple_trans_state *state = tevent_req_data(
     399             :                 req, struct wb_simple_trans_state);
     400             :         ssize_t ret;
     401             :         int err;
     402             : 
     403       91019 :         ret = wb_req_write_recv(subreq, &err);
     404       91019 :         TALLOC_FREE(subreq);
     405       91019 :         if (ret == -1) {
     406           0 :                 tevent_req_error(req, err);
     407           0 :                 return;
     408             :         }
     409       91019 :         subreq = wb_resp_read_send(state, state->ev, state->fd);
     410       91019 :         if (tevent_req_nomem(subreq, req)) {
     411           0 :                 return;
     412             :         }
     413       91019 :         tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
     414             : }
     415             : 
     416       91019 : static void wb_simple_trans_read_done(struct tevent_req *subreq)
     417             : {
     418       91019 :         struct tevent_req *req = tevent_req_callback_data(
     419             :                 subreq, struct tevent_req);
     420       91019 :         struct wb_simple_trans_state *state = tevent_req_data(
     421             :                 req, struct wb_simple_trans_state);
     422             :         ssize_t ret;
     423             :         int err;
     424             : 
     425       91019 :         ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
     426       91019 :         TALLOC_FREE(subreq);
     427       91019 :         if (ret == -1) {
     428           0 :                 tevent_req_error(req, err);
     429           0 :                 return;
     430             :         }
     431             : 
     432       91019 :         tevent_req_done(req);
     433             : }
     434             : 
     435       91019 : int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     436             :                          struct winbindd_response **presponse, int *err)
     437             : {
     438       91019 :         struct wb_simple_trans_state *state = tevent_req_data(
     439             :                 req, struct wb_simple_trans_state);
     440             : 
     441       91019 :         if (tevent_req_is_unix_error(req, err)) {
     442           0 :                 return -1;
     443             :         }
     444       91019 :         *presponse = talloc_move(mem_ctx, &state->wb_resp);
     445       91019 :         return 0;
     446             : }

Generated by: LCOV version 1.13