1/*	$OpenBSD: yplib_host.c,v 1.18 2015/01/16 06:40:22 deraadt Exp $ */
2
3/*
4 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/socket.h>
31#include <sys/types.h>
32#include <sys/uio.h>
33#include <sys/file.h>
34
35#include <ctype.h>
36#include <err.h>
37#include <errno.h>
38#include <netdb.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#include <netinet/in.h>
45#include <arpa/inet.h>
46
47#include <rpc/rpc.h>
48#include <rpc/xdr.h>
49#include <rpcsvc/yp.h>
50#include <rpcsvc/ypclnt.h>
51
52#include "yplib_host.h"
53
54extern bool_t xdr_ypresp_all_seq(XDR *, unsigned long *);
55
56extern int (*ypresp_allfn)(u_long, char *, int, char *, int, void *);
57extern void *ypresp_data;
58
59static int _yplib_host_timeout = 10;
60
61CLIENT *
62yp_bind_host(char *server, u_long program, u_long version, u_short port,
63    int usetcp)
64{
65	struct sockaddr_in rsrv_sin;
66	static CLIENT *client;
67	struct hostent *h;
68	struct timeval tv;
69	int rsrv_sock;
70
71	memset(&rsrv_sin, 0, sizeof rsrv_sin);
72	rsrv_sin.sin_len = sizeof rsrv_sin;
73	rsrv_sin.sin_family = AF_INET;
74	rsrv_sock = RPC_ANYSOCK;
75	if (port != 0)
76		rsrv_sin.sin_port = htons(port);
77
78	if (*server >= '0' && *server <= '9') {
79		if (inet_aton(server, &rsrv_sin.sin_addr) == 0) {
80			errx(1, "inet_aton: invalid address %s.",
81			    server);
82		}
83	} else {
84		h = gethostbyname(server);
85		if (h == NULL) {
86			errx(1, "gethostbyname: unknown host %s.",
87			    server);
88		}
89		rsrv_sin.sin_addr.s_addr = *(u_int32_t *)h->h_addr;
90	}
91
92	tv.tv_sec = 10;
93	tv.tv_usec = 0;
94
95	if (usetcp)
96		client = clnttcp_create(&rsrv_sin, program, version,
97		    &rsrv_sock, 0, 0);
98	else
99		client = clntudp_create(&rsrv_sin, program, version, tv,
100		    &rsrv_sock);
101
102	if (client == NULL) {
103		errx(1, "clntudp_create: no contact with host %s.",
104		    server);
105	}
106
107	return (client);
108}
109
110CLIENT *
111yp_bind_local(u_long program, u_long version)
112{
113	struct sockaddr_in rsrv_sin;
114	static CLIENT *client;
115	struct timeval tv;
116	int rsrv_sock;
117
118	memset(&rsrv_sin, 0, sizeof rsrv_sin);
119	rsrv_sin.sin_len = sizeof rsrv_sin;
120	rsrv_sin.sin_family = AF_INET;
121	rsrv_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
122	rsrv_sock = RPC_ANYSOCK;
123
124	tv.tv_sec = 10;
125	tv.tv_usec = 0;
126
127	client = clntudp_create(&rsrv_sin, program, version, tv, &rsrv_sock);
128	if (client == NULL) {
129		errx(1, "clntudp_create: no contact with localhost.");
130	}
131
132	return (client);
133}
134
135int
136yp_match_host(CLIENT *client, char *indomain, char *inmap, const char *inkey,
137    int inkeylen, char **outval, int *outvallen)
138{
139	struct ypresp_val yprv;
140	struct ypreq_key yprk;
141	struct timeval tv;
142	int r;
143
144	*outval = NULL;
145	*outvallen = 0;
146
147	tv.tv_sec = _yplib_host_timeout;
148	tv.tv_usec = 0;
149
150	yprk.domain = indomain;
151	yprk.map = inmap;
152	yprk.key.keydat_val = (char *)inkey;
153	yprk.key.keydat_len = inkeylen;
154
155	memset(&yprv, 0, sizeof yprv);
156
157	r = clnt_call(client, YPPROC_MATCH,
158	    (xdrproc_t)xdr_ypreq_key, &yprk,
159	    (xdrproc_t)xdr_ypresp_val, &yprv, tv);
160	if (r != RPC_SUCCESS)
161		clnt_perror(client, "yp_match_host: clnt_call");
162	if ( !(r = ypprot_err(yprv.stat)) ) {
163		*outvallen = yprv.val.valdat_len;
164		*outval = malloc(*outvallen + 1);
165		memcpy(*outval, yprv.val.valdat_val, *outvallen);
166		(*outval)[*outvallen] = '\0';
167	}
168	xdr_free((xdrproc_t)xdr_ypresp_val, (char *)&yprv);
169
170	return (r);
171}
172
173int
174yp_first_host(CLIENT *client, char *indomain, char *inmap, char **outkey,
175    int *outkeylen, char **outval, int *outvallen)
176{
177	struct ypresp_key_val yprkv;
178	struct ypreq_nokey yprnk;
179	struct timeval tv;
180	int r;
181
182	*outkey = *outval = NULL;
183	*outkeylen = *outvallen = 0;
184
185	tv.tv_sec = _yplib_host_timeout;
186	tv.tv_usec = 0;
187
188	yprnk.domain = indomain;
189	yprnk.map = inmap;
190	memset(&yprkv, 0, sizeof yprkv);
191
192	r = clnt_call(client, YPPROC_FIRST,
193	    (xdrproc_t)xdr_ypreq_nokey, &yprnk,
194	    (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
195	if (r != RPC_SUCCESS)
196		clnt_perror(client, "yp_first_host: clnt_call");
197	if ( !(r = ypprot_err(yprkv.stat)) ) {
198		*outkeylen = yprkv.key.keydat_len;
199		*outkey = malloc(*outkeylen+1);
200		memcpy(*outkey, yprkv.key.keydat_val, *outkeylen);
201		(*outkey)[*outkeylen] = '\0';
202		*outvallen = yprkv.val.valdat_len;
203		*outval = malloc(*outvallen+1);
204		memcpy(*outval, yprkv.val.valdat_val, *outvallen);
205		(*outval)[*outvallen] = '\0';
206	}
207	xdr_free((xdrproc_t)xdr_ypresp_key_val, (char *)&yprkv);
208
209	return (r);
210}
211
212int
213yp_next_host(CLIENT *client, char *indomain, char *inmap, char *inkey,
214    int inkeylen, char **outkey, int *outkeylen, char **outval, int *outvallen)
215{
216	struct ypresp_key_val yprkv;
217	struct ypreq_key yprk;
218	struct timeval tv;
219	int r;
220
221	*outkey = *outval = NULL;
222	*outkeylen = *outvallen = 0;
223
224	tv.tv_sec = _yplib_host_timeout;
225	tv.tv_usec = 0;
226
227	yprk.domain = indomain;
228	yprk.map = inmap;
229	yprk.key.keydat_val = inkey;
230	yprk.key.keydat_len = inkeylen;
231	memset(&yprkv, 0, sizeof yprkv);
232
233	r = clnt_call(client, YPPROC_NEXT,
234	    (xdrproc_t)xdr_ypreq_key, &yprk,
235	    (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
236	if (r != RPC_SUCCESS)
237		clnt_perror(client, "yp_next_host: clnt_call");
238	if ( !(r = ypprot_err(yprkv.stat)) ) {
239		*outkeylen = yprkv.key.keydat_len;
240		*outkey = malloc(*outkeylen+1);
241		memcpy(*outkey, yprkv.key.keydat_val, *outkeylen);
242		(*outkey)[*outkeylen] = '\0';
243		*outvallen = yprkv.val.valdat_len;
244		*outval = malloc(*outvallen+1);
245		memcpy(*outval, yprkv.val.valdat_val, *outvallen);
246		(*outval)[*outvallen] = '\0';
247	}
248	xdr_free((xdrproc_t)xdr_ypresp_key_val, (char *)&yprkv);
249
250	return (r);
251}
252
253int
254yp_all_host(CLIENT *client, char *indomain, char *inmap,
255    struct ypall_callback *incallback)
256{
257	struct ypreq_nokey yprnk;
258	struct timeval tv;
259	u_long status;
260
261	tv.tv_sec = _yplib_host_timeout;
262	tv.tv_usec = 0;
263
264	yprnk.domain = indomain;
265	yprnk.map = inmap;
266	ypresp_allfn = incallback->foreach;
267	ypresp_data = (void *)incallback->data;
268
269	(void) clnt_call(client, YPPROC_ALL,
270	    (xdrproc_t)xdr_ypreq_nokey, &yprnk,
271	    (xdrproc_t)xdr_ypresp_all_seq, &status, tv);
272	if (status != YP_FALSE)
273		return ypprot_err(status);
274
275	return (0);
276}
277
278int
279yp_order_host(CLIENT *client, char *indomain, char *inmap, u_int32_t *outorder)
280{
281	struct ypresp_order ypro;
282	struct ypreq_nokey yprnk;
283	struct timeval tv;
284	int r;
285
286	tv.tv_sec = _yplib_host_timeout;
287	tv.tv_usec = 0;
288
289	yprnk.domain = indomain;
290	yprnk.map = inmap;
291
292	memset(&ypro, 0, sizeof ypro);
293
294	r = clnt_call(client, YPPROC_ORDER,
295	    (xdrproc_t)xdr_ypreq_nokey, &yprnk,
296	    (xdrproc_t)xdr_ypresp_order, &ypro, tv);
297	if (r != RPC_SUCCESS)
298		clnt_perror(client, "yp_order_host: clnt_call");
299	*outorder = ypro.ordernum;
300	xdr_free((xdrproc_t)xdr_ypresp_order, (char *)&ypro);
301
302	return ypprot_err(ypro.stat);
303}
304
305int
306yp_master_host(CLIENT *client, char *indomain, char *inmap, char **outname)
307{
308	struct ypresp_master yprm;
309	struct ypreq_nokey yprnk;
310	struct timeval tv;
311	int r;
312
313	tv.tv_sec = _yplib_host_timeout;
314	tv.tv_usec = 0;
315	yprnk.domain = indomain;
316	yprnk.map = inmap;
317
318	memset(&yprm, 0, sizeof yprm);
319
320	r = clnt_call(client, YPPROC_MASTER,
321	    (xdrproc_t)xdr_ypreq_nokey, &yprnk,
322	    (xdrproc_t)xdr_ypresp_master, &yprm, tv);
323	if (r != RPC_SUCCESS)
324		clnt_perror(client, "yp_master: clnt_call");
325	if (!(r = ypprot_err(yprm.stat)))
326		*outname = strdup(yprm.peer);
327	xdr_free((xdrproc_t)xdr_ypresp_master, (char *)&yprm);
328
329	return (r);
330}
331
332int
333yp_maplist_host(CLIENT *client, char *indomain, struct ypmaplist **outmaplist)
334{
335	struct ypresp_maplist ypml;
336	struct timeval tv;
337	int r;
338
339	tv.tv_sec = _yplib_host_timeout;
340	tv.tv_usec = 0;
341
342	memset(&ypml, 0, sizeof ypml);
343
344	r = clnt_call(client, YPPROC_MAPLIST,
345	    (xdrproc_t)xdr_domainname, &indomain,
346	    (xdrproc_t)xdr_ypresp_maplist, &ypml, tv);
347	if (r != RPC_SUCCESS)
348		clnt_perror(client, "yp_maplist: clnt_call");
349	*outmaplist = ypml.maps;
350	/* NO: xdr_free(xdr_ypresp_maplist, &ypml);*/
351
352	return ypprot_err(ypml.stat);
353}
354