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