126135Swpaul/*
226135Swpaul * Copyright (c) 1996, 1997
326135Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
426135Swpaul *
526135Swpaul * Redistribution and use in source and binary forms, with or without
626135Swpaul * modification, are permitted provided that the following conditions
726135Swpaul * are met:
826135Swpaul * 1. Redistributions of source code must retain the above copyright
926135Swpaul *    notice, this list of conditions and the following disclaimer.
1026135Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1126135Swpaul *    notice, this list of conditions and the following disclaimer in the
1226135Swpaul *    documentation and/or other materials provided with the distribution.
1326135Swpaul * 3. All advertising materials mentioning features or use of this software
1426135Swpaul *    must display the following acknowledgement:
1526135Swpaul *	This product includes software developed by Bill Paul.
1626135Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1726135Swpaul *    may be used to endorse or promote products derived from this software
1826135Swpaul *    without specific prior written permission.
1926135Swpaul *
2026135Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2126135Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2226135Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2326135Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2426135Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2526135Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2626135Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2726135Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2826135Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2926135Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3026135Swpaul * SUCH DAMAGE.
3126135Swpaul */
3226135Swpaul
3326135Swpaul/*
3426135Swpaul * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3526135Swpaul * unrestricted use provided that this legend is included on all tape
3626135Swpaul * media and as a part of the software program in whole or part.  Users
3726135Swpaul * may copy or modify Sun RPC without charge, but are not authorized
3826135Swpaul * to license or distribute it to anyone else except as part of a product or
3926135Swpaul * program developed by the user.
4026135Swpaul *
4126135Swpaul * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
4226135Swpaul * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
4326135Swpaul * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
4426135Swpaul *
4526135Swpaul * Sun RPC is provided with no support and without any obligation on the
4626135Swpaul * part of Sun Microsystems, Inc. to assist in its use, correction,
4726135Swpaul * modification or enhancement.
4826135Swpaul *
4926135Swpaul * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
5026135Swpaul * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
5126135Swpaul * OR ANY PART THEREOF.
5226135Swpaul *
5326135Swpaul * In no event will Sun Microsystems, Inc. be liable for any lost revenue
5426135Swpaul * or profits or other special, indirect and consequential damages, even if
5526135Swpaul * Sun has been advised of the possibility of such damages.
5626135Swpaul *
5726135Swpaul * Sun Microsystems, Inc.
5826135Swpaul * 2550 Garcia Avenue
5926135Swpaul * Mountain View, California  94043
6026135Swpaul */
6126135Swpaul
62114601Sobrien#if 0
6326135Swpaul#ifndef lint
6430762Scharnierstatic char *sccsid = "@(#)from: clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
6530762Scharnierstatic char *sccsid = "@(#)from: clnt_udp.c	2.2 88/08/01 4.0 RPCSRC";
6626135Swpaul#endif
6730762Scharnier#endif
68114601Sobrien#include <sys/cdefs.h>
69114601Sobrien__FBSDID("$FreeBSD$");
7026135Swpaul
7126135Swpaul/*
7226135Swpaul * clnt_udp.c, Implements a UDP/IP based, client side RPC.
7326135Swpaul *
7426135Swpaul * Copyright (C) 1984, Sun Microsystems, Inc.
7526135Swpaul */
7626135Swpaul
7730762Scharnier#include <errno.h>
7830762Scharnier#include <netdb.h>
7926135Swpaul#include <stdio.h>
8026135Swpaul#include <stdlib.h>
8130762Scharnier#include <string.h>
8226135Swpaul#include <unistd.h>
8374880Swpaul#include <pthread.h>
8426135Swpaul#include <rpc/rpc.h>
8526135Swpaul#include <rpc/pmap_clnt.h>
8626135Swpaul#include <rpc/pmap_prot.h>
8726135Swpaul#include <rpcsvc/yp.h>
8874880Swpaul#include <sys/types.h>
8974880Swpaul#include <sys/poll.h>
9030762Scharnier#include <sys/socket.h>
9174880Swpaul#include <sys/signal.h>
9230762Scharnier#include <sys/ioctl.h>
9390868Smike#include <arpa/inet.h>
9430762Scharnier#include <net/if.h>
9574880Swpaul
9626135Swpaul#include "yp_ping.h"
9726135Swpaul
9826135Swpaul/*
9926135Swpaul * pmap_getport.c
10026135Swpaul * Client interface to pmap rpc service.
10126135Swpaul *
10226135Swpaul * Copyright (C) 1984, Sun Microsystems, Inc.
10326135Swpaul */
10426135Swpaul
10526135Swpaul
10626135Swpaulstatic struct timeval timeout = { 1, 0 };
10726135Swpaulstatic struct timeval tottimeout = { 1, 0 };
10826135Swpaul
10926135Swpaul/*
11026135Swpaul * Find the mapped port for program,version.
11126135Swpaul * Calls the pmap service remotely to do the lookup.
11226135Swpaul * Returns 0 if no map exists.
11326135Swpaul */
11426135Swpaulstatic u_short
11590298Sdes__pmap_getport(struct sockaddr_in *address, u_long program, u_long version,
11690298Sdes    u_int protocol)
11726135Swpaul{
11826135Swpaul	u_short port = 0;
11926135Swpaul	int sock = -1;
12026135Swpaul	register CLIENT *client;
12126135Swpaul	struct pmap parms;
12226135Swpaul
12326135Swpaul	address->sin_port = htons(PMAPPORT);
12426135Swpaul
12526135Swpaul	client = clntudp_bufcreate(address, PMAPPROG,
12626135Swpaul	    PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
12726135Swpaul	if (client != (CLIENT *)NULL) {
12826135Swpaul		parms.pm_prog = program;
12926135Swpaul		parms.pm_vers = version;
13026135Swpaul		parms.pm_prot = protocol;
13126135Swpaul		parms.pm_port = 0;  /* not needed or used */
13295658Sdes		if (CLNT_CALL(client, PMAPPROC_GETPORT,
13395658Sdes			(xdrproc_t)xdr_pmap, &parms,
13495658Sdes			(xdrproc_t)xdr_u_short, &port,
13595658Sdes			tottimeout) != RPC_SUCCESS){
13626135Swpaul			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
13726135Swpaul			clnt_geterr(client, &rpc_createerr.cf_error);
13826135Swpaul		} else if (port == 0) {
13926135Swpaul			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
14026135Swpaul		}
14126135Swpaul		CLNT_DESTROY(client);
14226135Swpaul	}
14326135Swpaul	if (sock != -1)
14426135Swpaul		(void)close(sock);
14526135Swpaul	address->sin_port = 0;
14626135Swpaul	return (port);
14726135Swpaul}
14826135Swpaul
14926135Swpaul/*
15026135Swpaul * Transmit to YPPROC_DOMAIN_NONACK, return immediately.
15126135Swpaul */
15226135Swpaulstatic bool_t *
15326135Swpaulypproc_domain_nonack_2_send(domainname *argp, CLIENT *clnt)
15426135Swpaul{
15526135Swpaul	static bool_t clnt_res;
15626135Swpaul	struct timeval TIMEOUT = { 0, 0 };
15726135Swpaul
15826135Swpaul	memset((char *)&clnt_res, 0, sizeof (clnt_res));
15926135Swpaul	if (clnt_call(clnt, YPPROC_DOMAIN_NONACK,
16026135Swpaul		(xdrproc_t) xdr_domainname, (caddr_t) argp,
16126135Swpaul		(xdrproc_t) xdr_bool, (caddr_t) &clnt_res,
16226135Swpaul		TIMEOUT) != RPC_SUCCESS) {
16326135Swpaul		return (NULL);
16426135Swpaul	}
16526135Swpaul	return (&clnt_res);
16626135Swpaul}
16726135Swpaul
16826135Swpaul/*
16926135Swpaul * Receive response from YPPROC_DOMAIN_NONACK asynchronously.
17026135Swpaul */
17126135Swpaulstatic bool_t *
17226135Swpaulypproc_domain_nonack_2_recv(domainname *argp, CLIENT *clnt)
17326135Swpaul{
17426135Swpaul	static bool_t clnt_res;
17526135Swpaul	struct timeval TIMEOUT = { 0, 0 };
17626135Swpaul
17726135Swpaul	memset((char *)&clnt_res, 0, sizeof (clnt_res));
17826135Swpaul	if (clnt_call(clnt, YPPROC_DOMAIN_NONACK,
17926135Swpaul		(xdrproc_t) NULL, (caddr_t) argp,
18026135Swpaul		(xdrproc_t) xdr_bool, (caddr_t) &clnt_res,
18126135Swpaul		TIMEOUT) != RPC_SUCCESS) {
18226135Swpaul		return (NULL);
18326135Swpaul	}
18426135Swpaul	return (&clnt_res);
18526135Swpaul}
18626135Swpaul
18726135Swpaul/*
18826135Swpaul * "We have the machine that goes 'ping!'" -- Monty Python
18926135Swpaul *
19026135Swpaul * This function blasts packets at the YPPROC_DOMAIN_NONACK procedures
19126135Swpaul * of the NIS servers listed in restricted_addrs structure.
19226135Swpaul * Whoever replies the fastest becomes our chosen server.
19326135Swpaul *
19426135Swpaul * Note: THIS IS NOT A BROADCAST OPERATION! We could use clnt_broadcast()
19526135Swpaul * for this, but that has the following problems:
19626135Swpaul * - We only get the address of the machine that replied in the
19726135Swpaul *   'eachresult' callback, and on multi-homed machines this can
19826135Swpaul *   lead to confusion.
19926135Swpaul * - clnt_broadcast() only transmits to local networks, whereas with
20026135Swpaul *   NIS+ you can have a perfectly good server located anywhere on or
20126135Swpaul *   off the local network.
20226135Swpaul * - clnt_broadcast() blocks for an arbitrary amount of time which the
20326135Swpaul *   caller can't control -- we want to avoid that.
20426135Swpaul *
20526135Swpaul * Also note that this has nothing to do with the NIS_PING procedure used
20626135Swpaul * for replica updates.
20726135Swpaul */
20826135Swpaul
20926135Swpaulstruct ping_req {
21026135Swpaul	struct sockaddr_in	sin;
211103428Sfenner	u_int32_t		xid;
21226135Swpaul};
21326135Swpaul
21490298Sdesint
21590298Sdes__yp_ping(struct in_addr *restricted_addrs, int cnt, char *dom, short *port)
21626135Swpaul{
21790297Sdes	struct timeval		tv = { 5, 0 };
21826135Swpaul	struct ping_req		**reqs;
21926135Swpaul	unsigned long		i;
22074880Swpaul	int			async;
22132631Swpaul	struct sockaddr_in	sin, *any = NULL;
222183038Sdfr	struct netbuf		addr;
22326135Swpaul	int			winner = -1;
224103428Sfenner	u_int32_t		xid_seed, xid_lookup;
22526135Swpaul	int			sock, dontblock = 1;
22626135Swpaul	CLIENT			*clnt;
22726135Swpaul	char			*foo = dom;
22830252Swpaul	int			validsrvs = 0;
22926135Swpaul
23026135Swpaul	/* Set up handles. */
23126135Swpaul	reqs = calloc(1, sizeof(struct ping_req *) * cnt);
23226135Swpaul	xid_seed = time(NULL) ^ getpid();
23326135Swpaul
23426135Swpaul	for (i = 0; i < cnt; i++) {
23526135Swpaul		bzero((char *)&sin, sizeof(sin));
23626135Swpaul		sin.sin_family = AF_INET;
23726135Swpaul		bcopy((char *)&restricted_addrs[i],
23826135Swpaul			(char *)&sin.sin_addr, sizeof(struct in_addr));
23926135Swpaul		sin.sin_port = htons(__pmap_getport(&sin, YPPROG,
24026135Swpaul					YPVERS, IPPROTO_UDP));
24126135Swpaul		if (sin.sin_port == 0)
24226135Swpaul			continue;
24326135Swpaul		reqs[i] = calloc(1, sizeof(struct ping_req));
24426135Swpaul		bcopy((char *)&sin, (char *)&reqs[i]->sin, sizeof(sin));
24526135Swpaul		any = &reqs[i]->sin;
24626135Swpaul		reqs[i]->xid = xid_seed;
24726135Swpaul		xid_seed++;
24830252Swpaul		validsrvs++;
24926135Swpaul	}
25026135Swpaul
25126135Swpaul	/* Make sure at least one server was assigned */
25230252Swpaul	if (!validsrvs) {
25326135Swpaul		free(reqs);
25426135Swpaul		return(-1);
25526135Swpaul	}
25626135Swpaul
25726135Swpaul	/* Create RPC handle */
25826135Swpaul	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
25926135Swpaul	clnt = clntudp_create(any, YPPROG, YPVERS, tv, &sock);
26026135Swpaul	if (clnt == NULL) {
26126135Swpaul		close(sock);
26226135Swpaul		for (i = 0; i < cnt; i++)
26326135Swpaul			if (reqs[i] != NULL)
26426135Swpaul				free(reqs[i]);
26526135Swpaul		free(reqs);
26626135Swpaul		return(-1);
26726135Swpaul	}
26826135Swpaul	clnt->cl_auth = authunix_create_default();
26926135Swpaul	tv.tv_sec = 0;
27074880Swpaul
27174462Salfred	clnt_control(clnt, CLSET_TIMEOUT, (char *)&tv);
27274880Swpaul	async = TRUE;
27374880Swpaul	clnt_control(clnt, CLSET_ASYNC, (char *)&async);
27426135Swpaul	ioctl(sock, FIONBIO, &dontblock);
27526135Swpaul
27626135Swpaul	/* Transmit */
27726135Swpaul	for (i = 0; i < cnt; i++) {
27826135Swpaul		if (reqs[i] != NULL) {
27974880Swpaul			clnt_control(clnt, CLSET_XID, (char *)&reqs[i]->xid);
280183038Sdfr			addr.len = sizeof(reqs[i]->sin);
281183038Sdfr			addr.buf = (char *) &reqs[i]->sin;
282183038Sdfr			clnt_control(clnt, CLSET_SVC_ADDR, &addr);
28326135Swpaul			ypproc_domain_nonack_2_send(&foo, clnt);
28426135Swpaul		}
28526135Swpaul	}
28626135Swpaul
28726135Swpaul	/* Receive reply */
28826135Swpaul	ypproc_domain_nonack_2_recv(&foo, clnt);
28926135Swpaul
29026135Swpaul	/* Got a winner -- look him up. */
29174880Swpaul	clnt_control(clnt, CLGET_XID, (char *)&xid_lookup);
29226135Swpaul	for (i = 0; i < cnt; i++) {
29326135Swpaul		if (reqs[i] != NULL && reqs[i]->xid == xid_lookup) {
29426135Swpaul			winner = i;
29526135Swpaul			*port = reqs[i]->sin.sin_port;
29626135Swpaul		}
29726135Swpaul	}
29826135Swpaul
29926135Swpaul	/* Shut everything down */
30026135Swpaul	auth_destroy(clnt->cl_auth);
30126135Swpaul	clnt_destroy(clnt);
30226135Swpaul	close(sock);
30326135Swpaul
30426135Swpaul	for (i = 0; i < cnt; i++)
30526135Swpaul		if (reqs[i] != NULL)
30626135Swpaul			free(reqs[i]);
30726135Swpaul	free(reqs);
30826135Swpaul
30926135Swpaul	return(winner);
31026135Swpaul}
311