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