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