1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.1 (the "License"). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24/* 25 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 26 * unrestricted use provided that this legend is included on all tape 27 * media and as a part of the software program in whole or part. Users 28 * may copy or modify Sun RPC without charge, but are not authorized 29 * to license or distribute it to anyone else except as part of a product or 30 * program developed by the user. 31 * 32 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 33 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 34 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 35 * 36 * Sun RPC is provided with no support and without any obligation on the 37 * part of Sun Microsystems, Inc. to assist in its use, correction, 38 * modification or enhancement. 39 * 40 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 41 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 42 * OR ANY PART THEREOF. 43 * 44 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 45 * or profits or other special, indirect and consequential damages, even if 46 * Sun has been advised of the possibility of such damages. 47 * 48 * Sun Microsystems, Inc. 49 * 2550 Garcia Avenue 50 * Mountain View, California 94043 51 */ 52 53#if defined(LIBC_SCCS) && !defined(lint) 54/*static char *sccsid = "from: @(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";*/ 55/*static char *sccsid = "from: @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";*/ 56static char *rcsid = "$Id: pmap_rmt.c,v 1.6 2004/12/19 22:45:44 zarzycki Exp $"; 57#endif 58 59/* 60 * pmap_rmt.c 61 * Client interface to pmap rpc service. 62 * remote call and broadcast service 63 * 64 * Copyright (C) 1984, Sun Microsystems, Inc. 65 */ 66 67#include <string.h> 68#include <unistd.h> 69#include <rpc/rpc.h> 70#include <rpc/pmap_prot.h> 71#include <rpc/pmap_clnt.h> 72#include <rpc/pmap_rmt.h> 73#include <sys/socket.h> 74#include <sys/fcntl.h> 75#include <stdio.h> 76#include <errno.h> 77#include <net/if.h> 78#include <sys/ioctl.h> 79#include <arpa/inet.h> 80#define MAX_BROADCAST_SIZE 1400 81 82static struct timeval timeout = { 3, 0 }; 83 84 85/* 86 * pmapper remote-call-service interface. 87 * This routine is used to call the pmapper remote call service 88 * which will look up a service program in the port maps, and then 89 * remotely call that routine with the given parameters. This allows 90 * programs to do a lookup and call in one step. 91*/ 92enum clnt_stat 93pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) 94#ifdef __LP64__ 95 struct sockaddr_in *addr; 96 uint32_t prog, vers, proc; 97 xdrproc_t xdrargs, xdrres; 98 caddr_t argsp, resp; 99 struct timeval tout; 100 uint32_t *port_ptr; 101#else 102 struct sockaddr_in *addr; 103 u_long prog, vers, proc; 104 xdrproc_t xdrargs, xdrres; 105 caddr_t argsp, resp; 106 struct timeval tout; 107 u_long *port_ptr; 108#endif 109{ 110 int socket = -1; 111 register CLIENT *client; 112 struct rmtcallargs a; 113 struct rmtcallres r; 114 enum clnt_stat stat; 115 116 addr->sin_port = htons(PMAPPORT); 117 client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket); 118 if (client != (CLIENT *)NULL) { 119 a.prog = prog; 120 a.vers = vers; 121 a.proc = proc; 122 a.args_ptr = argsp; 123 a.xdr_args = xdrargs; 124 r.port_ptr = port_ptr; 125 r.results_ptr = resp; 126 r.xdr_results = xdrres; 127 stat = CLNT_CALL(client, PMAPPROC_CALLIT, (xdrproc_t)xdr_rmtcall_args, &a, (xdrproc_t)xdr_rmtcallres, &r, tout); 128 CLNT_DESTROY(client); 129 } else { 130 stat = RPC_FAILED; 131 } 132 (void)close(socket); 133 addr->sin_port = 0; 134 return (stat); 135} 136 137 138/* 139 * XDR remote call arguments 140 * written for XDR_ENCODE direction only 141 */ 142bool_t 143xdr_rmtcall_args(xdrs, cap) 144 register XDR *xdrs; 145 register struct rmtcallargs *cap; 146{ 147 u_int lenposition, argposition, position; 148 149 if (xdr_u_long(xdrs, &(cap->prog)) && 150 xdr_u_long(xdrs, &(cap->vers)) && 151 xdr_u_long(xdrs, &(cap->proc))) { 152 lenposition = XDR_GETPOS(xdrs); 153 if (! xdr_u_long(xdrs, &(cap->arglen))) 154 return (FALSE); 155 argposition = XDR_GETPOS(xdrs); 156 if (! (*(cap->xdr_args))(xdrs, cap->args_ptr, 0)) 157 return (FALSE); 158 position = XDR_GETPOS(xdrs); 159#ifdef __LP64__ 160 cap->arglen = (uint32_t)position - (uint32_t)argposition; 161#else 162 cap->arglen = (u_long)position - (u_long)argposition; 163#endif 164 XDR_SETPOS(xdrs, lenposition); 165 if (! xdr_u_long(xdrs, &(cap->arglen))) 166 return (FALSE); 167 XDR_SETPOS(xdrs, position); 168 return (TRUE); 169 } 170 return (FALSE); 171} 172 173/* 174 * XDR remote call results 175 * written for XDR_DECODE direction only 176 */ 177bool_t 178xdr_rmtcallres(xdrs, crp) 179 register XDR *xdrs; 180 register struct rmtcallres *crp; 181{ 182 caddr_t port_ptr; 183 184 port_ptr = (caddr_t)crp->port_ptr; 185#ifdef __LP64__ 186 if (xdr_reference(xdrs, &port_ptr, sizeof (uint32_t), (xdrproc_t)xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { 187 crp->port_ptr = (unsigned int *)port_ptr; 188 return ((*(crp->xdr_results))(xdrs, crp->results_ptr, 0)); 189 } 190#else 191 if (xdr_reference(xdrs, &port_ptr, sizeof (u_long), (xdrproc_t)xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { 192 crp->port_ptr = (unsigned long *)port_ptr; 193 return ((*(crp->xdr_results))(xdrs, crp->results_ptr, 0)); 194 } 195#endif 196 return (FALSE); 197} 198 199 200/* 201 * The following is kludged-up support for simple rpc broadcasts. 202 * Someday a large, complicated system will replace these trivial 203 * routines which only support udp/ip . 204 */ 205 206static int 207getbroadcastnets(addrs, sock, buf) 208 struct in_addr *addrs; 209 int sock; /* any valid socket will do */ 210 char *buf; /* why allocxate more when we can use existing... */ 211{ 212 struct ifconf ifc; 213 struct ifreq ifreq, *ifr; 214 struct sockaddr_in *sin; 215 char *cp, *cplim; 216 int i = 0; 217 218 ifc.ifc_len = UDPMSGSIZE; 219 ifc.ifc_buf = buf; 220 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { 221 perror("broadcast: ioctl (get interface configuration)"); 222 return (0); 223 } 224#define max(a, b) (a > b ? a : b) 225#define size(p) max((p).sa_len, sizeof(p)) 226 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ 227 for (cp = buf; cp < cplim; 228 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { 229 ifr = (struct ifreq *)cp; 230 if (ifr->ifr_addr.sa_family != AF_INET) 231 continue; 232 ifreq = *ifr; 233 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 234 perror("broadcast: ioctl (get interface flags)"); 235 continue; 236 } 237 if ((ifreq.ifr_flags & IFF_BROADCAST) && 238 (ifreq.ifr_flags & IFF_UP)) { 239 sin = (struct sockaddr_in *)&ifr->ifr_addr; 240#ifdef SIOCGIFBRDADDR /* 4.3BSD */ 241 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 242 addrs[i++] = 243 inet_makeaddr(inet_netof(sin->sin_addr), 244 INADDR_ANY); 245 } else { 246 addrs[i++] = ((struct sockaddr_in*) 247 &ifreq.ifr_addr)->sin_addr; 248 } 249#else /* 4.2 BSD */ 250 addrs[i++] = inet_makeaddr(inet_netof(sin->sin_addr), 251 INADDR_ANY); 252#endif 253 } 254 } 255 return (i); 256} 257 258typedef bool_t (*resultproc_t)(); 259 260enum clnt_stat 261clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) 262#ifdef __LP64__ 263 uint32_t prog; /* program number */ 264 uint32_t vers; /* version number */ 265 uint32_t proc; /* procedure number */ 266 xdrproc_t xargs; /* xdr routine for args */ 267 caddr_t argsp; /* pointer to args */ 268 xdrproc_t xresults; /* xdr routine for results */ 269 caddr_t resultsp; /* pointer to results */ 270 resultproc_t eachresult; /* call with each result obtained */ 271#else 272 u_long prog; /* program number */ 273 u_long vers; /* version number */ 274 u_long proc; /* procedure number */ 275 xdrproc_t xargs; /* xdr routine for args */ 276 caddr_t argsp; /* pointer to args */ 277 xdrproc_t xresults; /* xdr routine for results */ 278 caddr_t resultsp; /* pointer to results */ 279 resultproc_t eachresult; /* call with each result obtained */ 280#endif 281{ 282 enum clnt_stat stat; 283 AUTH *unix_auth = authunix_create_default(); 284 XDR xdr_stream; 285 register XDR *xdrs = &xdr_stream; 286 int outlen, inlen, nets; 287 unsigned int fromlen; 288 register int sock; 289 int on = 1; 290 fd_set mask; 291 fd_set readfds; 292 register int i; 293 bool_t done = FALSE; 294 uint32_t xid; 295#ifdef __LP64__ 296 unsigned int port; 297#else 298 unsigned long port; 299#endif 300 struct in_addr addrs[20]; 301 struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ 302 struct rmtcallargs a; 303 struct rmtcallres r; 304 struct rpc_msg msg; 305 struct timeval t; 306 char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; 307 int rfd; 308 309 stat = RPC_SUCCESS; 310 311 /* 312 * initialization: create a socket, a broadcast address, and 313 * preserialize the arguments into a send buffer. 314 */ 315 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 316 perror("Cannot create socket for broadcast rpc"); 317 stat = RPC_CANTSEND; 318 goto done_broad; 319 } 320#ifdef SO_BROADCAST 321 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 322 perror("Cannot set socket option SO_BROADCAST"); 323 stat = RPC_CANTSEND; 324 goto done_broad; 325 } 326#endif /* def SO_BROADCAST */ 327 FD_ZERO(&mask); 328 FD_SET(sock, &mask); 329 nets = getbroadcastnets(addrs, sock, inbuf); 330 bzero((char *)&baddr, sizeof (baddr)); 331 baddr.sin_family = AF_INET; 332 baddr.sin_port = htons(PMAPPORT); 333 baddr.sin_addr.s_addr = htonl(INADDR_ANY); 334/* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ 335 336 rfd = open("/dev/random", O_RDONLY, 0); 337 if ((rfd < 0) || (read(rfd, &xid, sizeof(xid)) != sizeof(xid))) 338 { 339 gettimeofday(&t, (struct timezone *)0); 340 xid = getpid() ^ t.tv_sec ^ t.tv_usec; 341 } 342 if (rfd > 0) close(rfd); 343 344 t.tv_usec = 0; 345 msg.rm_xid = xid; 346 msg.rm_direction = CALL; 347 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 348 msg.rm_call.cb_prog = PMAPPROG; 349 msg.rm_call.cb_vers = PMAPVERS; 350 msg.rm_call.cb_proc = PMAPPROC_CALLIT; 351 msg.rm_call.cb_cred = unix_auth->ah_cred; 352 msg.rm_call.cb_verf = unix_auth->ah_verf; 353 a.prog = prog; 354 a.vers = vers; 355 a.proc = proc; 356 a.xdr_args = xargs; 357 a.args_ptr = argsp; 358 r.port_ptr = &port; 359 r.xdr_results = xresults; 360 r.results_ptr = resultsp; 361 xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); 362 if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { 363 stat = RPC_CANTENCODEARGS; 364 goto done_broad; 365 } 366 outlen = (int)xdr_getpos(xdrs); 367 xdr_destroy(xdrs); 368 /* 369 * Basic loop: broadcast a packet and wait a while for response(s). 370 * The response timeout grows larger per iteration. 371 */ 372 for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { 373 for (i = 0; i < nets; i++) { 374 baddr.sin_addr = addrs[i]; 375 if (sendto(sock, outbuf, outlen, 0, 376 (struct sockaddr *)&baddr, 377 sizeof (struct sockaddr)) != outlen) { 378 perror("Cannot send broadcast packet"); 379 stat = RPC_CANTSEND; 380 goto done_broad; 381 } 382 } 383 if (eachresult == NULL) { 384 stat = RPC_SUCCESS; 385 goto done_broad; 386 } 387 recv_again: 388 msg.acpted_rply.ar_verf = _null_auth; 389 msg.acpted_rply.ar_results.where = (caddr_t)&r; 390 msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_rmtcallres; 391 readfds = mask; 392 switch (select(sock+1, &readfds, NULL, NULL, &t)) { 393 394 case 0: /* timed out */ 395 stat = RPC_TIMEDOUT; 396 continue; 397 398 case -1: /* some kind of error */ 399 if (errno == EINTR) 400 goto recv_again; 401 perror("Broadcast select problem"); 402 stat = RPC_CANTRECV; 403 goto done_broad; 404 405 } /* end of select results switch */ 406 try_again: 407 fromlen = sizeof(struct sockaddr); 408 inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0, (struct sockaddr *)&raddr, &fromlen); 409 if (inlen < 0) { 410 if (errno == EINTR) 411 goto try_again; 412 perror("Cannot receive reply to broadcast"); 413 stat = RPC_CANTRECV; 414 goto done_broad; 415 } 416#ifdef __LP64__ 417 if (inlen < sizeof(uint32_t)) 418 goto recv_again; 419#else 420 if (inlen < sizeof(u_long)) 421 goto recv_again; 422#endif 423 /* 424 * see if reply transaction id matches sent id. 425 * If so, decode the results. 426 */ 427 xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); 428 if (xdr_replymsg(xdrs, &msg)) { 429 if ((msg.rm_xid == xid) && 430 (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 431 (msg.acpted_rply.ar_stat == SUCCESS)) { 432 raddr.sin_port = htons((u_short)port); 433 done = (*eachresult)(resultsp, &raddr); 434 } 435 /* otherwise, we just ignore the errors ... */ 436 } else { 437#ifdef notdef 438 /* some kind of deserialization problem ... */ 439 if (msg.rm_xid == xid) 440 fprintf(stderr, "Broadcast deserialization problem"); 441 /* otherwise, just random garbage */ 442#endif 443 } 444 xdrs->x_op = XDR_FREE; 445 msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 446 (void)xdr_replymsg(xdrs, &msg); 447 (void)(*xresults)(xdrs, resultsp, 0); 448 xdr_destroy(xdrs); 449 if (done) { 450 stat = RPC_SUCCESS; 451 goto done_broad; 452 } else { 453 goto recv_again; 454 } 455 } 456done_broad: 457 (void)close(sock); 458 AUTH_DESTROY(unix_auth); 459 return (stat); 460} 461 462