]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/ypbind/yp_ping.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / ypbind / yp_ping.c
1 /*
2  * Copyright (c) 1996, 1997
3  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*-
34  * Copyright (c) 2009, Sun Microsystems, Inc.
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without 
38  * modification, are permitted provided that the following conditions are met:
39  * - Redistributions of source code must retain the above copyright notice, 
40  *   this list of conditions and the following disclaimer.
41  * - Redistributions in binary form must reproduce the above copyright notice, 
42  *   this list of conditions and the following disclaimer in the documentation 
43  *   and/or other materials provided with the distribution.
44  * - Neither the name of Sun Microsystems, Inc. nor the names of its 
45  *   contributors may be used to endorse or promote products derived 
46  *   from this software without specific prior written permission.
47  * 
48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
49  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
51  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
52  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
58  * POSSIBILITY OF SUCH DAMAGE.
59  */
60 #if 0
61 #ifndef lint
62 static char *sccsid = "@(#)from: clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
63 static char *sccsid = "@(#)from: clnt_udp.c     2.2 88/08/01 4.0 RPCSRC";
64 #endif
65 #endif
66 #include <sys/cdefs.h>
67 __FBSDID("$FreeBSD$");
68
69 /*
70  * clnt_udp.c, Implements a UDP/IP based, client side RPC.
71  *
72  * Copyright (C) 1984, Sun Microsystems, Inc.
73  */
74
75 #include <errno.h>
76 #include <netdb.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <unistd.h>
81 #include <pthread.h>
82 #include <rpc/rpc.h>
83 #include <rpc/pmap_clnt.h>
84 #include <rpc/pmap_prot.h>
85 #include <rpcsvc/yp.h>
86 #include <sys/types.h>
87 #include <sys/poll.h>
88 #include <sys/socket.h>
89 #include <sys/signal.h>
90 #include <sys/ioctl.h>
91 #include <arpa/inet.h>
92 #include <net/if.h>
93
94 #include "yp_ping.h"
95
96 /*
97  * pmap_getport.c
98  * Client interface to pmap rpc service.
99  *
100  * Copyright (C) 1984, Sun Microsystems, Inc.
101  */
102
103
104 static struct timeval timeout = { 1, 0 };
105 static struct timeval tottimeout = { 1, 0 };
106
107 /*
108  * Find the mapped port for program,version.
109  * Calls the pmap service remotely to do the lookup.
110  * Returns 0 if no map exists.
111  */
112 static u_short
113 __pmap_getport(struct sockaddr_in *address, u_long program, u_long version,
114     u_int protocol)
115 {
116         u_short port = 0;
117         int sock = -1;
118         register CLIENT *client;
119         struct pmap parms;
120
121         address->sin_port = htons(PMAPPORT);
122
123         client = clntudp_bufcreate(address, PMAPPROG,
124             PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
125         if (client != (CLIENT *)NULL) {
126                 parms.pm_prog = program;
127                 parms.pm_vers = version;
128                 parms.pm_prot = protocol;
129                 parms.pm_port = 0;  /* not needed or used */
130                 if (CLNT_CALL(client, PMAPPROC_GETPORT,
131                         (xdrproc_t)xdr_pmap, &parms,
132                         (xdrproc_t)xdr_u_short, &port,
133                         tottimeout) != RPC_SUCCESS){
134                         rpc_createerr.cf_stat = RPC_PMAPFAILURE;
135                         clnt_geterr(client, &rpc_createerr.cf_error);
136                 } else if (port == 0) {
137                         rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
138                 }
139                 CLNT_DESTROY(client);
140         }
141         if (sock != -1)
142                 (void)close(sock);
143         address->sin_port = 0;
144         return (port);
145 }
146
147 /*
148  * Transmit to YPPROC_DOMAIN_NONACK, return immediately.
149  */
150 static bool_t *
151 ypproc_domain_nonack_2_send(domainname *argp, CLIENT *clnt)
152 {
153         static bool_t clnt_res;
154         struct timeval TIMEOUT = { 0, 0 };
155
156         memset((char *)&clnt_res, 0, sizeof (clnt_res));
157         if (clnt_call(clnt, YPPROC_DOMAIN_NONACK,
158                 (xdrproc_t) xdr_domainname, (caddr_t) argp,
159                 (xdrproc_t) xdr_bool, (caddr_t) &clnt_res,
160                 TIMEOUT) != RPC_SUCCESS) {
161                 return (NULL);
162         }
163         return (&clnt_res);
164 }
165
166 /*
167  * Receive response from YPPROC_DOMAIN_NONACK asynchronously.
168  */
169 static bool_t *
170 ypproc_domain_nonack_2_recv(domainname *argp, CLIENT *clnt)
171 {
172         static bool_t clnt_res;
173         struct timeval TIMEOUT = { 0, 0 };
174
175         memset((char *)&clnt_res, 0, sizeof (clnt_res));
176         if (clnt_call(clnt, YPPROC_DOMAIN_NONACK,
177                 (xdrproc_t) NULL, (caddr_t) argp,
178                 (xdrproc_t) xdr_bool, (caddr_t) &clnt_res,
179                 TIMEOUT) != RPC_SUCCESS) {
180                 return (NULL);
181         }
182         return (&clnt_res);
183 }
184
185 /*
186  * "We have the machine that goes 'ping!'" -- Monty Python
187  *
188  * This function blasts packets at the YPPROC_DOMAIN_NONACK procedures
189  * of the NIS servers listed in restricted_addrs structure.
190  * Whoever replies the fastest becomes our chosen server.
191  *
192  * Note: THIS IS NOT A BROADCAST OPERATION! We could use clnt_broadcast()
193  * for this, but that has the following problems:
194  * - We only get the address of the machine that replied in the
195  *   'eachresult' callback, and on multi-homed machines this can
196  *   lead to confusion.
197  * - clnt_broadcast() only transmits to local networks, whereas with
198  *   NIS+ you can have a perfectly good server located anywhere on or
199  *   off the local network.
200  * - clnt_broadcast() blocks for an arbitrary amount of time which the
201  *   caller can't control -- we want to avoid that.
202  *
203  * Also note that this has nothing to do with the NIS_PING procedure used
204  * for replica updates.
205  */
206
207 struct ping_req {
208         struct sockaddr_in      sin;
209         u_int32_t               xid;
210 };
211
212 int
213 __yp_ping(struct in_addr *restricted_addrs, int cnt, char *dom, short *port)
214 {
215         struct timeval          tv = { 5, 0 };
216         struct ping_req         **reqs;
217         unsigned long           i;
218         int                     async;
219         struct sockaddr_in      sin, *any = NULL;
220         struct netbuf           addr;
221         int                     winner = -1;
222         u_int32_t               xid_seed, xid_lookup;
223         int                     sock, dontblock = 1;
224         CLIENT                  *clnt;
225         char                    *foo = dom;
226         int                     validsrvs = 0;
227
228         /* Set up handles. */
229         reqs = calloc(1, sizeof(struct ping_req *) * cnt);
230         xid_seed = time(NULL) ^ getpid();
231
232         for (i = 0; i < cnt; i++) {
233                 bzero((char *)&sin, sizeof(sin));
234                 sin.sin_family = AF_INET;
235                 bcopy((char *)&restricted_addrs[i],
236                         (char *)&sin.sin_addr, sizeof(struct in_addr));
237                 sin.sin_port = htons(__pmap_getport(&sin, YPPROG,
238                                         YPVERS, IPPROTO_UDP));
239                 if (sin.sin_port == 0)
240                         continue;
241                 reqs[i] = calloc(1, sizeof(struct ping_req));
242                 bcopy((char *)&sin, (char *)&reqs[i]->sin, sizeof(sin));
243                 any = &reqs[i]->sin;
244                 reqs[i]->xid = xid_seed;
245                 xid_seed++;
246                 validsrvs++;
247         }
248
249         /* Make sure at least one server was assigned */
250         if (!validsrvs) {
251                 free(reqs);
252                 return(-1);
253         }
254
255         /* Create RPC handle */
256         sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
257         clnt = clntudp_create(any, YPPROG, YPVERS, tv, &sock);
258         if (clnt == NULL) {
259                 close(sock);
260                 for (i = 0; i < cnt; i++)
261                         if (reqs[i] != NULL)
262                                 free(reqs[i]);
263                 free(reqs);
264                 return(-1);
265         }
266         clnt->cl_auth = authunix_create_default();
267         tv.tv_sec = 0;
268
269         clnt_control(clnt, CLSET_TIMEOUT, (char *)&tv);
270         async = TRUE;
271         clnt_control(clnt, CLSET_ASYNC, (char *)&async);
272         ioctl(sock, FIONBIO, &dontblock);
273
274         /* Transmit */
275         for (i = 0; i < cnt; i++) {
276                 if (reqs[i] != NULL) {
277                         clnt_control(clnt, CLSET_XID, (char *)&reqs[i]->xid);
278                         addr.len = sizeof(reqs[i]->sin);
279                         addr.buf = (char *) &reqs[i]->sin;
280                         clnt_control(clnt, CLSET_SVC_ADDR, &addr);
281                         ypproc_domain_nonack_2_send(&foo, clnt);
282                 }
283         }
284
285         /* Receive reply */
286         ypproc_domain_nonack_2_recv(&foo, clnt);
287
288         /* Got a winner -- look him up. */
289         clnt_control(clnt, CLGET_XID, (char *)&xid_lookup);
290         for (i = 0; i < cnt; i++) {
291                 if (reqs[i] != NULL && reqs[i]->xid == xid_lookup) {
292                         winner = i;
293                         *port = reqs[i]->sin.sin_port;
294                 }
295         }
296
297         /* Shut everything down */
298         auth_destroy(clnt->cl_auth);
299         clnt_destroy(clnt);
300         close(sock);
301
302         for (i = 0; i < cnt; i++)
303                 if (reqs[i] != NULL)
304                         free(reqs[i]);
305         free(reqs);
306
307         return(winner);
308 }