rpc_subr.c revision 546f41c465408bee9e87d051d2fdb40522350b40
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/* SVr4.0 1.1 */
/*
* Miscellaneous support routines for kernel implementation of RPC.
*/
#include <rpc/rpcb_prot.h>
#include <rpc/pmap_prot.h>
static int strtoi(char *, char **);
#define RPC_PMAP_TIMEOUT 15
/*
* define for max length of an ip address and port address, the value was
* calculated using INET6_ADDRSTRLEN (46) + max port address (12) +
* seperator "."'s in port address (2) + null (1) = 61.
* Then there is IPV6_TOKEN_LEN which is 64, so the value is 64 to be safe.
*/
#define RPC_MAX_IP_LENGTH 64
/*
* Kernel level debugging aid. The global variable "rpclog" is a bit
* mask which allows various types of debugging messages to be printed
* out.
*
* rpclog & 1 will cause actual failures to be printed.
* rpclog & 2 will cause informational messages to be
* printed on the client side of rpc.
* rpclog & 4 will cause informational messages to be
* printed on the server side of rpc.
* rpclog & 8 will cause informational messages for rare events to be
* printed on the client side of rpc.
* rpclog & 16 will cause informational messages for rare events to be
* printed on the server side of rpc.
* rpclog & 32 will cause informational messages for rare events to be
* rpclog & 64 will cause informational messages for manipulation
* client-side COTS dispatch list to be printed.
*/
void
{
&isfound);
if (error) {
return;
}
if (isfound) {
/*
* Pop timod module
*/
if (error) {
error);
return;
}
}
}
/*
* Check the passed in ip address for correctness (limited) and return its
* type.
*
* an ipv4 looks like this:
* "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]"
*
* an ipv6 looks like this:
* fec0:A02::2:202:4FCD
* or
* ::10.9.2.1
*/
int
char *ipaddr,
int *typeval)
{
char *cp;
int chcnt = 0;
int coloncnt = 0;
int dotcnt = 0;
int numcnt = 0;
int hexnumcnt = 0;
int othercnt = 0;
/* search for the different type of characters in the ip address */
switch (*cp) {
case ':':
coloncnt++;
break;
case '.':
dotcnt++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
numcnt++;
break;
case 'a':
case 'A':
case 'b':
case 'B':
case 'c':
case 'C':
case 'd':
case 'D':
case 'e':
case 'E':
case 'f':
case 'F':
hexnumcnt++;
break;
default:
othercnt++;
break;
}
chcnt++;
cp++;
}
/* check for bad ip strings */
return (-1);
/* if we have a coloncnt, it can only be an ipv6 address */
if (coloncnt) {
return (-1);
} else {
/* since there are no colons, make sure it is ipv4 */
return (-1);
}
return (0);
}
/*
* Return a port number from a sockaddr_in expressed in universal address
* format. Note that this routine does not work for address families other
* than INET. Eventually, we should replace this routine with one that
* contacts the rpcbind running locally.
*/
int
{
int p1;
int p2;
char *next, *p;
/*
* A struct sockaddr_in expressed in universal address
* format looks like:
*
* "IP.IP.IP.IP.PORT[top byte].PORT[bottom byte]"
*
* Where each component expresses as a character,
* the corresponding part of the IP address
* and port number.
* Thus 127.0.0.1, port 2345 looks like:
*
* 49 50 55 46 48 46 48 46 49 46 57 46 52 49
* 1 2 7 . 0 . 0 . 1 . 9 . 4 1
*
* 2345 = 929base16 = 9.32+9 = 9.41
*/
/*
* An IPv6 address is expressed in following two formats
* fec0:A02::2:202:4FCD or
* ::10.9.2.1
* An universal address will have porthi.portlo appended to
* v6 address. So always look for the last two dots when
* extracting port number.
*/
p = ++next;
next++;
}
}
}
/*
* Modified strtol(3). Should we be using mi_strtol() instead?
*/
static int
{
int c;
int val;
val *= 10;
val += c - '0';
}
return (val);
}
/*
* Utilities for manipulating netbuf's.
*
* Note that loopback addresses are not null-terminated, so these utilities
* typically use the strn* string routines.
*/
/*
* Utilities to patch a port number (for NC_INET protocols) or a
* port name (for NC_LOOPBACK) into a network address.
*/
/*
* PSARC 2003/523 Contract Private Interface
* put_inet_port
* Changes must be reviewed by Solaris File Sharing
* Changes must be communicated to contract-2003-523@sun.com
*/
void
{
/*
* Easy - we always patch an unsigned short on top of an
* unsigned short. No changes to addr's len or maxlen are
* necessary.
*/
}
void
{
}
void
{
char *dot;
char *newbuf;
int newlen;
/*
* We must make sure the addr has enough space for us,
* patch in `port', and then adjust addr's len and maxlen
* to reflect the change.
*/
return;
} else {
}
}
/*
* Convert a loopback universal address to a loopback transport address.
*/
static void
{
const char *univp; /* ptr into universal addr */
char *transp; /* ptr into transport addr */
/* Make sure the netbuf will be big enough. */
}
*transp = '\\';
univp += 2;
} else if (*univp == '\\') {
/* octal character */
univp += 4;
} else {
univp++;
}
transp++;
}
}
/*
* Make sure the given netbuf has a maxlen at least as big as the given
* length.
*/
static void
{
char *newbuf;
return;
}
/*
* XXX: xdr_pmap is here, because it's the only XDR function
* of portmap protocol. If there'll be more portmap functions,
* it would be better to put them to a separate file.
*/
{
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (TRUE);
}
/*
* Get remote port via PORTMAP protocol version 2 (works for IPv4 only)
* according to RFC 1833, section 3.
*/
static enum clnt_stat
{
} else { /* NC_UDP */
}
/*
* Mask all signals before doing RPC network operations
* in the same way rpcbind_getaddr() does (see comments
* there).
*/
return (RPC_TLIERROR);
}
if (status != RPC_SUCCESS)
goto out;
if (port == 0) {
goto out;
}
out:
return (status);
}
/*
* Try to get the address for the desired service by using the rpcbind
* protocol. Ignores signals. If addr is a loopback address, it is
* expected to be initialized to "<hostname>.".
* rpcbind_getaddr() is able to work with RPCBIND protocol version 3 and 4
* and PORTMAP protocol version 2.
* It tries version 4 at first, then version 3 and finally (if both failed)
* it tries portmapper protocol version 2.
*/
enum clnt_stat
{
int iptype;
/*
* Call rpcbind (local or remote) to get an address we can use
* in an RPC client handle.
*/
else
else
else
} else {
goto out;
}
/*
* Try RPCBIND versions 4 and 3 (if 4 fails).
*/
}
/*
* Mask signals for the duration of the handle creation and
* RPC calls. This allows relatively normal operation with a
* signal already posted to our thread (e.g., when we are
* sending an NLM_CANCEL in response to catching a signal).
*
* Any further exit paths from this routine must restore
* the original signal mask.
*/
continue;
}
if (status == RPC_SUCCESS) {
continue;
}
break;
}
}
if (status != RPC_SUCCESS)
goto try_portmap;
/*
* Convert the universal address to the transport address.
* Theoretically, we should call the local rpcbind to translate
* from the universal address to the transport address, but it gets
* complicated (e.g., there's no direct way to tell rpcbind that we
* want an IP address instead of a loopback address). Note that
* the transport address is potentially host-specific, so we can't
* just ask the remote rpcbind, because it might give us the wrong
* answer.
*/
/* make sure that the ip address is the correct type */
goto try_portmap;
}
/* make sure that the ip address is the correct type */
goto try_portmap;
}
} else {
/* "can't happen" - should have been checked for above */
}
if (status != RPC_SUCCESS &&
/*
* For IPv4 try to get remote port via PORTMAP protocol.
* NOTE: if we're here, then all attempts to get remote
* port via RPCBIND protocol failed.
*/
}
out:
return (status);
}
static const char *tpiprims[] = {
"T_CONN_REQ 0 connection request",
"T_CONN_RES 1 connection response",
"T_DISCON_REQ 2 disconnect request",
"T_DATA_REQ 3 data request",
"T_EXDATA_REQ 4 expedited data request",
"T_INFO_REQ 5 information request",
"T_BIND_REQ 6 bind request",
"T_UNBIND_REQ 7 unbind request",
"T_UNITDATA_REQ 8 unitdata request",
"T_OPTMGMT_REQ 9 manage options req",
"T_ORDREL_REQ 10 orderly release req",
"T_CONN_IND 11 connection indication",
"T_CONN_CON 12 connection confirmation",
"T_DISCON_IND 13 disconnect indication",
"T_DATA_IND 14 data indication",
"T_EXDATA_IND 15 expeditied data indication",
"T_INFO_ACK 16 information acknowledgment",
"T_BIND_ACK 17 bind acknowledment",
"T_ERROR_ACK 18 error acknowledgment",
"T_OK_ACK 19 ok acknowledgment",
"T_UNITDATA_IND 20 unitdata indication",
"T_UDERROR_IND 21 unitdata error indication",
"T_OPTMGMT_ACK 22 manage options ack",
"T_ORDREL_IND 23 orderly release ind"
};
const char *
{
return ("unknown primitive");
}
static const char *tpierrs[] = {
"error zero 0",
"TBADADDR 1 incorrect addr format",
"TBADOPT 2 incorrect option format",
"TACCES 3 incorrect permissions",
"TBADF 4 illegal transport fd",
"TNOADDR 5 couldn't allocate addr",
"TOUTSTATE 6 out of state",
"TBADSEQ 7 bad call sequnce number",
"TSYSERR 8 system error",
"TLOOK 9 event requires attention",
"TBADDATA 10 illegal amount of data",
"TBUFOVFLW 11 buffer not large enough",
"TFLOW 12 flow control",
"TNODATA 13 no data",
"TNODIS 14 discon_ind not found on q",
"TNOUDERR 15 unitdata error not found",
"TBADFLAG 16 bad flags",
"TNOREL 17 no ord rel found on q",
"TNOTSUPPORT 18 primitive not supported",
"TSTATECHNG 19 state is in process of changing"
};
const char *
{
return ("unknown error");
}
/*
* derive the code from user land inet_top6
* convert IPv6 binary address into presentation (printable) format
*/
#define INADDRSZ 4
#define IN6ADDRSZ 16
#define INT16SZ 2
const char *
char *dst;
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof ("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
char *tp;
int i;
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
for (i = 0; i < IN6ADDRSZ; i++)
if (words[i] == 0) {
else
} else {
}
}
}
}
/*
* Format the result.
*/
/* Are we inside the best run of 0x00's? */
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
}
/* Was it a trailing run of 0x00's? */
*tp++ = ':';
*tp++ = '\0';
/*
* Check for overflow, copy, and we're done.
*/
return (NULL);
}
return (dst);
}