LCOV - code coverage report
Current view: top level - sss_client - nss_passwd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 35 196 17.9 %
Date: 2016-06-29 Functions: 2 8 25.0 %

          Line data    Source code
       1             : /*
       2             :  * System Security Services Daemon. NSS client interface
       3             :  *
       4             :  * Copyright (C) Simo Sorce 2007
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of the
       9             :  * License, or (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /* PASSWD database NSS interface */
      21             : 
      22             : #include <nss.h>
      23             : #include <errno.h>
      24             : #include <sys/types.h>
      25             : #include <unistd.h>
      26             : #include <stdlib.h>
      27             : #include <stdint.h>
      28             : #include <string.h>
      29             : #include "sss_cli.h"
      30             : #include "nss_mc.h"
      31             : 
      32             : static struct sss_nss_getpwent_data {
      33             :     size_t len;
      34             :     size_t ptr;
      35             :     uint8_t *data;
      36             : } sss_nss_getpwent_data;
      37             : 
      38           0 : static void sss_nss_getpwent_data_clean(void) {
      39             : 
      40           0 :     if (sss_nss_getpwent_data.data != NULL) {
      41           0 :         free(sss_nss_getpwent_data.data);
      42           0 :         sss_nss_getpwent_data.data = NULL;
      43             :     }
      44           0 :     sss_nss_getpwent_data.len = 0;
      45           0 :     sss_nss_getpwent_data.ptr = 0;
      46           0 : }
      47             : 
      48             : /* GETPWNAM Request:
      49             :  *
      50             :  * 0-X: string with name
      51             :  *
      52             :  * GERTPWUID Request:
      53             :  *
      54             :  * 0-3: 32bit number with uid
      55             :  *
      56             :  * Replies:
      57             :  *
      58             :  * 0-3: 32bit unsigned number of results
      59             :  * 4-7: 32bit unsigned (reserved/padding)
      60             :  * For each result:
      61             :  *  0-3: 32bit number uid
      62             :  *  4-7: 32bit number gid
      63             :  *  8-X: sequence of 5, 0 terminated, strings (name, passwd, gecos, dir, shell)
      64             :  */
      65             : 
      66             : struct sss_nss_pw_rep {
      67             :     struct passwd *result;
      68             :     char *buffer;
      69             :     size_t buflen;
      70             : };
      71             : 
      72           0 : static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr,
      73             :                                  uint8_t *buf, size_t *len)
      74             : {
      75             :     errno_t ret;
      76             :     size_t i, slen, dlen;
      77             :     char *sbuf;
      78             :     uint32_t c;
      79             : 
      80           0 :     if (*len < 13) { /* not enough space for data, bad packet */
      81           0 :         return EBADMSG;
      82             :     }
      83             : 
      84           0 :     SAFEALIGN_COPY_UINT32(&c, buf, NULL);
      85           0 :     pr->result->pw_uid = c;
      86           0 :     SAFEALIGN_COPY_UINT32(&c, buf+sizeof(uint32_t), NULL);
      87           0 :     pr->result->pw_gid = c;
      88             : 
      89           0 :     sbuf = (char *)&buf[8];
      90           0 :     slen = *len - 8;
      91           0 :     dlen = pr->buflen;
      92             : 
      93           0 :     i = 0;
      94           0 :     pr->result->pw_name = &(pr->buffer[i]);
      95             : 
      96           0 :     ret = sss_readrep_copy_string(sbuf, &i,
      97             :                                   &slen, &dlen,
      98           0 :                                   &pr->result->pw_name,
      99             :                                   NULL);
     100           0 :     if (ret != EOK) return ret;
     101             : 
     102           0 :     pr->result->pw_passwd = &(pr->buffer[i]);
     103           0 :     ret = sss_readrep_copy_string(sbuf, &i,
     104             :                                   &slen, &dlen,
     105           0 :                                   &pr->result->pw_passwd,
     106             :                                   NULL);
     107           0 :     if (ret != EOK) return ret;
     108             : 
     109           0 :     pr->result->pw_gecos = &(pr->buffer[i]);
     110           0 :     ret = sss_readrep_copy_string(sbuf, &i,
     111             :                                   &slen, &dlen,
     112           0 :                                   &pr->result->pw_gecos,
     113             :                                   NULL);
     114           0 :     if (ret != EOK) return ret;
     115             : 
     116             : 
     117           0 :     pr->result->pw_dir = &(pr->buffer[i]);
     118           0 :     ret = sss_readrep_copy_string(sbuf, &i,
     119             :                                   &slen, &dlen,
     120           0 :                                   &pr->result->pw_dir,
     121             :                                   NULL);
     122           0 :     if (ret != EOK) return ret;
     123             : 
     124           0 :     pr->result->pw_shell = &(pr->buffer[i]);
     125           0 :     ret = sss_readrep_copy_string(sbuf, &i,
     126             :                                   &slen, &dlen,
     127           0 :                                   &pr->result->pw_shell,
     128             :                                   NULL);
     129           0 :     if (ret != EOK) return ret;
     130           0 :     *len = slen - i;
     131             : 
     132           0 :     return 0;
     133             : }
     134             : 
     135          38 : enum nss_status _nss_sss_getpwnam_r(const char *name, struct passwd *result,
     136             :                                     char *buffer, size_t buflen, int *errnop)
     137             : {
     138             :     struct sss_cli_req_data rd;
     139             :     struct sss_nss_pw_rep pwrep;
     140             :     uint8_t *repbuf;
     141             :     size_t replen, len, name_len;
     142             :     uint32_t num_results;
     143             :     enum nss_status nret;
     144             :     int ret;
     145             : 
     146             :     /* Caught once glibc passing in buffer == 0x0 */
     147          38 :     if (!buffer || !buflen) {
     148           0 :         *errnop = ERANGE;
     149           0 :         return NSS_STATUS_TRYAGAIN;
     150             :     }
     151             : 
     152          38 :     ret = sss_strnlen(name, SSS_NAME_MAX, &name_len);
     153          38 :     if (ret != 0) {
     154           0 :         *errnop = EINVAL;
     155           0 :         return NSS_STATUS_NOTFOUND;
     156             :     }
     157             : 
     158          38 :     ret = sss_nss_mc_getpwnam(name, name_len, result, buffer, buflen);
     159          38 :     switch (ret) {
     160             :     case 0:
     161           0 :         *errnop = 0;
     162           0 :         return NSS_STATUS_SUCCESS;
     163             :     case ERANGE:
     164           0 :         *errnop = ERANGE;
     165           0 :         return NSS_STATUS_TRYAGAIN;
     166             :     case ENOENT:
     167             :         /* fall through, we need to actively ask the parent
     168             :          * if no entry is found */
     169          38 :         break;
     170             :     default:
     171             :         /* if using the mmaped cache failed,
     172             :          * fall back to socket based comms */
     173           0 :         break;
     174             :     }
     175             : 
     176          38 :     rd.len = name_len + 1;
     177          38 :     rd.data = name;
     178             : 
     179          38 :     sss_nss_lock();
     180             : 
     181             :     /* previous thread might already initialize entry in mmap cache */
     182          38 :     ret = sss_nss_mc_getpwnam(name, name_len, result, buffer, buflen);
     183          38 :     switch (ret) {
     184             :     case 0:
     185           0 :         *errnop = 0;
     186           0 :         nret = NSS_STATUS_SUCCESS;
     187           0 :         goto out;
     188             :     case ERANGE:
     189           0 :         *errnop = ERANGE;
     190           0 :         nret = NSS_STATUS_TRYAGAIN;
     191           0 :         goto out;
     192             :     case ENOENT:
     193             :         /* fall through, we need to actively ask the parent
     194             :          * if no entry is found */
     195          38 :         break;
     196             :     default:
     197             :         /* if using the mmaped cache failed,
     198             :          * fall back to socket based comms */
     199           0 :         break;
     200             :     }
     201             : 
     202          38 :     nret = sss_nss_make_request(SSS_NSS_GETPWNAM, &rd,
     203             :                                 &repbuf, &replen, errnop);
     204          38 :     if (nret != NSS_STATUS_SUCCESS) {
     205          38 :         goto out;
     206             :     }
     207             : 
     208           0 :     pwrep.result = result;
     209           0 :     pwrep.buffer = buffer;
     210           0 :     pwrep.buflen = buflen;
     211             : 
     212             :     /* Get number of results from repbuf. */
     213           0 :     SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
     214             : 
     215             :     /* no results if not found */
     216           0 :     if (num_results == 0) {
     217           0 :         free(repbuf);
     218           0 :         nret = NSS_STATUS_NOTFOUND;
     219           0 :         goto out;
     220             :     }
     221             : 
     222             :     /* only 1 result is accepted for this function */
     223           0 :     if (num_results != 1) {
     224           0 :         *errnop = EBADMSG;
     225           0 :         free(repbuf);
     226           0 :         nret = NSS_STATUS_TRYAGAIN;
     227           0 :         goto out;
     228             :     }
     229             : 
     230           0 :     len = replen - 8;
     231           0 :     ret = sss_nss_getpw_readrep(&pwrep, repbuf+8, &len);
     232           0 :     free(repbuf);
     233           0 :     if (ret) {
     234           0 :         *errnop = ret;
     235           0 :         nret = NSS_STATUS_TRYAGAIN;
     236           0 :         goto out;
     237             :     }
     238             : 
     239           0 :     nret = NSS_STATUS_SUCCESS;
     240             : 
     241             : out:
     242          38 :     sss_nss_unlock();
     243          38 :     return nret;
     244             : }
     245             : 
     246           1 : enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result,
     247             :                                     char *buffer, size_t buflen, int *errnop)
     248             : {
     249             :     struct sss_cli_req_data rd;
     250             :     struct sss_nss_pw_rep pwrep;
     251             :     uint8_t *repbuf;
     252             :     size_t replen, len;
     253             :     uint32_t num_results;
     254             :     enum nss_status nret;
     255             :     uint32_t user_uid;
     256             :     int ret;
     257             : 
     258             :     /* Caught once glibc passing in buffer == 0x0 */
     259           1 :     if (!buffer || !buflen) return ERANGE;
     260             : 
     261           1 :     ret = sss_nss_mc_getpwuid(uid, result, buffer, buflen);
     262           1 :     switch (ret) {
     263             :     case 0:
     264           0 :         *errnop = 0;
     265           0 :         return NSS_STATUS_SUCCESS;
     266             :     case ERANGE:
     267           0 :         *errnop = ERANGE;
     268           0 :         return NSS_STATUS_TRYAGAIN;
     269             :     case ENOENT:
     270             :         /* fall through, we need to actively ask the parent
     271             :          * if no entry is found */
     272           1 :         break;
     273             :     default:
     274             :         /* if using the mmaped cache failed,
     275             :          * fall back to socket based comms */
     276           0 :         break;
     277             :     }
     278             : 
     279           1 :     user_uid = uid;
     280           1 :     rd.len = sizeof(uint32_t);
     281           1 :     rd.data = &user_uid;
     282             : 
     283           1 :     sss_nss_lock();
     284             : 
     285             :     /* previous thread might already initialize entry in mmap cache */
     286           1 :     ret = sss_nss_mc_getpwuid(uid, result, buffer, buflen);
     287           1 :     switch (ret) {
     288             :     case 0:
     289           0 :         *errnop = 0;
     290           0 :         nret = NSS_STATUS_SUCCESS;
     291           0 :         goto out;
     292             :     case ERANGE:
     293           0 :         *errnop = ERANGE;
     294           0 :         nret = NSS_STATUS_TRYAGAIN;
     295           0 :         goto out;
     296             :     case ENOENT:
     297             :         /* fall through, we need to actively ask the parent
     298             :          * if no entry is found */
     299           1 :         break;
     300             :     default:
     301             :         /* if using the mmaped cache failed,
     302             :          * fall back to socket based comms */
     303           0 :         break;
     304             :     }
     305             : 
     306           1 :     nret = sss_nss_make_request(SSS_NSS_GETPWUID, &rd,
     307             :                                 &repbuf, &replen, errnop);
     308           1 :     if (nret != NSS_STATUS_SUCCESS) {
     309           1 :         goto out;
     310             :     }
     311             : 
     312           0 :     pwrep.result = result;
     313           0 :     pwrep.buffer = buffer;
     314           0 :     pwrep.buflen = buflen;
     315             : 
     316             :     /* Get number of results from repbuf. */
     317           0 :     SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
     318             : 
     319             :     /* no results if not found */
     320           0 :     if (num_results == 0) {
     321           0 :         free(repbuf);
     322           0 :         nret = NSS_STATUS_NOTFOUND;
     323           0 :         goto out;
     324             :     }
     325             : 
     326             :     /* only 1 result is accepted for this function */
     327           0 :     if (num_results != 1) {
     328           0 :         *errnop = EBADMSG;
     329           0 :         free(repbuf);
     330           0 :         nret = NSS_STATUS_TRYAGAIN;
     331           0 :         goto out;
     332             :     }
     333             : 
     334           0 :     len = replen - 8;
     335           0 :     ret = sss_nss_getpw_readrep(&pwrep, repbuf+8, &len);
     336           0 :     free(repbuf);
     337           0 :     if (ret) {
     338           0 :         *errnop = ret;
     339           0 :         nret = NSS_STATUS_TRYAGAIN;
     340           0 :         goto out;
     341             :     }
     342             : 
     343           0 :     nret = NSS_STATUS_SUCCESS;
     344             : 
     345             : out:
     346           1 :     sss_nss_unlock();
     347           1 :     return nret;
     348             : }
     349             : 
     350           0 : enum nss_status _nss_sss_setpwent(void)
     351             : {
     352             :     enum nss_status nret;
     353             :     int errnop;
     354             : 
     355           0 :     sss_nss_lock();
     356             : 
     357             :     /* make sure we do not have leftovers, and release memory */
     358           0 :     sss_nss_getpwent_data_clean();
     359             : 
     360           0 :     nret = sss_nss_make_request(SSS_NSS_SETPWENT,
     361             :                                 NULL, NULL, NULL, &errnop);
     362           0 :     if (nret != NSS_STATUS_SUCCESS) {
     363           0 :         errno = errnop;
     364             :     }
     365             : 
     366           0 :     sss_nss_unlock();
     367           0 :     return nret;
     368             : }
     369             : 
     370           0 : static enum nss_status internal_getpwent_r(struct passwd *result,
     371             :                                            char *buffer, size_t buflen,
     372             :                                            int *errnop)
     373             : {
     374             :     struct sss_cli_req_data rd;
     375             :     struct sss_nss_pw_rep pwrep;
     376             :     uint8_t *repbuf;
     377             :     size_t replen;
     378             :     uint32_t num_results;
     379             :     enum nss_status nret;
     380             :     uint32_t num_entries;
     381             :     int ret;
     382             : 
     383             :     /* Caught once glibc passing in buffer == 0x0 */
     384           0 :     if (!buffer || !buflen) return ERANGE;
     385             : 
     386             :     /* if there are leftovers return the next one */
     387           0 :     if (sss_nss_getpwent_data.data != NULL &&
     388           0 :         sss_nss_getpwent_data.ptr < sss_nss_getpwent_data.len) {
     389             : 
     390           0 :         repbuf = sss_nss_getpwent_data.data + sss_nss_getpwent_data.ptr;
     391           0 :         replen = sss_nss_getpwent_data.len - sss_nss_getpwent_data.ptr;
     392             : 
     393           0 :         pwrep.result = result;
     394           0 :         pwrep.buffer = buffer;
     395           0 :         pwrep.buflen = buflen;
     396             : 
     397           0 :         ret = sss_nss_getpw_readrep(&pwrep, repbuf, &replen);
     398           0 :         if (ret) {
     399           0 :             *errnop = ret;
     400           0 :             return NSS_STATUS_TRYAGAIN;
     401             :         }
     402             : 
     403             :         /* advance buffer pointer */
     404           0 :         sss_nss_getpwent_data.ptr = sss_nss_getpwent_data.len - replen;
     405             : 
     406           0 :         return NSS_STATUS_SUCCESS;
     407             :     }
     408             : 
     409             :     /* release memory if any */
     410           0 :     sss_nss_getpwent_data_clean();
     411             : 
     412             :     /* retrieve no more than SSS_NSS_MAX_ENTRIES at a time */
     413           0 :     num_entries = SSS_NSS_MAX_ENTRIES;
     414           0 :     rd.len = sizeof(uint32_t);
     415           0 :     rd.data = &num_entries;
     416             : 
     417           0 :     nret = sss_nss_make_request(SSS_NSS_GETPWENT, &rd,
     418             :                                 &repbuf, &replen, errnop);
     419           0 :     if (nret != NSS_STATUS_SUCCESS) {
     420           0 :         return nret;
     421             :     }
     422             : 
     423             :     /* Get number of results from repbuf. */
     424           0 :     SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
     425             : 
     426             :     /* no results if not found */
     427           0 :     if ((num_results == 0) || (replen - 8 == 0)) {
     428           0 :         free(repbuf);
     429           0 :         return NSS_STATUS_NOTFOUND;
     430             :     }
     431             : 
     432           0 :     sss_nss_getpwent_data.data = repbuf;
     433           0 :     sss_nss_getpwent_data.len = replen;
     434           0 :     sss_nss_getpwent_data.ptr = 8; /* skip metadata fields */
     435             : 
     436             :     /* call again ourselves, this will return the first result */
     437           0 :     return internal_getpwent_r(result, buffer, buflen, errnop);
     438             : }
     439             : 
     440           0 : enum nss_status _nss_sss_getpwent_r(struct passwd *result,
     441             :                                     char *buffer, size_t buflen,
     442             :                                     int *errnop)
     443             : {
     444             :     enum nss_status nret;
     445             : 
     446           0 :     sss_nss_lock();
     447           0 :     nret = internal_getpwent_r(result, buffer, buflen, errnop);
     448           0 :     sss_nss_unlock();
     449             : 
     450           0 :     return nret;
     451             : }
     452             : 
     453           0 : enum nss_status _nss_sss_endpwent(void)
     454             : {
     455             :     enum nss_status nret;
     456             :     int errnop;
     457             : 
     458           0 :     sss_nss_lock();
     459             : 
     460             :     /* make sure we do not have leftovers, and release memory */
     461           0 :     sss_nss_getpwent_data_clean();
     462             : 
     463           0 :     nret = sss_nss_make_request(SSS_NSS_ENDPWENT,
     464             :                                 NULL, NULL, NULL, &errnop);
     465           0 :     if (nret != NSS_STATUS_SUCCESS) {
     466           0 :         errno = errnop;
     467             :     }
     468             : 
     469           0 :     sss_nss_unlock();
     470           0 :     return nret;
     471             : }

Generated by: LCOV version 1.10