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
rpc_disperr(struct rpc_err * stat)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
rpc_hdr(XDR * xdrs,uint_t xid,rpcprog_t prog,rpcvers_t vers,rpcproc_t proc)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
brpc_call(rpcprog_t prog,rpcvers_t vers,rpcproc_t proc,xdrproc_t in_xdr,caddr_t args,xdrproc_t out_xdr,caddr_t ret,int rexmit,int wait_time,struct sockaddr_in * to,struct sockaddr_in * from_who,uint_t auth)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