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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32 /* SVr4.0 1.1 */
33
34 /*
35 * Miscellaneous support routines for kernel implementation of RPC.
36 */
37
38 #include <sys/param.h>
39 #include <sys/t_lock.h>
40 #include <sys/user.h>
41 #include <sys/vnode.h>
42 #include <sys/stream.h>
43 #include <sys/stropts.h>
44 #include <sys/strsubr.h>
45 #include <sys/socket.h>
46 #include <sys/tihdr.h>
47 #include <sys/timod.h>
48 #include <sys/tiuser.h>
49 #include <sys/systm.h>
50 #include <sys/cmn_err.h>
51 #include <sys/debug.h>
52 #include <netinet/in.h>
53 #include <rpc/types.h>
54 #include <rpc/auth.h>
55 #include <rpc/clnt.h>
56 #include <rpc/rpcb_prot.h>
57 #include <rpc/pmap_prot.h>
58
59 static int strtoi(char *, char **);
60 static void grow_netbuf(struct netbuf *, size_t);
61 static void loopb_u2t(const char *, struct netbuf *);
62
63 #define RPC_PMAP_TIMEOUT 15
64 /*
65 * define for max length of an ip address and port address, the value was
66 * calculated using INET6_ADDRSTRLEN (46) + max port address (12) +
67 * seperator "."'s in port address (2) + null (1) = 61.
68 * Then there is IPV6_TOKEN_LEN which is 64, so the value is 64 to be safe.
69 */
70 #define RPC_MAX_IP_LENGTH 64
71
72 /*
73 * Kernel level debugging aid. The global variable "rpclog" is a bit
74 * mask which allows various types of debugging messages to be printed
75 * out.
76 *
77 * rpclog & 1 will cause actual failures to be printed.
78 * rpclog & 2 will cause informational messages to be
79 * printed on the client side of rpc.
80 * rpclog & 4 will cause informational messages to be
81 * printed on the server side of rpc.
82 * rpclog & 8 will cause informational messages for rare events to be
83 * printed on the client side of rpc.
84 * rpclog & 16 will cause informational messages for rare events to be
85 * printed on the server side of rpc.
86 * rpclog & 32 will cause informational messages for rare events to be
87 * printed on the common client/server code paths of rpc.
88 * rpclog & 64 will cause informational messages for manipulation
89 * client-side COTS dispatch list to be printed.
90 */
91
92 uint_t rpclog = 0;
93
94
95 void
rpc_poptimod(vnode_t * vp)96 rpc_poptimod(vnode_t *vp)
97 {
98 int error, isfound, ret;
99
100 error = strioctl(vp, I_FIND, (intptr_t)"timod", 0, K_TO_K, kcred,
101 &isfound);
102 if (error) {
103 RPCLOG(1, "rpc_poptimod: I_FIND strioctl error %d\n", error);
104 return;
105 }
106 if (isfound) {
107 /*
108 * Pop timod module
109 */
110 error = strioctl(vp, I_POP, 0, 0, K_TO_K, kcred, &ret);
111 if (error) {
112 RPCLOG(1, "rpc_poptimod: I_POP strioctl error %d\n",
113 error);
114 return;
115 }
116 }
117 }
118
119 /*
120 * Check the passed in ip address for correctness (limited) and return its
121 * type.
122 *
123 * an ipv4 looks like this:
124 * "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]"
125 *
126 * an ipv6 looks like this:
127 * fec0:A02::2:202:4FCD
128 * or
129 * ::10.9.2.1
130 */
131 int
rpc_iptype(char * ipaddr,int * typeval)132 rpc_iptype(
133 char *ipaddr,
134 int *typeval)
135 {
136 char *cp;
137 int chcnt = 0;
138 int coloncnt = 0;
139 int dotcnt = 0;
140 int numcnt = 0;
141 int hexnumcnt = 0;
142 int othercnt = 0;
143
144 cp = ipaddr;
145
146 /* search for the different type of characters in the ip address */
147 while ((*cp != '\0') && (chcnt < RPC_MAX_IP_LENGTH)) {
148 switch (*cp) {
149 case ':':
150 coloncnt++;
151 break;
152 case '.':
153 dotcnt++;
154 break;
155 case '0':
156 case '1':
157 case '2':
158 case '3':
159 case '4':
160 case '5':
161 case '6':
162 case '7':
163 case '8':
164 case '9':
165 numcnt++;
166 break;
167 case 'a':
168 case 'A':
169 case 'b':
170 case 'B':
171 case 'c':
172 case 'C':
173 case 'd':
174 case 'D':
175 case 'e':
176 case 'E':
177 case 'f':
178 case 'F':
179 hexnumcnt++;
180 break;
181 default:
182 othercnt++;
183 break;
184 }
185 chcnt++;
186 cp++;
187 }
188
189 /* check for bad ip strings */
190 if ((chcnt == RPC_MAX_IP_LENGTH) || (othercnt))
191 return (-1);
192
193 /* if we have a coloncnt, it can only be an ipv6 address */
194 if (coloncnt) {
195 if ((coloncnt < 2) || (coloncnt > 7))
196 return (-1);
197
198 *typeval = AF_INET6;
199 } else {
200 /* since there are no colons, make sure it is ipv4 */
201 if ((hexnumcnt) || (dotcnt != 5))
202 return (-1);
203
204 *typeval = AF_INET;
205 }
206 return (0);
207 }
208
209 /*
210 * Return a port number from a sockaddr_in expressed in universal address
211 * format. Note that this routine does not work for address families other
212 * than INET. Eventually, we should replace this routine with one that
213 * contacts the rpcbind running locally.
214 */
215 int
rpc_uaddr2port(int af,char * addr)216 rpc_uaddr2port(int af, char *addr)
217 {
218 int p1;
219 int p2;
220 char *next, *p;
221
222 if (af == AF_INET) {
223 /*
224 * A struct sockaddr_in expressed in universal address
225 * format looks like:
226 *
227 * "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]"
228 *
229 * Where each component expresses as a character,
230 * the corresponding part of the IP address
231 * and port number.
232 * Thus 127.0.0.1, port 2345 looks like:
233 *
234 * 49 50 55 46 48 46 48 46 49 46 57 46 52 49
235 * 1 2 7 . 0 . 0 . 1 . 9 . 4 1
236 *
237 * 2345 = 929base16 = 9.32+9 = 9.41
238 */
239 (void) strtoi(addr, &next);
240 (void) strtoi(next, &next);
241 (void) strtoi(next, &next);
242 (void) strtoi(next, &next);
243 p1 = strtoi(next, &next);
244 p2 = strtoi(next, &next);
245
246 } else if (af == AF_INET6) {
247 /*
248 * An IPv6 address is expressed in following two formats
249 * fec0:A02::2:202:4FCD or
250 * ::10.9.2.1
251 * An universal address will have porthi.portlo appended to
252 * v6 address. So always look for the last two dots when
253 * extracting port number.
254 */
255 next = addr;
256 while (next = strchr(next, '.')) {
257 p = ++next;
258 next = strchr(next, '.');
259 next++;
260 }
261 p1 = strtoi(p, &p);
262 p2 = strtoi(p, &p);
263 RPCLOG(1, "rpc_uaddr2port: IPv6 port %d\n", ((p1 << 8) + p2));
264 }
265
266 return ((p1 << 8) + p2);
267 }
268
269 /*
270 * Modified strtol(3). Should we be using mi_strtol() instead?
271 */
272 static int
strtoi(char * str,char ** ptr)273 strtoi(char *str, char **ptr)
274 {
275 int c;
276 int val;
277
278 for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
279 val *= 10;
280 val += c - '0';
281 }
282 *ptr = str;
283 return (val);
284 }
285
286 /*
287 * Utilities for manipulating netbuf's.
288 *
289 * Note that loopback addresses are not null-terminated, so these utilities
290 * typically use the strn* string routines.
291 */
292
293 /*
294 * Utilities to patch a port number (for NC_INET protocols) or a
295 * port name (for NC_LOOPBACK) into a network address.
296 */
297
298
299 /*
300 * PSARC 2003/523 Contract Private Interface
301 * put_inet_port
302 * Changes must be reviewed by Solaris File Sharing
303 * Changes must be communicated to contract-2003-523@sun.com
304 */
305 void
put_inet_port(struct netbuf * addr,ushort_t port)306 put_inet_port(struct netbuf *addr, ushort_t port)
307 {
308 /*
309 * Easy - we always patch an unsigned short on top of an
310 * unsigned short. No changes to addr's len or maxlen are
311 * necessary.
312 */
313 ((struct sockaddr_in *)(addr->buf))->sin_port = port;
314 }
315
316 void
put_inet6_port(struct netbuf * addr,ushort_t port)317 put_inet6_port(struct netbuf *addr, ushort_t port)
318 {
319 ((struct sockaddr_in6 *)(addr->buf))->sin6_port = port;
320 }
321
322 void
put_loopback_port(struct netbuf * addr,char * port)323 put_loopback_port(struct netbuf *addr, char *port)
324 {
325 char *dot;
326 char *newbuf;
327 int newlen;
328
329
330 /*
331 * We must make sure the addr has enough space for us,
332 * patch in `port', and then adjust addr's len and maxlen
333 * to reflect the change.
334 */
335 if ((dot = strnrchr(addr->buf, '.', addr->len)) == (char *)NULL)
336 return;
337
338 newlen = (int)((dot - addr->buf + 1) + strlen(port));
339 if (newlen > addr->maxlen) {
340 newbuf = kmem_zalloc(newlen, KM_SLEEP);
341 bcopy(addr->buf, newbuf, addr->len);
342 kmem_free(addr->buf, addr->maxlen);
343 addr->buf = newbuf;
344 addr->len = addr->maxlen = newlen;
345 dot = strnrchr(addr->buf, '.', addr->len);
346 } else {
347 addr->len = newlen;
348 }
349
350 (void) strncpy(++dot, port, strlen(port));
351 }
352
353 /*
354 * Convert a loopback universal address to a loopback transport address.
355 */
356 static void
loopb_u2t(const char * ua,struct netbuf * addr)357 loopb_u2t(const char *ua, struct netbuf *addr)
358 {
359 size_t stringlen = strlen(ua) + 1;
360 const char *univp; /* ptr into universal addr */
361 char *transp; /* ptr into transport addr */
362
363 /* Make sure the netbuf will be big enough. */
364 if (addr->maxlen < stringlen) {
365 grow_netbuf(addr, stringlen);
366 }
367
368 univp = ua;
369 transp = addr->buf;
370 while (*univp != NULL) {
371 if (*univp == '\\' && *(univp+1) == '\\') {
372 *transp = '\\';
373 univp += 2;
374 } else if (*univp == '\\') {
375 /* octal character */
376 *transp = (((*(univp+1) - '0') & 3) << 6) +
377 (((*(univp+2) - '0') & 7) << 3) +
378 ((*(univp+3) - '0') & 7);
379 univp += 4;
380 } else {
381 *transp = *univp;
382 univp++;
383 }
384 transp++;
385 }
386
387 addr->len = (unsigned int)(transp - addr->buf);
388 ASSERT(addr->len <= addr->maxlen);
389 }
390
391 /*
392 * Make sure the given netbuf has a maxlen at least as big as the given
393 * length.
394 */
395 static void
grow_netbuf(struct netbuf * nb,size_t length)396 grow_netbuf(struct netbuf *nb, size_t length)
397 {
398 char *newbuf;
399
400 if (nb->maxlen >= length)
401 return;
402
403 newbuf = kmem_zalloc(length, KM_SLEEP);
404 bcopy(nb->buf, newbuf, nb->len);
405 kmem_free(nb->buf, nb->maxlen);
406 nb->buf = newbuf;
407 nb->maxlen = (unsigned int)length;
408 }
409
410 /*
411 * Try to get the address for the desired service by using the rpcbind
412 * protocol. Ignores signals. If addr is a loopback address, it is
413 * expected to be initialized to "<hostname>.".
414 */
415
416 enum clnt_stat
rpcbind_getaddr(struct knetconfig * config,rpcprog_t prog,rpcvers_t vers,struct netbuf * addr)417 rpcbind_getaddr(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers,
418 struct netbuf *addr)
419 {
420 char *ua = NULL;
421 enum clnt_stat status;
422 RPCB parms;
423 struct timeval tmo;
424 CLIENT *client = NULL;
425 k_sigset_t oldmask;
426 k_sigset_t newmask;
427 ushort_t port;
428 int iptype;
429
430 /*
431 * Call rpcbind (local or remote) to get an address we can use
432 * in an RPC client handle.
433 */
434 tmo.tv_sec = RPC_PMAP_TIMEOUT;
435 tmo.tv_usec = 0;
436 parms.r_prog = prog;
437 parms.r_vers = vers;
438 parms.r_addr = parms.r_owner = "";
439
440 if (strcmp(config->knc_protofmly, NC_INET) == 0) {
441 if (strcmp(config->knc_proto, NC_TCP) == 0)
442 parms.r_netid = "tcp";
443 else
444 parms.r_netid = "udp";
445 put_inet_port(addr, htons(PMAPPORT));
446 } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) {
447 if (strcmp(config->knc_proto, NC_TCP) == 0)
448 parms.r_netid = "tcp6";
449 else
450 parms.r_netid = "udp6";
451 put_inet6_port(addr, htons(PMAPPORT));
452 } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) {
453 ASSERT(strnrchr(addr->buf, '.', addr->len) != NULL);
454 if (config->knc_semantics == NC_TPI_COTS_ORD)
455 parms.r_netid = "ticotsord";
456 else if (config->knc_semantics == NC_TPI_COTS)
457 parms.r_netid = "ticots";
458 else
459 parms.r_netid = "ticlts";
460
461 put_loopback_port(addr, "rpc");
462 } else {
463 status = RPC_UNKNOWNPROTO;
464 goto out;
465 }
466
467 /*
468 * Mask signals for the duration of the handle creation and
469 * RPC calls. This allows relatively normal operation with a
470 * signal already posted to our thread (e.g., when we are
471 * sending an NLM_CANCEL in response to catching a signal).
472 *
473 * Any further exit paths from this routine must restore
474 * the original signal mask.
475 */
476 sigfillset(&newmask);
477 sigreplace(&newmask, &oldmask);
478
479 if (clnt_tli_kcreate(config, addr, RPCBPROG,
480 RPCBVERS, 0, 0, CRED(), &client)) {
481 status = RPC_TLIERROR;
482 sigreplace(&oldmask, (k_sigset_t *)NULL);
483 goto out;
484 }
485
486 client->cl_nosignal = 1;
487 if ((status = CLNT_CALL(client, RPCBPROC_GETADDR,
488 xdr_rpcb, (char *)&parms,
489 xdr_wrapstring, (char *)&ua,
490 tmo)) != RPC_SUCCESS) {
491 sigreplace(&oldmask, (k_sigset_t *)NULL);
492 goto out;
493 }
494
495 sigreplace(&oldmask, (k_sigset_t *)NULL);
496
497 if (ua == NULL || *ua == NULL) {
498 status = RPC_PROGNOTREGISTERED;
499 goto out;
500 }
501
502 /*
503 * Convert the universal address to the transport address.
504 * Theoretically, we should call the local rpcbind to translate
505 * from the universal address to the transport address, but it gets
506 * complicated (e.g., there's no direct way to tell rpcbind that we
507 * want an IP address instead of a loopback address). Note that
508 * the transport address is potentially host-specific, so we can't
509 * just ask the remote rpcbind, because it might give us the wrong
510 * answer.
511 */
512 if (strcmp(config->knc_protofmly, NC_INET) == 0) {
513 /* make sure that the ip address is the correct type */
514 if (rpc_iptype(ua, &iptype) != 0) {
515 status = RPC_UNKNOWNADDR;
516 goto out;
517 }
518 port = rpc_uaddr2port(iptype, ua);
519 put_inet_port(addr, ntohs(port));
520 } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) {
521 /* make sure that the ip address is the correct type */
522 if (rpc_iptype(ua, &iptype) != 0) {
523 status = RPC_UNKNOWNADDR;
524 goto out;
525 }
526 port = rpc_uaddr2port(iptype, ua);
527 put_inet6_port(addr, ntohs(port));
528 } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) {
529 loopb_u2t(ua, addr);
530 } else {
531 /* "can't happen" - should have been checked for above */
532 cmn_err(CE_PANIC, "rpcbind_getaddr: bad protocol family");
533 }
534
535 out:
536 if (client != NULL) {
537 auth_destroy(client->cl_auth);
538 clnt_destroy(client);
539 }
540 if (ua != NULL)
541 xdr_free(xdr_wrapstring, (char *)&ua);
542 return (status);
543 }
544
545 static const char *tpiprims[] = {
546 "T_CONN_REQ 0 connection request",
547 "T_CONN_RES 1 connection response",
548 "T_DISCON_REQ 2 disconnect request",
549 "T_DATA_REQ 3 data request",
550 "T_EXDATA_REQ 4 expedited data request",
551 "T_INFO_REQ 5 information request",
552 "T_BIND_REQ 6 bind request",
553 "T_UNBIND_REQ 7 unbind request",
554 "T_UNITDATA_REQ 8 unitdata request",
555 "T_OPTMGMT_REQ 9 manage options req",
556 "T_ORDREL_REQ 10 orderly release req",
557 "T_CONN_IND 11 connection indication",
558 "T_CONN_CON 12 connection confirmation",
559 "T_DISCON_IND 13 disconnect indication",
560 "T_DATA_IND 14 data indication",
561 "T_EXDATA_IND 15 expeditied data indication",
562 "T_INFO_ACK 16 information acknowledgment",
563 "T_BIND_ACK 17 bind acknowledment",
564 "T_ERROR_ACK 18 error acknowledgment",
565 "T_OK_ACK 19 ok acknowledgment",
566 "T_UNITDATA_IND 20 unitdata indication",
567 "T_UDERROR_IND 21 unitdata error indication",
568 "T_OPTMGMT_ACK 22 manage options ack",
569 "T_ORDREL_IND 23 orderly release ind"
570 };
571
572
573 const char *
rpc_tpiprim2name(uint_t prim)574 rpc_tpiprim2name(uint_t prim)
575 {
576 if (prim > (sizeof (tpiprims) / sizeof (tpiprims[0]) - 1))
577 return ("unknown primitive");
578
579 return (tpiprims[prim]);
580 }
581
582 static const char *tpierrs[] = {
583 "error zero 0",
584 "TBADADDR 1 incorrect addr format",
585 "TBADOPT 2 incorrect option format",
586 "TACCES 3 incorrect permissions",
587 "TBADF 4 illegal transport fd",
588 "TNOADDR 5 couldn't allocate addr",
589 "TOUTSTATE 6 out of state",
590 "TBADSEQ 7 bad call sequnce number",
591 "TSYSERR 8 system error",
592 "TLOOK 9 event requires attention",
593 "TBADDATA 10 illegal amount of data",
594 "TBUFOVFLW 11 buffer not large enough",
595 "TFLOW 12 flow control",
596 "TNODATA 13 no data",
597 "TNODIS 14 discon_ind not found on q",
598 "TNOUDERR 15 unitdata error not found",
599 "TBADFLAG 16 bad flags",
600 "TNOREL 17 no ord rel found on q",
601 "TNOTSUPPORT 18 primitive not supported",
602 "TSTATECHNG 19 state is in process of changing"
603 };
604
605
606 const char *
rpc_tpierr2name(uint_t err)607 rpc_tpierr2name(uint_t err)
608 {
609 if (err > (sizeof (tpierrs) / sizeof (tpierrs[0]) - 1))
610 return ("unknown error");
611
612 return (tpierrs[err]);
613 }
614
615 /*
616 * derive the code from user land inet_top6
617 * convert IPv6 binary address into presentation (printable) format
618 */
619 #define INADDRSZ 4
620 #define IN6ADDRSZ 16
621 #define INT16SZ 2
622 const char *
kinet_ntop6(src,dst,size)623 kinet_ntop6(src, dst, size)
624 uchar_t *src;
625 char *dst;
626 size_t size;
627 {
628 /*
629 * Note that int32_t and int16_t need only be "at least" large enough
630 * to contain a value of the specified size. On some systems, like
631 * Crays, there is no such thing as an integer variable with 16 bits.
632 * Keep this in mind if you think this function should have been coded
633 * to use pointer overlays. All the world's not a VAX.
634 */
635 char tmp[sizeof ("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
636 char *tp;
637 struct { int base, len; } best, cur;
638 uint_t words[IN6ADDRSZ / INT16SZ];
639 int i;
640 size_t len; /* this is used to track the sprintf len */
641
642 /*
643 * Preprocess:
644 * Copy the input (bytewise) array into a wordwise array.
645 * Find the longest run of 0x00's in src[] for :: shorthanding.
646 */
647
648 bzero(words, sizeof (words));
649 for (i = 0; i < IN6ADDRSZ; i++)
650 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
651 best.base = -1;
652 cur.base = -1;
653
654 for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
655 if (words[i] == 0) {
656 if (cur.base == -1)
657 cur.base = i, cur.len = 1;
658 else
659 cur.len++;
660 } else {
661 if (cur.base != -1) {
662 if (best.base == -1 || cur.len > best.len)
663 best = cur;
664 cur.base = -1;
665 }
666 }
667 }
668 if (cur.base != -1) {
669 if (best.base == -1 || cur.len > best.len)
670 best = cur;
671 }
672
673 if (best.base != -1 && best.len < 2)
674 best.base = -1;
675
676 /*
677 * Format the result.
678 */
679 tp = tmp;
680 for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
681 /* Are we inside the best run of 0x00's? */
682 if (best.base != -1 && i >= best.base &&
683 i < (best.base + best.len)) {
684 if (i == best.base)
685 *tp++ = ':';
686 continue;
687 }
688 /* Are we following an initial run of 0x00s or any real hex? */
689 if (i != 0)
690 *tp++ = ':';
691 (void) sprintf(tp, "%x", words[i]);
692 len = strlen(tp);
693 tp += len;
694 }
695 /* Was it a trailing run of 0x00's? */
696 if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
697 *tp++ = ':';
698 *tp++ = '\0';
699
700 /*
701 * Check for overflow, copy, and we're done.
702 */
703 if ((int)(tp - tmp) > size) {
704 return (NULL);
705 }
706 (void) strcpy(dst, tmp);
707 return (dst);
708 }
709