LCOV - code coverage report
Current view: top level - nsswitch - wb_common.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 225 310 72.6 %
Date: 2024-06-13 04:01:37 Functions: 23 23 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    winbind client common code
       5             : 
       6             :    Copyright (C) Tim Potter 2000
       7             :    Copyright (C) Andrew Tridgell 2000
       8             :    Copyright (C) Andrew Bartlett 2002
       9             :    Copyright (C) Matthew Newton 2015
      10             : 
      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/select.h"
      28             : #include "winbind_client.h"
      29             : 
      30             : #ifdef HAVE_PTHREAD_H
      31             : #include <pthread.h>
      32             : #endif
      33             : 
      34             : static char client_name[32];
      35             : 
      36             : /* Global context */
      37             : 
      38             : struct winbindd_context {
      39             :         int winbindd_fd;        /* winbind file descriptor */
      40             :         bool is_privileged;     /* using the privileged socket? */
      41             :         pid_t our_pid;          /* calling process pid */
      42             : };
      43             : 
      44             : #ifdef HAVE_PTHREAD
      45             : static pthread_mutex_t wb_global_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
      46             : #endif
      47             : 
      48      177882 : static struct winbindd_context *get_wb_global_ctx(void)
      49             : {
      50             :         static struct winbindd_context wb_global_ctx = {
      51             :                 .winbindd_fd = -1,
      52             :                 .is_privileged = false,
      53             :                 .our_pid = 0
      54             :         };
      55             : 
      56             : #ifdef HAVE_PTHREAD
      57      177882 :         pthread_mutex_lock(&wb_global_ctx_mutex);
      58             : #endif
      59      177882 :         return &wb_global_ctx;
      60             : }
      61             : 
      62      177882 : static void put_wb_global_ctx(void)
      63             : {
      64             : #ifdef HAVE_PTHREAD
      65      177882 :         pthread_mutex_unlock(&wb_global_ctx_mutex);
      66             : #endif
      67      177882 :         return;
      68             : }
      69             : 
      70       22307 : void winbind_set_client_name(const char *name)
      71             : {
      72       22307 :         if (name == NULL || strlen(name) == 0) {
      73           0 :                 return;
      74             :         }
      75             : 
      76       22307 :         (void)snprintf(client_name, sizeof(client_name), "%s", name);
      77             : }
      78             : 
      79      122473 : static const char *winbind_get_client_name(void)
      80             : {
      81      122473 :         if (client_name[0] == '\0') {
      82        6901 :                 const char *progname = getprogname();
      83             :                 int len;
      84             : 
      85        6901 :                 if (progname == NULL) {
      86           0 :                         progname = "<unknown>";
      87             :                 }
      88             : 
      89        6901 :                 len = snprintf(client_name,
      90             :                                sizeof(client_name),
      91             :                                "%s",
      92             :                                progname);
      93        6901 :                 if (len <= 0) {
      94           0 :                         return progname;
      95             :                 }
      96             :         }
      97             : 
      98      122473 :         return client_name;
      99             : }
     100             : 
     101             : /* Initialise a request structure */
     102             : 
     103      122473 : static void winbindd_init_request(struct winbindd_request *request,
     104             :                                   int request_type)
     105             : {
     106      122473 :         request->length = sizeof(struct winbindd_request);
     107             : 
     108      122473 :         request->cmd = (enum winbindd_cmd)request_type;
     109      122473 :         request->pid = getpid();
     110             : 
     111      122473 :         (void)snprintf(request->client_name,
     112             :                        sizeof(request->client_name),
     113             :                        "%s",
     114             :                        winbind_get_client_name());
     115      122473 : }
     116             : 
     117             : /* Initialise a response structure */
     118             : 
     119      103299 : static void init_response(struct winbindd_response *response)
     120             : {
     121             :         /* Initialise return value */
     122             : 
     123      103299 :         response->result = WINBINDD_ERROR;
     124      103299 : }
     125             : 
     126             : /* Close established socket */
     127             : 
     128       85478 : static void winbind_close_sock(struct winbindd_context *ctx)
     129             : {
     130       85478 :         if (!ctx) {
     131           0 :                 return;
     132             :         }
     133             : 
     134       85478 :         if (ctx->winbindd_fd != -1) {
     135       16430 :                 close(ctx->winbindd_fd);
     136       16430 :                 ctx->winbindd_fd = -1;
     137             :         }
     138             : }
     139             : 
     140             : /* Destructor for global context to ensure fd is closed */
     141             : 
     142             : #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
     143             : __attribute__((destructor))
     144             : #elif defined (HAVE_PRAGMA_FINI)
     145             : #pragma fini (winbind_destructor)
     146             : #endif
     147       64489 : static void winbind_destructor(void)
     148             : {
     149             :         struct winbindd_context *ctx;
     150             : 
     151       64489 :         ctx = get_wb_global_ctx();
     152       64489 :         winbind_close_sock(ctx);
     153       64489 :         put_wb_global_ctx();
     154       64489 : }
     155             : 
     156             : #define CONNECT_TIMEOUT 30
     157             : 
     158             : /* Make sure socket handle isn't stdin, stdout or stderr */
     159             : #define RECURSION_LIMIT 3
     160             : 
     161       18197 : static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
     162             : {
     163             :         int new_fd;
     164       18197 :         if (fd >= 0 && fd <= 2) {
     165             : #ifdef F_DUPFD
     166           0 :                 if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
     167           0 :                         return -1;
     168             :                 }
     169             :                 /* Paranoia */
     170           0 :                 if (new_fd < 3) {
     171           0 :                         close(new_fd);
     172           0 :                         return -1;
     173             :                 }
     174           0 :                 close(fd);
     175           0 :                 return new_fd;
     176             : #else
     177             :                 if (limit <= 0)
     178             :                         return -1;
     179             : 
     180             :                 new_fd = dup(fd);
     181             :                 if (new_fd == -1)
     182             :                         return -1;
     183             : 
     184             :                 /* use the program stack to hold our list of FDs to close */
     185             :                 new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
     186             :                 close(fd);
     187             :                 return new_fd;
     188             : #endif
     189             :         }
     190       18197 :         return fd;
     191             : }
     192             : 
     193             : /****************************************************************************
     194             :  Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
     195             :  else
     196             :  if SYSV use O_NDELAY
     197             :  if BSD use FNDELAY
     198             :  Set close on exec also.
     199             : ****************************************************************************/
     200             : 
     201       18197 : static int make_safe_fd(int fd)
     202             : {
     203             :         int result, flags;
     204       18197 :         int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
     205       18197 :         if (new_fd == -1) {
     206           0 :                 close(fd);
     207           0 :                 return -1;
     208             :         }
     209             : 
     210             :         /* Socket should be nonblocking. */
     211             : #ifdef O_NONBLOCK
     212             : #define FLAG_TO_SET O_NONBLOCK
     213             : #else
     214             : #ifdef SYSV
     215             : #define FLAG_TO_SET O_NDELAY
     216             : #else /* BSD */
     217             : #define FLAG_TO_SET FNDELAY
     218             : #endif
     219             : #endif
     220             : 
     221       18197 :         if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
     222           0 :                 close(new_fd);
     223           0 :                 return -1;
     224             :         }
     225             : 
     226       18197 :         flags |= FLAG_TO_SET;
     227       18197 :         if (fcntl(new_fd, F_SETFL, flags) == -1) {
     228           0 :                 close(new_fd);
     229           0 :                 return -1;
     230             :         }
     231             : 
     232             : #undef FLAG_TO_SET
     233             : 
     234             :         /* Socket should be closed on exec() */
     235             : #ifdef FD_CLOEXEC
     236       18197 :         result = flags = fcntl(new_fd, F_GETFD, 0);
     237       18197 :         if (flags >= 0) {
     238       18197 :                 flags |= FD_CLOEXEC;
     239       18197 :                 result = fcntl( new_fd, F_SETFD, flags );
     240             :         }
     241       18197 :         if (result < 0) {
     242           0 :                 close(new_fd);
     243           0 :                 return -1;
     244             :         }
     245             : #endif
     246       18197 :         return new_fd;
     247             : }
     248             : 
     249             : /**
     250             :  * @internal
     251             :  *
     252             :  * @brief Check if we talk to the privileged pipe which should be owned by root.
     253             :  *
     254             :  * This checks if we have uid_wrapper running and if this is the case it will
     255             :  * allow one to connect to the winbind privileged pipe even it is not owned by root.
     256             :  *
     257             :  * @param[in]  uid      The uid to check if we can safely talk to the pipe.
     258             :  *
     259             :  * @return              If we have access it returns true, else false.
     260             :  */
     261       36398 : static bool winbind_privileged_pipe_is_root(uid_t uid)
     262             : {
     263       36398 :         if (uid == 0) {
     264           0 :                 return true;
     265             :         }
     266             : 
     267       36398 :         if (uid_wrapper_enabled()) {
     268       36398 :                 return true;
     269             :         }
     270             : 
     271           0 :         return false;
     272             : }
     273             : 
     274             : /* Connect to winbindd socket */
     275             : 
     276       37371 : static int winbind_named_pipe_sock(const char *dir)
     277             : {
     278             :         struct sockaddr_un sunaddr;
     279             :         struct stat st;
     280             :         int fd;
     281             :         int wait_time;
     282             :         int slept;
     283             :         int ret;
     284             : 
     285             :         /* Check permissions on unix socket directory */
     286             : 
     287       37371 :         if (lstat(dir, &st) == -1) {
     288       19170 :                 errno = ENOENT;
     289       19170 :                 return -1;
     290             :         }
     291             : 
     292             :         /*
     293             :          * This tells us that the pipe is owned by a privileged
     294             :          * process, as we will be sending passwords to it.
     295             :          */
     296       28338 :         if (!S_ISDIR(st.st_mode) ||
     297       18201 :             !winbind_privileged_pipe_is_root(st.st_uid)) {
     298           0 :                 errno = ENOENT;
     299           0 :                 return -1;
     300             :         }
     301             : 
     302             :         /* Connect to socket */
     303             : 
     304       18201 :         sunaddr = (struct sockaddr_un) { .sun_family = AF_UNIX };
     305             : 
     306       18201 :         ret = snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
     307             :                        "%s/%s", dir, WINBINDD_SOCKET_NAME);
     308       18201 :         if ((ret == -1) || (ret >= sizeof(sunaddr.sun_path))) {
     309           0 :                 errno = ENAMETOOLONG;
     310           0 :                 return -1;
     311             :         }
     312             : 
     313             :         /* If socket file doesn't exist, don't bother trying to connect
     314             :            with retry.  This is an attempt to make the system usable when
     315             :            the winbindd daemon is not running. */
     316             : 
     317       18201 :         if (lstat(sunaddr.sun_path, &st) == -1) {
     318           4 :                 errno = ENOENT;
     319           4 :                 return -1;
     320             :         }
     321             : 
     322             :         /* Check permissions on unix socket file */
     323             : 
     324             :         /*
     325             :          * This tells us that the pipe is owned by a privileged
     326             :          * process, as we will be sending passwords to it.
     327             :          */
     328       28332 :         if (!S_ISSOCK(st.st_mode) ||
     329       18197 :             !winbind_privileged_pipe_is_root(st.st_uid)) {
     330           0 :                 errno = ENOENT;
     331           0 :                 return -1;
     332             :         }
     333             : 
     334             :         /* Connect to socket */
     335             : 
     336       18197 :         if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
     337           0 :                 return -1;
     338             :         }
     339             : 
     340             :         /* Set socket non-blocking and close on exec. */
     341             : 
     342       18197 :         if ((fd = make_safe_fd( fd)) == -1) {
     343           0 :                 return fd;
     344             :         }
     345             : 
     346       28332 :         for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
     347           0 :                         wait_time += slept) {
     348             :                 struct pollfd pfd;
     349           0 :                 int connect_errno = 0;
     350             :                 socklen_t errnosize;
     351             : 
     352           0 :                 if (wait_time >= CONNECT_TIMEOUT)
     353           0 :                         goto error_out;
     354             : 
     355           0 :                 switch (errno) {
     356           0 :                         case EINPROGRESS:
     357           0 :                                 pfd.fd = fd;
     358           0 :                                 pfd.events = POLLOUT;
     359             : 
     360           0 :                                 ret = poll(&pfd, 1, (CONNECT_TIMEOUT - wait_time) * 1000);
     361             : 
     362           0 :                                 if (ret > 0) {
     363           0 :                                         errnosize = sizeof(connect_errno);
     364             : 
     365           0 :                                         ret = getsockopt(fd, SOL_SOCKET,
     366             :                                                         SO_ERROR, &connect_errno, &errnosize);
     367             : 
     368           0 :                                         if (ret >= 0 && connect_errno == 0) {
     369             :                                                 /* Connect succeed */
     370           0 :                                                 goto out;
     371             :                                         }
     372             :                                 }
     373             : 
     374           0 :                                 slept = CONNECT_TIMEOUT;
     375           0 :                                 break;
     376           0 :                         case EAGAIN:
     377           0 :                                 slept = rand() % 3 + 1;
     378           0 :                                 sleep(slept);
     379           0 :                                 break;
     380           0 :                         default:
     381           0 :                                 goto error_out;
     382             :                 }
     383             : 
     384             :         }
     385             : 
     386       18197 :   out:
     387             : 
     388       18197 :         return fd;
     389             : 
     390           0 :   error_out:
     391             : 
     392           0 :         close(fd);
     393           0 :         return -1;
     394             : }
     395             : 
     396       35605 : static const char *winbindd_socket_dir(void)
     397             : {
     398       35605 :         if (nss_wrapper_enabled()) {
     399             :                 const char *env_dir;
     400             : 
     401       35507 :                 env_dir = getenv("SELFTEST_WINBINDD_SOCKET_DIR");
     402       35507 :                 if (env_dir != NULL) {
     403       34695 :                         return env_dir;
     404             :                 }
     405             :         }
     406             : 
     407         910 :         return WINBINDD_SOCKET_DIR;
     408             : }
     409             : 
     410             : /* Connect to winbindd socket */
     411             : 
     412      263427 : static int winbind_open_pipe_sock(struct winbindd_context *ctx,
     413             :                                   int recursing, int need_priv)
     414             : {
     415             : #ifdef HAVE_UNIXSOCKET
     416             :         struct winbindd_request request;
     417             :         struct winbindd_response response;
     418             : 
     419      263427 :         ZERO_STRUCT(request);
     420      263427 :         ZERO_STRUCT(response);
     421             : 
     422      263427 :         if (!ctx) {
     423           0 :                 return -1;
     424             :         }
     425             : 
     426      263427 :         if (ctx->our_pid != getpid()) {
     427       19383 :                 winbind_close_sock(ctx);
     428       19383 :                 ctx->our_pid = getpid();
     429             :         }
     430             : 
     431      263427 :         if ((need_priv != 0) && !ctx->is_privileged) {
     432        1335 :                 winbind_close_sock(ctx);
     433             :         }
     434             : 
     435      263427 :         if (ctx->winbindd_fd != -1) {
     436      227822 :                 return ctx->winbindd_fd;
     437             :         }
     438             : 
     439       35605 :         if (recursing) {
     440           0 :                 return -1;
     441             :         }
     442             : 
     443       35605 :         ctx->winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir());
     444             : 
     445       35605 :         if (ctx->winbindd_fd == -1) {
     446       19174 :                 return -1;
     447             :         }
     448             : 
     449       16431 :         ctx->is_privileged = false;
     450             : 
     451             :         /* version-check the socket */
     452             : 
     453       16431 :         request.wb_flags = WBFLAG_RECURSE;
     454       16431 :         if ((winbindd_request_response(ctx, WINBINDD_INTERFACE_VERSION, &request,
     455       16431 :                                        &response) != NSS_STATUS_SUCCESS) ||
     456       16431 :             (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
     457           0 :                 winbind_close_sock(ctx);
     458           0 :                 return -1;
     459             :         }
     460             : 
     461       16431 :         if (need_priv == 0) {
     462       14665 :                 return ctx->winbindd_fd;
     463             :         }
     464             : 
     465             :         /* try and get priv pipe */
     466             : 
     467        1766 :         request.wb_flags = WBFLAG_RECURSE;
     468             : 
     469             :         /* Note that response needs to be initialized to avoid
     470             :          * crashing on clean up after WINBINDD_PRIV_PIPE_DIR call failed
     471             :          * as interface version (from the first request) returned as a fstring,
     472             :          * thus response.extra_data.data will not be NULL even though
     473             :          * winbindd response did not write over it due to a failure */
     474        1766 :         ZERO_STRUCT(response);
     475        1766 :         if (winbindd_request_response(ctx, WINBINDD_PRIV_PIPE_DIR, &request,
     476             :                                       &response) == NSS_STATUS_SUCCESS) {
     477             :                 int fd;
     478        1766 :                 fd = winbind_named_pipe_sock((char *)response.extra_data.data);
     479        1766 :                 if (fd != -1) {
     480        1766 :                         close(ctx->winbindd_fd);
     481        1766 :                         ctx->winbindd_fd = fd;
     482        1766 :                         ctx->is_privileged = true;
     483             :                 }
     484             : 
     485        1766 :                 SAFE_FREE(response.extra_data.data);
     486             :         }
     487             : 
     488        1766 :         if (!ctx->is_privileged) {
     489           0 :                 return -1;
     490             :         }
     491             : 
     492        1766 :         return ctx->winbindd_fd;
     493             : #else
     494             :         return -1;
     495             : #endif /* HAVE_UNIXSOCKET */
     496             : }
     497             : 
     498             : /* Write data to winbindd socket */
     499             : 
     500      140195 : static int winbind_write_sock(struct winbindd_context *ctx, void *buffer,
     501             :                               int count, int recursing, int need_priv)
     502             : {
     503             :         int fd, result, nwritten;
     504             : 
     505             :         /* Open connection to winbind daemon */
     506             : 
     507      140197 :  restart:
     508             : 
     509      140197 :         fd = winbind_open_pipe_sock(ctx, recursing, need_priv);
     510      140197 :         if (fd == -1) {
     511       19174 :                 errno = ENOENT;
     512       19174 :                 return -1;
     513             :         }
     514             : 
     515             :         /* Write data to socket */
     516             : 
     517      121023 :         nwritten = 0;
     518             : 
     519      316675 :         while(nwritten < count) {
     520             :                 struct pollfd pfd;
     521             :                 int ret;
     522             : 
     523             :                 /* Catch pipe close on other end by checking if a read()
     524             :                    call would not block by calling poll(). */
     525             : 
     526      121023 :                 pfd.fd = fd;
     527      121023 :                 pfd.events = POLLIN|POLLOUT|POLLHUP;
     528             : 
     529      121023 :                 ret = poll(&pfd, 1, -1);
     530      121023 :                 if (ret == -1) {
     531           0 :                         winbind_close_sock(ctx);
     532           0 :                         return -1;                   /* poll error */
     533             :                 }
     534             : 
     535             :                 /* Write should be OK if fd not available for reading */
     536             : 
     537      121023 :                 if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) {
     538             : 
     539             :                         /* Pipe has closed on remote end */
     540             : 
     541          11 :                         winbind_close_sock(ctx);
     542          11 :                         goto restart;
     543             :                 }
     544             : 
     545             :                 /* Do the write */
     546             : 
     547      167393 :                 result = write(fd, (char *)buffer + nwritten,
     548      121012 :                                count - nwritten);
     549             : 
     550      121012 :                 if ((result == -1) || (result == 0)) {
     551             : 
     552             :                         /* Write failed */
     553             : 
     554           0 :                         winbind_close_sock(ctx);
     555           0 :                         return -1;
     556             :                 }
     557             : 
     558      121012 :                 nwritten += result;
     559             :         }
     560             : 
     561      121012 :         return nwritten;
     562             : }
     563             : 
     564             : /* Read data from winbindd socket */
     565             : 
     566      123230 : static int winbind_read_sock(struct winbindd_context *ctx,
     567             :                              void *buffer, int count)
     568             : {
     569             :         int fd;
     570      123230 :         int nread = 0;
     571      123230 :         int total_time = 0;
     572             : 
     573      123230 :         fd = winbind_open_pipe_sock(ctx, false, false);
     574      123230 :         if (fd == -1) {
     575           0 :                 return -1;
     576             :         }
     577             : 
     578             :         /* Read data from socket */
     579      322539 :         while(nread < count) {
     580             :                 struct pollfd pfd;
     581             :                 int ret;
     582             : 
     583             :                 /* Catch pipe close on other end by checking if a read()
     584             :                    call would not block by calling poll(). */
     585             : 
     586      123230 :                 pfd.fd = fd;
     587      123230 :                 pfd.events = POLLIN|POLLHUP;
     588             : 
     589             :                 /* Wait for 5 seconds for a reply. May need to parameterise this... */
     590             : 
     591      123230 :                 ret = poll(&pfd, 1, 5000);
     592      123230 :                 if (ret == -1) {
     593           0 :                         winbind_close_sock(ctx);
     594           0 :                         return -1;                   /* poll error */
     595             :                 }
     596             : 
     597      123230 :                 if (ret == 0) {
     598             :                         /* Not ready for read yet... */
     599           0 :                         if (total_time >= 300) {
     600             :                                 /* Timeout */
     601           0 :                                 winbind_close_sock(ctx);
     602           0 :                                 return -1;
     603             :                         }
     604           0 :                         total_time += 5;
     605           0 :                         continue;
     606             :                 }
     607             : 
     608      123230 :                 if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) {
     609             : 
     610             :                         /* Do the Read */
     611             : 
     612      170381 :                         int result = read(fd, (char *)buffer + nread,
     613      123230 :                               count - nread);
     614             : 
     615      123230 :                         if ((result == -1) || (result == 0)) {
     616             : 
     617             :                                 /* Read failed.  I think the only useful thing we
     618             :                                    can do here is just return -1 and fail since the
     619             :                                    transaction has failed half way through. */
     620             : 
     621           0 :                                 winbind_close_sock(ctx);
     622           0 :                                 return -1;
     623             :                         }
     624             : 
     625      123230 :                         nread += result;
     626             : 
     627             :                 }
     628             :         }
     629             : 
     630      123230 :         return nread;
     631             : }
     632             : 
     633             : /* Read reply */
     634             : 
     635      103299 : static int winbindd_read_reply(struct winbindd_context *ctx,
     636             :                                struct winbindd_response *response)
     637             : {
     638      103299 :         int result1, result2 = 0;
     639             : 
     640      103299 :         if (!response) {
     641           0 :                 return -1;
     642             :         }
     643             : 
     644             :         /* Read fixed length response */
     645             : 
     646      103299 :         result1 = winbind_read_sock(ctx, response,
     647             :                                     sizeof(struct winbindd_response));
     648             : 
     649             :         /* We actually send the pointer value of the extra_data field from
     650             :            the server.  This has no meaning in the client's address space
     651             :            so we clear it out. */
     652             : 
     653      103299 :         response->extra_data.data = NULL;
     654             : 
     655      103299 :         if (result1 == -1) {
     656           0 :                 return -1;
     657             :         }
     658             : 
     659      103299 :         if (response->length < sizeof(struct winbindd_response)) {
     660           0 :                 return -1;
     661             :         }
     662             : 
     663             :         /* Read variable length response */
     664             : 
     665      103299 :         if (response->length > sizeof(struct winbindd_response)) {
     666       19931 :                 int extra_data_len = response->length -
     667             :                         sizeof(struct winbindd_response);
     668             : 
     669             :                 /* Mallocate memory for extra data */
     670             : 
     671       19931 :                 if (!(response->extra_data.data = malloc(extra_data_len))) {
     672           0 :                         return -1;
     673             :                 }
     674             : 
     675       19931 :                 result2 = winbind_read_sock(ctx, response->extra_data.data,
     676             :                                             extra_data_len);
     677       19931 :                 if (result2 == -1) {
     678           0 :                         winbindd_free_response(response);
     679           0 :                         return -1;
     680             :                 }
     681             :         }
     682             : 
     683             :         /* Return total amount of data read */
     684             : 
     685      103299 :         return result1 + result2;
     686             : }
     687             : 
     688             : /*
     689             :  * send simple types of requests
     690             :  */
     691             : 
     692      132810 : static NSS_STATUS winbindd_send_request(
     693             :         struct winbindd_context *ctx,
     694             :         int req_type,
     695             :         int need_priv,
     696             :         struct winbindd_request *request)
     697             : {
     698             :         struct winbindd_request lrequest;
     699             : 
     700             :         /* Check for our tricky environment variable */
     701             : 
     702      132810 :         if (winbind_env_set()) {
     703       10337 :                 return NSS_STATUS_NOTFOUND;
     704             :         }
     705             : 
     706      122473 :         if (!request) {
     707       49864 :                 ZERO_STRUCT(lrequest);
     708       49864 :                 request = &lrequest;
     709             :         }
     710             : 
     711             :         /* Fill in request and send down pipe */
     712             : 
     713      122473 :         winbindd_init_request(request, req_type);
     714             : 
     715      122473 :         if (winbind_write_sock(ctx, request, sizeof(*request),
     716      122473 :                                request->wb_flags & WBFLAG_RECURSE,
     717             :                                need_priv) == -1)
     718             :         {
     719             :                 /* Set ENOENT for consistency.  Required by some apps */
     720       19174 :                 errno = ENOENT;
     721             : 
     722       19174 :                 return NSS_STATUS_UNAVAIL;
     723             :         }
     724             : 
     725      121012 :         if ((request->extra_len != 0) &&
     726       32081 :             (winbind_write_sock(ctx, request->extra_data.data,
     727       17713 :                                 request->extra_len,
     728       17713 :                                 request->wb_flags & WBFLAG_RECURSE,
     729             :                                 need_priv) == -1))
     730             :         {
     731             :                 /* Set ENOENT for consistency.  Required by some apps */
     732           0 :                 errno = ENOENT;
     733             : 
     734           0 :                 return NSS_STATUS_UNAVAIL;
     735             :         }
     736             : 
     737      103299 :         return NSS_STATUS_SUCCESS;
     738             : }
     739             : 
     740             : /*
     741             :  * Get results from winbindd request
     742             :  */
     743             : 
     744      103299 : static NSS_STATUS winbindd_get_response(struct winbindd_context *ctx,
     745             :                                         struct winbindd_response *response)
     746             : {
     747             :         struct winbindd_response lresponse;
     748             : 
     749      103299 :         if (!response) {
     750       46548 :                 ZERO_STRUCT(lresponse);
     751       46548 :                 response = &lresponse;
     752             :         }
     753             : 
     754      103299 :         init_response(response);
     755             : 
     756             :         /* Wait for reply */
     757      103299 :         if (winbindd_read_reply(ctx, response) == -1) {
     758             :                 /* Set ENOENT for consistency.  Required by some apps */
     759           0 :                 errno = ENOENT;
     760             : 
     761           0 :                 return NSS_STATUS_UNAVAIL;
     762             :         }
     763             : 
     764             :         /* Throw away extra data if client didn't request it */
     765      103299 :         if (response == &lresponse) {
     766       46548 :                 winbindd_free_response(response);
     767             :         }
     768             : 
     769             :         /* Copy reply data from socket */
     770      103299 :         if (response->result != WINBINDD_OK) {
     771        2381 :                 return NSS_STATUS_NOTFOUND;
     772             :         }
     773             : 
     774      100918 :         return NSS_STATUS_SUCCESS;
     775             : }
     776             : 
     777             : /* Handle simple types of requests */
     778             : 
     779      128658 : NSS_STATUS winbindd_request_response(struct winbindd_context *ctx,
     780             :                                      int req_type,
     781             :                                      struct winbindd_request *request,
     782             :                                      struct winbindd_response *response)
     783             : {
     784      128658 :         NSS_STATUS status = NSS_STATUS_UNAVAIL;
     785      128658 :         bool release_global_ctx = false;
     786             : 
     787      128658 :         if (ctx == NULL) {
     788      109241 :                 ctx = get_wb_global_ctx();
     789      109241 :                 release_global_ctx = true;
     790             :         }
     791             : 
     792      128658 :         status = winbindd_send_request(ctx, req_type, 0, request);
     793      128658 :         if (status != NSS_STATUS_SUCCESS) {
     794       29511 :                 goto out;
     795             :         }
     796       99147 :         status = winbindd_get_response(ctx, response);
     797             : 
     798      128658 : out:
     799      128658 :         if (release_global_ctx) {
     800      109241 :                 put_wb_global_ctx();
     801             :         }
     802      128658 :         return status;
     803             : }
     804             : 
     805        4152 : NSS_STATUS winbindd_priv_request_response(struct winbindd_context *ctx,
     806             :                                           int req_type,
     807             :                                           struct winbindd_request *request,
     808             :                                           struct winbindd_response *response)
     809             : {
     810        4152 :         NSS_STATUS status = NSS_STATUS_UNAVAIL;
     811        4152 :         bool release_global_ctx = false;
     812             : 
     813        4152 :         if (ctx == NULL) {
     814        4152 :                 ctx = get_wb_global_ctx();
     815        4152 :                 release_global_ctx = true;
     816             :         }
     817             : 
     818        4152 :         status = winbindd_send_request(ctx, req_type, 1, request);
     819        4152 :         if (status != NSS_STATUS_SUCCESS) {
     820           0 :                 goto out;
     821             :         }
     822        4152 :         status = winbindd_get_response(ctx, response);
     823             : 
     824        4152 : out:
     825        4152 :         if (release_global_ctx) {
     826        4152 :                 put_wb_global_ctx();
     827             :         }
     828        4152 :         return status;
     829             : }
     830             : 
     831             : /* Create and free winbindd context */
     832             : 
     833         260 : struct winbindd_context *winbindd_ctx_create(void)
     834             : {
     835             :         struct winbindd_context *ctx;
     836             : 
     837         260 :         ctx = calloc(1, sizeof(struct winbindd_context));
     838             : 
     839         260 :         if (!ctx) {
     840           0 :                 return NULL;
     841             :         }
     842             : 
     843         260 :         ctx->winbindd_fd = -1;
     844             : 
     845         260 :         return ctx;
     846             : }
     847             : 
     848         260 : void winbindd_ctx_free(struct winbindd_context *ctx)
     849             : {
     850         260 :         winbind_close_sock(ctx);
     851         260 :         free(ctx);
     852         260 : }

Generated by: LCOV version 1.13