1/*	$OpenBSD: ypwhich.c,v 1.23 2015/02/08 23:40:35 deraadt Exp $	*/
2/*	$NetBSD: ypwhich.c,v 1.6 1996/05/13 02:43:48 thorpej Exp $	*/
3
4/*-
5 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
6 *
7 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35#include <sys/param.h>
36#include <sys/types.h>
37#include <sys/socket.h>
38
39#include <netinet/in.h>
40#include <arpa/inet.h>
41
42#include <ctype.h>
43#include <err.h>
44#include <netdb.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include <rpc/rpc.h>
51#include <rpc/xdr.h>
52#include <rpcsvc/yp.h>
53#include <rpcsvc/ypclnt.h>
54
55#include "yplib_host.h"
56
57static const struct ypalias {
58	char *alias, *name;
59} ypaliases[] = {
60	{ "passwd", "passwd.byname" },
61	{ "master.passwd", "master.passwd.byname" },
62	{ "shadow", "shadow.byname" },
63	{ "group", "group.byname" },
64	{ "networks", "networks.byaddr" },
65	{ "hosts", "hosts.byaddr" },
66	{ "protocols", "protocols.bynumber" },
67	{ "services", "services.byname" },
68	{ "aliases", "mail.aliases" },
69	{ "ethers", "ethers.byname" },
70};
71
72static void
73usage(void)
74{
75	fprintf(stderr,
76	    "usage: ypwhich [-t] [-d domain] [[-h] host]\n"
77	    "       ypwhich [-t] [-d domain] [-h host] -m [mname]\n"
78	    "       ypwhich -x\n");
79	exit(1);
80}
81
82
83/*
84 * Like yp_bind except can query a specific host
85 */
86static int
87bind_host(char *dom, struct sockaddr_in *sin)
88{
89	struct hostent *hent = NULL;
90	struct ypbind_resp ypbr;
91	struct in_addr ss_addr;
92	struct timeval tv;
93	CLIENT *client;
94	int sock, r;
95
96	sock = RPC_ANYSOCK;
97	tv.tv_sec = 15;
98	tv.tv_usec = 0;
99	client = clntudp_create(sin, YPBINDPROG, YPBINDVERS, tv, &sock);
100
101	if (client == NULL) {
102		warnx("host is not bound to a ypmaster");
103		return (YPERR_YPBIND);
104	}
105
106	tv.tv_sec = 5;
107	tv.tv_usec = 0;
108
109	r = clnt_call(client, YPBINDPROC_DOMAIN,
110		(xdrproc_t)xdr_domainname, &dom,
111		(xdrproc_t)xdr_ypbind_resp, &ypbr, tv);
112	if (r != RPC_SUCCESS) {
113		warnx("can't clnt_call: %s", yperr_string(YPERR_YPBIND));
114		clnt_destroy(client);
115		return (YPERR_YPBIND);
116	} else {
117		if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
118			warnx("can't yp_bind: reason: %s",
119			    yperr_string(ypbr.ypbind_status));
120			clnt_destroy(client);
121			return (r);
122		}
123	}
124	clnt_destroy(client);
125
126	memmove(&ss_addr.s_addr, &ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
127	    sizeof (ss_addr));
128
129	hent = gethostbyaddr((char *)&ss_addr.s_addr, sizeof(ss_addr.s_addr),
130	    AF_INET);
131	if (hent != NULL)
132		printf("%s\n", hent->h_name);
133	else
134		printf("%s\n", inet_ntoa(ss_addr));
135
136	return (0);
137}
138
139int
140main(int argc, char *argv[])
141{
142	char *domain, *master, *map = NULL, *host = NULL;
143	int notrans = 0, mode = 0, c, r, i;
144	struct ypmaplist *ypml, *y;
145	struct sockaddr_in sin;
146	struct hostent *hent;
147	CLIENT *client = NULL;
148
149	yp_get_default_domain(&domain);
150	if (domain == NULL)
151		errx(1, "YP domain name not set");
152
153	while ((c = getopt(argc, argv, "xd:h:mt")) != -1)
154		switch (c) {
155		case 'x':
156			for (i = 0; i < nitems(ypaliases); i++)
157				printf("\"%s\" is an alias for \"%s\"\n",
158					ypaliases[i].alias,
159					ypaliases[i].name);
160			exit(0);
161		case 'h':
162			host = optarg;
163			break;
164		case 'd':
165			domain = optarg;
166			break;
167		case 't':
168			notrans = 1;
169			break;
170		case 'm':
171			mode = 1;
172			break;
173		default:
174			usage();
175		}
176	argc -= optind;
177	argv += optind;
178
179	if (mode == 0) {
180		switch (argc) {
181		case 0:
182			memset(&sin, 0, sizeof sin);
183			sin.sin_family = AF_INET;
184			sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
185
186			if (bind_host(domain, &sin))
187				exit(1);
188			break;
189		case 1:
190			bzero(&sin, sizeof sin);
191			sin.sin_family = AF_INET;
192			if (inet_aton(argv[0], &sin.sin_addr) == 0) {
193				hent = gethostbyname(argv[0]);
194				if (!hent) {
195					errx(1, "host %s unknown",
196					    argv[0]);
197				}
198			}
199			if (bind_host(domain, &sin))
200				exit(1);
201			break;
202		default:
203			usage();
204		}
205		exit(0);
206	}
207
208	if (argc > 1)
209		usage();
210
211	if (host != NULL)
212		client = yp_bind_host(host, YPPROG, YPVERS, 0, 1);
213
214	if (argv[0]) {
215		map = argv[0];
216		if (notrans == 0) {
217			for (i = 0; i < nitems(ypaliases); i++)
218				if (strcmp(map, ypaliases[i].alias) == 0)
219					map = ypaliases[i].name;
220		}
221
222		if (host != NULL)
223			r = yp_master_host(client, domain, map, &master);
224		else
225			r = yp_master(domain, map, &master);
226
227		switch (r) {
228		case 0:
229			printf("%s\n", master);
230			free(master);
231			break;
232		case YPERR_YPBIND:
233			errx(1, "not running ypbind");
234		default:
235			errx(1, "can't find master for map %s: reason: %s",
236			    map, yperr_string(r));
237		}
238		exit(0);
239	}
240
241	ypml = NULL;
242	if (host != NULL)
243		r = yp_maplist_host(client, domain, &ypml);
244	else
245		r = yp_maplist(domain, &ypml);
246
247	r = 0;
248	switch (r) {
249	case 0:
250		for (y = ypml; y; ) {
251			ypml = y;
252			if (host != NULL) {
253				r = yp_master_host(client,
254						   domain, ypml->map, &master);
255			} else {
256				r = yp_master(domain, ypml->map, &master);
257			}
258			switch (r) {
259			case 0:
260				printf("%s %s\n", ypml->map, master);
261				free(master);
262				break;
263			default:
264				warnx("can't find the master of %s: reason: %s",
265				    ypml->map, yperr_string(r));
266				break;
267			}
268			y = ypml->next;
269			free(ypml);
270		}
271		break;
272	case YPERR_YPBIND:
273		errx(1, "not running ypbind");
274	default:
275		errx(1, "can't get map list for domain %s: reason: %s",
276		    domain, yperr_string(r));
277	}
278	exit(0);
279}
280