1 /* 2 * Copyright (c) 1989 Jan-Simon Pendry 3 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry at Imperial College, London. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * from: @(#)rpc_fwd.c 8.1 (Berkeley) 6/6/93 35 * $Id: rpc_fwd.c,v 1.11 2019/06/28 13:32:46 deraadt Exp $ 36 */ 37 38 /* 39 * RPC packet forwarding 40 */ 41 42 #include "am.h" 43 #include <sys/ioctl.h> 44 45 /* 46 * Note that the ID field in the external packet is only 47 * ever treated as a 32 bit opaque data object, so there 48 * is no need to convert to and from network byte ordering. 49 */ 50 51 /* 52 * Each pending reply has an rpc_forward structure 53 * associated with it. These have a 15 second lifespan. 54 * If a new structure is required, then an expired 55 * one will be re-allocated if available, otherwise a fresh 56 * one is allocated. Whenever a reply is received the 57 * structure is discarded. 58 */ 59 typedef struct rpc_forward rpc_forward; 60 struct rpc_forward { 61 qelem rf_q; /* Linked list */ 62 time_t rf_ttl; /* Time to live */ 63 u_int rf_xid; /* Packet id */ 64 u_int rf_oldid; /* Original packet id */ 65 fwd_fun rf_fwd; /* Forwarding function */ 66 void * rf_ptr; 67 struct sockaddr_in rf_sin; 68 }; 69 70 /* 71 * Head of list of pending replies 72 */ 73 extern qelem rpc_head; 74 qelem rpc_head = { &rpc_head, &rpc_head }; 75 76 static u_int xid; 77 #define XID_ALLOC() (xid++) 78 79 #define MAX_PACKET_SIZE 8192 /* Maximum UDP packet size */ 80 81 int fwd_sock; 82 83 /* 84 * Allocate a rely structure 85 */ 86 static rpc_forward * 87 fwd_alloc() 88 { 89 time_t now = clocktime(); 90 rpc_forward *p = 0, *p2; 91 92 #ifdef DEBUG 93 /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/ 94 #endif /* DEBUG */ 95 /* 96 * First search for an existing expired one. 97 */ 98 ITER(p2, rpc_forward, &rpc_head) { 99 if (p2->rf_ttl <= now) { 100 p = p2; 101 break; 102 } 103 } 104 105 /* 106 * If one couldn't be found then allocate 107 * a new structure and link it at the 108 * head of the list. 109 */ 110 if (p) { 111 /* 112 * Call forwarding function to say that 113 * this message was junked. 114 */ 115 #ifdef DEBUG 116 dlog("Re-using packet forwarding slot - id %#x", p->rf_xid); 117 #endif /* DEBUG */ 118 if (p->rf_fwd) 119 (*p->rf_fwd)(0, 0, 0, &p->rf_sin, p->rf_ptr, FALSE); 120 rem_que(&p->rf_q); 121 } else { 122 p = ALLOC(rpc_forward); 123 } 124 ins_que(&p->rf_q, &rpc_head); 125 126 /* 127 * Set the time to live field 128 * Timeout in 43 seconds 129 */ 130 p->rf_ttl = now + 43; 131 132 #ifdef DEBUG 133 /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/ 134 #endif /* DEBUG */ 135 return p; 136 } 137 138 /* 139 * Free an allocated reply structure. 140 * First unlink it from the list, then 141 * discard it. 142 */ 143 static void 144 fwd_free(rpc_forward *p) 145 { 146 #ifdef DEBUG 147 /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/ 148 #endif /* DEBUG */ 149 rem_que(&p->rf_q); 150 #ifdef DEBUG 151 /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/ 152 #endif /* DEBUG */ 153 free(p); 154 } 155 156 /* 157 * Initialise the RPC forwarder 158 */ 159 int fwd_init() 160 { 161 /* 162 * Create ping socket 163 */ 164 fwd_sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); 165 if (fwd_sock == -1) { 166 plog(XLOG_ERROR, "Unable to create RPC forwarding socket: %m"); 167 return errno; 168 } 169 170 /* 171 * Some things we talk to require a priv port - so make one here 172 */ 173 if (bind_resv_port(fwd_sock, (unsigned short *) 0) == -1) 174 plog(XLOG_ERROR, "can't bind privileged port"); 175 176 return 0; 177 } 178 179 /* 180 * Locate a packet in the forwarding list 181 */ 182 static rpc_forward * 183 fwd_locate(u_int id) 184 { 185 rpc_forward *p; 186 187 ITER(p, rpc_forward, &rpc_head) { 188 if (p->rf_xid == id) 189 return p; 190 } 191 192 return 0; 193 } 194 195 /* 196 * This is called to forward a packet to another 197 * RPC server. The message id is changed and noted 198 * so that when a reply appears we can tie it up 199 * correctly. Just matching the reply's source address 200 * would not work because it might come from a 201 * different address. 202 */ 203 int 204 fwd_packet(int type_id, void *pkt, int len, struct sockaddr_in *fwdto, 205 struct sockaddr_in *replyto, void *i, fwd_fun cb) 206 { 207 rpc_forward *p; 208 u_int *pkt_int; 209 int error; 210 211 if ((int)amd_state >= (int)Finishing) 212 return ENOENT; 213 214 /* 215 * See if the type_id is fully specified. 216 * If so, then discard any old entries 217 * for this id. 218 * Otherwise make sure the type_id is 219 * fully qualified by allocating an id here. 220 */ 221 #ifdef DEBUG 222 switch (type_id & RPC_XID_MASK) { 223 case RPC_XID_PORTMAP: dlog("Sending PORTMAP request"); break; 224 case RPC_XID_MOUNTD: dlog("Sending MOUNTD request %#x", type_id); break; 225 case RPC_XID_NFSPING: dlog("Sending NFS ping"); break; 226 default: dlog("UNKNOWN RPC XID"); break; 227 } 228 #endif /* DEBUG */ 229 230 if (type_id & ~RPC_XID_MASK) { 231 #ifdef DEBUG 232 /*dlog("Fully qualified rpc type provided");*/ 233 #endif /* DEBUG */ 234 p = fwd_locate(type_id); 235 if (p) { 236 #ifdef DEBUG 237 dlog("Discarding earlier rpc fwd handle"); 238 #endif /* DEBUG */ 239 fwd_free(p); 240 } 241 } else { 242 #ifdef DEBUG 243 dlog("Allocating a new xid..."); 244 #endif /* DEBUG */ 245 type_id = MK_RPC_XID(type_id, XID_ALLOC()); 246 } 247 248 p = fwd_alloc(); 249 if (!p) 250 return ENOBUFS; 251 252 error = 0; 253 254 pkt_int = (u_int *) pkt; 255 256 /* 257 * Get the original packet id 258 */ 259 p->rf_oldid = *pkt_int; 260 261 /* 262 * Replace with newly allocated id 263 */ 264 p->rf_xid = *pkt_int = type_id; 265 266 /* 267 * The sendto may fail if, for example, the route 268 * to a remote host is lost because an intermediate 269 * gateway has gone down. Important to fill in the 270 * rest of "p" otherwise nasty things happen later... 271 */ 272 #ifdef DEBUG 273 { char dq[20]; 274 275 dlog("Sending packet id %#x to %s.%d", p->rf_xid, 276 inet_dquad(dq, sizeof(dq), fwdto->sin_addr.s_addr), 277 ntohs(fwdto->sin_port)); 278 } 279 #endif /* DEBUG */ 280 if (sendto(fwd_sock, (char *) pkt, len, 0, 281 (struct sockaddr *) fwdto, sizeof(*fwdto)) == -1) 282 error = errno; 283 284 /* 285 * Save callback function and return address 286 */ 287 p->rf_fwd = cb; 288 if (replyto) 289 p->rf_sin = *replyto; 290 else 291 bzero(&p->rf_sin, sizeof(p->rf_sin)); 292 p->rf_ptr = i; 293 294 return error; 295 } 296 297 /* 298 * Called when some data arrives on the forwarding socket 299 */ 300 void 301 fwd_reply() 302 { 303 int len; 304 #ifdef DYNAMIC_BUFFERS 305 void *pkt; 306 #else 307 u_int pkt[MAX_PACKET_SIZE/sizeof(u_int)+1]; 308 #endif /* DYNAMIC_BUFFERS */ 309 u_int *pkt_int; 310 int rc; 311 rpc_forward *p; 312 struct sockaddr_in src_addr; 313 socklen_t src_addr_len; 314 315 /* 316 * Determine the length of the packet 317 */ 318 #ifdef DYNAMIC_BUFFERS 319 if (ioctl(fwd_sock, FIONREAD, &len) == -1 || len < 0) { 320 plog(XLOG_ERROR, "Error reading packet size: %m"); 321 return; 322 } 323 324 /* 325 * Allocate a buffer 326 */ 327 pkt = malloc(len); 328 if (!pkt) { 329 plog(XLOG_ERROR, "Out of buffers in fwd_reply"); 330 return; 331 } 332 #else 333 len = MAX_PACKET_SIZE; 334 #endif /* DYNAMIC_BUFFERS */ 335 336 /* 337 * Read the packet and check for validity 338 */ 339 again: 340 src_addr_len = sizeof(src_addr); 341 rc = recvfrom(fwd_sock, (char *) pkt, len, 0, 342 (struct sockaddr *) &src_addr, &src_addr_len); 343 if (rc == -1 || src_addr_len != sizeof(src_addr) || 344 src_addr.sin_family != AF_INET) { 345 if (rc == -1 && errno == EINTR) 346 goto again; 347 plog(XLOG_ERROR, "Error reading RPC reply: %m"); 348 goto out; 349 } 350 351 #ifdef DYNAMIC_BUFFERS 352 if (rc != len) { 353 plog(XLOG_ERROR, "Short read in fwd_reply"); 354 goto out; 355 } 356 #endif /* DYNAMIC_BUFFERS */ 357 358 /* 359 * Do no more work if finishing soon 360 */ 361 if ((int)amd_state >= (int)Finishing) 362 goto out; 363 364 /* 365 * Find packet reference 366 */ 367 pkt_int = (u_int *) pkt; 368 369 #ifdef DEBUG 370 switch (*pkt_int & RPC_XID_MASK) { 371 case RPC_XID_PORTMAP: dlog("Receiving PORTMAP reply"); break; 372 case RPC_XID_MOUNTD: dlog("Receiving MOUNTD reply %#x", *pkt_int); break; 373 case RPC_XID_NFSPING: dlog("Receiving NFS ping %#x", *pkt_int); break; 374 default: dlog("UNKNOWN RPC XID"); break; 375 } 376 #endif /* DEBUG */ 377 378 p = fwd_locate(*pkt_int); 379 if (!p) { 380 #ifdef DEBUG 381 dlog("Can't forward reply id %#x", *pkt_int); 382 #endif /* DEBUG */ 383 goto out; 384 } 385 386 if (p->rf_fwd) { 387 /* 388 * Put the original message id back 389 * into the packet. 390 */ 391 *pkt_int = p->rf_oldid; 392 393 /* 394 * Call forwarding function 395 */ 396 (*p->rf_fwd)(pkt, rc, &src_addr, &p->rf_sin, p->rf_ptr, TRUE); 397 } 398 399 /* 400 * Free forwarding info 401 */ 402 fwd_free(p); 403 404 out:; 405 #ifdef DYNAMIC_BUFFERS 406 /* 407 * Free the packet 408 */ 409 free(pkt); 410 #endif /* DYNAMIC_BUFFERS */ 411 } 412