1 /* $NetBSD: rpc.c,v 1.31 2019/04/05 20:09:29 christos 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(struct iodesc *, void *, size_t, saseconds_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(struct iodesc *d, n_long prog, n_long vers, n_long proc, 117 void *sdata, size_t slen, void *rdata, size_t rlen) 118 { 119 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("%s: prog=0x%x vers=%d proc=%d\n", __func__, 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 (void)memset(send_head, 0, 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("%s: cc=%zd rlen=%zu\n", __func__, cc, rlen); 192 #endif 193 if (cc == -1) 194 return -1; 195 196 if ((size_t)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("%s: reply auth != NULL\n", __func__); 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("%s: error = %d\n", __func__, 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(struct iodesc *d, void *pkt, size_t len, saseconds_t tleft) 236 { 237 struct rpc_reply *reply; 238 ssize_t n; 239 int x; 240 241 errno = 0; 242 #ifdef RPC_DEBUG 243 if (debug) 244 printf("%s: called len=%zu\n", __func__, len); 245 #endif 246 247 n = readudp(d, pkt, len, tleft); 248 if (n <= (4 * 4)) 249 return -1; 250 251 reply = (struct rpc_reply *)pkt; 252 253 x = ntohl(reply->rp_xid); 254 if (x != rpc_xid) { 255 #ifdef RPC_DEBUG 256 if (debug) 257 printf("%s: rp_xid %d != xid %d\n", 258 __func__, x, rpc_xid); 259 #endif 260 return -1; 261 } 262 263 x = ntohl(reply->rp_direction); 264 if (x != RPC_REPLY) { 265 #ifdef RPC_DEBUG 266 if (debug) 267 printf("%s: rp_direction %d != REPLY\n", __func__, x); 268 #endif 269 return -1; 270 } 271 272 x = ntohl(reply->rp_astatus); 273 if (x != RPC_MSGACCEPTED) { 274 errno = ntohl(reply->rp_u.rpu_errno); 275 printf("%s: reject, astat=%d, errno=%d\n", __func__, x, errno); 276 return -1; 277 } 278 279 /* Return data count (thus indicating success) */ 280 return n; 281 } 282 283 /* 284 * Given a pointer to a reply just received, 285 * dig out the IP address/port from the headers. 286 */ 287 void 288 rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port) 289 { 290 struct hackhdr { 291 /* Tail of IP header: just IP addresses */ 292 n_long ip_src; 293 n_long ip_dst; 294 /* UDP header: */ 295 u_int16_t uh_sport; /* source port */ 296 u_int16_t uh_dport; /* destination port */ 297 int16_t uh_ulen; /* udp length */ 298 u_int16_t uh_sum; /* udp checksum */ 299 /* RPC reply header: */ 300 struct rpc_reply rpc; 301 } *hhdr; 302 303 hhdr = ((struct hackhdr *)pkt) - 1; 304 addr->s_addr = hhdr->ip_src; 305 *port = hhdr->uh_sport; 306 } 307 308 #ifdef NO_PMAP_CACHE 309 #define rpc_pmap_getcache(addr, prog, vers) (-1) 310 #define rpc_pmap_putcache(addr, prog, vers, port) 311 #else 312 313 /* 314 * RPC Portmapper cache 315 */ 316 #define PMAP_NUM 8 /* need at most 5 pmap entries */ 317 318 int rpc_pmap_num; 319 struct pmap_list { 320 struct in_addr addr; /* server, net order */ 321 u_int prog; /* host order */ 322 u_int vers; /* host order */ 323 int port; /* host order */ 324 } rpc_pmap_list[PMAP_NUM]; 325 326 /* 327 * return port number in host order, or -1. 328 * arguments are: 329 * addr .. server, net order. 330 * prog .. host order. 331 * vers .. host order. 332 */ 333 int 334 rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) 335 { 336 struct pmap_list *pl; 337 338 for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { 339 if (pl->addr.s_addr == addr.s_addr && 340 pl->prog == prog && pl->vers == vers ) 341 { 342 return pl->port; 343 } 344 } 345 return -1; 346 } 347 348 /* 349 * arguments are: 350 * addr .. server, net order. 351 * prog .. host order. 352 * vers .. host order. 353 * port .. host order. 354 */ 355 void 356 rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) 357 { 358 struct pmap_list *pl; 359 360 /* Don't overflow cache... */ 361 if (rpc_pmap_num >= PMAP_NUM) { 362 /* ... just re-use the last entry. */ 363 rpc_pmap_num = PMAP_NUM - 1; 364 #ifdef RPC_DEBUG 365 printf("%s: cache overflow\n", __func__); 366 #endif 367 } 368 369 pl = &rpc_pmap_list[rpc_pmap_num]; 370 rpc_pmap_num++; 371 372 /* Cache answer */ 373 pl->addr = addr; 374 pl->prog = prog; 375 pl->vers = vers; 376 pl->port = port; 377 } 378 #endif 379 380 /* 381 * Request a port number from the port mapper. 382 * Returns the port in host order. 383 * prog and vers are host order. 384 */ 385 int 386 rpc_getport(struct iodesc *d, n_long prog, n_long vers) 387 { 388 struct args { 389 n_long prog; /* call program */ 390 n_long vers; /* call version */ 391 n_long proto; /* call protocol */ 392 n_long port; /* call port (unused) */ 393 } *args; 394 struct res { 395 n_long port; 396 } *res; 397 struct { 398 n_long h[RPC_HEADER_WORDS]; 399 struct args d; 400 } sdata; 401 struct { 402 n_long h[RPC_HEADER_WORDS]; 403 struct res d; 404 n_long pad; 405 } rdata; 406 ssize_t cc; 407 int port; 408 409 #ifdef RPC_DEBUG 410 if (debug) 411 printf("%s: prog=0x%x vers=%d\n", __func__, prog, vers); 412 #endif 413 414 /* This one is fixed forever. */ 415 if (prog == PMAPPROG) 416 return PMAPPORT; 417 418 /* Try for cached answer first */ 419 port = rpc_pmap_getcache(d->destip, prog, vers); 420 if (port != -1) 421 return port; 422 423 args = &sdata.d; 424 args->prog = htonl(prog); 425 args->vers = htonl(vers); 426 args->proto = htonl(IPPROTO_UDP); 427 args->port = 0; 428 res = &rdata.d; 429 430 cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 431 args, sizeof(*args), res, sizeof(*res)); 432 if ((size_t)cc < sizeof(*res)) { 433 printf("%s: %s", __func__, strerror(errno)); 434 errno = EBADRPC; 435 return -1; 436 } 437 port = (int)ntohl(res->port); 438 439 rpc_pmap_putcache(d->destip, prog, vers, port); 440 441 return port; 442 } 443