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