]>
Commit | Line | Data |
---|---|---|
dcf46d3f DD |
1 | /* Copyright (c) 2020 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> | |
28b4928b | 29 | #include <sys/param.h> |
dcf46d3f DD |
30 | |
31 | #include "nscd.h" | |
32 | #include "dbg_log.h" | |
33 | ||
34 | static void *the_cache; | |
35 | ||
cbd15699 | 36 | #define NO_REF ((ref_t) -1) |
dcf46d3f DD |
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". */ | |
cbd15699 | 85 | #define A(x) (int) ((char *) &(x) - (char *) the_cache) |
dcf46d3f DD |
86 | |
87 | /* Common code for "print field DPS->F, it's offset, and contents". */ | |
cbd15699 | 88 | #define DPS(f) printf("%08x: %24s : %10d %08x\n", A (dps->f), #f, (int) dps->f, (int) dps->f); |
dcf46d3f DD |
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); | |
28b4928b DD |
141 | printf ("\" (len:%ld) Data %08lx\n", (long) here->len, |
142 | (long unsigned int) ((char *) dh - (char *) the_cache)); | |
dcf46d3f DD |
143 | |
144 | if (debug_level > 0) | |
145 | { | |
146 | /* Common code for printing fields in struct DATAHEAD DH. */ | |
cbd15699 | 147 | #define DH(f) printf ("%08x; %24s : %10d %08x\n", A (dh->f), #f, (int) dh->f, (int) dh->f); |
dcf46d3f DD |
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); | |
28b4928b DD |
260 | printf (" naddrs %ld addrslen %ld canonlen %ld error %d [", |
261 | (long) ai->naddrs, (long) ai->addrslen, | |
262 | (long) ai->canonlen, ai->error); | |
dcf46d3f DD |
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); | |
28b4928b DD |
310 | printf (" alias_cnt %ld port %d (stored as %d)", |
311 | (long) serv->s_aliases_cnt, | |
dcf46d3f DD |
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 | } |