LCOV - code coverage report
Current view: top level - source3/torture - wbc_async.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 192 371 51.8 %
Date: 2024-04-21 15:09:00 Functions: 22 28 78.6 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Infrastructure for async winbind requests
       4             :    Copyright (C) Volker Lendecke 2008
       5             : 
       6             :      ** NOTE! The following LGPL license applies to the wbclient
       7             :      ** library. This does NOT imply that all of Samba is released
       8             :      ** under the LGPL
       9             : 
      10             :    This library is free software; you can redistribute it and/or
      11             :    modify it under the terms of the GNU Lesser General Public
      12             :    License as published by the Free Software Foundation; either
      13             :    version 3 of the License, or (at your option) any later version.
      14             : 
      15             :    This library is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18             :    Library General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU Lesser General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "replace.h"
      25             : #include "system/filesys.h"
      26             : #include "system/network.h"
      27             : #include <talloc.h>
      28             : #include <tevent.h>
      29             : #include "lib/async_req/async_sock.h"
      30             : #include "nsswitch/winbind_struct_protocol.h"
      31             : #include "nsswitch/libwbclient/wbclient.h"
      32             : #include "wbc_async.h"
      33             : #include "lib/util/blocking.h"
      34             : 
      35           0 : wbcErr map_wbc_err_from_errno(int error)
      36             : {
      37           0 :         switch(error) {
      38           0 :         case EPERM:
      39             :         case EACCES:
      40           0 :                 return WBC_ERR_AUTH_ERROR;
      41           0 :         case ENOMEM:
      42           0 :                 return WBC_ERR_NO_MEMORY;
      43           0 :         case EIO:
      44             :         default:
      45           0 :                 return WBC_ERR_UNKNOWN_FAILURE;
      46             :         }
      47             : }
      48             : 
      49         206 : bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err)
      50             : {
      51           0 :         enum tevent_req_state state;
      52           0 :         uint64_t error;
      53         206 :         if (!tevent_req_is_error(req, &state, &error)) {
      54         206 :                 *pwbc_err = WBC_ERR_SUCCESS;
      55         206 :                 return false;
      56             :         }
      57             : 
      58           0 :         switch (state) {
      59           0 :         case TEVENT_REQ_USER_ERROR:
      60           0 :                 *pwbc_err = error;
      61           0 :                 break;
      62           0 :         case TEVENT_REQ_TIMED_OUT:
      63           0 :                 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
      64           0 :                 break;
      65           0 :         case TEVENT_REQ_NO_MEMORY:
      66           0 :                 *pwbc_err = WBC_ERR_NO_MEMORY;
      67           0 :                 break;
      68           0 :         default:
      69           0 :                 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
      70           0 :                 break;
      71             :         }
      72           0 :         return true;
      73             : }
      74             : 
      75           6 : wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req)
      76             : {
      77           0 :         wbcErr wbc_err;
      78             : 
      79           6 :         if (tevent_req_is_wbcerr(req, &wbc_err)) {
      80           0 :                 return wbc_err;
      81             :         }
      82             : 
      83           6 :         return WBC_ERR_SUCCESS;
      84             : }
      85             : 
      86             : struct wbc_debug_ops {
      87             :         void (*debug)(void *context, enum wbcDebugLevel level,
      88             :                       const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
      89             :         void *context;
      90             : };
      91             : 
      92             : struct wb_context {
      93             :         struct tevent_queue *queue;
      94             :         int fd;
      95             :         bool is_priv;
      96             :         const char *dir;
      97             :         struct wbc_debug_ops debug_ops;
      98             : };
      99             : 
     100           4 : static int make_nonstd_fd(int fd)
     101             : {
     102           0 :         size_t i;
     103           4 :         int sys_errno = 0;
     104           0 :         int fds[3];
     105           4 :         size_t num_fds = 0;
     106             : 
     107           4 :         if (fd == -1) {
     108           0 :                 return -1;
     109             :         }
     110           4 :         while (fd < 3) {
     111           0 :                 fds[num_fds++] = fd;
     112           0 :                 fd = dup(fd);
     113           0 :                 if (fd == -1) {
     114           0 :                         sys_errno = errno;
     115           0 :                         break;
     116             :                 }
     117             :         }
     118           4 :         for (i=0; i<num_fds; i++) {
     119           0 :                 close(fds[i]);
     120             :         }
     121           4 :         if (fd == -1) {
     122           0 :                 errno = sys_errno;
     123             :         }
     124           4 :         return fd;
     125             : }
     126             : 
     127             : /****************************************************************************
     128             :  Set a fd into blocking/nonblocking mode.
     129             :  Set close on exec also.
     130             : ****************************************************************************/
     131             : 
     132           4 : static int make_safe_fd(int fd)
     133             : {
     134           0 :         int result, flags;
     135           4 :         int new_fd = make_nonstd_fd(fd);
     136             : 
     137           4 :         if (new_fd == -1) {
     138           0 :                 goto fail;
     139             :         }
     140             : 
     141           4 :         result = set_blocking(new_fd, false);
     142           4 :         if (result == -1) {
     143           0 :                 goto fail;
     144             :         }
     145             : 
     146             :         /* Socket should be closed on exec() */
     147             : #ifdef FD_CLOEXEC
     148           4 :         result = flags = fcntl(new_fd, F_GETFD, 0);
     149           4 :         if (flags >= 0) {
     150           4 :                 flags |= FD_CLOEXEC;
     151           4 :                 result = fcntl( new_fd, F_SETFD, flags );
     152             :         }
     153           4 :         if (result < 0) {
     154           0 :                 goto fail;
     155             :         }
     156             : #endif
     157           4 :         return new_fd;
     158             : 
     159           0 :  fail:
     160           0 :         if (new_fd != -1) {
     161           0 :                 int sys_errno = errno;
     162           0 :                 close(new_fd);
     163           0 :                 errno = sys_errno;
     164             :         }
     165           0 :         return -1;
     166             : }
     167             : 
     168             : /* Just put a prototype to avoid moving the whole function around */
     169             : static const char *winbindd_socket_dir(void);
     170             : 
     171           2 : struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx, const char* dir)
     172             : {
     173           0 :         struct wb_context *result;
     174             : 
     175           2 :         result = talloc_zero(mem_ctx, struct wb_context);
     176           2 :         if (result == NULL) {
     177           0 :                 return NULL;
     178             :         }
     179           2 :         result->queue = tevent_queue_create(result, "wb_trans");
     180           2 :         if (result->queue == NULL) {
     181           0 :                 TALLOC_FREE(result);
     182           0 :                 return NULL;
     183             :         }
     184           2 :         result->fd = -1;
     185           2 :         result->is_priv = false;
     186             : 
     187           2 :         if (dir != NULL) {
     188           0 :                 result->dir = talloc_strdup(result, dir);
     189             :         } else {
     190           2 :                 result->dir = winbindd_socket_dir();
     191             :         }
     192           2 :         if (result->dir == NULL) {
     193           0 :                 TALLOC_FREE(result);
     194           0 :                 return NULL;
     195             :         }
     196           2 :         return result;
     197             : }
     198             : 
     199             : struct wb_connect_state {
     200             :         int dummy;
     201             : };
     202             : 
     203             : static void wbc_connect_connected(struct tevent_req *subreq);
     204             : 
     205           4 : static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx,
     206             :                                           struct tevent_context *ev,
     207             :                                           struct wb_context *wb_ctx,
     208             :                                           const char *dir)
     209             : {
     210           0 :         struct tevent_req *result, *subreq;
     211           0 :         struct wb_connect_state *state;
     212           0 :         struct sockaddr_un sunaddr;
     213           0 :         struct stat st;
     214           4 :         char *path = NULL;
     215           0 :         wbcErr wbc_err;
     216             : 
     217           4 :         result = tevent_req_create(mem_ctx, &state, struct wb_connect_state);
     218           4 :         if (result == NULL) {
     219           0 :                 return NULL;
     220             :         }
     221             : 
     222           4 :         if (wb_ctx->fd != -1) {
     223           0 :                 close(wb_ctx->fd);
     224           0 :                 wb_ctx->fd = -1;
     225             :         }
     226             : 
     227             :         /* Check permissions on unix socket directory */
     228             : 
     229           4 :         if (lstat(dir, &st) == -1) {
     230           0 :                 wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
     231           0 :                 goto post_status;
     232             :         }
     233             : 
     234           4 :         if (!S_ISDIR(st.st_mode) ||
     235           4 :             (st.st_uid != 0 && st.st_uid != geteuid())) {
     236           0 :                 wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
     237           0 :                 goto post_status;
     238             :         }
     239             : 
     240             :         /* Connect to socket */
     241             : 
     242           4 :         path = talloc_asprintf(mem_ctx, "%s/%s", dir,
     243             :                                WINBINDD_SOCKET_NAME);
     244           4 :         if (path == NULL) {
     245           0 :                 goto nomem;
     246             :         }
     247             : 
     248           4 :         sunaddr.sun_family = AF_UNIX;
     249           4 :         strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
     250           4 :         TALLOC_FREE(path);
     251             : 
     252             :         /* If socket file doesn't exist, don't bother trying to connect
     253             :            with retry.  This is an attempt to make the system usable when
     254             :            the winbindd daemon is not running. */
     255             : 
     256           4 :         if ((lstat(sunaddr.sun_path, &st) == -1)
     257           4 :             || !S_ISSOCK(st.st_mode)
     258           4 :             || (st.st_uid != 0 && st.st_uid != geteuid())) {
     259           0 :                 wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
     260           0 :                 goto post_status;
     261             :         }
     262             : 
     263           4 :         wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0));
     264           4 :         if (wb_ctx->fd == -1) {
     265           0 :                 wbc_err = map_wbc_err_from_errno(errno);
     266           0 :                 goto post_status;
     267             :         }
     268             : 
     269           4 :         subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd,
     270             :                                     (struct sockaddr *)(void *)&sunaddr,
     271             :                                     sizeof(sunaddr), NULL, NULL, NULL);
     272           4 :         if (subreq == NULL) {
     273           0 :                 goto nomem;
     274             :         }
     275           4 :         tevent_req_set_callback(subreq, wbc_connect_connected, result);
     276           4 :         return result;
     277             : 
     278           0 :  post_status:
     279           0 :         tevent_req_error(result, wbc_err);
     280           0 :         return tevent_req_post(result, ev);
     281           0 :  nomem:
     282           0 :         TALLOC_FREE(result);
     283           0 :         return NULL;
     284             : }
     285             : 
     286           4 : static void wbc_connect_connected(struct tevent_req *subreq)
     287             : {
     288           4 :         struct tevent_req *req = tevent_req_callback_data(
     289             :                 subreq, struct tevent_req);
     290           0 :         int res, err;
     291             : 
     292           4 :         res = async_connect_recv(subreq, &err);
     293           4 :         TALLOC_FREE(subreq);
     294           4 :         if (res == -1) {
     295           0 :                 tevent_req_error(req, map_wbc_err_from_errno(err));
     296           0 :                 return;
     297             :         }
     298           4 :         tevent_req_done(req);
     299             : }
     300             : 
     301           4 : static wbcErr wb_connect_recv(struct tevent_req *req)
     302             : {
     303           4 :         return tevent_req_simple_recv_wbcerr(req);
     304             : }
     305             : 
     306           2 : static const char *winbindd_socket_dir(void)
     307             : {
     308           2 :         if (nss_wrapper_enabled()) {
     309           0 :                 const char *env_dir;
     310             : 
     311           2 :                 env_dir = getenv("SELFTEST_WINBINDD_SOCKET_DIR");
     312           2 :                 if (env_dir != NULL) {
     313           2 :                         return env_dir;
     314             :                 }
     315             :         }
     316             : 
     317           0 :         return WINBINDD_SOCKET_DIR;
     318             : }
     319             : 
     320             : struct wb_open_pipe_state {
     321             :         struct wb_context *wb_ctx;
     322             :         struct tevent_context *ev;
     323             :         bool need_priv;
     324             :         struct winbindd_request wb_req;
     325             : };
     326             : 
     327             : static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq);
     328             : static void wb_open_pipe_ping_done(struct tevent_req *subreq);
     329             : static void wb_open_pipe_getpriv_done(struct tevent_req *subreq);
     330             : static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq);
     331             : 
     332           2 : static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
     333             :                                             struct tevent_context *ev,
     334             :                                             struct wb_context *wb_ctx,
     335             :                                             bool need_priv)
     336             : {
     337           0 :         struct tevent_req *result, *subreq;
     338           0 :         struct wb_open_pipe_state *state;
     339             : 
     340           2 :         result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state);
     341           2 :         if (result == NULL) {
     342           0 :                 return NULL;
     343             :         }
     344           2 :         state->wb_ctx = wb_ctx;
     345           2 :         state->ev = ev;
     346           2 :         state->need_priv = need_priv;
     347             : 
     348           2 :         if (wb_ctx->fd != -1) {
     349           0 :                 close(wb_ctx->fd);
     350           0 :                 wb_ctx->fd = -1;
     351             :         }
     352             : 
     353           2 :         subreq = wb_connect_send(state, ev, wb_ctx, wb_ctx->dir);
     354           2 :         if (subreq == NULL) {
     355           0 :                 goto fail;
     356             :         }
     357           2 :         tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done,
     358             :                                 result);
     359           2 :         return result;
     360             : 
     361           0 :  fail:
     362           0 :         TALLOC_FREE(result);
     363           0 :         return NULL;
     364             : }
     365             : 
     366           2 : static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq)
     367             : {
     368           2 :         struct tevent_req *req = tevent_req_callback_data(
     369             :                 subreq, struct tevent_req);
     370           2 :         struct wb_open_pipe_state *state = tevent_req_data(
     371             :                 req, struct wb_open_pipe_state);
     372           0 :         wbcErr wbc_err;
     373             : 
     374           2 :         wbc_err = wb_connect_recv(subreq);
     375           2 :         TALLOC_FREE(subreq);
     376           2 :         if (!WBC_ERROR_IS_OK(wbc_err)) {
     377           0 :                 state->wb_ctx->is_priv = true;
     378           0 :                 tevent_req_error(req, wbc_err);
     379           0 :                 return;
     380             :         }
     381             : 
     382           2 :         ZERO_STRUCT(state->wb_req);
     383           2 :         state->wb_req.cmd = WINBINDD_INTERFACE_VERSION;
     384           2 :         state->wb_req.pid = getpid();
     385           2 :         (void)snprintf(state->wb_req.client_name,
     386             :                        sizeof(state->wb_req.client_name),
     387             :                        "%s",
     388             :                        "TORTURE");
     389             : 
     390           2 :         subreq = wb_simple_trans_send(state, state->ev, NULL,
     391           2 :                                       state->wb_ctx->fd, &state->wb_req);
     392           2 :         if (tevent_req_nomem(subreq, req)) {
     393           0 :                 return;
     394             :         }
     395           2 :         tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req);
     396             : }
     397             : 
     398           2 : static void wb_open_pipe_ping_done(struct tevent_req *subreq)
     399             : {
     400           2 :         struct tevent_req *req = tevent_req_callback_data(
     401             :                 subreq, struct tevent_req);
     402           2 :         struct wb_open_pipe_state *state = tevent_req_data(
     403             :                 req, struct wb_open_pipe_state);
     404           0 :         struct winbindd_response *wb_resp;
     405           0 :         int ret, err;
     406             : 
     407           2 :         ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
     408           2 :         TALLOC_FREE(subreq);
     409           2 :         if (ret == -1) {
     410           0 :                 tevent_req_error(req, map_wbc_err_from_errno(err));
     411           0 :                 return;
     412             :         }
     413             : 
     414           2 :         if (!state->need_priv) {
     415           0 :                 tevent_req_done(req);
     416           0 :                 return;
     417             :         }
     418             : 
     419           2 :         state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR;
     420           2 :         state->wb_req.pid = getpid();
     421             : 
     422           2 :         subreq = wb_simple_trans_send(state, state->ev, NULL,
     423           2 :                                       state->wb_ctx->fd, &state->wb_req);
     424           2 :         if (tevent_req_nomem(subreq, req)) {
     425           0 :                 return;
     426             :         }
     427           2 :         tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req);
     428             : }
     429             : 
     430           2 : static void wb_open_pipe_getpriv_done(struct tevent_req *subreq)
     431             : {
     432           2 :         struct tevent_req *req = tevent_req_callback_data(
     433             :                 subreq, struct tevent_req);
     434           2 :         struct wb_open_pipe_state *state = tevent_req_data(
     435             :                 req, struct wb_open_pipe_state);
     436           2 :         struct winbindd_response *wb_resp = NULL;
     437           0 :         int ret, err;
     438             : 
     439           2 :         ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
     440           2 :         TALLOC_FREE(subreq);
     441           2 :         if (ret == -1) {
     442           0 :                 tevent_req_error(req, map_wbc_err_from_errno(err));
     443           0 :                 return;
     444             :         }
     445             : 
     446           2 :         close(state->wb_ctx->fd);
     447           2 :         state->wb_ctx->fd = -1;
     448             : 
     449           2 :         subreq = wb_connect_send(state, state->ev, state->wb_ctx,
     450           2 :                                   (char *)wb_resp->extra_data.data);
     451           2 :         TALLOC_FREE(wb_resp);
     452           2 :         if (tevent_req_nomem(subreq, req)) {
     453           0 :                 return;
     454             :         }
     455           2 :         tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req);
     456             : }
     457             : 
     458           2 : static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq)
     459             : {
     460           2 :         struct tevent_req *req = tevent_req_callback_data(
     461             :                 subreq, struct tevent_req);
     462           2 :         struct wb_open_pipe_state *state = tevent_req_data(
     463             :                 req, struct wb_open_pipe_state);
     464           0 :         wbcErr wbc_err;
     465             : 
     466           2 :         wbc_err = wb_connect_recv(subreq);
     467           2 :         TALLOC_FREE(subreq);
     468           2 :         if (!WBC_ERROR_IS_OK(wbc_err)) {
     469           0 :                 tevent_req_error(req, wbc_err);
     470           0 :                 return;
     471             :         }
     472           2 :         state->wb_ctx->is_priv = true;
     473           2 :         tevent_req_done(req);
     474             : }
     475             : 
     476           2 : static wbcErr wb_open_pipe_recv(struct tevent_req *req)
     477             : {
     478           2 :         return tevent_req_simple_recv_wbcerr(req);
     479             : }
     480             : 
     481             : struct wb_trans_state {
     482             :         struct wb_trans_state *prev, *next;
     483             :         struct wb_context *wb_ctx;
     484             :         struct tevent_context *ev;
     485             :         struct winbindd_request *wb_req;
     486             :         struct winbindd_response *wb_resp;
     487             :         bool need_priv;
     488             : };
     489             : 
     490         198 : static bool closed_fd(int fd)
     491             : {
     492           0 :         struct timeval tv;
     493           0 :         fd_set r_fds;
     494           0 :         int selret;
     495             : 
     496         198 :         if (fd == -1) {
     497           0 :                 return true;
     498             :         }
     499             : 
     500        3366 :         FD_ZERO(&r_fds);
     501         198 :         FD_SET(fd, &r_fds);
     502         198 :         ZERO_STRUCT(tv);
     503             : 
     504         198 :         selret = select(fd+1, &r_fds, NULL, NULL, &tv);
     505         198 :         if (selret == -1) {
     506           0 :                 return true;
     507             :         }
     508         198 :         if (selret == 0) {
     509         198 :                 return false;
     510             :         }
     511           0 :         return (FD_ISSET(fd, &r_fds));
     512             : }
     513             : 
     514             : static void wb_trans_trigger(struct tevent_req *req, void *private_data);
     515             : static void wb_trans_connect_done(struct tevent_req *subreq);
     516             : static void wb_trans_done(struct tevent_req *subreq);
     517             : static void wb_trans_retry_wait_done(struct tevent_req *subreq);
     518             : 
     519         200 : struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx,
     520             :                                  struct tevent_context *ev,
     521             :                                  struct wb_context *wb_ctx, bool need_priv,
     522             :                                  struct winbindd_request *wb_req)
     523             : {
     524           0 :         struct tevent_req *req;
     525           0 :         struct wb_trans_state *state;
     526             : 
     527         200 :         req = tevent_req_create(mem_ctx, &state, struct wb_trans_state);
     528         200 :         if (req == NULL) {
     529           0 :                 return NULL;
     530             :         }
     531         200 :         state->wb_ctx = wb_ctx;
     532         200 :         state->ev = ev;
     533         200 :         state->wb_req = wb_req;
     534         200 :         state->need_priv = need_priv;
     535             : 
     536         200 :         if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger,
     537             :                               NULL)) {
     538           0 :                 tevent_req_oom(req);
     539           0 :                 return tevent_req_post(req, ev);
     540             :         }
     541         200 :         return req;
     542             : }
     543             : 
     544         200 : static void wb_trans_trigger(struct tevent_req *req, void *private_data)
     545             : {
     546         200 :         struct wb_trans_state *state = tevent_req_data(
     547             :                 req, struct wb_trans_state);
     548           0 :         struct tevent_req *subreq;
     549             : 
     550         200 :         if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) {
     551           0 :                 close(state->wb_ctx->fd);
     552           0 :                 state->wb_ctx->fd = -1;
     553             :         }
     554             : 
     555         200 :         if ((state->wb_ctx->fd == -1)
     556         198 :             || (state->need_priv && !state->wb_ctx->is_priv)) {
     557           2 :                 subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
     558           2 :                                            state->need_priv);
     559           2 :                 if (tevent_req_nomem(subreq, req)) {
     560           0 :                         return;
     561             :                 }
     562           2 :                 tevent_req_set_callback(subreq, wb_trans_connect_done, req);
     563           2 :                 return;
     564             :         }
     565             : 
     566         198 :         state->wb_req->pid = getpid();
     567             : 
     568         198 :         subreq = wb_simple_trans_send(state, state->ev, NULL,
     569         198 :                                       state->wb_ctx->fd, state->wb_req);
     570         198 :         if (tevent_req_nomem(subreq, req)) {
     571           0 :                 return;
     572             :         }
     573         198 :         tevent_req_set_callback(subreq, wb_trans_done, req);
     574             : }
     575             : 
     576           2 : static bool wb_trans_retry(struct tevent_req *req,
     577             :                            struct wb_trans_state *state,
     578             :                            wbcErr wbc_err)
     579             : {
     580           0 :         struct tevent_req *subreq;
     581             : 
     582           2 :         if (WBC_ERROR_IS_OK(wbc_err)) {
     583           2 :                 return false;
     584             :         }
     585             : 
     586           0 :         if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) {
     587             :                 /*
     588             :                  * Winbind not around or we can't connect to the pipe. Fail
     589             :                  * immediately.
     590             :                  */
     591           0 :                 tevent_req_error(req, wbc_err);
     592           0 :                 return true;
     593             :         }
     594             : 
     595             :         /*
     596             :          * The transfer as such failed, retry after one second
     597             :          */
     598             : 
     599           0 :         if (state->wb_ctx->fd != -1) {
     600           0 :                 close(state->wb_ctx->fd);
     601           0 :                 state->wb_ctx->fd = -1;
     602             :         }
     603             : 
     604           0 :         subreq = tevent_wakeup_send(state, state->ev,
     605             :                                     tevent_timeval_current_ofs(1, 0));
     606           0 :         if (tevent_req_nomem(subreq, req)) {
     607           0 :                 return true;
     608             :         }
     609           0 :         tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req);
     610           0 :         return true;
     611             : }
     612             : 
     613           0 : static void wb_trans_retry_wait_done(struct tevent_req *subreq)
     614             : {
     615           0 :         struct tevent_req *req = tevent_req_callback_data(
     616             :                 subreq, struct tevent_req);
     617           0 :         struct wb_trans_state *state = tevent_req_data(
     618             :                 req, struct wb_trans_state);
     619           0 :         bool ret;
     620             : 
     621           0 :         ret = tevent_wakeup_recv(subreq);
     622           0 :         TALLOC_FREE(subreq);
     623           0 :         if (!ret) {
     624           0 :                 tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE);
     625           0 :                 return;
     626             :         }
     627             : 
     628           0 :         subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
     629           0 :                                    state->need_priv);
     630           0 :         if (tevent_req_nomem(subreq, req)) {
     631           0 :                 return;
     632             :         }
     633           0 :         tevent_req_set_callback(subreq, wb_trans_connect_done, req);
     634             : }
     635             : 
     636           2 : static void wb_trans_connect_done(struct tevent_req *subreq)
     637             : {
     638           2 :         struct tevent_req *req = tevent_req_callback_data(
     639             :                 subreq, struct tevent_req);
     640           2 :         struct wb_trans_state *state = tevent_req_data(
     641             :                 req, struct wb_trans_state);
     642           0 :         wbcErr wbc_err;
     643             : 
     644           2 :         wbc_err = wb_open_pipe_recv(subreq);
     645           2 :         TALLOC_FREE(subreq);
     646             : 
     647           2 :         if (wb_trans_retry(req, state, wbc_err)) {
     648           0 :                 return;
     649             :         }
     650             : 
     651           2 :         subreq = wb_simple_trans_send(state, state->ev, NULL,
     652           2 :                                       state->wb_ctx->fd, state->wb_req);
     653           2 :         if (tevent_req_nomem(subreq, req)) {
     654           0 :                 return;
     655             :         }
     656           2 :         tevent_req_set_callback(subreq, wb_trans_done, req);
     657             : }
     658             : 
     659         200 : static void wb_trans_done(struct tevent_req *subreq)
     660             : {
     661         200 :         struct tevent_req *req = tevent_req_callback_data(
     662             :                 subreq, struct tevent_req);
     663         200 :         struct wb_trans_state *state = tevent_req_data(
     664             :                 req, struct wb_trans_state);
     665           0 :         int ret, err;
     666             : 
     667         200 :         ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err);
     668         200 :         TALLOC_FREE(subreq);
     669         200 :         if ((ret == -1)
     670           0 :             && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) {
     671           0 :                 return;
     672             :         }
     673             : 
     674         200 :         tevent_req_done(req);
     675             : }
     676             : 
     677         200 : wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     678             :                      struct winbindd_response **presponse)
     679             : {
     680         200 :         struct wb_trans_state *state = tevent_req_data(
     681             :                 req, struct wb_trans_state);
     682           0 :         wbcErr wbc_err;
     683             : 
     684         200 :         if (tevent_req_is_wbcerr(req, &wbc_err)) {
     685           0 :                 return wbc_err;
     686             :         }
     687             : 
     688         200 :         *presponse = talloc_move(mem_ctx, &state->wb_resp);
     689         200 :         return WBC_ERR_SUCCESS;
     690             : }
     691             : 
     692             : /********************************************************************
     693             :  * Debug wrapper functions, modeled (with lot's of code copied as is)
     694             :  * after the tevent debug wrapper functions
     695             :  ********************************************************************/
     696             : 
     697             : /*
     698             :   this allows the user to choose their own debug function
     699             : */
     700           0 : int wbcSetDebug(struct wb_context *wb_ctx,
     701             :                 void (*debug)(void *context,
     702             :                               enum wbcDebugLevel level,
     703             :                               const char *fmt,
     704             :                               va_list ap) PRINTF_ATTRIBUTE(3,0),
     705             :                 void *context)
     706             : {
     707           0 :         wb_ctx->debug_ops.debug = debug;
     708           0 :         wb_ctx->debug_ops.context = context;
     709           0 :         return 0;
     710             : }
     711             : 
     712             : /*
     713             :   debug function for wbcSetDebugStderr
     714             : */
     715             : static void wbcDebugStderr(void *private_data,
     716             :                            enum wbcDebugLevel level,
     717             :                            const char *fmt,
     718             :                            va_list ap) PRINTF_ATTRIBUTE(3,0);
     719           0 : static void wbcDebugStderr(void *private_data,
     720             :                            enum wbcDebugLevel level,
     721             :                            const char *fmt, va_list ap)
     722             : {
     723           0 :         if (level <= WBC_DEBUG_WARNING) {
     724           0 :                 vfprintf(stderr, fmt, ap);
     725             :         }
     726           0 : }
     727             : 
     728             : /*
     729             :   convenience function to setup debug messages on stderr
     730             :   messages of level WBC_DEBUG_WARNING and higher are printed
     731             : */
     732           0 : int wbcSetDebugStderr(struct wb_context *wb_ctx)
     733             : {
     734           0 :         return wbcSetDebug(wb_ctx, wbcDebugStderr, wb_ctx);
     735             : }
     736             : 
     737             : /*
     738             :  * log a message
     739             :  *
     740             :  * The default debug action is to ignore debugging messages.
     741             :  * This is the most appropriate action for a library.
     742             :  * Applications using the library must decide where to
     743             :  * redirect debugging messages
     744             : */
     745           0 : void wbcDebug(struct wb_context *wb_ctx, enum wbcDebugLevel level,
     746             :               const char *fmt, ...)
     747             : {
     748           0 :         va_list ap;
     749           0 :         if (!wb_ctx) {
     750           0 :                 return;
     751             :         }
     752           0 :         if (wb_ctx->debug_ops.debug == NULL) {
     753           0 :                 return;
     754             :         }
     755           0 :         va_start(ap, fmt);
     756           0 :         wb_ctx->debug_ops.debug(wb_ctx->debug_ops.context, level, fmt, ap);
     757           0 :         va_end(ap);
     758             : }

Generated by: LCOV version 1.14