Skip to content
Permalink
1979f3c1ad
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
960 lines (808 sloc) 18.9 KB
/* Copyright (c) 1998-2016 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* getent: get entries from administrative database. */
#include <aliases.h>
#include <argp.h>
#include <ctype.h>
#include <error.h>
#include <grp.h>
#include <gshadow.h>
#include <libintl.h>
#include <locale.h>
#include <mcheck.h>
#include <netdb.h>
#include <pwd.h>
#include <shadow.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
/* Get libc version number. */
#include <version.h>
#define PACKAGE _libc_intl_domainname
/* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
/* Short description of parameters. */
static const char args_doc[] = N_("database [key ...]");
/* Supported options. */
static const struct argp_option args_options[] =
{
{ "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") },
{ "no-idn", 'i', NULL, 0, N_("disable IDN encoding") },
{ NULL, 0, NULL, 0, NULL },
};
/* Short description of program. */
static const char doc[] = N_("Get entries from administrative database.");
/* Prototype for option handler. */
static error_t parse_option (int key, char *arg, struct argp_state *state);
/* Function to print some extra text in the help message. */
static char *more_help (int key, const char *text, void *input);
/* Data structure to communicate with argp functions. */
static struct argp argp =
{
args_options, parse_option, args_doc, doc, NULL, more_help
};
/* Additional getaddrinfo flags for IDN encoding. */
static int idn_flags = AI_IDN | AI_CANONIDN;
/* Print the version information. */
static void
print_version (FILE *stream, struct argp_state *state)
{
fprintf (stream, "getent %s%s\n", PKGVERSION, VERSION);
fprintf (stream, gettext ("\
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"), "2016");
fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
}
/* This is for aliases */
static void
print_aliases (struct aliasent *alias)
{
unsigned int i = 0;
printf ("%s: ", alias->alias_name);
for (i = strlen (alias->alias_name); i < 14; ++i)
fputs_unlocked (" ", stdout);
for (i = 0; i < alias->alias_members_len; ++i)
printf ("%s%s",
alias->alias_members [i],
i + 1 == alias->alias_members_len ? "\n" : ", ");
}
static int
aliases_keys (int number, char *key[])
{
int result = 0;
int i;
struct aliasent *alias;
if (number == 0)
{
setaliasent ();
while ((alias = getaliasent ()) != NULL)
print_aliases (alias);
endaliasent ();
return result;
}
for (i = 0; i < number; ++i)
{
alias = getaliasbyname (key[i]);
if (alias == NULL)
result = 2;
else
print_aliases (alias);
}
return result;
}
/* This is for ethers */
static int
ethers_keys (int number, char *key[])
{
int result = 0;
int i;
if (number == 0)
{
fprintf (stderr, _("Enumeration not supported on %s\n"), "ethers");
return 3;
}
for (i = 0; i < number; ++i)
{
struct ether_addr *ethp, eth;
char buffer [1024], *p;
ethp = ether_aton (key[i]);
if (ethp != NULL)
{
if (ether_ntohost (buffer, ethp))
{
result = 2;
continue;
}
p = buffer;
}
else
{
if (ether_hostton (key[i], &eth))
{
result = 2;
continue;
}
p = key[i];
ethp = &eth;
}
printf ("%s %s\n", ether_ntoa (ethp), p);
}
return result;
}
/* This is for group */
static void
print_group (struct group *grp)
{
if (putgrent (grp, stdout) != 0)
fprintf (stderr, "error writing group entry: %m\n");
}
static int
group_keys (int number, char *key[])
{
int result = 0;
int i;
struct group *grp;
if (number == 0)
{
setgrent ();
while ((grp = getgrent ()) != NULL)
print_group (grp);
endgrent ();
return result;
}
for (i = 0; i < number; ++i)
{
errno = 0;
char *ep;
gid_t arg_gid = strtoul(key[i], &ep, 10);
if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
/* Valid numeric gid. */
grp = getgrgid (arg_gid);
else
grp = getgrnam (key[i]);
if (grp == NULL)
result = 2;
else
print_group (grp);
}
return result;
}
/* This is for gshadow */
static void
print_gshadow (struct sgrp *sg)
{
if (putsgent (sg, stdout) != 0)
fprintf (stderr, "error writing gshadow entry: %m\n");
}
static int
gshadow_keys (int number, char *key[])
{
int result = 0;
int i;
if (number == 0)
{
struct sgrp *sg;
setsgent ();
while ((sg = getsgent ()) != NULL)
print_gshadow (sg);
endsgent ();
return result;
}
for (i = 0; i < number; ++i)
{
struct sgrp *sg;
sg = getsgnam (key[i]);
if (sg == NULL)
result = 2;
else
print_gshadow (sg);
}
return result;
}
/* This is for hosts */
static void
print_hosts (struct hostent *host)
{
unsigned int cnt;
for (cnt = 0; host->h_addr_list[cnt] != NULL; ++cnt)
{
char buf[INET6_ADDRSTRLEN];
const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[cnt],
buf, sizeof (buf));
printf ("%-15s %s", ip, host->h_name);
unsigned int i;
for (i = 0; host->h_aliases[i] != NULL; ++i)
{
putchar_unlocked (' ');
fputs_unlocked (host->h_aliases[i], stdout);
}
putchar_unlocked ('\n');
}
}
static int
hosts_keys (int number, char *key[])
{
int result = 0;
int i;
struct hostent *host;
if (number == 0)
{
sethostent (0);
while ((host = gethostent ()) != NULL)
print_hosts (host);
endhostent ();
return result;
}
for (i = 0; i < number; ++i)
{
struct hostent *host = NULL;
char addr[IN6ADDRSZ];
if (inet_pton (AF_INET6, key[i], &addr) > 0)
host = gethostbyaddr (addr, IN6ADDRSZ, AF_INET6);
else if (inet_pton (AF_INET, key[i], &addr) > 0)
host = gethostbyaddr (addr, INADDRSZ, AF_INET);
else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
host = gethostbyname2 (key[i], AF_INET);
if (host == NULL)
result = 2;
else
print_hosts (host);
}
return result;
}
/* This is for hosts, but using getaddrinfo */
static int
ahosts_keys_int (int af, int xflags, int number, char *key[])
{
int result = 0;
int i;
struct hostent *host;
if (number == 0)
{
sethostent (0);
while ((host = gethostent ()) != NULL)
print_hosts (host);
endhostent ();
return result;
}
struct addrinfo hint;
memset (&hint, '\0', sizeof (hint));
hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME
| idn_flags | xflags);
hint.ai_family = af;
for (i = 0; i < number; ++i)
{
struct addrinfo *res;
if (getaddrinfo (key[i], NULL, &hint, &res) != 0)
result = 2;
else
{
struct addrinfo *runp = res;
while (runp != NULL)
{
char sockbuf[20];
const char *sockstr;
if (runp->ai_socktype == SOCK_STREAM)
sockstr = "STREAM";
else if (runp->ai_socktype == SOCK_DGRAM)
sockstr = "DGRAM";
else if (runp->ai_socktype == SOCK_RAW)
sockstr = "RAW";
#ifdef SOCK_SEQPACKET
else if (runp->ai_socktype == SOCK_SEQPACKET)
sockstr = "SEQPACKET";
#endif
#ifdef SOCK_RDM
else if (runp->ai_socktype == SOCK_RDM)
sockstr = "RDM";
#endif
#ifdef SOCK_DCCP
else if (runp->ai_socktype == SOCK_DCCP)
sockstr = "DCCP";
#endif
#ifdef SOCK_PACKET
else if (runp->ai_socktype == SOCK_PACKET)
sockstr = "PACKET";
#endif
else
{
snprintf (sockbuf, sizeof (sockbuf), "%d",
runp->ai_socktype);
sockstr = sockbuf;
}
char buf[INET6_ADDRSTRLEN];
printf ("%-15s %-6s %s\n",
inet_ntop (runp->ai_family,
runp->ai_family == AF_INET
? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr
: (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr,
buf, sizeof (buf)),
sockstr,
runp->ai_canonname ?: "");
runp = runp->ai_next;
}
freeaddrinfo (res);
}
}
return result;
}
static int
ahosts_keys (int number, char *key[])
{
return ahosts_keys_int (AF_UNSPEC, 0, number, key);
}
static int
ahostsv4_keys (int number, char *key[])
{
return ahosts_keys_int (AF_INET, 0, number, key);
}
static int
ahostsv6_keys (int number, char *key[])
{
return ahosts_keys_int (AF_INET6, AI_V4MAPPED, number, key);
}
/* This is for netgroup */
static int
netgroup_keys (int number, char *key[])
{
int result = 0;
if (number == 0)
{
fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup");
return 3;
}
if (number == 4)
{
char *host = strcmp (key[1], "*") == 0 ? NULL : key[1];
char *user = strcmp (key[2], "*") == 0 ? NULL : key[2];
char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3];
printf ("%-21s (%s,%s,%s) = %d\n",
key[0], host ?: "", user ?: "", domain ?: "",
innetgr (key[0], host, user, domain));
}
else if (number == 1)
{
if (!setnetgrent (key[0]))
result = 2;
else
{
char *p[3];
printf ("%-21s", key[0]);
while (getnetgrent (p, p + 1, p + 2))
printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
putchar_unlocked ('\n');
}
}
endnetgrent ();
return result;
}
/* This is for initgroups */
static int
initgroups_keys (int number, char *key[])
{
int ngrps = 100;
size_t grpslen = ngrps * sizeof (gid_t);
gid_t *grps = alloca (grpslen);
if (number == 0)
{
fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups");
return 3;
}
for (int i = 0; i < number; ++i)
{
int no = ngrps;
int n;
while ((n = getgrouplist (key[i], -1, grps, &no)) == -1
&& no > ngrps)
{
grps = extend_alloca (grps, grpslen, no * sizeof (gid_t));
ngrps = no;
}
if (n == -1)
return 1;
printf ("%-21s", key[i]);
for (int j = 0; j < n; ++j)
if (grps[j] != -1)
printf (" %ld", (long int) grps[j]);
putchar_unlocked ('\n');
}
return 0;
}
/* This is for networks */
static void
print_networks (struct netent *net)
{
unsigned int i;
struct in_addr ip;
ip.s_addr = htonl (net->n_net);
printf ("%-21s %s", net->n_name, inet_ntoa (ip));
i = 0;
while (net->n_aliases[i] != NULL)
{
putchar_unlocked (' ');
fputs_unlocked (net->n_aliases[i], stdout);
++i;
}
putchar_unlocked ('\n');
}
static int
networks_keys (int number, char *key[])
{
int result = 0;
int i;
struct netent *net;
if (number == 0)
{
setnetent (0);
while ((net = getnetent ()) != NULL)
print_networks (net);
endnetent ();
return result;
}
for (i = 0; i < number; ++i)
{
if (isdigit (key[i][0]))
net = getnetbyaddr (ntohl (inet_addr (key[i])), AF_UNSPEC);
else
net = getnetbyname (key[i]);
if (net == NULL)
result = 2;
else
print_networks (net);
}
return result;
}
/* Now is all for passwd */
static void
print_passwd (struct passwd *pwd)
{
if (putpwent (pwd, stdout) != 0)
fprintf (stderr, "error writing passwd entry: %m\n");
}
static int
passwd_keys (int number, char *key[])
{
int result = 0;
int i;
struct passwd *pwd;
if (number == 0)
{
setpwent ();
while ((pwd = getpwent ()) != NULL)
print_passwd (pwd);
endpwent ();
return result;
}
for (i = 0; i < number; ++i)
{
errno = 0;
char *ep;
uid_t arg_uid = strtoul(key[i], &ep, 10);
if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
/* Valid numeric uid. */
pwd = getpwuid (arg_uid);
else
pwd = getpwnam (key[i]);
if (pwd == NULL)
result = 2;
else
print_passwd (pwd);
}
return result;
}
/* This is for protocols */
static void
print_protocols (struct protoent *proto)
{
unsigned int i;
printf ("%-21s %d", proto->p_name, proto->p_proto);
i = 0;
while (proto->p_aliases[i] != NULL)
{
putchar_unlocked (' ');
fputs_unlocked (proto->p_aliases[i], stdout);
++i;
}
putchar_unlocked ('\n');
}
static int
protocols_keys (int number, char *key[])
{
int result = 0;
int i;
struct protoent *proto;
if (number == 0)
{
setprotoent (0);
while ((proto = getprotoent ()) != NULL)
print_protocols (proto);
endprotoent ();
return result;
}
for (i = 0; i < number; ++i)
{
if (isdigit (key[i][0]))
proto = getprotobynumber (atol (key[i]));
else
proto = getprotobyname (key[i]);
if (proto == NULL)
result = 2;
else
print_protocols (proto);
}
return result;
}
#if HAVE_SUNRPC
/* Now is all for rpc */
static void
print_rpc (struct rpcent *rpc)
{
int i;
printf ("%-15s %d%s",
rpc->r_name, rpc->r_number, rpc->r_aliases[0] ? " " : "");
for (i = 0; rpc->r_aliases[i]; ++i)
printf (" %s", rpc->r_aliases[i]);
putchar_unlocked ('\n');
}
static int
rpc_keys (int number, char *key[])
{
int result = 0;
int i;
struct rpcent *rpc;
if (number == 0)
{
setrpcent (0);
while ((rpc = getrpcent ()) != NULL)
print_rpc (rpc);
endrpcent ();
return result;
}
for (i = 0; i < number; ++i)
{
if (isdigit (key[i][0]))
rpc = getrpcbynumber (atol (key[i]));
else
rpc = getrpcbyname (key[i]);
if (rpc == NULL)
result = 2;
else
print_rpc (rpc);
}
return result;
}
#endif
/* for services */
static void
print_services (struct servent *serv)
{
unsigned int i;
printf ("%-21s %d/%s", serv->s_name, ntohs (serv->s_port), serv->s_proto);
i = 0;
while (serv->s_aliases[i] != NULL)
{
putchar_unlocked (' ');
fputs_unlocked (serv->s_aliases[i], stdout);
++i;
}
putchar_unlocked ('\n');
}
static int
services_keys (int number, char *key[])
{
int result = 0;
int i;
struct servent *serv;
if (!number)
{
setservent (0);
while ((serv = getservent ()) != NULL)
print_services (serv);
endservent ();
return result;
}
for (i = 0; i < number; ++i)
{
struct servent *serv;
char *proto = strchr (key[i], '/');
if (proto != NULL)
*proto++ = '\0';
char *endptr;
long port = strtol (key[i], &endptr, 10);
if (isdigit (key[i][0]) && *endptr == '\0'
&& 0 <= port && port <= 65535)
serv = getservbyport (htons (port), proto);
else
serv = getservbyname (key[i], proto);
if (serv == NULL)
result = 2;
else
print_services (serv);
}
return result;
}
/* This is for shadow */
static void
print_shadow (struct spwd *sp)
{
if (putspent (sp, stdout) != 0)
fprintf (stderr, "error writing shadow entry: %m\n");
}
static int
shadow_keys (int number, char *key[])
{
int result = 0;
int i;
if (number == 0)
{
struct spwd *sp;
setspent ();
while ((sp = getspent ()) != NULL)
print_shadow (sp);
endspent ();
return result;
}
for (i = 0; i < number; ++i)
{
struct spwd *sp;
sp = getspnam (key[i]);
if (sp == NULL)
result = 2;
else
print_shadow (sp);
}
return result;
}
struct
{
const char *name;
int (*func) (int number, char *key[]);
} databases[] =
{
#define D(name) { #name, name ## _keys },
D(ahosts)
D(ahostsv4)
D(ahostsv6)
D(aliases)
D(ethers)
D(group)
D(gshadow)
D(hosts)
D(initgroups)
D(netgroup)
D(networks)
D(passwd)
D(protocols)
#if HAVE_SUNRPC
D(rpc)
#endif
D(services)
D(shadow)
#undef D
{ NULL, NULL }
};
/* Handle arguments found by argp. */
static error_t
parse_option (int key, char *arg, struct argp_state *state)
{
char *endp;
switch (key)
{
case 's':
endp = strchr (arg, ':');
if (endp == NULL)
/* No specific database, change them all. */
for (int i = 0; databases[i].name != NULL; ++i)
__nss_configure_lookup (databases[i].name, arg);
else
{
int i;
for (i = 0; databases[i].name != NULL; ++i)
if (strncmp (databases[i].name, arg, endp - arg) == 0)
{
__nss_configure_lookup (databases[i].name, endp + 1);
break;
}
if (databases[i].name == NULL)
error (EXIT_FAILURE, 0, gettext ("Unknown database name"));
}
break;
case 'i':
idn_flags = 0;
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static char *
more_help (int key, const char *text, void *input)
{
switch (key)
{
size_t len;
char *doc;
FILE *fp;
case ARGP_KEY_HELP_EXTRA:
/* We print some extra information. */
fp = open_memstream (&doc, &len);
if (fp != NULL)
{
fputs_unlocked (_("Supported databases:\n"), fp);
for (int i = 0, col = 0; databases[i].name != NULL; ++i)
{
len = strlen (databases[i].name);
if (i != 0)
{
if (col + len > 72)
{
col = 0;
fputc_unlocked ('\n', fp);
}
else
fputc_unlocked (' ', fp);
}
fputs_unlocked (databases[i].name, fp);
col += len + 1;
}
fputs ("\n\n", fp);
fprintf (fp, gettext ("\
For bug reporting instructions, please see:\n\
%s.\n"), REPORT_BUGS_TO);
if (fclose (fp) == 0)
return doc;
}
break;
default:
break;
}
return (char *) text;
}
/* the main function */
int
main (int argc, char *argv[])
{
/* Debugging support. */
mtrace ();
/* Set locale via LC_ALL. */
setlocale (LC_ALL, "");
/* Set the text message domain. */
textdomain (PACKAGE);
/* Parse and process arguments. */
int remaining;
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
if ((argc - remaining) < 1)
{
error (0, 0, gettext ("wrong number of arguments"));
argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
return 1;
}
for (int i = 0; databases[i].name; ++i)
if (argv[remaining][0] == databases[i].name[0]
&& !strcmp (argv[remaining], databases[i].name))
return databases[i].func (argc - remaining - 1, &argv[remaining + 1]);
fprintf (stderr, _("Unknown database: %s\n"), argv[remaining]);
argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
return 1;
}