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