1 /* $NetBSD: rpc.c,v 1.25 2006/01/21 10:06:06 dsl 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 #ifdef _STANDALONE 57 #include <lib/libkern/libkern.h> 58 #include "stand.h" 59 #else 60 #include <string.h> 61 #include <errno.h> 62 #include <stdio.h> 63 #endif 64 65 #include "rpcv2.h" 66 67 #include "net.h" 68 #include "rpc.h" 69 70 struct auth_info { 71 int32_t authtype; /* auth type */ 72 u_int32_t authlen; /* auth length */ 73 }; 74 75 struct auth_unix { 76 int32_t ua_time; 77 int32_t ua_hostname; /* null */ 78 int32_t ua_uid; 79 int32_t ua_gid; 80 int32_t ua_gidlist; /* null */ 81 }; 82 83 struct rpc_call { 84 u_int32_t rp_xid; /* request transaction id */ 85 int32_t rp_direction; /* call direction (0) */ 86 u_int32_t rp_rpcvers; /* rpc version (2) */ 87 u_int32_t rp_prog; /* program */ 88 u_int32_t rp_vers; /* version */ 89 u_int32_t rp_proc; /* procedure */ 90 }; 91 92 struct rpc_reply { 93 u_int32_t rp_xid; /* request transaction id */ 94 int32_t rp_direction; /* call direction (1) */ 95 int32_t rp_astatus; /* accept status (0: accepted) */ 96 union { 97 u_int32_t rpu_errno; 98 struct { 99 struct auth_info rok_auth; 100 u_int32_t rok_status; 101 } rpu_rok; 102 } rp_u; 103 }; 104 105 /* Local forwards */ 106 static ssize_t recvrpc __P((struct iodesc *, void *, size_t, time_t)); 107 108 int rpc_xid; 109 int rpc_port = 0x400; /* predecrement */ 110 111 /* 112 * Make a rpc call; return length of answer 113 * Note: Caller must leave room for headers. 114 */ 115 ssize_t 116 rpc_call(d, prog, vers, proc, sdata, slen, rdata, rlen) 117 struct iodesc *d; 118 n_long prog, vers, proc; 119 void *sdata; 120 size_t slen; 121 void *rdata; 122 size_t rlen; 123 { 124 ssize_t cc; 125 struct auth_info *auth; 126 struct rpc_call *call; 127 struct rpc_reply *reply; 128 char *send_head, *send_tail; 129 char *recv_head, *recv_tail; 130 n_long x; 131 int port; /* host order */ 132 133 #ifdef RPC_DEBUG 134 if (debug) 135 printf("rpc_call: prog=0x%x vers=%d proc=%d\n", 136 prog, vers, proc); 137 #endif 138 139 port = rpc_getport(d, prog, vers); 140 if (port == -1) 141 return (-1); 142 143 d->destport = htons(port); 144 145 /* 146 * Prepend authorization stuff and headers. 147 * Note, must prepend things in reverse order. 148 */ 149 send_head = sdata; 150 send_tail = (char *)sdata + slen; 151 152 /* Auth verifier is always auth_null */ 153 send_head -= sizeof(*auth); 154 auth = (struct auth_info *)send_head; 155 auth->authtype = htonl(RPCAUTH_NULL); 156 auth->authlen = 0; 157 158 #if 1 159 /* Auth credentials: always auth unix (as root) */ 160 send_head -= sizeof(struct auth_unix); 161 bzero(send_head, sizeof(struct auth_unix)); 162 send_head -= sizeof(*auth); 163 auth = (struct auth_info *)send_head; 164 auth->authtype = htonl(RPCAUTH_UNIX); 165 auth->authlen = htonl(sizeof(struct auth_unix)); 166 #else 167 /* Auth credentials: always auth_null (XXX OK?) */ 168 send_head -= sizeof(*auth); 169 auth = send_head; 170 auth->authtype = htonl(RPCAUTH_NULL); 171 auth->authlen = 0; 172 #endif 173 174 /* RPC call structure. */ 175 send_head -= sizeof(*call); 176 call = (struct rpc_call *)send_head; 177 rpc_xid++; 178 call->rp_xid = htonl(rpc_xid); 179 call->rp_direction = htonl(RPC_CALL); 180 call->rp_rpcvers = htonl(RPC_VER2); 181 call->rp_prog = htonl(prog); 182 call->rp_vers = htonl(vers); 183 call->rp_proc = htonl(proc); 184 185 /* Make room for the rpc_reply header. */ 186 recv_head = rdata; 187 recv_tail = (char *)rdata + rlen; 188 recv_head -= sizeof(*reply); 189 190 cc = sendrecv(d, 191 sendudp, send_head, send_tail - send_head, 192 recvrpc, recv_head, recv_tail - recv_head); 193 194 #ifdef RPC_DEBUG 195 if (debug) 196 printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen); 197 #endif 198 if (cc == -1) 199 return (-1); 200 201 if ((size_t)cc <= sizeof(*reply)) { 202 errno = EBADRPC; 203 return (-1); 204 } 205 206 recv_tail = recv_head + cc; 207 208 /* 209 * Check the RPC reply status. 210 * The xid, dir, astatus were already checked. 211 */ 212 reply = (struct rpc_reply *)recv_head; 213 auth = &reply->rp_u.rpu_rok.rok_auth; 214 x = ntohl(auth->authlen); 215 if (x != 0) { 216 #ifdef RPC_DEBUG 217 if (debug) 218 printf("callrpc: reply auth != NULL\n"); 219 #endif 220 errno = EBADRPC; 221 return(-1); 222 } 223 x = ntohl(reply->rp_u.rpu_rok.rok_status); 224 if (x != 0) { 225 printf("callrpc: error = %d\n", x); 226 errno = EBADRPC; 227 return(-1); 228 } 229 recv_head += sizeof(*reply); 230 231 return (ssize_t)(recv_tail - recv_head); 232 } 233 234 /* 235 * Returns true if packet is the one we're waiting for. 236 * This just checks the XID, direction, acceptance. 237 * Remaining checks are done by callrpc 238 */ 239 static ssize_t 240 recvrpc(d, pkt, len, tleft) 241 struct iodesc *d; 242 void *pkt; 243 size_t len; 244 time_t tleft; 245 { 246 struct rpc_reply *reply; 247 ssize_t n; 248 int x; 249 250 errno = 0; 251 #ifdef RPC_DEBUG 252 if (debug) 253 printf("recvrpc: called len=%lu\n", (u_long)len); 254 #endif 255 256 n = readudp(d, pkt, len, tleft); 257 if (n <= (4 * 4)) 258 return -1; 259 260 reply = (struct rpc_reply *)pkt; 261 262 x = ntohl(reply->rp_xid); 263 if (x != rpc_xid) { 264 #ifdef RPC_DEBUG 265 if (debug) 266 printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); 267 #endif 268 return -1; 269 } 270 271 x = ntohl(reply->rp_direction); 272 if (x != RPC_REPLY) { 273 #ifdef RPC_DEBUG 274 if (debug) 275 printf("recvrpc: rp_direction %d != REPLY\n", x); 276 #endif 277 return -1; 278 } 279 280 x = ntohl(reply->rp_astatus); 281 if (x != RPC_MSGACCEPTED) { 282 errno = ntohl(reply->rp_u.rpu_errno); 283 printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); 284 return -1; 285 } 286 287 /* Return data count (thus indicating success) */ 288 return (n); 289 } 290 291 /* 292 * Given a pointer to a reply just received, 293 * dig out the IP address/port from the headers. 294 */ 295 void 296 rpc_fromaddr(pkt, addr, port) 297 void *pkt; 298 struct in_addr *addr; 299 u_short *port; 300 { 301 struct hackhdr { 302 /* Tail of IP header: just IP addresses */ 303 n_long ip_src; 304 n_long ip_dst; 305 /* UDP header: */ 306 u_int16_t uh_sport; /* source port */ 307 u_int16_t uh_dport; /* destination port */ 308 int16_t uh_ulen; /* udp length */ 309 u_int16_t uh_sum; /* udp checksum */ 310 /* RPC reply header: */ 311 struct rpc_reply rpc; 312 } *hhdr; 313 314 hhdr = ((struct hackhdr *)pkt) - 1; 315 addr->s_addr = hhdr->ip_src; 316 *port = hhdr->uh_sport; 317 } 318 319 #ifdef NO_PMAP_CACHE 320 #define rpc_pmap_getcache(addr, prog, vers) (-1) 321 #define rpc_pmap_putcache(addr, prog, vers, port) 322 #else 323 324 /* 325 * RPC Portmapper cache 326 */ 327 #define PMAP_NUM 8 /* need at most 5 pmap entries */ 328 329 int rpc_pmap_num; 330 struct pmap_list { 331 struct in_addr addr; /* server, net order */ 332 u_int prog; /* host order */ 333 u_int vers; /* host order */ 334 int port; /* host order */ 335 } rpc_pmap_list[PMAP_NUM]; 336 337 /* return port number in host order, or -1 */ 338 int 339 rpc_pmap_getcache(addr, prog, vers) 340 struct in_addr addr; /* server, net order */ 341 u_int prog; /* host order */ 342 u_int vers; /* host order */ 343 { 344 struct pmap_list *pl; 345 346 for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { 347 if (pl->addr.s_addr == addr.s_addr && 348 pl->prog == prog && pl->vers == vers ) 349 { 350 return (pl->port); 351 } 352 } 353 return (-1); 354 } 355 356 void 357 rpc_pmap_putcache(addr, prog, vers, port) 358 struct in_addr addr; /* server, net order */ 359 u_int prog; /* host order */ 360 u_int vers; /* host order */ 361 int port; /* host order */ 362 { 363 struct pmap_list *pl; 364 365 /* Don't overflow cache... */ 366 if (rpc_pmap_num >= PMAP_NUM) { 367 /* ... just re-use the last entry. */ 368 rpc_pmap_num = PMAP_NUM - 1; 369 #ifdef RPC_DEBUG 370 printf("rpc_pmap_putcache: cache overflow\n"); 371 #endif 372 } 373 374 pl = &rpc_pmap_list[rpc_pmap_num]; 375 rpc_pmap_num++; 376 377 /* Cache answer */ 378 pl->addr = addr; 379 pl->prog = prog; 380 pl->vers = vers; 381 pl->port = port; 382 } 383 #endif 384 385 /* 386 * Request a port number from the port mapper. 387 * Returns the port in host order. 388 */ 389 int 390 rpc_getport(d, prog, vers) 391 struct iodesc *d; 392 n_long prog; /* host order */ 393 n_long vers; /* host order */ 394 { 395 struct args { 396 n_long prog; /* call program */ 397 n_long vers; /* call version */ 398 n_long proto; /* call protocol */ 399 n_long port; /* call port (unused) */ 400 } *args; 401 struct res { 402 n_long port; 403 } *res; 404 struct { 405 n_long h[RPC_HEADER_WORDS]; 406 struct args d; 407 } sdata; 408 struct { 409 n_long h[RPC_HEADER_WORDS]; 410 struct res d; 411 n_long pad; 412 } rdata; 413 ssize_t cc; 414 int port; 415 416 #ifdef RPC_DEBUG 417 if (debug) 418 printf("getport: prog=0x%x vers=%d\n", prog, vers); 419 #endif 420 421 /* This one is fixed forever. */ 422 if (prog == PMAPPROG) 423 return (PMAPPORT); 424 425 /* Try for cached answer first */ 426 port = rpc_pmap_getcache(d->destip, prog, vers); 427 if (port != -1) 428 return (port); 429 430 args = &sdata.d; 431 args->prog = htonl(prog); 432 args->vers = htonl(vers); 433 args->proto = htonl(IPPROTO_UDP); 434 args->port = 0; 435 res = &rdata.d; 436 437 cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 438 args, sizeof(*args), res, sizeof(*res)); 439 if ((size_t)cc < sizeof(*res)) { 440 printf("getport: %s", strerror(errno)); 441 errno = EBADRPC; 442 return (-1); 443 } 444 port = (int)ntohl(res->port); 445 446 rpc_pmap_putcache(d->destip, prog, vers, port); 447 448 return (port); 449 } 450