rpc.c revision 38451
1/* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1992 Regents of the University of California. 5 * All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Lawrence Berkeley Laboratory and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 40 */ 41 42/* 43 * RPC functions used by NFS and bootparams. 44 * Note that bootparams requires the ability to find out the 45 * address of the server from which its response has come. 46 * This is supported by keeping the IP/UDP headers in the 47 * buffer space provided by the caller. (See rpc_fromaddr) 48 */ 49 50#include <sys/param.h> 51#include <sys/socket.h> 52 53#include <netinet/in.h> 54#include <netinet/in_systm.h> 55 56#include <string.h> 57 58#include "rpcv2.h" 59 60#include "stand.h" 61#include "net.h" 62#include "netif.h" 63#include "rpc.h" 64 65struct auth_info { 66 int32_t authtype; /* auth type */ 67 u_int32_t authlen; /* auth length */ 68}; 69 70struct auth_unix { 71 int32_t ua_time; 72 int32_t ua_hostname; /* null */ 73 int32_t ua_uid; 74 int32_t ua_gid; 75 int32_t ua_gidlist; /* null */ 76}; 77 78struct rpc_call { 79 u_int32_t rp_xid; /* request transaction id */ 80 int32_t rp_direction; /* call direction (0) */ 81 u_int32_t rp_rpcvers; /* rpc version (2) */ 82 u_int32_t rp_prog; /* program */ 83 u_int32_t rp_vers; /* version */ 84 u_int32_t rp_proc; /* procedure */ 85}; 86 87struct rpc_reply { 88 u_int32_t rp_xid; /* request transaction id */ 89 int32_t rp_direction; /* call direction (1) */ 90 int32_t rp_astatus; /* accept status (0: accepted) */ 91 union { 92 u_int32_t rpu_errno; 93 struct { 94 struct auth_info rok_auth; 95 u_int32_t rok_status; 96 } rpu_rok; 97 } rp_u; 98}; 99 100/* Local forwards */ 101static ssize_t recvrpc(struct iodesc *, void *, size_t, time_t); 102static int rpc_getport(struct iodesc *, n_long, n_long); 103 104int rpc_xid; 105int rpc_port = 0x400; /* predecrement */ 106 107/* 108 * Make a rpc call; return length of answer 109 * Note: Caller must leave room for headers. 110 */ 111ssize_t 112rpc_call(d, prog, vers, proc, sdata, slen, rdata, rlen) 113 register struct iodesc *d; 114 register n_long prog, vers, proc; 115 register void *sdata; 116 register size_t slen; 117 register void *rdata; 118 register size_t rlen; 119{ 120 register ssize_t cc; 121 struct auth_info *auth; 122 struct rpc_call *call; 123 struct rpc_reply *reply; 124 char *send_head, *send_tail; 125 char *recv_head, *recv_tail; 126 n_long x; 127 int port; /* host order */ 128 129#ifdef RPC_DEBUG 130 if (debug) 131 printf("rpc_call: prog=0x%x vers=%d proc=%d\n", 132 prog, vers, proc); 133#endif 134 135 port = rpc_getport(d, prog, vers); 136 if (port == -1) 137 return (-1); 138 139 d->destport = htons(port); 140 141 /* 142 * Prepend authorization stuff and headers. 143 * Note, must prepend things in reverse order. 144 */ 145 send_head = sdata; 146 send_tail = (char *)sdata + slen; 147 148 /* Auth verifier is always auth_null */ 149 send_head -= sizeof(*auth); 150 auth = (struct auth_info *)send_head; 151 auth->authtype = htonl(RPCAUTH_NULL); 152 auth->authlen = 0; 153 154#if 1 155 /* Auth credentials: always auth unix (as root) */ 156 send_head -= sizeof(struct auth_unix); 157 bzero(send_head, sizeof(struct auth_unix)); 158 send_head -= sizeof(*auth); 159 auth = (struct auth_info *)send_head; 160 auth->authtype = htonl(RPCAUTH_UNIX); 161 auth->authlen = htonl(sizeof(struct auth_unix)); 162#else 163 /* Auth credentials: always auth_null (XXX OK?) */ 164 send_head -= sizeof(*auth); 165 auth = send_head; 166 auth->authtype = htonl(RPCAUTH_NULL); 167 auth->authlen = 0; 168#endif 169 170 /* RPC call structure. */ 171 send_head -= sizeof(*call); 172 call = (struct rpc_call *)send_head; 173 rpc_xid++; 174 call->rp_xid = htonl(rpc_xid); 175 call->rp_direction = htonl(RPC_CALL); 176 call->rp_rpcvers = htonl(RPC_VER2); 177 call->rp_prog = htonl(prog); 178 call->rp_vers = htonl(vers); 179 call->rp_proc = htonl(proc); 180 181 /* Make room for the rpc_reply header. */ 182 recv_head = rdata; 183 recv_tail = (char *)rdata + rlen; 184 recv_head -= sizeof(*reply); 185 186 cc = sendrecv(d, 187 sendudp, send_head, send_tail - send_head, 188 recvrpc, recv_head, recv_tail - recv_head); 189 190#ifdef RPC_DEBUG 191 if (debug) 192 printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen); 193#endif 194 if (cc == -1) 195 return (-1); 196 197 if (cc <= sizeof(*reply)) { 198 errno = EBADRPC; 199 return (-1); 200 } 201 202 recv_tail = recv_head + cc; 203 204 /* 205 * Check the RPC reply status. 206 * The xid, dir, astatus were already checked. 207 */ 208 reply = (struct rpc_reply *)recv_head; 209 auth = &reply->rp_u.rpu_rok.rok_auth; 210 x = ntohl(auth->authlen); 211 if (x != 0) { 212#ifdef RPC_DEBUG 213 if (debug) 214 printf("callrpc: reply auth != NULL\n"); 215#endif 216 errno = EBADRPC; 217 return(-1); 218 } 219 x = ntohl(reply->rp_u.rpu_rok.rok_status); 220 if (x != 0) { 221 printf("callrpc: error = %ld\n", (long)x); 222 errno = EBADRPC; 223 return(-1); 224 } 225 recv_head += sizeof(*reply); 226 227 return (ssize_t)(recv_tail - recv_head); 228} 229 230/* 231 * Returns true if packet is the one we're waiting for. 232 * This just checks the XID, direction, acceptance. 233 * Remaining checks are done by callrpc 234 */ 235static ssize_t 236recvrpc(d, pkt, len, tleft) 237 register struct iodesc *d; 238 register void *pkt; 239 register size_t len; 240 time_t tleft; 241{ 242 register struct rpc_reply *reply; 243 ssize_t n; 244 int x; 245 246 errno = 0; 247#ifdef RPC_DEBUG 248 if (debug) 249 printf("recvrpc: called len=%lu\n", (u_long)len); 250#endif 251 252 n = readudp(d, pkt, len, tleft); 253 if (n <= (4 * 4)) 254 return -1; 255 256 reply = (struct rpc_reply *)pkt; 257 258 x = ntohl(reply->rp_xid); 259 if (x != rpc_xid) { 260#ifdef RPC_DEBUG 261 if (debug) 262 printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); 263#endif 264 return -1; 265 } 266 267 x = ntohl(reply->rp_direction); 268 if (x != RPC_REPLY) { 269#ifdef RPC_DEBUG 270 if (debug) 271 printf("recvrpc: rp_direction %d != REPLY\n", x); 272#endif 273 return -1; 274 } 275 276 x = ntohl(reply->rp_astatus); 277 if (x != RPC_MSGACCEPTED) { 278 errno = ntohl(reply->rp_u.rpu_errno); 279 printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); 280 return -1; 281 } 282 283 /* Return data count (thus indicating success) */ 284 return (n); 285} 286 287/* 288 * Given a pointer to a reply just received, 289 * dig out the IP address/port from the headers. 290 */ 291void 292rpc_fromaddr(pkt, addr, port) 293 void *pkt; 294 struct in_addr *addr; 295 u_short *port; 296{ 297 struct hackhdr { 298 /* Tail of IP header: just IP addresses */ 299 n_long ip_src; 300 n_long ip_dst; 301 /* UDP header: */ 302 u_int16_t uh_sport; /* source port */ 303 u_int16_t uh_dport; /* destination port */ 304 int16_t uh_ulen; /* udp length */ 305 u_int16_t uh_sum; /* udp checksum */ 306 /* RPC reply header: */ 307 struct rpc_reply rpc; 308 } *hhdr; 309 310 hhdr = ((struct hackhdr *)pkt) - 1; 311 addr->s_addr = hhdr->ip_src; 312 *port = hhdr->uh_sport; 313} 314 315/* 316 * RPC Portmapper cache 317 */ 318#define PMAP_NUM 8 /* need at most 5 pmap entries */ 319 320int rpc_pmap_num; 321struct pmap_list { 322 struct in_addr addr; /* server, net order */ 323 u_int prog; /* host order */ 324 u_int vers; /* host order */ 325 int port; /* host order */ 326} rpc_pmap_list[PMAP_NUM]; 327 328/* return port number in host order, or -1 */ 329int 330rpc_pmap_getcache(addr, prog, vers) 331 struct in_addr addr; /* server, net order */ 332 u_int prog; /* host order */ 333 u_int vers; /* host order */ 334{ 335 struct pmap_list *pl; 336 337 for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { 338 if (pl->addr.s_addr == addr.s_addr && 339 pl->prog == prog && pl->vers == vers ) 340 { 341 return (pl->port); 342 } 343 } 344 return (-1); 345} 346 347void 348rpc_pmap_putcache(addr, prog, vers, port) 349 struct in_addr addr; /* server, net order */ 350 u_int prog; /* host order */ 351 u_int vers; /* host order */ 352 int port; /* host order */ 353{ 354 struct pmap_list *pl; 355 356 /* Don't overflow cache... */ 357 if (rpc_pmap_num >= PMAP_NUM) { 358 /* ... just re-use the last entry. */ 359 rpc_pmap_num = PMAP_NUM - 1; 360#ifdef RPC_DEBUG 361 printf("rpc_pmap_putcache: cache overflow\n"); 362#endif 363 } 364 365 pl = &rpc_pmap_list[rpc_pmap_num]; 366 rpc_pmap_num++; 367 368 /* Cache answer */ 369 pl->addr = addr; 370 pl->prog = prog; 371 pl->vers = vers; 372 pl->port = port; 373} 374 375 376/* 377 * Request a port number from the port mapper. 378 * Returns the port in host order. 379 */ 380int 381rpc_getport(d, prog, vers) 382 register struct iodesc *d; 383 n_long prog; /* host order */ 384 n_long vers; /* host order */ 385{ 386 struct args { 387 n_long prog; /* call program */ 388 n_long vers; /* call version */ 389 n_long proto; /* call protocol */ 390 n_long port; /* call port (unused) */ 391 } *args; 392 struct res { 393 n_long port; 394 } *res; 395 struct { 396 n_long h[RPC_HEADER_WORDS]; 397 struct args d; 398 } sdata; 399 struct { 400 n_long h[RPC_HEADER_WORDS]; 401 struct res d; 402 n_long pad; 403 } rdata; 404 ssize_t cc; 405 int port; 406 407#ifdef RPC_DEBUG 408 if (debug) 409 printf("getport: prog=0x%x vers=%d\n", prog, vers); 410#endif 411 412 /* This one is fixed forever. */ 413 if (prog == PMAPPROG) 414 return (PMAPPORT); 415 416 /* Try for cached answer first */ 417 port = rpc_pmap_getcache(d->destip, prog, vers); 418 if (port != -1) 419 return (port); 420 421 args = &sdata.d; 422 args->prog = htonl(prog); 423 args->vers = htonl(vers); 424 args->proto = htonl(IPPROTO_UDP); 425 args->port = 0; 426 res = &rdata.d; 427 428 cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 429 args, sizeof(*args), res, sizeof(*res)); 430 if (cc < sizeof(*res)) { 431 printf("getport: %s", strerror(errno)); 432 errno = EBADRPC; 433 return (-1); 434 } 435 port = (int)ntohl(res->port); 436 437 rpc_pmap_putcache(d->destip, prog, vers, port); 438 439 return (port); 440} 441