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