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
rpc_disperr(struct rpc_err * stat)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
rpc_hdr(XDR * xdrs,uint_t xid,rpcprog_t prog,rpcvers_t vers,rpcproc_t proc)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
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)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