1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * This file contains a simple implementation of RPC. Standard XDR is 27 * used. 28 */ 29 30 #include <sys/sysmacros.h> 31 #include <rpc/types.h> 32 #include <errno.h> 33 #include <sys/socket.h> 34 #include <netinet/in.h> 35 #include "socket_inet.h" 36 #include "ipv4.h" 37 #include <rpc/xdr.h> 38 #include <rpc/auth.h> 39 #include <rpc/auth_sys.h> 40 #include <rpc/rpc_msg.h> 41 #include <sys/t_lock.h> 42 #include <netdb.h> 43 #include "clnt.h" 44 #include <rpc/rpc.h> 45 #include "brpc.h" 46 #include "auth_inet.h" 47 #include "pmap.h" 48 #include <sys/promif.h> 49 #include "nfs_inet.h" 50 #include <rpcsvc/nfs_prot.h> 51 #include <rpc/auth_unix.h> 52 #include <sys/salib.h> 53 #include "mac.h" 54 #include <sys/bootdebug.h> 55 56 #define dprintf if (boothowto & RB_DEBUG) printf 57 58 static struct in_addr cached_destination; 59 60 void 61 rpc_disperr(struct rpc_err *stat) 62 { 63 if (boothowto & RB_DEBUG) { 64 switch (stat->re_status) { 65 case RPC_CANTENCODEARGS: 66 printf("RPC: Can't encode arguments.\n"); 67 break; 68 case RPC_CANTDECODERES: 69 printf("RPC: Can't decode result.\n"); 70 break; 71 case RPC_CANTSEND: 72 printf("RPC: Unable to send (%s).\n", 73 strerror(errno)); 74 break; 75 case RPC_CANTRECV: 76 printf("RPC: Unable to receive (%s).\n", 77 strerror(errno)); 78 break; 79 case RPC_TIMEDOUT: 80 printf("RPC: Timed out.\n"); 81 break; 82 case RPC_VERSMISMATCH: 83 printf("RPC: Incompatible versions of RPC.\n"); 84 break; 85 case RPC_AUTHERROR: 86 printf("RPC: Authentication error:\n"); 87 switch (stat->re_why) { 88 case AUTH_BADCRED: 89 printf("remote: bogus credentials " 90 "(seal broken).\n"); 91 break; 92 case AUTH_REJECTEDCRED: 93 printf("remote: client should begin new " 94 "session.\n"); 95 break; 96 case AUTH_BADVERF: 97 printf("remote: bogus verifier " 98 "(seal broken).\n"); 99 break; 100 case AUTH_REJECTEDVERF: 101 printf("remote: verifier expired or was " 102 "replayed.\n"); 103 break; 104 case AUTH_TOOWEAK: 105 printf("remote: rejected due to security " 106 "reasons.\n"); 107 break; 108 case AUTH_INVALIDRESP: 109 printf("local: bogus response verifier.\n"); 110 break; 111 case AUTH_FAILED: 112 /* FALLTHRU */ 113 default: 114 printf("local: unknown error.\n"); 115 break; 116 } 117 break; 118 case RPC_PROGUNAVAIL: 119 printf("RPC: Program unavailable.\n"); 120 break; 121 case RPC_PROGVERSMISMATCH: 122 printf("RPC: Program/version mismatch.\n"); 123 break; 124 case RPC_PROCUNAVAIL: 125 printf("RPC: Procedure unavailable.\n"); 126 break; 127 case RPC_CANTDECODEARGS: 128 printf("RPC: Server can't decode arguments.\n"); 129 break; 130 case RPC_SYSTEMERROR: 131 printf("RPC: Remote system error.\n"); 132 break; 133 case RPC_UNKNOWNHOST: 134 printf("RPC: Unknown host.\n"); 135 break; 136 case RPC_UNKNOWNPROTO: 137 printf("RPC: Unknown protocol.\n"); 138 break; 139 case RPC_PMAPFAILURE: 140 printf("RPC: Port mapper failure.\n"); 141 break; 142 case RPC_PROGNOTREGISTERED: 143 printf("RPC: Program not registered.\n"); 144 break; 145 case RPC_FAILED: 146 printf("RPC: Failed (unspecified error).\n"); 147 break; 148 default: 149 printf("RPC: (unknown error code).\n"); 150 break; 151 } 152 } 153 } 154 155 /* 156 * rpc_hdr: sets the fields in the rpc msg header. 157 * 158 * Returns: TRUE on success, FALSE if failure. 159 */ 160 /*ARGSUSED*/ 161 static bool_t 162 rpc_hdr(XDR *xdrs, uint_t xid, rpcprog_t prog, rpcvers_t vers, rpcproc_t proc) 163 { 164 struct rpc_msg call_msg; 165 166 /* setup header */ 167 call_msg.rm_xid = xid; 168 call_msg.rm_direction = CALL; 169 call_msg.rm_call.cb_rpcvers = (rpcvers_t)RPC_MSG_VERSION; 170 call_msg.rm_call.cb_prog = prog; 171 call_msg.rm_call.cb_vers = vers; 172 173 /* xdr the header. */ 174 if (xdr_callhdr(xdrs, &call_msg) == FALSE) 175 return (FALSE); 176 else 177 return (TRUE); 178 } 179 180 /* 181 * our version of brpc_call(). We cache in portnumber in to->sin_port for 182 * your convenience. to and from addresses are taken and received in network 183 * order. 184 */ 185 enum clnt_stat 186 brpc_call( 187 rpcprog_t prog, /* rpc program number to call. */ 188 rpcvers_t vers, /* rpc program version */ 189 rpcproc_t proc, /* rpc procedure to call */ 190 xdrproc_t in_xdr, /* routine to serialize arguments */ 191 caddr_t args, /* arg vector for remote call */ 192 xdrproc_t out_xdr, /* routine to deserialize results */ 193 caddr_t ret, /* addr of buf to place results in */ 194 int rexmit, /* retransmission interval (secs) */ 195 int wait_time, /* how long (secs) to wait (resp) */ 196 struct sockaddr_in *to, /* destination */ 197 struct sockaddr_in *from_who, /* responder's port/address */ 198 uint_t auth) /* type of auth wanted. */ 199 { 200 int s; 201 char hostname[MAXHOSTNAMELEN]; 202 struct sockaddr_in from; /* us. */ 203 socklen_t from_len; 204 XDR xmit_xdrs, rcv_xdrs; /* xdr memory */ 205 AUTH *xmit_auth; /* our chosen auth cookie */ 206 gid_t fake_gids = 1; /* fake gids list for auth_unix */ 207 caddr_t trm_msg, rcv_msg; /* outgoing/incoming rpc mesgs */ 208 struct rpc_msg reply; /* our reply msg header */ 209 int trm_len, rcv_len; 210 struct rpc_err rpc_error; /* to store RPC errors in on rcv. */ 211 static uint_t xid; /* current xid */ 212 uint_t xmit_len; /* How much of the buffer we used */ 213 int nrefreshes = 2; /* # of times to refresh cred */ 214 int flags = 0; /* send flags */ 215 uint_t xdelay; 216 int errors, preserve_errno; 217 uint32_t timeout; 218 socklen_t optlen; 219 220 xmit_auth = NULL; 221 222 trm_len = mac_get_mtu(); 223 trm_msg = bkmem_alloc(trm_len); 224 rcv_msg = bkmem_alloc(NFSBUF_SIZE); 225 226 if (trm_msg == NULL || rcv_msg == NULL) { 227 errno = ENOMEM; 228 rpc_error.re_status = RPC_CANTSEND; 229 goto gt_error; 230 } 231 232 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 233 rpc_error.re_status = RPC_CANTSEND; 234 goto gt_error; 235 } 236 237 if (dontroute) { 238 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 239 (const void *)&dontroute, sizeof (dontroute)); 240 } 241 242 if (to->sin_addr.s_addr == cached_destination.s_addr) { 243 optlen = sizeof (timeout); 244 (void) getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, 245 &optlen); 246 } else { 247 cached_destination.s_addr = htonl(INADDR_ANY); 248 } 249 250 /* Bind our endpoint. */ 251 from.sin_family = AF_INET; 252 ipv4_getipaddr(&from.sin_addr); 253 from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); 254 from.sin_port = get_source_port(B_TRUE); 255 256 if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) { 257 rpc_error.re_status = RPC_CANTSEND; 258 goto gt_error; 259 } 260 261 bzero((caddr_t)&rpc_error, sizeof (struct rpc_err)); 262 263 /* initialize reply's rpc_msg struct, so we can decode later. */ 264 reply.acpted_rply.ar_verf = _null_auth; /* struct copy */ 265 reply.acpted_rply.ar_results.where = ret; 266 reply.acpted_rply.ar_results.proc = out_xdr; 267 268 if (ntohs(to->sin_port) == 0) { 269 /* snag the udp port we need. */ 270 if ((to->sin_port = (in_port_t)bpmap_getport(prog, vers, 271 &(rpc_error.re_status), to, NULL)) == 0) 272 goto gt_error; 273 to->sin_port = htons(to->sin_port); 274 } 275 276 /* generate xid - increment */ 277 if (xid == 0) 278 xid = (uint_t)(prom_gettime() / 1000) + 1; 279 else 280 xid++; 281 282 /* set up outgoing pkt as xdr modified. */ 283 xdrmem_create(&xmit_xdrs, trm_msg, trm_len, XDR_ENCODE); 284 285 /* setup rpc header */ 286 if (rpc_hdr(&xmit_xdrs, xid, prog, vers, proc) != TRUE) { 287 dprintf("brpc_call: cannot setup rpc header.\n"); 288 rpc_error.re_status = RPC_FAILED; 289 goto gt_error; 290 } 291 292 /* setup authentication */ 293 switch (auth) { 294 case AUTH_NONE: 295 xmit_auth = authnone_create(); 296 break; 297 case AUTH_UNIX: 298 /* 299 * Assumes we've configured the stack and thus know our 300 * IP address/hostname, either by using DHCP or rarp/bootparams. 301 */ 302 (void) gethostname(hostname, sizeof (hostname)); 303 xmit_auth = authunix_create(hostname, 0, 1, 1, &fake_gids); 304 break; 305 default: 306 dprintf("brpc_call: Unsupported authentication type: %d\n", 307 auth); 308 rpc_error.re_status = RPC_AUTHERROR; 309 goto gt_error; 310 /*NOTREACHED*/ 311 } 312 313 /* 314 * rpc_hdr puts everything in the xmit buffer for the header 315 * EXCEPT the proc. Put it, and our authentication info into 316 * it now, serializing as we go. We will be at the place where 317 * we left off. 318 */ 319 xmit_xdrs.x_op = XDR_ENCODE; 320 if ((XDR_PUTINT32(&xmit_xdrs, (int32_t *)&proc) == FALSE) || 321 (AUTH_MARSHALL(xmit_auth, &xmit_xdrs, NULL) == FALSE) || 322 ((*in_xdr)(&xmit_xdrs, args) == FALSE)) { 323 rpc_error.re_status = RPC_CANTENCODEARGS; 324 goto gt_error; 325 } else 326 xmit_len = (int)XDR_GETPOS(&xmit_xdrs); /* for sendto */ 327 328 /* 329 * Right now the outgoing packet should be all serialized and 330 * ready to go... Set up timers. 331 */ 332 333 xdelay = (rexmit == 0) ? RPC_REXMIT_MSEC : (rexmit * 1000); 334 (void) setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&xdelay, 335 sizeof (xdelay)); 336 wait_time = (wait_time == 0) ? RPC_RCVWAIT_MSEC : (wait_time * 1000); 337 338 wait_time += prom_gettime(); 339 340 /* 341 * send out the request. The first item in the receive buffer will 342 * be the xid. Check if it is correct. 343 */ 344 errors = 0; 345 rpc_error.re_status = RPC_TIMEDOUT; 346 do { 347 if (sendto(s, trm_msg, xmit_len, flags, (struct sockaddr *)to, 348 sizeof (struct sockaddr_in)) < 0) { 349 /* 350 * If errno is set to ETIMEDOUT, return 351 * with RPC status as RPC_TIMEDOUT. Calling 352 * funciton will take care of this error by 353 * retrying the RPC call. 354 */ 355 if (errno == ETIMEDOUT) { 356 rpc_error.re_status = RPC_TIMEDOUT; 357 } else { 358 rpc_error.re_status = RPC_CANTSEND; 359 } 360 goto gt_error; 361 } 362 363 from_len = sizeof (struct sockaddr_in); 364 while ((rcv_len = recvfrom(s, rcv_msg, NFSBUF_SIZE, 365 MSG_DONTWAIT, (struct sockaddr *)from_who, 366 &from_len)) > 0 || errors < RPC_ALLOWABLE_ERRORS) { 367 if (rcv_len < 0) { 368 if (errno == EWOULDBLOCK || 369 errno == ETIMEDOUT) { 370 break; /* timeout */ 371 } 372 rpc_error.re_status = RPC_CANTRECV; 373 goto gt_error; 374 } 375 if (ntohl(*((uint32_t *)(rcv_msg))) != xid) { 376 dprintf("brpc_call: xid: 0x%x != 0x%x\n", 377 *(uint32_t *)(rcv_msg), xid); 378 continue; 379 } 380 /* 381 * Let's deserialize the data into our 'ret' buffer. 382 */ 383 xdrmem_create(&rcv_xdrs, rcv_msg, rcv_len, XDR_DECODE); 384 if (xdr_replymsg(&rcv_xdrs, &reply) == FALSE) { 385 rpc_error.re_status = RPC_CANTDECODERES; 386 goto gt_error; 387 } 388 _seterr_reply(&reply, &rpc_error); 389 switch (rpc_error.re_status) { 390 case RPC_SUCCESS: 391 /* 392 * XXX - validate for unix and none 393 * always return true. 394 */ 395 if (AUTH_VALIDATE(xmit_auth, 396 &reply.acpted_rply.ar_verf) == FALSE) { 397 rpc_error.re_status = RPC_AUTHERROR; 398 rpc_error.re_why = AUTH_INVALIDRESP; 399 errors++; 400 } 401 if (reply.acpted_rply.ar_verf.oa_base != 402 0) { 403 xmit_xdrs.x_op = XDR_FREE; 404 (void) xdr_opaque_auth( 405 &xmit_xdrs, 406 &reply.acpted_rply.ar_verf); 407 } 408 break; 409 410 case RPC_AUTHERROR: 411 /* 412 * Let's see if our credentials need 413 * refreshing 414 */ 415 if (nrefreshes > 0 && AUTH_REFRESH(xmit_auth, 416 NULL, NULL)) { 417 nrefreshes--; 418 } 419 errors++; 420 break; 421 422 case RPC_PROCUNAVAIL: 423 /* 424 * Might be a silly portmapper implementation 425 * erroneously responding to our rpc broadcast 426 * indirect portmapper call. For this 427 * particular case, we don't increment the 428 * error counter because we want to keep 429 * sifting for successful replies... 430 */ 431 if (to->sin_addr.s_addr != 432 ntohl(INADDR_BROADCAST)) 433 errors++; 434 break; 435 436 case RPC_PROGVERSMISMATCH: 437 /* 438 * Successfully talked to server, but they 439 * don't speak our lingo. 440 */ 441 goto gt_error; 442 443 default: 444 /* Just keep trying till there's no data... */ 445 errors++; 446 break; 447 } 448 449 if (rpc_error.re_status != RPC_SUCCESS) { 450 dprintf("brpc_call: from: %s, error: ", 451 inet_ntoa(from_who->sin_addr)); 452 rpc_disperr(&rpc_error); 453 } else 454 break; 455 } 456 457 /* 458 * If we're having trouble reassembling datagrams, let the 459 * application know ASAP so that it can take the appropriate 460 * actions. 461 */ 462 463 } while (rpc_error.re_status != RPC_SUCCESS && errno != ETIMEDOUT && 464 prom_gettime() < wait_time); 465 466 gt_error: 467 if (xmit_auth != NULL) 468 AUTH_DESTROY(xmit_auth); 469 470 if (trm_msg != NULL) 471 bkmem_free(trm_msg, trm_len); 472 if (rcv_msg != NULL) 473 bkmem_free(rcv_msg, NFSBUF_SIZE); 474 475 if (rpc_error.re_status != RPC_SUCCESS) 476 rpc_disperr(&rpc_error); 477 478 /* 479 * socket calls reset errno. Since we want to hold onto the errno 480 * value if it is ETIMEDOUT to communicate to our caller that this 481 * RPC_TIMEDOUT situation is due to a stack problem (we're getting 482 * a reply, but the stack simply can't assemble it.), we need to 483 * preserve errno's value over the socket_close(). 484 */ 485 preserve_errno = (errno == ETIMEDOUT) ? errno : 0; 486 (void) socket_close(s); 487 errno = preserve_errno; 488 489 return (rpc_error.re_status); 490 } 491