xref: /illumos-gate/usr/src/stand/lib/fs/nfs/rpc.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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