diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libsocket | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libsocket')
49 files changed, 8461 insertions, 0 deletions
diff --git a/usr/src/lib/libsocket/Makefile b/usr/src/lib/libsocket/Makefile new file mode 100644 index 0000000000..6252e47d92 --- /dev/null +++ b/usr/src/lib/libsocket/Makefile @@ -0,0 +1,60 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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) 1993-2001 by Sun Microsystems, Inc. +# All rights reserved. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.lib + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +POFILE = libsocket.po +MSGFILES = `$(GREP) -l gettext */*.[ch]` +XGETFLAGS += -a +TEXT_DOMAIN = SUNW_OST_NETRPC + +.KEEP_STATE: + +all clean clobber install: spec .WAIT $(SUBDIRS) + +lint: $(SUBDIRS) + +_msg: $(MSGDOMAINPOFILE) + +$(POFILE): pofile_MSGFILES + +$(SUBDIRS) spec: FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/Makefile.msg.targ diff --git a/usr/src/lib/libsocket/Makefile.com b/usr/src/lib/libsocket/Makefile.com new file mode 100644 index 0000000000..4664a4e7bb --- /dev/null +++ b/usr/src/lib/libsocket/Makefile.com @@ -0,0 +1,74 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY = libsocket.a +VERS = .1 + +INETOBJS = bindresvport.o bootparams_getbyname.o byteorder.o ether_addr.o \ + getaddrinfo.o getnameinfo.o getnetent.o getnetent_r.o \ + getprotoent.o getprotoent_r.o getservbyname_r.o getservent.o \ + getservent_r.o inet_lnaof.o inet_mkaddr.o inet_network.o \ + inet6_opt.o inet6_rthdr.o interface_id.o link_addr.o \ + netmasks.o rcmd.o rexec.o ruserpass.o sourcefilter.o +SOCKOBJS = _soutil.o sockatmark.o socket.o socketpair.o weaks.o +OBJECTS = $(INETOBJS) $(SOCKOBJS) + +include ../../Makefile.lib + +# install this library in the root filesystem +include ../../Makefile.rootfs + +LIBS = $(DYNLIB) $(LINTLIB) + +SRCS = $(INETOBJS:%.o=../inet/%.c) $(SOCKOBJS:%.o=../socket/%.c) +$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) +LDLIBS += -lnsl -lc + +SRCDIR = ../common +MAPDIR = ../spec/$(TRANSMACH) +SPECMAPFILE = $(MAPDIR)/mapfile + +CPPFLAGS += -DSYSV -D_REENTRANT -I../../common/inc +%/rcmd.o := CPPFLAGS += -DNIS + +.KEEP_STATE: + +all: + +lint: lintcheck + +# libsocket build rules +pics/%.o: ../inet/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +pics/%.o: ../socket/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +include ../../Makefile.targ diff --git a/usr/src/lib/libsocket/amd64/Makefile b/usr/src/lib/libsocket/amd64/Makefile new file mode 100644 index 0000000000..de119509d4 --- /dev/null +++ b/usr/src/lib/libsocket/amd64/Makefile @@ -0,0 +1,44 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# the following entry needs to be defined before the inclusion +# of ../Makefile.com, otherwise inet/byteorder.c will be used +# instead of amd64/byteorder.s + +objs/%.o pics/%.o: %.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +ASFLAGS += -P -D__STDC__ -D_ASM + +include ../Makefile.com +include ../../Makefile.lib.64 + +all: $(LIBS) + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libsocket/amd64/byteorder.s b/usr/src/lib/libsocket/amd64/byteorder.s new file mode 100644 index 0000000000..04d10df546 --- /dev/null +++ b/usr/src/lib/libsocket/amd64/byteorder.s @@ -0,0 +1,60 @@ +/ +/ Copyright 2005 Sun Microsystems, Inc. All rights reserved. +/ Use is subject to license terms. +/ +/ 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 +/ or http://www.opensolaris.org/os/licensing. +/ 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 +/ + .ident "%Z%%M% %I% %E% SMI" + + .file "byteorder.s" + +#include <sys/asm_linkage.h> + +/ +/ uint32_t htonl(uint32_t hl); +/ uint32_t ntohl(uint32_t nl); +/ +/ reverses the byte order of the argument. +/ + + ENTRY(htonl) + ENTRY(ntohl) + movl %edi, %eax + bswap %eax + ret + SET_SIZE(htonl) + SET_SIZE(ntohl) + +/ +/ uint16_t htons(uint16_t hs); +/ uint16_t ntohs(uint16_t ns); +/ +/ reverses the byte order of the argument. +/ + + ENTRY(htons) + ENTRY(ntohs) + movl %edi, %eax + bswap %eax + shr $16, %eax + ret + SET_SIZE(htons) + SET_SIZE(ntohs) diff --git a/usr/src/lib/libsocket/common/llib-lsocket b/usr/src/lib/libsocket/common/llib-lsocket new file mode 100644 index 0000000000..f74c8cea92 --- /dev/null +++ b/usr/src/lib/libsocket/common/llib-lsocket @@ -0,0 +1,126 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* LINTLIBRARY */ +/* PROTOLIB1 */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/uio.h> +#include <sys/isa_defs.h> +#include <arpa/inet.h> +#include <sys/ethernet.h> +#include <netdb.h> +#include <net/if_dl.h> + +/* + * usr/src/lib/libsocket/inet routines not prototyped in the above + * header files. + */ + +/* bindresvport.c */ +int bindresvport(int sd, struct sockaddr_in *sin); + +/* bootparams_getbyname.c */ +int bootparams_getbyname(char *name, char *linebuf, int linelen); + +/* inet6_rthdr.c */ +int __inet6_rthdr_add(void *, const struct in6_addr *); +struct in6_addr *__inet6_rthdr_getaddr(void *, int); + +/* netmasks.c */ +int getnetmaskbynet(const struct in_addr net, struct in_addr *mask); +int getnetmaskbyaddr(const struct in_addr addr, struct in_addr *mask); + +/* ruserpass.c */ +void _ruserpass(const char *host, char **aname, char **apass); + +/* + * usr/src/lib/libsocket/socket routines + */ + +/* _soutil.c */ + +/* socket.c */ +int socket(int domain, int type, int protocol); +int _socket(int domain, int type, int protocol); +int _socket_bsd(int family, int type, int protocol); +int __xnet_socket(int family, int type, int protocol); + +/* socketpair.c */ +int socketpair(int domain, int type, int protocol, int sv[]); +int _socketpair(int domain, int type, int protocol, int *sv); +int _socketpair_bsd(int domain, int type, int protocol, int *sv); +int __xnet_socketpair(int domain, int type, int protocol, int *sv); + +/* weaks.c */ +int bind(int s, const struct sockaddr *name, socklen_t namelen); +int listen(int s, int backlog); +int accept(int s, struct sockaddr *addr, Psocklen_t addrlen); +int connect(int s, const struct sockaddr *name, socklen_t namelen); +int shutdown(int s, int how); +ssize_t recv(int s, void *buf, size_t len, int flags); +ssize_t recvfrom(int s, void *buf, size_t len, int flags, + struct sockaddr *from, Psocklen_t fromlen); +ssize_t recvmsg(int s, struct msghdr *msg, int flags); +ssize_t send(int s, const void *msg, size_t len, int flags); +ssize_t sendmsg(int s, const struct msghdr *msg, int flags); +ssize_t sendto(int s, const void *msg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen); +int getpeername(int s, struct sockaddr *name, Psocklen_t namelen); +int getsockname(int s, struct sockaddr *name, Psocklen_t namelen); +int getsockopt(int s, int level, int optname, void *optval, Psocklen_t optlen); +int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); + +int _bind(int s, const struct sockaddr *name, int namelen); +int _listen(int s, int backlog); +int _accept(int s, struct sockaddr *addr, int *addrlen); +int _connect(int s, struct sockaddr *name, int namelen); +int _shutdown(int s, int how); +int _recv(int s, char *buf, int len, int flags); +int _recvfrom(int s, char *buf, int len, int flags, + struct sockaddr *from, int *fromlen); +int _recvmsg(int s, struct msghdr *msg, int flags); +int _send(int s, const char *msg, int len, int flags); +int _sendmsg(int s, const struct msghdr *msg, int flags); +int _sendto(int s, const char *msg, int len, int flags, + const struct sockaddr *to, int tolen); +int _getpeername(int s, struct sockaddr *name, int *namelen); +int _getsockname(int s, struct sockaddr *name, int *namelen); +int _getsockopt(int s, int level, int optname, char *optval, int *optlen); +int _setsockopt(int s, int level, int optname, const char *optval, int optlen); +int __xnet_bind(int sock, const struct sockaddr *addr, socklen_t addrlen); +int __xnet_listen(int sock, int backlog); +int __xnet_connect(int sock, const struct sockaddr *addr, socklen_t addrlen); +int __xnet_recvmsg(int sock, struct msghdr *msg, int flags); +int __xnet_sendmsg(int sock, const struct msghdr *msg, int flags); +int __xnet_sendto(int sock, const void *buf, size_t len, int flags, + const struct sockaddr *addr, socklen_t addrlen); +int __xnet_getsockopt(int sock, int level, int option_name, + void *option_value, socklen_t *option_lenp); diff --git a/usr/src/lib/libsocket/i386/Makefile b/usr/src/lib/libsocket/i386/Makefile new file mode 100644 index 0000000000..ea3915839c --- /dev/null +++ b/usr/src/lib/libsocket/i386/Makefile @@ -0,0 +1,43 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# the following entry needs to be defined before the inclusion +# of ../Makefile.com, otherwise inet/byteorder.c will be used +# instead of i386/byteorder.s + +objs/%.o pics/%.o: %.s + $(COMPILE.s) -o $@ $< + $(POST_PROCESS_O) + +ASFLAGS += -P -D__STDC__ -D_ASM + +include ../Makefile.com + +all: $(LIBS) + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libsocket/i386/byteorder.s b/usr/src/lib/libsocket/i386/byteorder.s new file mode 100644 index 0000000000..3b58df4707 --- /dev/null +++ b/usr/src/lib/libsocket/i386/byteorder.s @@ -0,0 +1,60 @@ +/ +/ Copyright 2005 Sun Microsystems, Inc. All rights reserved. +/ Use is subject to license terms. +/ +/ 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 +/ or http://www.opensolaris.org/os/licensing. +/ 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 +/ + .ident "%Z%%M% %I% %E% SMI" + + .file "byteorder.s" + +#include <sys/asm_linkage.h> + +/ +/ uint32_t htonl(uint32_t hl); +/ uint32_t ntohl(uint32_t nl); +/ +/ reverses the byte order of the argument. +/ + + ENTRY(htonl) + ENTRY(ntohl) + movl 4(%esp), %eax / %eax = hl + bswap %eax / reverses the byte order of %eax + ret / return (%eax) + SET_SIZE(htonl) + SET_SIZE(ntohl) + +/ +/ uint16_t htons(uint16_t hs); +/ uint16_t ntohs(uint16_t ns); +/ +/ reverses the byte order of the argument. +/ + + ENTRY(htons) + ENTRY(ntohs) + movl 4(%esp), %eax / %eax = hs + bswap %eax / reverses the byte order of %eax + shrl $16, %eax / moves high 16-bit to low 16-bit + ret / return (%eax) + SET_SIZE(htons) + SET_SIZE(ntohs) diff --git a/usr/src/lib/libsocket/inet/bindresvport.c b/usr/src/lib/libsocket/inet/bindresvport.c new file mode 100644 index 0000000000..d3cc2f5b8a --- /dev/null +++ b/usr/src/lib/libsocket/inet/bindresvport.c @@ -0,0 +1,127 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Portions of this source code were derived from Berkeley 4.3 BSD + * under license from the Regents of the University of California. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <string.h> +#include <unistd.h> + +#ifdef SYSV +#define bzero(s, len) (void) memset((s), 0, (len)) +#endif + + +/* + * Bind a socket to a privileged IP port + */ +int +bindresvport(int sd, struct sockaddr_in *sin) +{ + struct sockaddr_in myaddr; + struct sockaddr_in *bindaddr; + int level, optname; + int optval, len; + int ret; + + bindaddr = sin; + if (bindaddr == (struct sockaddr_in *)0) { + bindaddr = &myaddr; + bzero(bindaddr, sizeof (*bindaddr)); + bindaddr->sin_family = AF_INET; + } else if (bindaddr->sin_family != AF_INET) { + errno = EPFNOSUPPORT; + return (-1); + } + + len = sizeof (optval); + if (getsockopt(sd, SOL_SOCKET, SO_TYPE, &optval, &len) < 0) { + return (-1); + } + /* + * Use *_ANONPRIVBIND to ask the kernel to pick a port in the + * priviledged range for us. + */ + if (optval == SOCK_STREAM) { + level = IPPROTO_TCP; + optname = TCP_ANONPRIVBIND; + } else if (optval == SOCK_DGRAM) { + level = IPPROTO_UDP; + optname = UDP_ANONPRIVBIND; + } else { + errno = EPROTONOSUPPORT; + return (-1); + } + + optval = 1; + if (setsockopt(sd, level, optname, &optval, sizeof (optval)) < 0) { + return (-1); + } + + bindaddr->sin_port = 0; + ret = bind(sd, (struct sockaddr *)bindaddr, + sizeof (struct sockaddr_in)); + + /* + * Always turn off the option when we are done. Note that by doing + * this, if the caller has set this option before calling + * bindresvport(), it will be unset. But this should never happen... + */ + optval = 0; + (void) setsockopt(sd, level, optname, &optval, sizeof (optval)); + + if (ret >= 0 && sin != NULL) { + /* + * Historical note: + * + * Past versions of this bindresvport() code have + * returned with the reserved port number bound + * filled in its "sin" parameter (if passed in), perhaps + * "accidently" because of the structure of historical code. + * + * This is not documented but the behavior is + * explicitly retained here for compatibility to minimize + * risk to applications, even though it is not clear if this + * was a design intent. + */ + len = sizeof (struct sockaddr_in); + (void) getsockname(sd, (struct sockaddr *)bindaddr, &len); + } + return (ret); +} diff --git a/usr/src/lib/libsocket/inet/bootparams_getbyname.c b/usr/src/lib/libsocket/inet/bootparams_getbyname.c new file mode 100644 index 0000000000..d071a81c2a --- /dev/null +++ b/usr/src/lib/libsocket/inet/bootparams_getbyname.c @@ -0,0 +1,107 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 1997 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <nss_dbdefs.h> + +static int str2bootent(const char *, int, void *, char *, int); + +static DEFINE_NSS_DB_ROOT(db_root); + +static void +_nss_initf_bootparams(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_BOOTPARAMS; + p->default_config = NSS_DEFCONF_BOOTPARAMS; +} + +int +bootparams_getbyname( + char *name, /* lookup key */ + char *linebuf, /* buffer to put the answer in */ + int linelen /* max # of bytes to put into linebuf */ +) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, linebuf, linebuf, linelen, str2bootent); + arg.key.name = name; + res = nss_search(&db_root, _nss_initf_bootparams, + NSS_DBOP_BOOTPARAMS_BYNAME, &arg); + (void) NSS_XbyY_FINI(&arg); + return (arg.status = res); +} + +/* + * Return values: 0 = success, 1 = parse error, 2 = erange ... + * The structure pointer passed in is a buffer in the caller's space. + * instring and buffer should be separate areas. + * The calling routine does all the real parsing; we just check limits and + * store the entry in the buffer we were passed by the caller. + * NOTE: we expect the data we're passed (in instr) has had the host's name + * stripped off the begining. + */ +/* ARGSUSED */ +static int +str2bootent( + const char *instr, + int lenstr, + void *ent, /* really (char *) */ + char *buffer, + int buflen +) +{ + const char *p, *limit; + + if ((instr >= buffer && (buffer + buflen) > instr) || + (buffer >= instr && (instr + lenstr) > buffer)) { + return (NSS_STR_PARSE_PARSE); + } + p = instr; + limit = p + lenstr; + + /* Skip over leading whitespace */ + while (p < limit && isspace(*p)) { + p++; + } + if (p >= limit) { + /* Syntax error -- no data! */ + return (NSS_STR_PARSE_PARSE); + } + lenstr -= (p - instr); + if (buflen <= lenstr) { /* not enough buffer */ + return (NSS_STR_PARSE_ERANGE); + } + (void) memcpy(buffer, p, lenstr); + buffer[lenstr] = '\0'; + + return (NSS_STR_PARSE_SUCCESS); +} diff --git a/usr/src/lib/libsocket/inet/byteorder.c b/usr/src/lib/libsocket/inet/byteorder.c new file mode 100644 index 0000000000..1b325c6c5e --- /dev/null +++ b/usr/src/lib/libsocket/inet/byteorder.c @@ -0,0 +1,61 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/isa_defs.h> +#include <sys/types.h> + + +#ifdef _LITTLE_ENDIAN +#error Use ISA-specific byteorder.s on a little-endian machine. + +#else /* !_LITTLE_ENDIAN */ + +uint32_t +htonl(uint32_t in) +{ + return (in); +} + +uint32_t +ntohl(uint32_t in) +{ + return (in); +} + +uint16_t +htons(uint16_t in) +{ + return (in); +} + +uint16_t +ntohs(uint16_t in) +{ + return (in); +} +#endif /* _LITTLE_ENDIAN */ diff --git a/usr/src/lib/libsocket/inet/ether_addr.c b/usr/src/lib/libsocket/inet/ether_addr.c new file mode 100644 index 0000000000..7bf8d069ef --- /dev/null +++ b/usr/src/lib/libsocket/inet/ether_addr.c @@ -0,0 +1,311 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * All routines necessary to deal the "ethers" database. The sources + * contain mappings between 48 bit ethernet addresses and corresponding + * hosts names. The addresses have an ascii representation of the form + * "x:x:x:x:x:x" where x is a hex number between 0x00 and 0xff; the + * bytes are always in network order. + */ + +#include "mtlib.h" +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <thread.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <nss_dbdefs.h> + +static int str2ether(const char *, int, void *, char *, int); + +static DEFINE_NSS_DB_ROOT(db_root); + +static void +_nss_initf_ethers(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_ETHERS; + p->default_config = NSS_DEFCONF_ETHERS; +} + +/* + * Given a host's name, this routine finds the corresponding 48 bit + * ethernet address based on the "ethers" policy in /etc/nsswitch.conf. + * Returns zero if successful, non-zero otherwise. + */ +int +ether_hostton( + const char *host, /* function input */ + struct ether_addr *e /* function output */ +) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + /* + * let the backend do the allocation to store stuff for parsing. + */ + NSS_XbyY_INIT(&arg, e, NULL, 0, str2ether); + arg.key.name = host; + res = nss_search(&db_root, _nss_initf_ethers, + NSS_DBOP_ETHERS_HOSTTON, &arg); + (void) NSS_XbyY_FINI(&arg); + return (arg.status = res); +} + +/* + * Given a 48 bit ethernet address, it finds the corresponding hostname + * ethernet address based on the "ethers" policy in /etc/nsswitch.conf. + * Returns zero if successful, non-zero otherwise. + */ +int +ether_ntohost( + char *host, /* function output */ + const struct ether_addr *e /* function input */ +) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + /* + * let the backend do the allocation to store stuff for parsing. + */ + NSS_XbyY_INIT(&arg, NULL, host, 0, str2ether); + arg.key.ether = (void *)e; + res = nss_search(&db_root, _nss_initf_ethers, + NSS_DBOP_ETHERS_NTOHOST, &arg); + /* memcpy(host, ether_res.host, strlen(ether_res.host)); */ + (void) NSS_XbyY_FINI(&arg); + return (arg.status = res); +} + +/* + * Parses a line from "ethers" database into its components. The line has + * the form 8:0:20:1:17:c8 krypton + * where the first part is a 48 bit ethernet address and the second is + * the corresponding hosts name. + * Returns zero if successful, non-zero otherwise. + */ +int +ether_line( + const char *s, /* the string to be parsed */ + struct ether_addr *e, /* ethernet address struct to be filled in */ + char *hostname /* hosts name to be set */ +) +{ + int i; + uint_t t[6]; + + i = sscanf(s, " %x:%x:%x:%x:%x:%x %s", + &t[0], &t[1], &t[2], &t[3], &t[4], &t[5], hostname); + if (i != 7) { + return (7 - i); + } + for (i = 0; i < 6; i++) + e->ether_addr_octet[i] = (uchar_t)t[i]; + return (0); +} + +/* + * Parses a line from "ethers" database into its components. + * Useful for the vile purposes of the backends that + * expect a str2ether() format. + * + * This function, after parsing the instr line, will + * place the resulting struct ether_addr in b->buf.result only if + * b->buf.result is initialized (not NULL). I.e. it always happens + * for "files" backend (that needs to parse input line and + * then do a match for the ether key) and happens for "nis" + * backend only if the call was ether_hostton. + * + * Also, it will place the resulting hostname into b->buf.buffer + * only if b->buf.buffer is initialized. I.e. it always happens + * for "files" backend (that needs to parse input line and + * then do a match for the host key) and happens for "nis" + * backend only if the call was ether_ntohost. + * + * Cannot use the sscanf() technique for parsing because instr + * is a read-only, not necessarily null-terminated, buffer. + * + * Return values: 0 = success, 1 = parse error, 2 = erange ... + * The structure pointer passed in is a structure in the caller's space + * wherein the field pointers would be set to areas in the buffer if + * need be. instring and buffer should be separate areas. + */ +#define DIGIT(x) (isdigit(x) ? (x) - '0' : \ + islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A') +#define lisalnum(x) (isdigit(x) || \ + ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z')) +/* ARGSUSED */ +static int +str2ether(const char *instr, int lenstr, void *ent, char *buffer, int buflen) +{ + uchar_t *ether = (uchar_t *)ent; + char *host = buffer; + const char *p, *limit, *start; + ptrdiff_t i; + + p = instr; + limit = p + lenstr; + + /* skip beginning whitespace, if any */ + while (p < limit && isspace(*p)) + p++; + + if (ether) { /* parse ether */ + for (i = 0; i < 6; i++) { + int j = 0, n = 0; + + start = p; + while (p < limit && lisalnum(start[j])) { + /* don't worry about overflow here */ + n = 16 * n + DIGIT(start[j]); + j++; + p++; + } + if (*p != ':' && i < 5) { + return (NSS_STR_PARSE_PARSE); + } else { + p++; + *(ether + i) = (uchar_t)n; + } + } + } else { /* skip ether */ + while (p < limit && !isspace(*p)) + p++; + } + if (host) { /* parse host */ + while (p < limit && isspace(*p)) /* skip whitespace */ + p++; + start = p; + while (p < limit && !isspace(*p)) /* skip hostname */ + p++; + if ((i = (p - start)) < MAXHOSTNAMELEN) { + (void) memcpy(host, start, i); + host[i] = '\0'; + } else + return (NSS_STR_PARSE_ERANGE); /* failure */ + } + return (NSS_STR_PARSE_SUCCESS); +} + +typedef struct { + char ea_string[18]; + struct ether_addr ea_addr; +} eabuf_t; + +static eabuf_t * +ea_buf(void) +{ + static thread_key_t key; + static int key_once = 0; + static mutex_t tsd_lock = DEFAULTMUTEX; + static eabuf_t ea_main; + eabuf_t *eabuf = NULL; + + if (thr_main()) + return (&ea_main); + + if (key_once == 0) { + (void) mutex_lock(&tsd_lock); + if (key_once == 0) { + if (thr_keycreate(&key, free) != 0) { + (void) mutex_unlock(&tsd_lock); + return (NULL); + } + key_once = 1; + } + (void) mutex_unlock(&tsd_lock); + } + (void) thr_getspecific(key, (void **)&eabuf); + if (eabuf == NULL) { + eabuf = malloc(sizeof (eabuf_t)); + (void) thr_setspecific(key, eabuf); + } + return (eabuf); +} + +/* + * Converts a 48 bit ethernet number to its string representation. + */ +char * +ether_ntoa(const struct ether_addr *e) +{ + eabuf_t *eabuf; + char *s; + + if ((eabuf = ea_buf()) == NULL) + return (NULL); + s = eabuf->ea_string; + (void) sprintf(s, "%x:%x:%x:%x:%x:%x", + e->ether_addr_octet[0], e->ether_addr_octet[1], + e->ether_addr_octet[2], e->ether_addr_octet[3], + e->ether_addr_octet[4], e->ether_addr_octet[5]); + return (s); +} + +/* + * Converts an ethernet address representation back into its 48 bits. + */ +struct ether_addr * +ether_aton(const char *s) +{ + eabuf_t *eabuf; + struct ether_addr *e; + int i; + uint_t t[6]; + + if ((eabuf = ea_buf()) == NULL) + return (NULL); + e = &eabuf->ea_addr; + i = sscanf(s, " %x:%x:%x:%x:%x:%x", + &t[0], &t[1], &t[2], &t[3], &t[4], &t[5]); + if (i != 6) + return (NULL); + for (i = 0; i < 6; i++) + e->ether_addr_octet[i] = (uchar_t)t[i]; + return (e); +} diff --git a/usr/src/lib/libsocket/inet/getaddrinfo.c b/usr/src/lib/libsocket/inet/getaddrinfo.c new file mode 100644 index 0000000000..9d978a7496 --- /dev/null +++ b/usr/src/lib/libsocket/inet/getaddrinfo.c @@ -0,0 +1,806 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + +#include <netdb.h> +#include <arpa/inet.h> +#include <nss_dbdefs.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <stdlib.h> +#include <net/if.h> + +extern char *_dgettext(const char *, const char *); + +#define ai2sin(x) ((struct sockaddr_in *)((x)->ai_addr)) +#define ai2sin6(x) ((struct sockaddr_in6 *)((x)->ai_addr)) + +#define HOST_BROADCAST "255.255.255.255" + +/* + * getaddrinfo() returns EAI_NONAME in some cases, however + * since EAI_NONAME is not part of SUSv3 it needed to be + * masked in the standards compliant environment. + * GAIV_DEFAULT and GAIV_XPG6 accomplish this. + */ +#define GAIV_DEFAULT 0 +#define GAIV_XPG6 1 + +/* + * Storage allocation for global variables in6addr_any and + * in6addr_loopback. The extern declarations for these + * variables are defined in <netinet/in.h>. These two + * variables could have been defined in any of the "C" files + * in libsocket. They are defined here with other IPv6 + * related interfaces. + */ +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; + +/* AI_MASK: all valid flags for addrinfo */ +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \ + | AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL) +#define ANY 0 +/* function prototypes for used by getaddrinfo() routine */ +static int get_addr(int family, const char *hostname, struct addrinfo *aip, + struct addrinfo *cur, ushort_t port, int version); +static uint_t getscopeidfromzone(const struct sockaddr_in6 *sa, + const char *zone, uint32_t *sin6_scope_id); +static boolean_t str_isnumber(const char *p); + +/* + * getaddrinfo: + * + * Purpose: + * Routine for performing Address-to-nodename in a + * protocol-independent fashion. + * Description and history of the routine: + * Nodename-to-address translation is done in a protocol- + * independent fashion using the getaddrinfo() function + * that is taken from the IEEE POSIX 1003.1g. + * + * The official specification for this function will be the + * final POSIX standard, with the following additional + * requirements: + * + * - getaddrinfo() must be thread safe + * - The AI_NUMERICHOST is new. + * - All fields in socket address structures returned by + * + * getaddrinfo() that are not filled in through an explicit + * argument (e.g., sin6_flowinfo and sin_zero) must be set to 0. + * (This makes it easier to compare socket address structures). + * + * Input Parameters: + * nodename - pointer to null-terminated strings that represents + * a hostname or literal ip address (IPv4/IPv6) or this + * pointer can be NULL. + * servname - pointer to null-terminated strings that represents + * a servicename or literal port number or this + * pointer can be NULL. + * hints - optional argument that points to an addrinfo structure + * to provide hints on the type of socket that the caller + * supports. + * Possible setting of the ai_flags member of the hints structure: + * AI_PASSIVE - If set, the caller plans to use the returned socket + * address in a call to bind(). In this case, it the + * nodename argument is NULL, then the IP address portion + * of the socket address structure will be set to + * INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6. + * AI_PASSIVE - If not set, then the returned socket address will be + * ready for a call to connect() (for conn-oriented) or + * connect(), sendto(), or sendmsg() (for connectionless). + * In this case, if nodename is NULL, then the IP address + * portion of the socket address structure will be set to + * the loopback address. + * AI_CANONNAME - If set, then upon successful return the ai_canonname + * field of the first addrinfo structure in the linked + * list will point to a NULL-terminated string + * containing the canonical name of the specified nodename. + * AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric + * host address string. Otherwise an error of EAI_NONAME + * is returned. This flag prevents any type of name + * resolution service from being called. + * AI_NUMERICSERV - If set, then a non-null servname string supplied shall + * be a numeric port string. Otherwise, an [EAI_NONAME] + * error shall be returned. This flag shall prevent any + * type of name resolution service from being invoked. + * AI_V4MAPPED - If set, along with an ai_family of AF_INET6, then + * getaddrinfo() shall return IPv4-mapped IPv6 addresses + * on finding no matching IPv6 addresses ( ai_addrlen shall + * be 16). The AI_V4MAPPED flag shall be ignored unless + * ai_family equals AF_INET6. + * AI_ALL - If the AI_ALL flag is used with the AI_V4MAPPED flag, + * then getaddrinfo() shall return all matching IPv6 and + * IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED + * flag is ignored. + * Output Parameters: + * res - upon successful return a pointer to a linked list of one + * or more addrinfo structures is returned through this + * argument. The caller can process each addrinfo structures + * in this list by following the ai_next pointer, until a + * NULL pointer is encountered. In each returned addrinfo + * structure the three members ai_family, ai_socktype, and + * ai_protocol are corresponding arguments for a call to the + * socket() function. In each addrinfo structure the ai_addr + * field points to filled-in socket address structure whose + * length is specified by the ai_addrlen member. + * + * Return Value: + * This function returns 0 upon success or a nonzero error code. The + * following names are nonzero error codes from getaddrinfo(), and are + * defined in <netdb.h>. + * EAI_ADDRFAMILY - address family not supported + * EAI_AGAIN - DNS temporary failure + * EAI_BADFLAGS - invalid ai_flags + * EAI_FAIL - DNS non-recoverable failure + * EAI_FAMILY - ai_family not supported + * EAI_MEMORY - memory allocation failure + * EAI_NODATA - no address associated with nodename + * EAI_NONAME - host/servname not known + * EAI_SERVICE - servname not supported for ai_socktype + * EAI_SOCKTYPE - ai_socktype not supported + * EAI_SYSTEM - system error in errno + * + * Memory Allocation: + * All of the information returned by getaddrinfo() is dynamically + * allocated: the addrinfo structures, and the socket address + * structures and canonical node name strings pointed to by the + * addrinfo structures. + */ + + +static int +_getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res, int version) +{ + struct addrinfo *cur; + struct addrinfo *aip; + struct addrinfo ai; + int error; + ushort_t port; + + cur = &ai; + aip = &ai; + + aip->ai_flags = 0; + aip->ai_family = PF_UNSPEC; + aip->ai_socktype = 0; + aip->ai_protocol = 0; +#ifdef __sparcv9 + /* + * We need to clear _ai_pad to preserve binary + * compatibility with previously compiled 64-bit + * applications by guaranteeing the upper 32-bits + * are empty. + */ + aip->_ai_pad = 0; +#endif /* __sparcv9 */ + aip->ai_addrlen = 0; + aip->ai_canonname = NULL; + aip->ai_addr = NULL; + aip->ai_next = NULL; + port = 0; + + /* if nodename nor servname provided */ + if (hostname == NULL && servname == NULL) { + *res = NULL; + return (EAI_NONAME); + } + if (hints != NULL) { + /* check for bad flags in hints */ + if ((hints->ai_flags != 0) && (hints->ai_flags & ~AI_MASK)) { + *res = NULL; + return (EAI_BADFLAGS); + } + if ((hostname == NULL || *hostname == '\0') && + (hints->ai_flags & AI_CANONNAME)) { + *res = NULL; + return (EAI_BADFLAGS); + } + if (hints->ai_family != PF_UNSPEC && + hints->ai_family != PF_INET && + hints->ai_family != PF_INET6) { + *res = NULL; + return (EAI_FAMILY); + } + + (void) memcpy(aip, hints, sizeof (*aip)); +#ifdef __sparcv9 + /* + * We need to clear _ai_pad to preserve binary + * compatibility. See prior comment. + */ + aip->_ai_pad = 0; +#endif /* __sparcv9 */ + switch (aip->ai_socktype) { + case ANY: + switch (aip->ai_protocol) { + case ANY: + break; + case IPPROTO_UDP: + aip->ai_socktype = SOCK_DGRAM; + break; + case IPPROTO_TCP: + aip->ai_socktype = SOCK_STREAM; + break; + default: + aip->ai_socktype = SOCK_RAW; + break; + } + break; + case SOCK_RAW: + break; + case SOCK_DGRAM: + aip->ai_protocol = IPPROTO_UDP; + break; + case SOCK_STREAM: + aip->ai_protocol = IPPROTO_TCP; + break; + default: + *res = NULL; + return (EAI_SOCKTYPE); + } + } + + /* + * Get the service. + */ + + if (servname != NULL) { + struct servent result; + int bufsize = 128; + char *buf = NULL; + struct servent *sp; + char *proto = NULL; + + switch (aip->ai_socktype) { + case ANY: + proto = NULL; + break; + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + } + /* + * Servname string can be a decimal port number. + * If we already know the socket type there is no need + * to call getservbyport. + */ + if (aip->ai_flags & AI_NUMERICSERV) { + if (!str_isnumber(servname)) { + return (EAI_NONAME); + } + port = htons(atoi(servname)); + } else if (str_isnumber(servname)) { + port = htons(atoi(servname)); + if (aip->ai_socktype == ANY) { + do { + if (buf != NULL) + free(buf); + bufsize *= 2; + buf = malloc(bufsize); + if (buf == NULL) { + *res = NULL; + return (EAI_MEMORY); + } + + sp = getservbyport_r(port, proto, + &result, buf, bufsize); + if (sp == NULL && errno != ERANGE) { + free(buf); + *res = NULL; + return (EAI_SERVICE); + } + /* + * errno == ERANGE so our scratch buffer space + * wasn't big enough. Double it and try + * again. + */ + } while (sp == NULL); + } + } else { + do { + if (buf != NULL) + free(buf); + bufsize *= 2; + buf = malloc(bufsize); + if (buf == NULL) { + *res = NULL; + return (EAI_MEMORY); + } + + sp = getservbyname_r(servname, proto, &result, + buf, bufsize); + if (sp == NULL && errno != ERANGE) { + free(buf); + *res = NULL; + return (EAI_SERVICE); + } + /* + * errno == ERANGE so our scratch buffer space wasn't + * big enough. Double it and try again. + */ + } while (sp == NULL); + + port = sp->s_port; + } + if (aip->ai_socktype == ANY) { + if (aip->ai_flags & AI_NUMERICSERV) { + /* + * RFC 2553bis doesn't allow us to use the + * any resolver to find out if there is a + * match. We could walk the service file + * with *servent(). Given the commonality of + * calling getaddrinfo() with a number and + * ANY protocol we won't add that at this time. + */ + return (EAI_NONAME); + } + + if (strcmp(sp->s_proto, "udp") == 0) { + aip->ai_socktype = SOCK_DGRAM; + aip->ai_protocol = IPPROTO_UDP; + } else if (strcmp(sp->s_proto, "tcp") == 0) { + aip->ai_socktype = SOCK_STREAM; + aip->ai_protocol = IPPROTO_TCP; + } else { + if (buf != NULL) + free(buf); + + *res = NULL; + errno = EPROTONOSUPPORT; + return (EAI_SYSTEM); + } + } + + if (buf != NULL) + free(buf); + } + + /* + * hostname is NULL + * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or :: + * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1 + */ + + if (hostname == NULL) { + struct addrinfo *nai; + socklen_t addrlen; + char *canonname; + + if (aip->ai_family == PF_INET) + goto v4only; + /* create IPv6 addrinfo */ + nai = malloc(sizeof (struct addrinfo)); + if (nai == NULL) + goto nomem; + *nai = *aip; + addrlen = sizeof (struct sockaddr_in6); + nai->ai_addr = malloc(addrlen); + if (nai->ai_addr == NULL) { + freeaddrinfo(nai); + goto nomem; + } + bzero(nai->ai_addr, addrlen); + nai->ai_addrlen = addrlen; + nai->ai_family = PF_INET6; + nai->ai_protocol = 0; + nai->ai_canonname = NULL; + if (nai->ai_flags & AI_PASSIVE) { + ai2sin6(nai)->sin6_addr = in6addr_any; + } else { + ai2sin6(nai)->sin6_addr = in6addr_loopback; + if (nai->ai_flags & AI_CANONNAME) { + canonname = strdup("loopback"); + if (canonname == NULL) { + freeaddrinfo(nai); + goto nomem; + } + nai->ai_canonname = canonname; + } + } + ai2sin6(nai)->sin6_family = PF_INET6; + ai2sin6(nai)->sin6_port = port; + cur->ai_next = nai; + cur = nai; + if (aip->ai_family == PF_INET6) { + cur->ai_next = NULL; + goto success; + } + /* If address family is PF_UNSPEC or PF_INET */ +v4only: + /* create IPv4 addrinfo */ + nai = malloc(sizeof (struct addrinfo)); + if (nai == NULL) + goto nomem; + *nai = *aip; + addrlen = sizeof (struct sockaddr_in); + nai->ai_addr = malloc(addrlen); + if (nai->ai_addr == NULL) { + freeaddrinfo(nai); + goto nomem; + } + bzero(nai->ai_addr, addrlen); + nai->ai_addrlen = addrlen; + nai->ai_family = PF_INET; + nai->ai_protocol = 0; + nai->ai_canonname = NULL; + if (nai->ai_flags & AI_PASSIVE) { + ai2sin(nai)->sin_addr.s_addr = INADDR_ANY; + } else { + ai2sin(nai)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (nai->ai_flags & AI_CANONNAME && + nai->ai_family != PF_UNSPEC) { + canonname = strdup("loopback"); + if (canonname == NULL) { + freeaddrinfo(nai); + goto nomem; + } + nai->ai_canonname = canonname; + } + } + ai2sin(nai)->sin_family = PF_INET; + ai2sin(nai)->sin_port = port; + cur->ai_next = nai; + cur = nai; + cur->ai_next = NULL; + goto success; + } + + /* hostname string is a literal address or an alphabetical name */ + error = get_addr(aip->ai_family, hostname, aip, cur, port, version); + if (error) { + *res = NULL; + return (error); + } + +success: + *res = aip->ai_next; + return (0); + +nomem: + return (EAI_MEMORY); +} + +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT)); +} + +int +__xnet_getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6)); +} + +static int +get_addr(int family, const char *hostname, struct addrinfo *aip, struct + addrinfo *cur, ushort_t port, int version) +{ + struct hostent *hp; + char _hostname[MAXHOSTNAMELEN]; + int i, errnum; + struct addrinfo *nai; + int addrlen; + char *canonname; + boolean_t firsttime = B_TRUE; + boolean_t create_v6_addrinfo; + struct in_addr v4addr; + struct in6_addr v6addr; + struct in6_addr *v6addrp; + char *zonestr = NULL; + + /* + * Check for existence of address-zoneid delimiter '%' + * If the delimiter exists, parse the zoneid portion of + * <addr>%<zone_id> + */ + if ((zonestr = strchr(hostname, '%')) != NULL) { + /* make sure we have room for <addr> portion of hostname */ + if (((zonestr - hostname) + 1) > sizeof (_hostname)) { + return (EAI_MEMORY); + } + + /* chop off and save <zone_id> portion */ + (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1); + ++zonestr; /* make zonestr point at start of <zone-id> */ + /* ensure zone is valid */ + if ((*zonestr == '\0') || (strlen(zonestr) > LIFNAMSIZ)) { + return (EAI_NONAME); + } + } else { + size_t hlen = sizeof (_hostname); + + if (strlcpy(_hostname, hostname, hlen) >= hlen) { + return (EAI_MEMORY); + } + } + + /* Check to see if AI_NUMERICHOST bit is set */ + if (aip->ai_flags & AI_NUMERICHOST) { + /* check to see if _hostname points to a literal IP address */ + if (!((inet_addr(_hostname) != ((in_addr_t)-1)) || + (strcmp(_hostname, HOST_BROADCAST) == 0) || + (inet_pton(AF_INET6, _hostname, &v6addr) > 0))) { + return (EAI_NONAME); + } + } + + /* if hostname argument is literal, name service doesn't get called */ + if (family == PF_UNSPEC) { + hp = getipnodebyname(_hostname, AF_INET6, AI_ALL | + aip->ai_flags | AI_V4MAPPED, &errnum); + } else { + hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum); + } + + if (hp == NULL) { + switch (errnum) { + case HOST_NOT_FOUND: + return (EAI_NONAME); + case TRY_AGAIN: + return (EAI_AGAIN); + case NO_RECOVERY: + return (EAI_FAIL); + case NO_ADDRESS: + if (version == GAIV_XPG6) + return (EAI_NONAME); + return (EAI_NODATA); + default: + return (EAI_SYSTEM); + } + } + + for (i = 0; hp->h_addr_list[i]; i++) { + /* Determine if an IPv6 addrinfo structure should be created */ + create_v6_addrinfo = B_TRUE; + if (hp->h_addrtype == AF_INET6) { + v6addrp = (struct in6_addr *)hp->h_addr_list[i]; + if (!(aip->ai_flags & AI_V4MAPPED) && + IN6_IS_ADDR_V4MAPPED(v6addrp)) { + create_v6_addrinfo = B_FALSE; + IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr); + } + } else if (hp->h_addrtype == AF_INET) { + create_v6_addrinfo = B_FALSE; + (void) memcpy(&v4addr, hp->h_addr_list[i], + sizeof (struct in_addr)); + } else { + return (EAI_SYSTEM); + } + + if (create_v6_addrinfo) { + /* create IPv6 addrinfo */ + nai = malloc(sizeof (struct addrinfo)); + if (nai == NULL) + goto nomem; + *nai = *aip; + addrlen = sizeof (struct sockaddr_in6); + nai->ai_addr = malloc(addrlen); + if (nai->ai_addr == NULL) { + freeaddrinfo(nai); + goto nomem; + } + bzero(nai->ai_addr, addrlen); + nai->ai_addrlen = addrlen; + nai->ai_family = PF_INET6; + nai->ai_protocol = 0; + + (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr, + hp->h_addr_list[i], sizeof (struct in6_addr)); + nai->ai_canonname = NULL; + if ((nai->ai_flags & AI_CANONNAME) && firsttime) { + canonname = strdup(hp->h_name); + if (canonname == NULL) { + freeaddrinfo(nai); + goto nomem; + } + nai->ai_canonname = canonname; + firsttime = B_FALSE; + } + ai2sin6(nai)->sin6_family = PF_INET6; + ai2sin6(nai)->sin6_port = port; + /* set sin6_scope_id */ + if (zonestr != NULL) { + /* + * Translate 'zonestr' into a valid + * sin6_scope_id. + */ + if ((errnum = + getscopeidfromzone(ai2sin6(nai), zonestr, + &ai2sin6(nai)->sin6_scope_id)) != 0) { + return (errnum); + } + } else { + ai2sin6(nai)->sin6_scope_id = 0; + } + } else { + /* create IPv4 addrinfo */ + nai = malloc(sizeof (struct addrinfo)); + if (nai == NULL) + goto nomem; + *nai = *aip; + addrlen = sizeof (struct sockaddr_in); + nai->ai_addr = malloc(addrlen); + if (nai->ai_addr == NULL) { + freeaddrinfo(nai); + goto nomem; + } + bzero(nai->ai_addr, addrlen); + nai->ai_addrlen = addrlen; + nai->ai_family = PF_INET; + nai->ai_protocol = 0; + (void) memcpy(&(ai2sin(nai)->sin_addr.s_addr), + &v4addr, sizeof (struct in_addr)); + nai->ai_canonname = NULL; + if (nai->ai_flags & AI_CANONNAME && firsttime) { + canonname = strdup(hp->h_name); + if (canonname == NULL) { + freeaddrinfo(nai); + goto nomem; + } + nai->ai_canonname = canonname; + firsttime = B_FALSE; + } + ai2sin(nai)->sin_family = PF_INET; + ai2sin(nai)->sin_port = port; + } + + cur->ai_next = nai; + cur = nai; + } + cur->ai_next = NULL; + freehostent(hp); + return (0); + +nomem: + freehostent(hp); + return (EAI_MEMORY); + +} + +/* + * getscopeidfromzone(sa, zone, sin6_scope_id) + * + * Converts the string pointed to by 'zone' into a sin6_scope_id. + * 'zone' will either be a pointer to an interface name or will + * be a literal sin6_scope_id. + * + * 0 is returned on success and the output parameter 'sin6_scope_id' will + * be set to a valid sin6_scope_id. + * EAI_NONAME is returned for either of two reasons: + * 1. The IPv6 address pointed to by sa->sin6_addr is not + * part of the 'link scope' (ie link local, nodelocal multicast or + * linklocal multicast address) + * 2. The string pointed to by 'zone' can not be translate to a valid + * sin6_scope_id. + */ +static uint_t +getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone, + uint32_t *sin6_scope_id) { + const in6_addr_t *addr = &sa->sin6_addr; + ulong_t ul_scope_id; + char *endp; + + if (IN6_IS_ADDR_LINKSCOPE(addr)) { + /* + * Look up interface index associated with interface name + * pointed to by 'zone'. Since the address is part of the link + * scope, there is a one-to-one relationship between interface + * index and sin6_scope_id. + * If an interface index can not be found for 'zone', then + * treat 'zone' as a literal sin6_scope_id value. + */ + if ((*sin6_scope_id = if_nametoindex(zone)) != 0) { + return (0); + } else { + if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) { + /* check that entire string was read */ + if (*endp != '\0') { + return (EAI_NONAME); + } + *sin6_scope_id = + (uint32_t)(ul_scope_id & 0xffffffffUL); + } else { + return (EAI_NONAME); + } + } + } else { + return (EAI_NONAME); + } + return (0); +} + + +void +freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + if (ai->ai_addr) + free(ai->ai_addr); + free(ai); + ai = next; + } while (ai != NULL); +} + +static boolean_t +str_isnumber(const char *p) +{ + char *q = (char *)p; + while (*q) { + if (!isdigit(*q)) + return (B_FALSE); + q++; + } + return (B_TRUE); +} +static const char *gai_errlist[] = { + "name translation error 0 (no error)", /* 0 */ + "specified address family not supported", /* 1 EAI_ADDRFAMILY */ + "temporary name resolution failure", /* 2 EAI_AGAIN */ + "invalid flags", /* 3 EAI_BADFLAGS */ + "non-recoverable name resolution failure", /* 4 EAI_FAIL */ + "specified address family not supported", /* 5 EAI_FAMILY */ + "memory allocation failure", /* 6 EAI_MEMORY */ + "no address for the specified node name", /* 7 EAI_NODATA */ + "node name or service name not known", /* 8 EAI_NONAME */ + "service name not available for the specified socket type", + /* 9 EAI_SERVICE */ + "specified socket type not supported", /* 10 EAI_SOCKTYPE */ + "system error", /* 11 EAI_SYSTEM */ +}; +static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) }; + +const char * +gai_strerror(int ecode) +{ + if (ecode < 0) + return (_dgettext(TEXT_DOMAIN, + "name translation internal error")); + else if (ecode < gai_nerr) + return (_dgettext(TEXT_DOMAIN, gai_errlist[ecode])); + return (_dgettext(TEXT_DOMAIN, "unknown name translation error")); +} diff --git a/usr/src/lib/libsocket/inet/getnameinfo.c b/usr/src/lib/libsocket/inet/getnameinfo.c new file mode 100644 index 0000000000..3b707bb7f7 --- /dev/null +++ b/usr/src/lib/libsocket/inet/getnameinfo.c @@ -0,0 +1,378 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <ctype.h> +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <nss_dbdefs.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <net/if.h> + +#define sa2sin(x) ((struct sockaddr_in *)(x)) +#define sa2sin6(x) ((struct sockaddr_in6 *)(x)) + +#define NI_MASK (NI_NOFQDN | NI_NUMERICHOST | NI_NAMEREQD | NI_NUMERICSERV | \ + NI_DGRAM | NI_WITHSCOPEID) + +static int addzoneid(const struct sockaddr_in6 *sa, char *host, + size_t hostlen); +static size_t getzonestr(const struct sockaddr_in6 *sa, char *zonestr, + size_t zonelen); +static const char *_inet_ntop_native(); +/* + * getnameinfo: + * + * Purpose: + * Routine for performing Address-to-nodename in a + * protocol-independent fashion. + * Description: + * This function looks up an IP address and port number provided + * by the caller in the name service database and returns the nodename + * and servname respectively in the buffers provided by the caller. + * Input Parameters: + * sa - points to either a sockaddr_in structure (for + * IPv4) or a sockaddr_in6 structure (for IPv6). + * salen - length of the sockaddr_in or sockaddr_in6 structure. + * hostlen - length of caller supplied "host" buffer + * servlen - length of caller supplied "serv" buffer + * flags - changes default actions based on setting. + * Possible settings for "flags": + * NI_NOFQDN - Always return nodename portion of the fully-qualified + * domain name (FQDN). + * NI_NUMERICHOST - Always return numeric form of the host's + * address. + * NI_NAMEREQD - If hostname cannot be located in database, + * don't return numeric form of address - return + * an error instead. + * NI_NUMERICSERV - Always return numeric form of the service address + * instead of its name. + * NI_DGRAM - Specifies that the service is a datagram service, and + * causes getservbyport() to be called with a second + * argument of "udp" instead of its default "tcp". + * Output Parameters: + * host - return the nodename associcated with the IP address in the + * buffer pointed to by the "host" argument. + * serv - return the service name associated with the port number + * in the buffer pointed to by the "serv" argument. + * Return Value: + * This function indicates successful completion by a zero return + * value; a non-zero return value indicates failure. + */ +int +getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, socklen_t hostlen, + char *serv, socklen_t servlen, int flags) +{ + char *addr; + size_t alen, slen; + in_port_t port; + int errnum; + int err; + + /* Verify correctness of buffer lengths */ + if ((hostlen == 0) && (servlen == 0)) + return (EAI_FAIL); + /* Verify correctness of possible flag settings */ + if ((flags != 0) && (flags & ~NI_MASK)) + return (EAI_BADFLAGS); + if (sa == NULL) + return (EAI_ADDRFAMILY); + switch (sa->sa_family) { + case AF_INET: + addr = (char *)&sa2sin(sa)->sin_addr; + alen = sizeof (struct in_addr); + slen = sizeof (struct sockaddr_in); + port = (sa2sin(sa)->sin_port); /* network byte order */ + break; + case AF_INET6: + addr = (char *)&sa2sin6(sa)->sin6_addr; + alen = sizeof (struct in6_addr); + slen = sizeof (struct sockaddr_in6); + port = (sa2sin6(sa)->sin6_port); /* network byte order */ + break; + default: + return (EAI_FAMILY); + } + if (salen != slen) + return (EAI_FAIL); + /* + * Case 1: if Caller sets hostlen != 0, then + * fill in "host" buffer that user passed in + * with appropriate text string. + */ + if (hostlen != 0) { + if (flags & NI_NUMERICHOST) { + /* Caller wants the host's numeric address */ + if (inet_ntop(sa->sa_family, addr, + host, hostlen) == NULL) + return (EAI_SYSTEM); + } else { + struct hostent *hp; + + /* Caller wants the name of host */ + hp = getipnodebyaddr(addr, alen, sa->sa_family, + &errnum); + if (hp != NULL) { + if (flags & NI_NOFQDN) { + char *dot; + /* + * Caller doesn't want fully-qualified + * name. + */ + dot = strchr(hp->h_name, '.'); + if (dot != NULL) + *dot = '\0'; + } + if (strlen(hp->h_name) + 1 > hostlen) { + freehostent(hp); + return (EAI_OVERFLOW); + } + (void) strcpy(host, hp->h_name); + freehostent(hp); + } else { + /* + * Host's name cannot be located in the name + * service database. If NI_NAMEREQD is set, + * return error; otherwise, return host's + * numeric address. + */ + if (flags & NI_NAMEREQD) { + switch (errnum) { + case HOST_NOT_FOUND: + return (EAI_NONAME); + case TRY_AGAIN: + return (EAI_AGAIN); + case NO_RECOVERY: + return (EAI_FAIL); + case NO_ADDRESS: + return (EAI_NODATA); + default: + return (EAI_SYSTEM); + } + } + if (_inet_ntop_native(sa->sa_family, addr, + host, hostlen) == NULL) + return (EAI_SYSTEM); + } + } + + /* + * Check for a non-zero sin6_scope_id, indicating a + * zone-id needs to be appended to the resultant 'host' + * string. + */ + if ((sa->sa_family == AF_INET6) && + (sa2sin6(sa)->sin6_scope_id != 0)) { + /* + * According to draft-ietf-ipngwg-scoping-arch-XX, only + * non-global scope addresses can make use of the + * <addr>%<zoneid> format. This implemenation + * supports only link scope addresses, since the use of + * site-local addressing is not yet fully specified. + * If the address meets this criteria, attempt to add a + * zone-id to 'host'. If it does not, return + * EAI_NONAME. + */ + if (IN6_IS_ADDR_LINKSCOPE(&(sa2sin6(sa)->sin6_addr))) { + if ((err = addzoneid(sa2sin6(sa), host, + hostlen)) != 0) { + return (err); + } + } else { + return (EAI_NONAME); + } + } + } + /* + * Case 2: if Caller sets servlen != 0, then + * fill in "serv" buffer that user passed in + * with appropriate text string. + */ + if (servlen != 0) { + char port_buf[10]; + int portlen; + + if (flags & NI_NUMERICSERV) { + /* Caller wants the textual form of the port number */ + portlen = snprintf(port_buf, sizeof (port_buf), "%hu", + ntohs(port)); + if (servlen < portlen + 1) + return (EAI_OVERFLOW); + (void) strcpy(serv, port_buf); + } else { + struct servent *sp; + /* + * Caller wants the name of the service. + * If NI_DGRAM is set, get service name for + * specified port for udp. + */ + sp = getservbyport(port, + flags & NI_DGRAM ? "udp" : "tcp"); + if (sp != NULL) { + if (servlen < strlen(sp->s_name) + 1) + return (EAI_OVERFLOW); + (void) strcpy(serv, sp->s_name); + } else { + /* + * if service is not in the name server's + * database, fill buffer with numeric form for + * port number. + */ + portlen = snprintf(port_buf, sizeof (port_buf), + "%hu", ntohs(port)); + if (servlen < portlen + 1) + return (EAI_OVERFLOW); + (void) strcpy(serv, port_buf); + } + } + } + return (0); +} + +/* + * addzoneid(sa, host, hostlen) + * + * Appends a zone-id to the input 'host' string if the input sin6_scope_id + * is non-zero. The resultant 'host' string would be of the form + * 'host'%'zone-id'. Where 'zone-id' can be either an interface name or a + * literal interface index. + * + * Return Values: + * 0 - on success + * EAI_MEMORY - an error occured when forming the output string + */ +static int +addzoneid(const struct sockaddr_in6 *sa, char *host, size_t hostlen) +{ + char zonestr[LIFNAMSIZ]; + size_t zonelen; + size_t addrlen = strlen(host); + + /* make sure zonelen is valid sizeof (<addr>%<zoneid>\0) */ + if (((zonelen = getzonestr(sa, zonestr, sizeof (zonestr))) == 0) || + ((addrlen + 1 + zonelen + 1) > hostlen)) { + return (EAI_MEMORY); + } + + /* Create address string of form <addr>%<zoneid> */ + host[addrlen] = '%'; /* place address-zoneid delimiter */ + (void) strlcpy((host + addrlen + 1), zonestr, (zonelen + 1)); + return (0); +} + +/* + * getzonestr(sa, zonestr) + * + * parse zone string from input sockaddr_in6 + * + * Note: This function calls if_indextoname, a very poor interface, + * defined in RFC2553, for converting an interface index to an + * interface name. Callers of this function must be sure that + * zonestr is atleast LIFNAMSIZ in length, since this is the longest + * possible value if_indextoname will return. + * + * Return values: + * 0 an error with calling this function occured + * >0 zonestr is filled with a valid zoneid string and the return value is the + * length of that string. + */ +static size_t +getzonestr(const struct sockaddr_in6 *sa, char *zonestr, size_t zonelen) +{ + const in6_addr_t *addr; + uint32_t ifindex; + char *retstr; + + if (zonestr == NULL) { + return (0); + } + + addr = &sa->sin6_addr; + /* + * Since this implementation only supports link scope addresses, + * there is a one-to-one mapping between interface index and + * sin6_scope_id. + */ + ifindex = sa->sin6_scope_id; + + if ((retstr = if_indextoname(ifindex, zonestr)) != NULL) { + return (strlen(retstr)); + } else { + int n; + + /* + * Failed to convert ifindex into an interface name, + * simply return the literal value of ifindex as + * a string. + */ + if ((n = snprintf(zonestr, zonelen, "%u", + ifindex)) < 0) { + return (0); + } else { + if (n >= zonelen) { + return (0); + } + return (n); + } + } +} + + +/* + * This is a wrapper function for inet_ntop(). In case the af is AF_INET6 + * and the address pointed by src is a IPv4-mapped IPv6 address, it + * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases + * it behaves just like inet_ntop(). + */ +static const char * +_inet_ntop_native(int af, const void *src, char *dst, size_t size) +{ + struct in_addr src4; + const char *result; + + if (af == AF_INET6) { + if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)) { + IN6_V4MAPPED_TO_INADDR((struct in6_addr *)src, &src4); + result = inet_ntop(AF_INET, &src4, dst, size); + } else { + result = inet_ntop(AF_INET6, src, dst, size); + } + } else { + result = inet_ntop(af, src, dst, size); + } + + return (result); +} diff --git a/usr/src/lib/libsocket/inet/getnetent.c b/usr/src/lib/libsocket/inet/getnetent.c new file mode 100644 index 0000000000..194416a36c --- /dev/null +++ b/usr/src/lib/libsocket/inet/getnetent.c @@ -0,0 +1,86 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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) 1986-1992,2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <netdb.h> +#include <nss_dbdefs.h> + + +#ifdef NSS_INCLUDE_UNSAFE + +/* + * Ye olde non-reentrant interface (MT-unsafe, caveat utor) + */ + +/* + * Don't free this, even on an endnetent(), because bitter experience shows + * that there's production code that does getXXXbyYYY(), then endXXXent(), + * and then continues to use the pointer it got back. + */ +static nss_XbyY_buf_t *buffer; +#define GETBUF() \ +NSS_XbyY_ALLOC(&buffer, (int)sizeof (struct netent), NSS_BUFLEN_NETWORKS) + /* === ?? set ENOMEM on failure? */ + +struct netent * +getnetbyname(const char *nam) +{ + nss_XbyY_buf_t *b; + struct netent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getnetbyname_r(nam, b->result, b->buffer, b->buflen); + } + return (res); +} + +struct netent * +getnetbyaddr(in_addr_t net, int type) +{ + nss_XbyY_buf_t *b; + struct netent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getnetbyaddr_r(net, type, b->result, + b->buffer, b->buflen); + } + return (res); +} + +struct netent * +getnetent(void) +{ + nss_XbyY_buf_t *b; + struct netent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getnetent_r(b->result, b->buffer, b->buflen); + } + return (res); +} + +#endif /* NSS_INCLUDE_UNSAFE */ diff --git a/usr/src/lib/libsocket/inet/getnetent_r.c b/usr/src/lib/libsocket/inet/getnetent_r.c new file mode 100644 index 0000000000..1484809b15 --- /dev/null +++ b/usr/src/lib/libsocket/inet/getnetent_r.c @@ -0,0 +1,215 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 1986-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <nss_dbdefs.h> + + +static int str2netent(const char *, int, void *, char *, int); + +static int net_stayopen; +/* + * Unsynchronized, but it affects only + * efficiency, not correctness + */ + +static DEFINE_NSS_DB_ROOT(db_root); +static DEFINE_NSS_GETENT(context); + +static void +_nss_initf_net(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_NETWORKS; + p->default_config = NSS_DEFCONF_NETWORKS; +} + +struct netent * +getnetbyname_r(const char *name, struct netent *result, + char *buffer, int buflen) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2netent); + arg.key.name = name; + arg.stayopen = net_stayopen; + res = nss_search(&db_root, _nss_initf_net, + NSS_DBOP_NETWORKS_BYNAME, &arg); + arg.status = res; + (void) NSS_XbyY_FINI(&arg); + return ((struct netent *)arg.returnval); +} + +struct netent * +getnetbyaddr_r(long net, int type, struct netent *result, + char *buffer, int buflen) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2netent); + arg.key.netaddr.net = (uint32_t)net; + arg.key.netaddr.type = type; + arg.stayopen = net_stayopen; + res = nss_search(&db_root, _nss_initf_net, + NSS_DBOP_NETWORKS_BYADDR, &arg); + arg.status = res; + (void) NSS_XbyY_FINI(&arg); + return ((struct netent *)arg.returnval); +} + +int +setnetent(int stay) +{ + net_stayopen |= stay; /* === Or maybe just "=" ? */ + nss_setent(&db_root, _nss_initf_net, &context); + return (0); +} + +int +endnetent() +{ + net_stayopen = 0; + nss_endent(&db_root, _nss_initf_net, &context); + nss_delete(&db_root); + return (0); +} + +struct netent * +getnetent_r(struct netent *result, char *buffer, int buflen) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2netent); + /* No stayopen flag; of course you stay open for iteration */ + res = nss_getent(&db_root, _nss_initf_net, &context, &arg); + arg.status = res; + (void) NSS_XbyY_FINI(&arg); + return ((struct netent *)arg.returnval); +} + +/* + * Return values: 0 = success, 1 = parse error, 2 = erange ... + * The structure pointer passed in is a structure in the caller's space + * wherein the field pointers would be set to areas in the buffer if + * need be. instring and buffer should be separate areas. + */ +static int +str2netent(const char *instr, int lenstr, + void *ent /* really (struct netnet *) */, char *buffer, int buflen) +{ + struct netent *net = (struct netent *)ent; + const char *p, *numstart, *limit, *namestart; + int namelen = 0; + ptrdiff_t numlen; + char numbuf[16]; + + if ((instr >= buffer && (buffer + buflen) > instr) || + (buffer >= instr && (instr + lenstr) > buffer)) { + return (NSS_STR_PARSE_PARSE); + } + + p = instr; + limit = p + lenstr; + + while (p < limit && isspace(*p)) { + p++; + } + namestart = p; + while (p < limit && !isspace(*p)) { + p++; /* Skip over the canonical name */ + } + namelen = (int)(p - namestart); + + if (buflen <= namelen) { /* not enough buffer */ + return (NSS_STR_PARSE_ERANGE); + } + (void) memcpy(buffer, namestart, namelen); + buffer[namelen] = '\0'; + net->n_name = buffer; + + while (p < limit && isspace(*p)) { + p++; + } + if (p >= limit) { + /* Syntax error -- no net number */ + return (NSS_STR_PARSE_PARSE); + } + numstart = p; + do { + p++; /* Find the end of the net number */ + } while (p < limit && !isspace(*p)); + numlen = p - numstart; + if (numlen >= (ptrdiff_t)sizeof (numbuf)) { + /* Syntax error -- supposed number is too long */ + return (NSS_STR_PARSE_PARSE); + } + (void) memcpy(numbuf, numstart, numlen); + numbuf[numlen] = '\0'; + net->n_net = inet_network(numbuf); + if (net->n_net == (in_addr_t)-1) { + /* inet_network failed to parse the string */ + return (NSS_STR_PARSE_PARSE); + } + + net->n_addrtype = AF_INET; + + while (p < limit && isspace(*p)) { + p++; + } + /* + * Although nss_files_XY_all calls us with # stripped, + * we should be able to deal with it here in order to + * be more useful. + */ + if (p >= limit || *p == '#') { /* no aliases, no problem */ + char **ptr; + + ptr = (char **)ROUND_UP(buffer + namelen + 1, + sizeof (char *)); + if ((char *)ptr >= buffer + buflen) { + net->n_aliases = 0; /* hope they don't try to peek in */ + return (NSS_STR_PARSE_ERANGE); + } else { + *ptr = 0; + net->n_aliases = ptr; + return (NSS_STR_PARSE_SUCCESS); + } + } + net->n_aliases = _nss_netdb_aliases(p, lenstr - (int)(p - instr), + buffer + namelen + 1, buflen - namelen - 1); + return (NSS_STR_PARSE_SUCCESS); +} diff --git a/usr/src/lib/libsocket/inet/getprotoent.c b/usr/src/lib/libsocket/inet/getprotoent.c new file mode 100644 index 0000000000..c19398e963 --- /dev/null +++ b/usr/src/lib/libsocket/inet/getprotoent.c @@ -0,0 +1,86 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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) 1986-1992,2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <netdb.h> +#include <nss_dbdefs.h> + + +#ifdef NSS_INCLUDE_UNSAFE + +/* + * Ye olde non-reentrant interface (MT-unsafe, caveat utor) + */ + +/* + * Don't free this, even on an endprotoent(), because bitter experience shows + * that there's production code that does getXXXbyYYY(), then endXXXent(), + * and then continues to use the pointer it got back. + */ +static nss_XbyY_buf_t *buffer; +#define GETBUF() \ +NSS_XbyY_ALLOC(&buffer, (int)sizeof (struct protoent), NSS_BUFLEN_PROTOCOLS) + /* === ?? set ENOMEM on failure? */ + +struct protoent * +getprotobyname(const char *nam) +{ + nss_XbyY_buf_t *b; + struct protoent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getprotobyname_r(nam, b->result, b->buffer, b->buflen); + } + return (res); +} + +struct protoent * +getprotobynumber(int proto) +{ + nss_XbyY_buf_t *b; + struct protoent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getprotobynumber_r(proto, b->result, + b->buffer, b->buflen); + } + return (res); +} + +struct protoent * +getprotoent() +{ + nss_XbyY_buf_t *b; + struct protoent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getprotoent_r(b->result, b->buffer, b->buflen); + } + return (res); +} + +#endif /* NSS_INCLUDE_UNSAFE */ diff --git a/usr/src/lib/libsocket/inet/getprotoent_r.c b/usr/src/lib/libsocket/inet/getprotoent_r.c new file mode 100644 index 0000000000..e1cb1c7f0b --- /dev/null +++ b/usr/src/lib/libsocket/inet/getprotoent_r.c @@ -0,0 +1,209 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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) 1986-1992 by Sun Microsystems Inc. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <ctype.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <nss_dbdefs.h> + +static int str2protoent(const char *, int, void *, + char *, int); + +static int proto_stayopen; +/* + * Unsynchronized, but it affects only + * efficiency, not correctness + */ + +static DEFINE_NSS_DB_ROOT(db_root); +static DEFINE_NSS_GETENT(context); + +static void +_nss_initf_proto(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PROTOCOLS; + p->default_config = NSS_DEFCONF_PROTOCOLS; +} + +struct protoent * +getprotobyname_r(const char *name, struct protoent *result, + char *buffer, int buflen) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent); + arg.key.name = name; + arg.stayopen = proto_stayopen; + res = nss_search(&db_root, _nss_initf_proto, + NSS_DBOP_PROTOCOLS_BYNAME, &arg); + arg.status = res; + (void) NSS_XbyY_FINI(&arg); + return ((struct protoent *)arg.returnval); +} + +struct protoent * +getprotobynumber_r(int proto, struct protoent *result, char *buffer, int buflen) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent); + arg.key.number = proto; + arg.stayopen = proto_stayopen; + res = nss_search(&db_root, _nss_initf_proto, + NSS_DBOP_PROTOCOLS_BYNUMBER, &arg); + arg.status = res; + (void) NSS_XbyY_FINI(&arg); + return ((struct protoent *)arg.returnval); +} + +int +setprotoent(int stay) +{ + proto_stayopen = stay; + nss_setent(&db_root, _nss_initf_proto, &context); + return (0); +} + +int +endprotoent() +{ + proto_stayopen = 0; + nss_endent(&db_root, _nss_initf_proto, &context); + nss_delete(&db_root); + return (0); +} + +struct protoent * +getprotoent_r(struct protoent *result, char *buffer, int buflen) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent); + /* No stayopen flag; of course you stay open for iteration */ + res = nss_getent(&db_root, _nss_initf_proto, &context, &arg); + arg.status = res; + (void) NSS_XbyY_FINI(&arg); + return ((struct protoent *)arg.returnval); +} + +/* + * Return values: 0 = success, 1 = parse error, 2 = erange ... + * The structure pointer passed in is a structure in the caller's space + * wherein the field pointers would be set to areas in the buffer if + * need be. instring and buffer should be separate areas. Let's not + * fight over crumbs. + */ +static int +str2protoent(const char *instr, int lenstr, + void *ent /* it is really (struct protoent *) */, + char *buffer, int buflen) +{ + struct protoent *proto = (struct protoent *)ent; + const char *p, *numstart, *namestart, *limit; + int numlen, namelen = 0; + char numbuf[16]; + char *numend; + + if ((instr >= buffer && (buffer + buflen) > instr) || + (buffer >= instr && (instr + lenstr) > buffer)) { + return (NSS_STR_PARSE_PARSE); + } + + p = instr; + limit = p + lenstr; + + while (p < limit && isspace(*p)) { + p++; + } + namestart = p; + while (p < limit && !isspace(*p)) { + p++; /* Skip over the canonical name */ + } + namelen = (int)(p - namestart); + + if (buflen <= namelen) { /* not enough buffer */ + return (NSS_STR_PARSE_ERANGE); + } + (void) memcpy(buffer, namestart, namelen); + buffer[namelen] = '\0'; + proto->p_name = buffer; + + while (p < limit && isspace(*p)) { + p++; + } + if (p >= limit) { + /* Syntax error -- no proto number */ + return (NSS_STR_PARSE_PARSE); + } + numstart = p; + do { + p++; /* Find the end of the proto number */ + } while (p < limit && !isspace(*p)); + numlen = (int)(p - numstart); + if (numlen >= (int)sizeof (numbuf)) { + /* Syntax error -- supposed number is too long */ + return (NSS_STR_PARSE_PARSE); + } + (void) memcpy(numbuf, numstart, (size_t)numlen); + numbuf[numlen] = '\0'; + proto->p_proto = (int)strtol(numbuf, &numend, 10); + if (*numend != '\0') { + /* Syntax error -- protocol number isn't a number */ + return (NSS_STR_PARSE_PARSE); + } + + while (p < limit && isspace(*p)) { + p++; + } + /* + * Although nss_files_XY_all calls us with # stripped, + * we should be able to deal with it here in order to + * be more useful. + */ + if (p >= limit || *p == '#') { /* no aliases, no problem */ + char **ptr; + + ptr = (char **)ROUND_UP(buffer + namelen + 1, + sizeof (char *)); + if ((char *)ptr >= buffer + buflen) { + /* hope they don't try to peek in */ + proto->p_aliases = 0; + return (NSS_STR_PARSE_ERANGE); + } else { + *ptr = 0; + proto->p_aliases = ptr; + return (NSS_STR_PARSE_SUCCESS); + } + } + proto->p_aliases = _nss_netdb_aliases(p, lenstr - (int)(p - instr), + buffer + namelen + 1, buflen - namelen - 1); + return (NSS_STR_PARSE_SUCCESS); +} diff --git a/usr/src/lib/libsocket/inet/getservbyname_r.c b/usr/src/lib/libsocket/inet/getservbyname_r.c new file mode 100644 index 0000000000..4af830e51d --- /dev/null +++ b/usr/src/lib/libsocket/inet/getservbyname_r.c @@ -0,0 +1,124 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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) 1991-1994 Sun Microsystems, Inc + * + * lib/libsocket/inet/getservbyname_r.c + * + * getservbyname_r() is defined in this file. It is implemented on top of + * _get_hostserv_inetnetdir_byname() which is also used to implement + * netdir_getbyname() for inet family transports. In turn the common code + * uses the name service switch policy for "hosts" and "services" unless + * the administrator chooses to bypass the name service switch by + * specifying third-party supplied nametoaddr libs for inet transports + * in /etc/netconfig. + * + * getservbyport_r() is similarly related to _get_hostserv_inetnetdir_byaddr() + * and netdir_getbyaddr(); + * + * The common code lives in lib/libnsl/nss/netdir_inet.c. + * + * getservent_r(), setservent() and endservent() are *not* implemented on top + * of the common interface; they go straight to the switch and are + * defined in getservent_r.c. + * + * There is absolutely no data sharing, not even the stayopen flag or + * enumeration state, between getservbyYY_r() and getservent_r(); + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <netdb.h> +#include <netdir.h> +#include <sys/types.h> +#include <nss_netdir.h> + +extern int str2servent(const char *, int, void *, char *, int); +extern struct netconfig *__rpc_getconfip(); + +struct servent * +getservbyname_r(const char *name, const char *proto, struct servent *result, + char *buffer, int buflen) +{ + struct netconfig *nconf; + struct nss_netdirbyname_in nssin; + union nss_netdirbyname_out nssout; + int neterr; + + if ((nconf = __rpc_getconfip("udp")) == NULL && + (nconf = __rpc_getconfip("tcp")) == NULL) { + return ((struct servent *)NULL); + } + nssin.op_t = NSS_SERV; + nssin.arg.nss.serv.name = name; + nssin.arg.nss.serv.proto = proto; + nssin.arg.nss.serv.buf = buffer; + nssin.arg.nss.serv.buflen = buflen; + + nssout.nss.serv = result; + + /* + * We pass in nconf and let the implementation of the long-named func + * decide whether to use the switch based on nc_nlookups. + */ + neterr = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout); + + (void) freenetconfigent(nconf); + if (neterr != ND_OK) { + return ((struct servent *)NULL); + } + return (nssout.nss.serv); +} + +struct servent * +getservbyport_r(int port, const char *proto, struct servent *result, + char *buffer, int buflen) +{ + struct netconfig *nconf; + struct nss_netdirbyaddr_in nssin; + union nss_netdirbyaddr_out nssout; + int neterr; + + if ((nconf = __rpc_getconfip("udp")) == NULL && + (nconf = __rpc_getconfip("tcp")) == NULL) { + return ((struct servent *)NULL); + } + nssin.op_t = NSS_SERV; + nssin.arg.nss.serv.port = port; + nssin.arg.nss.serv.proto = proto; + nssin.arg.nss.serv.buf = buffer; + nssin.arg.nss.serv.buflen = buflen; + + nssout.nss.serv = result; + + /* + * We pass in nconf and let the implementation of this long-named func + * decide whether to use the switch based on nc_nlookups. + */ + neterr = _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); + + (void) freenetconfigent(nconf); + if (neterr != ND_OK) { + return ((struct servent *)NULL); + } + return (nssout.nss.serv); +} diff --git a/usr/src/lib/libsocket/inet/getservent.c b/usr/src/lib/libsocket/inet/getservent.c new file mode 100644 index 0000000000..9dfb4215a8 --- /dev/null +++ b/usr/src/lib/libsocket/inet/getservent.c @@ -0,0 +1,86 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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) 1986-1994,2001 by Sun Microsystems, Inc. + * All rights reserved. + * + * Ye olde non-reentrant interface (MT-unsafe, caveat utor) + * + * lib/libsocket/inet/getservent.c + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <netdb.h> +#include <nss_dbdefs.h> + +#ifdef NSS_INCLUDE_UNSAFE + +/* + * Don't free this, even on an endservent(), because bitter experience shows + * that there's production code that does getXXXbyYYY(), then endXXXent(), + * and then continues to use the pointer it got back. + */ +static nss_XbyY_buf_t *buffer; +#define GETBUF() \ +NSS_XbyY_ALLOC(&buffer, (int)sizeof (struct servent), NSS_BUFLEN_SERVICES) + /* === ?? set ENOMEM on failure? */ + +struct servent * +getservbyname(const char *nam, const char *proto) +{ + nss_XbyY_buf_t *b; + struct servent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getservbyname_r(nam, proto, + b->result, b->buffer, b->buflen); + } + return (res); +} + +struct servent * +getservbyport(int port, const char *proto) +{ + nss_XbyY_buf_t *b; + struct servent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getservbyport_r(port, proto, + b->result, b->buffer, b->buflen); + } + return (res); +} + +struct servent * +getservent(void) +{ + nss_XbyY_buf_t *b; + struct servent *res = 0; + + if ((b = GETBUF()) != 0) { + res = getservent_r(b->result, b->buffer, b->buflen); + } + return (res); +} + +#endif /* NSS_INCLUDE_UNSAFE */ diff --git a/usr/src/lib/libsocket/inet/getservent_r.c b/usr/src/lib/libsocket/inet/getservent_r.c new file mode 100644 index 0000000000..6eb9ff49a2 --- /dev/null +++ b/usr/src/lib/libsocket/inet/getservent_r.c @@ -0,0 +1,100 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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) 1986-1994 by Sun Microsystems Inc. + * + * lib/libsocket/inet/getservent_r.c + * + * This file defines and implements the re-entrant enumeration routines for + * services: setservent(), getservent_r(), and endservent(). They consult + * the switch policy directly and do not "share" their enumeration state + * nor the stayopen flag with the implentation of the more common + * getservbyname_r()/getservbyport_r(). The latter follows a tortuous + * route in order to be consistent with netdir_getbyYY() (see + * getservbyname_r.c and lib/libnsl/nss/netdir_inet.c). + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <nss_dbdefs.h> + +/* + * str2servent is implemented in libnsl, libnsl/nss/netdir_inet.c, since + * the "engine" of the new gethost/getserv/netdir lives in libnsl. + */ +int str2servent(const char *, int, void *, char *, int); + +/* + * Unsynchronized, but it affects only + * efficiency, not correctness. + */ +static int services_stayopen; +static DEFINE_NSS_DB_ROOT(db_root); +static DEFINE_NSS_GETENT(context); + +static void +_nss_initf_services(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_SERVICES; + p->default_config = NSS_DEFCONF_SERVICES; +} + +int +setservent(int stay) +{ + services_stayopen |= stay; + nss_setent(&db_root, _nss_initf_services, &context); + return (0); +} + +int +endservent() +{ + services_stayopen = 0; + nss_endent(&db_root, _nss_initf_services, &context); + nss_delete(&db_root); + return (0); +} + +struct servent * +getservent_r(struct servent *result, char *buffer, int buflen) +{ + nss_XbyY_args_t arg; + nss_status_t res; + + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); + /* + * Setting proto to NULL here is a bit of a hack since we share + * the parsing code in the NIS+ backend with our getservbyYY() + * brethren who can search on 1-1/2 key. If they pass a NULL + * proto, the parsing code deals with it by picking the protocol + * from the first NIS+ matching object and combining all entries + * with "that" proto field. NIS+ is the only name service, so far, + * that can return multiple entries on a lookup. + */ + arg.key.serv.proto = NULL; + /* === No stayopen flag; of course you stay open for iteration */ + res = nss_getent(&db_root, _nss_initf_services, &context, &arg); + arg.status = res; + return (struct servent *)NSS_XbyY_FINI(&arg); +} diff --git a/usr/src/lib/libsocket/inet/inet6_opt.c b/usr/src/lib/libsocket/inet/inet6_opt.c new file mode 100644 index 0000000000..42b923c5b3 --- /dev/null +++ b/usr/src/lib/libsocket/inet/inet6_opt.c @@ -0,0 +1,300 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This code is conformant to RFC 3542. + */ + +#include <assert.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sysmacros.h> +#include <netinet/in.h> +#include <netinet/ip6.h> + +#include <stdio.h> + +#define bufpos(p) ((p) - (uint8_t *)extbuf) + +/* + * Section 10.1 RFC3542. This function returns the size of the empty + * extension header. If extbuf is not NULL then it initializes its length + * field. If extlen is invalid then -1 is returned. + */ +int +inet6_opt_init(void *extbuf, socklen_t extlen) +{ + if (extbuf && ((extlen < 0) || (extlen % 8))) { + return (-1); + } + + if (extbuf) { + *(uint8_t *)extbuf = 0; + *((uint8_t *)extbuf + 1) = extlen/8 - 1; + } + + return (2); +} + +/* + * Section 10.2 RFC3542. This function appends an option to an already + * initialized option buffer. inet6_opt_append() returns the total length + * after adding the option. + */ +int +inet6_opt_append(void *extbuf, socklen_t extlen, int offset, uint8_t type, + socklen_t len, uint_t align, void **databufp) +{ + uint8_t *p; + socklen_t endlen; + int remainder, padbytes; + + if (align > len || + (align != 1 && align != 2 && align != 4 && align != 8) || + len < 0 || len > 255 || type < 2) { + return (-1); + } + + if (extbuf) { + /* + * The length of the buffer is the minimum of the length + * passed in and the length stamped onto the buffer. The + * length stamped onto the buffer is the number of 8 byte + * octets in the buffer minus 1. + */ + extlen = MIN(extlen, (*((uint8_t *)extbuf + 1) + 1) * 8); + } + + remainder = (offset + 2 + len) % align; + if (remainder == 0) { + padbytes = 0; + } else { + padbytes = align - remainder; + } + + endlen = offset + padbytes + 2 + len; + if ((endlen > extlen) || !extbuf) { + if (extbuf) { + return (-1); + } else { + return (endlen); + } + } + + p = (uint8_t *)extbuf + offset; + if (padbytes != 0) { + /* + * Pad out the buffer here with pad options. If its only + * one byte then there is a special TLV with no L or V, just + * a zero to say skip this byte. For two bytes or more + * we have a special TLV with type 0 and length the number of + * padbytes. + */ + if (padbytes == 1) { + *p = IP6OPT_PAD1; + } else { + *p = IP6OPT_PADN; + *(p + 1) = padbytes - 2; + memset(p + 2, 0, padbytes - 2); + } + p += padbytes; + } + + *p++ = type; + *p++ = len; + if (databufp) { + *databufp = p; + } + return (endlen); +} + +/* + * Section 10.3 RFC3542. This function returns the updated total length. + * This functions inserts pad options to complete the option header as + * needed. + */ +int +inet6_opt_finish(void *extbuf, socklen_t extlen, int offset) +{ + uint8_t *p; + int padbytes; + + if (extbuf) { + /* + * The length of the buffer is the minimum of the length + * passed in and the length stamped onto the buffer. The + * length stamped onto the buffer is the number of 8 byte + * octets in the buffer minus 1. + */ + extlen = MIN(extlen, (*((uint8_t *)extbuf + 1) + 1) * 8); + } + + padbytes = 8 - (offset % 8); + if (padbytes == 8) + padbytes = 0; + + if ((offset + padbytes > extlen) || !extbuf) { + if (extbuf) { + return (-1); + } else { + return (offset + padbytes); + } + } + + p = (uint8_t *)extbuf + offset; + if (padbytes != 0) { + /* + * Pad out the buffer here with pad options. If its only + * one byte then there is a special TLV with no L or V, just + * a zero to say skip this byte. For two bytes or more + * we have a special TLV with type 0 and length the number of + * padbytes. + */ + if (padbytes == 1) { + *p = IP6OPT_PAD1; + } else { + *p = IP6OPT_PADN; + *(p + 1) = padbytes - 2; + memset(p + 2, 0, padbytes - 2); + } + p += padbytes; + } + + return (offset + padbytes); +} + +/* + * Section 10.4 RFC3542. Ths function takes a pointer to the data as + * returned by inet6_opt_append and inserts the data. + */ +int +inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen) +{ + memcpy((uint8_t *)databuf + offset, val, vallen); + return (offset + vallen); +} + +/* + * Section 10.5 RFC 3542. Starting walking the option header offset into the + * header. Returns where we left off. You take the output of this function + * and pass it back in as offset to iterate. -1 is returned on error. + * + * We use the fact that the first unsigned 8 bit quantity in the option + * header is the type and the second is the length. + */ +int +inet6_opt_next(void *extbuf, socklen_t extlen, int offset, uint8_t *typep, + socklen_t *lenp, void **databufp) +{ + uint8_t *p; + uint8_t *end; + + /* + * The length of the buffer is the minimum of the length + * passed in and the length stamped onto the buffer. The + * length stamped onto the buffer is the number of 8 byte + * octets in the buffer minus 1. + */ + extlen = MIN(extlen, (*((uint8_t *)extbuf + 1) + 1) * 8); + end = (uint8_t *)extbuf + extlen; + if (offset == 0) { + offset = 2; + } + + /* assumption: IP6OPT_PAD1 == 0 and IP6OPT_PADN == 1 */ + p = (uint8_t *)extbuf + offset; + while (*p == IP6OPT_PAD1 || *p == IP6OPT_PADN) { + switch (*p) { + case IP6OPT_PAD1: + p++; + break; + case IP6OPT_PADN: + /* *(p + 1) is the length of the option. */ + if (p + 2 + *(p + 1) >= end) + return (-1); + p += *(p + 1) + 2; + break; + } + } + + /* type, len, and data must fit... */ + if ((p + 2 >= end) || (p + 2 + *(p + 1) > end)) { + return (-1); + } + + if (typep) { + *typep = *p; + } + if (lenp) { + *lenp = *(p + 1); + } + if (databufp) { + *databufp = p + 2; + } + + return ((p - (uint8_t *)extbuf) + 2 + *lenp); +} + +/* + * Section 10.6 RFC 3542. Starting walking the option header offset into the + * header. Returns where we left off. You take the output of this function + * and pass it back in as offset to iterate. -1 is returned on error. + * + * We use the fact that the first unsigned 8 bit quantity in the option + * header is the type and the second is the length. + */ +int +inet6_opt_find(void *extbuf, socklen_t extlen, int offset, uint8_t type, + socklen_t *lenp, void **databufp) +{ + uint8_t newtype; + + do { + offset = inet6_opt_next(extbuf, extlen, offset, &newtype, lenp, + databufp); + + if (offset == -1) + return (-1); + } while (newtype != type); + + /* value to feed back into inet6_opt_find() as offset */ + return (offset); +} + +/* + * Section 10.7 RFC 3542. databuf should be a pointer as returned by + * inet6_opt_next or inet6_opt_find. The data is extracted from the option + * at that point. + */ +int +inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen) +{ + memcpy(val, (uint8_t *)databuf + offset, vallen); + return (offset + vallen); +} diff --git a/usr/src/lib/libsocket/inet/inet6_rthdr.c b/usr/src/lib/libsocket/inet/inet6_rthdr.c new file mode 100644 index 0000000000..4134f8a196 --- /dev/null +++ b/usr/src/lib/libsocket/inet/inet6_rthdr.c @@ -0,0 +1,180 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2003 Sun Microsystems, Inc. + * All rights reserved. Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This code is conformant to revision 7 of 2292bis. Some of these functions + * were provided (named inet6_rthdr_) in a very similar form in RFC 2292. + * The RFC 2292 variants are not supported. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <unistd.h> +#include <errno.h> + +#define MAX_RTHDR0_SEGMENTS 127 + +/* + * Return amount of space needed to hold N segments for the specified + * routing type. Does NOT include space for cmsghdr. + */ +socklen_t +inet6_rth_space(int type, int segments) +{ + if (type != IPV6_RTHDR_TYPE_0 || segments < 0 || + segments > MAX_RTHDR0_SEGMENTS) + return (0); + + return (sizeof (struct ip6_rthdr0) + + segments * sizeof (struct in6_addr)); +} + +/* + * Initializes rthdr structure. Verifies the segments against the length of + * the buffer. + * Note that a routing header can only hold 127 segments since the length field + * in the header is just a byte. + */ +void * +inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments) +{ + struct ip6_rthdr0 *rthdr; + + if (type != IPV6_RTHDR_TYPE_0 || segments < 0 || + segments > MAX_RTHDR0_SEGMENTS) + return (NULL); + + if (bp_len < sizeof (struct ip6_rthdr0) + + segments * sizeof (struct in6_addr)) + return (NULL); + + rthdr = (struct ip6_rthdr0 *)bp; + rthdr->ip6r0_nxt = 0; + rthdr->ip6r0_len = (segments * 2); + rthdr->ip6r0_type = type; + rthdr->ip6r0_segleft = 0; /* Incremented by rthdr_add */ + *(uint32_t *)&rthdr->ip6r0_reserved = 0; + return (bp); +} + +/* + * Add one more address to the routing header. Fails when there is no more + * room. + */ +int +inet6_rth_add(void *bp, const struct in6_addr *addr) +{ + struct ip6_rthdr0 *rthdr; + struct in6_addr *addrs; + + rthdr = (struct ip6_rthdr0 *)bp; + if ((rthdr->ip6r0_segleft + 1) * 2 > rthdr->ip6r0_len) { + /* Not room for one more */ + return (-1); + } + addrs = (struct in6_addr *)((char *)rthdr + sizeof (*rthdr)); + addrs[rthdr->ip6r0_segleft++] = *addr; + return (0); +} + +/* + * Reverse a source route. Both arguments can point to the same buffer. + */ +int +inet6_rth_reverse(const void *in, void *out) +{ + struct ip6_rthdr0 *rtin, *rtout; + int i, segments; + struct in6_addr tmp; + struct in6_addr *rtout_addrs; + struct in6_addr *rtin_addrs; + + rtin = (struct ip6_rthdr0 *)in; + rtout = (struct ip6_rthdr0 *)out; + + if (rtout->ip6r0_type != 0 || rtin->ip6r0_type != 0 || + rtout->ip6r0_len > MAX_RTHDR0_SEGMENTS * 2 || + rtin->ip6r0_len > MAX_RTHDR0_SEGMENTS * 2 || + rtout->ip6r0_len != rtin->ip6r0_len) + return (-1); + + segments = rtin->ip6r0_len / 2; + rtout_addrs = (struct in6_addr *)((char *)rtout + sizeof (*rtout)); + rtin_addrs = (struct in6_addr *)((char *)rtin + sizeof (*rtin)); + for (i = 0; i < (segments + 1)/2; i++) { + tmp = rtin_addrs[i]; + rtout_addrs[i] = rtin_addrs[segments - 1 - i]; + rtout_addrs[segments - 1 - i] = tmp; + } + rtout->ip6r0_segleft = segments; + return (0); +} + +/* + * Return the number of segments in the routing header. + */ +int +inet6_rth_segments(const void *bp) +{ + struct ip6_rthdr0 *rthdr; + + rthdr = (struct ip6_rthdr0 *)bp; + if (rthdr->ip6r0_type == 0) { + if (rthdr->ip6r0_len > MAX_RTHDR0_SEGMENTS * 2) { + return (-1); + } else { + return (rthdr->ip6r0_len / 2); + } + } else { + return (-1); + } +} + +/* + * Return a pointer to an element in the source route. + * This uses the C convention for index [0, size-1]. + */ +struct in6_addr * +inet6_rth_getaddr(const void *bp, int index) +{ + struct ip6_rthdr0 *rthdr; + struct in6_addr *rv; + + rthdr = (struct ip6_rthdr0 *)bp; + if (index >= rthdr->ip6r0_len/2 || index < 0) + return (NULL); + + rv = (struct in6_addr *)((char *)rthdr + sizeof (*rthdr)); + return (&rv[index]); +} diff --git a/usr/src/lib/libsocket/inet/inet_lnaof.c b/usr/src/lib/libsocket/inet/inet_lnaof.c new file mode 100644 index 0000000000..eeadb0d6cd --- /dev/null +++ b/usr/src/lib/libsocket/inet/inet_lnaof.c @@ -0,0 +1,61 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 1997 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <netinet/in.h> + +/* + * Return the local network address portion of an + * internet address; handles class a/b/c network + * number formats. + */ +int +inet_lnaof(struct in_addr in) +{ + uint32_t i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return ((i)&IN_CLASSA_HOST); + else if (IN_CLASSB(i)) + return ((i)&IN_CLASSB_HOST); + else + return ((i)&IN_CLASSC_HOST); +} diff --git a/usr/src/lib/libsocket/inet/inet_mkaddr.c b/usr/src/lib/libsocket/inet/inet_mkaddr.c new file mode 100644 index 0000000000..6c0127264d --- /dev/null +++ b/usr/src/lib/libsocket/inet/inet_mkaddr.c @@ -0,0 +1,66 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2001 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <netinet/in.h> + +/* + * Formulate an Internet address from network + host. Used in + * building addresses stored in the ifnet structure. + */ +struct in_addr +inet_makeaddr(ipaddr_t net, ipaddr_t host) +{ + ipaddr_t addr; + struct in_addr inaddr; + + if (net < 128) + addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); + else if (net < 65536) + addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); + else if (net < 16777216L) + addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); + else + addr = net | host; + addr = htonl(addr); + inaddr.s_addr = addr; + return (inaddr); +} diff --git a/usr/src/lib/libsocket/inet/inet_network.c b/usr/src/lib/libsocket/inet/inet_network.c new file mode 100644 index 0000000000..b7512dc228 --- /dev/null +++ b/usr/src/lib/libsocket/inet/inet_network.c @@ -0,0 +1,99 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2001 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <ctype.h> +#include <netinet/in.h> + +/* + * Internet network address interpretation routine. + * The library routines call this routine to interpret + * network numbers. + */ +in_addr_t +inet_network(const char *cp) +{ + in_addr_t val; + int base; + ptrdiff_t n; + char c; + in_addr_t parts[4], *pp = parts; + int i; + +again: + val = 0; base = 10; + if (*cp == '0') { + if (*++cp == 'x' || *cp == 'X') + base = 16, cp++; + else + base = 8; + } + while ((c = *cp) != NULL) { + if (isdigit(c)) { + if ((c - '0') >= base) + break; + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isxdigit(c)) { + val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (pp >= parts + 4 || val > 0xff) + return ((in_addr_t)-1); + *pp++ = val; + if (*cp == '.') { + cp++; + goto again; + } + if (*cp != '\0' && !isspace(*cp)) + return ((in_addr_t)-1); + n = pp - parts; + for (val = 0, i = 0; i < n; i++) { + val <<= 8; + val |= parts[i]; + } + return (val); +} diff --git a/usr/src/lib/libsocket/inet/interface_id.c b/usr/src/lib/libsocket/inet/interface_id.c new file mode 100644 index 0000000000..2a512b025f --- /dev/null +++ b/usr/src/lib/libsocket/inet/interface_id.c @@ -0,0 +1,355 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <inet/common.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/sockio.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <errno.h> + +#define IPIF_SEPARATOR_CHAR ":" + +/* + * Given an interface name, this function retrives the associated + * index value. Returns index value if successful, zero otherwise. + * The length of the supplied interface name must be at most + * IF_NAMESIZE-1 bytes + */ +uint32_t +if_nametoindex(const char *ifname) +{ + int s; + struct lifreq lifr; + int save_err; + size_t size; + + + /* Make sure the given name is not NULL */ + if ((ifname == NULL)||(*ifname == '\0')) { + errno = ENXIO; + return (0); + } + + /* + * Fill up the interface name in the ioctl + * request message. Make sure that the length of + * the given interface name <= (IF_NAMESIZE-1) + */ + size = strlen(ifname); + if (size > (IF_NAMESIZE - 1)) { + errno = EINVAL; + return (0); + } + + strncpy(lifr.lifr_name, ifname, size +1); + + /* Check the v4 interfaces first */ + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s >= 0) { + if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) { + (void) close(s); + return (lifr.lifr_index); + } + (void) close(s); + } + + /* Check the v6 interface list */ + s = socket(AF_INET6, SOCK_DGRAM, 0); + if (s < 0) + return (0); + + if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0) + lifr.lifr_index = 0; + + save_err = errno; + (void) close(s); + errno = save_err; + return (lifr.lifr_index); +} + +/* + * Given an index, this function returns the associated interface + * name in the supplied buffer ifname. + * Returns physical interface name if successful, NULL otherwise. + * The interface name returned will be at most IF_NAMESIZE-1 bytes. + */ +char * +if_indextoname(uint32_t ifindex, char *ifname) +{ + int n; + int s; + char *buf; + uint32_t index; + struct lifnum lifn; + struct lifconf lifc; + struct lifreq *lifrp; + int numifs; + size_t bufsize; + boolean_t found; + + /* A interface index of 0 is invalid */ + if (ifindex == 0) { + errno = ENXIO; + return (NULL); + } + + s = socket(AF_INET6, SOCK_DGRAM, 0); + if (s < 0) { + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + return (NULL); + } + } + + /* Prepare to send a SIOCGLIFNUM request message */ + lifn.lifn_family = AF_UNSPEC; + lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; + if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) { + int save_err = errno; + (void) close(s); + errno = save_err; + return (NULL); + } + numifs = lifn.lifn_count; + + /* + * Provide enough buffer to obtain the interface + * list from the kernel as response to a SIOCGLIFCONF + * request + */ + + bufsize = numifs * sizeof (struct lifreq); + buf = malloc(bufsize); + if (buf == NULL) { + int save_err = errno; + (void) close(s); + errno = save_err; + return (NULL); + } + lifc.lifc_family = AF_UNSPEC; + lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; + lifc.lifc_len = bufsize; + lifc.lifc_buf = buf; + if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { + int save_err = errno; + (void) close(s); + errno = save_err; + free(buf); + return (NULL); + } + + lifrp = lifc.lifc_req; + found = B_FALSE; + for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { + /* + * Obtain the index value of each interface, and + * match to see if the retrived index value matches + * the given one. If so we have return the corresponding + * device name of that interface. + */ + size_t size; + + index = if_nametoindex(lifrp->lifr_name); + if (index == 0) + /* Oops the interface just disappeared */ + continue; + if (index == ifindex) { + size = strcspn(lifrp->lifr_name, + (char *)IPIF_SEPARATOR_CHAR); + lifrp->lifr_name[size] = '\0'; + found = B_TRUE; + (void) strncpy(ifname, lifrp->lifr_name, + size + 1); + break; + } + } + (void) close(s); + free(buf); + if (!found) { + errno = ENXIO; + return (NULL); + } + return (ifname); +} + +/* + * This function returns all the interface names and indexes + */ +struct if_nameindex * +if_nameindex(void) +{ + int n; + int s; + boolean_t found; + char *buf; + struct lifnum lifn; + struct lifconf lifc; + struct lifreq *lifrp; + int numifs; + int index; + int i; + int physinterf_num; + size_t bufsize; + struct if_nameindex *interface_list; + struct if_nameindex *interface_entry; + + s = socket(AF_INET6, SOCK_DGRAM, 0); + if (s < 0) { + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + return (NULL); + } + + lifn.lifn_family = AF_UNSPEC; + lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; + if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) + return (NULL); + numifs = lifn.lifn_count; + + bufsize = numifs * sizeof (struct lifreq); + buf = malloc(bufsize); + if (buf == NULL) { + int save_err = errno; + (void) close(s); + errno = save_err; + return (NULL); + } + lifc.lifc_family = AF_UNSPEC; + lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; + lifc.lifc_len = bufsize; + lifc.lifc_buf = buf; + if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { + int save_err = errno; + (void) close(s); + errno = save_err; + free(buf); + return (NULL); + } + + lifrp = lifc.lifc_req; + (void) close(s); + + /* Allocate the array of if_nameindex structure */ + interface_list = malloc((numifs + 1) * sizeof (struct if_nameindex)); + if (!interface_list) { + int save_err = errno; + free(buf); + errno = save_err; + return (NULL); + } + /* + * Make sure that terminator structure automatically + * happens to be all zeroes. + */ + bzero(interface_list, ((numifs + 1) * sizeof (struct if_nameindex))); + interface_entry = interface_list; + physinterf_num = 0; + for (n = numifs; n > 0; n--, lifrp++) { + size_t size; + + size = strcspn(lifrp->lifr_name, (char *)IPIF_SEPARATOR_CHAR); + lifrp->lifr_name[size] = '\0'; + found = B_FALSE; + /* + * Search the current array to see if this interface + * already exists + */ + + for (i = 0; i < physinterf_num; i++) { + if (strcmp(interface_entry[i].if_name, + lifrp->lifr_name) == 0) { + found = B_TRUE; + break; + } + } + +allocate_new: + /* New one. Allocate an array element and fill it */ + if (!found) { + if ((interface_entry[physinterf_num].if_name = + strdup(lifrp->lifr_name)) == NULL) { + int save_err; + + if_freenameindex(interface_list); + save_err = errno; + free(buf); + errno = save_err; + return (NULL); + } + + /* + * Obtain the index value for the interface + */ + interface_entry[physinterf_num].if_index = + if_nametoindex(lifrp->lifr_name); + physinterf_num++; + } + } + + /* Create the last one of the array */ + interface_entry[physinterf_num].if_name = NULL; + interface_entry[physinterf_num].if_index = 0; + + /* Free up the excess array space */ + free(buf); + interface_list = realloc(interface_list, ((physinterf_num + 1) * + sizeof (struct if_nameindex))); + + return (interface_list); +} + +/* + * This function frees the the array that is created while + * the if_nameindex function. + */ +void +if_freenameindex(struct if_nameindex *ptr) +{ + + if (ptr == NULL) + return; + + + /* First free the if_name member in each array element */ + while (ptr->if_name != NULL) { + free(ptr->if_name); + ptr++; + } + + /* Now free up the array space */ + free(ptr); +} diff --git a/usr/src/lib/libsocket/inet/link_addr.c b/usr/src/lib/libsocket/inet/link_addr.c new file mode 100644 index 0000000000..36840521ab --- /dev/null +++ b/usr/src/lib/libsocket/inet/link_addr.c @@ -0,0 +1,135 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Function implementations to convert between link layer addresses and + * ascii representations of the form "x:x:x:...:x:x:x" where x is a hex + * number between 0x00 and 0xff; the bytes are always in network order. + */ + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <sys/types.h> +#include <net/if_dl.h> + +/* + * Converts a "size" bytes long mac address to its string representation. + * Currently, the "mactype" is unused, but in the future, the string + * can be modulated by "mactype" (IFT_* value from <net/if_types.h>) + */ +/* ARGSUSED */ +char * +_link_ntoa(const unsigned char *macaddr, char *str, int size, int mactype) +{ + char *buf; + int i, n; + + if (((buf = str) == NULL) && + ((buf = malloc(3 * size)) == NULL)) + return (NULL); + n = sprintf(buf, "%x", *macaddr++); + for (i = 0; i < (size - 1); i++) + n += sprintf(buf+n, ":%x", *macaddr++); + return (buf); +} + +/* + * Converts a string possibly representing a link address into its + * bit format, returning length of the address in bytes. + */ +uchar_t * +_link_aton(const char *ascaddr, int *maclen) +{ + unsigned char cval, num = 0; + int idx = 0, numcolons = 0, digits = 0; + uchar_t *netaddr; + const char *cptr; + char lastc = ':'; + + while (isspace(*ascaddr)) + ascaddr++; + + /* + * Find how many :'s in the string. Also sanity check + * the string for valid hex chars, absence of white + * spaces, not starting or ending with :, absence of + * consecutive :'s, excessive digits per element + * and non-null string. + */ + cptr = ascaddr; + while ((cval = *cptr++) != '\0') { + if (cval == ':') { + if (lastc == ':') + break; + numcolons++; + digits = 0; + } else if (!isxdigit(cval)) { + break; + } else { + digits++; + } + + if (digits > 2) + break; + + lastc = cval; + } + if ((lastc == ':') || (cval != '\0' && !isspace(cval)) || + (digits > 2)) { + *maclen = -1; + return (NULL); + } + + if ((netaddr = malloc(numcolons)) == NULL) { + *maclen = 0; + return (NULL); + } + + for (;;) { + cval = *ascaddr++; + if (isdigit(cval)) { + num = (num << 4) | (cval - '0'); + } else if (isxdigit(cval)) { + num = (num << 4) | + (cval - (isupper(cval) ? 'A' : 'a') + 10); + } else if (cval == ':') { + netaddr[idx++] = num; + num = 0; + } else { + /* + * We must have hit a whitespace. Stop + * parsing now. + */ + netaddr[idx++] = num; + break; + } + } + *maclen = idx; + return (netaddr); +} diff --git a/usr/src/lib/libsocket/inet/netmasks.c b/usr/src/lib/libsocket/inet/netmasks.c new file mode 100644 index 0000000000..e944e00e84 --- /dev/null +++ b/usr/src/lib/libsocket/inet/netmasks.c @@ -0,0 +1,277 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * All routines necessary to deal the "netmasks" database. The sources + * contain mappings between 32 bit Internet addresses and corresponding + * 32 bit Internet address masks. The addresses are in dotted internet + * address notation. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <nss_dbdefs.h> + +static int str2addr(const char *, int, void *, char *, int); + +static DEFINE_NSS_DB_ROOT(db_root); + +static void +_nss_initf_netmasks(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_NETMASKS; + p->default_config = NSS_DEFCONF_NETMASKS; +} + +/* + * Print a network number such as 129.144 as well as an IP address. + * Assumes network byte order for both IP addresses and network numbers + * (Network numbers are normally passed around in host byte order). + */ +static char * +inet_nettoa(struct in_addr in) +{ + uint32_t addr = in.s_addr; + uchar_t *up = (uchar_t *)&addr; + static char result[256]; + + /* Omit leading zeros */ + if (up[0]) { + (void) sprintf(result, "%d.%d.%d.%d", + up[0], up[1], up[2], up[3]); + } else if (up[1]) { + (void) sprintf(result, "%d.%d.%d", up[1], up[2], up[3]); + } else if (up[2]) { + (void) sprintf(result, "%d.%d", up[2], up[3]); + } else { + (void) sprintf(result, "%d", up[3]); + } + return (result); +} + +/* + * Given a 32 bit key look it up in the netmasks database + * based on the "netmasks" policy in /etc/nsswitch.conf. + * If the key is a network number with the trailing zero's removed + * (e.g. "192.9.200") this routine can't use inet_ntoa to convert + * the address to the string key. + * Returns zero if successful, non-zero otherwise. + */ +static int +getnetmaskbykey(const struct in_addr addr, struct in_addr *mask) +{ + nss_XbyY_args_t arg; + nss_status_t res; + char tmp[NSS_LINELEN_NETMASKS]; + + /* + * let the backend do the allocation to store stuff for parsing. + * To simplify things, we put the dotted internet address form of + * the network address in the 'name' field as a filter to speed + * up the lookup. + */ + NSS_XbyY_INIT(&arg, mask, NULL, 0, str2addr); + (void) strcpy(tmp, inet_nettoa(addr)); + arg.key.name = tmp; + res = nss_search(&db_root, _nss_initf_netmasks, + NSS_DBOP_NETMASKS_BYNET, &arg); + (void) NSS_XbyY_FINI(&arg); + return (arg.status = res); +} + +/* + * Given a 32 bit internet network number, it finds the corresponding netmask + * address based on the "netmasks" policy in /etc/nsswitch.conf. + * Returns zero if successful, non-zero otherwise. + * Check both for the (masked) network number and the shifted network + * number (e.g., both "10.0.0.0" and "10"). + * Assumes that the caller passes in an unshifted number (or an IP address). + */ +int +getnetmaskbynet(const struct in_addr net, struct in_addr *mask) +{ + struct in_addr net1, net2; + uint32_t i; + + i = ntohl(net.s_addr); + + /* + * Try looking for the network number both with and without + * the trailing zeros. + */ + if ((i & IN_CLASSA_NET) == 0) { + /* Assume already a right-shifted network number */ + net2.s_addr = htonl(i); + if ((i & IN_CLASSB_NET) != 0) { + net1.s_addr = htonl(i << IN_CLASSC_NSHIFT); + } else if ((i & IN_CLASSC_NET) != 0) { + net1.s_addr = htonl(i << IN_CLASSB_NSHIFT); + } else { + net1.s_addr = htonl(i << IN_CLASSA_NSHIFT); + } + } else if (IN_CLASSA(i)) { + net1.s_addr = htonl(i & IN_CLASSA_NET); + net2.s_addr = htonl(i >> IN_CLASSA_NSHIFT); + } else if (IN_CLASSB(i)) { + net1.s_addr = htonl(i & IN_CLASSB_NET); + net2.s_addr = htonl(i >> IN_CLASSB_NSHIFT); + } else { + net1.s_addr = htonl(i & IN_CLASSC_NET); + net2.s_addr = htonl(i >> IN_CLASSC_NSHIFT); + } + + if (getnetmaskbykey(net1, mask) == 0) { + return (0); + } + if (getnetmaskbykey(net2, mask) == 0) { + return (0); + } + return (-1); +} + +/* + * Find the netmask used for an IP address. + * Returns zero if successful, non-zero otherwise. + * + * Support Variable Length Subnetmasks by looking for the longest + * matching subnetmask in the database. + * Start by looking for a match for the full IP address and + * mask off one rightmost bit after another until we find a match. + * Note that for a match the found netmask must match what was used + * for the lookup masking. + * As a fallback for compatibility finally lookup the network + * number with and without the trailing zeros. + * In order to suppress redundant lookups in the name service + * we keep the previous lookup key and compare against it before + * doing the lookup. + */ +int +getnetmaskbyaddr(const struct in_addr addr, struct in_addr *mask) +{ + struct in_addr prevnet, net; + uint32_t i, maskoff; + + i = ntohl(addr.s_addr); + prevnet.s_addr = 0; + mask->s_addr = 0; + + for (maskoff = 0xFFFFFFFF; maskoff != 0; maskoff = maskoff << 1) { + net.s_addr = htonl(i & maskoff); + + if (net.s_addr != prevnet.s_addr) { + if (getnetmaskbykey(net, mask) != 0) { + mask->s_addr = 0; + } + } + if (htonl(maskoff) == mask->s_addr) + return (0); + + prevnet.s_addr = net.s_addr; + } + + /* + * Non-VLSM fallback. + * Try looking for the network number with and without the trailing + * zeros. + */ + return (getnetmaskbynet(addr, mask)); +} + +/* + * Parse netmasks entry into its components. The network address is placed + * in buffer for use by check_addr for 'files' backend, to match the network + * address. The network address is placed in the buffer as a network order + * internet address, if buffer is non null. The network order form of the mask + * itself is placed in 'ent'. + */ +int +str2addr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) +{ + int retval; + struct in_addr *mask = (struct in_addr *)ent; + const char *p, *limit, *start; + struct in_addr addr; + int i; + char tmp[NSS_LINELEN_NETMASKS]; + + p = instr; + limit = p + lenstr; + retval = NSS_STR_PARSE_PARSE; + + while (p < limit && isspace(*p)) /* skip leading whitespace */ + p++; + + if (buffer) { /* for 'files' backend verification */ + for (start = p, i = 0; p < limit && !isspace(*p); p++) + i++; + if (p < limit && i < buflen) { + (void) memcpy(tmp, start, i); + tmp[i] = '\0'; + addr.s_addr = inet_addr(tmp); + /* Addr will always be an ipv4 address (32bits) */ + if (addr.s_addr == 0xffffffffUL) + return (NSS_STR_PARSE_PARSE); + else { + (void) memcpy(buffer, (char *)&addr, + sizeof (struct in_addr)); + } + } else + return (NSS_STR_PARSE_ERANGE); + } + + while (p < limit && isspace(*p)) /* skip intermediate */ + p++; + + if (mask) { + for (start = p, i = 0; p < limit && !isspace(*p); p++) + i++; + if (p <= limit) { + if ((i + 1) > NSS_LINELEN_NETMASKS) + return (NSS_STR_PARSE_ERANGE); + (void) memcpy(tmp, start, i); + tmp[i] = '\0'; + addr.s_addr = inet_addr(tmp); + /* Addr will always be an ipv4 address (32bits) */ + if (addr.s_addr == 0xffffffffUL) + retval = NSS_STR_PARSE_PARSE; + else { + mask->s_addr = addr.s_addr; + retval = NSS_STR_PARSE_SUCCESS; + } + } + } + + return (retval); +} diff --git a/usr/src/lib/libsocket/inet/rcmd.c b/usr/src/lib/libsocket/inet/rcmd.c new file mode 100644 index 0000000000..8cb2cd1291 --- /dev/null +++ b/usr/src/lib/libsocket/inet/rcmd.c @@ -0,0 +1,820 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <limits.h> +#include <stdio.h> +#include <ctype.h> +#include <pwd.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#include <signal.h> +#include <libintl.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <inet/common.h> + +#include <netdb.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <grp.h> +#include <arpa/inet.h> + +#include <priv_utils.h> + +#ifdef SYSV +#define bcopy(s1, s2, len) (void) memcpy(s2, s1, len) +#define bzero(s, len) (void) memset(s, 0, len) +#define index(s, c) strchr(s, c) +char *strchr(); +#else +char *index(); +#endif /* SYSV */ + +extern char *_dgettext(); +extern int _sigaction(); +extern int _sigaddset(); +extern int _sigprocmask(); +extern int _fcntl(); +extern int usingypmap(); + +static int _validuser(FILE *hostf, char *rhost, const char *luser, + const char *ruser, int baselen); +static int _checkhost(char *rhost, char *lhost, int len); + + +#ifdef NIS +static char *domain; +#endif + +int rcmd(char **ahost, unsigned short rport, const char *locuser, + const char *remuser, const char *cmd, int *fd2p) +{ + int rcmd_ret; + + rcmd_ret = rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, + AF_INET); + return (rcmd_ret); +} + +int rcmd_af(char **ahost, unsigned short rport, const char *locuser, + const char *remuser, const char *cmd, int *fd2p, int af) +{ + int s, timo = 1; + ssize_t retval; + pid_t pid; + struct sockaddr_storage caddr, faddr; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + struct addrinfo hints; + struct addrinfo *res, *resp; + size_t addrlen; + int rc; +#define MAX_SHORTSTRLEN 6 + char aport[MAX_SHORTSTRLEN]; + char c; + int lport = 0; +#ifdef SYSV + sigset_t oldmask; + sigset_t newmask; + struct sigaction oldaction; + struct sigaction newaction; +#else + int oldmask; +#endif /* SYSV */ + fd_set fdset; + int selret; + char *addr; + static char hostname[MAXHOSTNAMELEN]; + socklen_t len; + char abuf[INET6_ADDRSTRLEN]; + + if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) { + errno = EAFNOSUPPORT; + return (-1); + } + + pid = getpid(); + memset(&hints, 0, sizeof (hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + if (af == AF_INET6) { + hints.ai_flags |= AI_V4MAPPED; + hints.ai_family = AF_UNSPEC; + } else { + hints.ai_family = af; + } + (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport)); + rc = getaddrinfo(*ahost, aport, &hints, &res); + if (rc != 0) { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, "%s: unknown host%s\n"), + *ahost, rc == EAI_AGAIN ? " (try again later)" : ""); + return (-1); + } + resp = res; + (void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN); + *ahost = hostname; +#ifdef SYSV + /* ignore SIGPIPE */ + bzero((char *)&newaction, sizeof (newaction)); + newaction.sa_handler = SIG_IGN; + (void) _sigaction(SIGPIPE, &newaction, &oldaction); + + /* block SIGURG */ + bzero((char *)&newmask, sizeof (newmask)); + (void) _sigaddset(&newmask, SIGURG); + (void) _sigprocmask(SIG_BLOCK, &newmask, &oldmask); +#else + oldmask = _sigblock(sigmask(SIGURG)); +#endif /* SYSV */ + for (;;) { + s = rresvport_af(&lport, res->ai_family); + if (s < 0) { + int af = res->ai_family; + + /* + * See if we have any addresses of a different type + * to try. + */ + while (res != NULL && res->ai_family == af) + res = res->ai_next; + + if (res != NULL) + continue; + + if (errno == EAGAIN) + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "socket: All ports in use\n")); + else + perror("rcmd: socket"); +#ifdef SYSV + /* restore original SIGPIPE handler */ + (void) _sigaction(SIGPIPE, &oldaction, + (struct sigaction *)0); + + /* restore original signal mask */ + (void) _sigprocmask(SIG_SETMASK, &oldmask, + (sigset_t *)0); +#else + sigsetmask(oldmask); +#endif /* SYSV */ + freeaddrinfo(resp); + return (-1); + } + bzero((char *)&caddr, sizeof (caddr)); + bcopy(res->ai_addr, &caddr, res->ai_addrlen); + addrlen = res->ai_addrlen; + if (af == AF_INET6 && res->ai_addr->sa_family == AF_INET) { + struct in6_addr ia6; + struct sockaddr_in6 *in6addr; + IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in *) + res->ai_addr)->sin_addr, &ia6); + in6addr = (struct sockaddr_in6 *)&caddr; + in6addr->sin6_addr = ia6; + in6addr->sin6_family = AF_INET6; + addrlen = sizeof (struct sockaddr_in6); + } + (void) _fcntl(s, F_SETOWN, pid); + if (connect(s, (struct sockaddr *)&caddr, addrlen) >= 0) + break; + (void) close(s); + if (errno == EADDRINUSE) { + lport = 0; + continue; + } + if (errno == ECONNREFUSED && timo <= 16) { + (void) sleep(timo); + timo *= 2; + continue; + } + if (res->ai_next != NULL) { + int oerrno = errno; + if (res->ai_addr->sa_family == AF_INET6) + addr = (char *)&((struct sockaddr_in6 *) + res->ai_addr)->sin6_addr; + else + addr = (char *)&((struct sockaddr_in *) + res->ai_addr)->sin_addr; + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, "connect to address %s: "), + inet_ntop(res->ai_addr->sa_family, addr, + abuf, sizeof (abuf))); + errno = oerrno; + perror(0); + res = res->ai_next; + if (res->ai_addr->sa_family == AF_INET6) + addr = (char *)&((struct sockaddr_in6 *) + res->ai_addr)->sin6_addr; + else + addr = (char *)&((struct sockaddr_in *) + res->ai_addr)->sin_addr; + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, "Trying %s...\n"), + inet_ntop(res->ai_addr->sa_family, addr, + abuf, sizeof (abuf))); + continue; + } + perror(*ahost); + freeaddrinfo(resp); +#ifdef SYSV + /* restore original SIGPIPE handler */ + (void) _sigaction(SIGPIPE, &oldaction, + (struct sigaction *)0); + + /* restore original signal mask */ + (void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); +#else + sigsetmask(oldmask); +#endif /* SYSV */ + return (-1); + } + lport = 0; + if (fd2p == 0) { + (void) write(s, "", 1); + } else { + int s2 = rresvport_af(&lport, res->ai_family), s3; + + len = (socklen_t)sizeof (faddr); + + if (s2 < 0) + goto bad; + (void) listen(s2, 1); + (void) snprintf(aport, MAX_SHORTSTRLEN, "%d", lport); + if (write(s, aport, strlen(aport)+1) != strlen(aport)+1) { + perror(_dgettext(TEXT_DOMAIN, + "write: setting up stderr")); + (void) close(s2); + goto bad; + } + FD_ZERO(&fdset); + FD_SET(s, &fdset); + FD_SET(s2, &fdset); + while ((selret = select(FD_SETSIZE, &fdset, (fd_set *)0, + (fd_set *)0, (struct timeval *)0)) > 0) { + if (FD_ISSET(s, &fdset)) { + /* + * Something's wrong: we should get no + * data on this connection at this point, + * so we assume that the connection has + * gone away. + */ + (void) close(s2); + goto bad; + } + if (FD_ISSET(s2, &fdset)) { + /* + * We assume this is an incoming connect + * request and proceed normally. + */ + s3 = accept(s2, (struct sockaddr *)&faddr, + &len); + FD_CLR(s2, &fdset); + (void) close(s2); + if (s3 < 0) { + perror("accept"); + lport = 0; + goto bad; + } + else + break; + } + } + if (selret == -1) { + /* + * This should not happen, and we treat it as + * a fatal error. + */ + (void) close(s2); + goto bad; + } + + *fd2p = s3; + switch (faddr.ss_family) { + case AF_INET: + sin = (struct sockaddr_in *)&faddr; + if (ntohs(sin->sin_port) >= IPPORT_RESERVED) { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "socket: protocol failure in circuit " + "setup.\n")); + goto bad2; + } + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)&faddr; + if (ntohs(sin6->sin6_port) >= IPPORT_RESERVED) { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "socket: protocol failure in circuit " + "setup.\n")); + goto bad2; + } + break; + default: + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "socket: protocol failure in circuit setup.\n")); + goto bad2; + } + } + (void) write(s, locuser, strlen(locuser)+1); + (void) write(s, remuser, strlen(remuser)+1); + (void) write(s, cmd, strlen(cmd)+1); + retval = read(s, &c, 1); + if (retval != 1) { + if (retval == 0) { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "Protocol error, %s closed connection\n"), + *ahost); + } else if (retval < 0) { + perror(*ahost); + } else { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "Protocol error, %s sent %d bytes\n"), + *ahost, retval); + } + goto bad2; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void) write(2, &c, 1); + if (c == '\n') + break; + } + goto bad2; + } +#ifdef SYSV + /* restore original SIGPIPE handler */ + (void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0); + + /* restore original signal mask */ + (void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); +#else + sigsetmask(oldmask); +#endif /* SYSV */ + freeaddrinfo(resp); + return (s); +bad2: + if (lport) + (void) close(*fd2p); +bad: + (void) close(s); +#ifdef SYSV + /* restore original SIGPIPE handler */ + (void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0); + + /* restore original signal mask */ + (void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); +#else + sigsetmask(oldmask); +#endif /* SYSV */ + freeaddrinfo(resp); + return (-1); +} + +static int +_rresvport_addr(int *alport, struct sockaddr_storage *addr) +{ + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + int s; + socklen_t len; + int on = 1; + int off = 0; + + if (addr->ss_family == AF_INET) { + sin = (struct sockaddr_in *)addr; + len = sizeof (struct sockaddr_in); + } else if (addr->ss_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *)addr; + len = sizeof (struct sockaddr_in6); + } else { + errno = EAFNOSUPPORT; + return (-1); + } + s = socket(addr->ss_family, SOCK_STREAM, 0); + if (s < 0) + return (-1); + + /* + * Set TCP_EXCLBIND to get a "unique" port, which is not bound + * to any other sockets. + */ + if (setsockopt(s, IPPROTO_TCP, TCP_EXCLBIND, &on, sizeof (on)) < 0) { + (void) close(s); + return (-1); + } + + /* Try to bind() to the given port first. */ + if (*alport != 0) { + if (addr->ss_family == AF_INET) { + sin->sin_port = htons((ushort_t)*alport); + } else { + sin6->sin6_port = htons((ushort_t)*alport); + } + if (bind(s, (struct sockaddr *)addr, len) >= 0) { + /* To be safe, need to turn off TCP_EXCLBIND. */ + (void) setsockopt(s, IPPROTO_TCP, TCP_EXCLBIND, &off, + sizeof (off)); + return (s); + } + if (errno != EADDRINUSE) { + (void) close(s); + return (-1); + } + } + + /* + * If no port is given or the above bind() does not succeed, set + * TCP_ANONPRIVBIND option to ask the kernel to pick a port in the + * priviledged range for us. + */ + if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, + sizeof (on)) < 0) { + (void) close(s); + return (-1); + } + if (addr->ss_family == AF_INET) { + sin->sin_port = 0; + } else { + sin6->sin6_port = 0; + } + if (bind(s, (struct sockaddr *)addr, len) >= 0) { + /* + * We need to tell the caller what the port is. + */ + if (getsockname(s, (struct sockaddr *)addr, &len) < 0) { + (void) close(s); + return (-1); + } + switch (addr->ss_family) { + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + *alport = ntohs(sin6->sin6_port); + break; + case AF_INET: + sin = (struct sockaddr_in *)addr; + *alport = ntohs(sin->sin_port); + break; + } + + /* + * To be safe, always turn off these options when we are done. + */ + (void) setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &off, + sizeof (off)); + (void) setsockopt(s, IPPROTO_TCP, TCP_EXCLBIND, &off, + sizeof (off)); + return (s); + } + (void) close(s); + return (-1); +} + +int +rresvport_addr(int *alport, struct sockaddr_storage *addr) +{ + int res, err; + + (void) __priv_bracket(PRIV_ON); + + res = _rresvport_addr(alport, addr); + + err = errno; + (void) __priv_bracket(PRIV_OFF); + errno = err; + + return (res); +} + +int +rresvport_af(int *alport, int af) +{ + struct sockaddr_storage laddr; + + bzero(&laddr, sizeof (laddr)); + if (af == AF_INET || af == AF_INET6) { + laddr.ss_family = (sa_family_t)af; + } else { + errno = EAFNOSUPPORT; + return (-1); + } + return (rresvport_addr(alport, &laddr)); +} + +int +rresvport(int *alport) +{ + return (rresvport_af(alport, AF_INET)); +} + +int +ruserok(const char *rhost, int superuser, const char *ruser, const char *luser) +{ + FILE *hostf; + char fhost[MAXHOSTNAMELEN]; + const char *sp; + char *p; + int baselen = -1; + + struct stat64 sbuf; + struct passwd *pwd; + char pbuf[MAXPATHLEN]; + uid_t uid = (uid_t)-1; + gid_t gid = (gid_t)-1; + gid_t grouplist[NGROUPS_MAX]; + int ngroups; + + sp = rhost; + p = fhost; + while (*sp) { + if (*sp == '.') { + if (baselen == -1) + baselen = (int)(sp - rhost); + *p++ = *sp++; + } else { + *p++ = isupper(*sp) ? tolower(*sp++) : *sp++; + } + } + *p = '\0'; + + /* check /etc/hosts.equiv */ + if (!superuser) { + if ((hostf = fopen("/etc/hosts.equiv", "r")) != NULL) { + if (!_validuser(hostf, fhost, luser, ruser, baselen)) { + (void) fclose(hostf); + return (0); + } + (void) fclose(hostf); + } + } + + /* check ~/.rhosts */ + + if ((pwd = getpwnam(luser)) == NULL) + return (-1); + (void) strcpy(pbuf, pwd->pw_dir); + (void) strcat(pbuf, "/.rhosts"); + + /* + * Read .rhosts as the local user to avoid NFS mapping the root uid + * to something that can't read .rhosts. + */ + gid = getegid(); + uid = geteuid(); + if ((ngroups = getgroups(NGROUPS_MAX, grouplist)) == -1) + return (-1); + + (void) setegid(pwd->pw_gid); + initgroups(pwd->pw_name, pwd->pw_gid); + (void) seteuid(pwd->pw_uid); + if ((hostf = fopen(pbuf, "r")) == NULL) { + if (gid != (gid_t)-1) + (void) setegid(gid); + if (uid != (uid_t)-1) + (void) seteuid(uid); + setgroups(ngroups, grouplist); + return (-1); + } + (void) fstat64(fileno(hostf), &sbuf); + if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { + (void) fclose(hostf); + if (gid != (gid_t)-1) + (void) setegid(gid); + if (uid != (uid_t)-1) + (void) seteuid(uid); + setgroups(ngroups, grouplist); + return (-1); + } + + if (!_validuser(hostf, fhost, luser, ruser, baselen)) { + (void) fclose(hostf); + if (gid != (gid_t)-1) + (void) setegid(gid); + if (uid != (uid_t)-1) + (void) seteuid(uid); + setgroups(ngroups, grouplist); + return (0); + } + + (void) fclose(hostf); + if (gid != (gid_t)-1) + (void) setegid(gid); + if (uid != (uid_t)-1) + (void) seteuid(uid); + setgroups(ngroups, grouplist); + return (-1); +} + +static int +_validuser(FILE *hostf, char *rhost, const char *luser, + const char *ruser, int baselen) +{ + char *user; + char ahost[BUFSIZ]; + char *uchost = (char *)NULL; + int hostmatch, usermatch; + char *p; + +#ifdef NIS + if (domain == NULL) { + (void) usingypmap(&domain, NULL); + } +#endif /* NIS */ + + while (fgets(ahost, (int)sizeof (ahost), hostf)) { + uchost = (char *)NULL; + hostmatch = usermatch = 0; + p = ahost; + /* + * We can get a line bigger than our buffer. If so we skip + * the offending line. + */ + if (strchr(p, '\n') == NULL) { + while (fgets(ahost, (int)sizeof (ahost), hostf) && + strchr(ahost, '\n') == NULL) + ; + continue; + } + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { + /* + * Both host and user ``names'' can be netgroups, + * and must have their case preserved. Case is + * preserved for user names because we break out + * of this loop when finding a field separator. + * To do so for host names, we must make a copy of + * the host name field. + */ + if (isupper(*p)) { + if (uchost == (char *)NULL) + uchost = strdup(ahost); + *p = tolower(*p); + } + p++; + } + if (*p != '\0' && uchost != (char *)NULL) + uchost[p - ahost] = '\0'; + if (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + user = p; + while (*p != '\n' && *p != ' ' && *p != '\t' && + *p != '\0') + p++; + } else + user = p; + *p = '\0'; + if (ahost[0] == '+' && ahost[1] == 0) + hostmatch = 1; +#ifdef NIS + else if (ahost[0] == '+' && ahost[1] == '@') + if (uchost != (char *)NULL) + hostmatch = innetgr(uchost + 2, rhost, + NULL, domain); + else + hostmatch = innetgr(ahost + 2, rhost, + NULL, domain); + else if (ahost[0] == '-' && ahost[1] == '@') { + if (uchost != (char *)NULL) { + if (innetgr(uchost + 2, rhost, NULL, domain)) + break; + } else { + if (innetgr(ahost + 2, rhost, NULL, domain)) + break; + } + } +#endif /* NIS */ + else if (ahost[0] == '-') { + if (_checkhost(rhost, ahost+1, baselen)) + break; + } + else + hostmatch = _checkhost(rhost, ahost, baselen); + if (user[0]) { + if (user[0] == '+' && user[1] == 0) + usermatch = 1; +#ifdef NIS + else if (user[0] == '+' && user[1] == '@') + usermatch = innetgr(user+2, NULL, + ruser, domain); + else if (user[0] == '-' && user[1] == '@') { + if (hostmatch && + innetgr(user+2, NULL, ruser, domain)) + break; + } +#endif /* NIS */ + else if (user[0] == '-') { + if (hostmatch && (strcmp(user+1, ruser) == 0)) + break; + } + else + usermatch = (strcmp(user, ruser) == 0); + } + else + usermatch = (strcmp(ruser, luser) == 0); + if (uchost != (char *)NULL) + free(uchost); + if (hostmatch && usermatch) + return (0); + } + + if (uchost != (char *)NULL) + free(uchost); + return (-1); +} + +static int +_checkhost(char *rhost, char *lhost, int len) +{ + static char *ldomain; + static char *domainp; + static int nodomain; + char *cp; + + if (ldomain == NULL) { + ldomain = (char *)malloc(MAXHOSTNAMELEN+1); + if (ldomain == 0) + return (0); + } + + if (len == -1) + return (strcmp(rhost, lhost) == 0); + if (strncmp(rhost, lhost, len)) + return (0); + if (strcmp(rhost, lhost) == 0) + return (1); + if (*(lhost + len) != '\0') + return (0); + if (nodomain) + return (0); + if (!domainp) { + /* + * "domainp" points after the first dot in the host name + */ + if (gethostname(ldomain, MAXHOSTNAMELEN) == -1) { + nodomain = 1; + return (0); + } + ldomain[MAXHOSTNAMELEN] = NULL; + if ((domainp = index(ldomain, '.')) == (char *)NULL) { + nodomain = 1; + return (0); + } + domainp++; + cp = domainp; + while (*cp) { + *cp = isupper(*cp) ? tolower(*cp) : *cp; + cp++; + } + } + return (strcmp(domainp, rhost + len + 1) == 0); +} diff --git a/usr/src/lib/libsocket/inet/rexec.c b/usr/src/lib/libsocket/inet/rexec.c new file mode 100644 index 0000000000..b663fa2523 --- /dev/null +++ b/usr/src/lib/libsocket/inet/rexec.c @@ -0,0 +1,189 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <stdio.h> +#include <netdb.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <libintl.h> + +#ifdef SYSV +#define bcopy(a, b, c) (void) memcpy((b), (a), (c)) +#endif + +#define MAX_SHORTSTRLEN 6 + +extern char *_dgettext(); + +void _ruserpass(const char *host, char **aname, char **apass); + +int rexec(char **ahost, unsigned short rport, const char *name, + const char *pass, const char *cmd, int *fd2p) +{ + return (rexec_af(ahost, rport, name, pass, cmd, fd2p, AF_INET)); +} + +int rexec_af(char **ahost, unsigned short rport, const char *name, + const char *pass, const char *cmd, int *fd2p, int af) +{ + int s, timo = 1, s3; + char c; + ushort_t port; + static char hostname[MAXHOSTNAMELEN]; + int rc; + struct addrinfo *res; + struct addrinfo hints; + char aport[MAX_SHORTSTRLEN]; + + if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, "%d: Address family not " + "supported\n"), af); + errno = EAFNOSUPPORT; + return (-1); + } + memset(&hints, 0, sizeof (hints)); + (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport)); + hints.ai_flags = AI_CANONNAME|AI_ADDRCONFIG|AI_V4MAPPED; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = af; + rc = getaddrinfo(*ahost, aport, &hints, &res); + + if (rc != 0) { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, "%s: unknown host\n"), + *ahost); + return (-1); + } + (void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN); + *ahost = hostname; + _ruserpass(res->ai_canonname, (char **)&name, (char **)&pass); +retry: + s = socket(res->ai_addr->sa_family, res->ai_socktype, res->ai_protocol); + if (s < 0) { + perror("rexec: socket"); + freeaddrinfo(res); + return (-1); + } + if (connect(s, res->ai_addr, res->ai_addrlen) != 0) { + if (errno == ECONNREFUSED && timo <= 16) { + (void) close(s); + (void) sleep(timo); + timo *= 2; + goto retry; + } + perror(*ahost); + (void) close(s); + freeaddrinfo(res); + return (-1); + } + if (fd2p == 0) { + (void) write(s, "", 1); + port = 0; + } else { + int s2; + socklen_t sin2len; + struct sockaddr_storage sin2, from; + + s2 = socket(res->ai_family, SOCK_STREAM, 0); + if (s2 < 0) { + (void) close(s); + freeaddrinfo(res); + return (-1); + } + (void) listen(s2, 1); + sin2len = (socklen_t)sizeof (sin2); + if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0) { + perror("getsockname"); + (void) close(s2); + goto bad; + } + if (res->ai_family == AF_INET6) { + port = ((struct sockaddr_in6 *)&sin2)->sin6_port; + } else { + port = ((struct sockaddr_in *)&sin2)->sin_port; + } + (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", port); + (void) write(s, aport, strlen(aport)+1); + { + socklen_t len = (socklen_t)sizeof (from); + s3 = accept(s2, (struct sockaddr *)&from, &len); + (void) close(s2); + if (s3 < 0) { + perror("accept"); + port = 0; + goto bad; + } + } + *fd2p = s3; + } + (void) write(s, name, strlen(name) + 1); + /* should public key encypt the password here */ + (void) write(s, pass, strlen(pass) + 1); + (void) write(s, cmd, strlen(cmd) + 1); + if (read(s, &c, 1) != 1) { + perror(*ahost); + goto bad; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void) write(2, &c, 1); + if (c == '\n') + break; + } + goto bad; + } + freeaddrinfo(res); + return (s); +bad: + if (port) + (void) close(*fd2p); + (void) close(s); + freeaddrinfo(res); + return (-1); +} diff --git a/usr/src/lib/libsocket/inet/ruserpass.c b/usr/src/lib/libsocket/inet/ruserpass.c new file mode 100644 index 0000000000..475bcf0ae3 --- /dev/null +++ b/usr/src/lib/libsocket/inet/ruserpass.c @@ -0,0 +1,270 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 1998 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <libintl.h> + +extern char *_dgettext(); + +#ifdef SYSV +#define index strchr +#endif /* SYSV */ + +static void rnetrc(const char *host, char **aname, char **apass); +static int token(); + +#define DEFAULT 1 +#define LOGIN 2 +#define PASSWD 3 +#define NOTIFY 4 +#define WRITE 5 +#define YES 6 +#define NO 7 +#define COMMAND 8 +#define FORCE 9 +#define ID 10 +#define MACHINE 11 + +#define MAXTOKEN 11 +#define NTOKENS (MAXTOKEN - 1 + 2 + 1) /* two duplicates and null, minus id */ + +static struct ruserdata { + char tokval[100]; + struct toktab { + char *tokstr; + int tval; + } toktab[NTOKENS]; + FILE *cfile; +} *ruserdata, *_ruserdata(); + + +static struct ruserdata * +_ruserdata() +{ + struct ruserdata *d = ruserdata; + struct toktab *t; + + if (d == 0) { + if ((d = (struct ruserdata *) + calloc(1, sizeof (struct ruserdata))) == NULL) { + return (NULL); + } + ruserdata = d; + t = d->toktab; + t->tokstr = "default"; t++->tval = DEFAULT; + t->tokstr = "login"; t++->tval = LOGIN; + t->tokstr = "password"; t++->tval = PASSWD; + t->tokstr = "notify"; t++->tval = NOTIFY; + t->tokstr = "write"; t++->tval = WRITE; + t->tokstr = "yes"; t++->tval = YES; + t->tokstr = "y"; t++->tval = YES; + t->tokstr = "no"; t++->tval = NO; + t->tokstr = "n"; t++->tval = NO; + t->tokstr = "command"; t++->tval = COMMAND; + t->tokstr = "force"; t++->tval = FORCE; + t->tokstr = "machine"; t++->tval = MACHINE; + t->tokstr = 0; t->tval = 0; + } + return (d); +} + + +#define MAXANAME 16 + +void +_ruserpass(const char *host, char **aname, char **apass) +{ + + if (*aname == 0 || *apass == 0) + rnetrc(host, aname, apass); + if (*aname == 0) { + char myname[L_cuserid]; + + *aname = malloc(MAXANAME + 1); + (void) cuserid(myname); + (void) printf(_dgettext(TEXT_DOMAIN, "Name (%s:%s): "), host, myname); + (void) fflush(stdout); + if (read(2, *aname, MAXANAME) <= 0) + exit(1); + aname[0][MAXANAME] = '\0'; + if ((*aname)[0] == '\n') + (void) strcpy(*aname, myname); + else + if (index(*aname, '\n')) + *index(*aname, '\n') = 0; + } + if (*aname && *apass == 0) { + (void) printf(_dgettext(TEXT_DOMAIN, "Password (%s:%s): "), + host, *aname); + (void) fflush(stdout); + *apass = getpass(""); + } +} + + +static void +rnetrc(const char *host, char **aname, char **apass) +{ + struct ruserdata *d = _ruserdata(); + char *hdir, buf[BUFSIZ]; + int t; + struct stat64 stb; + + if (d == 0) + return; + + hdir = getenv("HOME"); + if (hdir == NULL) + hdir = "."; + (void) sprintf(buf, "%s/.netrc", hdir); + d->cfile = fopen(buf, "r"); + if (d->cfile == NULL) { + if (errno != ENOENT) + perror(buf); + return; + } +next: + while ((t = token())) + switch (t) { + + case DEFAULT: + (void) token(); + continue; + + case MACHINE: + if (token() != ID || strcmp(host, d->tokval)) + continue; + while ((t = token()) != 0 && t != MACHINE) + switch (t) { + + case LOGIN: + if (token()) + if (*aname == 0) { + *aname = malloc(strlen(d->tokval) + 1); + (void) strcpy(*aname, d->tokval); + } else { + if (strcmp(*aname, d->tokval)) + goto next; + } + break; + case PASSWD: + if (fstat64(fileno(d->cfile), &stb) >= 0 && + (stb.st_mode & 077) != 0) { + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "Error - .netrc file not correct mode.\n")); + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, + "Remove password or correct mode.\n")); + exit(1); + } + if (token() && *apass == 0) { + *apass = malloc(strlen(d->tokval) + 1); + (void) strcpy(*apass, d->tokval); + } + break; + case COMMAND: + case NOTIFY: + case WRITE: + case FORCE: + (void) token(); + break; + default: + (void) fprintf(stderr, + _dgettext(TEXT_DOMAIN, "Unknown .netrc option %s\n"), + d->tokval); + break; + } + goto done; + } +done: + (void) fclose(d->cfile); +} + +static int +token() +{ + struct ruserdata *d = _ruserdata(); + char *cp; + int c; + struct toktab *t; + + if (d == 0) + return (0); + + if (feof(d->cfile)) + return (0); + while ((c = getc(d->cfile)) != EOF && + (c == '\n' || c == '\t' || c == ' ' || c == ',')) + continue; + if (c == EOF) + return (0); + cp = d->tokval; + if (c == '"') { + while ((c = getc(d->cfile)) != EOF && c != '"') { + if (c == '\\') + c = getc(d->cfile); + *cp++ = (char)c; + } + } else { + *cp++ = (char)c; + while ((c = getc(d->cfile)) != EOF && + c != '\n' && c != '\t' && c != ' ' && c != ',') { + if (c == '\\') + c = getc(d->cfile); + *cp++ = (char)c; + } + } + *cp = 0; + if (d->tokval[0] == 0) + return (0); + for (t = d->toktab; t->tokstr; t++) + if ((strcmp(t->tokstr, d->tokval) == 0)) + return (t->tval); + return (ID); +} diff --git a/usr/src/lib/libsocket/inet/sourcefilter.c b/usr/src/lib/libsocket/inet/sourcefilter.c new file mode 100644 index 0000000000..77181226b0 --- /dev/null +++ b/usr/src/lib/libsocket/inet/sourcefilter.c @@ -0,0 +1,229 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stropts.h> +#include <errno.h> +#include <sys/sysmacros.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <netinet/in.h> + +int +getsourcefilter(int s, uint32_t interface, struct sockaddr *group, + socklen_t grouplen, uint32_t *fmode, uint_t *numsrc, + struct sockaddr_storage *slist) +{ + struct group_filter *gf; + int mallocsize, orig_numsrc, cpsize, rtnerr; + + mallocsize = (*numsrc == 0) ? + sizeof (struct group_filter) : GROUP_FILTER_SIZE(*numsrc); + gf = (struct group_filter *)malloc(mallocsize); + if (gf == NULL) { + errno = ENOMEM; + return (-1); + } + + gf->gf_interface = interface; + gf->gf_numsrc = orig_numsrc = *numsrc; + switch (group->sa_family) { + case AF_INET: + if (grouplen < sizeof (struct sockaddr_in)) { + rtnerr = ENOPROTOOPT; + goto done; + } + (void) memcpy((void *)&gf->gf_group, (void *)group, + sizeof (struct sockaddr_in)); + break; + case AF_INET6: + if (grouplen < sizeof (struct sockaddr_in6)) { + rtnerr = ENOPROTOOPT; + goto done; + } + (void) memcpy((void *)&gf->gf_group, (void *)group, + sizeof (struct sockaddr_in6)); + break; + default: + rtnerr = EAFNOSUPPORT; + goto done; + } + + rtnerr = ioctl(s, SIOCGMSFILTER, (void *)gf); + if (rtnerr == -1) { + rtnerr = errno; + goto done; + } + + *fmode = gf->gf_fmode; + *numsrc = gf->gf_numsrc; + cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct sockaddr_storage); + (void) memcpy((void *)slist, (void *)gf->gf_slist, cpsize); + +done: + free(gf); + errno = rtnerr; + if (errno != 0) + return (-1); + + return (0); +} + +int +setsourcefilter(int s, uint32_t interface, struct sockaddr *group, + socklen_t grouplen, uint32_t fmode, uint_t numsrc, + struct sockaddr_storage *slist) +{ + struct group_filter *gf; + int mallocsize, rtnerr; + + mallocsize = (numsrc == 0) ? + sizeof (struct group_filter) : GROUP_FILTER_SIZE(numsrc); + gf = (struct group_filter *)malloc(mallocsize); + if (gf == NULL) { + errno = ENOMEM; + return (-1); + } + + switch (group->sa_family) { + case AF_INET: + if (grouplen < sizeof (struct sockaddr_in)) { + rtnerr = ENOPROTOOPT; + goto done; + } + (void) memcpy((void *)&gf->gf_group, (void *)group, + sizeof (struct sockaddr_in)); + break; + case AF_INET6: + if (grouplen < sizeof (struct sockaddr_in6)) { + rtnerr = ENOPROTOOPT; + goto done; + } + (void) memcpy((void *)&gf->gf_group, (void *)group, + sizeof (struct sockaddr_in6)); + break; + default: + rtnerr = EAFNOSUPPORT; + goto done; + } + gf->gf_interface = interface; + gf->gf_fmode = fmode; + gf->gf_numsrc = numsrc; + (void) memcpy((void *)gf->gf_slist, (void *)slist, + (numsrc * sizeof (struct sockaddr_storage))); + + rtnerr = ioctl(s, SIOCSMSFILTER, (void *)gf); + if (rtnerr == -1) { + rtnerr = errno; + } + +done: + free(gf); + errno = rtnerr; + if (errno != 0) + return (-1); + + return (0); +} + +int +getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group, + uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist) +{ + struct ip_msfilter *imsf; + int mallocsize, orig_numsrc, cpsize, rtnerr; + + mallocsize = (*numsrc == 0) ? + sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(*numsrc); + imsf = (struct ip_msfilter *)malloc(mallocsize); + if (imsf == NULL) { + errno = ENOMEM; + return (-1); + } + + imsf->imsf_interface = interface; + imsf->imsf_numsrc = orig_numsrc = *numsrc; + imsf->imsf_multiaddr = group; + + rtnerr = ioctl(s, SIOCGIPMSFILTER, (void *)imsf); + if (rtnerr == -1) { + rtnerr = errno; + goto done; + } + + *fmode = imsf->imsf_fmode; + *numsrc = imsf->imsf_numsrc; + cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct in_addr); + (void) memcpy((void *)slist, (void *)imsf->imsf_slist, cpsize); + +done: + free(imsf); + errno = rtnerr; + if (errno != 0) + return (-1); + + return (0); +} + +int +setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group, + uint32_t fmode, uint32_t numsrc, struct in_addr *slist) +{ + struct ip_msfilter *imsf; + int mallocsize, rtnerr; + + mallocsize = (numsrc == 0) ? + sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(numsrc); + imsf = (struct ip_msfilter *)malloc(mallocsize); + if (imsf == NULL) { + errno = ENOMEM; + return (-1); + } + + imsf->imsf_multiaddr = group; + imsf->imsf_interface = interface; + imsf->imsf_fmode = fmode; + imsf->imsf_numsrc = numsrc; + (void) memcpy((void *)imsf->imsf_slist, (void *)slist, + (numsrc * sizeof (struct in_addr))); + + rtnerr = ioctl(s, SIOCSIPMSFILTER, (void *)imsf); + if (rtnerr == -1) { + rtnerr = errno; + } + + free(imsf); + errno = rtnerr; + if (errno != 0) + return (-1); + + return (0); +} diff --git a/usr/src/lib/libsocket/socket/_soutil.c b/usr/src/lib/libsocket/socket/_soutil.c new file mode 100644 index 0000000000..732b544ac6 --- /dev/null +++ b/usr/src/lib/libsocket/socket/_soutil.c @@ -0,0 +1,254 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 1989 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Portions of this source code were derived from Berkeley 4.3 BSD + * under license from the Regents of the University of California. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +extern int _stat(); + +/* + * XXX The functions in this file are only needed to support transport + * providers that have not yet been converted to use /etc/sock2path. + * Once all transport providers have been converted this file can be + * removed. + */ + +static struct netconfig *_s_match_netconf(int family, int type, int proto, + void **nethandle); + +/* + * The following two string arrays map a number as specified + * by a user of sockets, to the string as would be returned + * by a call to getnetconfig(). + * + * They are used by _s_match_netconf(); + * + * proto_sw contains protocol entries for which there is a corresponding + * /dev device. All others would presumably use raw IP and download the + * desired protocol. + */ +static char *proto_sw[] = { + "", + "icmp", /* 1 = ICMP */ + "", + "", + "", + "", + "tcp", /* 6 = TCP */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "udp", /* 17 = UDP */ +}; + +static char *family_sw[] = { + "-", /* 0 = AF_UNSPEC */ + "loopback", /* 1 = AF_UNIX */ + "inet", /* 2 = AF_INET */ + "implink", /* 3 = AF_IMPLINK */ + "pup", /* 4 = AF_PUP */ + "chaos", /* 5 = AF_CHAOS */ + "ns", /* 6 = AF_NS */ + "nbs", /* 7 = AF_NBS */ + "ecma", /* 8 = AF_ECMA */ + "datakit", /* 9 = AF_DATAKIT */ + "ccitt", /* 10 = AF_CCITT */ + "sna", /* 11 = AF_SNA */ + "decnet", /* 12 = AF_DECnet */ + "dli", /* 13 = AF_DLI */ + "lat", /* 14 = AF_LAT */ + "hylink", /* 15 = AF_HYLINK */ + "appletalk", /* 16 = AF_APPLETALK */ + "nit", /* 17 = AF_NIT */ + "ieee802", /* 18 = AF_802 */ + "osi", /* 19 = AF_OSI */ + "x25", /* 20 = AF_X25 */ + "osinet", /* 21 = AF_OSINET */ + "gosip", /* 22 = AF_GOSIP */ + "ipx", /* 23 = AF_IPX */ + "route", /* 24 = AF_ROUTE */ + "link", /* 25 = AF_LINK */ + "inet6", /* 26 = AF_INET6 */ + "key", /* 27 = AF_KEY */ +}; + +/* + * Lookup family/type/protocol in /etc/netconfig. + * Returns the pathname and a prototype value (to be passed into SO_PROTOTYPE) + * The path is malloc'ed and has to be freed by the caller. + */ +int +_s_netconfig_path(int family, int type, int protocol, + char **pathp, int *prototype) +{ + struct netconfig *net; + void *nethandle; + struct stat stats; + + net = _s_match_netconf(family, type, protocol, &nethandle); + if (net == NULL) + return (-1); + + if (strcmp(net->nc_proto, NC_NOPROTO) != 0) + *prototype = 0; + else + *prototype = protocol; + +retry: +#if defined(i386) + if (_xstat(_STAT_VER, net->nc_device, &stats) < 0) { +#else + if (_stat(net->nc_device, &stats) < 0) { +#endif + switch (errno) { + case EINTR: + goto retry; + + case ENOENT: + case ENOLINK: + case ELOOP: + case EMULTIHOP: + case ENOTDIR: + errno = EPFNOSUPPORT; + break; + } + endnetconfig(nethandle); /* finished with netconfig struct */ + return (-1); + } + if (!S_ISCHR(stats.st_mode)) { + errno = EPFNOSUPPORT; + endnetconfig(nethandle); /* finished with netconfig struct */ + return (-1); + } + *pathp = malloc(strlen(net->nc_device) + 1); + if (*pathp == NULL) { + endnetconfig(nethandle); + errno = ENOMEM; + return (-1); + } + (void) strcpy(*pathp, net->nc_device); + endnetconfig(nethandle); /* finished with netconfig struct */ + return (0); +} + +/* + * Match config entry for protocol + * requested. + */ +static struct netconfig * +_s_match_netconf(int family, int type, int proto, void **nethandle) +{ + struct netconfig *net; + struct netconfig *maybe; + char *oproto; + + if (family < 0 || + family >= (int)sizeof (family_sw) / (int)sizeof (char *) || + proto < 0 || proto >= IPPROTO_MAX) { + errno = EPROTONOSUPPORT; + return (NULL); + } + if (proto) { + if (proto >= (int)sizeof (proto_sw) / (int)sizeof (char *)) + oproto = ""; + else oproto = proto_sw[proto]; + } + + /* + * Loop through each entry in netconfig + * until one matches or we reach the end. + */ + if ((*nethandle = setnetconfig()) == NULL) { + return (NULL); + } + + maybe = NULL; + while ((net = getnetconfig(*nethandle)) != NULL) { + /* + * We make a copy of net->nc_semantics rather than modifying + * it in place because the network selection code shares the + * structures returned by getnetconfig() among all its callers. + * See bug #1160886 for more details. + */ + unsigned int semantics = net->nc_semantics; + + if (semantics == NC_TPI_COTS_ORD) + semantics = NC_TPI_COTS; + if (proto) { + if (strcmp(net->nc_protofmly, family_sw[family]) == 0 && + semantics == type && + strcmp(net->nc_proto, oproto) == 0) + break; + + if (strcmp(net->nc_protofmly, family_sw[family]) == 0 && + type == SOCK_RAW && + semantics == SOCK_RAW && + strcmp(net->nc_proto, NC_NOPROTO) == 0 && + maybe == NULL) + maybe = net; /* in case no exact match */ + + continue; + } else { + if (strcmp(net->nc_protofmly, family_sw[family]) == 0 && + semantics == type) { + break; + } + } + } + if (net == NULL && maybe) + net = maybe; + + if (net == NULL) { + endnetconfig(*nethandle); + errno = EPROTONOSUPPORT; + return (NULL); + } + + return (net); +} diff --git a/usr/src/lib/libsocket/socket/sockatmark.c b/usr/src/lib/libsocket/socket/sockatmark.c new file mode 100644 index 0000000000..9f30e1bbd3 --- /dev/null +++ b/usr/src/lib/libsocket/socket/sockatmark.c @@ -0,0 +1,46 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/sockio.h> +#include <unistd.h> + +#pragma weak sockatmark = _sockatmark + +/* + * Determine whether the socket is at the out-of-band + * data mark. + */ +int +_sockatmark(int sock) +{ + int val; + + if (ioctl(sock, SIOCATMARK, &val) == -1) + return (-1); + return (val); +} diff --git a/usr/src/lib/libsocket/socket/socket.c b/usr/src/lib/libsocket/socket/socket.c new file mode 100644 index 0000000000..3e99ed4900 --- /dev/null +++ b/usr/src/lib/libsocket/socket/socket.c @@ -0,0 +1,156 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 1997 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stropts.h> +#include <sys/stream.h> +#include <sys/socketvar.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> + +extern int _so_socket(); +extern int _s_netconfig_path(); +extern int _setsockopt(); + +int _socket_create(int, int, int, int); + +#pragma weak socket = _socket + +int +_socket(int family, int type, int protocol) +{ + return (_socket_create(family, type, protocol, SOV_DEFAULT)); +} + +/* + * Used by the BCP library. + */ +int +_socket_bsd(int family, int type, int protocol) +{ + return (_socket_create(family, type, protocol, SOV_SOCKBSD)); +} + +int +_socket_svr4(int family, int type, int protocol) +{ + return (_socket_create(family, type, protocol, SOV_SOCKSTREAM)); +} + +int +__xnet_socket(int family, int type, int protocol) +{ + return (_socket_create(family, type, protocol, SOV_XPG4_2)); +} + +/* + * Create a socket endpoint for socket() and socketpair(). + * In SunOS 4.X and in SunOS 5.X prior to XPG 4.2 the only error + * that could be returned due to invalid <family, type, protocol> + * was EPROTONOSUPPORT. (While the SunOS 4.X source contains EPROTOTYPE + * error as well that error can only be generated if the kernel is + * incorrectly configured.) + * For backwards compatibility only applications that request XPG 4.2 + * (through c89 or XOPEN_SOURCE) will get EPROTOTYPE or EAFNOSUPPORT errors. + */ +int +_socket_create(int family, int type, int protocol, int version) +{ + int fd; + + /* + * Try creating without knowing the device assuming that + * the transport provider is registered in /etc/sock2path. + * If none found fall back to using /etc/netconfig to look + * up the name of the transport device name. This provides + * backwards compatibility for transport providers that have not + * yet been converted to using /etc/sock2path. + * XXX When all transport providers use /etc/sock2path this + * part of the code can be removed. + */ + fd = _so_socket(family, type, protocol, NULL, version); + if (fd == -1) { + char *devpath; + int saved_errno = errno; + int prototype = 0; + + switch (saved_errno) { + case EAFNOSUPPORT: + case EPROTOTYPE: + if (version != SOV_XPG4_2) + saved_errno = EPROTONOSUPPORT; + break; + case EPROTONOSUPPORT: + break; + + default: + errno = saved_errno; + return (-1); + } + if (_s_netconfig_path(family, type, protocol, + &devpath, &prototype) == -1) { + errno = saved_errno; + return (-1); + } + fd = _so_socket(family, type, protocol, devpath, version); + free(devpath); + if (fd == -1) { + errno = saved_errno; + return (-1); + } + if (prototype != 0) { + if (_setsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, + (caddr_t)&prototype, (int)sizeof (prototype)) < 0) { + (void) close(fd); + /* + * setsockopt often fails with ENOPROTOOPT + * but socket() should fail with + * EPROTONOSUPPORT. + */ + errno = EPROTONOSUPPORT; + return (-1); + } + } + } + return (fd); +} diff --git a/usr/src/lib/libsocket/socket/socketpair.c b/usr/src/lib/libsocket/socket/socketpair.c new file mode 100644 index 0000000000..d9bbc8f461 --- /dev/null +++ b/usr/src/lib/libsocket/socket/socketpair.c @@ -0,0 +1,130 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 1997 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stropts.h> +#include <sys/stream.h> +#include <sys/socketvar.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> + +extern int _socket_create(int, int, int, int); +extern int _so_socketpair(int*); + +int _socketpair_create(int, int, int, int*, int); + +#pragma weak socketpair = _socketpair + +int +_socketpair(int family, int type, int protocol, int sv[2]) +{ + return (_socketpair_create(family, type, protocol, sv, SOV_DEFAULT)); +} + +/* + * Used by the BCP library. + */ +int +_socketpair_bsd(int family, int type, int protocol, int sv[2]) +{ + return (_socketpair_create(family, type, protocol, sv, SOV_SOCKBSD)); +} + +int +_socketpair_svr4(int family, int type, int protocol, int sv[2]) +{ + return (_socketpair_create(family, type, protocol, sv, + SOV_SOCKSTREAM)); +} + +int +__xnet_socketpair(int family, int type, int protocol, int sv[2]) +{ + return (_socketpair_create(family, type, protocol, sv, + SOV_XPG4_2)); +} + +int +_socketpair_create(int family, int type, int protocol, int sv[2], int version) +{ + int res; + int fd1, fd2; + + /* + * Create the two sockets and pass them to _so_socketpair, which + * will connect them together. + */ + fd1 = _socket_create(family, type, protocol, version); + if (fd1 < 0) + return (-1); + fd2 = _socket_create(family, type, protocol, version); + if (fd2 < 0) { + int error = errno; + + (void) close(fd1); + errno = error; + return (-1); + } + sv[0] = fd1; + sv[1] = fd2; + res = _so_socketpair(sv); + if (res < 0) { + int error = errno; + + (void) close(fd1); + (void) close(fd2); + errno = error; + return (-1); + } + /* + * Check if kernel returned different fds in which case we close + * the original ones. This is the case for SOCK_STREAM where + * one of the original sockets is used as a listener and + * _so_socketpair passes out the newly accepted socket. + */ + if (sv[0] != fd1) + (void) close(fd1); + if (sv[1] != fd2) + (void) close(fd2); + return (res); +} diff --git a/usr/src/lib/libsocket/socket/weaks.c b/usr/src/lib/libsocket/socket/weaks.c new file mode 100644 index 0000000000..ddca64c410 --- /dev/null +++ b/usr/src/lib/libsocket/socket/weaks.c @@ -0,0 +1,264 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stropts.h> +#include <sys/stream.h> +#include <sys/socketvar.h> +#include <sys/sockio.h> + +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <stropts.h> +#include <stdio.h> +#include <strings.h> +#include <netinet/sctp.h> + +#pragma weak bind = _bind +#pragma weak listen = _listen +#pragma weak accept = _accept +#pragma weak connect = _connect +#pragma weak shutdown = _shutdown +#pragma weak recv = _recv +#pragma weak recvfrom = _recvfrom +#pragma weak recvmsg = _recvmsg +#pragma weak send = _send +#pragma weak sendmsg = _sendmsg +#pragma weak sendto = _sendto +#pragma weak getpeername = _getpeername +#pragma weak getsockname = _getsockname +#pragma weak getsockopt = _getsockopt +#pragma weak setsockopt = _setsockopt + +extern int _so_bind(); +extern int _so_listen(); +extern int _so_accept(); +extern int _so_connect(); +extern int _so_shutdown(); +extern int _so_recv(); +extern int _so_recvfrom(); +extern int _so_recvmsg(); +extern int _so_send(); +extern int _so_sendmsg(); +extern int _so_sendto(); +extern int _so_getpeername(); +extern int _so_getsockopt(); +extern int _so_setsockopt(); +extern int _so_setsockname(); +extern int _so_getsockname(); + +/* + * Note that regular sockets use SOV_SOCKBSD here to not allow a rebind of an + * already bound socket. + */ +int +_bind(int sock, struct sockaddr *addr, int addrlen) +{ + return (_so_bind(sock, addr, addrlen, SOV_SOCKBSD)); +} + +int +_listen(int sock, int backlog) +{ + return (_so_listen(sock, backlog, SOV_DEFAULT)); +} + +int +_accept(int sock, struct sockaddr *addr, int *addrlen) +{ + return (_so_accept(sock, addr, addrlen, SOV_DEFAULT)); +} + +int +_connect(int sock, struct sockaddr *addr, int addrlen) +{ + return (_so_connect(sock, addr, addrlen, SOV_DEFAULT)); +} + +int +_shutdown(int sock, int how) +{ + return (_so_shutdown(sock, how, SOV_DEFAULT)); +} + +int +_recv(int sock, char *buf, int len, int flags) +{ + return (_so_recv(sock, buf, len, flags & ~MSG_XPG4_2)); +} + +int +_recvfrom(int sock, char *buf, int len, int flags, + struct sockaddr *addr, int *addrlen) +{ + return (_so_recvfrom(sock, buf, len, flags & ~MSG_XPG4_2, + addr, addrlen)); +} + +int +_recvmsg(int sock, struct msghdr *msg, int flags) +{ + return (_so_recvmsg(sock, msg, flags & ~MSG_XPG4_2)); +} + +int +_send(int sock, char *buf, int len, int flags) +{ + return (_so_send(sock, buf, len, flags & ~MSG_XPG4_2)); +} + +int +_sendmsg(int sock, struct msghdr *msg, int flags) +{ + return (_so_sendmsg(sock, msg, flags & ~MSG_XPG4_2)); +} + +int +_sendto(int sock, char *buf, int len, int flags, + struct sockaddr *addr, int *addrlen) +{ + return (_so_sendto(sock, buf, len, flags & ~MSG_XPG4_2, + addr, addrlen)); +} + +int +_getpeername(int sock, struct sockaddr *name, int *namelen) +{ + return (_so_getpeername(sock, name, namelen, SOV_DEFAULT)); +} + +int +_getsockname(int sock, struct sockaddr *name, int *namelen) +{ + return (_so_getsockname(sock, name, namelen, SOV_DEFAULT)); +} + +int +_getsockopt(int sock, int level, int optname, char *optval, int *optlen) +{ + if (level == IPPROTO_SCTP) { + sctp_assoc_t id = 0; + socklen_t len = *optlen; + int err = 0; + struct sctpopt sopt; + + switch (optname) { + case SCTP_RTOINFO: + case SCTP_ASSOCINFO: + case SCTP_SET_PEER_PRIMARY_ADDR: + case SCTP_PRIMARY_ADDR: + case SCTP_PEER_ADDR_PARAMS: + case SCTP_STATUS: + case SCTP_GET_PEER_ADDR_INFO: + /* + * Association ID is the first element params struct + */ + bcopy(optval, &id, sizeof (id)); + break; + case SCTP_DEFAULT_SEND_PARAM: + bcopy(&((struct sctp_sndrcvinfo *) + optval)->sinfo_assoc_id, &id, sizeof (id)); + break; + } + + sopt.sopt_aid = id; + sopt.sopt_name = optname; + sopt.sopt_val = optval; + sopt.sopt_len = len; + if (ioctl(sock, SIOCSCTPGOPT, &sopt) == -1) { + err = -1; + } else { + *optlen = sopt.sopt_len; + } + return (err); + } else { + return (_so_getsockopt(sock, level, optname, optval, optlen, + SOV_DEFAULT)); + } +} + +int +_setsockopt(int sock, int level, int optname, char *optval, int optlen) +{ + return (_so_setsockopt(sock, level, optname, optval, optlen, + SOV_DEFAULT)); +} + +int +__xnet_bind(int sock, const struct sockaddr *addr, socklen_t addrlen) +{ + return (_so_bind(sock, addr, addrlen, SOV_XPG4_2)); +} + + +int +__xnet_listen(int sock, int backlog) +{ + return (_so_listen(sock, backlog, SOV_XPG4_2)); +} + +int +__xnet_connect(int sock, const struct sockaddr *addr, socklen_t addrlen) +{ + return (_so_connect(sock, addr, addrlen, SOV_XPG4_2)); +} + +int +__xnet_recvmsg(int sock, struct msghdr *msg, int flags) +{ + return (_so_recvmsg(sock, msg, flags | MSG_XPG4_2)); +} + +int +__xnet_sendmsg(int sock, const struct msghdr *msg, int flags) +{ + return (_so_sendmsg(sock, msg, flags | MSG_XPG4_2)); +} + +int +__xnet_sendto(int sock, const void *buf, size_t len, int flags, + const struct sockaddr *addr, socklen_t addrlen) +{ + return (_so_sendto(sock, buf, len, flags | MSG_XPG4_2, + addr, addrlen)); +} + +int +__xnet_getsockopt(int sock, int level, int option_name, + void *option_value, socklen_t *option_lenp) +{ + if (level == IPPROTO_SCTP) { + return (_getsockopt(sock, level, option_name, option_value, + (int *)option_lenp)); + } else { + return (_so_getsockopt(sock, level, option_name, option_value, + option_lenp, SOV_XPG4_2)); + } +} diff --git a/usr/src/lib/libsocket/sparc/Makefile b/usr/src/lib/libsocket/sparc/Makefile new file mode 100644 index 0000000000..c3ea53cfe4 --- /dev/null +++ b/usr/src/lib/libsocket/sparc/Makefile @@ -0,0 +1,33 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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) 1997-2001 by Sun Microsystems, Inc. +# All rights reserved. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +all: $(LIBS) + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libsocket/sparcv9/Makefile b/usr/src/lib/libsocket/sparcv9/Makefile new file mode 100644 index 0000000000..2eafde412a --- /dev/null +++ b/usr/src/lib/libsocket/sparcv9/Makefile @@ -0,0 +1,34 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 1997-2003 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +all: $(LIBS) + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libsocket/spec/Makefile b/usr/src/lib/libsocket/spec/Makefile new file mode 100644 index 0000000000..e64c72ecb3 --- /dev/null +++ b/usr/src/lib/libsocket/spec/Makefile @@ -0,0 +1,29 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1998-1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# lib/libsocket/spec/Makefile + +include $(SRC)/lib/Makefile.spec.arch diff --git a/usr/src/lib/libsocket/spec/Makefile.targ b/usr/src/lib/libsocket/spec/Makefile.targ new file mode 100644 index 0000000000..9cc59c24e7 --- /dev/null +++ b/usr/src/lib/libsocket/spec/Makefile.targ @@ -0,0 +1,36 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1998-1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# lib/libsocket/spec/Makefile.targ + +LIBRARY = libsocket.a +VERS = .1 + +OBJECTS = socket.o \ + svr4msg.o \ + xpgmsg.o + +SPECCPP = -I.. diff --git a/usr/src/lib/libsocket/spec/amd64/Makefile b/usr/src/lib/libsocket/spec/amd64/Makefile new file mode 100644 index 0000000000..453c0ea671 --- /dev/null +++ b/usr/src/lib/libsocket/spec/amd64/Makefile @@ -0,0 +1,44 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +.KEEP_STATE: + +include ../Makefile.targ + +# Add arch specific objects here +OBJECTS += + +include $(SRC)/lib/Makefile.lib +include $(SRC)/lib/Makefile.lib.64 + +# Uncomment the following if the linker complains +#amd64_C_PICFLAGS = -K PIC + +include $(SRC)/lib/Makefile.spec + +install: $(ROOTABILIB64) diff --git a/usr/src/lib/libsocket/spec/i386/Makefile b/usr/src/lib/libsocket/spec/i386/Makefile new file mode 100644 index 0000000000..e5a8b4318a --- /dev/null +++ b/usr/src/lib/libsocket/spec/i386/Makefile @@ -0,0 +1,44 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1998-1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# lib/libsocket/spec/i386/Makefile + +.KEEP_STATE: + +include ../Makefile.targ + +# Add arch specific objects here +OBJECTS += + +include $(SRC)/lib/Makefile.lib + +# Uncomment the following if the linker complains +#i386_C_PICFLAGS = -K PIC + +include $(SRC)/lib/Makefile.spec + +install: $(ROOTABILIB) diff --git a/usr/src/lib/libsocket/spec/socket.spec b/usr/src/lib/libsocket/spec/socket.spec new file mode 100644 index 0000000000..bb614f918b --- /dev/null +++ b/usr/src/lib/libsocket/spec/socket.spec @@ -0,0 +1,895 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# ident "%Z%%M% %I% %E% SMI" +# + +# NOTE: Look at "versions" file for more details on why there may +# appear to be "gaps" in version number space. + +function endservent +include <netdb.h> +declaration int endservent(void) +version SUNW_0.7 +end + +function __xnet_bind +include <sys/types.h>, <sys/socket.h> +declaration int __xnet_bind(int socket, const struct sockaddr *address, \ + socklen_t address_len) +version SUNW_1.1 +errno EACCES EADDRINUSE EADDRNOTAVAIL EBADF EINVAL ENOSR \ + ENOTSOCK EIO EISDIR ELOOP ENOENT ENOTDIR EROFS +exception +end + +function __xnet_connect +include <sys/types.h>, <sys/socket.h> +declaration int __xnet_connect(int socket, const struct sockaddr *address, \ + socklen_t address_len) +version SUNW_1.1 +errno EACCES EADDRINUSE EADDRNOTAVAIL EAFNOSUPPORT EALREADY EBADF \ + ECONNREFUSED EINPROGRESS EINTR EINVAL EIO EISCONN ELOOP \ + ENETUNREACH ENOENT ENOSR ENXIO ETIMEDOUT ENOTDIR \ + ENOTSOCK EPROTOTYPE +exception $return == -1 +end + +function __xnet_getsockopt +include <sys/types.h>, <sys/socket.h> +declaration int __xnet_getsockopt(int socket, int level, \ + int option_name, void *option_value, \ + Psocklen_t option_len) +version SUNW_1.1 +errno EBADF ENOPROTOOPT ENOTSOCK EINVAL EOPNOTSUPP ENOBUFS ENOSR +exception $return == -1 +end + +function __xnet_listen +include <sys/types.h>, <sys/socket.h> +declaration int __xnet_listen(int socket, int backlog) +version SUNW_1.1 +errno EBADF ENOTSOCK EOPNOTSUPP EINVAL EDESTADDRREQ ENOBUFS +exception $return == -1 +end + +function __xnet_sendto +include <sys/types.h>, <sys/socket.h> +declaration int __xnet_sendto(int socket, const void *message, \ + size_t length, int flags, \ + const struct sockaddr *dest_addr, size_t dest_len) +version SUNW_1.1 +errno EAFNOSUPPORT EBADF ECONNRESET EINTR EMSGSIZE ENOTCONN \ + ENOTSOCK EOPNOTSUPP EPIPE EWOULDBLOCK EAGAIN EACCES \ + EIO ELOOP ENAMETOOLONG ENOENT ENOTDIR EDESTADDRREQ \ + EHOSTUNREACH EISCONN ENETDOWN ENETUNREACH ENOBUFS \ + ENOMEM ENOSR +exception $return == -1 +end + +function __xnet_socket +include <sys/types.h>, <sys/socket.h> +declaration int __xnet_socket(int domain, int type, int protocol) +version SUNW_1.1 +errno EACCES EAFNOSUPPORT EMFILE ENFILE EPROTONOSUPPORT EPROTOTYPE \ + ENOBUFS ENOMEM ENOSR +exception $return == -1 +end + +function __xnet_socketpair +include <sys/types.h>, <sys/socket.h> +declaration int __xnet_socketpair(int domain, int type, int protocol, \ + int socket_vector[2]) +version SUNW_1.1 +errno EAFNOSUPPORT EMFILE ENFILE EOPNOTSUPP EPROTONOSUPPORT \ + EPROTOTYPE EACCES ENOMEM ENOBUFS ENOSR +exception $return == -1 +end + +function accept +include <sys/types.h>, <sys/socket.h> +declaration int accept(int s, struct sockaddr *addr, void *addrlen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF EINTR ENODEV ENOMEM ENOSR ENOTSOCK EOPNOTSUPP EPROTO \ + EWOULDBLOCK +exception $return == -1 +end + +function bind +include <sys/types.h>, <sys/socket.h> +declaration int bind(int s, const struct sockaddr *name, socklen_t namelen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EACCES EADDRINUSE EADDRNOTAVAIL EBADF EINVAL ENOSR ENOTSOCK \ + EIO EISDIR ELOOP ENOENT ENOTDIR EROFS +exception +end + +function bindresvport +version SUNWprivate_1.1 +end + +function connect +include <sys/types.h>, <sys/socket.h> +declaration int connect(int s, const struct sockaddr *name, \ + socklen_t namelen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EACCES EADDRINUSE EADDRNOTAVAIL EAFNOSUPPORT EALREADY EBADF \ + ECONNREFUSED EINPROGRESS EINTR EINVAL EIO EISCONN \ + ELOOP ENETUNREACH ENOENT ENOSR ENXIO ETIMEDOUT \ + ENOTDIR ENOTSOCK EPROTOTYPE +exception $return == -1 +end + +function endnetent +include <netdb.h> +declaration int endnetent(void) +version SUNW_0.7 +exception $return == -1 +end + +function endprotoent +include <netdb.h> +declaration int endprotoent(void) +version SUNW_0.7 +errno ERANGE +end + +function ether_aton +include <sys/types.h> +include <sys/socket.h> +include <net/if.h> +include <netinet/in.h> +include <netinet/if_ether.h> +declaration struct ether_addr *ether_aton (const char *s) +version SUNW_0.7 +exception +end + +function ether_hostton +include <sys/types.h> +include <sys/socket.h> +include <net/if.h> +include <netinet/in.h> +include <netinet/if_ether.h> +declaration int ether_hostton (const char *hostname, struct ether_addr *e) +version SUNW_0.7 +exception +end + +function ether_line +include <sys/types.h> +include <sys/socket.h> +include <net/if.h> +include <netinet/in.h> +include <netinet/if_ether.h> +declaration int ether_line (const char *l, struct ether_addr *e, \ + char *hostname) +version SUNW_0.7 +exception +end + +function ether_ntoa +include <sys/types.h> +include <sys/socket.h> +include <net/if.h> +include <netinet/in.h> +include <netinet/if_ether.h> +declaration char *ether_ntoa (const struct ether_addr *e) +version SUNW_0.7 +exception +end + +function ether_ntohost +include <sys/types.h> +include <sys/socket.h> +include <net/if.h> +include <netinet/in.h> +include <netinet/if_ether.h> +declaration int ether_ntohost (char *hostname, const struct ether_addr *e) +version SUNW_0.7 +exception +end + +function freeaddrinfo +include <sys/socket.h> +include <netdb.h> +declaration void freeaddrinfo(struct addrinfo *ai) +version SUNW_1.4 +end + +function gai_strerror +include <sys/socket.h> +include <netdb.h> +declaration const char *gai_strerror(int ecode) +version SUNW_1.4 +end + +function getaddrinfo +include <sys/socket.h> +include <netdb.h> +declaration int getaddrinfo(const char *hostname, const char *servname, \ + const struct addrinfo *hints, struct addrinfo **res) +version SUNW_1.4 +exception $return != 0 +end + +function __xnet_getaddrinfo +include <sys/socket.h> +include <netdb.h> +declaration int __xnet_getaddrinfo(const char *hostname, \ + const char *servname, const struct addrinfo *hints, \ + struct addrinfo **res) +version SUNW_1.5 +exception $return != 0 +end + +function getnameinfo +include <sys/socket.h> +include <netdb.h> +declaration int getnameinfo(const struct sockaddr *sa, socklen_t salen, \ + char *host, socklen_t hostlen, char *serv, \ + socklen_t servlen, int flags) +version SUNW_1.4 +exception $return != 0 +end + +function getnetbyaddr +include <netdb.h> +declaration struct netent *getnetbyaddr(in_addr_t net, int type) +version SUNW_0.7 +exception $return == 0 +end + +function getnetbyaddr_r +include <netdb.h> +declaration struct netent *getnetbyaddr_r(long net, int type, \ + struct netent *result, char *buffer, int buflen) +version SUNW_0.7 +exception $return == 0 +end + +function getnetbyname +include <netdb.h> +declaration struct netent *getnetbyname(const char *name) +version SUNW_0.7 +exception $return == 0 +end + +function getnetbyname_r +include <netdb.h> +declaration struct netent *getnetbyname_r(const char *name, \ + struct netent *result, char *buffer, int buflen) +version SUNW_0.7 +exception $return == 0 +end + +function getnetent +include <netdb.h> +declaration struct netent *getnetent(void) +version SUNW_0.7 +exception $return == 0 +end + +function getnetent_r +include <netdb.h> +declaration struct netent *getnetent_r(struct netent *result, \ + char *buffer, int buflen) +version SUNW_0.7 +exception $return == 0 +end + +function getpeername +include <sys/socket.h> +declaration int getpeername(int s, struct sockaddr *name, \ + Psocklen_t namelen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF ENOMEM ENOSR ENOTCONN ENOTSOCK +exception $return == -1 +end + +function getprotobyname +include <netdb.h> +declaration struct protoent *getprotobyname(const char *name) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno ERANGE +exception $return == 0 +end + +function getprotobyname_r +include <netdb.h> +declaration struct protoent *getprotobyname_r(const char *name, \ + struct protoent *result, char *buffer, int buflen) +version SUNW_0.7 +errno ERANGE +exception $return == 0 +end + +function getprotobynumber +include <netdb.h> +declaration struct protoent *getprotobynumber(int proto) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno ERANGE +exception $return == 0 +end + +function getprotobynumber_r +include <netdb.h> +declaration struct protoent *getprotobynumber_r(int proto, \ + struct protoent *result, char *buffer, int buflen) +version SUNW_0.7 +errno ERANGE +exception $return == 0 +end + +function getprotoent +include <netdb.h> +declaration struct protoent *getprotoent(void) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno ERANGE +exception $return == 0 +end + +function getprotoent_r +include <netdb.h> +declaration struct protoent *getprotoent_r(struct protoent *result, \ + char *buffer, int buflen) +version SUNW_0.7 +errno ERANGE +exception $return == 0 +end + +function getservbyname +include <netdb.h> +declaration struct servent *getservbyname(const char *name, \ + const char *proto) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +exception $return == 0 +end + +function getservbyname_r +include <netdb.h> +declaration struct servent *getservbyname_r(const char *name, \ + const char *proto, struct servent *result, \ + char *buffer, int buflen) +version SUNW_0.7 +exception $return == 0 +end + +function getservbyport +include <netdb.h> +declaration struct servent *getservbyport(int port, const char *proto) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +exception $return == 0 +end + +function getservbyport_r +include <netdb.h> +declaration struct servent *getservbyport_r(int port, const char *proto, \ + struct servent *result, char *buffer, int buflen) +version SUNW_0.7 +exception $return == 0 +end + +function getservent +include <netdb.h> +declaration struct servent *getservent(void) +version SUNW_0.7 +exception $return == 0 +end + +function getservent_r +include <netdb.h> +declaration struct servent *getservent_r(struct servent *result, \ + char *buffer, int buflen) +version SUNW_0.7 +exception $return == 0 +end + +function getsockname +include <sys/types.h> +include <sys/socket.h> +declaration int getsockname(int s, struct sockaddr *name, void *namelen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF ENOMEM ENOSR ENOTSOCK +exception $return == -1 +end + +function getsockopt +include <sys/types.h> +include <sys/socket.h> +declaration int getsockopt(int s, int level, int optname, void *optval, \ + void *optlen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF ENOMEM ENOPROTOOPT ENOSR ENOTSOCK +exception $return == -1 +end + +function getsourcefilter +include <netinet/in.h> +declaration int getsourcefilter(int s, uint32_t interface, \ + struct sockaddr *group, socklen_t grouplen, \ + uint32_t *fmode, uint_t *numsrc, \ + struct sockaddr_storage *slist) +version SUNW_1.6 +errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO EADDRNOTAVAIL +exception $return == -1 +end + +function getipv4sourcefilter +include <netinet/in.h> +declaration int getipv4sourcefilter(int s, struct in_addr interface, \ + struct in_addr group, uint32_t *fmode, \ + uint32_t *numsrc, struct in_addr *slist) +version SUNW_1.6 +errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO EADDRNOTAVAIL +exception $return == -1 +end + +function htonl +include <sys/types.h> +include <netinet/in.h> +include <inttypes.h> +declaration uint32_t htonl(uint32_t hostlong) +version SUNW_0.7 +end + +function htons +include <sys/types.h> +include <netinet/in.h> +include <inttypes.h> +declaration uint16_t htons(uint16_t hostshort) +version SUNW_0.7 +end + +function if_freenameindex +include <net/if.h> +declaration void if_freenameindex(struct if_nameindex *ptr) +version SUNW_1.4 +end + +function if_indextoname +include <net/if.h> +declaration char *if_indextoname(uint32_t ifindex, char *ifname) +version SUNW_1.4 +exception $return == 0 +end + +function if_nametoindex +include <net/if.h> +declaration uint32_t if_nametoindex(const char *ifname) +version SUNW_1.4 +exception $return == 0 +end + +function if_nameindex +include <net/if.h> +declaration struct if_nameindex *if_nameindex(void) +version SUNW_1.4 +exception $return == 0 +end + +data in6addr_any +declaration const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT +version SUNW_1.4 +end + +data in6addr_loopback +declaration const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT +version SUNW_1.4 +end + +function inet_lnaof +include <sys/types.h> +include <netinet/in.h> +declaration in_addr_t inet_lnaof(struct in_addr in) +# see inet_lnaof inet (3n) - Internet address manipulation +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +end + +function inet_makeaddr +include <sys/types.h> +include <netinet/in.h> +declaration struct in_addr inet_makeaddr(in_addr_t net, in_addr_t lna) +# see inet_makeaddr inet (3n) - Internet address manipulation +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +end + +function inet_network +include <sys/types.h> +include <netinet/in.h> +declaration in_addr_t inet_network(const char *cp) +# see inet_network inet (3n) - Internet address manipulation +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +end + +function listen +include <sys/types.h> +include <sys/socket.h> +declaration int listen(int socket, int backlog) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF ENOTSOCK EOPNOTSUPP EINVAL EDESTADDRREQ ENOBUFS +exception $return == -1 +end + +function ntohl +include <sys/types.h> +include <netinet/in.h> +include <inttypes.h> +declaration uint32_t ntohl(uint32_t netlong) +version SUNW_0.7 +end + +function ntohs +include <sys/types.h> +include <netinet/in.h> +include <inttypes.h> +declaration uint16_t ntohs(uint16_t netshort) +version SUNW_0.7 +end + +function rcmd +include <netdb.h> +declaration int rcmd(char **ahost, unsigned short inport, \ + const char *luser, const char *ruser, const char *cmd, \ + int *fd2p) +version SUNW_0.7 +exception $return == -1 +end + +function rcmd_af +include <netdb.h> +declaration int rcmd_af(char **ahost, unsigned short inport, \ + const char *luser, const char *ruser, \ + const char *cmd, int *fd2p, int af) +version SUNW_1.4 +exception $return == -1 +end + +function recv +include <sys/types.h> +include <sys/socket.h> +include <sys/uio.h> +declaration ssize_t recv(int s, void *buf, size_t len, int flags) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF EINTR EIO ENOMEM ENOSR ENOTSOCK ESTALE EWOULDBLOCK +exception $return == -1 +end + +function recvfrom +include <sys/types.h> +include <sys/socket.h> +include <sys/uio.h> +declaration ssize_t recvfrom(int s, void *buf, size_t len, int flags, \ + struct sockaddr *from, void *fromlen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF EINTR EIO ENOMEM ENOSR ENOTSOCK ESTALE EWOULDBLOCK +exception $return == -1 +end + +function rexec +include <netdb.h> +declaration int rexec(char **ahost, unsigned short inport, \ + const char *user, const char *passwd, const char *cmd, \ + int *fd2p) +version SUNW_0.7 +exception $return == -1 +end + +function rexec_af +include <netdb.h> +declaration int rexec_af(char **ahost, unsigned short inport, \ + const char *user, const char *passwd, \ + const char *cmd, int *fd2p, int af) +version SUNW_1.4 +exception $return == -1 +end + +function rresvport +include <netdb.h> +declaration int rresvport(int *port) +version SUNW_0.7 +exception $return == -1 +end + +function rresvport_af +include <netdb.h> +declaration int rresvport_af(int *alport, int af) +version SUNW_1.4 +exception $return == -1 +end + +function rresvport_addr +include <netdb.h> +declaration int rresvport_addr(int *alport, struct sockaddr_storage *addr) +version SUNWprivate_1.1 +exception $return == -1 +end + +function ruserok +include <netdb.h> +declaration int ruserok(const char *rhost, int suser, const char *ruser, \ + const char *luser) +version SUNW_0.7 +exception $return == -1 +end + +function send +include <sys/types.h> +include <sys/socket.h> +declaration ssize_t send(int s, const void *msg, size_t len, int flags) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF EINTR EINVAL EMSGSIZE ENOMEM ENOSR ENOTSOCK EWOULDBLOCK +exception $return == -1 +end + +function sendto +include <sys/types.h> +include <sys/socket.h> +declaration ssize_t sendto(int s, const void *msg, size_t len, int flags, \ + const struct sockaddr *to, socklen_t tolen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF EINTR EINVAL EMSGSIZE ENOMEM ENOSR ENOTSOCK EWOULDBLOCK +exception $return == -1 +end + +function setnetent +include <netdb.h> +declaration int setnetent(int stayopen) +version SUNW_0.7 +exception $return == -1 +end + +function setprotoent +include <netdb.h> +declaration int setprotoent(int stayopen) +version SUNW_0.7 +errno ERANGE +end + +function setservent +include <netdb.h> +declaration int setservent(int stayopen) +version SUNW_0.7 +exception $return == 0 +end + +function setsockopt +include <sys/types.h> +include <sys/socket.h> +declaration int setsockopt(int s, int level, int optname, \ + const void *optval, socklen_t optlen) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF ENOMEM ENOPROTOOPT ENOSR ENOTSOCK +exception $return == -1 +end + +function setsourcefilter +include <netinet/in.h> +declaration int setsourcefilter(int s, uint32_t interface, \ + struct sockaddr *group, socklen_t grouplen, \ + uint32_t fmode, uint_t numsrc, \ + struct sockaddr_storage *slist) +version SUNW_1.6 +errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO ENOBUFS +exception $return == -1 +end + +function setipv4sourcefilter +include <netinet/in.h> +declaration int setipv4sourcefilter(int s, struct in_addr interface, \ + struct in_addr group, uint32_t fmode, + uint32_t numsrc, struct in_addr *slist) +version SUNW_1.6 +errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO ENOBUFS +exception $return == -1 +end + +function shutdown +declaration int shutdown(int s, int how) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF ENOMEM ENOSR ENOTCONN ENOTSOCK +exception $return == -1 +end + +function sockatmark +declaration int sockatmark(int socket) +version SUNW_1.5 +errno EBADF ENOTTY +exception $return == -1 +end + +function socket +include <sys/types.h> +include <sys/socket.h> +declaration int socket(int domain, int type, int protocol) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EACCES EMFILE ENOMEM ENOSR EPROTONOSUPPORT +exception $return == -1 +end + +function socketpair +include <sys/types.h> +include <sys/socket.h> +declaration int socketpair(int domain, int type, int protocol, int sv[2]) +version SUNW_0.7 +errno EAFNOSUPPORT EMFILE ENOMEM ENOSR EOPNOTSUPP EPROTONOSUPPORT +exception $return == -1 +end + +function _link_ntoa +include <net/if_dl.h> +declaration char *_link_ntoa(const unsigned char *, char *, int, int) +version SUNWprivate_1.3 +exception $return == 0 +end + +function _link_aton +include <net/if_dl.h> +declaration unsigned char *_link_aton(const char *, int *) +version SUNWprivate_1.3 +exception $return == 0 +end + +# IPv6 routing header manipulation +function inet6_rth_add +include <netinet/in.h> +declaration int inet6_rth_add(void *bp, const struct in6_addr *addr) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_rth_init +include <netinet/in.h> +declaration void *inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments) +version SUNW_1.5 +errno +exception $return == 0 +end + +function inet6_rth_getaddr +include <netinet/in.h> +declaration struct in6_addr *inet6_rth_getaddr(const void *bp, int index) +version SUNW_1.5 +errno +exception $return == 0 +end + +function inet6_rth_reverse +include <netinet/in.h> +declaration int inet6_rth_reverse(const void *in, void *out) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_rth_segments +include <netinet/in.h> +declaration int inet6_rth_segments(const void *bp) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_rth_space +include <unistd.h> +declaration socklen_t inet6_rth_space(int type, int segments) +version SUNW_1.5 +errno +exception $return == 0 +end + +# IPv6 option header manipulation +function inet6_opt_init +include <netinet/in.h>, <sys/socket.h> +declaration int inet6_opt_init(void *extbuf, socklen_t extlen) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_opt_append +include <netinet/in.h>, <sys/socket.h> +declaration int inet6_opt_append(void *extbuf, socklen_t extlen,\ + int offset, uint8_t type, socklen_t len, uint_t align,\ + void **databufp) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_opt_finish +include <netinet/in.h>, <sys/socket.h> +declaration int inet6_opt_finish(void *extbuf, socklen_t extlen,\ + int offset) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_opt_set_val +include <netinet/in.h>, <sys/socket.h> +declaration int inet6_opt_set_val(void *databuf, int offset, void *val,\ + socklen_t vallen) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_opt_next +include <netinet/in.h>, <sys/socket.h> +declaration int inet6_opt_next(void *extbuf, socklen_t extlen, int offset,\ + uint8_t *typep, socklen_t *lenp, void **databufp) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_opt_find +include <netinet/in.h>, <sys/socket.h> +declaration int inet6_opt_find(void *extbuf, socklen_t extlen, int offset,\ + uint8_t type, socklen_t *lenp, void **databufp) +version SUNW_1.5 +errno +exception $return == -1 +end + +function inet6_opt_get_val +include <netinet/in.h>, <sys/socket.h> +declaration int inet6_opt_get_val(void *databuf, int offset, void *val,\ + socklen_t vallen) +version SUNW_1.5 +errno +exception $return == -1 +end + +# mh mailing system +function _ruserpass +version SUNWprivate_1.1 +end + +# BCP +function _socket_bsd +version SUNWprivate_1.1 +end + +# BCP +function _socketpair_bsd +version SUNWprivate_1.1 +end + +# rpc.bootparamd +function bootparams_getbyname +version SUNWprivate_1.1 +end + +# ifconfig +function getnetmaskbyaddr +version SUNWprivate_1.2 +end + +# in.dhcpd, dhcp admin +function getnetmaskbynet +version SUNWprivate_1.2 +end diff --git a/usr/src/lib/libsocket/spec/sparc/Makefile b/usr/src/lib/libsocket/spec/sparc/Makefile new file mode 100644 index 0000000000..3de398fdd4 --- /dev/null +++ b/usr/src/lib/libsocket/spec/sparc/Makefile @@ -0,0 +1,44 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1998-1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# lib/libsocket/spec/sparc/Makefile + +.KEEP_STATE: + +include ../Makefile.targ + +# Add arch specific objects here +OBJECTS += + +include $(SRC)/lib/Makefile.lib + +# Uncomment the following if the linker complains +#sparc_C_PICFLAGS = -K PIC + +include $(SRC)/lib/Makefile.spec + +install: $(ROOTABILIB) diff --git a/usr/src/lib/libsocket/spec/sparcv9/Makefile b/usr/src/lib/libsocket/spec/sparcv9/Makefile new file mode 100644 index 0000000000..378854c037 --- /dev/null +++ b/usr/src/lib/libsocket/spec/sparcv9/Makefile @@ -0,0 +1,45 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1998-1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# lib/libsocket/spec/sparcv9/Makefile + +.KEEP_STATE: + +include ../Makefile.targ + +# Add arch specific objects here +OBJECTS += + +include $(SRC)/lib/Makefile.lib +include $(SRC)/lib/Makefile.lib.64 + +# Uncomment the following if the linker complains +sparcv9_C_PICFLAGS = -K PIC + +include $(SRC)/lib/Makefile.spec + +install: $(ROOTABILIB64) diff --git a/usr/src/lib/libsocket/spec/svr4msg.spec b/usr/src/lib/libsocket/spec/svr4msg.spec new file mode 100644 index 0000000000..47f236948c --- /dev/null +++ b/usr/src/lib/libsocket/spec/svr4msg.spec @@ -0,0 +1,131 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# ident "%Z%%M% %I% %E% SMI" +# + +function recvmsg +include "svr4msg_spec.h", <sys/types.h>, <sys/socket.h> +declaration ssize_t recvmsg(int s, struct SVR4_msghdr *msg, int flags) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF EINTR EIO ENOMEM ENOSR ENOTSOCK ESTALE EWOULDBLOCK +exception $return == -1 +end + +function sendmsg +include "svr4msg_spec.h", <sys/types.h>, <sys/socket.h> +declaration ssize_t sendmsg(int s, const struct SVR4_msghdr *msg, int flags ) +version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7 +errno EBADF EINTR EINVAL EMSGSIZE ENOMEM ENOSR ENOTSOCK EWOULDBLOCK +exception $return == -1 +end + +# +# weak interfaces +# +function _recvmsg +weak recvmsg +version SUNWprivate_1.1 +end + +function _sendmsg +weak sendmsg +version SUNWprivate_1.1 +end + +function _socket +weak socket +version SUNWprivate_1.1 +end + +function _socketpair +weak socketpair +version SUNWprivate_1.1 +end + +function _bind +weak bind +version SUNWprivate_1.1 +end + +function _listen +weak listen +version SUNWprivate_1.1 +end + +function _accept +weak accept +version SUNWprivate_1.1 +end + +function _connect +weak connect +version SUNWprivate_1.1 +end + +function _shutdown +weak shutdown +version SUNWprivate_1.1 +end + +function _recv +weak recv +version SUNWprivate_1.1 +end + +function _recvfrom +weak recvfrom +version SUNWprivate_1.1 +end + +function _send +weak send +version SUNWprivate_1.1 +end + +function _sendto +weak sendto +version SUNWprivate_1.1 +end + +function _getpeername +weak getpeername +version SUNWprivate_1.1 +end + +function _getsockname +weak getsockname +version SUNWprivate_1.1 +end + +function _getsockopt +weak getsockopt +version SUNWprivate_1.1 +end + +function _setsockopt +weak setsockopt +version SUNWprivate_1.1 +end + diff --git a/usr/src/lib/libsocket/spec/versions b/usr/src/lib/libsocket/spec/versions new file mode 100644 index 0000000000..5ad9b43212 --- /dev/null +++ b/usr/src/lib/libsocket/spec/versions @@ -0,0 +1,84 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# Note (re: SUNW_1.2 .. SUNW_1.3): +# Even though the SUNW_1.2 and SUNW_1.3 versions now contain no +# symbols these versions MUST be present. This is because applications +# built on 2.6 Beta (when they did contain symbols explicitly) may +# depend on them. +# +# All symbol content for Solaris2.6 is now contained in SUNW_1.1, +# and (the now empty) versions SUNW_1.2 and SUNW_1.3 must be kept. +# +i386 { + SUNW_1.6: {SUNW_1.5}; + SUNW_1.5: {SUNW_1.4}; + SUNW_1.4: {SUNW_1.3}; + SUNW_1.3: {SUNW_1.2}; + SUNW_1.2: {SUNW_1.1}; + SUNW_1.1: {SUNW_0.7}; + SUNW_0.7; + SUNWprivate_1.3: {SUNWprivate_1.2}; + SUNWprivate_1.2: {SUNWprivate_1.1}; + SUNWprivate_1.1; +} +sparc { + SUNW_1.6: {SUNW_1.5}; + SUNW_1.5: {SUNW_1.4}; + SUNW_1.4: {SUNW_1.3}; + SUNW_1.3: {SUNW_1.2}; + SUNW_1.2: {SUNW_1.1}; + SUNW_1.1: {SUNW_0.7}; + SUNW_0.7: {SISCD_2.3}; + SISCD_2.3; + SUNWprivate_1.3: {SUNWprivate_1.2}; + SUNWprivate_1.2: {SUNWprivate_1.1}; + SUNWprivate_1.1; +} +sparcv9 { + SUNW_1.6: {SUNW_1.5}; + SUNW_1.5: {SUNW_1.4}; + SUNW_1.4: {SUNW_1.3}; + SUNW_1.3: {SUNW_1.2}; + SUNW_1.2: {SUNW_1.1}; + SUNW_1.1: {SUNW_0.7}; + SUNW_0.7; + SUNWprivate_1.3: {SUNWprivate_1.2}; + SUNWprivate_1.2: {SUNWprivate_1.1}; + SUNWprivate_1.1; +} +amd64 { + SUNW_1.6: {SUNW_1.5}; + SUNW_1.5: {SUNW_1.4}; + SUNW_1.4: {SUNW_1.3}; + SUNW_1.3: {SUNW_1.2}; + SUNW_1.2: {SUNW_1.1}; + SUNW_1.1: {SUNW_0.7}; + SUNW_0.7; + SUNWprivate_1.3: {SUNWprivate_1.2}; + SUNWprivate_1.2: {SUNWprivate_1.1}; + SUNWprivate_1.1; +} diff --git a/usr/src/lib/libsocket/spec/xpgmsg.spec b/usr/src/lib/libsocket/spec/xpgmsg.spec new file mode 100644 index 0000000000..61ffcef9f8 --- /dev/null +++ b/usr/src/lib/libsocket/spec/xpgmsg.spec @@ -0,0 +1,48 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +#ident "%Z%%M% %I% %E% SMI" +# + +function __xnet_recvmsg +include "xpgmsg_spec.h", <sys/types.h>, <sys/socket.h> +declaration ssize_t __xnet_recvmsg(int socket, struct XPG_msghdr *msg, \ + int flags) +version SUNW_1.1 +errno EBADF ENOTSOCK EINVAL EWOULDBLOCK EAGAIN EINTR EOPNOTSUPP \ + ENOTCONN ETIMEDOUT ECONNRESET EIO ENOBUFS ENOMEM ENOSR +exception $return == -1 +end + +function __xnet_sendmsg +include "xpgmsg_spec.h", <sys/types.h>, <sys/socket.h> +declaration ssize_t __xnet_sendmsg(int socket, const struct XPG_msghdr *msg, \ + int flags ) +version SUNW_1.1 +errno EAFNOSUPPORT EBADF ECONNRESET EINTR EINVAL EMSGSIZE ENOTCONN \ + ENOTSOCK EOPNOTSUPP EPIPE EWOULDBLOCK EAGAIN EACCES EIO \ + ELOOP ENAMETOOLONG ENOENT ENOTDIR EDESTADDRREQ EHOSTUNREACH \ + EISCONN ENETDOWN ENETUNREACH ENOBUFS ENOSR +exception $return == -1 +end |
