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

Generated by: LCOV version 1.13