1 /* Copyright (c) 2020-2022 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 *
data_string(unsigned char * cp,const char * str,int len)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
nscd_print_cache(const char * name)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 }
376