1 /* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */ 2 /* $DragonFly: src/lib/libstand/rpc.c,v 1.3 2005/12/11 02:27:26 swildner 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. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 37 */ 38 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 u_int32_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 u_int32_t rp_xid; /* request transaction id */ 77 int32_t rp_direction; /* call direction (0) */ 78 u_int32_t rp_rpcvers; /* rpc version (2) */ 79 u_int32_t rp_prog; /* program */ 80 u_int32_t rp_vers; /* version */ 81 u_int32_t rp_proc; /* procedure */ 82 }; 83 84 struct rpc_reply { 85 u_int32_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 u_int32_t rpu_errno; 90 struct { 91 struct auth_info rok_auth; 92 u_int32_t rok_status; 93 } rpu_rok; 94 } rp_u; 95 }; 96 97 /* Local forwards */ 98 static ssize_t recvrpc(struct iodesc *, void *, size_t, time_t); 99 static int rpc_getport(struct iodesc *, n_long, n_long); 100 101 int rpc_xid; 102 static int rpc_port = 0x400; 103 104 int 105 rpc_newport(void) 106 { 107 if (rpc_port <= 256) /* recycle after a while */ 108 rpc_port = 0x400; 109 return (--rpc_port); 110 } 111 112 /* 113 * Make a rpc call; return length of answer 114 * Note: Caller must leave room for headers. 115 */ 116 ssize_t 117 rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, void *sdata, 118 size_t slen, void *rdata, size_t rlen) 119 { 120 ssize_t cc; 121 struct auth_info *auth; 122 struct rpc_call *call; 123 struct rpc_reply *reply; 124 char *send_head, *send_tail; 125 char *recv_head, *recv_tail; 126 n_long x; 127 int port; /* host order */ 128 129 #ifdef RPC_DEBUG 130 if (debug) 131 printf("rpc_call: prog=0x%x vers=%d proc=%d\n", 132 prog, vers, proc); 133 #endif 134 135 port = rpc_getport(d, prog, vers); 136 if (port == -1) 137 return (-1); 138 139 d->destport = htons(port); 140 141 /* 142 * Prepend authorization stuff and headers. 143 * Note, must prepend things in reverse order. 144 */ 145 send_head = sdata; 146 send_tail = (char *)sdata + slen; 147 148 /* Auth verifier is always auth_null */ 149 send_head -= sizeof(*auth); 150 auth = (struct auth_info *)send_head; 151 auth->authtype = htonl(RPCAUTH_NULL); 152 auth->authlen = 0; 153 154 #if 1 155 /* Auth credentials: always auth unix (as root) */ 156 send_head -= sizeof(struct auth_unix); 157 bzero(send_head, sizeof(struct auth_unix)); 158 send_head -= sizeof(*auth); 159 auth = (struct auth_info *)send_head; 160 auth->authtype = htonl(RPCAUTH_UNIX); 161 auth->authlen = htonl(sizeof(struct auth_unix)); 162 #else 163 /* Auth credentials: always auth_null (XXX OK?) */ 164 send_head -= sizeof(*auth); 165 auth = send_head; 166 auth->authtype = htonl(RPCAUTH_NULL); 167 auth->authlen = 0; 168 #endif 169 170 /* RPC call structure. */ 171 send_head -= sizeof(*call); 172 call = (struct rpc_call *)send_head; 173 rpc_xid++; 174 call->rp_xid = htonl(rpc_xid); 175 call->rp_direction = htonl(RPC_CALL); 176 call->rp_rpcvers = htonl(RPC_VER2); 177 call->rp_prog = htonl(prog); 178 call->rp_vers = htonl(vers); 179 call->rp_proc = htonl(proc); 180 181 /* Make room for the rpc_reply header. */ 182 recv_head = rdata; 183 recv_tail = (char *)rdata + rlen; 184 recv_head -= sizeof(*reply); 185 186 cc = sendrecv(d, 187 sendudp, send_head, send_tail - send_head, 188 recvrpc, recv_head, recv_tail - recv_head); 189 190 #ifdef RPC_DEBUG 191 if (debug) 192 printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen); 193 #endif 194 if (cc == -1) 195 return (-1); 196 197 if (cc <= sizeof(*reply)) { 198 errno = EBADRPC; 199 return (-1); 200 } 201 202 recv_tail = recv_head + cc; 203 204 /* 205 * Check the RPC reply status. 206 * The xid, dir, astatus were already checked. 207 */ 208 reply = (struct rpc_reply *)recv_head; 209 auth = &reply->rp_u.rpu_rok.rok_auth; 210 x = ntohl(auth->authlen); 211 if (x != 0) { 212 #ifdef RPC_DEBUG 213 if (debug) 214 printf("callrpc: reply auth != NULL\n"); 215 #endif 216 errno = EBADRPC; 217 return(-1); 218 } 219 x = ntohl(reply->rp_u.rpu_rok.rok_status); 220 if (x != 0) { 221 printf("callrpc: error = %ld\n", (long)x); 222 errno = EBADRPC; 223 return(-1); 224 } 225 recv_head += sizeof(*reply); 226 227 return (ssize_t)(recv_tail - recv_head); 228 } 229 230 /* 231 * Returns true if packet is the one we're waiting for. 232 * This just checks the XID, direction, acceptance. 233 * Remaining checks are done by callrpc 234 */ 235 static ssize_t 236 recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft) 237 { 238 struct rpc_reply *reply; 239 ssize_t n; 240 int x; 241 242 errno = 0; 243 #ifdef RPC_DEBUG 244 if (debug) 245 printf("recvrpc: called len=%lu\n", (u_long)len); 246 #endif 247 248 n = readudp(d, pkt, len, tleft); 249 if (n <= (4 * 4)) 250 return -1; 251 252 reply = (struct rpc_reply *)pkt; 253 254 x = ntohl(reply->rp_xid); 255 if (x != rpc_xid) { 256 #ifdef RPC_DEBUG 257 if (debug) 258 printf("recvrpc: rp_xid %d != xid %d\n", 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("recvrpc: rp_direction %d != REPLY\n", 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("recvrpc: reject, astat=%d, errno=%d\n", 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 /* 309 * RPC Portmapper cache 310 */ 311 #define PMAP_NUM 8 /* need at most 5 pmap entries */ 312 313 int rpc_pmap_num; 314 struct pmap_list { 315 struct in_addr addr; /* server, net order */ 316 u_int prog; /* host order */ 317 u_int vers; /* host order */ 318 int port; /* host order */ 319 } rpc_pmap_list[PMAP_NUM]; 320 321 /* 322 * return port number in host order, or -1 323 * 324 * Parameters: 325 * addr: server, net order 326 * prog: host order 327 * vers: host order 328 */ 329 int 330 rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) 331 { 332 struct pmap_list *pl; 333 334 for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { 335 if (pl->addr.s_addr == addr.s_addr && 336 pl->prog == prog && pl->vers == vers ) 337 { 338 return (pl->port); 339 } 340 } 341 return (-1); 342 } 343 344 /* 345 * Parameters: 346 * addr: server, net order 347 * prog: host order 348 * vers: host order 349 * port: host order 350 */ 351 void 352 rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) 353 { 354 struct pmap_list *pl; 355 356 /* Don't overflow cache... */ 357 if (rpc_pmap_num >= PMAP_NUM) { 358 /* ... just re-use the last entry. */ 359 rpc_pmap_num = PMAP_NUM - 1; 360 #ifdef RPC_DEBUG 361 printf("rpc_pmap_putcache: cache overflow\n"); 362 #endif 363 } 364 365 pl = &rpc_pmap_list[rpc_pmap_num]; 366 rpc_pmap_num++; 367 368 /* Cache answer */ 369 pl->addr = addr; 370 pl->prog = prog; 371 pl->vers = vers; 372 pl->port = port; 373 } 374 375 376 /* 377 * Request a port number from the port mapper. 378 * Returns the port in host order. 379 * 380 * Parameters: 381 * prog: host order 382 * vers: host order 383 */ 384 int 385 rpc_getport(struct iodesc *d, n_long prog, n_long vers) 386 { 387 struct args { 388 n_long prog; /* call program */ 389 n_long vers; /* call version */ 390 n_long proto; /* call protocol */ 391 n_long port; /* call port (unused) */ 392 } *args; 393 struct res { 394 n_long port; 395 } *res; 396 struct { 397 n_long h[RPC_HEADER_WORDS]; 398 struct args d; 399 } sdata; 400 struct { 401 n_long h[RPC_HEADER_WORDS]; 402 struct res d; 403 n_long pad; 404 } rdata; 405 ssize_t cc; 406 int port; 407 408 #ifdef RPC_DEBUG 409 if (debug) 410 printf("getport: prog=0x%x vers=%d\n", prog, vers); 411 #endif 412 413 /* This one is fixed forever. */ 414 if (prog == PMAPPROG) 415 return (PMAPPORT); 416 417 /* Try for cached answer first */ 418 port = rpc_pmap_getcache(d->destip, prog, vers); 419 if (port != -1) 420 return (port); 421 422 args = &sdata.d; 423 args->prog = htonl(prog); 424 args->vers = htonl(vers); 425 args->proto = htonl(IPPROTO_UDP); 426 args->port = 0; 427 res = &rdata.d; 428 429 cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 430 args, sizeof(*args), res, sizeof(*res)); 431 if (cc < sizeof(*res)) { 432 printf("getport: %s", strerror(errno)); 433 errno = EBADRPC; 434 return (-1); 435 } 436 port = (int)ntohl(res->port); 437 438 rpc_pmap_putcache(d->destip, prog, vers, port); 439 440 return (port); 441 } 442