(root)/
glibc-2.38/
nss/
nss_test.h
       1  /* Common code for NSS test cases.
       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  
      20  /* There are two (or more) NSS test modules named nss_test1,
      21     nss_test2, etc.  Each one will call a function IN THE TEST CASE
      22     called _nss_test1_init_hook(test_tables *) (or _nss_test2_*, etc).
      23  
      24     In your copy of the hook function, you may change the *_table
      25     pointers in the passed struct to point to static tables in your
      26     test case, and the test modules will use that table instead.
      27  
      28     Your tables MUST end with an entry that has a *_LAST() macro.
      29     Use the *_ISLAST() macro to test for end of list.
      30  
      31     Use __nss_configure_lookup("passwd", "test1 test2") (for example) to
      32     configure NSS to use the test modules.  */
      33  
      34  #include <pwd.h>
      35  #include <grp.h>
      36  #include <shadow.h>
      37  #include <netdb.h>
      38  
      39  typedef struct test_tables {
      40    struct passwd *pwd_table;
      41    struct group *grp_table;
      42    struct spwd *spwd_table;
      43    struct hostent *host_table;
      44  } test_tables;
      45  
      46  extern void _nss_test1_init_hook (test_tables *) __attribute__((weak));
      47  extern void _nss_test2_init_hook (test_tables *) __attribute__((weak));
      48  
      49  #define PWD_LAST()    { .pw_name = NULL, .pw_uid = 0 }
      50  #define GRP_LAST()    { .gr_name = NULL, .gr_gid = 0 }
      51  #define SPWD_LAST()    { .sp_namp = NULL, .sp_pwdp = NULL }
      52  #define HOST_LAST()    { .h_name = NULL, .h_aliases = NULL, .h_length = 0, .h_addr_list = NULL }
      53  
      54  #define PWD_ISLAST(p)    ((p)->pw_name == NULL && (p)->pw_uid == 0)
      55  #define GRP_ISLAST(g)    ((g)->gr_name == NULL && (g)->gr_gid == 0)
      56  #define SPWD_ISLAST(s)    ((s)->sp_namp == NULL && (s)->sp_pwdp == 0)
      57  #define HOST_ISLAST(h)    ((h)->h_name == NULL && (h)->h_length == 0)
      58  
      59  /* Macros to fill in the tables easily.  */
      60  
      61  /* Note that the "unparameterized" fields are not magic; they're just
      62     arbitrary values.  Tests which need to verify those fields should
      63     fill them in explicitly.  */
      64  
      65  #define PWD(u) \
      66      { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u,  \
      67        .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",	      \
      68        .pw_shell = (char *) "*" }
      69  
      70  #define PWD_N(u,n)								\
      71      { .pw_name = (char *) n, .pw_passwd = (char *) "*", .pw_uid = u,  \
      72        .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",	      \
      73        .pw_shell = (char *) "*" }
      74  
      75  #define GRP(u) \
      76      { .gr_name = (char *) "name" #u, .gr_passwd = (char *) "*", .gr_gid = u, \
      77        .gr_mem = (char **) group_##u }
      78  
      79  #define GRP_N(u,n,m)						     \
      80      { .gr_name = (char *) n, .gr_passwd = (char *) "*", .gr_gid = u, \
      81        .gr_mem = (char **) m }
      82  
      83  #define SPWD(u) \
      84      { .sp_namp = (char *) "name" #u, .sp_pwdp = (char *) "passwd" #u }
      85  
      86  #define HOST(u)								\
      87      { .h_name = (char *) "name" #u, .h_aliases = NULL, .h_addrtype = u,	\
      88        .h_length = 4,							\
      89        .h_addr_list = (char **) hostaddr_##u  }
      90  
      91  /*------------------------------------------------------------*/
      92  
      93  /* Helper functions for testing passwd entries.  Call
      94     compare_passwds() passing a test index, the passwd entry you got,
      95     and the expected passwd entry.  The function will return the number
      96     of mismatches, or zero of the two records are the same.  */
      97  
      98  static void __attribute__((used))
      99  print_passwd (struct passwd *p)
     100  {
     101    printf ("    passwd %u.%s (%s) :", p->pw_uid, p->pw_name, p->pw_passwd);
     102    printf (" %u, %s, %s, %s\n", p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
     103    printf ("\n");
     104  }
     105  
     106  static int  __attribute__((used))
     107  compare_passwd_field (int i, struct passwd *p, const char *got,
     108  		      const char *exp, const char *name)
     109  {
     110    /* Does the entry have a value?  */
     111    if (got == NULL)
     112      {
     113        printf ("[%d] passwd %s for %u.%s was (null)\n",
     114  	      i, name,
     115  	      p->pw_uid, p->pw_name);
     116        return 1;
     117      }
     118    /* Does the entry have an unexpected name?  */
     119    else if (exp == NULL)
     120      {
     121        printf ("[%d] passwd %s for %u.(null) was %s\n",
     122  	      i, name,
     123  	      p->pw_uid, got);
     124        return 1;
     125      }
     126    /* And is it correct?  */
     127    else if (got && strcmp (got, exp) != 0)
     128      {
     129        printf("[%d] passwd entry %u.%s had %s \"%s\" (expected \"%s\") \n",
     130  	     i,
     131  	     p->pw_uid, p->pw_name, name,
     132  	     got, exp);
     133        return 1;
     134      }
     135    return 0;
     136  }
     137  
     138  #define COMPARE_PWD_FIELD(f) \
     139    retval += compare_passwd_field (i, e, p->f, e->f, #f)
     140  
     141  /* Compare passwd to expected passwd, return number of "problems".
     142     "I" is the index into the testcase data.  */
     143  static int  __attribute__((used))
     144  compare_passwds (int i, struct passwd *p, struct passwd *e)
     145  {
     146    int retval = 0;
     147  
     148    /* Did we get the expected uid?  */
     149    if (p->pw_uid != e->pw_uid)
     150      {
     151        printf("[%d] passwd entry %u.%s had uid %u\n", i,
     152  	     e->pw_uid, e->pw_name,
     153  	     p->pw_uid);
     154        ++retval;
     155      }
     156  
     157    /* Did we get the expected gid?  */
     158    if (p->pw_gid != e->pw_gid)
     159      {
     160        printf("[%d] passwd entry %u.%s had gid %u (expected %u)\n", i,
     161  	     e->pw_uid, e->pw_name,
     162  	     p->pw_gid, e->pw_gid);
     163        ++retval;
     164      }
     165  
     166    COMPARE_PWD_FIELD (pw_name);
     167    COMPARE_PWD_FIELD (pw_passwd);
     168    COMPARE_PWD_FIELD (pw_gecos);
     169    COMPARE_PWD_FIELD (pw_dir);
     170    COMPARE_PWD_FIELD (pw_shell);
     171  
     172    if (retval > 0)
     173      {
     174        /* Left in for debugging later, if needed.  */
     175        print_passwd (p);
     176        print_passwd (e);
     177      }
     178  
     179    return retval;
     180  }
     181  
     182  /*------------------------------------------------------------*/
     183  
     184  /* Helpers for checking group entries.  See passwd helper comment
     185     above for details.  */
     186  
     187  static void __attribute__((used))
     188  print_group (struct group *g)
     189  {
     190    int j;
     191  
     192    printf ("    group %u.%s (%s) :", g->gr_gid, g->gr_name, g->gr_passwd);
     193    if (g->gr_mem)
     194      for (j=0; g->gr_mem[j]; j++)
     195        printf ("%s%s", j==0 ? " " : ", ", g->gr_mem[j]);
     196    printf ("\n");
     197  }
     198  
     199  /* Compare group to expected group, return number of "problems".  "I"
     200     is the index into the testcase data.  */
     201  static int  __attribute__((used))
     202  compare_groups (int i, struct group *g, struct group *e)
     203  {
     204    int j;
     205    int retval = 0;
     206  
     207    /* Did we get the expected gid?  */
     208    if (g->gr_gid != e->gr_gid)
     209      {
     210        printf("[%d] group entry %u.%s had gid %u\n", i,
     211  	     e->gr_gid, e->gr_name,
     212  	     g->gr_gid);
     213        ++retval;
     214      }
     215  
     216    /* Does the entry have a name?  */
     217    if (g->gr_name == NULL)
     218      {
     219        printf ("[%d] group name for %u.%s was (null)\n", i,
     220  	      e->gr_gid, e->gr_name);
     221        ++retval;
     222      }
     223    /* Does the entry have an unexpected name?  */
     224    else if (e->gr_name == NULL)
     225      {
     226        printf ("[%d] group name for %u.(null) was %s\n", i,
     227  	      e->gr_gid, g->gr_name);
     228        ++retval;
     229      }
     230    /* And is it correct?  */
     231    else if (strcmp (g->gr_name, e->gr_name) != 0)
     232      {
     233        printf("[%d] group entry %u.%s had name \"%s\"\n", i,
     234  	     e->gr_gid, e->gr_name,
     235  	     g->gr_name);
     236        ++retval;
     237      }
     238  
     239    /* Does the entry have a password?  */
     240    if (g->gr_passwd == NULL && e->gr_passwd != NULL)
     241      {
     242        printf ("[%d] group password for %u.%s was NULL\n", i,
     243  	      e->gr_gid, e->gr_name);
     244        ++retval;
     245      }
     246    else if (g->gr_passwd != NULL && e->gr_passwd == NULL)
     247      {
     248        printf ("[%d] group password for %u.%s was not NULL\n", i,
     249  	      e->gr_gid, e->gr_name);
     250        ++retval;
     251      }
     252    /* And is it correct?  */
     253    else if (g->gr_passwd && strcmp (g->gr_passwd, e->gr_passwd) != 0)
     254      {
     255        printf("[%d] group entry %u.%s had password \"%s\" (not \"%s\")\n", i,
     256  	     e->gr_gid, e->gr_name,
     257  	     g->gr_passwd, e->gr_passwd);
     258        ++retval;
     259      }
     260  
     261    /* Now compare group members... */
     262  
     263    if (e->gr_mem != NULL && g->gr_mem == NULL)
     264      {
     265        printf("[%d] group entry %u.%s missing member list\n", i,
     266  	     e->gr_gid, e->gr_name);
     267        ++retval;
     268      }
     269    else if (e->gr_mem == NULL && g->gr_mem != NULL)
     270      {
     271        printf("[%d] group entry %u.%s has unexpected member list\n", i,
     272  	     e->gr_gid, e->gr_name);
     273        ++retval;
     274      }
     275    else if (e->gr_mem == NULL && g->gr_mem == NULL)
     276      {
     277        /* This case is OK.  */
     278      }
     279    else
     280      {
     281        /* Compare two existing lists.  */
     282        j = 0;
     283        for (;;)
     284  	{
     285  	  if (g->gr_mem[j] == NULL && e->gr_mem[j] == NULL)
     286  	    {
     287  	      /* Matching end-of-lists.  */
     288  	      break;
     289  	    }
     290  	  if (g->gr_mem[j] == NULL)
     291  	    {
     292  	      printf ("[%d] group member list for %u.%s is too short.\n", i,
     293  		      e->gr_gid, e->gr_name);
     294  	      ++retval;
     295  	      break;
     296  	    }
     297  	  if (e->gr_mem[j] == NULL)
     298  	    {
     299  	      printf ("[%d] group member list for %u.%s is too long.\n", i,
     300  		      e->gr_gid, e->gr_name);
     301  	      ++retval;
     302  	      break;
     303  	    }
     304  	  if (strcmp (g->gr_mem[j], e->gr_mem[j]) != 0)
     305  	    {
     306  	      printf ("[%d] group member list for %u.%s differs: %s vs %s.\n", i,
     307  		      e->gr_gid, e->gr_name,
     308  		      e->gr_mem[j], g->gr_mem[j]);
     309  	      ++retval;
     310  	    }
     311  
     312  	  j++;
     313  	}
     314      }
     315  
     316    if (retval > 0)
     317      {
     318        /* Left in for debugging later, if needed.  */
     319        print_group (g);
     320        print_group (e);
     321      }
     322  
     323    return retval;
     324  }