LCOV - code coverage report
Current view: top level - sss_client - common.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 99 509 19.4 %
Date: 2016-06-29 Functions: 17 36 47.2 %

          Line data    Source code
       1             : /*
       2             :  * System Security Services Daemon. NSS client interface
       3             :  *
       4             :  * Copyright (C) Simo Sorce 2007
       5             :  *
       6             :  * Winbind derived code:
       7             :  * Copyright (C) Tim Potter 2000
       8             :  * Copyright (C) Andrew Tridgell 2000
       9             :  * Copyright (C) Andrew Bartlett 2002
      10             :  *
      11             :  * This program is free software; you can redistribute it and/or modify
      12             :  * it under the terms of the GNU Lesser General Public License as
      13             :  * published by the Free Software Foundation; either version 2.1 of the
      14             :  * License, or (at your option) any later version.
      15             :  *
      16             :  * This program is distributed in the hope that it will be useful,
      17             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :  * GNU Lesser General Public License for more details.
      20             :  *
      21             :  * You should have received a copy of the GNU Lesser General Public License
      22             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             :  */
      24             : 
      25             : #include "config.h"
      26             : 
      27             : #include <nss.h>
      28             : #include <security/pam_modules.h>
      29             : #include <errno.h>
      30             : #include <sys/types.h>
      31             : #include <sys/socket.h>
      32             : #include <sys/un.h>
      33             : #include <sys/stat.h>
      34             : #include <unistd.h>
      35             : #include <stdlib.h>
      36             : #include <stdbool.h>
      37             : #include <stdint.h>
      38             : #include <string.h>
      39             : #include <fcntl.h>
      40             : #include <poll.h>
      41             : #include <time.h>
      42             : 
      43             : #include <libintl.h>
      44             : #define _(STRING) dgettext (PACKAGE, STRING)
      45             : #include "sss_cli.h"
      46             : 
      47             : #if HAVE_PTHREAD
      48             : #include <pthread.h>
      49             : #endif
      50             : 
      51             : /*
      52             : * Note we set MSG_NOSIGNAL to avoid
      53             : * having to fiddle with signal masks
      54             : * but also do not want to die in case
      55             : * SIGPIPE gets raised and the application
      56             : * does not handle it.
      57             : */
      58             : #ifdef MSG_NOSIGNAL
      59             : #define SSS_DEFAULT_WRITE_FLAGS MSG_NOSIGNAL
      60             : #else
      61             : #define SSS_DEFAULT_WRITE_FLAGS 0
      62             : #endif
      63             : 
      64             : /* common functions */
      65             : 
      66             : int sss_cli_sd = -1; /* the sss client socket descriptor */
      67             : struct stat sss_cli_sb; /* the sss client stat buffer */
      68             : 
      69             : #if HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR
      70             : __attribute__((destructor))
      71             : #endif
      72          14 : static void sss_cli_close_socket(void)
      73             : {
      74          14 :     if (sss_cli_sd != -1) {
      75           0 :         close(sss_cli_sd);
      76           0 :         sss_cli_sd = -1;
      77             :     }
      78          14 : }
      79             : 
      80             : /* Requests:
      81             :  *
      82             :  * byte 0-3: 32bit unsigned with length (the complete packet length: 0 to X)
      83             :  * byte 4-7: 32bit unsigned with command code
      84             :  * byte 8-11: 32bit unsigned (reserved)
      85             :  * byte 12-15: 32bit unsigned (reserved)
      86             :  * byte 16-X: (optional) request structure associated to the command code used
      87             :  */
      88           0 : static enum sss_status sss_cli_send_req(enum sss_cli_command cmd,
      89             :                                         struct sss_cli_req_data *rd,
      90             :                                         int *errnop)
      91             : {
      92             :     uint32_t header[4];
      93             :     size_t datasent;
      94             : 
      95           0 :     header[0] = SSS_NSS_HEADER_SIZE + (rd?rd->len:0);
      96           0 :     header[1] = cmd;
      97           0 :     header[2] = 0;
      98           0 :     header[3] = 0;
      99             : 
     100           0 :     datasent = 0;
     101             : 
     102           0 :     while (datasent < header[0]) {
     103             :         struct pollfd pfd;
     104             :         int rdsent;
     105             :         int res, error;
     106             : 
     107           0 :         *errnop = 0;
     108           0 :         pfd.fd = sss_cli_sd;
     109           0 :         pfd.events = POLLOUT;
     110             : 
     111             :         do {
     112           0 :             errno = 0;
     113           0 :             res = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT);
     114           0 :             error = errno;
     115             : 
     116             :             /* If error is EINTR here, we'll try again
     117             :              * If it's any other error, we'll catch it
     118             :              * below.
     119             :              */
     120           0 :         } while (error == EINTR);
     121             : 
     122           0 :         switch (res) {
     123             :         case -1:
     124           0 :             *errnop = error;
     125           0 :             break;
     126             :         case 0:
     127           0 :             *errnop = ETIME;
     128           0 :             break;
     129             :         case 1:
     130           0 :             if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
     131           0 :                 *errnop = EPIPE;
     132             :             }
     133           0 :             if (!(pfd.revents & POLLOUT)) {
     134           0 :                 *errnop = EBUSY;
     135             :             }
     136           0 :             break;
     137             :         default: /* more than one avail ?? */
     138           0 :             *errnop = EBADF;
     139           0 :             break;
     140             :         }
     141           0 :         if (*errnop) {
     142           0 :             sss_cli_close_socket();
     143           0 :             return SSS_STATUS_UNAVAIL;
     144             :         }
     145             : 
     146           0 :         errno = 0;
     147           0 :         if (datasent < SSS_NSS_HEADER_SIZE) {
     148           0 :             res = send(sss_cli_sd,
     149             :                        (char *)header + datasent,
     150             :                        SSS_NSS_HEADER_SIZE - datasent,
     151             :                        SSS_DEFAULT_WRITE_FLAGS);
     152             :         } else {
     153           0 :             rdsent = datasent - SSS_NSS_HEADER_SIZE;
     154           0 :             res = send(sss_cli_sd,
     155           0 :                        (const char *)rd->data + rdsent,
     156           0 :                        rd->len - rdsent,
     157             :                        SSS_DEFAULT_WRITE_FLAGS);
     158             :         }
     159           0 :         error = errno;
     160             : 
     161           0 :         if ((res == -1) || (res == 0)) {
     162           0 :             if ((error == EINTR) || error == EAGAIN) {
     163             :                 /* If the write was interrupted, go back through
     164             :                  * the loop and try again
     165             :                  */
     166           0 :                 continue;
     167             :             }
     168             : 
     169             :             /* Write failed */
     170           0 :             sss_cli_close_socket();
     171           0 :             *errnop = error;
     172           0 :             return SSS_STATUS_UNAVAIL;
     173             :         }
     174             : 
     175           0 :         datasent += res;
     176             :     }
     177             : 
     178           0 :     return SSS_STATUS_SUCCESS;
     179             : }
     180             : 
     181             : /* Replies:
     182             :  *
     183             :  * byte 0-3: 32bit unsigned with length (the complete packet length: 0 to X)
     184             :  * byte 4-7: 32bit unsigned with command code
     185             :  * byte 8-11: 32bit unsigned with the request status (server errno)
     186             :  * byte 12-15: 32bit unsigned (reserved)
     187             :  * byte 16-X: (optional) reply structure associated to the command code used
     188             :  */
     189             : 
     190           0 : static enum sss_status sss_cli_recv_rep(enum sss_cli_command cmd,
     191             :                                         uint8_t **_buf, int *_len,
     192             :                                         int *errnop)
     193             : {
     194             :     uint32_t header[4];
     195             :     size_t datarecv;
     196           0 :     uint8_t *buf = NULL;
     197           0 :     bool pollhup = false;
     198             :     int len;
     199             :     int ret;
     200             : 
     201           0 :     header[0] = SSS_NSS_HEADER_SIZE; /* unitl we know the real length */
     202           0 :     header[1] = 0;
     203           0 :     header[2] = 0;
     204           0 :     header[3] = 0;
     205             : 
     206           0 :     datarecv = 0;
     207           0 :     buf = NULL;
     208           0 :     len = 0;
     209           0 :     *errnop = 0;
     210             : 
     211           0 :     while (datarecv < header[0]) {
     212             :         struct pollfd pfd;
     213             :         int bufrecv;
     214             :         int res, error;
     215             : 
     216           0 :         pfd.fd = sss_cli_sd;
     217           0 :         pfd.events = POLLIN;
     218             : 
     219             :         do {
     220           0 :             errno = 0;
     221           0 :             res = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT);
     222           0 :             error = errno;
     223             : 
     224             :             /* If error is EINTR here, we'll try again
     225             :              * If it's any other error, we'll catch it
     226             :              * below.
     227             :              */
     228           0 :         } while (error == EINTR);
     229             : 
     230           0 :         switch (res) {
     231             :         case -1:
     232           0 :             *errnop = error;
     233           0 :             break;
     234             :         case 0:
     235           0 :             *errnop = ETIME;
     236           0 :             break;
     237             :         case 1:
     238           0 :             if (pfd.revents & (POLLHUP)) {
     239           0 :                 pollhup = true;
     240             :             }
     241           0 :             if (pfd.revents & (POLLERR | POLLNVAL)) {
     242           0 :                 *errnop = EPIPE;
     243             :             }
     244           0 :             if (!(pfd.revents & POLLIN)) {
     245           0 :                 *errnop = EBUSY;
     246             :             }
     247           0 :             break;
     248             :         default: /* more than one avail ?? */
     249           0 :             *errnop = EBADF;
     250           0 :             break;
     251             :         }
     252           0 :         if (*errnop) {
     253           0 :             sss_cli_close_socket();
     254           0 :             ret = SSS_STATUS_UNAVAIL;
     255           0 :             goto failed;
     256             :         }
     257             : 
     258           0 :         errno = 0;
     259           0 :         if (datarecv < SSS_NSS_HEADER_SIZE) {
     260           0 :             res = read(sss_cli_sd,
     261             :                        (char *)header + datarecv,
     262             :                        SSS_NSS_HEADER_SIZE - datarecv);
     263             :         } else {
     264           0 :             bufrecv = datarecv - SSS_NSS_HEADER_SIZE;
     265           0 :             res = read(sss_cli_sd,
     266             :                        (char *) buf + bufrecv,
     267           0 :                        header[0] - datarecv);
     268             :         }
     269           0 :         error = errno;
     270             : 
     271           0 :         if ((res == -1) || (res == 0)) {
     272           0 :             if ((error == EINTR) || error == EAGAIN) {
     273             :                 /* If the read was interrupted, go back through
     274             :                  * the loop and try again
     275             :                  */
     276           0 :                 continue;
     277             :             }
     278             : 
     279             :             /* Read failed.  I think the only useful thing
     280             :              * we can do here is just return -1 and fail
     281             :              * since the transaction has failed half way
     282             :              * through. */
     283             : 
     284           0 :             sss_cli_close_socket();
     285           0 :             *errnop = error;
     286           0 :             ret = SSS_STATUS_UNAVAIL;
     287           0 :             goto failed;
     288             :         }
     289             : 
     290           0 :         datarecv += res;
     291             : 
     292           0 :         if (datarecv == SSS_NSS_HEADER_SIZE && len == 0) {
     293             :             /* at this point recv buf is not yet
     294             :              * allocated and the header has just
     295             :              * been read, do checks and proceed */
     296           0 :             if (header[2] != 0) {
     297             :                 /* server side error */
     298           0 :                 sss_cli_close_socket();
     299           0 :                 *errnop = header[2];
     300           0 :                 if (*errnop == EAGAIN) {
     301           0 :                     ret = SSS_STATUS_TRYAGAIN;
     302           0 :                     goto failed;
     303             :                 } else {
     304           0 :                     ret = SSS_STATUS_UNAVAIL;
     305           0 :                     goto failed;
     306             :                 }
     307             :             }
     308           0 :             if (header[1] != cmd) {
     309             :                 /* wrong command id */
     310           0 :                 sss_cli_close_socket();
     311           0 :                 *errnop = EBADMSG;
     312           0 :                 ret = SSS_STATUS_UNAVAIL;
     313           0 :                 goto failed;
     314             :             }
     315           0 :             if (header[0] > SSS_NSS_HEADER_SIZE) {
     316           0 :                 len = header[0] - SSS_NSS_HEADER_SIZE;
     317           0 :                 buf = malloc(len);
     318           0 :                 if (!buf) {
     319           0 :                     sss_cli_close_socket();
     320           0 :                     *errnop = ENOMEM;
     321           0 :                     ret = SSS_STATUS_UNAVAIL;
     322           0 :                     goto failed;
     323             :                 }
     324             :             }
     325             :         }
     326             :     }
     327             : 
     328           0 :     if (pollhup) {
     329           0 :         sss_cli_close_socket();
     330             :     }
     331             : 
     332           0 :     *_len = len;
     333           0 :     *_buf = buf;
     334             : 
     335           0 :     return SSS_STATUS_SUCCESS;
     336             : 
     337             : failed:
     338           0 :     free(buf);
     339           0 :     return ret;
     340             : }
     341             : 
     342             : /* this function will check command codes match and returned length is ok */
     343             : /* repbuf and replen report only the data section not the header */
     344           0 : static enum sss_status sss_cli_make_request_nochecks(
     345             :                                        enum sss_cli_command cmd,
     346             :                                        struct sss_cli_req_data *rd,
     347             :                                        uint8_t **repbuf, size_t *replen,
     348             :                                        int *errnop)
     349             : {
     350             :     enum sss_status ret;
     351           0 :     uint8_t *buf = NULL;
     352           0 :     int len = 0;
     353             : 
     354             :     /* send data */
     355           0 :     ret = sss_cli_send_req(cmd, rd, errnop);
     356           0 :     if (ret != SSS_STATUS_SUCCESS) {
     357           0 :         return ret;
     358             :     }
     359             : 
     360             :     /* data sent, now get reply */
     361           0 :     ret = sss_cli_recv_rep(cmd, &buf, &len, errnop);
     362           0 :     if (ret != SSS_STATUS_SUCCESS) {
     363           0 :         return ret;
     364             :     }
     365             : 
     366             :     /* we got through, now we have the custom data in buf if any,
     367             :      * return it if requested */
     368           0 :     if (repbuf && buf) {
     369           0 :         *repbuf = buf;
     370           0 :         if (replen) {
     371           0 :             *replen = len;
     372             :         }
     373             :     } else {
     374           0 :         free(buf);
     375           0 :         if (replen) {
     376           0 :             *replen = 0;
     377             :         }
     378             :     }
     379             : 
     380           0 :     return SSS_STATUS_SUCCESS;
     381             : }
     382             : 
     383             : /* GET_VERSION Reply:
     384             :  * 0-3: 32bit unsigned version number
     385             :  */
     386             : 
     387           0 : static bool sss_cli_check_version(const char *socket_name)
     388             : {
     389           0 :     uint8_t *repbuf = NULL;
     390             :     size_t replen;
     391             :     enum sss_status nret;
     392             :     int errnop;
     393             :     uint32_t expected_version;
     394             :     uint32_t obtained_version;
     395             :     struct sss_cli_req_data req;
     396             : 
     397           0 :     if (strcmp(socket_name, SSS_NSS_SOCKET_NAME) == 0) {
     398           0 :         expected_version = SSS_NSS_PROTOCOL_VERSION;
     399           0 :     } else if (strcmp(socket_name, SSS_PAM_SOCKET_NAME) == 0 ||
     400           0 :                strcmp(socket_name, SSS_PAM_PRIV_SOCKET_NAME) == 0) {
     401           0 :         expected_version = SSS_PAM_PROTOCOL_VERSION;
     402           0 :     } else if (strcmp(socket_name, SSS_SUDO_SOCKET_NAME) == 0) {
     403           0 :         expected_version = SSS_SUDO_PROTOCOL_VERSION;
     404           0 :     } else if (strcmp(socket_name, SSS_AUTOFS_SOCKET_NAME) == 0) {
     405           0 :         expected_version = SSS_AUTOFS_PROTOCOL_VERSION;
     406           0 :     } else if (strcmp(socket_name, SSS_SSH_SOCKET_NAME) == 0) {
     407           0 :         expected_version = SSS_SSH_PROTOCOL_VERSION;
     408           0 :     } else if (strcmp(socket_name, SSS_PAC_SOCKET_NAME) == 0) {
     409           0 :         expected_version = SSS_PAC_PROTOCOL_VERSION;
     410             :     } else {
     411           0 :         return false;
     412             :     }
     413             : 
     414           0 :     req.len = sizeof(expected_version);
     415           0 :     req.data = &expected_version;
     416             : 
     417           0 :     nret = sss_cli_make_request_nochecks(SSS_GET_VERSION, &req,
     418             :                                          &repbuf, &replen, &errnop);
     419           0 :     if (nret != SSS_STATUS_SUCCESS) {
     420           0 :         return false;
     421             :     }
     422             : 
     423           0 :     if (!repbuf) {
     424           0 :         return false;
     425             :     }
     426             : 
     427           0 :     SAFEALIGN_COPY_UINT32(&obtained_version, repbuf, NULL);
     428           0 :     free(repbuf);
     429             : 
     430           0 :     return (obtained_version == expected_version);
     431             : }
     432             : 
     433             : /* this 2 functions are adapted from samba3 winbinbd's wb_common.c */
     434             : 
     435             : /* Make sure socket handle isn't stdin (0), stdout(1) or stderr(2) by setting
     436             :  * the limit to 3 */
     437             : #define RECURSION_LIMIT 3
     438             : 
     439          65 : static int make_nonstd_fd_internals(int fd, int limit)
     440             : {
     441             :     int new_fd;
     442          65 :     if (fd >= 0 && fd <= 2) {
     443             : #ifdef F_DUPFD
     444           0 :         if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
     445           0 :             return -1;
     446             :         }
     447             :         /* Paranoia */
     448           0 :         if (new_fd < 3) {
     449           0 :             close(new_fd);
     450           0 :             return -1;
     451             :         }
     452           0 :         close(fd);
     453           0 :         return new_fd;
     454             : #else
     455             :         if (limit <= 0)
     456             :             return -1;
     457             : 
     458             :         new_fd = dup(fd);
     459             :         if (new_fd == -1)
     460             :             return -1;
     461             : 
     462             :         /* use the program stack to hold our list of FDs to close */
     463             :         new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
     464             :         close(fd);
     465             :         return new_fd;
     466             : #endif
     467             :     }
     468          65 :     return fd;
     469             : }
     470             : 
     471             : /****************************************************************************
     472             :  Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
     473             :  else
     474             :  if SYSV use O_NDELAY
     475             :  if BSD use FNDELAY
     476             :  Set close on exec also.
     477             : ****************************************************************************/
     478             : 
     479          65 : static int make_safe_fd(int fd)
     480             : {
     481             :     int result, flags;
     482          65 :     int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
     483          65 :     if (new_fd == -1) {
     484           0 :         close(fd);
     485           0 :         return -1;
     486             :     }
     487             : 
     488             :     /* Socket should be nonblocking. */
     489             : #ifdef O_NONBLOCK
     490             : #define FLAG_TO_SET O_NONBLOCK
     491             : #else
     492             : #ifdef SYSV
     493             : #define FLAG_TO_SET O_NDELAY
     494             : #else /* BSD */
     495             : #define FLAG_TO_SET FNDELAY
     496             : #endif
     497             : #endif
     498             : 
     499          65 :     if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
     500           0 :         close(new_fd);
     501           0 :         return -1;
     502             :     }
     503             : 
     504          65 :     flags |= FLAG_TO_SET;
     505          65 :     if (fcntl(new_fd, F_SETFL, flags) == -1) {
     506           0 :         close(new_fd);
     507           0 :         return -1;
     508             :     }
     509             : 
     510             : #undef FLAG_TO_SET
     511             : 
     512             :     /* Socket should be closed on exec() */
     513             : #ifdef FD_CLOEXEC
     514          65 :     result = flags = fcntl(new_fd, F_GETFD, 0);
     515          65 :     if (flags >= 0) {
     516          65 :         flags |= FD_CLOEXEC;
     517          65 :         result = fcntl( new_fd, F_SETFD, flags );
     518             :     }
     519          65 :     if (result < 0) {
     520           0 :         close(new_fd);
     521           0 :         return -1;
     522             :     }
     523             : #endif
     524          65 :     return new_fd;
     525             : }
     526             : 
     527          65 : static int sss_cli_open_socket(int *errnop, const char *socket_name)
     528             : {
     529             :     struct sockaddr_un nssaddr;
     530          65 :     bool inprogress = true;
     531          65 :     bool connected = false;
     532             :     unsigned int wait_time;
     533             :     unsigned int sleep_time;
     534          65 :     time_t start_time = time(NULL);
     535             :     int ret;
     536             :     int sd;
     537             : 
     538          65 :     memset(&nssaddr, 0, sizeof(struct sockaddr_un));
     539          65 :     nssaddr.sun_family = AF_UNIX;
     540          65 :     strncpy(nssaddr.sun_path, socket_name,
     541          65 :             strlen(socket_name) + 1);
     542             : 
     543          65 :     sd = socket(AF_UNIX, SOCK_STREAM, 0);
     544          65 :     if (sd == -1) {
     545           0 :         *errnop = errno;
     546           0 :         return -1;
     547             :     }
     548             : 
     549             :     /* set as non-blocking, close on exec, and make sure standard
     550             :      * descriptors are not used */
     551          65 :     sd = make_safe_fd(sd);
     552          65 :     if (sd == -1) {
     553           0 :         *errnop = errno;
     554           0 :         return -1;
     555             :     }
     556             : 
     557             :     /* this piece is adapted from winbind client code */
     558          65 :     wait_time = 0;
     559          65 :     sleep_time = 0;
     560         195 :     while (inprogress) {
     561          65 :         int connect_errno = 0;
     562             :         socklen_t errnosize;
     563             :         struct pollfd pfd;
     564             : 
     565          65 :         wait_time += sleep_time;
     566             : 
     567          65 :         ret = connect(sd, (struct sockaddr *)&nssaddr,
     568             :                       sizeof(nssaddr));
     569          65 :         if (ret == 0) {
     570           0 :             connected = true;
     571           0 :             break;
     572             :         }
     573             : 
     574          65 :         switch(errno) {
     575             :         case EINPROGRESS:
     576           0 :             pfd.fd = sd;
     577           0 :             pfd.events = POLLOUT;
     578             : 
     579           0 :             ret = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT - wait_time);
     580             : 
     581           0 :             if (ret > 0) {
     582           0 :                 errnosize = sizeof(connect_errno);
     583           0 :                 ret = getsockopt(sd, SOL_SOCKET, SO_ERROR,
     584             :                                  &connect_errno, &errnosize);
     585           0 :                 if (ret >= 0 && connect_errno == 0) {
     586           0 :                     connected = true;
     587           0 :                     break;
     588             :                 }
     589             :             }
     590           0 :             wait_time = time(NULL) - start_time;
     591           0 :             break;
     592             :         case EAGAIN:
     593           0 :             if (wait_time < SSS_CLI_SOCKET_TIMEOUT) {
     594           0 :                 sleep_time = rand() % 2 + 1;
     595           0 :                 sleep(sleep_time);
     596             :             }
     597           0 :             break;
     598             :         default:
     599          65 :             *errnop = errno;
     600          65 :             inprogress = false;
     601          65 :             break;
     602             :         }
     603             : 
     604          65 :         if (wait_time >= SSS_CLI_SOCKET_TIMEOUT) {
     605           0 :             inprogress = false;
     606             :         }
     607             : 
     608          65 :         if (connected) {
     609           0 :             inprogress = false;
     610             :         }
     611             :     }
     612             : 
     613          65 :     if (!connected) {
     614          65 :         close(sd);
     615          65 :         return -1;
     616             :     }
     617             : 
     618           0 :     ret = fstat(sd, &sss_cli_sb);
     619           0 :     if (ret != 0) {
     620           0 :         close(sd);
     621           0 :         return -1;
     622             :     }
     623             : 
     624           0 :     return sd;
     625             : }
     626             : 
     627          65 : static enum sss_status sss_cli_check_socket(int *errnop, const char *socket_name)
     628             : {
     629             :     static pid_t mypid;
     630             :     struct stat mysb;
     631             :     int mysd;
     632             :     int ret;
     633             : 
     634          65 :     if (getpid() != mypid) {
     635           4 :         ret = fstat(sss_cli_sd, &mysb);
     636           4 :         if (ret == 0) {
     637           0 :             if (S_ISSOCK(mysb.st_mode) &&
     638           0 :                 mysb.st_dev == sss_cli_sb.st_dev &&
     639           0 :                 mysb.st_ino == sss_cli_sb.st_ino) {
     640           0 :                 sss_cli_close_socket();
     641             :             }
     642             :         }
     643           4 :         sss_cli_sd = -1;
     644           4 :         mypid = getpid();
     645             :     }
     646             : 
     647             :     /* check if the socket has been closed on the other side */
     648          65 :     if (sss_cli_sd != -1) {
     649             :         struct pollfd pfd;
     650             :         int res, error;
     651             : 
     652           0 :         *errnop = 0;
     653           0 :         pfd.fd = sss_cli_sd;
     654           0 :         pfd.events = POLLIN | POLLOUT;
     655             : 
     656             :         do {
     657           0 :             errno = 0;
     658           0 :             res = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT);
     659           0 :             error = errno;
     660             : 
     661             :             /* If error is EINTR here, we'll try again
     662             :              * If it's any other error, we'll catch it
     663             :              * below.
     664             :              */
     665           0 :         } while (error == EINTR);
     666             : 
     667           0 :         switch (res) {
     668             :         case -1:
     669           0 :             *errnop = error;
     670           0 :             break;
     671             :         case 0:
     672           0 :             *errnop = ETIME;
     673           0 :             break;
     674             :         case 1:
     675           0 :             if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
     676           0 :                 *errnop = EPIPE;
     677             :             }
     678           0 :             if (!(pfd.revents & (POLLIN | POLLOUT))) {
     679           0 :                 *errnop = EBUSY;
     680             :             }
     681           0 :             break;
     682             :         default: /* more than one avail ?? */
     683           0 :             *errnop = EBADF;
     684           0 :             break;
     685             :         }
     686           0 :         if (*errnop == 0) {
     687           0 :             return SSS_STATUS_SUCCESS;
     688             :         }
     689             : 
     690           0 :         sss_cli_close_socket();
     691             :     }
     692             : 
     693          65 :     mysd = sss_cli_open_socket(errnop, socket_name);
     694          65 :     if (mysd == -1) {
     695          65 :         return SSS_STATUS_UNAVAIL;
     696             :     }
     697             : 
     698           0 :     sss_cli_sd = mysd;
     699             : 
     700           0 :     if (sss_cli_check_version(socket_name)) {
     701           0 :         return SSS_STATUS_SUCCESS;
     702             :     }
     703             : 
     704           0 :     sss_cli_close_socket();
     705           0 :     *errnop = EFAULT;
     706           0 :     return SSS_STATUS_UNAVAIL;
     707             : }
     708             : 
     709             : /* this function will check command codes match and returned length is ok */
     710             : /* repbuf and replen report only the data section not the header */
     711          65 : enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
     712             :                       struct sss_cli_req_data *rd,
     713             :                       uint8_t **repbuf, size_t *replen,
     714             :                       int *errnop)
     715             : {
     716             :     enum sss_status ret;
     717             :     char *envval;
     718             : 
     719             :     /* avoid looping in the nss daemon */
     720          65 :     envval = getenv("_SSS_LOOPS");
     721          65 :     if (envval && strcmp(envval, "NO") == 0) {
     722           0 :         return NSS_STATUS_NOTFOUND;
     723             :     }
     724             : 
     725          65 :     ret = sss_cli_check_socket(errnop, SSS_NSS_SOCKET_NAME);
     726          65 :     if (ret != SSS_STATUS_SUCCESS) {
     727             : #ifdef NONSTANDARD_SSS_NSS_BEHAVIOUR
     728             :         *errnop = 0;
     729             :         errno = 0;
     730             :         return NSS_STATUS_NOTFOUND;
     731             : #else
     732          65 :         return NSS_STATUS_UNAVAIL;
     733             : #endif
     734             :     }
     735             : 
     736           0 :     ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     737           0 :     if (ret == SSS_STATUS_UNAVAIL && *errnop == EPIPE) {
     738             :         /* try reopen socket */
     739           0 :         ret = sss_cli_check_socket(errnop, SSS_NSS_SOCKET_NAME);
     740           0 :         if (ret != SSS_STATUS_SUCCESS) {
     741             : #ifdef NONSTANDARD_SSS_NSS_BEHAVIOUR
     742             :             *errnop = 0;
     743             :             errno = 0;
     744             :             return NSS_STATUS_NOTFOUND;
     745             : #else
     746           0 :             return NSS_STATUS_UNAVAIL;
     747             : #endif
     748             :         }
     749             : 
     750             :         /* and make request one more time */
     751           0 :         ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     752             :     }
     753           0 :     switch (ret) {
     754             :     case SSS_STATUS_TRYAGAIN:
     755           0 :         return NSS_STATUS_TRYAGAIN;
     756             :     case SSS_STATUS_SUCCESS:
     757           0 :         return NSS_STATUS_SUCCESS;
     758             :     case SSS_STATUS_UNAVAIL:
     759             :     default:
     760             : #ifdef NONSTANDARD_SSS_NSS_BEHAVIOUR
     761             :         *errnop = 0;
     762             :         errno = 0;
     763             :         return NSS_STATUS_NOTFOUND;
     764             : #else
     765           0 :         return NSS_STATUS_UNAVAIL;
     766             : #endif
     767             :     }
     768             : }
     769             : 
     770           0 : int sss_pac_check_and_open(void)
     771             : {
     772             :     enum sss_status ret;
     773             :     int errnop;
     774             : 
     775           0 :     ret = sss_cli_check_socket(&errnop, SSS_PAC_SOCKET_NAME);
     776           0 :     if (ret != SSS_STATUS_SUCCESS) {
     777           0 :         return EIO;
     778             :     }
     779             : 
     780           0 :     return EOK;
     781             : }
     782             : 
     783           0 : int sss_pac_make_request(enum sss_cli_command cmd,
     784             :                          struct sss_cli_req_data *rd,
     785             :                          uint8_t **repbuf, size_t *replen,
     786             :                          int *errnop)
     787             : {
     788             :     enum sss_status ret;
     789             :     char *envval;
     790             : 
     791             :     /* avoid looping in the nss daemon */
     792           0 :     envval = getenv("_SSS_LOOPS");
     793           0 :     if (envval && strcmp(envval, "NO") == 0) {
     794           0 :         return NSS_STATUS_NOTFOUND;
     795             :     }
     796             : 
     797           0 :     ret = sss_cli_check_socket(errnop, SSS_PAC_SOCKET_NAME);
     798           0 :     if (ret != SSS_STATUS_SUCCESS) {
     799           0 :         return NSS_STATUS_UNAVAIL;
     800             :     }
     801             : 
     802           0 :     ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     803           0 :     if (ret == SSS_STATUS_UNAVAIL && *errnop == EPIPE) {
     804             :         /* try reopen socket */
     805           0 :         ret = sss_cli_check_socket(errnop, SSS_PAC_SOCKET_NAME);
     806           0 :         if (ret != SSS_STATUS_SUCCESS) {
     807           0 :             return NSS_STATUS_UNAVAIL;
     808             :         }
     809             : 
     810             :         /* and make request one more time */
     811           0 :         ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     812             :     }
     813           0 :     switch (ret) {
     814             :     case SSS_STATUS_TRYAGAIN:
     815           0 :         return NSS_STATUS_TRYAGAIN;
     816             :     case SSS_STATUS_SUCCESS:
     817           0 :         return NSS_STATUS_SUCCESS;
     818             :     case SSS_STATUS_UNAVAIL:
     819             :     default:
     820           0 :         return NSS_STATUS_UNAVAIL;
     821             :     }
     822             : }
     823             : 
     824           0 : errno_t check_server_cred(int sockfd)
     825             : {
     826             : #ifdef HAVE_UCRED
     827             :     int ret;
     828             :     struct ucred server_cred;
     829           0 :     socklen_t server_cred_len = sizeof(server_cred);
     830             : 
     831           0 :     ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &server_cred,
     832             :                      &server_cred_len);
     833           0 :     if (ret != 0) {
     834           0 :         return errno;
     835             :     }
     836             : 
     837           0 :     if (server_cred_len != sizeof(struct ucred)) {
     838           0 :         return ESSS_BAD_CRED_MSG;
     839             :     }
     840             : 
     841           0 :     if (server_cred.uid != 0 || server_cred.gid != 0) {
     842           0 :         return ESSS_SERVER_NOT_TRUSTED;
     843             :     }
     844             : #endif
     845           0 :     return 0;
     846             : }
     847             : 
     848           0 : int sss_pam_make_request(enum sss_cli_command cmd,
     849             :                       struct sss_cli_req_data *rd,
     850             :                       uint8_t **repbuf, size_t *replen,
     851             :                       int *errnop)
     852             : {
     853             :     int ret, statret;
     854             :     errno_t error;
     855             :     enum sss_status status;
     856             :     char *envval;
     857             :     struct stat stat_buf;
     858             :     const char *socket_name;
     859             : 
     860           0 :     sss_pam_lock();
     861             : 
     862             :     /* avoid looping in the pam daemon */
     863           0 :     envval = getenv("_SSS_LOOPS");
     864           0 :     if (envval && strcmp(envval, "NO") == 0) {
     865           0 :         ret = PAM_SERVICE_ERR;
     866           0 :         goto out;
     867             :     }
     868             : 
     869             :     /* only root shall use the privileged pipe */
     870           0 :     if (getuid() == 0 && getgid() == 0) {
     871           0 :         socket_name = SSS_PAM_PRIV_SOCKET_NAME;
     872           0 :         statret = stat(socket_name, &stat_buf);
     873           0 :         if (statret != 0) {
     874           0 :             ret = PAM_SERVICE_ERR;
     875           0 :             goto out;
     876             :         }
     877           0 :         if ( ! (stat_buf.st_uid == 0 &&
     878           0 :                 stat_buf.st_gid == 0 &&
     879           0 :                 S_ISSOCK(stat_buf.st_mode) &&
     880           0 :                 (stat_buf.st_mode & ~S_IFMT) == 0600 )) {
     881           0 :             *errnop = ESSS_BAD_PRIV_SOCKET;
     882           0 :             ret = PAM_SERVICE_ERR;
     883           0 :             goto out;
     884             :         }
     885             :     } else {
     886           0 :         socket_name = SSS_PAM_SOCKET_NAME;
     887           0 :         statret = stat(socket_name, &stat_buf);
     888           0 :         if (statret != 0) {
     889           0 :             ret = PAM_SERVICE_ERR;
     890           0 :             goto out;
     891             :         }
     892           0 :         if ( ! (stat_buf.st_uid == 0 &&
     893           0 :                 stat_buf.st_gid == 0 &&
     894           0 :                 S_ISSOCK(stat_buf.st_mode) &&
     895           0 :                 (stat_buf.st_mode & ~S_IFMT) == 0666 )) {
     896           0 :             *errnop = ESSS_BAD_PUB_SOCKET;
     897           0 :             ret = PAM_SERVICE_ERR;
     898           0 :             goto out;
     899             :         }
     900             :     }
     901             : 
     902           0 :     status = sss_cli_check_socket(errnop, socket_name);
     903           0 :     if (status != SSS_STATUS_SUCCESS) {
     904           0 :         ret = PAM_SERVICE_ERR;
     905           0 :         goto out;
     906             :     }
     907             : 
     908           0 :     error = check_server_cred(sss_cli_sd);
     909           0 :     if (error != 0) {
     910           0 :         sss_cli_close_socket();
     911           0 :         *errnop = error;
     912           0 :         ret = PAM_SERVICE_ERR;
     913           0 :         goto out;
     914             :     }
     915             : 
     916           0 :     status = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     917           0 :     if (status == SSS_STATUS_UNAVAIL && *errnop == EPIPE) {
     918             :         /* try reopen socket */
     919           0 :         status = sss_cli_check_socket(errnop, socket_name);
     920           0 :         if (status != SSS_STATUS_SUCCESS) {
     921           0 :             ret = PAM_SERVICE_ERR;
     922           0 :             goto out;
     923             :         }
     924             : 
     925             :         /* and make request one more time */
     926           0 :         status = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     927             :     }
     928             : 
     929           0 :     if (status == SSS_STATUS_SUCCESS) {
     930           0 :         ret = PAM_SUCCESS;
     931             :     } else {
     932           0 :         ret = PAM_SERVICE_ERR;
     933             :     }
     934             : 
     935             : out:
     936           0 :     sss_pam_unlock();
     937           0 :     return ret;
     938             : }
     939             : 
     940           0 : void sss_pam_close_fd(void)
     941             : {
     942           0 :     sss_pam_lock();
     943             : 
     944           0 :     if (sss_cli_sd != -1) {
     945           0 :         close(sss_cli_sd);
     946           0 :         sss_cli_sd = -1;
     947             :     }
     948             : 
     949           0 :     sss_pam_unlock();
     950           0 : }
     951             : 
     952             : static enum sss_status
     953           0 : sss_cli_make_request_with_checks(enum sss_cli_command cmd,
     954             :                                  struct sss_cli_req_data *rd,
     955             :                                  uint8_t **repbuf, size_t *replen,
     956             :                                  int *errnop,
     957             :                                  const char *socket_name)
     958             : {
     959           0 :     enum sss_status ret = SSS_STATUS_UNAVAIL;
     960             : 
     961           0 :     ret = sss_cli_check_socket(errnop, socket_name);
     962           0 :     if (ret != SSS_STATUS_SUCCESS) {
     963           0 :         return SSS_STATUS_UNAVAIL;
     964             :     }
     965             : 
     966           0 :     ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     967           0 :     if (ret == SSS_STATUS_UNAVAIL && *errnop == EPIPE) {
     968             :         /* try reopen socket */
     969           0 :         ret = sss_cli_check_socket(errnop, socket_name);
     970           0 :         if (ret != SSS_STATUS_SUCCESS) {
     971           0 :             return SSS_STATUS_UNAVAIL;
     972             :         }
     973             : 
     974             :         /* and make request one more time */
     975           0 :         ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
     976             :     }
     977             : 
     978           0 :     return ret;
     979             : }
     980             : 
     981           0 : int sss_sudo_make_request(enum sss_cli_command cmd,
     982             :                           struct sss_cli_req_data *rd,
     983             :                           uint8_t **repbuf, size_t *replen,
     984             :                           int *errnop)
     985             : {
     986           0 :     return sss_cli_make_request_with_checks(cmd, rd, repbuf, replen, errnop,
     987             :                                             SSS_SUDO_SOCKET_NAME);
     988             : }
     989             : 
     990           0 : int sss_autofs_make_request(enum sss_cli_command cmd,
     991             :                             struct sss_cli_req_data *rd,
     992             :                             uint8_t **repbuf, size_t *replen,
     993             :                             int *errnop)
     994             : {
     995           0 :     return sss_cli_make_request_with_checks(cmd, rd, repbuf, replen, errnop,
     996             :                                             SSS_AUTOFS_SOCKET_NAME);
     997             : }
     998             : 
     999           0 : int sss_ssh_make_request(enum sss_cli_command cmd,
    1000             :                          struct sss_cli_req_data *rd,
    1001             :                          uint8_t **repbuf, size_t *replen,
    1002             :                          int *errnop)
    1003             : {
    1004           0 :     return sss_cli_make_request_with_checks(cmd, rd, repbuf, replen, errnop,
    1005             :                                             SSS_SSH_SOCKET_NAME);
    1006             : }
    1007             : 
    1008             : 
    1009           0 : const char *ssscli_err2string(int err)
    1010             : {
    1011             :     const char *m;
    1012             : 
    1013           0 :     switch(err) {
    1014             :         case ESSS_BAD_PRIV_SOCKET:
    1015           0 :             return _("Privileged socket has wrong ownership or permissions.");
    1016             :             break;
    1017             :         case ESSS_BAD_PUB_SOCKET:
    1018           0 :             return _("Public socket has wrong ownership or permissions.");
    1019             :             break;
    1020             :         case ESSS_BAD_CRED_MSG:
    1021           0 :             return _("Unexpected format of the server credential message.");
    1022             :             break;
    1023             :         case ESSS_SERVER_NOT_TRUSTED:
    1024           0 :             return _("SSSD is not run by root.");
    1025             :             break;
    1026             :         default:
    1027           0 :             m = strerror(err);
    1028           0 :             if (m == NULL) {
    1029           0 :                 return _("An error occurred, but no description can be found.");
    1030             :             }
    1031           0 :             return m;
    1032             :             break;
    1033             :     }
    1034             : 
    1035             :     return _("Unexpected error while looking for an error description");
    1036             : }
    1037             : 
    1038             : /* Return strlen(str) or maxlen, whichever is shorter
    1039             :  * Returns EINVAL if str is NULL, EFBIG if str is longer than maxlen
    1040             :  * _len will return the result
    1041             :  *
    1042             :  * This function is useful for preventing buffer overflow attacks.
    1043             :  */
    1044          67 : errno_t sss_strnlen(const char *str, size_t maxlen, size_t *len)
    1045             : {
    1046          67 :     if (!str) {
    1047           0 :         return EINVAL;
    1048             :     }
    1049             : 
    1050             : #if defined __USE_GNU
    1051          67 :     *len = strnlen(str, maxlen);
    1052             : #else
    1053             :     *len = 0;
    1054             :     while (*len < maxlen) {
    1055             :         if (str[*len] == '\0') break;
    1056             :         (*len)++;
    1057             :     }
    1058             : #endif
    1059             : 
    1060          67 :     if (*len == maxlen && str[*len] != '\0') {
    1061           0 :         return EFBIG;
    1062             :     }
    1063             : 
    1064          67 :     return 0;
    1065             : }
    1066             : 
    1067             : #if HAVE_PTHREAD
    1068             : typedef void (*sss_mutex_init)(void);
    1069             : 
    1070             : struct sss_mutex {
    1071             :     pthread_mutex_t mtx;
    1072             : 
    1073             :     pthread_once_t once;
    1074             :     sss_mutex_init init;
    1075             : };
    1076             : 
    1077             : static void sss_nss_mt_init(void);
    1078             : static void sss_pam_mt_init(void);
    1079             : static void sss_nss_mc_mt_init(void);
    1080             : 
    1081             : static struct sss_mutex sss_nss_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER,
    1082             :                                         .once = PTHREAD_ONCE_INIT,
    1083             :                                         .init = sss_nss_mt_init };
    1084             : 
    1085             : static struct sss_mutex sss_pam_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER,
    1086             :                                         .once = PTHREAD_ONCE_INIT,
    1087             :                                         .init = sss_pam_mt_init };
    1088             : 
    1089             : static struct sss_mutex sss_nss_mc_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER,
    1090             :                                            .once = PTHREAD_ONCE_INIT,
    1091             :                                            .init = sss_nss_mc_mt_init };
    1092             : 
    1093             : /* Wrappers for robust mutex support */
    1094           9 : static int sss_mutexattr_setrobust (pthread_mutexattr_t *attr)
    1095             : {
    1096             : #ifdef HAVE_PTHREAD_MUTEXATTR_SETROBUST
    1097           9 :     return pthread_mutexattr_setrobust(attr, PTHREAD_MUTEX_ROBUST);
    1098             : #elif defined(HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP)
    1099             :     return pthread_mutexattr_setrobust_np(attr, PTHREAD_MUTEX_ROBUST_NP);
    1100             : #else
    1101             : #warning Robust mutexes are not supported on this platform.
    1102             :     return 0;
    1103             : #endif
    1104             : }
    1105             : 
    1106           0 : static int sss_mutex_consistent(pthread_mutex_t *mtx)
    1107             : {
    1108             : #ifdef HAVE_PTHREAD_MUTEX_CONSISTENT
    1109           0 :     return pthread_mutex_consistent(mtx);
    1110             : #elif defined(HAVE_PTHREAD_MUTEX_CONSISTENT_NP)
    1111             :     return pthread_mutex_consistent_np(mtx);
    1112             : #else
    1113             : #warning Robust mutexes are not supported on this platform.
    1114             :     return 0;
    1115             : #endif
    1116             : }
    1117             : 
    1118             : /* Generic mutex init, lock, unlock functions */
    1119           9 : static void sss_mt_init(struct sss_mutex *m)
    1120             : {
    1121             :     pthread_mutexattr_t attr;
    1122             : 
    1123           9 :     if (pthread_mutexattr_init(&attr) != 0) {
    1124           0 :         return;
    1125             :     }
    1126           9 :     if (sss_mutexattr_setrobust(&attr) != 0) {
    1127           0 :         return;
    1128             :     }
    1129             : 
    1130           9 :     pthread_mutex_init(&m->mtx, &attr);
    1131           9 :     pthread_mutexattr_destroy(&attr);
    1132             : }
    1133             : 
    1134         200 : static void sss_mt_lock(struct sss_mutex *m)
    1135             : {
    1136         200 :     pthread_once(&m->once, m->init);
    1137         200 :     if (pthread_mutex_lock(&m->mtx) == EOWNERDEAD) {
    1138           0 :         sss_cli_close_socket();
    1139           0 :         sss_mutex_consistent(&m->mtx);
    1140             :     }
    1141         200 : }
    1142             : 
    1143         200 : static void sss_mt_unlock(struct sss_mutex *m)
    1144             : {
    1145         200 :     pthread_mutex_unlock(&m->mtx);
    1146         200 : }
    1147             : 
    1148             : /* NSS mutex wrappers */
    1149           5 : static void sss_nss_mt_init(void)
    1150             : {
    1151           5 :     sss_mt_init(&sss_nss_mtx);
    1152           5 : }
    1153          70 : void sss_nss_lock(void)
    1154             : {
    1155          70 :     sss_mt_lock(&sss_nss_mtx);
    1156          70 : }
    1157          70 : void sss_nss_unlock(void)
    1158             : {
    1159          70 :     sss_mt_unlock(&sss_nss_mtx);
    1160          70 : }
    1161             : 
    1162             : /* NSS mutex wrappers */
    1163           0 : static void sss_pam_mt_init(void)
    1164             : {
    1165           0 :     sss_mt_init(&sss_pam_mtx);
    1166           0 : }
    1167           0 : void sss_pam_lock(void)
    1168             : {
    1169           0 :     sss_mt_lock(&sss_pam_mtx);
    1170           0 : }
    1171           0 : void sss_pam_unlock(void)
    1172             : {
    1173           0 :     sss_mt_unlock(&sss_pam_mtx);
    1174           0 : }
    1175             : 
    1176             : /* NSS mutex wrappers */
    1177           4 : static void sss_nss_mc_mt_init(void)
    1178             : {
    1179           4 :     sss_mt_init(&sss_nss_mc_mtx);
    1180           4 : }
    1181         130 : void sss_nss_mc_lock(void)
    1182             : {
    1183         130 :     sss_mt_lock(&sss_nss_mc_mtx);
    1184         130 : }
    1185         130 : void sss_nss_mc_unlock(void)
    1186             : {
    1187         130 :     sss_mt_unlock(&sss_nss_mc_mtx);
    1188         130 : }
    1189             : 
    1190             : #else
    1191             : 
    1192             : /* sorry no mutexes available */
    1193             : void sss_nss_lock(void) { return; }
    1194             : void sss_nss_unlock(void) { return; }
    1195             : void sss_pam_lock(void) { return; }
    1196             : void sss_pam_unlock(void) { return; }
    1197             : void sss_nss_mc_lock(void) { return; }
    1198             : void sss_nss_mc_unlock(void) { return; }
    1199             : #endif
    1200             : 
    1201             : 
    1202           0 : errno_t sss_readrep_copy_string(const char *in,
    1203             :                                 size_t *offset,
    1204             :                                 size_t *slen,
    1205             :                                 size_t *dlen,
    1206             :                                 char **out,
    1207             :                                 size_t *size)
    1208             : {
    1209           0 :     size_t i = 0;
    1210           0 :     while (*slen > *offset && *dlen > 0) {
    1211           0 :         (*out)[i] = in[*offset];
    1212           0 :         if ((*out)[i] == '\0') break;
    1213           0 :         i++;
    1214           0 :         (*offset)++;
    1215           0 :         (*dlen)--;
    1216             :     }
    1217           0 :     if (*slen <= *offset) { /* premature end of buf */
    1218           0 :         return EBADMSG;
    1219             :     }
    1220           0 :     if (*dlen == 0) { /* not enough memory */
    1221           0 :         return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
    1222             :     }
    1223           0 :     (*offset)++;
    1224           0 :     (*dlen)--;
    1225           0 :     if (size) {
    1226           0 :         *size = i;
    1227             :     }
    1228             : 
    1229           0 :     return EOK;
    1230             : }

Generated by: LCOV version 1.10