From patchwork Fri Feb 7 23:12:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 37750 Received: (qmail 25331 invoked by alias); 7 Feb 2020 23:12:09 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 25255 invoked by uid 89); 7 Feb 2020 23:12:08 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.3 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=enjoy! X-HELO: us-smtp-1.mimecast.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1581117125; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=EDcoT8onssdAeLbDpiX1OtxcH08mPVqsozEzWS10/lM=; b=gWuacpRJSRUI8TqZ7biCsNBl4k2mS+S4HMpGAJxXGNY0PVuG2dT3nHfm8HFNmL/hww9hEy 4AKAkYNAC9aIzJiQ9g4tozYJ74dFrQ7PCp9qNAqZPO6SYsqLwi0dSqSlmfu95Hvgxze76C suDJN3jaYpHwQj/37C0BXiCwEXxO5nA= Date: Fri, 07 Feb 2020 18:12:00 -0500 Message-Id: From: DJ Delorie To: libc-alpha@sourceware.org Subject: New utility: nscd cache dumper X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com First pass. Dumps contents of nscd cache files (/var/db/nscd/* on Fedora). I'm open to tweaks to what's included with -v (verbose) and/or -x (extra). Enjoy! diff --git a/nscd/Makefile b/nscd/Makefile index e12b9f11f1..d2d91830d0 100644 --- a/nscd/Makefile +++ b/nscd/Makefile @@ -46,6 +46,8 @@ install-sbin := nscd extra-objs = $(nscd-modules:=.o) +others += cachedumper + endif all-nscd-modules := $(nscd-modules) selinux @@ -101,3 +103,6 @@ $(objpfx)nscd: $(shared-thread-library) else $(objpfx)nscd: $(static-thread-library) endif + +cache_dumper-modules := cachedumper + diff --git a/nscd/cachedumper.c b/nscd/cachedumper.c new file mode 100644 index 0000000000..4b276f8a73 --- /dev/null +++ b/nscd/cachedumper.c @@ -0,0 +1,395 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nscd-client.h" + +void *the_cache; + +int verbose = 0; +int extended = 0; +int noesc = 0; + +#define NO_REF ((ref_t)-1) + +/* Map request type to a string. */ +const char *const serv2str[LASTREQ] = +{ + [GETPWBYNAME] = "GETPWBYNAME", + [GETPWBYUID] = "GETPWBYUID", + [GETGRBYNAME] = "GETGRBYNAME", + [GETGRBYGID] = "GETGRBYGID", + [GETHOSTBYNAME] = "GETHOSTBYNAME", + [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6", + [GETHOSTBYADDR] = "GETHOSTBYADDR", + [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6", + [SHUTDOWN] = "SHUTDOWN", + [GETSTAT] = "GETSTAT", + [INVALIDATE] = "INVALIDATE", + [GETFDPW] = "GETFDPW", + [GETFDGR] = "GETFDGR", + [GETFDHST] = "GETFDHST", + [GETAI] = "GETAI", + [INITGROUPS] = "INITGROUPS", + [GETSERVBYNAME] = "GETSERVBYNAME", + [GETSERVBYPORT] = "GETSERVBYPORT", + [GETFDSERV] = "GETFDSERV", + [GETNETGRENT] = "GETNETGRENT", + [INNETGR] = "INNETGR", + [GETFDNETGR] = "GETFDNETGR" +}; + +unsigned char * +data_string (unsigned char *cp, const char *str, int len) +{ + int oops = 0; + unsigned char *cpe = cp + len; + printf ("%s", str); + while ((len == -1) ? 1 : (cp < cpe)) + { + if (isgraph (*cp)) + putchar (*cp); + else + if (noesc) + printf ("<%02x>", + (unsigned char) *cp); + else + printf ("\033[%dm<%02x>\033[0m", + *cp % 6 + 31, + (unsigned char) *cp); + if (len == -1 && *cp == 0) + return cp + 1; + + ++ cp; + if (++oops > 1000) + break; + } + return cp; +} + +int +main (int argc, char **argv) +{ + struct stat st; + int fd; + int i, o; + + while ((o = getopt (argc, argv, "vxph")) != -1) + switch (o) + { + case 'v': + verbose ++; + break; + case 'x': + extended ++; + break; + case 'p': + noesc ++; + break; + case '?': + case 'h': + fprintf (stderr, "Usage: %s [-v] [-x] [-p] /var/db/nscd/\n", argv[0]); + fprintf (stderr, " -v = verbose, may be given multiple times\n"); + fprintf (stderr, " -x = print extra data after record (twice," + " prints all data of record)\n"); + fprintf (stderr, " -p = plain text, no colors\n"); + exit (1); + } + + if (stat (argv[optind], &st) < 0) + { + perror (argv [optind]); + exit (1); + } + + fd = open (argv[optind], O_RDONLY); + + the_cache = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + + struct database_pers_head *dps = (struct database_pers_head *) the_cache; + +#define A(x) (int)((char *)&(x)-(char *)the_cache) + +#define DPS(f) printf("%08x: %24s : %10d %08x\n", A (dps->f), #f, (int)dps->f, (int)dps->f); + + if (verbose) + { + DPS (version); + DPS (header_size); + DPS (gc_cycle); + DPS (nscd_certainly_running); + DPS (timestamp); + DPS (module); + DPS (data_size); + DPS (first_free); + DPS (nentries); + DPS (maxnentries); + DPS (maxnsearched); + DPS (poshit); + DPS (neghit); + DPS (posmiss); + DPS (negmiss); + DPS (rdlockdelayed); + DPS (wrlockdelayed); + DPS (addfailed); + printf ("\n"); + } + + + char *data = (char *) &dps->array[roundup (dps->module, + ALIGN / sizeof (ref_t))]; + + for (i=0; imodule; i++) + { + ref_t r = dps->array[i]; + if (r == NO_REF) + continue; + + if (verbose > 2) + printf ("hash[%4d] = 0x%x\n", i, r); + + while (r != NO_REF) + { + struct hashentry *here = (struct hashentry *) (data + r); + + unsigned char *key = (unsigned char *) data + here->key; + + printf ("\n%08x: type %s key %p \"", A (*here), + serv2str[here->type], key); + + data_string (key, "", here->len); + + struct datahead *dh = (struct datahead *) (data + here->packet); + printf ("\" (len:%d) Data %08lx\n", here->len, + (char *)dh - (char *)the_cache); + + if (verbose) + { +#define DH(f) printf ("%08x; %24s : %10d %08x\n", A (dh->f), #f, (int)dh->f, (int)dh->f); + DH (allocsize); + DH (recsize); + DH (timeout); + DH (notfound); + DH (nreloads); + DH (usable); + DH (unused); + DH (ttl); + } + + unsigned char *cp = (unsigned char *)(&dh->data[0]); + unsigned char *cpe = (unsigned char *)(&dh->data[0]) + dh->allocsize; + + + int i; + uint32_t *grplens; + + if (extended > 1) + { + data_string (cp, " - all data: ", cpe-cp); + printf ("\n"); + } + + /* These two are common to all responses. */ + printf ("V%d F%d", + dh->data[0].pwdata.version, dh->data[0].pwdata.found); + +#define DSTR(str, l) cp = data_string (cp, str, l) + + switch (here->type) + { + case GETPWBYNAME: + case GETPWBYUID: + { + pw_response_header *pw = &(dh->data[0].pwdata); + cp += sizeof (*pw); + DSTR (" name ", pw->pw_name_len); + DSTR (" passwd ", pw->pw_passwd_len); + printf (" uid %d gid %d", pw->pw_uid, pw->pw_gid); + DSTR (" gecos ", pw->pw_gecos_len); + DSTR (" dir ", pw->pw_dir_len); + DSTR (" shell ", pw->pw_shell_len); + DSTR (" byuid ", -1); + DSTR (" key ", -1); + printf ("\n"); + } + break; + + case GETGRBYNAME: + case GETGRBYGID: + { + gr_response_header *gr = &(dh->data[0].grdata); + cp += sizeof (*gr); + grplens = (uint32_t *) cp; + cp += gr->gr_mem_cnt * sizeof (uint32_t); + DSTR (" name ", gr->gr_name_len); + DSTR (" passwd ", gr->gr_passwd_len); + printf (" gid %d members %d [ ", (int)gr->gr_gid, (int)gr->gr_mem_cnt); + for (i=0; igr_mem_cnt; i++) + DSTR (" ", grplens[i]); + DSTR (" ] bygid ", -1); + DSTR (" key ", -1); + printf ("\n"); + } + break; + + case GETHOSTBYADDR: + case GETHOSTBYADDRv6: + case GETHOSTBYNAME: + case GETHOSTBYNAMEv6: + { + hst_response_header *hst = &(dh->data[0].hstdata); + printf (" addrtype %d error %d", + hst->h_addrtype, hst->error); + cp += sizeof (*hst); + DSTR (" name ", hst->h_name_len); + uint32_t *aliases_len = (uint32_t *)cp; + cp += hst->h_aliases_cnt * sizeof (uint32_t); + uint32_t *addrs = (uint32_t *)cp; + cp += hst->h_length * hst->h_addr_list_cnt; + + if (hst->h_aliases_cnt) + { + printf (" aliases ["); + for (i=0; ih_aliases_cnt; i++) + DSTR (" ", aliases_len[i]); + printf (" ]"); + } + if (hst->h_addr_list_cnt) + { + char buf[INET6_ADDRSTRLEN]; + printf (" addresses ["); + for (i=0; ih_addr_list_cnt; i++) + { + inet_ntop (hst->h_addrtype, addrs, buf, sizeof (buf)); + printf (" %s", buf); + addrs += hst->h_length; + } + printf (" ]"); + } + + printf ("\n"); + } + break; + + case GETAI: + { + ai_response_header *ai = &(dh->data[0].aidata); + printf (" naddrs %d addrslen %d canonlen %d error %d [", + ai->naddrs, ai->addrslen, ai->canonlen, ai->error); + cp += sizeof (*ai); + unsigned char *addrs = cp; + unsigned char *families = cp + ai->addrslen; + cp = families + ai->naddrs; + char buf[INET6_ADDRSTRLEN]; + + for (i=0; inaddrs; i++) + { + switch (*families) { + case AF_INET: + inet_ntop (*families, addrs, buf, sizeof (buf)); + printf (" %s", buf); + addrs += 4; + break; + case AF_INET6: + inet_ntop (*families, addrs, buf, sizeof (buf)); + printf (" %s", buf); + addrs += 16; + break; + } + families ++; + } + DSTR (" ] canon ", ai->canonlen); + DSTR (" key ", -1); + printf ("\n"); + } + break; + + case INITGROUPS: + { + initgr_response_header *ig = &(dh->data[0].initgrdata); + printf (" nresults %d groups [", + (int)ig->ngrps); + cp += sizeof (*ig); + grplens = (uint32_t *) cp; + cp += ig->ngrps * sizeof (uint32_t); + for (i=0; ingrps; i++) + printf (" %d", grplens[i]); + DSTR (" ] key ", -1); + printf ("\n"); + } + break; + + case GETSERVBYNAME: + case GETSERVBYPORT: + { + serv_response_header *serv = &(dh->data[0].servdata); + printf (" alias_cnt %d port %d (stored as %d)", + serv->s_aliases_cnt, + ((serv->s_port & 0xff00) >> 8) | ((serv->s_port & 0xff) << 8), + serv->s_port); + cp += sizeof (*serv); + DSTR (" name ", serv->s_name_len); + DSTR (" proto ", serv->s_proto_len); + if (serv->s_aliases_cnt) + { + uint32_t *alias_len = (uint32_t *) cp; + printf (" aliases ["); + cp += sizeof (uint32_t) * serv->s_aliases_cnt; + for (i=0; is_aliases_cnt; i++) + DSTR (" ", alias_len[i]); + printf (" ]"); + } + printf ("\n"); + } + break; + + case GETNETGRENT: + { + netgroup_response_header *ng = &(dh->data[0].netgroupdata); + printf (" nresults %d len %d\n", + (int)ng->nresults, (int)ng->result_len); + cp += sizeof (*ng); + for (i=0; inresults; i++) + { + DSTR (" (", -1); + DSTR (",", -1); + DSTR (",", -1); + printf (")"); + } + printf ("\n"); + } + break; + + case INNETGR: + { + innetgroup_response_header *ing = &(dh->data[0].innetgroupdata); + printf (" result %d\n", ing->result); + } + break; + + default: + break; + } + + if (extended && cp && cp < cpe) + { + printf (" - remaining data %p: ", cp); + data_string (cp, "", cpe-cp); + printf ("\n"); + } + + + r = here->next; + } + } + + munmap (the_cache, st.st_size); + + exit (0); +}