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