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