(root)/
glibc-2.38/
nscd/
cachedumper.c
       1  /* Copyright (c) 2020-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     This program is free software; you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published
       6     by the Free Software Foundation; version 2 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* cachedumper - dump a human-readable representation of a cache file.  */
      18  
      19  #include <ctype.h>
      20  #include <stdio.h>
      21  #include <fcntl.h>
      22  #include <unistd.h>
      23  #include <libintl.h>
      24  #include <sys/types.h>
      25  #include <sys/stat.h>
      26  #include <sys/mman.h>
      27  #include <arpa/inet.h>
      28  #include <getopt.h>
      29  #include <sys/param.h>
      30  
      31  #include "nscd.h"
      32  #include "dbg_log.h"
      33  
      34  static void *the_cache;
      35  
      36  #define NO_REF ((ref_t) -1)
      37  
      38  /* Given a chunk of raw data CP of length LEN, print it in a hopefully
      39     user-readable format, including colorizing non-readable characters.
      40     STR prefixes it, if non-NULL.  If LEN is -1, CP is
      41     NUL-terminated.  */
      42  unsigned char *
      43  data_string (unsigned char *cp, const char *str, int len)
      44  {
      45    int oops = 0;
      46    unsigned char *cpe = cp + len;
      47    printf ("%s", str);
      48    while (len == -1 || cp < cpe)
      49      {
      50        if (isgraph (*cp))
      51  	putchar (*cp);
      52        else
      53  	printf ("\033[%dm<%02x>\033[0m", *cp % 6 + 31, *cp);
      54        if (len == -1 && *cp == 0)
      55  	return cp + 1;
      56  
      57        ++cp;
      58        if (++oops > 1000)
      59  	break;
      60      }
      61    return cp;
      62  }
      63  
      64  void
      65  nscd_print_cache (const char *name)
      66  {
      67    struct stat st;
      68    int fd;
      69    int i;
      70  
      71    if (stat (name, &st) < 0)
      72      {
      73        perror (name);
      74        exit (1);
      75      }
      76  
      77    fd = open (name, O_RDONLY);
      78  
      79    the_cache = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
      80  
      81    struct database_pers_head *dps = (struct database_pers_head *) the_cache;
      82  
      83    /* Shortcut for "print the cache offset (address) of X in the
      84       cache".  */
      85  #define A(x) (int) ((char *) &(x) - (char *) the_cache)
      86  
      87    /* Common code for "print field DPS->F, it's offset, and contents".  */
      88  #define DPS(f) printf("%08x: %24s : %10d %08x\n", A (dps->f), #f, (int) dps->f, (int) dps->f);
      89  
      90    if (debug_level > 0)
      91      {
      92        DPS (version);
      93        DPS (header_size);
      94        DPS (gc_cycle);
      95        DPS (nscd_certainly_running);
      96        DPS (timestamp);
      97        DPS (module);
      98        DPS (data_size);
      99        DPS (first_free);
     100        DPS (nentries);
     101        DPS (maxnentries);
     102        DPS (maxnsearched);
     103        DPS (poshit);
     104        DPS (neghit);
     105        DPS (posmiss);
     106        DPS (negmiss);
     107        DPS (rdlockdelayed);
     108        DPS (wrlockdelayed);
     109        DPS (addfailed);
     110        printf ("\n");
     111      }
     112  
     113  
     114    char *data = (char *) &dps->array[roundup (dps->module,
     115  					     ALIGN / sizeof (ref_t))];
     116  
     117    /* Loop through each entry in the hash table, which is of size
     118       dps->module.  Raw data is stored after the hash table in the
     119       cache file.  */
     120    for (i = 0; i < dps->module; i++)
     121      {
     122        ref_t r = dps->array[i];
     123        if (r == NO_REF)
     124  	continue;
     125  
     126        if (debug_level > 2)
     127  	printf ("hash[%4d] = 0x%x\n", i, r);
     128  
     129        while (r != NO_REF)
     130  	{
     131  	  struct hashentry *here = (struct hashentry *) (data + r);
     132  
     133  	  unsigned char *key = (unsigned char *) data + here->key;
     134  
     135  	  printf ("\n%08x: type %s key %p \"", A (*here),
     136  		  serv2str[here->type], key);
     137  
     138  	  data_string (key, "", here->len);
     139  
     140  	  struct datahead *dh = (struct datahead *) (data + here->packet);
     141  	  printf ("\" (len:%ld)  Data %08lx\n", (long) here->len,
     142  		  (long unsigned int) ((char *) dh - (char *) the_cache));
     143  
     144  	  if (debug_level > 0)
     145  	    {
     146  /* Common code for printing fields in struct DATAHEAD DH.  */
     147  #define DH(f) printf ("%08x; %24s : %10d %08x\n", A (dh->f), #f, (int) dh->f, (int) dh->f);
     148  	      DH (allocsize);
     149  	      DH (recsize);
     150  	      DH (timeout);
     151  	      DH (notfound);
     152  	      DH (nreloads);
     153  	      DH (usable);
     154  	      DH (unused);
     155  	      DH (ttl);
     156  	    }
     157  
     158  	  unsigned char *cp = (unsigned char *) (&dh->data[0]);
     159  	  unsigned char *cpe =
     160  	    (unsigned char *) (&dh->data[0]) + dh->allocsize;
     161  
     162  
     163  	  int i;
     164  	  uint32_t *grplens;
     165  
     166  	  if (debug_level > 1)
     167  	    {
     168  	      data_string (cp, _(" - all data: "), cpe - cp);
     169  	      printf ("\n");
     170  	    }
     171  
     172  	  /* These two are common to all responses.  */
     173  	  printf ("V%d F%d",
     174  		  dh->data[0].pwdata.version, dh->data[0].pwdata.found);
     175  
     176  /* Shortcut for the common case where we iterate through
     177     fixed-length strings stored in the data portion of the
     178     cache.  CP is updated to point to the next string.  */
     179  #define DSTR(str, l) cp = data_string (cp, str, l)
     180  
     181  	  switch (here->type)
     182  	    {
     183  	    case GETPWBYNAME:
     184  	    case GETPWBYUID:
     185  	      {
     186  		pw_response_header *pw = &(dh->data[0].pwdata);
     187  		cp += sizeof (*pw);
     188  		DSTR (" name ", pw->pw_name_len);
     189  		DSTR (" passwd ", pw->pw_passwd_len);
     190  		printf (" uid %d gid %d", pw->pw_uid, pw->pw_gid);
     191  		DSTR (" gecos ", pw->pw_gecos_len);
     192  		DSTR (" dir ", pw->pw_dir_len);
     193  		DSTR (" shell ", pw->pw_shell_len);
     194  		DSTR (" byuid ", -1);
     195  		DSTR (" key ", -1);
     196  		printf ("\n");
     197  	      }
     198  	      break;
     199  
     200  	    case GETGRBYNAME:
     201  	    case GETGRBYGID:
     202  	      {
     203  		gr_response_header *gr = &(dh->data[0].grdata);
     204  		cp += sizeof (*gr);
     205  		grplens = (uint32_t *) cp;
     206  		cp += gr->gr_mem_cnt * sizeof (uint32_t);
     207  		DSTR (" name ", gr->gr_name_len);
     208  		DSTR (" passwd ", gr->gr_passwd_len);
     209  		printf (" gid %d members %d [ ", (int) gr->gr_gid,
     210  			(int) gr->gr_mem_cnt);
     211  		for (i = 0; i < gr->gr_mem_cnt; i++)
     212  		  DSTR (" ", grplens[i]);
     213  		DSTR (" ] bygid ", -1);
     214  		DSTR (" key ", -1);
     215  		printf ("\n");
     216  	      }
     217  	      break;
     218  
     219  	    case GETHOSTBYADDR:
     220  	    case GETHOSTBYADDRv6:
     221  	    case GETHOSTBYNAME:
     222  	    case GETHOSTBYNAMEv6:
     223  	      {
     224  		hst_response_header *hst = &(dh->data[0].hstdata);
     225  		printf (" addrtype %d error %d", hst->h_addrtype, hst->error);
     226  		cp += sizeof (*hst);
     227  		DSTR (" name ", hst->h_name_len);
     228  		uint32_t *aliases_len = (uint32_t *) cp;
     229  		cp += hst->h_aliases_cnt * sizeof (uint32_t);
     230  		uint32_t *addrs = (uint32_t *) cp;
     231  		cp += hst->h_length * hst->h_addr_list_cnt;
     232  
     233  		if (hst->h_aliases_cnt)
     234  		  {
     235  		    printf (" aliases [");
     236  		    for (i = 0; i < hst->h_aliases_cnt; i++)
     237  		      DSTR (" ", aliases_len[i]);
     238  		    printf (" ]");
     239  		  }
     240  		if (hst->h_addr_list_cnt)
     241  		  {
     242  		    char buf[INET6_ADDRSTRLEN];
     243  		    printf (" addresses [");
     244  		    for (i = 0; i < hst->h_addr_list_cnt; i++)
     245  		      {
     246  			inet_ntop (hst->h_addrtype, addrs, buf, sizeof (buf));
     247  			printf (" %s", buf);
     248  			addrs += hst->h_length;
     249  		      }
     250  		    printf (" ]");
     251  		  }
     252  
     253  		printf ("\n");
     254  	      }
     255  	      break;
     256  
     257  	    case GETAI:
     258  	      {
     259  		ai_response_header *ai = &(dh->data[0].aidata);
     260  		printf (" naddrs %ld addrslen %ld canonlen %ld error %d [",
     261  			(long) ai->naddrs, (long) ai->addrslen,
     262  			(long) ai->canonlen, ai->error);
     263  		cp += sizeof (*ai);
     264  		unsigned char *addrs = cp;
     265  		unsigned char *families = cp + ai->addrslen;
     266  		cp = families + ai->naddrs;
     267  		char buf[INET6_ADDRSTRLEN];
     268  
     269  		for (i = 0; i < ai->naddrs; i++)
     270  		  {
     271  		    switch (*families)
     272  		      {
     273  		      case AF_INET:
     274  			inet_ntop (*families, addrs, buf, sizeof (buf));
     275  			printf (" %s", buf);
     276  			addrs += 4;
     277  			break;
     278  		      case AF_INET6:
     279  			inet_ntop (*families, addrs, buf, sizeof (buf));
     280  			printf (" %s", buf);
     281  			addrs += 16;
     282  			break;
     283  		      }
     284  		    families++;
     285  		  }
     286  		DSTR (" ] canon ", ai->canonlen);
     287  		DSTR (" key ", -1);
     288  		printf ("\n");
     289  	      }
     290  	      break;
     291  
     292  	    case INITGROUPS:
     293  	      {
     294  		initgr_response_header *ig = &(dh->data[0].initgrdata);
     295  		printf (" nresults %d groups [", (int) ig->ngrps);
     296  		cp += sizeof (*ig);
     297  		grplens = (uint32_t *) cp;
     298  		cp += ig->ngrps * sizeof (uint32_t);
     299  		for (i = 0; i < ig->ngrps; i++)
     300  		  printf (" %d", grplens[i]);
     301  		DSTR (" ] key ", -1);
     302  		printf ("\n");
     303  	      }
     304  	      break;
     305  
     306  	    case GETSERVBYNAME:
     307  	    case GETSERVBYPORT:
     308  	      {
     309  		serv_response_header *serv = &(dh->data[0].servdata);
     310  		printf (" alias_cnt %ld port %d (stored as %d)",
     311  			(long) serv->s_aliases_cnt,
     312  			((serv->s_port & 0xff00) >> 8) | ((serv->
     313  							   s_port & 0xff) <<
     314  							  8), serv->s_port);
     315  		cp += sizeof (*serv);
     316  		DSTR (" name ", serv->s_name_len);
     317  		DSTR (" proto ", serv->s_proto_len);
     318  		if (serv->s_aliases_cnt)
     319  		  {
     320  		    uint32_t *alias_len = (uint32_t *) cp;
     321  		    printf (" aliases [");
     322  		    cp += sizeof (uint32_t) * serv->s_aliases_cnt;
     323  		    for (i = 0; i < serv->s_aliases_cnt; i++)
     324  		      DSTR (" ", alias_len[i]);
     325  		    printf (" ]");
     326  		  }
     327  		printf ("\n");
     328  	      }
     329  	      break;
     330  
     331  	    case GETNETGRENT:
     332  	      {
     333  		netgroup_response_header *ng = &(dh->data[0].netgroupdata);
     334  		printf (" nresults %d len %d\n",
     335  			(int) ng->nresults, (int) ng->result_len);
     336  		cp += sizeof (*ng);
     337  		for (i = 0; i < ng->nresults; i++)
     338  		  {
     339  		    DSTR (" (", -1);
     340  		    DSTR (",", -1);
     341  		    DSTR (",", -1);
     342  		    printf (")");
     343  		  }
     344  		printf ("\n");
     345  	      }
     346  	      break;
     347  
     348  	    case INNETGR:
     349  	      {
     350  		innetgroup_response_header *ing =
     351  		  &(dh->data[0].innetgroupdata);
     352  		printf (" result %d\n", ing->result);
     353  	      }
     354  	      break;
     355  
     356  	    default:
     357  	      break;
     358  	    }
     359  
     360  	  if (debug_level > 2 && cp && cp < cpe)
     361  	    {
     362  	      printf (_(" - remaining data %p: "), cp);
     363  	      data_string (cp, "", cpe - cp);
     364  	      printf ("\n");
     365  	    }
     366  
     367  
     368  	  r = here->next;
     369  	}
     370      }
     371  
     372    munmap (the_cache, st.st_size);
     373  
     374    exit (0);
     375  }