(root)/
glibc-2.38/
nss/
nss_test1.c
       1  /* Template generic NSS service provider.  See nss_test.h for usage.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <nss.h>
      21  #include <pthread.h>
      22  #include <string.h>
      23  #include <stdio.h>
      24  #include <alloc_buffer.h>
      25  
      26  
      27  /* We need to be able to handle NULLs "properly" within the testsuite,
      28     to test known bad data.  */
      29  #define alloc_buffer_maybe_copy_string(b,s) s ? alloc_buffer_copy_string (b, s) : NULL;
      30  
      31  /* This file is the master template.  Other instances of this test
      32     module should define NAME(x) to have their name instead of "test1",
      33     then include this file.
      34  */
      35  #define NAME_(x,n) _nss_##n##_##x
      36  #ifndef NAME
      37  #define NAME(x) NAME_(x,test1)
      38  #endif
      39  #define NAMESTR__(x) #x
      40  #define NAMESTR_(x) NAMESTR__(x)
      41  #define NAMESTR(x) NAMESTR_(NAME(x))
      42  
      43  #include "nss_test.h"
      44  
      45  /* -------------------------------------------------- */
      46  /* Default Data.  */
      47  
      48  static struct passwd default_pwd_data[] =
      49    {
      50  #define PWD(u) \
      51      { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u,  \
      52        .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",	      \
      53        .pw_shell = (char *) "*" }
      54      PWD (30),
      55      PWD (100),
      56      PWD (200),
      57      PWD (60),
      58      PWD (20000)
      59    };
      60  #define default_npwd_data \
      61    (sizeof (default_pwd_data) / sizeof (default_pwd_data[0]))
      62  
      63  static struct passwd *pwd_data = default_pwd_data;
      64  static int npwd_data = default_npwd_data;
      65  
      66  static struct group *grp_data = NULL;
      67  static int ngrp_data = 0;
      68  
      69  static struct spwd *spwd_data = NULL;
      70  static int nspwd_data = 0;
      71  
      72  static struct hostent *host_data = NULL;
      73  static int nhost_data = 0;
      74  
      75  /* This function will get called, and once per session, look back into
      76     the test case's executable for an init hook function, and call
      77     it.  */
      78  
      79  static int initted = 0;
      80  static void
      81  init(void)
      82  {
      83    test_tables t;
      84    int i;
      85  
      86    if (initted)
      87      return;
      88    if (NAME(init_hook))
      89      {
      90        memset (&t, 0, sizeof (t));
      91        NAME(init_hook)(&t);
      92  
      93        if (t.pwd_table)
      94  	{
      95  	  pwd_data = t.pwd_table;
      96  	  for (i=0; ! PWD_ISLAST(& pwd_data[i]); i++)
      97  	    ;
      98  	  npwd_data = i;
      99  	}
     100  
     101        if (t.grp_table)
     102  	{
     103  	  grp_data = t.grp_table;
     104  	  for (i=0; ! GRP_ISLAST(& grp_data[i]); i++)
     105  	    ;
     106  	  ngrp_data = i;
     107  	}
     108        if (t.spwd_table)
     109  	{
     110  	  spwd_data = t.spwd_table;
     111  	  for (i=0; ! SPWD_ISLAST(& spwd_data[i]); i++)
     112  	    ;
     113  	  nspwd_data = i;
     114  	}
     115        if (t.host_table)
     116  	{
     117  	  host_data = t.host_table;
     118  	  for (i=0; ! HOST_ISLAST(& host_data[i]); i++)
     119  	    ;
     120  	  nhost_data = i;
     121  	}
     122      }
     123    initted = 1;
     124  }
     125  
     126  /* -------------------------------------------------- */
     127  /* Password handling.  */
     128  
     129  static size_t pwd_iter;
     130  #define CURPWD pwd_data[pwd_iter]
     131  
     132  static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER;
     133  
     134  enum nss_status
     135  NAME(setpwent) (int stayopen)
     136  {
     137    init();
     138    pwd_iter = 0;
     139    return NSS_STATUS_SUCCESS;
     140  }
     141  
     142  
     143  enum nss_status
     144  NAME(endpwent) (void)
     145  {
     146    init();
     147    return NSS_STATUS_SUCCESS;
     148  }
     149  
     150  static enum nss_status
     151  copy_passwd (struct passwd *result, struct passwd *local,
     152  	    char *buffer, size_t buflen, int *errnop)
     153  {
     154    struct alloc_buffer buf = alloc_buffer_create (buffer, buflen);
     155  
     156    result->pw_name = alloc_buffer_maybe_copy_string (&buf, local->pw_name);
     157    result->pw_passwd = alloc_buffer_maybe_copy_string (&buf, local->pw_passwd);
     158    result->pw_uid = local->pw_uid;
     159    result->pw_gid = local->pw_gid;
     160    result->pw_gecos = alloc_buffer_maybe_copy_string (&buf, local->pw_gecos);
     161    result->pw_dir = alloc_buffer_maybe_copy_string (&buf, local->pw_dir);
     162    result->pw_shell = alloc_buffer_maybe_copy_string (&buf, local->pw_shell);
     163  
     164    if (alloc_buffer_has_failed (&buf))
     165      {
     166        *errnop = ERANGE;
     167        return NSS_STATUS_TRYAGAIN;
     168      }
     169  
     170    return NSS_STATUS_SUCCESS;
     171  }
     172  
     173  enum nss_status
     174  NAME(getpwent_r) (struct passwd *result, char *buffer, size_t buflen,
     175  		       int *errnop)
     176  {
     177    int res = NSS_STATUS_SUCCESS;
     178  
     179    init();
     180    pthread_mutex_lock (&pwd_lock);
     181  
     182    if (pwd_iter >= npwd_data)
     183      res = NSS_STATUS_NOTFOUND;
     184    else
     185      {
     186        res = copy_passwd (result, &CURPWD, buffer, buflen, errnop);
     187        ++pwd_iter;
     188      }
     189  
     190    pthread_mutex_unlock (&pwd_lock);
     191  
     192    return res;
     193  }
     194  
     195  
     196  enum nss_status
     197  NAME(getpwuid_r) (uid_t uid, struct passwd *result, char *buffer,
     198  		       size_t buflen, int *errnop)
     199  {
     200    init();
     201    for (size_t idx = 0; idx < npwd_data; ++idx)
     202      if (pwd_data[idx].pw_uid == uid)
     203        return copy_passwd (result, &pwd_data[idx], buffer, buflen, errnop);
     204  
     205    return NSS_STATUS_NOTFOUND;
     206  }
     207  
     208  
     209  enum nss_status
     210  NAME(getpwnam_r) (const char *name, struct passwd *result, char *buffer,
     211  		       size_t buflen, int *errnop)
     212  {
     213    init();
     214    for (size_t idx = 0; idx < npwd_data; ++idx)
     215      if (strcmp (pwd_data[idx].pw_name, name) == 0)
     216        return copy_passwd (result, &pwd_data[idx], buffer, buflen, errnop);
     217  
     218    return NSS_STATUS_NOTFOUND;
     219  }
     220  
     221  /* -------------------------------------------------- */
     222  /* Group handling.  */
     223  
     224  static size_t grp_iter;
     225  #define CURGRP grp_data[grp_iter]
     226  
     227  static pthread_mutex_t grp_lock = PTHREAD_MUTEX_INITIALIZER;
     228  
     229  enum nss_status
     230  NAME(setgrent) (int stayopen)
     231  {
     232    init();
     233    grp_iter = 0;
     234    return NSS_STATUS_SUCCESS;
     235  }
     236  
     237  
     238  enum nss_status
     239  NAME(endgrent) (void)
     240  {
     241    init();
     242    return NSS_STATUS_SUCCESS;
     243  }
     244  
     245  static enum nss_status
     246  copy_group (struct group *result, struct group *local,
     247  	    char *buffer, size_t buflen, int *errnop)
     248  {
     249    struct alloc_buffer buf = alloc_buffer_create (buffer, buflen);
     250    char **memlist;
     251    int i;
     252  
     253    if (local->gr_mem)
     254      {
     255        i = 0;
     256        while (local->gr_mem[i])
     257  	++i;
     258  
     259        memlist = alloc_buffer_alloc_array (&buf, char *, i + 1);
     260  
     261        if (memlist) {
     262  	for (i = 0; local->gr_mem[i]; ++i)
     263  	  memlist[i] = alloc_buffer_maybe_copy_string (&buf, local->gr_mem[i]);
     264  	memlist[i] = NULL;
     265        }
     266  
     267        result->gr_mem = memlist;
     268      }
     269    else
     270      result->gr_mem = NULL;
     271  
     272    result->gr_name = alloc_buffer_maybe_copy_string (&buf, local->gr_name);
     273    result->gr_passwd = alloc_buffer_maybe_copy_string (&buf, local->gr_passwd);
     274    result->gr_gid = local->gr_gid;
     275  
     276    if (alloc_buffer_has_failed (&buf))
     277      {
     278        *errnop = ERANGE;
     279        return NSS_STATUS_TRYAGAIN;
     280      }
     281  
     282    return NSS_STATUS_SUCCESS;
     283  }
     284  
     285  
     286  enum nss_status
     287  NAME(getgrent_r) (struct group *result, char *buffer, size_t buflen,
     288  		       int *errnop)
     289  {
     290    int res = NSS_STATUS_SUCCESS;
     291  
     292    init();
     293    pthread_mutex_lock (&grp_lock);
     294  
     295    if (grp_iter >= ngrp_data)
     296      res = NSS_STATUS_NOTFOUND;
     297    else
     298      {
     299        res = copy_group (result, &CURGRP, buffer, buflen, errnop);
     300        ++grp_iter;
     301      }
     302  
     303    pthread_mutex_unlock (&grp_lock);
     304  
     305    return res;
     306  }
     307  
     308  
     309  enum nss_status
     310  NAME(getgrgid_r) (gid_t gid, struct group *result, char *buffer,
     311  		  size_t buflen, int *errnop)
     312  {
     313    init();
     314    for (size_t idx = 0; idx < ngrp_data; ++idx)
     315      if (grp_data[idx].gr_gid == gid)
     316        return copy_group (result, &grp_data[idx], buffer, buflen, errnop);
     317  
     318    return NSS_STATUS_NOTFOUND;
     319  }
     320  
     321  
     322  enum nss_status
     323  NAME(getgrnam_r) (const char *name, struct group *result, char *buffer,
     324  		       size_t buflen, int *errnop)
     325  {
     326    init();
     327    for (size_t idx = 0; idx < ngrp_data; ++idx)
     328      if (strcmp (pwd_data[idx].pw_name, name) == 0)
     329        {
     330  	return copy_group (result, &grp_data[idx], buffer, buflen, errnop);
     331        }
     332  
     333    return NSS_STATUS_NOTFOUND;
     334  }
     335  
     336  /* -------------------------------------------------- */
     337  /* Shadow password handling.  */
     338  
     339  static size_t spwd_iter;
     340  #define CURSPWD spwd_data[spwd_iter]
     341  
     342  static pthread_mutex_t spwd_lock = PTHREAD_MUTEX_INITIALIZER;
     343  
     344  enum nss_status
     345  NAME(setspent) (int stayopen)
     346  {
     347    init();
     348    spwd_iter = 0;
     349    return NSS_STATUS_SUCCESS;
     350  }
     351  
     352  
     353  enum nss_status
     354  NAME(endspwent) (void)
     355  {
     356    init();
     357    return NSS_STATUS_SUCCESS;
     358  }
     359  
     360  static enum nss_status
     361  copy_shadow (struct spwd *result, struct spwd *local,
     362  	    char *buffer, size_t buflen, int *errnop)
     363  {
     364    struct alloc_buffer buf = alloc_buffer_create (buffer, buflen);
     365  
     366    result->sp_namp = alloc_buffer_maybe_copy_string (&buf, local->sp_namp);
     367    result->sp_pwdp = alloc_buffer_maybe_copy_string (&buf, local->sp_pwdp);
     368    result->sp_lstchg = local->sp_lstchg;
     369    result->sp_min = local->sp_min;
     370    result->sp_max = local->sp_max;
     371    result->sp_warn = local->sp_warn;
     372    result->sp_inact = local->sp_inact;
     373    result->sp_expire = local->sp_expire;
     374    result->sp_flag = local->sp_flag;
     375  
     376    if (alloc_buffer_has_failed (&buf))
     377      {
     378        *errnop = ERANGE;
     379        return NSS_STATUS_TRYAGAIN;
     380      }
     381  
     382    return NSS_STATUS_SUCCESS;
     383  }
     384  
     385  enum nss_status
     386  NAME(getspent_r) (struct spwd *result, char *buffer, size_t buflen,
     387  		  int *errnop)
     388  {
     389    int res = NSS_STATUS_SUCCESS;
     390  
     391    init();
     392    pthread_mutex_lock (&spwd_lock);
     393  
     394    if (spwd_iter >= nspwd_data)
     395      res = NSS_STATUS_NOTFOUND;
     396    else
     397      {
     398        res = copy_shadow (result, &CURSPWD, buffer, buflen, errnop);
     399        ++spwd_iter;
     400      }
     401  
     402    pthread_mutex_unlock (&spwd_lock);
     403  
     404    return res;
     405  }
     406  
     407  enum nss_status
     408  NAME(getspnam_r) (const char *name, struct spwd *result, char *buffer,
     409  		  size_t buflen, int *errnop)
     410  {
     411    init();
     412    for (size_t idx = 0; idx < nspwd_data; ++idx)
     413      if (strcmp (spwd_data[idx].sp_namp, name) == 0)
     414        return copy_shadow (result, &spwd_data[idx], buffer, buflen, errnop);
     415  
     416    return NSS_STATUS_NOTFOUND;
     417  }
     418  
     419  /* -------------------------------------------------- */
     420  /* Host handling.  */
     421  
     422  static size_t host_iter;
     423  #define CURHOST host_data[host_iter]
     424  
     425  static pthread_mutex_t host_lock = PTHREAD_MUTEX_INITIALIZER;
     426  
     427  enum nss_status
     428  NAME(sethostent) (int stayopen)
     429  {
     430    init();
     431    host_iter = 0;
     432    return NSS_STATUS_SUCCESS;
     433  }
     434  
     435  
     436  enum nss_status
     437  NAME(endhostent) (void)
     438  {
     439    init();
     440    return NSS_STATUS_SUCCESS;
     441  }
     442  
     443  static enum nss_status
     444  copy_host (struct hostent *result, struct hostent *local,
     445  	    char *buffer, size_t buflen, int *errnop)
     446  {
     447    struct alloc_buffer buf = alloc_buffer_create (buffer, buflen);
     448    char **memlist;
     449    int i, j;
     450  
     451    if (local->h_addr_list)
     452      {
     453        i = 0;
     454        while (local->h_addr_list[i])
     455  	++i;
     456  
     457        memlist = alloc_buffer_alloc_array (&buf, char *, i + 1);
     458  
     459        if (memlist) {
     460  	for (j = 0; j < i; ++j)
     461  	  memlist[j] = alloc_buffer_maybe_copy_string (&buf, local->h_addr_list[j]);
     462  	memlist[j] = NULL;
     463        }
     464  
     465        result->h_addr_list = memlist;
     466      }
     467    else
     468      {
     469        result->h_addr_list = NULL;
     470      }
     471  
     472    result->h_aliases = NULL;
     473    result->h_addrtype = AF_INET;
     474    result->h_length = 4;
     475    result->h_name = alloc_buffer_maybe_copy_string (&buf, local->h_name);
     476  
     477    if (alloc_buffer_has_failed (&buf))
     478      {
     479        *errnop = ERANGE;
     480        return NSS_STATUS_TRYAGAIN;
     481      }
     482  
     483    return NSS_STATUS_SUCCESS;
     484  }
     485  
     486  
     487  enum nss_status
     488  NAME(gethostent_r) (struct hostent *ret, char *buffer, size_t buflen,
     489  		    struct hostent **result, int *errnop)
     490  {
     491    int res = NSS_STATUS_SUCCESS;
     492  
     493    init();
     494    pthread_mutex_lock (&host_lock);
     495  
     496    if (host_iter >= nhost_data)
     497      {
     498        res = NSS_STATUS_NOTFOUND;
     499        *result = NULL;
     500      }
     501    else
     502      {
     503        res = copy_host (ret, &CURHOST, buffer, buflen, errnop);
     504        *result = ret;
     505        ++host_iter;
     506      }
     507  
     508    pthread_mutex_unlock (&host_lock);
     509  
     510    return res;
     511  }
     512  
     513  enum nss_status
     514  NAME(gethostbyname3_r) (const char *name, int af, struct hostent *ret,
     515  			     char *buffer, size_t buflen, int *errnop,
     516  			     int *h_errnop, int32_t *ttlp, char **canonp)
     517  {
     518    init();
     519  
     520    for (size_t idx = 0; idx < nhost_data; ++idx)
     521      if (strcmp (host_data[idx].h_name, name) == 0)
     522        return copy_host (ret, & host_data[idx], buffer, buflen, h_errnop);
     523  
     524    return NSS_STATUS_NOTFOUND;
     525  }
     526  
     527  enum nss_status
     528  NAME(gethostbyname_r) (const char *name, struct hostent *result,
     529  		       char *buffer, size_t buflen,
     530  		       int *errnop, int *h_errnop)
     531  {
     532    return NAME(gethostbyname3_r) (name, AF_INET, result, buffer, buflen,
     533  				 errnop, h_errnop, NULL, NULL);
     534  }
     535  
     536  enum nss_status
     537  NAME(gethostbyname2_r) (const char *name, int af, struct hostent *result,
     538  			char *buffer, size_t buflen,
     539  			int *errnop, int *h_errnop)
     540  {
     541    return NAME(gethostbyname3_r) (name, af, result, buffer, buflen,
     542  				 errnop, h_errnop, NULL, NULL);
     543  }
     544  
     545  enum nss_status
     546  NAME(gethostbyaddr2_r) (const void *addr, socklen_t len, int af,
     547  			struct hostent *result, char *buffer, size_t buflen,
     548  			int *errnop, int *h_errnop, int32_t *ttlp)
     549  {
     550    init();
     551  
     552    /* Support this later.  */
     553    if (len != 4)
     554      return NSS_STATUS_NOTFOUND;
     555  
     556    for (size_t idx = 0; idx < nhost_data; ++idx)
     557      if (memcmp (host_data[idx].h_addr, addr, len) == 0)
     558        return copy_host (result, & host_data[idx], buffer, buflen, h_errnop);
     559  
     560    return NSS_STATUS_NOTFOUND;
     561  }
     562  
     563  /* Note: only the first address is supported, intentionally.  */
     564  enum nss_status
     565  NAME(gethostbyaddr_r) (const void *addr, socklen_t len, int af,
     566  		       struct hostent *result, char *buffer, size_t buflen,
     567  		       int *errnop, int *h_errnop)
     568  {
     569    return NAME(gethostbyaddr2_r) (addr, len, af, result, buffer, buflen,
     570  				 errnop, h_errnop, NULL);
     571  }