#
-# Generated by the NeXT Project Builder.
+# Generated by the Apple Project Builder.
#
# NOTE: Do NOT change this file -- Project Builder maintains it.
#
PROJECT_TYPE = Library
SUBPROJECTS = dns.subproj gen.subproj lookup.subproj netinfo.subproj\
- nis.subproj rpc.subproj util.subproj
+ nis.subproj rpc.subproj util.subproj mdns.subproj
OTHERSRCS = Makefile.preamble Makefile Makefile.postamble
netinfo.subproj,
nis.subproj,
rpc.subproj,
- util.subproj
+ util.subproj,
+ mdns.subproj
);
};
LANGUAGE = English;
MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
+ NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
NEXTSTEP_INSTALLDIR = /usr/local/lib/system;
NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- NEXTSTEP_PUBLICHEADERSDIR = /usr/include;
+ NEXTSTEP_PUBLICHEADERSDIR = /usr/include;
PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
PDO_UNIX_INSTALLDIR = /lib;
PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id: gethnamaddr.c,v 1.2 1999/10/14 21:56:44 wsanchez Exp $";
+static char rcsid[] = "$Id: gethnamaddr.c,v 1.6 2002/06/13 01:04:37 majka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <arpa/nameser.h>
#include <stdio.h>
+#include <stdlib.h>
#include <netdb.h>
#include <resolv.h>
#include <ctype.h>
#define MAXALIASES 35
#define MAXADDRS 35
+#define MAXHOSTBUF 8*1024
static const char AskedForGot[] =
"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
static struct hostent host;
static char *host_aliases[MAXALIASES];
-static char hostbuf[8*1024];
+static char *hostbuf = NULL;
static struct in_addr host_addr;
static FILE *hostf = NULL;
static int stayopen = 0;
extern int h_errno;
+extern int _lu_running(void);
+
#ifdef DEBUG
static void
dprintf(msg, num)
char tbuf[MAXDNAME+1];
const char *tname;
+ if (hostbuf == NULL) {
+ hostbuf = malloc(MAXHOSTBUF);
+ if (hostbuf == NULL)
+ return (NULL);
+ }
+ buflen = MAXHOSTBUF;
+
tname = qname;
host.h_name = NULL;
eom = answer->buf + anslen;
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
bp = hostbuf;
- buflen = sizeof hostbuf;
cp = answer->buf + HFIXEDSZ;
if (qdcount != 1) {
h_errno = NO_RECOVERY;
bp += sizeof(align) - ((u_long)bp % sizeof(align));
- if (bp + n >= &hostbuf[sizeof hostbuf]) {
+ if (bp + n >= &hostbuf[MAXHOSTBUF]) {
dprintf("size (%d) too big\n", n);
had_error++;
continue;
const char *name;
int af;
{
- switch (af) {
- case AF_INET:
- return (gethostbyname_ipv4(name));
+ if (_lu_running())
+ {
+ return getipnodebyname(name, af, 0, &h_errno);
+ }
+ else
+ {
+ if (af == AF_INET) return gethostbyname_ipv4(name);
+
+ errno = EAFNOSUPPORT;
+ h_errno = NETDB_INTERNAL;
+ return NULL;
}
- errno = EAFNOSUPPORT;
- h_errno = NETDB_INTERNAL;
- return (NULL);
}
static struct hostent *
extern struct hostent *_gethtbyname();
#endif /* !NeXT */
+ if (hostbuf == NULL)
+ {
+ hostbuf = malloc(MAXHOSTBUF);
+ if (hostbuf == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+ }
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
return (NULL);
h_errno = NETDB_INTERNAL;
return (NULL);
}
+ if (hostbuf == NULL) {
+ hostbuf = malloc(MAXHOSTBUF);
+ if (hostbuf == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+ }
again:
- if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
+ if (!(p = fgets(hostbuf, MAXHOSTBUF, hostf))) {
h_errno = HOST_NOT_FOUND;
return (NULL);
}
cp++;
host.h_name = cp;
q = host.h_aliases = host_aliases;
- if (cp = strpbrk(cp, " \t"))
+ if ((cp = strpbrk(cp, " \t")))
*cp++ = '\0';
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
}
if (q < &host_aliases[MAXALIASES - 1])
*q++ = cp;
- if (cp = strpbrk(cp, " \t"))
+ if ((cp = strpbrk(cp, " \t")))
*cp++ = '\0';
}
*q = NULL;
register char **cp;
_sethtent(0);
- while (p = _gethtent()) {
+ while ((p = _gethtent())) {
if (strcasecmp(p->h_name, name) == 0)
break;
for (cp = p->h_aliases; *cp != 0; cp++)
register struct hostent *p;
_sethtent(0);
- while (p = _gethtent())
+ while ((p = _gethtent()))
if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
break;
_endhtent();
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getnetbyaddr.c 1.1 (Coimbra) 93/06/02";
-static char rcsid[] = "$Id: getnetbyaddr.c,v 1.2 1999/10/14 21:56:44 wsanchez Exp $";
+static char rcsid[] = "$Id: getnetbyaddr.c,v 1.3 2002/02/19 20:36:12 epeyton Exp $";
#endif /* LIBC_SCCS and not lint */
#include <netdb.h>
register struct netent *p;
setnetent(_net_stayopen);
- while (p = getnetent())
+ while ((p = getnetent()))
if (p->n_addrtype == type && p->n_net == net)
break;
if (!_net_stayopen)
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getnetbyname.c 8.1 (Berkeley) 6/4/93";
static char sccsid_[] = "from getnetbyname.c 1.1 (Coimbra) 93/06/02";
-static char rcsid[] = "$Id: getnetbyname.c,v 1.2 1999/10/14 21:56:44 wsanchez Exp $";
+static char rcsid[] = "$Id: getnetbyname.c,v 1.3 2002/02/19 20:36:12 epeyton Exp $";
#endif /* LIBC_SCCS and not lint */
#include <netdb.h>
register char **cp;
setnetent(_net_stayopen);
- while (p = getnetent()) {
+ while ((p = getnetent())) {
if (strcasecmp(p->n_name, name) == 0)
break;
for (cp = p->n_aliases; *cp != 0; cp++)
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getnetent.c 8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id: getnetent.c,v 1.2 1999/10/14 21:56:44 wsanchez Exp $";
+static char rcsid[] = "$Id: getnetent.c,v 1.3 2002/06/12 17:40:29 epeyton Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <arpa/nameser.h>
#include <stdio.h>
+#include <stdlib.h>
#include <resolv.h>
#include <netdb.h>
#include <string.h>
#define MAXALIASES 35
static FILE *netf;
-static char line[BUFSIZ+1];
static struct netent net;
static char *net_aliases[MAXALIASES];
#if defined(__APPLE__)
getnetent()
{
char *p;
+ static char *line = NULL;
register char *cp, **q;
if (netf == NULL && (netf = fopen(_PATH_NETWORKS, "r" )) == NULL)
return (NULL);
+
+ if (line == NULL) {
+ line = malloc(BUFSIZ+1);
+ if (line == NULL)
+ return (NULL);
+ }
again:
p = fgets(line, BUFSIZ, netf);
if (p == NULL)
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getnetbyaddr.c 8.1 (Berkeley) 6/4/93";
static char sccsid_[] = "from getnetnamadr.c 1.4 (Coimbra) 93/06/03";
-static char rcsid[] = "$Id: getnetnamadr.c,v 1.2 1999/10/14 21:56:44 wsanchez Exp $";
+static char rcsid[] = "$Id: getnetnamadr.c,v 1.3 2002/06/12 17:40:29 epeyton Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <arpa/nameser.h>
#include <stdio.h>
+#include <stdlib.h>
#include <netdb.h>
#include <resolv.h>
#include <ctype.h>
char aux1[30], aux2[30], ans[30], *in, *st, *pauxt, *bp, **ap,
*paux1 = &aux1[0], *paux2 = &aux2[0], flag = 0;
static struct netent net_entry;
-static char *net_aliases[MAXALIASES], netbuf[BUFSIZ+1];
+static char *net_aliases[MAXALIASES], *netbuf = NULL;
+
+ if (netbuf == NULL) {
+ netbuf = malloc(BUFSIZ+1);
+ if (netbuf == NULL)
+ return (NULL);
+ }
+ buflen = BUFSIZ+1;
/*
* find first satisfactory answer
ancount = ntohs(hp->ancount); /* #/records in the answer section */
qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
bp = netbuf;
- buflen = sizeof(netbuf);
cp = answer->buf + HFIXEDSZ;
if (!qdcount) {
if (hp->aa)
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id: herror.c,v 1.2 1999/10/14 21:56:44 wsanchez Exp $";
+static char rcsid[] = "$Id: herror.c,v 1.3 2002/02/19 20:36:12 epeyton Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
if (err < 0)
return ("Resolver internal error");
else if (err < h_nerr)
- return (h_errlist[err]);
+ return ((char *)h_errlist[err]);
return ("Unknown resolver error");
}
/*
* @(#)inet.h 8.1 (Berkeley) 6/2/93
- * $Id: inet.h,v 1.2 1999/10/14 21:56:45 wsanchez Exp $
+ * $Id: inet.h,v 1.3 2002/04/19 20:38:01 majka Exp $
*/
#ifndef _INET_H_
unsigned long inet_netof __P((struct in_addr));
unsigned long inet_network __P((const char *));
char *inet_ntoa __P((struct in_addr));
+int inet_pton __P((int, const char *, void *));
+const char *inet_ntop __P((int, const void *, char *, size_t));
+
u_int inet_nsap_addr __P((const char *, u_char *, int maxlen));
char *inet_nsap_ntoa __P((int, const u_char *, char *ascii));
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id: res_comp.c,v 1.2 1999/10/14 21:56:45 wsanchez Exp $";
+static char rcsid[] = "$Id: res_comp.c,v 1.3 2002/02/19 20:36:12 epeyton Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
/*
* fetch next label in domain name
*/
- while (n = *cp++) {
+ while ((n = *cp++)) {
/*
* Check for indirection
*/
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
dn = exp_dn;
sp = cp = *cpp;
- while (n = *cp++) {
+ while ((n = *cp++)) {
/*
* check for indirection
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id: res_debug.c,v 1.2 1999/10/14 21:56:45 wsanchez Exp $";
+static char rcsid[] = "$Id: res_debug.c,v 1.3 2002/02/19 20:36:12 epeyton Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
* Print answer records.
*/
sflag = (_res.pfcode & pflag);
- if (n = ntohs(cnt)) {
+ if ((n = ntohs(cnt))) {
if ((!_res.pfcode) ||
((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
fprintf(file, hs);
/*
* Print question records.
*/
- if (n = ntohs(hp->qdcount)) {
+ if ((n = ntohs(hp->qdcount))) {
if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
fprintf(file, ";; QUESTIONS:\n");
while (--n >= 0) {
case T_HINFO:
case T_ISDN:
cp2 = cp + dlen;
- if (n = *cp++) {
+ if ((n = *cp++)) {
fprintf(file, "\t%.*s", n, cp);
cp += n;
}
(void) fputs("\t\"", file);
cp2 = cp1 + dlen;
while (cp < cp2) {
- if (n = (unsigned char) *cp++) {
+ if ((n = (unsigned char) *cp++)) {
for (c = n; c > 0 && cp < cp2; c--)
if ((*cp == '\n') || (*cp == '"')) {
(void) putc('\\', file);
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
-static char rcsid[] = "$Id: res_init.c,v 1.3 2000/08/01 23:12:13 lindak Exp $";
+static char rcsid[] = "$Id: res_init.c,v 1.5 2002/03/26 20:12:06 ajn Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
* - Internal resolver variables can be set from the value of the "options"
* property.
*/
-#if defined(__APPLE__)
+#if defined(__APPLE__) && defined(CONFIGURE_RESOLVER_FROM_NETINFO)
# include <netinfo/ni.h>
# define NI_PATH_RESCONF "/locations/resolver"
# define NI_TIMEOUT 10
#endif
(void) fclose(fp);
}
-#ifdef __APPLE__
+#if defined(__APPLE__) && defined(CONFIGURE_RESOLVER_FROM_NETINFO)
else netinfo_res_init(&haveenv, &havesearch);
#endif
}
#endif
-#ifdef __APPLE__
+#if defined(__APPLE__) && defined(CONFIGURE_RESOLVER_FROM_NETINFO)
static int
netinfo_res_init(haveenv, havesearch)
int *haveenv;
for (n = 0;
n < nl.ni_namelist_len && nsort < MAXRESOLVSORT;
n++) {
- char ch;
+ char ch = '\0';
char *cp;
const char *sp;
struct in_addr a;
#
-# Generated by the NeXT Project Builder.
+# Generated by the Apple Project Builder.
#
# NOTE: Do NOT change this file -- Project Builder maintains it.
#
PROJECTVERSION = 2.8
PROJECT_TYPE = Component
-CFILES = aliasdb.c ether_addr.c fstab.c getaddrinfo.c getgrent.c getproto.c\
- getprotoent.c getprotoname.c getpwent.c getservbyname.c\
- getservbyport.c getservent.c initgroups.c printerdb.c
+HFILES = ifaddrs.h
-OTHERSRCS = Makefile.preamble Makefile
+CFILES = aliasdb.c ether_addr.c fstab.c getaddrinfo.c getgrent.c\
+ getifaddrs.c getnameinfo.c getproto.c getprotoent.c\
+ getprotoname.c getpwent.c getservbyname.c getservbyport.c\
+ getservent.c if_indextoname.c if_nameindex.c if_nametoindex.c\
+ inet_ntop.c inet_pton.c initgroups.c printerdb.c\
+ map_v4v6.c ip6opt.c rthdr.c vars.c
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble getaddrinfo.3\
+ getifaddrs.3 if_indextoname.3 inet6_rthdr_space.3\
+ gethostbyname.3 getnameinfo.3 inet6_option_space.3\
+ linkaddr.3 getprotoent.3 gethostbyname.3 getipnodebyname.3\
+ getnetent.3 getservent.3 inet6_option_space.3
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
MAKEFILE = subproj.make
+NEXTSTEP_INSTALLDIR = /usr/local/lib/system
LIBS =
DEBUG_LIBS = $(LIBS)
PROF_LIBS = $(LIBS)
+PUBLIC_HEADERS = ifaddrs.h
+
+
+NEXTSTEP_PUBLIC_HEADERS_DIR = /usr/include
NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
--- /dev/null
+###############################################################################
+# NeXT Makefile.postamble Template
+# Copyright 1993, NeXT Computer, Inc.
+#
+# This Makefile is used for configuring the standard app makefiles associated
+# with ProjectBuilder.
+#
+# Use this template to set attributes for a project, sub-project, bundle, or
+# palette. Each node in the project's tree of sub-projects and bundles
+# should have it's own Makefile.preamble and Makefile.postamble. Additional
+# rules (e.g., after_install) that are defined by the developer should be
+# defined in this file.
+#
+###############################################################################
+#
+# Here are the variables exported by the common "app" makefiles that can be
+# used in any customizations you make to the template below:
+#
+# PRODUCT_ROOT - Name of the directory to which resources are copied.
+# OFILE_DIR - Directory into which .o object files are generated.
+# (Note that this name is calculated based on the target
+# architectures specified in Project Builder).
+# DERIVED_SRC_DIR - Directory used for all other derived files
+# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations
+#
+# NAME - name of application, bundle, subproject, palette, etc.
+# LANGUAGE - langage in which the project is written (default "English")
+# ENGLISH - boolean flag set iff $(LANGUAGE) = "English"
+# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese"
+# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES - non-localized resources of project
+# PROJECTVERSION - version of ProjectBuilder that output Makefile
+# APPICON - application icon file
+# DOCICONS - dock icon files
+# ICONSECTIONS - Specifies icon sections when linking executable
+#
+# CLASSES - Class implementation files in project.
+# HFILES - Header files in project.
+# MFILES - Other Objective-C source files in project.
+# CFILES - Other C source files in project.
+# PSWFILES - .psw files in the project
+# PSWMFILES - .pswm files in the project
+# SUBPROJECTS - Subprojects of this project
+# BUNDLES - Bundle subprojects of this project
+# OTHERSRCS - Other miscellaneous sources of this project
+# OTHERLINKED - Source files not matching a standard source extention
+#
+# LIBS - Libraries to link with when making app target
+# DEBUG_LIBS - Libraries to link with when making debug target
+# PROF_LIBS - Libraries to link with when making profile target
+# OTHERLINKEDOFILES - Other relocatable files to (always) link in.
+#
+# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles
+# MAKEFILEDIR - Directory in which to find $(MAKEFILE)
+# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make)
+# INSTALLDIR - Directory app will be installed into by 'install' target
+#
+###############################################################################
+
+
+# Change defaults assumed by the standard makefiles here. Edit the
+# following default values as appropriate. (Note that if no Makefile.postamble
+# exists, these values will have defaults set in common.make).
+
+# Versioning of frameworks, libraries, bundles, and palettes:
+#CURRENTLY_ACTIVE_VERSION = YES # Set to "NO" to produce a compatibility binary
+#DEPLOY_WITH_VERSION_NAME = A
+#COMPATIBILITY_PROJECT_VERSION = 1
+
+# Some compiler flags can be easily overridden here, but onlytake effect at
+# the top-level:
+#OPTIMIZATION_CFLAG = -O
+#DEBUG_SYMBOLS_CFLAG = -g
+#WARNING_CFLAGS = -Wall
+#DEBUG_BUILD_CFLAGS = -DDEBUG
+#PROFILE_BUILD_CFLAGS = -pg -DPROFILE
+
+# Flags passed to yacc
+#YFLAGS = -d
+
+# Library and Framework projects only:
+# 1. If you want something other than the default .dylib name, override it here
+#DYLIB_INSTALL_NAME = lib$(NAME).dylib
+
+# 2. If you want to change the -install_name flag from the absolute path to the development area, change it here. One good choice is the installation directory. Another one might be none at all.
+#DYLIB_INSTALL_DIR = $(INSTALLDIR)
+
+# Ownership and permissions of files installed by 'install' target
+#INSTALL_AS_USER = root # User/group ownership
+#INSTALL_AS_GROUP = wheel # (probably want to set both of these)
+#INSTALL_PERMISSIONS = # If set, 'install' chmod's executable to this
+
+# Options to strip for various project types. Note: -S strips debugging symbols
+# (executables can be stripped down further with -x or, if they load no bundles, with no
+# options at all).
+#APP_STRIP_OPTS = -S
+#TOOL_STRIP_OPTS = -S
+#LIBRARY_STRIP_OPTS = -S # for .a archives
+#DYNAMIC_STRIP_OPTS = -S # for bundles and shared libraries
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. "Official"
+# user-defined rules are:
+# * before_install
+# * after_install
+# * after_installhdrs
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
+install-man-page:
+ mkdir -p "$(DSTROOT)/usr/share/man/man3"
+ install -c -m 644 getaddrinfo.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getaddrinfo.3" "$(DSTROOT)/usr/share/man/man3/freeaddrinfo.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getaddrinfo.3" "$(DSTROOT)/usr/share/man/man3/gai_strerror.3"
+ install -c -m 644 getnameinfo.3 "$(DSTROOT)/usr/share/man/man3"
+ install -c -m 644 gethostbyname.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/gethostbyname.3" "$(DSTROOT)/usr/share/man/man3/endhostent.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/gethostbyname.3" "$(DSTROOT)/usr/share/man/man3/gethostbyaddr.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/gethostbyname.3" "$(DSTROOT)/usr/share/man/man3/gethostbyname2.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/gethostbyname.3" "$(DSTROOT)/usr/share/man/man3/gethostent.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/gethostbyname.3" "$(DSTROOT)/usr/share/man/man3/herror.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/gethostbyname.3" "$(DSTROOT)/usr/share/man/man3/hstrerror.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/gethostbyname.3" "$(DSTROOT)/usr/share/man/man3/sethostent.3"
+ install -c -m 644 getifaddrs.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getifaddrs.3" "$(DSTROOT)/usr/share/man/man3/freeifaddrs.3"
+ install -c -m 644 getipnodebyname.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getipnodebyname.3" "$(DSTROOT)/usr/share/man/man3/freehostent.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getipnodebyname.3" "$(DSTROOT)/usr/share/man/man3/getipnodebyaddr.3"
+ install -c -m 644 getnetent.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getnetent.3" "$(DSTROOT)/usr/share/man/man3/endnetent.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getnetent.3" "$(DSTROOT)/usr/share/man/man3/getnetbyaddr.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getnetent.3" "$(DSTROOT)/usr/share/man/man3/getnetbyname.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getnetent.3" "$(DSTROOT)/usr/share/man/man3/setnetent.3"
+ install -c -m 644 getprotoent.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getprotoent.3" "$(DSTROOT)/usr/share/man/man3/endprotoent.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getprotoent.3" "$(DSTROOT)/usr/share/man/man3/getprotobyname.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getprotoent.3" "$(DSTROOT)/usr/share/man/man3/getprotobynumber.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getprotoent.3" "$(DSTROOT)/usr/share/man/man3/setprotoent.3"
+ install -c -m 644 getservent.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getservent.3" "$(DSTROOT)/usr/share/man/man3/endservent.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getservent.3" "$(DSTROOT)/usr/share/man/man3/getservbyname.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getservent.3" "$(DSTROOT)/usr/share/man/man3/getservbyport.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/getservent.3" "$(DSTROOT)/usr/share/man/man3/setservent.3"
+ install -c -m 644 if_indextoname.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/if_indextoname.3" "$(DSTROOT)/usr/share/man/man3/if_freenameindex.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/if_indextoname.3" "$(DSTROOT)/usr/share/man/man3/if_nameindex.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/if_indextoname.3" "$(DSTROOT)/usr/share/man/man3/if_nametoindex.3"
+ install -c -m 644 inet6_option_space.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_option_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_option_alloc.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_option_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_option_append.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_option_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_option_find.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_option_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_option_init.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_option_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_option_next.3"
+ install -c -m 644 inet6_rthdr_space.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_add.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_getaddr.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_getflags.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_init.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_lasthop.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_reverse.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_space.3" "$(DSTROOT)/usr/share/man/man3/inet6_rthdr_segments.3"
+ install -c -m 644 linkaddr.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/linkaddr.3" "$(DSTROOT)/usr/share/man/man3/link_addr.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/linkaddr.3" "$(DSTROOT)/usr/share/man/man3/link_ntoa.3"
+AFTER_POSTINSTALL += install-man-page
OTHER_CFLAGS = \
+ -DINET6=1 \
-Dsetservent=_old_setservent \
-Dgetservent=_old_getservent \
-Dendservent=_old_endservent \
{
DYNAMIC_CODE_GEN = YES;
FILESTABLE = {
- H_FILES = ();
+ H_FILES = (ifaddrs.h);
OTHER_LINKED = (
aliasdb.c,
ether_addr.c,
fstab.c,
getaddrinfo.c,
getgrent.c,
+ getifaddrs.c,
+ getnameinfo.c,
getproto.c,
getprotoent.c,
getprotoname.c,
getservbyname.c,
getservbyport.c,
getservent.c,
+ if_indextoname.c,
+ if_nameindex.c,
+ if_nametoindex.c,
+ inet_ntop.c,
+ inet_pton.c,
initgroups.c,
- printerdb.c
+ printerdb.c,
+ map_v4v6.c,
+ ip6opt.c,
+ rthdr.c,
+ vars.c
);
- OTHER_SOURCES = (Makefile.preamble, Makefile);
+ OTHER_SOURCES = (
+ Makefile.preamble,
+ Makefile,
+ Makefile.postamble,
+ getaddrinfo.3,
+ getifaddrs.3,
+ if_indextoname.3,
+ inet6_rthdr_space.3,
+ gethostbyname.3,
+ getnameinfo.3,
+ inet6_option_space.3,
+ getprotoent.3,
+ gethostbyname.3,
+ getipnodebyname.3,
+ getnetent.3,
+ getservent.3,
+ inet6_option_space.3,
+ linkaddr.3
+ );
+ PUBLIC_HEADERS = (ifaddrs.h);
};
LANGUAGE = English;
MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
+ NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
+ NEXTSTEP_INSTALLDIR = /usr/local/lib/system;
NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ NEXTSTEP_PUBLICHEADERSDIR = /usr/include;
PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
static int firstTime = 1;
static int returnedRoot = 0;
static void error __P((int));
-static fstabscan __P((void));
-static char *getRootDev(void);
+static int fstabscan __P((void));
static const char *slash = "/";
static const char *remountedroot = "/root";
*/
static char *getDevPath(dev_t target_dev) {
- static char dev[MAXPATHLEN];
+ static char *dev = NULL;
char *name;
+ if (dev == NULL) {
+ dev = malloc(MAXPATHLEN);
+ if (dev == NULL)
+ return NULL;
+ }
+
strcpy(dev, _PATH_DEV);
/* The root device in fstab should always be a block special device */
static int initrootentry(struct fstab *rootentry)
{
- char *rootpath = slash;
+ char *rootpath = (char *)slash;
struct stat rootstat;
struct statfs rootfsinfo;
- char *rootdevname;
if (stat(rootpath, &rootstat) < 0) {
perror("stat");
/* Check to make sure we're not looking at a synthetic root: */
if (strcmp(rootfsinfo.f_fstypename, "synthfs") == 0) {
- rootpath = remountedroot;
+ rootpath = (char *)remountedroot;
if (stat(rootpath, &rootstat) < 0) {
perror("stat");
return -1;
{
register char *cp;
#define MAXLINELENGTH 1024
- static char line[MAXLINELENGTH];
+ static char *line = NULL;
char subline[MAXLINELENGTH];
int typexx;
if (!_fs_fp) {
return(0);
}
+
+ if (line == NULL) {
+ line = malloc(MAXLINELENGTH);
+ if (line == NULL)
+ return 0;
+ }
+
for (;;) {
if (!(cp = fgets(line, sizeof(line), _fs_fp)))
return(0);
--- /dev/null
+.\" $FreeBSD: src/lib/libc/net/getaddrinfo.3,v 1.2.2.8 2001/08/17 15:42:38 ru Exp $
+.\" $KAME: getaddrinfo.3,v 1.22 2000/08/09 21:16:17 itojun Exp $
+.\"
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
+.\"
+.Dd May 25, 1995
+.Dt GETADDRINFO 3
+.Os
+.\"
+.Sh NAME
+.Nm getaddrinfo ,
+.Nm freeaddrinfo ,
+.Nm gai_strerror
+.Nd nodename-to-address translation in protocol-independent manner
+.\"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <netdb.h>
+.Ft int
+.Fn getaddrinfo "const char *nodename" "const char *servname" \
+"const struct addrinfo *hints" "struct addrinfo **res"
+.Ft void
+.Fn freeaddrinfo "struct addrinfo *ai"
+.Ft "char *"
+.Fn gai_strerror "int ecode"
+.\"
+.Sh DESCRIPTION
+The
+.Fn getaddrinfo
+function is defined for protocol-independent nodename-to-address translation.
+It performs the functionality of
+.Xr gethostbyname 3
+and
+.Xr getservbyname 3 ,
+but in a more sophisticated manner.
+.Pp
+The
+.Li addrinfo
+structure is defined as a result of including the
+.Aq Pa netdb.h
+header:
+.Bd -literal -offset
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for nodename */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+.Ed
+.Pp
+The
+.Fa nodename
+and
+.Fa servname
+arguments are pointers to null-terminated strings or
+.Dv NULL .
+One or both of these two arguments must be a
+.Pf non Dv -NULL
+pointer.
+In the normal client scenario, both the
+.Fa nodename
+and
+.Fa servname
+are specified.
+In the normal server scenario, only the
+.Fa servname
+is specified.
+A
+.Pf non Dv -NULL
+.Fa nodename
+string can be either a node name or a numeric host address string
+(i.e., a dotted-decimal IPv4 address or an IPv6 hex address).
+A
+.Pf non Dv -NULL
+.Fa servname
+string can be either a service name or a decimal port number.
+.Pp
+The caller can optionally pass an
+.Li addrinfo
+structure, pointed to by the third argument,
+to provide hints concerning the type of socket that the caller supports.
+In this
+.Fa hints
+structure all members other than
+.Fa ai_flags ,
+.Fa ai_family ,
+.Fa ai_socktype ,
+and
+.Fa ai_protocol
+must be zero or a
+.Dv NULL
+pointer.
+A value of
+.Dv PF_UNSPEC
+for
+.Fa ai_family
+means the caller will accept any protocol family.
+A value of 0 for
+.Fa ai_socktype
+means the caller will accept any socket type.
+A value of 0 for
+.Fa ai_protocol
+means the caller will accept any protocol.
+For example, if the caller handles only TCP and not UDP, then the
+.Fa ai_socktype
+member of the hints structure should be set to
+.Dv SOCK_STREAM
+when
+.Fn getaddrinfo
+is called.
+If the caller handles only IPv4 and not IPv6, then the
+.Fa ai_family
+member of the
+.Fa hints
+structure should be set to
+.Dv PF_INET
+when
+.Fn getaddrinfo
+is called.
+If the third argument to
+.Fn getaddrinfo
+is a
+.Dv NULL
+pointer, this is the same as if the caller had filled in an
+.Li addrinfo
+structure initialized to zero with
+.Fa ai_family
+set to
+.Dv PF_UNSPEC .
+.Pp
+Upon successful return a pointer to a linked list of one or more
+.Li addrinfo
+structures is returned through the final argument.
+The caller can process each
+.Li addrinfo
+structure in this list by following the
+.Fa ai_next
+pointer, until a
+.Dv NULL
+pointer is encountered.
+In each returned
+.Li addrinfo
+structure the three members
+.Fa ai_family ,
+.Fa ai_socktype ,
+and
+.Fa ai_protocol
+are the corresponding arguments for a call to the
+.Fn socket
+function.
+In each
+.Li addrinfo
+structure the
+.Fa ai_addr
+member points to a filled-in socket address structure whose length is
+specified by the
+.Fa ai_addrlen
+member.
+.Pp
+If the
+.Dv AI_PASSIVE
+bit is set in the
+.Fa ai_flags
+member of the
+.Fa hints
+structure, then the caller plans to use the returned socket address
+structure in a call to
+.Fn bind .
+In this case, if the
+.Fa nodename
+argument is a
+.Dv NULL
+pointer, then the IP address portion of the socket
+address structure will be set to
+.Dv INADDR_ANY
+for an IPv4 address or
+.Dv IN6ADDR_ANY_INIT
+for an IPv6 address.
+.Pp
+If the
+.Dv AI_PASSIVE
+bit is not set in the
+.Fa ai_flags
+member of the
+.Fa hints
+structure, then the returned socket address structure will be ready for a
+call to
+.Fn connect
+(for a connection-oriented protocol)
+or either
+.Fn connect ,
+.Fn sendto ,
+or
+.Fn sendmsg
+(for a connectionless protocol).
+In this case, if the
+.Fa nodename
+argument is a
+.Dv NULL
+pointer, then the IP address portion of the
+socket address structure will be set to the loopback address.
+.Pp
+If the
+.Dv AI_CANONNAME
+bit is set in the
+.Fa ai_flags
+member of the
+.Fa hints
+structure, then upon successful return the
+.Fa ai_canonname
+member of the first
+.Li addrinfo
+structure in the linked list will point to a null-terminated string
+containing the canonical name of the specified
+.Fa nodename .
+.Pp
+If the
+.Dv AI_NUMERICHOST
+bit is set in the
+.Fa ai_flags
+member of the
+.Fa hints
+structure, then a
+.Pf non Dv -NULL
+.Fa nodename
+string must be a numeric host address string.
+Otherwise an error of
+.Dv EAI_NONAME
+is returned.
+This flag prevents any type of name resolution service (e.g., the DNS)
+from being called.
+.Pp
+The arguments to
+.Fn getaddrinfo
+must be sufficiently consistent and unambiguous.
+Here are some problem cases you may encounter:
+.Bl -bullet
+.It
+.Fn getaddrinfo
+will fail if the members in the
+.Fa hints
+structure are not consistent.
+For example, for internet address families,
+.Fn getaddrinfo
+will fail if you specify
+.Dv SOCK_STREAM
+to
+.Fa ai_socktype
+while you specify
+.Dv IPPROTO_UDP
+to
+.Fa ai_protocol .
+.It
+If you specify a
+.Fa servname
+which is defined only for certain
+.Fa ai_socktype ,
+.Fn getaddrinfo
+will fail because the arguments are not consistent.
+For example,
+.Fn getaddrinfo
+will return an error if you ask for
+.Dq Li tftp
+service on
+.Dv SOCK_STREAM .
+.It
+For internet address families, if you specify
+.Fa servname
+while you set
+.Fa ai_socktype
+to
+.Dv SOCK_RAW ,
+.Fn getaddrinfo
+will fail, because service names are not defined for the internet
+.Dv SOCK_RAW
+space.
+.It
+If you specify numeric
+.Fa servname ,
+while leaving
+.Fa ai_socktype
+and
+.Fa ai_protocol
+unspecified,
+.Fn getaddrinfo
+will fail.
+This is because the numeric
+.Fa servname
+does not identify any socket type, and
+.Fn getaddrinfo
+is not allowed to glob the argument in such case.
+.El
+.Pp
+All of the information returned by
+.Fn getaddrinfo
+is dynamically allocated:
+the
+.Li addrinfo
+structures, the socket address structures, and canonical node name
+strings pointed to by the addrinfo structures.
+To return this information to the system the function
+.Fn freeaddrinfo
+is called.
+The
+.Fa addrinfo
+structure pointed to by the
+.Fa ai argument
+is freed, along with any dynamic storage pointed to by the structure.
+This operation is repeated until a
+.Dv NULL
+.Fa ai_next
+pointer is encountered.
+.Pp
+To aid applications in printing error messages based on the
+.Dv EAI_xxx
+codes returned by
+.Fn getaddrinfo ,
+.Fn gai_strerror
+is defined.
+The argument is one of the
+.Dv EAI_xxx
+values defined earlier and the return value points to a string describing
+the error.
+If the argument is not one of the
+.Dv EAI_xxx
+values, the function still returns a pointer to a string whose contents
+indicate an unknown error.
+.\"
+.Sh EXTENSIONS
+This implementation supports numeric IPv6 address notation with the
+experimental scope identifier.
+By appending a percent sign and scope identifier to the address, you
+can specify the value of the
+.Li sin6_scope_id
+field of the socket address.
+This makes management of scoped address easier,
+and allows cut-and-paste input of scoped addresses.
+.Pp
+At the moment the code supports only link-local addresses in this format.
+The scope identifier is hardcoded to name of hardware interface associated
+with the link,
+(such as
+.Li ne0 ) .
+For example,
+.Dq Li fe80::1%ne0 ,
+which means
+.Do
+.Li fe80::1
+on the link associated with the
+.Li ne0
+interface
+.Dc .
+.Pp
+This implementation is still very experimental and non-standard.
+The current implementation assumes a one-to-one relationship between
+interfaces and links, which is not necessarily true according to the
+specification.
+.\"
+.Sh EXAMPLES
+The following code tries to connect to
+.Dq Li www.kame.net
+service
+.Dq Li http .
+via stream socket.
+It loops through all the addresses available, regardless of the address family.
+If the destination resolves to an IPv4 address, it will use an
+.Dv AF_INET
+socket.
+Similarly, if it resolves to IPv6, an
+.Dv AF_INET6
+socket is used.
+Observe that there is no hardcoded reference to particular address family.
+The code works even if
+.Fn getaddrinfo
+returns addresses that are not IPv4/v6.
+.Bd -literal -offset indent
+struct addrinfo hints, *res, *res0;
+int error;
+int s;
+const char *cause = NULL;
+
+memset(&hints, 0, sizeof(hints));
+hints.ai_family = PF_UNSPEC;
+hints.ai_socktype = SOCK_STREAM;
+error = getaddrinfo("www.kame.net", "http", &hints, &res0);
+if (error) {
+ errx(1, "%s", gai_strerror(error));
+ /*NOTREACHED*/
+}
+s = -1;
+cause = "no addresses";
+errno = EADDRNOTAVAIL;
+for (res = res0; res; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (s < 0) {
+ cause = "socket";
+ continue;
+ }
+
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ cause = "connect";
+ close(s);
+ s = -1;
+ continue;
+ }
+
+ break; /* okay we got one */
+}
+if (s < 0) {
+ err(1, cause);
+ /*NOTREACHED*/
+}
+freeaddrinfo(res0);
+.Ed
+.Pp
+The following example tries to open a wildcard listening socket onto service
+.Dq Li http ,
+for all the address families available.
+.Bd -literal -offset indent
+struct addrinfo hints, *res, *res0;
+int error;
+int s[MAXSOCK];
+int nsock;
+const char *cause = NULL;
+
+memset(&hints, 0, sizeof(hints));
+hints.ai_family = PF_UNSPEC;
+hints.ai_socktype = SOCK_STREAM;
+hints.ai_flags = AI_PASSIVE;
+error = getaddrinfo(NULL, "http", &hints, &res0);
+if (error) {
+ errx(1, "%s", gai_strerror(error));
+ /*NOTREACHED*/
+}
+nsock = 0;
+for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) {
+ s[nsock] = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (s[nsock] < 0) {
+ cause = "socket";
+ continue;
+ }
+
+ if (bind(s[nsock], res->ai_addr, res->ai_addrlen) < 0) {
+ cause = "bind";
+ close(s[nsock]);
+ continue;
+ }
+
+ if (listen(s[nsock], SOMAXCONN) < 0) {
+ cause = "listen";
+ close(s[nsock]);
+ continue;
+ }
+
+ nsock++;
+}
+if (nsock == 0) {
+ err(1, cause);
+ /*NOTREACHED*/
+}
+freeaddrinfo(res0);
+.Ed
+.\"
+.Sh FILES
+.Bl -tag -width /etc/resolv.conf -compact
+.It Pa /etc/hosts
+.It Pa /etc/host.conf
+.It Pa /etc/resolv.conf
+.El
+.\"
+.Sh DIAGNOSTICS
+Error return status from
+.Fn getaddrinfo
+is zero on success and non-zero on errors.
+Non-zero error codes are defined in
+.Aq Pa netdb.h ,
+and as follows:
+.Pp
+.Bl -tag -width EAI_ADDRFAMILY -compact
+.It Dv EAI_ADDRFAMILY
+Address family for
+.Fa nodename
+not supported.
+.It Dv EAI_AGAIN
+Temporary failure in name resolution.
+.It Dv EAI_BADFLAGS
+Invalid value for
+.Fa ai_flags .
+.It Dv EAI_FAIL
+Non-recoverable failure in name resolution.
+.It Dv EAI_FAMILY
+.Fa ai_family
+not supported.
+.It Dv EAI_MEMORY
+Memory allocation failure.
+.It Dv EAI_NODATA
+No address associated with
+.Fa nodename .
+.It Dv EAI_NONAME
+.Fa nodename
+nor
+.Fa servname
+provided, or not known.
+.It Dv EAI_SERVICE
+.Fa servname
+not supported for
+.Fa ai_socktype .
+.It Dv EAI_SOCKTYPE
+.Fa ai_socktype
+not supported.
+.It Dv EAI_SYSTEM
+System error returned in
+.Va errno .
+.El
+.Pp
+If called with an appropriate argument,
+.Fn gai_strerror
+returns a pointer to a string describing the given error code.
+If the argument is not one of the
+.Dv EAI_xxx
+values, the function still returns a pointer to a string whose contents
+indicate an unknown error.
+.\"
+.Sh SEE ALSO
+.Xr gethostbyname 3 ,
+.Xr getnameinfo 3 ,
+.Xr getservbyname 3 ,
+.Xr hosts 5 ,
+.Xr services 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Pp
+.Rs
+.%A R. Gilligan
+.%A S. Thomson
+.%A J. Bound
+.%A W. Stevens
+.%T Basic Socket Interface Extensions for IPv6
+.%R RFC2553
+.%D March 1999
+.Re
+.Rs
+.%A Tatsuya Jinmei
+.%A Atsushi Onoe
+.%T "An Extension of Format for IPv6 Scoped Addresses"
+.%R internet draft
+.%N draft-ietf-ipngwg-scopedaddr-format-02.txt
+.%O work in progress material
+.Re
+.Rs
+.%A Craig Metz
+.%T Protocol Independence Using the Sockets API
+.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference"
+.%D June 2000
+.Re
+.\"
+.Sh HISTORY
+The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\"
+.Sh STANDARDS
+The
+.Fn getaddrinfo
+function is defined in
+.St -p1003.1g-2000 ,
+and documented in
+.Dq Basic Socket Interface Extensions for IPv6
+(RFC2553).
+.\"
+.Sh BUGS
+The current implementation is not thread-safe.
+.Pp
+The text was shamelessly copied from RFC2553.
#include <servers/bootstrap.h>
#include <nameser.h>
#include <resolv.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
#define SOCK_UNSPEC 0
#define IPPROTO_UNSPEC 0
+#define WANT_A4_ONLY 1
+#define WANT_A6_ONLY 2
+#define WANT_A6_PLUS_MAPPED_A4 3
+#define WANT_A6_OR_MAPPED4_IF_NO_A6 4
+
#define LONG_STRING_LENGTH 8192
#define _LU_MAXLUSTRLEN 256
-static char *LOOKUPD_NAME = "lookup daemon";
-
+extern int _lu_running(void);
+extern mach_port_t _lookupd_port();
extern int _lookup_link();
extern int _lookup_one();
extern int _lookup_all();
static int supported_socket[] =
{
+ SOCK_RAW,
SOCK_UNSPEC,
SOCK_DGRAM,
SOCK_STREAM
};
-static int supported_socket_count = 3;
+static int supported_socket_count = 4;
static int supported_protocol[] =
{
IPPROTO_UNSPEC,
+ IPPROTO_ICMPV6,
IPPROTO_UDP,
IPPROTO_TCP
};
-static int supported_protocol_count = 3;
+static int supported_protocol_count = 4;
static int supported_socket_protocol_pair[] =
{
- SOCK_UNSPEC, IPPROTO_UNSPEC,
- SOCK_UNSPEC, IPPROTO_UDP,
- SOCK_UNSPEC, IPPROTO_TCP,
- SOCK_DGRAM, IPPROTO_UNSPEC,
- SOCK_DGRAM, IPPROTO_UDP,
- SOCK_STREAM, IPPROTO_UNSPEC,
- SOCK_STREAM, IPPROTO_TCP
+ SOCK_RAW, IPPROTO_UNSPEC,
+ SOCK_RAW, IPPROTO_UDP,
+ SOCK_RAW, IPPROTO_TCP,
+ SOCK_RAW, IPPROTO_ICMPV6,
+ SOCK_UNSPEC, IPPROTO_UNSPEC,
+ SOCK_UNSPEC, IPPROTO_UDP,
+ SOCK_UNSPEC, IPPROTO_TCP,
+ SOCK_UNSPEC, IPPROTO_ICMPV6,
+ SOCK_DGRAM, IPPROTO_UNSPEC,
+ SOCK_DGRAM, IPPROTO_UDP,
+ SOCK_STREAM, IPPROTO_UNSPEC,
+ SOCK_STREAM, IPPROTO_TCP
};
-static int supported_socket_protocol_pair_count = 7;
+static int supported_socket_protocol_pair_count = 12;
static int
gai_family_type_check(int f)
static int
gai_inet_pton(const char *s, struct in6_addr *a6)
{
- int run, ncolon;
- unsigned short x[8];
- char *p, buf[4];
-
if (s == NULL) return 0;
if (a6 == NULL) return 0;
-
- for (ncolon = 0; ncolon < 8; ncolon++) x[ncolon] = 0;
- memset(buf, 0, 4);
-
- ncolon = 0;
- run = 0;
- for (p = (char *)s; *p != '\0'; p++)
- {
- if (*p == ':')
- {
- if (run > 0) sscanf(buf, "%hx", &(x[ncolon]));
- ncolon++;
- if (ncolon > 7) return 0;
- run = 0;
- memset(buf, 0, 4);
- }
- else if (((*p >= '0') && (*p <= '9')) || ((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')))
- {
- buf[run] = *p;
- run++;
- if (run > 4) return 0;
- }
- }
-
- if (ncolon != 7) return 0;
-
- if (run > 0) sscanf(buf, "%hx", &(x[7]));
-
- a6->__u6_addr.__u6_addr32[0] = (x[0] << 16) + x[1];
- a6->__u6_addr.__u6_addr32[1] = (x[2] << 16) + x[3];
- a6->__u6_addr.__u6_addr32[2] = (x[4] << 16) + x[5];
- a6->__u6_addr.__u6_addr32[3] = (x[6] << 16) + x[7];
-
- return 1;
-}
-
-static char *
-gai_inet_ntop(struct in6_addr a)
-{
- static char buf[128];
- char t[32];
- unsigned short x;
- char *p;
- int i;
-
- memset(buf, 0, 128);
-
- p = (char *)&a.__u6_addr.__u6_addr32;
- for (i = 0; i < 8; i++, x += 1)
- {
- memmove(&x, p, 2);
- p += 2;
- sprintf(t, "%hx", x);
- strcat(buf, t);
- if (i < 7) strcat(buf, ":");
- }
-
- return buf;
+ return inet_pton(AF_INET6, s, (void *)&a6->__u6_addr.__u6_addr32[0]);
}
char *
}
x = *l;
- while (x->ai_next != NULL) x = x->ai_next;
- x->ai_next = a;
+
+ if (a->ai_family == PF_INET6)
+ {
+ if (x->ai_family == PF_INET)
+ {
+ *l = a;
+ a->ai_next = x;
+ return;
+ }
+
+ while ((x->ai_next != NULL) && (x->ai_next->ai_family != PF_INET)) x = x->ai_next;
+ a->ai_next = x->ai_next;
+ x->ai_next = a;
+ }
+ else
+ {
+ while (x->ai_next != NULL) x = x->ai_next;
+ a->ai_next = NULL;
+ x->ai_next = a;
+ }
}
static void
}
}
+static int
+_lu_str_equal(char *a, char *b)
+{
+ if (a == NULL)
+ {
+ if (b == NULL) return 1;
+ return 0;
+ }
+
+ if (b == NULL) return 0;
+
+ if (!strcmp(a, b)) return 1;
+ return 0;
+}
+
+static int
+lu_dict_equal(struct lu_dict *a, struct lu_dict *b)
+{
+ if (a == NULL) return 0;
+ if (b == NULL) return 0;
+
+ if (_lu_str_equal(a->type, b->type) == 0) return 0;
+ if (_lu_str_equal(a->name, b->name) == 0) return 0;
+ if (_lu_str_equal(a->cname, b->cname) == 0) return 0;
+ if (_lu_str_equal(a->mx, b->mx) == 0) return 0;
+ if (_lu_str_equal(a->ipv4, b->ipv4) == 0) return 0;
+ if (_lu_str_equal(a->ipv6, b->ipv6) == 0) return 0;
+ if (_lu_str_equal(a->service, b->service) == 0) return 0;
+ if (_lu_str_equal(a->port, b->port) == 0) return 0;
+ if (_lu_str_equal(a->protocol, b->protocol) == 0) return 0;
+ if (_lu_str_equal(a->target, b->target) == 0) return 0;
+ if (_lu_str_equal(a->priority, b->priority) == 0) return 0;
+ if (_lu_str_equal(a->weight, b->weight) == 0) return 0;
+ return 1;
+}
+
+/*
+ * Append a single dictionary to a list if it is unique.
+ * Free it if it is not appended.
+ */
+static void
+merge_lu_dict(struct lu_dict **l, struct lu_dict *d)
+{
+ struct lu_dict *x, *e;
+
+ if (l == NULL) return;
+ if (d == NULL) return;
+
+ if (*l == NULL)
+ {
+ *l = d;
+ return;
+ }
+
+ e = *l;
+ for (x = *l; x != NULL; x = x->lu_next)
+ {
+ e = x;
+ if (lu_dict_equal(x, d))
+ {
+ free_lu_dict(d);
+ return;
+ }
+ }
+
+ e->lu_next = d;
+}
+
static void
append_lu_dict(struct lu_dict **l, struct lu_dict *d)
{
- struct lu_dict *x;
+ struct lu_dict *x, *next;
if (l == NULL) return;
if (d == NULL) return;
return;
}
- x = *l;
- while (x->lu_next != NULL) x = x->lu_next;
- x->lu_next = d;
+ x = d;
+
+ while (x != NULL)
+ {
+ next = x->lu_next;
+ x->lu_next = NULL;
+ merge_lu_dict(l, x);
+ x = next;
+ }
}
/*
}
}
- append_lu_dict(l, d);
-}
-
-static mach_port_t
-lookupd_port(char *name)
-{
- mach_port_t p;
- kern_return_t status;
-
- status = bootstrap_look_up(bootstrap_port, name, &p);
- if (status == KERN_SUCCESS) return p;
- return MACH_PORT_NULL;
+ merge_lu_dict(l, d);
}
static int
struct servent *s;
struct hostent *h;
struct lu_dict *d;
- char str[64];
+ char str[64], portstr[64];
struct in_addr a4;
if (!strcmp(q->type, "service"))
d->port = strdup(str);
if (s->s_proto != NULL) d->protocol = strdup(s->s_proto);
- append_lu_dict(list, d);
+ merge_lu_dict(list, d);
return 1;
}
- else if (!strcmp(q->type, "host"))
+ if (!strcmp(q->type, "host"))
{
+ s = NULL;
+ if (q->service != NULL)
+ {
+ s = getservbyname(q->service, q->protocol);
+ }
+ else if (q->port != NULL)
+ {
+ port = atoi(q->port);
+ s = getservbyport(port, q->protocol);
+ }
+
+ sprintf(portstr, "0");
+ if (s != NULL) sprintf(portstr, "%u", ntohl(s->s_port));
+
h = NULL;
if (q->name != NULL)
{
d = (struct lu_dict *)malloc(sizeof(struct lu_dict));
memset(d, 0, sizeof(struct lu_dict));
- if (h->h_name != NULL) d->name = strdup(h->h_name);
+ if (h->h_name != NULL)
+ {
+ d->name = strdup(h->h_name);
+ d->target = strdup(h->h_name);
+ }
memmove((void *)&a4.s_addr, h->h_addr_list[i], h->h_length);
sprintf(str, "%s", inet_ntoa(a4));
d->ipv4 = strdup(str);
- append_lu_dict(list, d);
+ if (s != NULL)
+ {
+ if (s->s_name != NULL) d->service = strdup(s->s_name);
+ d->port = strdup(portstr);
+ }
+
+ merge_lu_dict(list, d);
}
return i;
}
if (q->type == NULL) return 0;
if (list == NULL) return -1;
-
- server_port = lookupd_port(LOOKUPD_NAME);
- if (server_port == NULL) return gai_files(q, list);
+
+ server_port = MACH_PORT_NULL;
+ if (_lu_running()) server_port = _lookupd_port(0);
+
+ if (server_port == MACH_PORT_NULL) return gai_files(q, list);
status = _lookup_link(server_port, "query", &proc);
if (status != KERN_SUCCESS) return gai_files(q, list);
xdr_destroy(&outxdr);
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
datalen *= BYTES_PER_XDR_UNIT;
-#endif
+
xdrmem_create(&inxdr, listbuf, datalen, XDR_DECODE);
if (!xdr_int(&inxdr, &n))
if (!isdigit(*p)) port = -1;
}
- if (port == 0) port = atoi(servname);
- if ((port > 0) && (port < 0xffff)) q->port = (char *)servname;
+ if (port == 0) q->port = (char *)servname;
else q->service = (char *)servname;
}
a = (struct lu_dict *)malloc(sizeof(struct lu_dict));
memset(a, 0, sizeof(struct lu_dict));
a->ipv4 = strdup(h->ipv4);
- append_lu_dict(list, a);
+ merge_lu_dict(list, a);
n++;
}
a = (struct lu_dict *)malloc(sizeof(struct lu_dict));
memset(a, 0, sizeof(struct lu_dict));
a->ipv6 = strdup(h->ipv6);
- append_lu_dict(list, a);
+ merge_lu_dict(list, a);
n++;
}
a = (struct lu_dict *)malloc(sizeof(struct lu_dict));
memset(a, 0, sizeof(struct lu_dict));
a->port = strdup(s->port);
- append_lu_dict(list, a);
+ merge_lu_dict(list, a);
return 1;
}
{
if (d->cname != NULL)
{
- cname = strdup(d->cname);
+ if (cname == NULL) cname = strdup(d->cname);
gai_node_lookupd(d->cname, family, 0, &list);
}
}
if (nodename == NULL)
{
/* If node is NULL, find service */
- return gai_serv(servname, hints, res);
+ status = gai_serv(servname, hints, res);
+ if ((status == 0) && (*res == NULL)) status = EAI_NODATA;
+ return status;
}
if (servname == NULL)
{
/* If service is NULL, find node */
- return gai_node(nodename, hints, res);
+ status = gai_node(nodename, hints, res);
+ if ((status == 0) && (*res == NULL)) status = EAI_NODATA;
+ return status;
}
/* Find node + service */
- return gai_nodeserv(nodename, servname, hints, res);
+ status = gai_nodeserv(nodename, servname, hints, res);
+ if ((status == 0) && (*res == NULL)) status = EAI_NODATA;
+ return status;
}
+
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <grp.h>
static FILE *_gr_fp;
struct group *
getgrent()
{
- if (!_gr_fp && !start_gr() || !grscan(0, 0, NULL))
+ if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL))
return(NULL);
return(&_gr_group);
}
return(rval ? &_gr_group : NULL);
}
-static
+static int
start_gr()
{
if (_gr_fp) {
}
}
-static
+static int
grscan(search, gid, name)
register int search, gid;
register char *name;
--- /dev/null
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
+.\" $FreeBSD: src/lib/libc/net/gethostbyname.3,v 1.12.2.6 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd May 25, 1995
+.Dt GETHOSTBYNAME 3
+.Os
+.Sh NAME
+.Nm gethostbyname ,
+.Nm gethostbyname2 ,
+.Nm gethostbyaddr ,
+.Nm gethostent ,
+.Nm sethostent ,
+.Nm endhostent ,
+.Nm herror ,
+.Nm hstrerror
+.Nd get network host entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <netdb.h>
+.Vt extern int h_errno ;
+.Ft struct hostent *
+.Fn gethostbyname "const char *name"
+.Ft struct hostent *
+.Fn gethostbyname2 "const char *name" "int af"
+.Ft struct hostent *
+.Fn gethostbyaddr "const char *addr" "int len" "int type"
+.Ft struct hostent *
+.Fn gethostent void
+.Ft void
+.Fn sethostent "int stayopen"
+.Ft void
+.Fn endhostent void
+.Ft void
+.Fn herror "const char *string"
+.Ft const char *
+.Fn hstrerror "int err"
+.Sh DESCRIPTION
+The
+.Fn gethostbyname ,
+.Fn gethostbyname2
+and
+.Fn gethostbyaddr
+functions
+each return a pointer to an object with the
+following structure describing an internet host
+referenced by name or by address, respectively.
+This structure contains either the information obtained from the name server,
+.Xr named 8 ,
+or broken-out fields from a line in
+.Pa /etc/hosts .
+If the local name server is not running these routines do a lookup in
+.Pa /etc/hosts .
+.Bd -literal
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width h_addr_list
+.It Va h_name
+Official name of the host.
+.It Va h_aliases
+A
+.Dv NULL Ns -terminated
+array of alternate names for the host.
+.It Va h_addrtype
+The type of address being returned; usually
+.Dv AF_INET .
+.It Va h_length
+The length, in bytes, of the address.
+.It Va h_addr_list
+A
+.Dv NULL Ns -terminated
+array of network addresses for the host.
+Host addresses are returned in network byte order.
+.It Va h_addr
+The first address in
+.Va h_addr_list ;
+this is for backward compatibility.
+.El
+.Pp
+When using the nameserver,
+.Fn gethostbyname
+and
+.Fn gethostbyname2
+will search for the named host in the current domain and its parents
+unless the name ends in a dot.
+If the name contains no dot, and if the environment variable
+.Dq Ev HOSTALIASES
+contains the name of an alias file, the alias file will first be searched
+for an alias matching the input name.
+See
+.Xr hostname 7
+for the domain search procedure and the alias file format.
+.Pp
+The
+.Fn gethostbyname2
+function is an evolution of
+.Fn gethostbyname
+which is intended to allow lookups in address families other than
+.Dv AF_INET ,
+for example
+.Dv AF_INET6 .
+Currently the
+.Fa af
+argument must be specified as
+.Dv AF_INET
+else the function will return
+.Dv NULL
+after having set
+.Va h_errno
+to
+.Dv NETDB_INTERNAL
+.Pp
+The
+.Fn sethostent
+function
+may be used to request the use of a connected
+.Tn TCP
+socket for queries.
+If the
+.Fa stayopen
+flag is non-zero,
+this sets the option to send all queries to the name server using
+.Tn TCP
+and to retain the connection after each call to
+.Fn gethostbyname ,
+.Fn gethostbyname2
+or
+.Fn gethostbyaddr .
+Otherwise, queries are performed using
+.Tn UDP
+datagrams.
+.Pp
+The
+.Fn endhostent
+function
+closes the
+.Tn TCP
+connection.
+.Pp
+The
+.Fn herror
+function writes a message to the diagnostic output consisting of the
+string parameter
+.Fa s ,
+the constant string
+.Qq Li ":\ " ,
+and a message corresponding to the value of
+.Va h_errno .
+.Pp
+The
+.Fn hstrerror
+function returns a string which is the message text corresponding to the
+value of the
+.Fa err
+parameter.
+.Sh FILES
+.Bl -tag -width /etc/resolv.conf -compact
+.It Pa /etc/hosts
+.It Pa /etc/host.conf
+.It Pa /etc/resolv.conf
+.El
+.Sh DIAGNOSTICS
+Error return status from
+.Fn gethostbyname ,
+.Fn gethostbyname2
+and
+.Fn gethostbyaddr
+is indicated by return of a
+.Dv NULL
+pointer.
+The external integer
+.Va h_errno
+may then be checked to see whether this is a temporary failure
+or an invalid or unknown host.
+The routine
+.Fn herror
+can be used to print an error message describing the failure.
+If its argument
+.Fa string
+is
+.Pf non- Dv NULL ,
+it is printed, followed by a colon and a space.
+The error message is printed with a trailing newline.
+.Pp
+The variable
+.Va h_errno
+can have the following values:
+.Bl -tag -width HOST_NOT_FOUND
+.It Dv HOST_NOT_FOUND
+No such host is known.
+.It Dv TRY_AGAIN
+This is usually a temporary error
+and means that the local server did not receive
+a response from an authoritative server.
+A retry at some later time may succeed.
+.It Dv NO_RECOVERY
+Some unexpected server failure was encountered.
+This is a non-recoverable error.
+.It Dv NO_DATA
+The requested name is valid but does not have an IP address;
+this is not a temporary error.
+This means that the name is known to the name server but there is no address
+associated with this name.
+Another type of request to the name server using this domain name
+will result in an answer;
+for example, a mail-forwarder may be registered for this domain.
+.El
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr resolver 3 ,
+.Xr hosts 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Sh CAVEAT
+The
+.Fn gethostent
+function
+is defined, and
+.Fn sethostent
+and
+.Fn endhostent
+are redefined,
+when
+.Xr libc 3
+is built to use only the routines to lookup in
+.Pa /etc/hosts
+and not the name server.
+.Pp
+The
+.Fn gethostent
+function
+reads the next line of
+.Pa /etc/hosts ,
+opening the file if necessary.
+.Pp
+The
+.Fn sethostent
+function
+opens and/or rewinds the file
+.Pa /etc/hosts .
+If the
+.Fa stayopen
+argument is non-zero,
+the file will not be closed after each call to
+.Fn gethostbyname ,
+.Fn gethostbyname2
+or
+.Fn gethostbyaddr .
+.Pp
+The
+.Fn endhostent
+function
+closes the file.
+.Sh HISTORY
+The
+.Fn herror
+function appeared in
+.Bx 4.3 .
+The
+.Fn endhostent ,
+.Fn gethostbyaddr ,
+.Fn gethostbyname ,
+.Fn gethostent ,
+and
+.Fn sethostent
+functions appeared in
+.Bx 4.2 .
+The
+.Fn gethostbyname2
+function first appeared in
+.Tn BIND
+version 4.9.4.
+.Sh BUGS
+These functions use static data storage;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
+Only the Internet
+address format is currently understood.
--- /dev/null
+.\" $FreeBSD: src/lib/libc/net/getifaddrs.3,v 1.1.2.4 2001/08/31 10:15:14 ru Exp $
+.\" $KAME: getifaddrs.3,v 1.4 2000/05/17 14:13:14 itojun Exp $
+.\" BSDI getifaddrs.3,v 2.5 2000/02/23 14:51:59 dab Exp
+.\"
+.\" Copyright (c) 1995, 1999
+.\" Berkeley Software Design, Inc. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.Dd October 12, 1995
+.Dt GETIFADDRS 3
+.Os
+.Sh NAME
+.Nm getifaddrs
+.Nd get interface addresses
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <ifaddrs.h>
+.Ft int
+.Fn getifaddrs "struct ifaddrs **ifap"
+.Ft void
+.Fn freeifaddrs "struct ifaddrs *ifp"
+.Sh DESCRIPTION
+The
+.Fn getifaddrs
+function stores a reference to a linked list of the network interfaces
+on the local machine in the memory referenced by
+.Fa ifap .
+The list consists of
+.Nm ifaddrs
+structures, as defined in the include file
+.Aq Pa ifaddrs.h .
+The
+.Nm ifaddrs
+structure contains at least the following entries:
+.Bd -literal
+ struct ifaddrs *ifa_next; /* Pointer to next struct */
+ char *ifa_name; /* Interface name */
+ u_int ifa_flags; /* Interface flags */
+ struct sockaddr *ifa_addr; /* Interface address */
+ struct sockaddr *ifa_netmask; /* Interface netmask */
+ struct sockaddr *ifa_broadaddr; /* Interface broadcast address */
+ struct sockaddr *ifa_dstaddr; /* P2P interface destination */
+ void *ifa_data; /* Address specific data */
+.Ed
+.Pp
+The
+.Li ifa_next
+field contains a pointer to the next structure on the list.
+This field is
+.Dv NULL
+in last structure on the list.
+.Pp
+The
+.Li ifa_name
+field contains the interface name.
+.Pp
+The
+.Li ifa_flags
+field contains the interface flags, as set by
+.Xr ifconfig 8
+utility.
+.Pp
+The
+.Li ifa_addr
+field references either the address of the interface or the link level
+address of the interface, if one exists, otherwise it is NULL.
+(The
+.Li sa_family
+field of the
+.Li ifa_addr
+field should be consulted to determine the format of the
+.Li ifa_addr
+address.)
+.Pp
+The
+.Li ifa_netmask
+field references the netmask associated with
+.Li ifa_addr ,
+if one is set, otherwise it is NULL.
+.Pp
+The
+.Li ifa_broadaddr
+field,
+which should only be referenced for non-P2P interfaces,
+references the broadcast address associated with
+.Li ifa_addr ,
+if one exists, otherwise it is NULL.
+.Pp
+The
+.Li ifa_dstaddr
+field references the destination address on a P2P interface,
+if one exists, otherwise it is NULL.
+.Pp
+The
+.Li ifa_data
+field references address family specific data. For
+.Dv AF_LINK
+addresses it contains a pointer to the
+.Fa struct if_data
+(as defined in include file
+.Aq Pa net/if.h )
+which contains various interface attributes and statistics.
+For all other address families, it contains a pointer to the
+.Fa struct ifa_data
+(as defined in include file
+.Aq Pa net/if.h )
+which contains per-address interface statistics.
+.Pp
+The data returned by
+.Fn getifaddrs
+is dynamically allocated and should be freed using
+.Fn freeifaddrs
+when no longer needed.
+.Sh RETURN VALUES
+.Rv -std getifaddrs
+.Sh ERRORS
+The
+.Fn getifaddrs
+may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr malloc 3
+or
+.Xr sysctl 3 .
+.Sh BUGS
+If both
+.Aq Pa net/if.h
+and
+.Aq Pa ifaddrs.h
+are being included,
+.Aq Pa net/if.h
+.Em must
+be included before
+.Aq Pa ifaddrs.h .
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr sysctl 3 ,
+.Xr networking 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+implementation first appeared in BSDi
+.Bsx .
--- /dev/null
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
+ */
+/*
+ * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
+ * try-and-error for region size.
+ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef NET_RT_IFLIST
+#include <sys/param.h>
+#include <net/route.h>
+#include <sys/sysctl.h>
+#include <net/if_dl.h>
+#endif
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(AF_LINK)
+#define SA_LEN(sa) sizeof(struct sockaddr)
+#endif
+
+#if !defined(SA_LEN)
+#define SA_LEN(sa) (sa)->sa_len
+#endif
+
+#define SALIGN (sizeof(long) - 1)
+#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
+
+#ifndef ALIGNBYTES
+/*
+ * On systems with a routing socket, ALIGNBYTES should match the value
+ * that the kernel uses when building the messages.
+ */
+#define ALIGNBYTES XXX
+#endif
+#ifndef ALIGN
+#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+#endif
+
+#if _BSDI_VERSION >= 199701
+#define HAVE_IFM_DATA
+#endif
+
+#if _BSDI_VERSION >= 199802
+/* ifam_data is very specific to recent versions of bsdi */
+#define HAVE_IFAM_DATA
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+#define HAVE_IFM_DATA
+#endif
+
+int
+getifaddrs(struct ifaddrs **pif)
+{
+ int icnt = 1;
+ int dcnt = 0;
+ int ncnt = 0;
+#ifdef NET_RT_IFLIST
+ int mib[6];
+ size_t needed;
+ char *buf;
+ char *next;
+ struct ifaddrs *cif = 0;
+ char *p, *p0;
+ struct rt_msghdr *rtm;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *dl;
+ struct sockaddr *sa;
+ struct ifaddrs *ifa, *ift;
+ u_short index = 0;
+#else /* NET_RT_IFLIST */
+ char buf[1024];
+ int m, sock;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct ifreq *lifr;
+#endif /* NET_RT_IFLIST */
+ int i;
+ size_t len, alen;
+ char *data;
+ char *names;
+
+#ifdef NET_RT_IFLIST
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return (-1);
+ if ((buf = malloc(needed)) == NULL)
+ return (-1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ free(buf);
+ return (-1);
+ }
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)rtm;
+ if (ifm->ifm_addrs & RTA_IFP) {
+ index = ifm->ifm_index;
+ ++icnt;
+ dl = (struct sockaddr_dl *)(ifm + 1);
+ dcnt += SA_RLEN((struct sockaddr *)dl) +
+ ALIGNBYTES;
+#ifdef HAVE_IFM_DATA
+ dcnt += sizeof(ifm->ifm_data);
+#endif /* HAVE_IFM_DATA */
+ ncnt += dl->sdl_nlen + 1;
+ } else
+ index = 0;
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+ if (index && ifam->ifam_index != index)
+ abort(); /* this cannot happen */
+
+#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
+ if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
+ break;
+ p = (char *)(ifam + 1);
+ ++icnt;
+#ifdef HAVE_IFAM_DATA
+ dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
+#endif /* HAVE_IFAM_DATA */
+ /* Scan to look for length of address */
+ alen = 0;
+ for (p0 = p, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_IFA) {
+ alen = len;
+ break;
+ }
+ p += len;
+ }
+ for (p = p0, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
+ dcnt += alen;
+ else
+ dcnt += len;
+ p += len;
+ }
+ break;
+ }
+ }
+#else /* NET_RT_IFLIST */
+ ifc.ifc_buf = buf;
+ ifc.ifc_len = sizeof(buf);
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return (-1);
+ i = ioctl(sock, SIOCGIFCONF, (char *)&ifc);
+ close(sock);
+ if (i < 0)
+ return (-1);
+
+ ifr = ifc.ifc_req;
+ lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
+
+ while (ifr < lifr) {
+ struct sockaddr *sa;
+
+ sa = &ifr->ifr_addr;
+ ++icnt;
+ dcnt += SA_RLEN(sa);
+ ncnt += sizeof(ifr->ifr_name) + 1;
+
+ ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
+ }
+#endif /* NET_RT_IFLIST */
+
+ if (icnt + dcnt + ncnt == 1) {
+ *pif = NULL;
+ free(buf);
+ return (0);
+ }
+ data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
+ if (data == NULL) {
+ free(buf);
+ return(-1);
+ }
+
+ ifa = (struct ifaddrs *)data;
+ data += sizeof(struct ifaddrs) * icnt;
+ names = data + dcnt;
+
+ memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
+ ift = ifa;
+
+#ifdef NET_RT_IFLIST
+ index = 0;
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)rtm;
+ if (ifm->ifm_addrs & RTA_IFP) {
+ index = ifm->ifm_index;
+ dl = (struct sockaddr_dl *)(ifm + 1);
+
+ cif = ift;
+ ift->ifa_name = names;
+ ift->ifa_flags = (int)ifm->ifm_flags;
+ memcpy(names, dl->sdl_data, dl->sdl_nlen);
+ names[dl->sdl_nlen] = 0;
+ names += dl->sdl_nlen + 1;
+
+ ift->ifa_addr = (struct sockaddr *)data;
+ memcpy(data, dl, SA_LEN((struct sockaddr *)dl));
+ data += SA_RLEN((struct sockaddr *)dl);
+
+#ifdef HAVE_IFM_DATA
+ /* ifm_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
+ data += sizeof(ifm->ifm_data);
+#else /* HAVE_IFM_DATA */
+ ift->ifa_data = NULL;
+#endif /* HAVE_IFM_DATA */
+
+ ift = (ift->ifa_next = ift + 1);
+ } else
+ index = 0;
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+ if (index && ifam->ifam_index != index)
+ abort(); /* this cannot happen */
+
+ if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
+ break;
+ ift->ifa_name = cif->ifa_name;
+ ift->ifa_flags = cif->ifa_flags;
+ ift->ifa_data = NULL;
+ p = (char *)(ifam + 1);
+ /* Scan to look for length of address */
+ alen = 0;
+ for (p0 = p, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_IFA) {
+ alen = len;
+ break;
+ }
+ p += len;
+ }
+ for (p = p0, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ switch (i) {
+ case RTAX_IFA:
+ ift->ifa_addr = (struct sockaddr *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_NETMASK:
+ ift->ifa_netmask =
+ (struct sockaddr *)data;
+ if (SA_LEN(sa) == 0) {
+ memset(data, 0, alen);
+ data += alen;
+ break;
+ }
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_BRD:
+ ift->ifa_broadaddr =
+ (struct sockaddr *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+ }
+ p += len;
+ }
+
+#ifdef HAVE_IFAM_DATA
+ /* ifam_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
+ data += sizeof(ifam->ifam_data);
+#endif /* HAVE_IFAM_DATA */
+
+ ift = (ift->ifa_next = ift + 1);
+ break;
+ }
+ }
+
+ free(buf);
+#else /* NET_RT_IFLIST */
+ ifr = ifc.ifc_req;
+ lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
+
+ while (ifr < lifr) {
+ struct sockaddr *sa;
+
+ ift->ifa_name = names;
+ names[sizeof(ifr->ifr_name)] = 0;
+ strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
+ while (*names++)
+ ;
+
+ ift->ifa_addr = (struct sockaddr *)data;
+ sa = &ifr->ifr_addr;
+ memcpy(data, sa, SA_LEN(sa));
+ data += SA_RLEN(sa);
+
+ ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
+ ift = (ift->ifa_next = ift + 1);
+ }
+#endif /* NET_RT_IFLIST */
+ if (--ift >= ifa) {
+ ift->ifa_next = NULL;
+ *pif = ifa;
+ } else {
+ *pif = NULL;
+ free(ifa);
+ }
+ return (0);
+}
+
+void
+freeifaddrs(struct ifaddrs *ifp)
+{
+ free(ifp);
+}
--- /dev/null
+.\" $FreeBSD: src/lib/libc/net/getipnodebyname.3,v 1.2.2.3 2001/08/17 15:42:38 ru Exp $
+.\" $KAME: getipnodebyname.3,v 1.6 2000/08/09 21:16:17 itojun Exp $
+.\"
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
+.\"
+.Dd May 25, 1995
+.Dt GETIPNODEBYNAME 3
+.Os
+.\"
+.Sh NAME
+.Nm getipnodebyname ,
+.Nm getipnodebyaddr ,
+.Nm freehostent
+.Nd nodename-to-address and address-to-nodename translation
+.\"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <netdb.h>
+.Ft "struct hostent *"
+.Fn getipnodebyname "const char *name" "int af" "int flags" "int *error_num"
+.Ft "struct hostent *"
+.Fn getipnodebyaddr "const void *src" "size_t len" "int af" "int *error_num"
+.Ft void
+.Fn freehostent "struct hostent *ptr"
+.\"
+.Sh DESCRIPTION
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+functions are very similar to
+.Xr gethostbyname 3 ,
+.Xr gethostbyname2 3
+and
+.Xr gethostbyaddr 3 .
+The functions cover all the functionalities provided by the older ones,
+and provide better interface to programmers.
+The functions require additional arguments,
+.Ar af ,
+and
+.Ar flags ,
+for specifying address family and operation mode.
+The additional arguments allow programmer to get address for a nodename,
+for specific address family
+(such as
+.Dv AF_INET
+or
+.Dv AF_INET6 ) .
+The functions also require an additional pointer argument,
+.Ar error_num
+to return the appropriate error code,
+to support thread safe error code returns.
+.Pp
+The type and usage of the return value,
+.Li "struct hostent"
+is described in
+.Xr gethostbyname 3 .
+.Pp
+For
+.Fn getipnodebyname ,
+the
+.Ar name
+argument can be either a node name or a numeric address
+string
+(i.e., a dotted-decimal IPv4 address or an IPv6 hex address).
+The
+.Ar af
+argument specifies the address family, either
+.Dv AF_INET
+or
+.Dv AF_INET6 .
+The
+.Ar flags
+argument specifies the types of addresses that are searched for,
+and the types of addresses that are returned.
+We note that a special flags value of
+.Dv AI_DEFAULT
+(defined below)
+should handle most applications.
+That is, porting simple applications to use IPv6 replaces the call
+.Bd -literal -offset
+ hptr = gethostbyname(name);
+.Ed
+.Pp
+with
+.Bd -literal -offset
+ hptr = getipnodebyname(name, AF_INET6, AI_DEFAULT, &error_num);
+.Ed
+.Pp
+Applications desiring finer control over the types of addresses
+searched for and returned, can specify other combinations of the
+.Ar flags
+argument.
+.Pp
+A
+.Ar flags
+of
+.Li 0
+implies a strict interpretation of the
+.Ar af
+argument:
+.Bl -bullet
+.It
+If
+.Ar flags
+is 0 and
+.Ar af
+is
+.Dv AF_INET ,
+then the caller wants only IPv4 addresses.
+A query is made for
+.Li A
+records.
+If successful, the IPv4 addresses are returned and the
+.Li h_length
+member of the
+.Li hostent
+structure will be 4, else the function returns a
+.Dv NULL
+pointer.
+.It
+If
+.Ar flags
+is 0 and if
+.Ar af
+is
+.Li AF_INET6 ,
+then the caller wants only IPv6 addresses.
+A query is made for
+.Li AAAA
+records.
+If successful, the IPv6 addresses are returned and the
+.Li h_length
+member of the
+.Li hostent
+structure will be 16, else the function returns a
+.Dv NULL
+pointer.
+.El
+.Pp
+Other constants can be logically-ORed into the
+.Ar flags
+argument, to modify the behavior of the function.
+.Bl -bullet
+.It
+If the
+.Dv AI_V4MAPPED
+flag is specified along with an
+.Ar af
+of
+.Dv AF_INET6 ,
+then the caller will accept IPv4-mapped IPv6 addresses.
+That is, if no
+.Li AAAA
+records are found then a query is made for
+.Li A
+records and any found are returned as IPv4-mapped IPv6 addresses
+.Li ( h_length
+will be 16).
+The
+.Dv AI_V4MAPPED
+flag is ignored unless
+.Ar af
+equals
+.Dv AF_INET6 .
+.It
+The
+.Dv AI_V4MAPPED_CFG
+flag is exact same as the
+.Dv AI_V4MAPPED
+flag only if the kernel supports IPv4-mapped IPv6 address.
+.It
+If the
+.Dv AI_ALL
+flag is used in conjunction with the
+.Dv AI_V4MAPPED
+flag, and only used with the IPv6 address family.
+When
+.Dv AI_ALL
+is logically or'd with
+.Dv AI_V4MAPPED
+flag then the caller wants all addresses: IPv6 and IPv4-mapped IPv6.
+A query is first made for
+.Li AAAA
+records and if successful, the
+IPv6 addresses are returned. Another query is then made for
+.Li A
+records and any found are returned as IPv4-mapped IPv6 addresses.
+.Li h_length
+will be 16. Only if both queries fail does the function
+return a
+.Dv NULL
+pointer. This flag is ignored unless af equals
+AF_INET6. If both
+.Dv AI_ALL
+and
+.Dv AI_V4MAPPED
+are specified,
+.Dv AI_ALL
+takes precedence.
+.It
+The
+.Dv AI_ADDRCONFIG
+flag specifies that a query for
+.Li AAAA
+records
+should occur only if the node has at least one IPv6 source
+address configured and a query for
+.Li A
+records should occur only if the node has at least one IPv4 source address
+configured.
+.Pp
+For example, if the node has no IPv6 source addresses configured,
+and
+.Ar af
+equals AF_INET6, and the node name being looked up has both
+.Li AAAA
+and
+.Li A
+records, then:
+(a) if only
+.Dv AI_ADDRCONFIG
+is
+specified, the function returns a
+.Dv NULL
+pointer;
+(b) if
+.Dv AI_ADDRCONFIG
+|
+.Dv AI_V4MAPPED
+is specified, the
+.Li A
+records are returned as IPv4-mapped IPv6 addresses;
+.El
+.Pp
+The special flags value of
+.Dv AI_DEFAULT
+is defined as
+.Bd -literal -offset
+ #define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG)
+.Ed
+.Pp
+We noted that the
+.Fn getipnodebyname
+function must allow the
+.Ar name
+argument to be either a node name or a literal address string
+(i.e., a dotted-decimal IPv4 address or an IPv6 hex address).
+This saves applications from having to call
+.Xr inet_pton 3
+to handle literal address strings.
+When the
+.Ar name
+argument is a literal address string,
+the
+.Ar flags
+argument is always ignored.
+.Pp
+There are four scenarios based on the type of literal address string
+and the value of the
+.Ar af
+argument.
+The two simple cases are when
+.Ar name
+is a dotted-decimal IPv4 address and
+.Ar af
+equals
+.Dv AF_INET ,
+or when
+.Ar name
+is an IPv6 hex address and
+.Ar af
+equals
+.Dv AF_INET6 .
+The members of the
+returned hostent structure are:
+.Li h_name
+points to a copy of the
+.Ar name
+argument,
+.Li h_aliases
+is a
+.Dv NULL
+pointer,
+.Li h_addrtype
+is a copy of the
+.Ar af
+argument,
+.Li h_length
+is either 4
+(for
+.Dv AF_INET )
+or 16
+(for
+.Dv AF_INET6 ) ,
+.Li h_addr_list[0]
+is a pointer to the 4-byte or 16-byte binary address,
+and
+.Li h_addr_list[1]
+is a
+.Dv NULL
+pointer.
+.Pp
+When
+.Ar name
+is a dotted-decimal IPv4 address and
+.Ar af
+equals
+.Dv AF_INET6 ,
+and
+.Dv AI_V4MAPPED
+is specified,
+an IPv4-mapped IPv6 address is returned:
+.Li h_name
+points to an IPv6 hex address containing the IPv4-mapped IPv6 address,
+.Li h_aliases
+is a
+.Dv NULL
+pointer,
+.Li h_addrtype
+is
+.Dv AF_INET6 ,
+.Li h_length
+is 16,
+.Li h_addr_list[0]
+is a pointer to the 16-byte binary address, and
+.Li h_addr_list[1]
+is a
+.Dv NULL
+pointer.
+.Pp
+It is an error when
+.Ar name
+is an IPv6 hex address and
+.Ar af
+equals
+.Dv AF_INET .
+The function's return value is a
+.Dv NULL
+pointer and the value pointed to by
+.Ar error_num
+equals
+.Dv HOST_NOT_FOUND .
+.Pp
+.Fn getipnodebyaddr
+takes almost the same argument as
+.Xr gethostbyaddr 3 ,
+but adds a pointer to return an error number.
+Additionally it takes care of IPv4-mapped IPv6 addresses,
+and IPv4-compatible IPv6 addresses.
+.Pp
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+dynamically allocate the structure to be returned to the caller.
+.Fn freehostent
+reclaims memory region allocated and returned by
+.Fn getipnodebyname
+or
+.Fn getipnodebyaddr .
+.\"
+.Sh FILES
+.Bl -tag -width /etc/resolv.conf -compact
+.It Pa /etc/hosts
+.It Pa /etc/host.conf
+.It Pa /etc/resolv.conf
+.El
+.\"
+.Sh DIAGNOSTICS
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+returns
+.Dv NULL
+on errors.
+The integer values pointed to by
+.Ar error_num
+may then be checked to see whether this is a temporary failure
+or an invalid or unknown host.
+The meanings of each error code are described in
+.Xr gethostbyname 3 .
+.\"
+.Sh SEE ALSO
+.Xr gethostbyaddr 3 ,
+.Xr gethostbyname 3 ,
+.Xr hosts 5 ,
+.Xr services 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Pp
+.Rs
+.%A R. Gilligan
+.%A S. Thomson
+.%A J. Bound
+.%A W. Stevens
+.%T Basic Socket Interface Extensions for IPv6
+.%R RFC2553
+.%D March 1999
+.Re
+.\"
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
+.\"
+.Sh STANDARDS
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+are documented in
+.Dq Basic Socket Interface Extensions for IPv6
+(RFC2553).
+.\"
+.Sh BUGS
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+do not handle scoped IPv6 address properly.
+If you use these functions,
+your program will not be able to handle scoped IPv6 addresses.
+For IPv6 address manipulation,
+.Fn getaddrinfo 3
+and
+.Fn getnameinfo 3
+are recommended.
+.Pp
+The current implementation is not thread-safe.
+.Pp
+The text was shamelessly copied from RFC2553.
--- /dev/null
+.\" $FreeBSD: src/lib/libc/net/getnameinfo.3,v 1.2.2.7 2001/08/17 15:42:38 ru Exp $
+.\" $KAME: getnameinfo.3,v 1.17 2000/08/09 21:16:17 itojun Exp $
+.\"
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
+.\"
+.Dd May 25, 1995
+.Dt GETNAMEINFO 3
+.Os
+.\"
+.Sh NAME
+.Nm getnameinfo
+.Nd address-to-nodename translation in protocol-independent manner
+.\"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <netdb.h>
+.Ft int
+.Fn getnameinfo "const struct sockaddr *sa" "socklen_t salen" \
+"char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags"
+.\"
+.Sh DESCRIPTION
+The
+.Fn getnameinfo
+function is defined for protocol-independent address-to-nodename translation.
+Its functionality is a reverse conversion of
+.Xr getaddrinfo 3 ,
+and implements similar functionality with
+.Xr gethostbyaddr 3
+and
+.Xr getservbyport 3
+in more sophisticated manner.
+.Pp
+This function looks up an IP address and port number provided by the
+caller in the DNS and system-specific database, and returns text
+strings for both in buffers provided by the caller.
+The function indicates successful completion by a zero return value;
+a non-zero return value indicates failure.
+.Pp
+The first argument,
+.Fa sa ,
+points to either a
+.Li sockaddr_in
+structure (for IPv4) or a
+.Li sockaddr_in6
+structure (for IPv6) that holds the IP address and port number.
+The
+.Fa salen
+argument gives the length of the
+.Li sockaddr_in
+or
+.Li sockaddr_in6
+structure.
+.Pp
+The function returns the nodename associated with the IP address in
+the buffer pointed to by the
+.Fa host
+argument.
+The caller provides the size of this buffer via the
+.Fa hostlen
+argument.
+The service name associated with the port number is returned in the buffer
+pointed to by
+.Fa serv ,
+and the
+.Fa servlen
+argument gives the length of this buffer.
+The caller specifies not to return either string by providing a zero
+value for the
+.Fa hostlen
+or
+.Fa servlen
+arguments.
+Otherwise, the caller must provide buffers large enough to hold the
+nodename and the service name, including the terminating null characters.
+.Pp
+Unfortunately most systems do not provide constants that specify the
+maximum size of either a fully-qualified domain name or a service name.
+Therefore to aid the application in allocating buffers for these two
+returned strings the following constants are defined in
+.Aq Pa netdb.h :
+.Bd -literal -offset
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+.Ed
+.Pp
+The first value is actually defined as the constant
+.Dv MAXDNAME
+in recent versions of BIND's
+.Aq Pa arpa/nameser.h
+header
+(older versions of BIND define this constant to be 256)
+and the second is a guess based on the services listed in the current
+Assigned Numbers RFC.
+.Pp
+The final argument is a
+.Fa flag
+that changes the default actions of this function.
+By default the fully-qualified domain name (FQDN) for the host is
+looked up in the DNS and returned.
+If the flag bit
+.Dv NI_NOFQDN
+is set, only the nodename portion of the FQDN is returned for local hosts.
+.Pp
+If the
+.Fa flag
+bit
+.Dv NI_NUMERICHOST
+is set, or if the host's name cannot be located in the DNS,
+the numeric form of the host's address is returned instead of its name
+(e.g., by calling
+.Fn inet_ntop
+instead of
+.Fn getnodebyaddr ) .
+If the
+.Fa flag
+bit
+.Dv NI_NAMEREQD
+is set, an error is returned if the host's name cannot be located in the DNS.
+.Pp
+If the flag bit
+.Dv NI_NUMERICSERV
+is set, the numeric form of the service address is returned
+(e.g., its port number)
+instead of its name.
+The two
+.Dv NI_NUMERICxxx
+flags are required to support the
+.Fl n
+flag that many commands provide.
+.Pp
+A fifth flag bit,
+.Dv NI_DGRAM ,
+specifies that the service is a datagram service, and causes
+.Fn getservbyport
+to be called with a second argument of
+.Dq udp
+instead of its default of
+.Dq tcp .
+This is required for the few ports (512-514)
+that have different services for UDP and TCP.
+.Pp
+These
+.Dv NI_xxx
+flags are defined in
+.Aq Pa netdb.h .
+.\"
+.Sh EXTENSION
+The implementation allows experimental numeric IPv6 address notation with
+scope identifier.
+IPv6 link-local address will appear as string like
+.Dq Li fe80::1%ne0 ,
+if
+.Dv NI_WITHSCOPEID
+bit is enabled in
+.Ar flags
+argument.
+Refer to
+.Xr getaddrinfo 3
+for the notation.
+.\"
+.Sh EXAMPLES
+The following code tries to get numeric hostname, and service name,
+for given socket address.
+Observe that there is no hardcoded reference to particular address family.
+.Bd -literal -offset indent
+struct sockaddr *sa; /* input */
+char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+
+if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf,
+ sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
+ errx(1, "could not get numeric hostname");
+ /*NOTREACHED*/
+}
+printf("host=%s, serv=%s\\n", hbuf, sbuf);
+.Ed
+.Pp
+The following version checks if the socket address has reverse address mapping.
+.Bd -literal -offset indent
+struct sockaddr *sa; /* input */
+char hbuf[NI_MAXHOST];
+
+if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
+ NI_NAMEREQD)) {
+ errx(1, "could not resolve hostname");
+ /*NOTREACHED*/
+}
+printf("host=%s\\n", hbuf);
+.Ed
+.\"
+.Sh FILES
+.Bl -tag -width /etc/resolv.conf -compact
+.It Pa /etc/hosts
+.It Pa /etc/host.conf
+.It Pa /etc/resolv.conf
+.El
+.\"
+.Sh DIAGNOSTICS
+The function indicates successful completion by a zero return value;
+a non-zero return value indicates failure.
+Error codes are as below:
+.Bl -tag -width Er
+.It Bq Er EAI_AGAIN
+The name could not be resolved at this time.
+Future attempts may succeed.
+.It Bq Er EAI_BADFLAGS
+The flags had an invalid value.
+.It Bq Er EAI_FAIL
+A non-recoverable error occurred.
+.It Bq Er EAI_FAMILY
+The address family was not recognized or the address length was invalid
+for the specified family.
+.It Bq Er EAI_MEMORY
+There was a memory allocation failure.
+.It Bq Er EAI_NONAME
+The name does not resolve for the supplied parameters.
+.Dv NI_NAMEREQD
+is set and the host's name cannot be located,
+or both nodename and servname were null.
+.It Bq Er EAI_SYSTEM
+A system error occurred.
+The error code can be found in errno.
+.El
+.\"
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr gethostbyaddr 3 ,
+.Xr getservbyport 3 ,
+.Xr hosts 5 ,
+.Xr services 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Pp
+.Rs
+.%A R. Gilligan
+.%A S. Thomson
+.%A J. Bound
+.%A W. Stevens
+.%T Basic Socket Interface Extensions for IPv6
+.%R RFC2553
+.%D March 1999
+.Re
+.Rs
+.%A Tatsuya Jinmei
+.%A Atsushi Onoe
+.%T "An Extension of Format for IPv6 Scoped Addresses"
+.%R internet draft
+.%N draft-ietf-ipngwg-scopedaddr-format-02.txt
+.%O work in progress material
+.Re
+.Rs
+.%A Craig Metz
+.%T Protocol Independence Using the Sockets API
+.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference"
+.%D June 2000
+.Re
+.\"
+.Sh HISTORY
+The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\"
+.Sh STANDARDS
+The
+.Fn getaddrinfo
+function is defined in
+.St -p1003.1g-2000 ,
+and documented in
+.Dq Basic Socket Interface Extensions for IPv6
+(RFC2553).
+.\"
+.Sh BUGS
+The current implementation is not thread-safe.
+.Pp
+The text was shamelessly copied from RFC2553.
+.Pp
+The type of the 2nd argument should be
+.Li socklen_t
+for RFC2553 conformance.
+The current code is based on pre-RFC2553 specification.
--- /dev/null
+/* $FreeBSD: src/lib/libc/net/getnameinfo.c,v 1.5 2000/07/05 05:09:17 itojun Exp $ */
+/* $KAME: getnameinfo.c,v 1.43 2000/06/12 04:27:03 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ * - Return values. There seems to be no standard for return value (RFC2553)
+ * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ * - RFC2553 says that we should raise error on short buffer. X/Open says
+ * we need to truncate the result. We obey RFC2553 (and X/Open should be
+ * modified).
+ * - What is "local" in NI_FQDN?
+ * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
+ * - (KAME extension) NI_WITHSCOPEID when called with global address,
+ * and sin6_scope_id filled
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stddef.h>
+#include <errno.h>
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO 0
+
+static struct afd {
+ int a_af;
+ int a_addrlen;
+ int a_socklen;
+ int a_off;
+} afdl [] = {
+#ifdef INET6
+ {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr)},
+#endif
+ {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr)},
+ {0, 0, 0},
+};
+
+struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+};
+
+
+#ifdef INET6
+static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
+ size_t, int));
+static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int));
+#endif
+
+#define ENI_NOSOCKET EAI_FAIL /*XXX*/
+#define ENI_NOSERVNAME EAI_NONAME
+#define ENI_NOHOSTNAME EAI_NONAME
+#define ENI_MEMORY EAI_MEMORY
+#define ENI_SYSTEM EAI_SYSTEM
+#define ENI_FAMILY EAI_FAMILY
+#define ENI_SALEN EAI_FAMILY
+
+int
+getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+ const struct sockaddr *sa;
+ size_t salen;
+ char *host;
+ size_t hostlen;
+ char *serv;
+ size_t servlen;
+ int flags;
+{
+ struct afd *afd;
+ struct servent *sp;
+ struct hostent *hp;
+ u_short port;
+ int family, i;
+ const char *addr;
+ u_int32_t v4a;
+ char numserv[512];
+ char numaddr[512];
+
+ if (sa == NULL)
+ return ENI_NOSOCKET;
+
+#ifdef NOTDEF
+ if (sa->sa_len != salen)
+ return ENI_SALEN;
+#endif
+
+ family = sa->sa_family;
+ for (i = 0; afdl[i].a_af; i++)
+ if (afdl[i].a_af == family) {
+ afd = &afdl[i];
+ goto found;
+ }
+ return ENI_FAMILY;
+
+ found:
+ if (salen != afd->a_socklen)
+ return ENI_SALEN;
+
+ /* network byte order */
+ port = ((const struct sockinet *)sa)->si_port;
+ addr = (const char *)sa + afd->a_off;
+
+ if (serv == NULL || servlen == 0) {
+ /*
+ * do nothing in this case.
+ * in case you are wondering if "&&" is more correct than
+ * "||" here: RFC2553 says that serv == NULL OR servlen == 0
+ * means that the caller does not want the result.
+ */
+ } else {
+ if (flags & NI_NUMERICSERV)
+ sp = NULL;
+ else {
+ sp = getservbyport(port,
+ (flags & NI_DGRAM) ? "udp" : "tcp");
+ }
+ if (sp) {
+ if (strlen(sp->s_name) > servlen)
+ return ENI_MEMORY;
+ strcpy(serv, sp->s_name);
+ } else {
+ snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
+ if (strlen(numserv) > servlen)
+ return ENI_MEMORY;
+ strcpy(serv, numserv);
+ }
+ }
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ v4a = (u_int32_t)
+ ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
+ if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+ flags |= NI_NUMERICHOST;
+ v4a >>= IN_CLASSA_NSHIFT;
+ if (v4a == 0)
+ flags |= NI_NUMERICHOST;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ {
+ const struct sockaddr_in6 *sin6;
+ sin6 = (const struct sockaddr_in6 *)sa;
+ switch (sin6->sin6_addr.s6_addr[0]) {
+ case 0x00:
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ ;
+ else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+ ;
+ else
+ flags |= NI_NUMERICHOST;
+ break;
+ default:
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ flags |= NI_NUMERICHOST;
+ }
+ else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+ flags |= NI_NUMERICHOST;
+ break;
+ }
+ }
+ break;
+#endif
+ }
+ if (host == NULL || hostlen == 0) {
+ /*
+ * do nothing in this case.
+ * in case you are wondering if "&&" is more correct than
+ * "||" here: RFC2553 says that host == NULL OR hostlen == 0
+ * means that the caller does not want the result.
+ */
+ } else if (flags & NI_NUMERICHOST) {
+ int numaddrlen;
+
+ /* NUMERICHOST and NAMEREQD conflicts with each other */
+ if (flags & NI_NAMEREQD)
+ return ENI_NOHOSTNAME;
+
+ switch(afd->a_af) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ int error;
+
+ if ((error = ip6_parsenumeric(sa, addr, host,
+ hostlen, flags)) != 0)
+ return(error);
+ break;
+ }
+#endif
+ default:
+ if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return ENI_SYSTEM;
+ numaddrlen = strlen(numaddr);
+ if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+ return ENI_MEMORY;
+ strcpy(host, numaddr);
+ break;
+ }
+ } else {
+#if 0
+ int h_error;
+ hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
+#else
+ hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+#endif
+
+ if (hp) {
+#if 0
+ /*
+ * commented out, since "for local host" is not
+ * implemented here - see RFC2553 p30
+ */
+ if (flags & NI_NOFQDN) {
+ char *p;
+ p = strchr(hp->h_name, '.');
+ if (p)
+ *p = '\0';
+ }
+#endif
+ if (strlen(hp->h_name) > hostlen) {
+#if 0
+ freehostent(hp);
+#endif
+ return ENI_MEMORY;
+ }
+ strcpy(host, hp->h_name);
+#if 0
+ freehostent(hp);
+#endif
+ } else {
+ if (flags & NI_NAMEREQD)
+ return ENI_NOHOSTNAME;
+ switch(afd->a_af) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ int error;
+
+ if ((error = ip6_parsenumeric(sa, addr, host,
+ hostlen,
+ flags)) != 0)
+ return(error);
+ break;
+ }
+#endif
+ default:
+ if (inet_ntop(afd->a_af, addr, host,
+ hostlen) == NULL)
+ return ENI_SYSTEM;
+ break;
+ }
+ }
+ }
+ return SUCCESS;
+}
+
+#ifdef INET6
+static int
+ip6_parsenumeric(sa, addr, host, hostlen, flags)
+ const struct sockaddr *sa;
+ const char *addr;
+ char *host;
+ size_t hostlen;
+ int flags;
+{
+ int numaddrlen;
+ char numaddr[512];
+
+ if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return ENI_SYSTEM;
+
+ numaddrlen = strlen(numaddr);
+ if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+ return ENI_MEMORY;
+ strcpy(host, numaddr);
+
+#ifdef NI_WITHSCOPEID
+ if (
+#ifdef DONT_OPAQUE_SCOPEID
+ (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
+ IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
+#endif
+ ((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
+#ifndef ALWAYS_WITHSCOPE
+ if (flags & NI_WITHSCOPEID)
+#endif /* !ALWAYS_WITHSCOPE */
+ {
+ char scopebuf[MAXHOSTNAMELEN];
+ int scopelen;
+
+ /* ip6_sa2str never fails */
+ scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa,
+ scopebuf, sizeof(scopebuf),
+ flags);
+ if (scopelen + 1 + numaddrlen + 1 > hostlen)
+ return ENI_MEMORY;
+ /*
+ * construct <numeric-addr><delim><scopeid>
+ */
+ memcpy(host + numaddrlen + 1, scopebuf,
+ scopelen);
+ host[numaddrlen] = SCOPE_DELIMITER;
+ host[numaddrlen + 1 + scopelen] = '\0';
+ }
+ }
+#endif /* NI_WITHSCOPEID */
+
+ return 0;
+}
+
+/* ARGSUSED */
+static int
+ip6_sa2str(sa6, buf, bufsiz, flags)
+ const struct sockaddr_in6 *sa6;
+ char *buf;
+ size_t bufsiz;
+ int flags;
+{
+ unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
+ const struct in6_addr *a6 = &sa6->sin6_addr;
+
+#ifdef NI_NUMERICSCOPE
+ if (flags & NI_NUMERICSCOPE) {
+ return(snprintf(buf, bufsiz, "%d", sa6->sin6_scope_id));
+ }
+#endif
+
+ /* if_indextoname() does not take buffer size. not a good api... */
+ if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
+ bufsiz >= IF_NAMESIZE) {
+ char *p = if_indextoname(ifindex, buf);
+ if (p) {
+ return(strlen(p));
+ }
+ }
+
+ /* last resort */
+ return(snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id));
+}
+#endif /* INET6 */
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getnetent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/lib/libc/net/getnetent.3,v 1.11.2.3 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd June 4, 1993
+.Dt GETNETENT 3
+.Os
+.Sh NAME
+.Nm getnetent ,
+.Nm getnetbyaddr ,
+.Nm getnetbyname ,
+.Nm setnetent ,
+.Nm endnetent
+.Nd get network entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <netdb.h>
+.Ft struct netent *
+.Fn getnetent void
+.Ft struct netent *
+.Fn getnetbyname "const char *name"
+.Ft struct netent *
+.Fn getnetbyaddr "unsigned long net" "int type"
+.Ft void
+.Fn setnetent "int stayopen"
+.Ft void
+.Fn endnetent void
+.Sh DESCRIPTION
+The
+.Fn getnetent ,
+.Fn getnetbyname ,
+and
+.Fn getnetbyaddr
+functions
+each return a pointer to an object with the
+following structure
+containing the broken-out
+fields of a line in the network data base,
+.Pa /etc/networks .
+.Bd -literal -offset indent
+struct netent {
+ char *n_name; /* official name of net */
+ char **n_aliases; /* alias list */
+ int n_addrtype; /* net number type */
+ unsigned long n_net; /* net number */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width n_addrtype
+.It Fa n_name
+The official name of the network.
+.It Fa n_aliases
+A zero terminated list of alternate names for the network.
+.It Fa n_addrtype
+The type of the network number returned; currently only AF_INET.
+.It Fa n_net
+The network number. Network numbers are returned in machine byte
+order.
+.El
+.Pp
+The
+.Fn getnetent
+function
+reads the next line of the file, opening the file if necessary.
+.Pp
+The
+.Fn setnetent
+function
+opens and rewinds the file. If the
+.Fa stayopen
+flag is non-zero,
+the net data base will not be closed after each call to
+.Fn getnetbyname
+or
+.Fn getnetbyaddr .
+.Pp
+The
+.Fn endnetent
+function
+closes the file.
+.Pp
+The
+.Fn getnetbyname
+function
+and
+.Fn getnetbyaddr
+sequentially search from the beginning
+of the file until a matching
+net name or
+net address and type is found,
+or until
+.Dv EOF
+is encountered.
+The
+.Fa type
+must be
+.Dv AF_INET .
+Network numbers are supplied in host order.
+.Sh FILES
+.Bl -tag -width /etc/networks -compact
+.It Pa /etc/networks
+.El
+.Sh DIAGNOSTICS
+Null pointer
+(0) returned on
+.Dv EOF
+or error.
+.Sh SEE ALSO
+.Xr networks 5
+.Pp
+.%T RFC 1101
+.Sh HISTORY
+The
+.Fn getnetent ,
+.Fn getnetbyaddr ,
+.Fn getnetbyname ,
+.Fn setnetent ,
+and
+.Fn endnetent
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+The data space used by
+these functions is static; if future use requires the data, it should be
+copied before any subsequent calls to these functions overwrite it.
+Only Internet network
+numbers are currently understood.
+Expecting network numbers to fit
+in no more than 32 bits is probably
+naive.
register struct protoent *p;
setprotoent(_proto_stayopen);
- while (p = getprotoent())
+ while ((p = getprotoent()))
if (p->p_proto == proto)
break;
if (!_proto_stayopen)
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getprotoent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/lib/libc/net/getprotoent.3,v 1.4.2.3 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd June 4, 1993
+.Dt GETPROTOENT 3
+.Os
+.Sh NAME
+.Nm getprotoent ,
+.Nm getprotobynumber ,
+.Nm getprotobyname ,
+.Nm setprotoent ,
+.Nm endprotoent
+.Nd get protocol entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <netdb.h>
+.Ft struct protoent *
+.Fn getprotoent void
+.Ft struct protoent *
+.Fn getprotobyname "const char *name"
+.Ft struct protoent *
+.Fn getprotobynumber "int proto"
+.Ft void
+.Fn setprotoent "int stayopen"
+.Ft void
+.Fn endprotoent void
+.Sh DESCRIPTION
+The
+.Fn getprotoent ,
+.Fn getprotobyname ,
+and
+.Fn getprotobynumber
+functions
+each return a pointer to an object with the
+following structure
+containing the broken-out
+fields of a line in the network protocol data base,
+.Pa /etc/protocols .
+.Bd -literal -offset indent
+.Pp
+struct protoent {
+ char *p_name; /* official name of protocol */
+ char **p_aliases; /* alias list */
+ int p_proto; /* protocol number */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width p_aliases
+.It Fa p_name
+The official name of the protocol.
+.It Fa p_aliases
+A zero terminated list of alternate names for the protocol.
+.It Fa p_proto
+The protocol number.
+.El
+.Pp
+The
+.Fn getprotoent
+function
+reads the next line of the file, opening the file if necessary.
+.Pp
+The
+.Fn setprotoent
+function
+opens and rewinds the file. If the
+.Fa stayopen
+flag is non-zero,
+the net data base will not be closed after each call to
+.Fn getprotobyname
+or
+.Fn getprotobynumber .
+.Pp
+The
+.Fn endprotoent
+function
+closes the file.
+.Pp
+The
+.Fn getprotobyname
+function
+and
+.Fn getprotobynumber
+sequentially search from the beginning
+of the file until a matching
+protocol name or
+protocol number is found,
+or until
+.Dv EOF
+is encountered.
+.Sh RETURN VALUES
+Null pointer
+(0) returned on
+.Dv EOF
+or error.
+.Sh FILES
+.Bl -tag -width /etc/protocols -compact
+.It Pa /etc/protocols
+.El
+.Sh SEE ALSO
+.Xr protocols 5
+.Sh HISTORY
+The
+.Fn getprotoent ,
+.Fn getprotobynumber ,
+.Fn getprotobyname ,
+.Fn setprotoent ,
+and
+.Fn endprotoent
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+These functions use a static data space;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
+Only the Internet
+protocols are currently understood.
#define MAXALIASES 35
static FILE *protof = NULL;
-static char line[BUFSIZ+1];
static struct protoent proto;
static char *proto_aliases[MAXALIASES];
int _proto_stayopen;
getprotoent()
{
char *p;
+ static char *line = NULL;
register char *cp, **q;
if (protof == NULL && (protof = fopen(_PATH_PROTOCOLS, "r" )) == NULL)
return (NULL);
+
+ if (line == NULL) {
+ line = malloc(BUFSIZ+1);
+ if (line == NULL)
+ return (NULL);
+ }
again:
if ((p = fgets(line, BUFSIZ, protof)) == NULL)
return (NULL);
register char **cp;
setprotoent(_proto_stayopen);
- while (p = getprotoent()) {
+ while ((p = getprotoent())) {
if (strcmp(p->p_name, name) == 0)
break;
for (cp = p->p_aliases; *cp != 0; cp++)
register char **cp;
setservent(_serv_stayopen);
- while (p = getservent()) {
+ while ((p = getservent())) {
if (strcmp(name, p->s_name) == 0)
goto gotname;
for (cp = p->s_aliases; *cp; cp++)
register struct servent *p;
setservent(_serv_stayopen);
- while (p = getservent()) {
+ while ((p = getservent())) {
if (p->s_port != port)
continue;
if (proto == 0 || strcmp(p->s_proto, proto) == 0)
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)getservent.3 8.3 (Berkeley) 1/12/94
+.\" $FreeBSD: src/lib/libc/net/getservent.3,v 1.7.2.4 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd July 9, 1995
+.Dt GETSERVENT 3
+.Os
+.Sh NAME
+.Nm getservent ,
+.Nm getservbyport ,
+.Nm getservbyname ,
+.Nm setservent ,
+.Nm endservent
+.Nd get service entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <netdb.h>
+.Ft struct servent *
+.Fn getservent
+.Ft struct servent *
+.Fn getservbyname "const char *name" "const char *proto"
+.Ft struct servent *
+.Fn getservbyport "int port" "const char *proto"
+.Ft void
+.Fn setservent "int stayopen"
+.Ft void
+.Fn endservent void
+.Sh DESCRIPTION
+The
+.Fn getservent ,
+.Fn getservbyname ,
+and
+.Fn getservbyport
+functions
+each return a pointer to an object with the
+following structure
+containing the broken-out
+fields of a line in the network services data base,
+.Pa /etc/services .
+.Bd -literal -offset indent
+struct servent {
+ char *s_name; /* official name of service */
+ char **s_aliases; /* alias list */
+ int s_port; /* port service resides at */
+ char *s_proto; /* protocol to use */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width s_aliases
+.It Fa s_name
+The official name of the service.
+.It Fa s_aliases
+A zero terminated list of alternate names for the service.
+.It Fa s_port
+The port number at which the service resides.
+Port numbers are returned in network byte order.
+.It Fa s_proto
+The name of the protocol to use when contacting the
+service.
+.El
+.Pp
+The
+.Fn getservent
+function
+reads the next line of the file, opening the file if necessary.
+.Pp
+The
+.Fn setservent
+function
+opens and rewinds the file. If the
+.Fa stayopen
+flag is non-zero,
+the net data base will not be closed after each call to
+.Fn getservbyname
+or
+.Fn getservbyport .
+.Pp
+The
+.Fn endservent
+function
+closes the file.
+.Pp
+The
+.Fn getservbyname
+and
+.Fn getservbyport
+functions
+sequentially search from the beginning
+of the file until a matching
+protocol name or
+port number (which must be specified in
+network byte order) is found,
+or until
+.Dv EOF
+is encountered.
+If a protocol name is also supplied (non-
+.Dv NULL ) ,
+searches must also match the protocol.
+.Sh FILES
+.Bl -tag -width /etc/services -compact
+.It Pa /etc/services
+.El
+.Sh DIAGNOSTICS
+Null pointer
+(0) returned on
+.Dv EOF
+or error.
+.Sh SEE ALSO
+.Xr getprotoent 3 ,
+.Xr services 5
+.Sh HISTORY
+The
+.Fn getservent ,
+.Fn getservbyport ,
+.Fn getservbyname ,
+.Fn setservent ,
+and
+.Fn endservent
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+These functions use static data storage;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
+Expecting port numbers to fit in a 32 bit
+quantity is probably naive.
#define MAXALIASES 35
static FILE *servf = NULL;
-static char line[BUFSIZ+1];
static struct servent serv;
static char *serv_aliases[MAXALIASES];
int _serv_stayopen;
getservent()
{
char *p;
+ static char *line = NULL;
register char *cp, **q;
if (servf == NULL && (servf = fopen(_PATH_SERVICES, "r" )) == NULL)
return (NULL);
+
+ if (line == NULL) {
+ line = malloc(BUFSIZ+1);
+ if (line == NULL)
+ return (NULL);
+ }
again:
if ((p = fgets(line, BUFSIZ, servf)) == NULL)
return (NULL);
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)rcmd.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/lib/libc/net/if_indextoname.3,v 1.2.2.4 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd May 21, 1998
+.Dt IF_NAMETOINDEX 3
+.Os
+.Sh NAME
+.Nm if_nametoindex ,
+.Nm if_indextoname ,
+.Nm if_nameindex ,
+.Nm if_freenameindex
+.Nd convert interface index to name, and vice versa
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <net/if.h>
+.Ft "unsigned int"
+.Fn if_nametoindex "const char *ifname"
+.Ft "char *"
+.Fn if_indextoname "unsigned int ifindex" "char *ifname"
+.Ft "struct if_nameindex *"
+.Fn if_nameindex "void"
+.Ft "void"
+.Fn if_freenameindex "struct if_nameindex *ptr"
+.Sh DESCRIPTION
+The functions map interface index to readable interface name
+(such as
+.Dq Li lo0 ) ,
+and vice versa.
+.Pp
+.Fn if_nametoindex
+converts readable interface name to interface index
+.Pp positive integer value .
+If the specified interface does not exist, 0 will be returned.
+.Pp
+.Fn if_indextoname
+converts interface index to readable interface name.
+The
+.Fa ifname
+argument must point to a buffer of at least
+.Dv IF_NAMESIZE
+bytes into which the interface name corresponding to the specified index is
+returned.
+.Dv ( IF_NAMESIZE
+is also defined in
+.Aq Pa net/if.h
+and its value includes a terminating null byte at the end of the
+interface name.)
+This pointer is also the return value of the function.
+If there is no interface corresponding to the specified index,
+.Dv NULL
+is returned.
+.Pp
+.Fn if_nameindex
+returns an array of
+.Fa if_nameindex
+structures.
+.Fa if_nametoindex
+is also defined in
+.Aq Pa net/if.h ,
+and is as follows:
+.Bd -literal -offset
+struct if_nameindex {
+ unsigned int if_index; /* 1, 2, ... */
+ char *if_name; /* null terminated name: "le0", ... */
+};
+.Ed
+.Pp
+The end of the array of structures is indicated by a structure with
+an
+.Fa if_index
+of 0 and an
+.Fa if_name
+of
+.Dv NULL .
+The function returns a
+.Dv NULL
+pointer upon an error.
+The memory used for this array of structures along with the interface
+names pointed to by the
+.Fa if_name
+members is obtained dynamically.
+This memory is freed by the
+.Fn if_freenameindex
+function.
+.Pp
+.Fn if_freenameindex
+takes a pointer that was returned by
+.Fn if_nameindex
+as argument
+.Pq Fa ptr ,
+and it reclaims the region allocated.
+.Sh DIAGNOSTICS
+.Fn if_nametoindex
+returns 0 on error, positive integer on success.
+.Fn if_indextoname
+and
+.Fn if_nameindex
+return
+.Dv NULL
+on errors.
+.Sh SEE ALSO
+R. Gilligan, S. Thomson, J. Bound, and W. Stevens,
+``Basic Socket Interface Extensions for IPv6,'' RFC2553, March 1999.
+.Sh HISTORY
+The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.Sh STANDARDS
+These functions are defined in ``Basic Socket Interface Extensions for IPv6''
+(RFC2533).
--- /dev/null
+/* $KAME: if_indextoname.c,v 1.7 2000/11/08 03:09:30 itojun Exp $ */
+
+/*-
+ * Copyright (c) 1997, 2000
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI Id: if_indextoname.c,v 2.3 2000/04/17 22:38:05 dab Exp
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_dl.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * From RFC 2533:
+ *
+ * The second function maps an interface index into its corresponding
+ * name.
+ *
+ * #include <net/if.h>
+ *
+ * char *if_indextoname(unsigned int ifindex, char *ifname);
+ *
+ * The ifname argument must point to a buffer of at least IF_NAMESIZE
+ * bytes into which the interface name corresponding to the specified
+ * index is returned. (IF_NAMESIZE is also defined in <net/if.h> and
+ * its value includes a terminating null byte at the end of the
+ * interface name.) This pointer is also the return value of the
+ * function. If there is no interface corresponding to the specified
+ * index, NULL is returned, and errno is set to ENXIO, if there was a
+ * system error (such as running out of memory), if_indextoname returns
+ * NULL and errno would be set to the proper value (e.g., ENOMEM).
+ */
+
+char *
+if_indextoname(unsigned int ifindex, char *ifname)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ int error = 0;
+
+ if (getifaddrs(&ifaddrs) < 0)
+ return(NULL); /* getifaddrs properly set errno */
+
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK &&
+ ifindex == ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index)
+ break;
+ }
+
+ if (ifa == NULL) {
+ error = ENXIO;
+ ifname = NULL;
+ }
+ else
+ strncpy(ifname, ifa->ifa_name, IFNAMSIZ);
+
+ freeifaddrs(ifaddrs);
+
+ errno = error;
+ return(ifname);
+}
--- /dev/null
+/* $KAME: if_nameindex.c,v 1.8 2000/11/24 08:20:01 itojun Exp $ */
+
+/*-
+ * Copyright (c) 1997, 2000
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_dl.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * From RFC 2553:
+ *
+ * 4.3 Return All Interface Names and Indexes
+ *
+ * The if_nameindex structure holds the information about a single
+ * interface and is defined as a result of including the <net/if.h>
+ * header.
+ *
+ * struct if_nameindex {
+ * unsigned int if_index;
+ * char *if_name;
+ * };
+ *
+ * The final function returns an array of if_nameindex structures, one
+ * structure per interface.
+ *
+ * struct if_nameindex *if_nameindex(void);
+ *
+ * The end of the array of structures is indicated by a structure with
+ * an if_index of 0 and an if_name of NULL. The function returns a NULL
+ * pointer upon an error, and would set errno to the appropriate value.
+ *
+ * The memory used for this array of structures along with the interface
+ * names pointed to by the if_name members is obtained dynamically.
+ * This memory is freed by the next function.
+ *
+ * 4.4. Free Memory
+ *
+ * The following function frees the dynamic memory that was allocated by
+ * if_nameindex().
+ *
+ * #include <net/if.h>
+ *
+ * void if_freenameindex(struct if_nameindex *ptr);
+ *
+ * The argument to this function must be a pointer that was returned by
+ * if_nameindex().
+ */
+
+struct if_nameindex *
+if_nameindex(void)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ unsigned int ni;
+ int nbytes;
+ struct if_nameindex *ifni, *ifni2;
+ char *cp;
+
+ if (getifaddrs(&ifaddrs) < 0)
+ return(NULL);
+
+ /*
+ * First, find out how many interfaces there are, and how
+ * much space we need for the string names.
+ */
+ ni = 0;
+ nbytes = 0;
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK) {
+ nbytes += strlen(ifa->ifa_name) + 1;
+ ni++;
+ }
+ }
+
+ /*
+ * Next, allocate a chunk of memory, use the first part
+ * for the array of structures, and the last part for
+ * the strings.
+ */
+ cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes);
+ ifni = (struct if_nameindex *)cp;
+ if (ifni == NULL)
+ goto out;
+ cp += (ni + 1) * sizeof(struct if_nameindex);
+
+ /*
+ * Now just loop through the list of interfaces again,
+ * filling in the if_nameindex array and making copies
+ * of all the strings.
+ */
+ ifni2 = ifni;
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK) {
+ ifni2->if_index =
+ ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index;
+ ifni2->if_name = cp;
+ strcpy(cp, ifa->ifa_name);
+ ifni2++;
+ cp += strlen(cp) + 1;
+ }
+ }
+ /*
+ * Finally, don't forget to terminate the array.
+ */
+ ifni2->if_index = 0;
+ ifni2->if_name = NULL;
+out:
+ freeifaddrs(ifaddrs);
+ return(ifni);
+}
+
+#ifndef __OpenBSD__
+void
+if_freenameindex(struct if_nameindex *ptr)
+{
+ free(ptr);
+}
+#endif
--- /dev/null
+/* $KAME: if_nametoindex.c,v 1.6 2000/11/24 08:18:54 itojun Exp $ */
+
+/*-
+ * Copyright (c) 1997, 2000
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI Id: if_nametoindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * From RFC 2553:
+ *
+ * 4.1 Name-to-Index
+ *
+ *
+ * The first function maps an interface name into its corresponding
+ * index.
+ *
+ * #include <net/if.h>
+ *
+ * unsigned int if_nametoindex(const char *ifname);
+ *
+ * If the specified interface name does not exist, the return value is
+ * 0, and errno is set to ENXIO. If there was a system error (such as
+ * running out of memory), the return value is 0 and errno is set to the
+ * proper value (e.g., ENOMEM).
+ */
+
+unsigned int
+if_nametoindex(const char *ifname)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ unsigned int ni;
+
+ if (getifaddrs(&ifaddrs) < 0)
+ return(0);
+
+ ni = 0;
+
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK &&
+ strcmp(ifa->ifa_name, ifname) == 0) {
+ ni = ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index;
+ break;
+ }
+ }
+
+ freeifaddrs(ifaddrs);
+ if (!ni)
+ errno = ENXIO;
+ return(ni);
+}
--- /dev/null
+/* $KAME: ifaddrs.h,v 1.3 2001/01/26 08:14:55 itojun Exp $ */
+
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef _IFADDRS_H_
+#define _IFADDRS_H_
+
+struct ifaddrs {
+ struct ifaddrs *ifa_next;
+ char *ifa_name;
+ u_int ifa_flags;
+ struct sockaddr *ifa_addr;
+ struct sockaddr *ifa_netmask;
+ struct sockaddr *ifa_dstaddr;
+ void *ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int getifaddrs __P((struct ifaddrs **));
+extern void freeifaddrs __P((struct ifaddrs *));
+__END_DECLS
+
+#endif
--- /dev/null
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: inet6_option_space.3,v 1.2 2002/03/19 17:20:07 majka Exp $
+.\" $FreeBSD: src/lib/libc/net/inet6_option_space.3,v 1.1.2.5 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd December 10, 1999
+.Dt INET6_OPTION_SPACE 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_option_space ,
+.Nm inet6_option_init ,
+.Nm inet6_option_append ,
+.Nm inet6_option_alloc ,
+.Nm inet6_option_next ,
+.Nm inet6_option_find
+.Nd IPv6 Hop-by-Hop and Destination Options manipulation
+.\"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <netinet/in.h>
+.Ft "int"
+.Fn inet6_option_space "int nbytes"
+.Ft "int"
+.Fn inet6_option_init "void *bp" "struct cmsghdr **cmsgp" "int type"
+.Ft "int"
+.Fn inet6_option_append "struct cmsghdr *cmsg" "const u_int8_t *typep" "int multx" "int plusy"
+.Ft "u_int8_t *"
+.Fn inet6_option_alloc "struct cmsghdr *cmsg" "int datalen" "int multx" "int plusy"
+.Ft "int"
+.Fn inet6_option_next "const struct cmsghdr *cmsg" "u_int8_t **tptrp"
+.Ft "int"
+.Fn inet6_option_find "const struct cmsghdr *cmsg" "u_int8_t **tptrp" "int type"
+.\"
+.Sh DESCRIPTION
+.\"
+Building and parsing the Hop-by-Hop and Destination options is
+complicated due to alignment constranints, padding and
+ancillary data manipulation.
+RFC2292 defines a set of functions to help the application.
+The function prototypes for
+these functions are all in the
+.Aq Li netinet/in.h
+header.
+.\"
+.Ss inet6_option_space
+.Fn inet6_option_space
+returns the number of bytes required to hold an option when it is stored as
+ancillary data, including the
+.Li cmsghdr
+structure at the beginning,
+and any padding at the end
+(to make its size a multiple of 8 bytes).
+The argument is the size of the structure defining the option,
+which must include any pad bytes at the beginning
+(the value
+.Li y
+in the alignment term
+.Dq Li "xn + y" ) ,
+the type byte, the length byte, and the option data.
+.Pp
+Note: If multiple options are stored in a single ancillary data
+object, which is the recommended technique, this function
+overestimates the amount of space required by the size of
+.Li N-1
+.Li cmsghdr
+structures,
+where
+.Li N
+is the number of options to be stored in the object.
+This is of little consequence, since it is assumed that most
+Hop-by-Hop option headers and Destination option headers carry only
+one option
+(appendix B of [RFC-2460]).
+.\"
+.Ss inet6_option_init
+.Fn inet6_option_init
+is called once per ancillary data object that will
+contain either Hop-by-Hop or Destination options.
+It returns
+.Li 0
+on success or
+.Li -1
+on an error.
+.Pp
+.Fa bp
+is a pointer to previously allocated space that will contain the
+ancillary data object.
+It must be large enough to contain all the
+individual options to be added by later calls to
+.Fn inet6_option_append
+and
+.Fn inet6_option_alloc .
+.Pp
+.Fa cmsgp
+is a pointer to a pointer to a
+.Li cmsghdr
+structure.
+.Fa *cmsgp
+is initialized by this function to point to the
+.Li cmsghdr
+structure constructed by this function in the buffer pointed to by
+.Fa bp .
+.Pp
+.Fa type
+is either
+.Dv IPV6_HOPOPTS
+or
+.Dv IPV6_DSTOPTS .
+This
+.Fa type
+is stored in the
+.Li cmsg_type
+member of the
+.Li cmsghdr
+structure pointed to by
+.Fa *cmsgp .
+.\"
+.Ss inet6_option_append
+This function appends a Hop-by-Hop option or a Destination option
+into an ancillary data object that has been initialized by
+.Fn inet6_option_init .
+This function returns
+.Li 0
+if it succeeds or
+.Li -1
+on an error.
+.Pp
+.Fa cmsg
+is a pointer to the
+.Li cmsghdr
+structure that must have been
+initialized by
+.Fn inet6_option_init .
+.Pp
+.Fa typep
+is a pointer to the 8-bit option type.
+It is assumed that this
+field is immediately followed by the 8-bit option data length field,
+which is then followed immediately by the option data.
+The caller
+initializes these three fields
+(the type-length-value, or TLV)
+before calling this function.
+.Pp
+The option type must have a value from
+.Li 2
+to
+.Li 255 ,
+inclusive.
+.Li ( 0
+and
+.Li 1
+are reserved for the
+.Li Pad1
+and
+.Li PadN
+options, respectively.)
+.Pp
+The option data length must have a value between
+.Li 0
+and
+.Li 255 ,
+inclusive, and is the length of the option data that follows.
+.Pp
+.Fa multx
+is the value
+.Li x
+in the alignment term
+.Dq Li xn + y .
+It must have a value of
+.Li 1 ,
+.Li 2 ,
+.Li 4 ,
+or
+.Li 8 .
+.Pp
+.Fa plusy
+is the value
+.Li y
+in the alignment term
+.Dq Li xn + y .
+It must have a value between
+.Li 0
+and
+.Li 7 ,
+inclusive.
+.\"
+.Ss inet6_option_alloc
+This function appends a Hop-by-Hop option or a Destination option
+into an ancillary data object that has been initialized by
+.Fn inet6_option_init .
+This function returns a pointer to the 8-bit
+option type field that starts the option on success, or
+.Dv NULL
+on an error.
+.Pp
+The difference between this function and
+.Fn inet6_option_append
+is that the latter copies the contents of a previously built option into
+the ancillary data object while the current function returns a
+pointer to the space in the data object where the option's TLV must
+then be built by the caller.
+.Pp
+.Fa cmsg
+is a pointer to the
+.Li cmsghdr
+structure that must have been
+initialized by
+.Fn inet6_option_init .
+.Pp
+.Fa datalen
+is the value of the option data length byte for this option.
+This value is required as an argument to allow the function to
+determine if padding must be appended at the end of the option.
+(The
+.Fn inet6_option_append
+function does not need a data length argument
+since the option data length must already be stored by the caller.)
+.Pp
+.Fa multx
+is the value
+.Li x
+in the alignment term
+.Dq Li xn + y .
+It must have a value of
+.Li 1 ,
+.Li 2 ,
+.Li 4 ,
+or
+.Li 8 .
+.Pp
+.Fa plusy
+is the value
+.Li y
+in the alignment term
+.Dq Li xn + y .
+It must have a value between
+.Li 0
+and
+.Li 7 ,
+inclusive.
+.\"
+.Ss inet6_option_next
+This function processes the next Hop-by-Hop option or Destination
+option in an ancillary data object.
+If another option remains to be
+processed, the return value of the function is
+.Li 0
+and
+.Fa *tptrp
+points to
+the 8-bit option type field
+(which is followed by the 8-bit option
+data length, followed by the option data).
+If no more options remain
+to be processed, the return value is
+.Li -1
+and
+.Fa *tptrp
+is
+.Dv NULL .
+If an error occurs, the return value is
+.Li -1
+and
+.Fa *tptrp
+is not
+.Dv NULL .
+.Pp
+.Fa cmsg
+is a pointer to
+.Li cmsghdr
+structure of which
+.Li cmsg_level
+equals
+.Dv IPPROTO_IPV6
+and
+.Li cmsg_type
+equals either
+.Dv IPV6_HOPOPTS
+or
+.Dv IPV6_DSTOPTS .
+.Pp
+.Fa tptrp
+is a pointer to a pointer to an 8-bit byte and
+.Fa *tptrp
+is used
+by the function to remember its place in the ancillary data object
+each time the function is called.
+The first time this function is
+called for a given ancillary data object,
+.Fa *tptrp
+must be set to
+.Dv NULL .
+.Pp
+Each time this function returns success,
+.Fa *tptrp
+points to the 8-bit
+option type field for the next option to be processed.
+.\"
+.Ss inet6_option_find
+This function is similar to the previously described
+.Fn inet6_option_next
+function, except this function lets the caller
+specify the option type to be searched for, instead of always
+returning the next option in the ancillary data object.
+.Fa cmsg
+is a
+pointer to
+.Li cmsghdr
+structure of which
+.Li cmsg_level
+equals
+.Dv IPPROTO_IPV6
+and
+.Li cmsg_type
+equals either
+.Dv IPV6_HOPOPTS
+or
+.Dv IPV6_DSTOPTS .
+.Pp
+.Fa tptrp
+is a pointer to a pointer to an 8-bit byte and
+.Fa *tptrp
+is used
+by the function to remember its place in the ancillary data object
+each time the function is called.
+The first time this function is
+called for a given ancillary data object,
+.Fa *tptrp
+must be set to
+.Dv NULL .
+.Pa
+This function starts searching for an option of the specified type
+beginning after the value of
+.Fa *tptrp .
+If an option of the specified
+type is located, this function returns
+.Li 0
+and
+.Fa *tptrp
+points to the 8-
+bit option type field for the option of the specified type.
+If an
+option of the specified type is not located, the return value is
+.Li -1
+and
+.Fa *tptrp
+is
+.Dv NULL .
+If an error occurs, the return value is
+.Li -1
+and
+.Fa *tptrp
+is not
+.Dv NULL .
+.\"
+.Sh DIAGNOSTICS
+.Fn inet6_option_init
+and
+.Fn inet6_option_append
+return
+.Li 0
+on success or
+.Li -1
+on an error.
+.Pp
+.Fn inet6_option_alloc
+returns
+.Dv NULL
+on an error.
+.Pp
+On errors,
+.Fn inet6_option_next
+and
+.Fn inet6_option_find
+return
+.Li -1
+setting
+.Fa *tptrp
+to non
+.Dv NULL
+value.
+.\"
+.Sh EXAMPLES
+RFC2292 gives comprehensive examples in chapter 6.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%T "Advanced Sockets API for IPv6"
+.%N RFC2292
+.%D February 1998
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.\"
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
+.\"
+.Sh STANDARDS
+The functions
+are documented in
+.Dq Advanced Sockets API for IPv6
+(RFC2292).
+.\"
+.Sh BUGS
+The text was shamelessly copied from RFC2292.
--- /dev/null
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: inet6_rthdr_space.3,v 1.2 2002/03/19 17:20:07 majka Exp $
+.\" $FreeBSD: src/lib/libc/net/inet6_rthdr_space.3,v 1.1.2.5 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd December 10, 1999
+.Dt INET6_RTHDR_SPACE 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_rthdr_space ,
+.Nm inet6_rthdr_init ,
+.Nm inet6_rthdr_add ,
+.Nm inet6_rthdr_lasthop ,
+.Nm inet6_rthdr_reverse ,
+.Nm inet6_rthdr_segments ,
+.Nm inet6_rthdr_getaddr ,
+.Nm inet6_rthdr_getflags
+.Nd IPv6 Routing Header Options manipulation
+.\"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <netinet/in.h>
+.Ft size_t
+.Fn inet6_rthdr_space "int type" "int segments"
+.Ft "struct cmsghdr *"
+.Fn inet6_rthdr_init "void *bp" "int type"
+.Ft int
+.Fn inet6_rthdr_add "struct cmsghdr *cmsg" "const struct in6_addr *addr" "unsigned int flags"
+.Ft int
+.Fn inet6_rthdr_lasthop "struct cmsghdr *cmsg" "unsigned int flags"
+.Ft int
+.Fn inet6_rthdr_reverse "const struct cmsghdr *in" "struct cmsghdr *out"
+.Ft int
+.Fn inet6_rthdr_segments "const struct cmsghdr *cmsg"
+.Ft "struct in6_addr *"
+.Fn inet6_rthdr_getaddr "struct cmsghdr *cmsg" "int index"
+.Ft int
+.Fn inet6_rthdr_getflags "const struct cmsghdr *cmsg" "int index"
+.\"
+.Sh DESCRIPTION
+RFC2292 IPv6 advanced API defines eight
+functions that the application calls to build and examine a Routing
+header. Four functions build a Routing header:
+.Bl -hang
+.It Fn inet6_rthdr_space
+return #bytes required for ancillary data
+.It Fn inet6_rthdr_init
+initialize ancillary data for Routing header
+.It Fn inet6_rthdr_add
+add IPv6 address & flags to Routing header
+.It Fn inet6_rthdr_lasthop
+specify the flags for the final hop
+.El
+.Pp
+Four functions deal with a returned Routing header:
+.Bl -hang
+.It Fn inet6_rthdr_reverse
+reverse a Routing header
+.It Fn inet6_rthdr_segments
+return #segments in a Routing header
+.It Fn inet6_rthdr_getaddr
+fetch one address from a Routing header
+.It Fn inet6_rthdr_getflags
+fetch one flag from a Routing header
+.El
+.Pp
+The function prototypes for these functions are all in the
+.Aq Li netinet/in.h
+header.
+.\"
+.Ss inet6_rthdr_space
+This function returns the number of bytes required to hold a Routing
+header of the specified
+.Fa type
+containing the specified number of
+.Fa segments
+(addresses).
+For an IPv6 Type 0 Routing header, the number
+of segments must be between 1 and 23, inclusive. The return value
+includes the size of the cmsghdr structure that precedes the Routing
+header, and any required padding.
+.Pp
+If the return value is 0, then either the type of the Routing header
+is not supported by this implementation or the number of segments is
+invalid for this type of Routing header.
+.Pp
+Note: This function returns the size but does not allocate the space
+required for the ancillary data.
+This allows an application to
+allocate a larger buffer, if other ancillary data objects are
+desired, since all the ancillary data objects must be specified to
+.Xr sendmsg 2
+as a single
+.Li msg_control
+buffer.
+.\"
+.Ss inet6_rthdr_init
+This function initializes the buffer pointed to by
+.Fa bp
+to contain a
+.Li cmsghdr
+structure followed by a Routing header of the specified
+.Fa type .
+The
+.Li cmsg_len
+member of the
+.Li cmsghdr
+structure is initialized to the
+size of the structure plus the amount of space required by the
+Routing header.
+The
+.Li cmsg_level
+and
+.Li cmsg_type
+members are also initialized as required.
+.Pp
+The caller must allocate the buffer and its size can be determined by
+calling
+.Fn inet6_rthdr_space .
+.Pp
+Upon success the return value is the pointer to the
+.Li cmsghdr
+structure, and this is then used as the first argument to the next
+two functions.
+Upon an error the return value is
+.Dv NULL .
+.\"
+.Ss inet6_rthdr_add
+This function adds the address pointed to by
+.Fa addr
+to the end of the
+Routing header being constructed and sets the type of this hop to the
+value of
+.Fa flags .
+For an IPv6 Type 0 Routing header,
+.Fa flags
+must be
+either
+.Dv IPV6_RTHDR_LOOSE
+or
+.Dv IPV6_RTHDR_STRICT .
+.Pp
+If successful, the
+.Li cmsg_len
+member of the
+.Li cmsghdr
+structure is
+updated to account for the new address in the Routing header and the
+return value of the function is 0.
+Upon an error the return value of
+the function is -1.
+.\"
+.Ss inet6_rthdr_lasthop
+This function specifies the Strict/Loose flag for the final hop of a
+Routing header.
+For an IPv6 Type 0 Routing header,
+.Fa flags
+must be either
+.Dv IPV6_RTHDR_LOOSE
+or
+.Dv IPV6_RTHDR_STRICT .
+.Pp
+The return value of the function is 0 upon success, or -1 upon an error.
+.Pp
+Notice that a Routing header specifying
+.Li N
+intermediate nodes requires
+.Li N+1
+Strict/Loose flags.
+This requires
+.Li N
+calls to
+.Fn inet6_rthdr_add
+followed by one call to
+.Fn inet6_rthdr_lasthop .
+.\"
+.Ss inet6_rthdr_reverse
+This function is not yet implemented.
+When implemented, this should behave as follows.
+.Pp
+This function takes a Routing header that was received as ancillary
+data
+(pointed to by the first argument,
+.Fa in )
+and writes a new Routing
+header that sends datagrams along the reverse of that route.
+Both
+arguments are allowed to point to the same buffer
+(that is, the reversal can occur in place).
+.Pp
+The return value of the function is 0 on success, or -1 upon an
+error.
+.\"
+.Ss inet6_rthdr_segments
+This function returns the number of segments
+(addresses)
+contained in
+the Routing header described by
+.Fa cmsg .
+On success the return value is
+between 1 and 23, inclusive.
+The return value of the function is -1 upon an error.
+.\"
+.Ss inet6_rthdr_getaddr
+This function returns a pointer to the IPv6 address specified by
+.Fa index
+(which must have a value between 1 and the value returned by
+.Fn inet6_rthdr_segments )
+in the Routing header described by
+.Fa cmsg .
+An
+application should first call
+.Fn inet6_rthdr_segments
+to obtain the number of segments in the Routing header.
+.Pp
+Upon an error the return value of the function is
+.Dv NULL .
+.\"
+.Ss inet6_rthdr_getflags
+This function returns the flags value specified by
+.Fa index
+(which must
+have a value between 0 and the value returned by
+.Fn inet6_rthdr_segments )
+in the Routing header described by
+.Fa cmsg .
+For an IPv6 Type 0 Routing header the return value will be either
+.Dv IPV6_RTHDR_LOOSE
+or
+.Dv IPV6_RTHDR_STRICT .
+.Pp
+Upon an error the return value of the function is -1.
+.Pp
+Note: Addresses are indexed starting at 1, and flags starting at 0,
+to maintain consistency with the terminology and figures in RFC2460.
+.\"
+.Sh DIAGNOSTICS
+.Fn inet6_rthdr_space
+returns 0 on errors.
+.Pp
+.Fn inet6_rthdr_add ,
+.Fn inet6_rthdr_lasthop
+and
+.Fn inet6_rthdr_reverse
+return 0 on success, and returns -1 on error.
+.Pp
+.Fn inet6_rthdr_init
+and
+.Fn inet6_rthdr_getaddr
+return
+.Dv NULL
+on error.
+.Pp
+.Fn inet6_rthdr_segments
+and
+.Fn inet6_rthdr_getflags
+return -1 on error.
+.\"
+.Sh EXAMPLES
+RFC2292 gives comprehensive examples in chapter 8.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%T "Advanced Sockets API for IPv6"
+.%N RFC2292
+.%D February 1998
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.\"
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
+.\"
+.Sh STANDARDS
+The functions
+are documented in
+.Dq Advanced Sockets API for IPv6
+(RFC2292).
+.\"
+.Sh BUGS
+The text was shamelessly copied from RFC2292.
+.Pp
+.Fn inet6_rthdr_reverse
+is not implemented yet.
--- /dev/null
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+
+void __res_close()
+{
+}
+
+const char *inet_ntop6(const struct in6_addr *addr,char *buf,size_t len)
+{
+ const u_int16_t *ap=addr->__u6_addr.__u6_addr16;
+ int colon=2;
+ int i;
+ char *bp=buf;
+
+ for(i=0;i<8;i++,ap++)
+ {
+ if(bp>=buf+len-1)
+ {
+ buf[len-1]=0;
+ return buf;
+ }
+ if(*ap || colon==-1)
+ {
+ if(colon==2)
+ colon=0;
+ if(colon)
+ colon=-1;
+ sprintf(bp,"%x",*ap);
+ bp+=strlen(bp);
+ if(i!=7)
+ *bp++=':';
+ }
+ else
+ {
+ if(colon==2)
+ {
+ *bp++=':';
+ *bp++=':';
+ }
+ else if(!colon && i!=7)
+ *bp++=':';
+ colon=1;
+ }
+ }
+ *bp=0;
+ return buf;
+}
+
+const char *inet_ntop4(const struct in_addr *addr,char *buf,size_t len)
+{
+ const u_int8_t *ap=(u_int8_t*)&addr->s_addr;
+ int i;
+ char *bp=buf;
+
+ for(i=0;i<4;i++,ap++)
+ {
+ if(bp>=buf+len-1)
+ {
+ buf[len-1]=0;
+ return buf;
+ }
+ sprintf(bp,"%d",*ap);
+ bp+=strlen(bp);
+ if(i!=3)
+ *bp++='.';
+ }
+ *bp=0;
+ return buf;
+}
+
+const char *inet_ntop(int af,const void *addr,char *buf,size_t len)
+{
+ if(af==AF_INET6)
+ return inet_ntop6(addr,buf,len);
+ if(af==AF_INET)
+ return inet_ntop4(addr,buf,len);
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id: inet_pton.c,v 1.2 2002/01/17 22:22:25 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <string.h>
+#include <errno.h>
+
+#define IN6ADDRSZ 16
+
+#if 0
+#ifndef HAVE_PORTABLE_PROTOTYPE
+#include "cdecl_ext.h"
+#endif
+
+#ifndef HAVE_U_INT16_T
+#include "bittypes.h"
+#endif
+#if !(defined(HAVE_INADDRSZ) && defined(HAVE_IN6ADDRSZ))
+#include "addrsize.h"
+#endif
+#endif
+#ifndef NS_INADDRSZ
+#define NS_INADDRSZ INADDRSZ
+#endif
+#ifndef NS_IN6ADDRSZ
+#define NS_IN6ADDRSZ IN6ADDRSZ
+#endif
+#ifndef NS_INT16SZ
+#define NS_INT16SZ sizeof(u_int16_t)
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4 __P((const char *src, u_char *dst));
+#ifdef INET6
+static int inet_pton6 __P((const char *src, u_char *dst));
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+inet_pton(af, src, dst)
+ int af;
+ const char *src;
+ void *dst;
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+#ifdef INET6
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ u_char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ u_int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+#ifdef INET6
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return (0);
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+#endif /*INET6*/
#include <sys/param.h>
#include <stdio.h>
+#include <unistd.h>
+#include <err.h>
int
initgroups(uname, agroup)
--- /dev/null
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/net/ip6opt.c,v 1.1 1999/12/16 18:32:01 shin Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <string.h>
+#include <stdio.h>
+
+static int ip6optlen(u_int8_t *opt, u_int8_t *lim);
+static void inet6_insert_padopt(u_char *p, int len);
+
+/*
+ * This function returns the number of bytes required to hold an option
+ * when it is stored as ancillary data, including the cmsghdr structure
+ * at the beginning, and any padding at the end (to make its size a
+ * multiple of 8 bytes). The argument is the size of the structure
+ * defining the option, which must include any pad bytes at the
+ * beginning (the value y in the alignment term "xn + y"), the type
+ * byte, the length byte, and the option data.
+ */
+int
+inet6_option_space(nbytes)
+ int nbytes;
+{
+ nbytes += 2; /* we need space for nxt-hdr and length fields */
+ return(CMSG_SPACE((nbytes + 7) & ~7));
+}
+
+/*
+ * This function is called once per ancillary data object that will
+ * contain either Hop-by-Hop or Destination options. It returns 0 on
+ * success or -1 on an error.
+ */
+int
+inet6_option_init(bp, cmsgp, type)
+ void *bp;
+ struct cmsghdr **cmsgp;
+ int type;
+{
+ register struct cmsghdr *ch = (struct cmsghdr *)bp;
+
+ /* argument validation */
+ if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS)
+ return(-1);
+
+ ch->cmsg_level = IPPROTO_IPV6;
+ ch->cmsg_type = type;
+ ch->cmsg_len = CMSG_LEN(0);
+
+ *cmsgp = ch;
+ return(0);
+}
+
+/*
+ * This function appends a Hop-by-Hop option or a Destination option
+ * into an ancillary data object that has been initialized by
+ * inet6_option_init(). This function returns 0 if it succeeds or -1 on
+ * an error.
+ * multx is the value x in the alignment term "xn + y" described
+ * earlier. It must have a value of 1, 2, 4, or 8.
+ * plusy is the value y in the alignment term "xn + y" described
+ * earlier. It must have a value between 0 and 7, inclusive.
+ */
+int
+inet6_option_append(cmsg, typep, multx, plusy)
+ struct cmsghdr *cmsg;
+ const u_int8_t *typep;
+ int multx;
+ int plusy;
+{
+ int padlen, optlen, off;
+ register u_char *bp = (u_char *)cmsg + cmsg->cmsg_len;
+ struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
+
+ /* argument validation */
+ if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
+ return(-1);
+ if (plusy < 0 || plusy > 7)
+ return(-1);
+ if (typep[0] > 255)
+ return(-1);
+
+ /*
+ * If this is the first option, allocate space for the
+ * first 2 bytes(for next header and length fields) of
+ * the option header.
+ */
+ if (bp == (u_char *)eh) {
+ bp += 2;
+ cmsg->cmsg_len += 2;
+ }
+
+ /* calculate pad length before the option. */
+ off = bp - (u_char *)eh;
+ padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
+ (off % multx);
+ padlen += plusy;
+ /* insert padding */
+ inet6_insert_padopt(bp, padlen);
+ cmsg->cmsg_len += padlen;
+ bp += padlen;
+
+ /* copy the option */
+ if (typep[0] == IP6OPT_PAD1)
+ optlen = 1;
+ else
+ optlen = typep[1] + 2;
+ memcpy(bp, typep, optlen);
+ bp += optlen;
+ cmsg->cmsg_len += optlen;
+
+ /* calculate pad length after the option and insert the padding */
+ off = bp - (u_char *)eh;
+ padlen = ((off + 7) & ~7) - off;
+ inet6_insert_padopt(bp, padlen);
+ bp += padlen;
+ cmsg->cmsg_len += padlen;
+
+ /* update the length field of the ip6 option header */
+ eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
+
+ return(0);
+}
+
+/*
+ * This function appends a Hop-by-Hop option or a Destination option
+ * into an ancillary data object that has been initialized by
+ * inet6_option_init(). This function returns a pointer to the 8-bit
+ * option type field that starts the option on success, or NULL on an
+ * error.
+ * The difference between this function and inet6_option_append() is
+ * that the latter copies the contents of a previously built option into
+ * the ancillary data object while the current function returns a
+ * pointer to the space in the data object where the option's TLV must
+ * then be built by the caller.
+ *
+ */
+u_int8_t *
+inet6_option_alloc(cmsg, datalen, multx, plusy)
+ struct cmsghdr *cmsg;
+ int datalen;
+ int multx;
+ int plusy;
+{
+ int padlen, off;
+ register u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len;
+ u_int8_t *retval;
+ struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
+
+ /* argument validation */
+ if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
+ return(NULL);
+ if (plusy < 0 || plusy > 7)
+ return(NULL);
+
+ /*
+ * If this is the first option, allocate space for the
+ * first 2 bytes(for next header and length fields) of
+ * the option header.
+ */
+ if (bp == (u_char *)eh) {
+ bp += 2;
+ cmsg->cmsg_len += 2;
+ }
+
+ /* calculate pad length before the option. */
+ off = bp - (u_char *)eh;
+ padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
+ (off % multx);
+ padlen += plusy;
+ /* insert padding */
+ inet6_insert_padopt(bp, padlen);
+ cmsg->cmsg_len += padlen;
+ bp += padlen;
+
+ /* keep space to store specified length of data */
+ retval = bp;
+ bp += datalen;
+ cmsg->cmsg_len += datalen;
+
+ /* calculate pad length after the option and insert the padding */
+ off = bp - (u_char *)eh;
+ padlen = ((off + 7) & ~7) - off;
+ inet6_insert_padopt(bp, padlen);
+ bp += padlen;
+ cmsg->cmsg_len += padlen;
+
+ /* update the length field of the ip6 option header */
+ eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
+
+ return(retval);
+}
+
+/*
+ * This function processes the next Hop-by-Hop option or Destination
+ * option in an ancillary data object. If another option remains to be
+ * processed, the return value of the function is 0 and *tptrp points to
+ * the 8-bit option type field (which is followed by the 8-bit option
+ * data length, followed by the option data). If no more options remain
+ * to be processed, the return value is -1 and *tptrp is NULL. If an
+ * error occurs, the return value is -1 and *tptrp is not NULL.
+ * (RFC 2292, 6.3.5)
+ */
+int
+inet6_option_next(cmsg, tptrp)
+ const struct cmsghdr *cmsg;
+ u_int8_t **tptrp;
+{
+ struct ip6_ext *ip6e;
+ int hdrlen, optlen;
+ u_int8_t *lim;
+
+ if (cmsg->cmsg_level != IPPROTO_IPV6 ||
+ (cmsg->cmsg_type != IPV6_HOPOPTS &&
+ cmsg->cmsg_type != IPV6_DSTOPTS))
+ return(-1);
+
+ /* message length validation */
+ if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
+ return(-1);
+ ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
+ hdrlen = (ip6e->ip6e_len + 1) << 3;
+ if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
+ return(-1);
+
+ /*
+ * If the caller does not specify the starting point,
+ * simply return the 1st option.
+ * Otherwise, search the option list for the next option.
+ */
+ lim = (u_int8_t *)ip6e + hdrlen;
+ if (*tptrp == NULL)
+ *tptrp = (u_int8_t *)(ip6e + 1);
+ else {
+ if ((optlen = ip6optlen(*tptrp, lim)) == 0)
+ return(-1);
+
+ *tptrp = *tptrp + optlen;
+ }
+ if (*tptrp >= lim) { /* there is no option */
+ *tptrp = NULL;
+ return(-1);
+ }
+ /*
+ * Finally, checks if the next option is safely stored in the
+ * cmsg data.
+ */
+ if (ip6optlen(*tptrp, lim) == 0)
+ return(-1);
+ else
+ return(0);
+}
+
+/*
+ * This function is similar to the inet6_option_next() function,
+ * except this function lets the caller specify the option type to be
+ * searched for, instead of always returning the next option in the
+ * ancillary data object.
+ * Note: RFC 2292 says the type of tptrp is u_int8_t *, but we think
+ * it's a typo. The variable should be type of u_int8_t **.
+ */
+int
+inet6_option_find(cmsg, tptrp, type)
+ const struct cmsghdr *cmsg;
+ u_int8_t **tptrp;
+ int type;
+{
+ struct ip6_ext *ip6e;
+ int hdrlen, optlen;
+ u_int8_t *optp, *lim;
+
+ if (cmsg->cmsg_level != IPPROTO_IPV6 ||
+ (cmsg->cmsg_type != IPV6_HOPOPTS &&
+ cmsg->cmsg_type != IPV6_DSTOPTS))
+ return(-1);
+
+ /* message length validation */
+ if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
+ return(-1);
+ ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
+ hdrlen = (ip6e->ip6e_len + 1) << 3;
+ if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
+ return(-1);
+
+ /*
+ * If the caller does not specify the starting point,
+ * search from the beginning of the option list.
+ * Otherwise, search from *the next option* of the specified point.
+ */
+ lim = (u_int8_t *)ip6e + hdrlen;
+ if (*tptrp == NULL)
+ *tptrp = (u_int8_t *)(ip6e + 1);
+ else {
+ if ((optlen = ip6optlen(*tptrp, lim)) == 0)
+ return(-1);
+
+ *tptrp = *tptrp + optlen;
+ }
+ for (optp = *tptrp; optp < lim; optp += optlen) {
+ if (*optp == type) {
+ *tptrp = optp;
+ return(0);
+ }
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ return(-1);
+ }
+
+ /* search failed */
+ *tptrp = NULL;
+ return(-1);
+}
+
+/*
+ * Calculate the length of a given IPv6 option. Also checks
+ * if the option is safely stored in user's buffer according to the
+ * calculated length and the limitation of the buffer.
+ */
+static int
+ip6optlen(opt, lim)
+ u_int8_t *opt, *lim;
+{
+ int optlen;
+
+ if (*opt == IP6OPT_PAD1)
+ optlen = 1;
+ else {
+ /* is there enough space to store type and len? */
+ if (opt + 2 > lim)
+ return(0);
+ optlen = *(opt + 1) + 2;
+ }
+ if (opt + optlen <= lim)
+ return(optlen);
+
+ return(0);
+}
+
+static void
+inet6_insert_padopt(u_char *p, int len)
+{
+ switch(len) {
+ case 0:
+ return;
+ case 1:
+ p[0] = IP6OPT_PAD1;
+ return;
+ default:
+ p[0] = IP6OPT_PADN;
+ p[1] = len - 2;
+ memset(&p[2], 0, len - 2);
+ return;
+ }
+}
--- /dev/null
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley at BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)linkaddr.3 8.1 (Berkeley) 7/28/93
+.\" $FreeBSD: src/lib/libc/net/linkaddr.3,v 1.8.2.3 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd June 17, 1996
+.Dt LINK_ADDR 3
+.Os
+.Sh NAME
+.Nm link_addr ,
+.Nm link_ntoa
+.Nd elementary address specification routines for link level access
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <net/if_dl.h>
+.Ft void
+.Fn link_addr "const char *addr" "struct sockaddr_dl *sdl"
+.Ft char *
+.Fn link_ntoa "const struct sockaddr_dl *sdl"
+.Sh DESCRIPTION
+The routine
+.Fn link_addr
+interprets character strings representing
+link-level addresses, returning binary information suitable
+for use in system calls.
+The routine
+.Fn link_ntoa
+takes
+a link-level
+address and returns an
+.Tn ASCII
+string representing some of the information present,
+including the link level address itself, and the interface name
+or number, if present.
+This facility is experimental and is
+still subject to change.
+.Pp
+For
+.Fn link_addr ,
+the string
+.Fa addr
+may contain
+an optional network interface identifier of the form
+.Dq "name unit-number" ,
+suitable for the first argument to
+.Xr ifconfig 8 ,
+followed in all cases by a colon and
+an interface address in the form of
+groups of hexadecimal digits
+separated by periods.
+Each group represents a byte of address;
+address bytes are filled left to right from
+low order bytes through high order bytes.
+.Pp
+.\" A regular expression may make this format clearer:
+.\" .Bd -literal -offset indent
+.\" ([a-z]+[0-9]+:)?[0-9a-f]+(\e.[0-9a-f]+)*
+.\" .Ed
+.\" .Pp
+Thus
+.Li le0:8.0.9.13.d.30
+represents an ethernet address
+to be transmitted on the first Lance ethernet interface.
+.Pp
+The direct use of these functions is deprecated in favor of the
+.Xr addr2ascii 3
+interface; however, portable programs cannot rely on the latter as it is
+not yet widely implemented.
+.Sh RETURN VALUES
+.Fn link_ntoa
+always returns a null terminated string.
+.Fn link_addr
+has no return value.
+(See
+.Sx BUGS . )
+.Sh SEE ALSO
+.Xr addr2ascii 3
+.\" .Xr iso 4
+.Sh HISTORY
+The
+.Fn link_addr
+and
+.Fn link_ntoa
+functions appeared in
+.Bx 4.3 Reno .
+.Sh BUGS
+The returned values for link_ntoa
+reside in a static memory area.
+.Pp
+The function
+.Fn link_addr
+should diagnose improperly formed input, and there should be an unambiguous
+way to recognize this.
+.Pp
+If the
+.Va sdl_len
+field of the link socket address
+.Fa sdl
+is 0,
+.Fn link_ntoa
+will not insert a colon before the interface address bytes.
+If this translated address is given to
+.Fn link_addr
+without inserting an initial colon,
+the latter will not interpret it correctly.
--- /dev/null
+/*
+ * ++Copyright++ 1985, 1988, 1993
+ * -
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "$FreeBSD: src/lib/libc/net/map_v4v6.c,v 1.5.2.1 2001/03/05 10:47:08 obrien Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <ctype.h>
+#include <syslog.h>
+
+#define IN6ADDRSZ 16
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+void
+_map_v4v6_address(src, dst)
+ const char *src;
+ char *dst;
+{
+ u_char *p = (u_char *)dst;
+ char tmp[INADDRSZ];
+ int i;
+
+ /* Stash a temporary copy so our caller can update in place. */
+ bcopy(src, tmp, INADDRSZ);
+ /* Mark this ipv6 addr as a mapped ipv4. */
+ for (i = 0; i < 10; i++)
+ *p++ = 0x00;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ /* Retrieve the saved copy and we're done. */
+ bcopy(tmp, (void*)p, INADDRSZ);
+}
+
+void
+_map_v4v6_hostent(hp, bpp, lenp)
+ struct hostent *hp;
+ char **bpp;
+ int *lenp;
+{
+ char **ap;
+
+ if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
+ return;
+ hp->h_addrtype = AF_INET6;
+ hp->h_length = IN6ADDRSZ;
+ for (ap = hp->h_addr_list; *ap; ap++) {
+ int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
+
+ if (*lenp < (i + IN6ADDRSZ)) {
+ /* Out of memory. Truncate address list here. XXX */
+ *ap = NULL;
+ return;
+ }
+ *bpp += i;
+ *lenp -= i;
+ _map_v4v6_address(*ap, *bpp);
+ *ap = *bpp;
+ *bpp += IN6ADDRSZ;
+ *lenp -= IN6ADDRSZ;
+ }
+}
#define strdup(x) strcpy(malloc(strlen(x) + 1), x)
extern size_t strlen(const char *);
-extern char *index(char *, char);
+extern char *index(const char *, int);
extern char *strcpy(char *, const char *);
extern int strcmp(const char *, const char*);
extern void *bcopy(void *, void *, unsigned);
if (pf == NULL) {
return (NULL);
}
- while (ent = _old_prdb_get()) {
+ while ((ent = _old_prdb_get())) {
if (prmatch(ent, prname)) {
break;
}
--- /dev/null
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/net/rthdr.c,v 1.2 2000/03/03 11:12:59 shin Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <string.h>
+#include <stdio.h>
+
+size_t
+inet6_rthdr_space(type, seg)
+ int type, seg;
+{
+ switch(type) {
+ case IPV6_RTHDR_TYPE_0:
+ if (seg < 1 || seg > 23)
+ return(0);
+ return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1)
+ + sizeof(struct ip6_rthdr0)));
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type);
+#endif
+ return(0);
+ }
+}
+
+struct cmsghdr *
+inet6_rthdr_init(bp, type)
+ void *bp;
+ int type;
+{
+ register struct cmsghdr *ch = (struct cmsghdr *)bp;
+ register struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
+
+ ch->cmsg_level = IPPROTO_IPV6;
+ ch->cmsg_type = IPV6_RTHDR;
+
+ switch(type) {
+ case IPV6_RTHDR_TYPE_0:
+ ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr));
+ bzero(rthdr, sizeof(struct ip6_rthdr0));
+ rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
+ return(ch);
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type);
+#endif
+ return(NULL);
+ }
+}
+
+int
+inet6_rthdr_add(cmsg, addr, flags)
+ struct cmsghdr *cmsg;
+ const struct in6_addr *addr;
+ u_int flags;
+{
+ register struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags);
+#endif
+ return(-1);
+ }
+ if (rt0->ip6r0_segleft == 23) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
+#endif
+ return(-1);
+ }
+ if (flags == IPV6_RTHDR_STRICT) {
+ int c, b;
+ c = rt0->ip6r0_segleft / 8;
+ b = rt0->ip6r0_segleft % 8;
+ rt0->ip6r0_slmap[c] |= (1 << (7 - b));
+ }
+ rt0->ip6r0_segleft++;
+ bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
+ sizeof(struct in6_addr));
+ rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
+ cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
+ break;
+ }
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return(-1);
+ }
+
+ return(0);
+}
+
+int
+inet6_rthdr_lasthop(cmsg, flags)
+ struct cmsghdr *cmsg;
+ unsigned int flags;
+{
+ register struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags);
+#endif
+ return(-1);
+ }
+ if (rt0->ip6r0_segleft > 23) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
+#endif
+ return(-1);
+ }
+ if (flags == IPV6_RTHDR_STRICT) {
+ int c, b;
+ c = rt0->ip6r0_segleft / 8;
+ b = rt0->ip6r0_segleft % 8;
+ rt0->ip6r0_slmap[c] |= (1 << (7 - b));
+ }
+ break;
+ }
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return(-1);
+ }
+
+ return(0);
+}
+
+#if 0
+int
+inet6_rthdr_reverse(in, out)
+ const struct cmsghdr *in;
+ struct cmsghdr *out;
+{
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
+#endif
+ return -1;
+}
+#endif
+
+int
+inet6_rthdr_segments(cmsg)
+ const struct cmsghdr *cmsg;
+{
+ register struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_segments: invalid size(%d)\n",
+ rt0->ip6r0_len);
+#endif
+ return -1;
+ }
+
+ return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ }
+
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_segments: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return -1;
+ }
+}
+
+struct in6_addr *
+inet6_rthdr_getaddr(cmsg, index)
+ struct cmsghdr *cmsg;
+ int index;
+{
+ register struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ int naddr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getaddr: invalid size(%d)\n",
+ rt0->ip6r0_len);
+#endif
+ return NULL;
+ }
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (index <= 0 || naddr < index) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getaddr: invalid index(%d)\n", index);
+#endif
+ return NULL;
+ }
+ return &rt0->ip6r0_addr[index - 1];
+ }
+
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return NULL;
+ }
+}
+
+int
+inet6_rthdr_getflags(cmsg, index)
+ const struct cmsghdr *cmsg;
+ int index;
+{
+ register struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch(rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ int naddr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getflags: invalid size(%d)\n",
+ rt0->ip6r0_len);
+#endif
+ return -1;
+ }
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (index < 0 || naddr < index) {
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getflags: invalid index(%d)\n", index);
+#endif
+ return -1;
+ }
+ if (rt0->ip6r0_slmap[index / 8] & (0x80 >> (index % 8)))
+ return IPV6_RTHDR_STRICT;
+ else
+ return IPV6_RTHDR_LOOSE;
+ }
+
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "inet6_rthdr_getflags: unknown type(%d)\n",
+ rthdr->ip6r_type);
+#endif
+ return -1;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/net/vars.c,v 1.1 1999/12/16 18:32:01 shin Exp $
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/*
+ * Definitions of some costant IPv6 addresses.
+ */
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT;
+const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
+const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
+
PROJECT_TYPE = Component
HFILES = aliasdb.h bootparams.h lookup_types.h lu_overrides.h\
- lu_utils.h netgr.h printerdb.h
+ lu_host.h lu_utils.h netdb_async.h netgr.h printerdb.h
CFILES = lu_alias.c lu_bootp.c lu_bootparam.c lu_fstab.c lu_group.c\
- lu_host.c lu_netgroup.c lu_network.c lu_printer.c\
+ lu_host.c lu_host_async.c lu_netgroup.c lu_network.c lu_printer.c\
lu_protocol.c lu_rpc.c lu_service.c lu_user.c lu_utils.c
OTHERSRCS = Makefile.preamble Makefile Makefile.postamble lookup.defs\
%_xdr.c: %.x
$(RPCGEN) $(ALL_RPCFLAGS) -c -o $(SYM_DIR)/$*_xdr.c $*.x
+async_hdrs: $(DSTROOT)$(PRIVATE_HDR_INSTALLDIR)$(ASYNC_HEADER_DIR_SUFFIX)
+ $(SILENT) $(FASTCP) $(ASYNC_HDRS) $(DSTROOT)$(PRIVATE_HDR_INSTALLDIR)$(ASYNC_HEADER_DIR_SUFFIX)
+
+$(DSTROOT)$(PRIVATE_HDR_INSTALLDIR)$(ASYNC_HEADER_DIR_SUFFIX):
+ $(MKDIRS) $@
+
netinfo_hdrs: $(DSTROOT)$(PUBLIC_HDR_INSTALLDIR)$(NETINFO_HEADER_DIR_SUFFIX)
$(SILENT) $(FASTCP) $(NETINFO_HDRS) $(DSTROOT)$(PUBLIC_HDR_INSTALLDIR)$(NETINFO_HEADER_DIR_SUFFIX)
RPCFILES = _lu_types.x
OTHER_OFILES = lookupUser.o _lu_types_xdr.o
AFTER_PREBUILD = _lu_types.h lookupUser.c
+ASYNC_HDRS = netdb_async.h
NETINFO_HDRS = lookup.h _lu_types.h lookup_types.h lookup.defs _lu_types.x
-BEFORE_INSTALLHDRS += $(SFILE_DIR) $(NETINFO_HDRS)
-AFTER_INSTALLHDRS += netinfo_hdrs
+BEFORE_INSTALLHDRS += $(SFILE_DIR) $(ASYNC_HDRS) $(NETINFO_HDRS)
+AFTER_INSTALLHDRS += async_hdrs netinfo_hdrs
PUBLIC_HEADER_DIR_SUFFIX =
+PRIVATE_HEADER_DIR = /usr/local/include
+ASYNC_HEADER_DIR_SUFFIX = /
NETINFO_HEADER_DIR_SUFFIX = /netinfo
bootparams.h,
lookup_types.h,
lu_overrides.h,
+ lu_host.h,
lu_utils.h,
+ netdb_async.h,
netgr.h,
printerdb.h
);
lu_fstab.c,
lu_group.c,
lu_host.c,
+ lu_host_async.c,
lu_netgroup.c,
lu_network.c,
lu_printer.c,
import <netinfo/lookup_types.h>;
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
-type int = MACH_MSG_TYPE_INTEGER_32;
-type mach_port_t = MACH_MSG_TYPE_COPY_SEND;
type lookup_name = array [256] of MACH_MSG_TYPE_CHAR;
type unit = array [4] of MACH_MSG_TYPE_CHAR;
type inline_data = array [ * : 4096 ] of unit;
type ooline_data = ^ array [] of unit;
+routine _lookup_link_secure
+(
+ server : mach_port_t;
+ name : lookup_name;
+ out procno : int;
+ UserSecToken token : security_token_t
+);
-routine _lookup_link( server : mach_port_t;
- name : lookup_name;
- out procno: int);
+routine _lookup_all_secure
+(
+ server : mach_port_t;
+ proc : int;
+ indata : inline_data;
+ out outdata : ooline_data;
+ UserSecToken token : security_token_t
+);
-routine _lookup_all( server : mach_port_t;
- proc : int;
- indata : inline_data;
- out outdata : ooline_data);
-
-routine _lookup_one( server : mach_port_t;
- proc : int;
- indata : inline_data;
- out outdata : inline_data);
-
-
-routine _lookup_ooall( server : mach_port_t;
- proc : int;
- indata : ooline_data;
- out outdata : ooline_data);
+routine _lookup_one_secure
+(
+ server : mach_port_t;
+ proc : int;
+ indata : inline_data;
+ out outdata : inline_data;
+ UserSecToken token : security_token_t
+);
+routine _lookup_ooall_secure
+(
+ server : mach_port_t;
+ proc : int;
+ indata : ooline_data;
+ out outdata : ooline_data;
+ UserSecToken token : security_token_t
+);
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <aliasdb.h>
+#include <pthread.h>
-#include "lookup.h"
#include "_lu_types.h"
+#include "lookup.h"
#include "lu_utils.h"
#include "lu_overrides.h"
-static lookup_state alias_state = LOOKUP_CACHE;
-static struct aliasent global_aliasent;
-static int global_free = 1;
-static char *alias_data = NULL;
-static unsigned alias_datalen;
-static int alias_nentries = 0;
-static int alias_start = 1;
-static XDR alias_xdr;
+static pthread_mutex_t _alias_lock = PTHREAD_MUTEX_INITIALIZER;
static void
-freeold(void)
+free_alias_data(struct aliasent *a)
{
- int i, len;
+ int i;
- if (global_free == 1) return;
+ if (a == NULL) return;
+
+ if (a->alias_name != NULL) free(a->alias_name);
+ for (i = 0; i < a->alias_members_len; i++) free(a->alias_members[i]);
+ if (a->alias_members != NULL) free(a->alias_members);
+}
- free(global_aliasent.alias_name);
+static void
+free_alias(struct aliasent *a)
+{
+ if (a == NULL) return;
+ free_alias_data(a);
+ free(a);
+}
- len = global_aliasent.alias_members_len;
- for (i = 0; i < len; i++)
- free(global_aliasent.alias_members[i]);
+static void
+free_lu_thread_info_alias(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_alias((struct aliasent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
- free(global_aliasent.alias_members);
+ _lu_data_free_vm_xdr(tdata);
- global_free = 1;
+ free(tdata);
}
-static void
-convert_aliasent(_lu_aliasent *lu_aliasent)
+static struct aliasent *
+extract_alias(XDR *xdr)
+{
+ int i, j, nkeys, nvals, status;
+ char *key, **vals;
+ struct aliasent *a;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ a = (struct aliasent *)calloc(1, sizeof(struct aliasent));
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_alias(a);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((a->alias_name == NULL) && (!strcmp("name", key)))
+ {
+ a->alias_name = vals[0];
+ j = 1;
+ }
+ else if (!strcmp("alias_local", key))
+ {
+ a->alias_local = atoi(vals[0]);
+ }
+ else if ((a->alias_members == NULL) && (!strcmp("members", key)))
+ {
+ a->alias_members_len = nvals;
+ a->alias_members = vals;
+ j = nvals;
+ vals = NULL;
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if (a->alias_name == NULL) a->alias_name = strdup("");
+ if (a->alias_members == NULL) a->alias_members = (char **)calloc(1, sizeof(char *));
+
+ return a;
+}
+
+static struct aliasent *
+copy_alias(struct aliasent *in)
{
- int i, len;
+ int i;
+ struct aliasent *a;
+
+ if (in == NULL) return NULL;
+
+ a = (struct aliasent *)calloc(1, sizeof(struct aliasent));
+
+ a->alias_name = LU_COPY_STRING(in->alias_name);
+
+ a->alias_members_len = in->alias_members_len;
+
+ if (a->alias_members_len == 0)
+ {
+ a->alias_members = (char **)calloc(1, sizeof(char *));
+ }
+ else
+ {
+ a->alias_members = (char **)calloc(a->alias_members_len, sizeof(char *));
+ }
- freeold();
+ for (i = 0; i < a->alias_members_len; i++)
+ {
+ a->alias_members[i] = strdup(in->alias_members[i]);
+ }
- global_aliasent.alias_name = strdup(lu_aliasent->alias_name);
+ a->alias_local = in->alias_local;
- len = lu_aliasent->alias_members.alias_members_len;
- global_aliasent.alias_members_len = len;
- global_aliasent.alias_members = (char **)malloc(len * sizeof(char *));
+ return a;
+}
- for (i = 0; i < len; i++)
+static void
+recycle_alias(struct lu_thread_info *tdata, struct aliasent *in)
+{
+ struct aliasent *a;
+
+ if (tdata == NULL) return;
+ a = (struct aliasent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_alias(a);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
{
- global_aliasent.alias_members[i] =
- strdup(lu_aliasent->alias_members.alias_members_val[i]);
+ tdata->lu_entry = in;
+ return;
}
- global_aliasent.alias_local = lu_aliasent->alias_local;
+ free_alias_data(a);
+
+ a->alias_name = in->alias_name;
+ a->alias_members_len = in->alias_members_len;
+ a->alias_members = in->alias_members;
+ a->alias_local = in->alias_local;
- global_free = 0;
+ free(in);
}
static struct aliasent *
lu_alias_getbyname(const char *name)
{
- unsigned datalen;
+ struct aliasent *a;
+ unsigned int datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
XDR outxdr;
XDR inxdr;
- _lu_aliasent_ptr lu_aliasent;
static int proc = -1;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "alias_getbyname", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_aliasent = NULL;
- if (!xdr__lu_aliasent_ptr(&inxdr, &lu_aliasent) || (lu_aliasent == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ a = extract_alias(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_aliasent(lu_aliasent);
- xdr_free(xdr__lu_aliasent_ptr, &lu_aliasent);
- return (&global_aliasent);
+ return a;
}
static void
lu_alias_endent(void)
{
- alias_nentries = 0;
- if (alias_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)alias_data, alias_datalen);
- alias_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_alias, free_lu_thread_info_alias);
+ _lu_data_free_vm_xdr(tdata);
}
static void
lu_alias_setent(void)
{
lu_alias_endent();
- alias_start = 1;
}
static struct aliasent *
lu_alias_getent(void)
{
static int proc = -1;
- _lu_aliasent lu_aliasent;
+ struct lu_thread_info *tdata;
+ struct aliasent *a;
- if (alias_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_alias, free_lu_thread_info_alias);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_alias, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- alias_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "alias_getent", &proc) != KERN_SUCCESS)
{
lu_alias_endent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &alias_data, &alias_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_alias_endent();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- alias_datalen *= BYTES_PER_XDR_UNIT;
-#endif
- xdrmem_create(&alias_xdr, alias_data,
- alias_datalen, XDR_DECODE);
- if (!xdr_int(&alias_xdr, &alias_nentries))
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&alias_xdr);
lu_alias_endent();
- return (NULL);
+ return NULL;
}
}
- if (alias_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&alias_xdr);
lu_alias_endent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_aliasent, sizeof(lu_aliasent));
- if (!xdr__lu_aliasent(&alias_xdr, &lu_aliasent))
+
+ a = extract_alias(tdata->lu_xdr);
+ if (a == NULL)
{
- xdr_destroy(&alias_xdr);
lu_alias_endent();
- return (NULL);
+ return NULL;
}
- alias_nentries--;
- convert_aliasent(&lu_aliasent);
- xdr_free(xdr__lu_aliasent, &lu_aliasent);
- return (&global_aliasent);
+ tdata->lu_vm_cursor--;
+
+ return a;
}
struct aliasent *
alias_getbyname(const char *name)
{
- LOOKUP1(lu_alias_getbyname, _old_alias_getbyname, name, struct aliasent);
+ struct aliasent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_alias, free_lu_thread_info_alias);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_alias, tdata);
+ }
+
+ if (_lu_running())
+ {
+ res = lu_alias_getbyname(name);
+ }
+ else
+ {
+ pthread_mutex_lock(&_alias_lock);
+ res = copy_alias(_old_alias_getbyname(name));
+ pthread_mutex_unlock(&_alias_lock);
+ }
+
+ recycle_alias(tdata, res);
+ return (struct aliasent *)tdata->lu_entry;
+
}
struct aliasent *
alias_getent(void)
{
- GETENT(lu_alias_getent, _old_alias_getent, &alias_state, struct aliasent);
+ struct aliasent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_alias, free_lu_thread_info_alias);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_alias, tdata);
+ }
+
+ if (_lu_running())
+ {
+ res = lu_alias_getent();
+ }
+ else
+ {
+ pthread_mutex_lock(&_alias_lock);
+ res = copy_alias(_old_alias_getent());
+ pthread_mutex_unlock(&_alias_lock);
+ }
+
+ recycle_alias(tdata, res);
+ return (struct aliasent *)tdata->lu_entry;
+
}
void
alias_setent(void)
{
- SETSTATEVOID(lu_alias_setent, _old_alias_setent, &alias_state);
+ if (_lu_running()) lu_alias_setent();
+ else _old_alias_setent();
}
void
alias_endent(void)
{
- UNSETSTATE(lu_alias_endent, _old_alias_endent, &alias_state);
+ if (_lu_running()) lu_alias_endent();
+ else _old_alias_endent();
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*/
#include <mach/mach.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include "lookup.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
-#include "_lu_types.h"
-#include "lu_utils.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/if_ether.h>
+#include <pthread.h>
+
+#include "_lu_types.h"
+#include "lookup.h"
+#include "lu_utils.h"
+
+extern struct ether_addr *ether_aton(char *);
+
+static pthread_mutex_t _bootp_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct bootpent
+{
+ char *b_name;
+ struct ether_addr b_enaddr;
+ struct in_addr b_ipaddr;
+ char *b_bootfile;
+};
+
+static void
+free_bootp(struct bootpent *b)
+{
+ if (b == NULL) return;
+
+ if (b->b_name != NULL) free(b->b_name);
+ if (b->b_bootfile != NULL) free(b->b_bootfile);
+
+ free(b);
+}
+
+static struct bootpent *
+extract_bootp(XDR *xdr)
+{
+ struct bootpent *b;
+ struct ether_addr *e;
+ int i, j, nvals, nkeys, status;
+ char *key, **vals;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ b = (struct bootpent *)calloc(1, sizeof(struct bootpent));
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_bootp(b);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((b->b_name == NULL) && (!strcmp("name", key)))
+ {
+ b->b_name = vals[0];
+ j = 1;
+ }
+ if ((b->b_name == NULL) && (!strcmp("bootfile", key)))
+ {
+ b->b_bootfile = vals[0];
+ j = 1;
+ }
+ else if (!strcmp("ip_address", key))
+ {
+ b->b_ipaddr.s_addr = inet_addr(vals[0]);
+ }
+ else if (!strcmp("en_address", key))
+ {
+ pthread_mutex_lock(&_bootp_lock);
+ e = ether_aton(vals[0]);
+ if (e != NULL) memcpy(&(b->b_enaddr), e, sizeof(struct ether_addr));
+ pthread_mutex_unlock(&_bootp_lock);
+ j = 1;
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if (b->b_name == NULL) b->b_name = strdup("");
+ if (b->b_bootfile == NULL) b->b_bootfile = strdup("");
+
+ return b;
+}
static int
lu_bootp_getbyether(struct ether_addr *enaddr, char **name,
struct in_addr *ipaddr, char **bootfile)
{
unsigned datalen;
- XDR xdr;
- static _lu_bootp_ent_ptr bp;
+ XDR inxdr;
+ struct bootpent *b;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
-
+ char *lookup_buf;
+ int count;
+
if (proc < 0)
{
if (_lookup_link(_lu_port, "bootp_getbyether", &proc) != KERN_SUCCESS)
{
- return (0);
+ return 0;
}
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)enaddr,
- ((sizeof(*enaddr) + sizeof(unit) - 1) / sizeof(unit)), lookup_buf,
- &datalen) != KERN_SUCCESS)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)enaddr, ((sizeof(*enaddr) + sizeof(unit) - 1) / sizeof(unit)), &lookup_buf, &datalen) != KERN_SUCCESS)
{
- return (0);
+ return 0;
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- xdr_free(xdr__lu_bootp_ent_ptr, &bp);
- if (!xdr__lu_bootp_ent_ptr(&xdr, &bp) || (bp == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
- xdr_destroy(&xdr);
- return (0);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return 0;
}
- xdr_destroy(&xdr);
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return 0;
+ }
- *name = bp->bootp_name;
- *bootfile = bp->bootp_bootfile;
- ipaddr->s_addr = bp->bootp_ipaddr;
- return (1);
+ b = extract_bootp(&inxdr);
+ xdr_destroy(&inxdr);
+
+ *name = b->b_name;
+ *bootfile = b->b_bootfile;
+ ipaddr->s_addr = b->b_ipaddr.s_addr;
+
+ free(b);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+
+ return 1;
}
static int
struct in_addr *ipaddr, char **bootfile)
{
unsigned datalen;
- XDR xdr;
- static _lu_bootp_ent_ptr bp;
+ XDR inxdr;
+ struct bootpent *b;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "bootp_getbyip", &proc) != KERN_SUCCESS)
{
- return (0);
+ return 0;
}
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)ipaddr,
- ((sizeof(*ipaddr) + sizeof(unit) - 1) / sizeof(unit)), lookup_buf,
- &datalen) != KERN_SUCCESS)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)ipaddr, ((sizeof(*ipaddr) + sizeof(unit) - 1) / sizeof(unit)), &lookup_buf, &datalen) != KERN_SUCCESS)
{
- return (0);
+ return 0;
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- xdr_free(xdr__lu_bootp_ent_ptr, &bp);
- if (!xdr__lu_bootp_ent_ptr(&xdr, &bp) || (bp == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return 0;
+ }
+
+ if (count == 0)
{
- xdr_destroy(&xdr);
- return (0);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return 0;
}
- xdr_destroy(&xdr);
+ b = extract_bootp(&inxdr);
+ xdr_destroy(&inxdr);
- *name = bp->bootp_name;
- *bootfile = bp->bootp_bootfile;
- bcopy(bp->bootp_enaddr, enaddr, sizeof(*enaddr));
- return (1);
+ *name = b->b_name;
+ *bootfile = b->b_bootfile;
+ memcpy(enaddr, &(b->b_enaddr), sizeof(struct ether_addr));
+
+ free(b);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+
+ return 1;
}
int
-bootp_getbyether(struct ether_addr *enaddr, char **name,
- struct in_addr *ipaddr, char **bootfile)
+bootp_getbyether(struct ether_addr *enaddr, char **name,struct in_addr *ipaddr, char **bootfile)
{
if (_lu_running())
+ {
return (lu_bootp_getbyether(enaddr, name, ipaddr, bootfile));
- return (0);
+ }
+ return 0;
}
int
-bootp_getbyip(struct ether_addr *enaddr, char **name,
- struct in_addr *ipaddr, char **bootfile)
+bootp_getbyip(struct ether_addr *enaddr, char **name, struct in_addr *ipaddr, char **bootfile)
{
if (_lu_running())
+ {
return (lu_bootp_getbyip(enaddr, name, ipaddr, bootfile));
- return (0);
+ }
+ return 0;
}
#include "_lu_types.h"
#include "lu_utils.h"
-static lookup_state bp_state = LOOKUP_CACHE;
-static struct bootparamsent global_bp;
-static int global_free = 1;
-static char *bp_data = NULL;
-static unsigned bp_datalen;
-static int bp_nentries;
-static int bp_start = 1;
-static XDR bp_xdr;
-
static void
-freeold(void)
+free_bootparams_data(struct bootparamsent *b)
{
- int i;
- if (global_free == 1) return;
+ char **param;
- free(global_bp.bp_name);
+ if (b == NULL) return;
- for (i = 0; global_bp.bp_bootparams[i] != NULL; i++)
- free(global_bp.bp_bootparams[i]);
+ if (b->bp_name != NULL) free(b->bp_name);
- global_free = 1;
+ param = b->bp_bootparams;
+ if (param != NULL)
+ {
+ while (*param != NULL) free(*param++);
+ free(b->bp_bootparams);
+ }
+}
+
+static void
+free_bootparams(struct bootparamsent *b)
+{
+ if (b == NULL) return;
+ free_bootparams_data(b);
+ free(b);
}
static void
-convert_bootparamsent(_lu_bootparams_ent *lu_bpent)
+free_lu_thread_info_bootparams(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_bootparams((struct bootparamsent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct bootparamsent *
+extract_bootparams(XDR *xdr)
{
- int i, len;
+ int i, j, nkeys, nvals, status;
+ char *key, **vals;
+ struct bootparamsent *b;
- freeold();
+ if (xdr == NULL) return NULL;
- global_bp.bp_name = strdup(lu_bpent->bootparams_name);
+ if (!xdr_int(xdr, &nkeys)) return NULL;
- len = lu_bpent->bootparams_keyvalues.bootparams_keyvalues_len;
- global_bp.bp_bootparams = (char **)malloc((len + 1) * sizeof(char *));
+ b = (struct bootparamsent *)calloc(1, sizeof(struct bootparamsent));
- for (i = 0; i < len; i++)
+ for (i = 0; i < nkeys; i++)
{
- global_bp.bp_bootparams[i] =
- strdup(lu_bpent->bootparams_keyvalues.bootparams_keyvalues_val[i]);
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_bootparams(b);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((b->bp_name == NULL) && (!strcmp("name", key)))
+ {
+ b->bp_name = vals[0];
+ j = 1;
+ }
+ else if ((b->bp_bootparams == NULL) && (!strcmp("bootparams", key)))
+ {
+ b->bp_bootparams = vals;
+ j = nvals;
+ vals = NULL;
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
}
- global_bp.bp_bootparams[len] = NULL;
+ if (b->bp_name == NULL) b->bp_name = strdup("");
+ if (b->bp_bootparams == NULL) b->bp_bootparams = (char **)calloc(1, sizeof(char *));
- global_free = 0;
+ return b;
+}
+
+static void
+recycle_bootparams(struct lu_thread_info *tdata, struct bootparamsent *in)
+{
+ struct bootparamsent *b;
+
+ if (tdata == NULL) return;
+ b = (struct bootparamsent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_bootparams(b);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
+
+ free_bootparams_data(b);
+
+ b->bp_name = in->bp_name;
+ b->bp_bootparams = in->bp_bootparams;
+
+ free(in);
}
static struct bootparamsent *
lu_bootparams_getbyname(const char *name)
{
+ struct bootparamsent *b;
unsigned datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
XDR outxdr;
XDR inxdr;
int size;
- _lu_bootparams_ent_ptr lu_bpent;
static int proc = -1;
-
+ int count;
+
if (proc < 0)
{
if (_lookup_link(_lu_port, "bootparams_getbyname", &proc)
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
return (NULL);
size = xdr_getpos(&outxdr);
xdr_destroy(&outxdr);
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf, size, lookup_buf,
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf, size, &lookup_buf,
&datalen) != KERN_SUCCESS)
{
return (NULL);
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_bpent = NULL;
- if (!xdr__lu_bootparams_ent_ptr(&inxdr, &lu_bpent) || (lu_bpent == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ b = extract_bootparams(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_bootparamsent(lu_bpent);
- xdr_free(xdr__lu_bootparams_ent_ptr, &lu_bpent);
- return (&global_bp);
+ return b;
}
static void
lu_bootparams_endent(void)
{
- bp_nentries = 0;
- if (bp_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)bp_data, bp_datalen);
- bp_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_bootparams, free_lu_thread_info_bootparams);
+ _lu_data_free_vm_xdr(tdata);
}
static void
lu_bootparams_setent(void)
{
lu_bootparams_endent();
- bp_start = 1;
}
static struct bootparamsent *
lu_bootparams_getent(void)
{
+ struct bootparamsent *b;
static int proc = -1;
- _lu_bootparams_ent lu_bpent;
+ struct lu_thread_info *tdata;
- if (bp_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_bootparams, free_lu_thread_info_bootparams);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_bootparams, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- bp_start = 0;
-
if (proc < 0)
{
- if (_lookup_link(_lu_port, "bootparams_getent", &proc)
- != KERN_SUCCESS)
+ if (_lookup_link(_lu_port, "bootparams_getent", &proc) != KERN_SUCCESS)
{
lu_bootparams_endent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &bp_data, &bp_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_bootparams_endent();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- bp_datalen *= BYTES_PER_XDR_UNIT;
-#endif
- xdrmem_create(&bp_xdr, bp_data, bp_datalen,
- XDR_DECODE);
- if (!xdr_int(&bp_xdr, &bp_nentries))
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&bp_xdr);
lu_bootparams_endent();
- return (NULL);
+ return NULL;
}
}
- if (bp_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&bp_xdr);
lu_bootparams_endent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_bpent, sizeof(lu_bpent));
- if (!xdr__lu_bootparams_ent(&bp_xdr, &lu_bpent))
+ b = extract_bootparams(tdata->lu_xdr);
+ if (b == NULL)
{
- xdr_destroy(&bp_xdr);
lu_bootparams_endent();
- return (NULL);
+ return NULL;
}
- bp_nentries--;
- convert_bootparamsent(&lu_bpent);
- xdr_free(xdr__lu_bootparams_ent, &lu_bpent);
- return (&global_bp);
+ tdata->lu_vm_cursor--;
+
+ return b;
}
struct bootparamsent *
bootparams_getbyname(const char *name)
{
- if (_lu_running()) return (lu_bootparams_getbyname(name));
- return (NULL);
+ struct bootparamsent *res;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_bootparams, free_lu_thread_info_bootparams);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_bootparams, tdata);
+ }
+
+ if (_lu_running())
+ {
+ res = lu_bootparams_getbyname(name);
+ recycle_bootparams(tdata, res);
+ return (struct bootparamsent *)tdata->lu_entry;
+ }
+
+ return NULL;
}
struct bootparamsent *
bootparams_getent(void)
{
- if (_lu_running()) return (lu_bootparams_getent());
- return (NULL);
+ struct bootparamsent *res;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_bootparams, free_lu_thread_info_bootparams);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_bootparams, tdata);
+ }
+
+ if (_lu_running())
+ {
+ res = lu_bootparams_getent();
+ recycle_bootparams(tdata, res);
+ return (struct bootparamsent *)tdata->lu_entry;
+ }
+
+ return NULL;
}
void
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <fstab.h>
+#include <pthread.h>
#include "lookup.h"
#include "_lu_types.h"
#include "lu_utils.h"
#include "lu_overrides.h"
-static struct fstab global_fs;
-static int global_free = 1;
-static char *fs_data = NULL;
-static unsigned fs_datalen = 0;
-static int fs_nentries = 0;
-static int fs_start = 1;
-static XDR fs_xdr = { 0 };
+static pthread_mutex_t _fstab_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define FS_GET_SPEC 1
+#define FS_GET_FILE 2
+#define FS_GET_ENT 3
static void
-freeold(void)
+free_fstab_data(struct fstab *f)
{
- if (global_free == 1) return;
+ if (f == NULL) return;
- free(global_fs.fs_spec);
- free(global_fs.fs_file);
- free(global_fs.fs_type);
- free(global_fs.fs_vfstype);
- free(global_fs.fs_mntops);
+ if (f->fs_spec != NULL) free(f->fs_spec);
+ if (f->fs_file != NULL) free(f->fs_file);
+ if (f->fs_vfstype != NULL) free(f->fs_vfstype);
+ if (f->fs_mntops != NULL) free(f->fs_mntops);
+ if (f->fs_type != NULL) free(f->fs_type);
+}
- global_free = 1;
+static void
+free_fstab(struct fstab *f)
+{
+ if (f == NULL) return;
+ free_fstab_data(f);
+ free(f);
}
static void
-convert_fs(_lu_fsent *lu_fs)
+free_lu_thread_info_fstab(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_fstab((struct fstab *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct fstab *
+extract_fstab(XDR *xdr)
{
- freeold();
+ int i, j, nkeys, nvals, status;
+ char *key, **vals;
+ struct fstab *f;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
- global_fs.fs_spec = strdup(lu_fs->fs_spec);
- global_fs.fs_file = strdup(lu_fs->fs_file);
+ f = (struct fstab *)calloc(1, sizeof(struct fstab));
- /*
- * Special case - if vfstype is unknown and spec is
- * of the form foo:bar, then assume nfs.
- */
- if (lu_fs->fs_vfstype[0] == '\0')
+ for (i = 0; i < nkeys; i++)
{
- if (strchr(lu_fs->fs_spec, ':') != NULL)
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_fstab(f);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((f->fs_spec == NULL) && (!strcmp("name", key)))
+ {
+ f->fs_spec = vals[0];
+ j = 1;
+ }
+ else if ((f->fs_file == NULL) && (!strcmp("dir", key)))
+ {
+ f->fs_file = vals[0];
+ j = 1;
+ }
+ else if ((f->fs_vfstype == NULL) && (!strcmp("vfstype", key)))
+ {
+ f->fs_vfstype = vals[0];
+ j = 1;
+ }
+ else if ((f->fs_mntops == NULL) && (!strcmp("opts", key)))
+ {
+ f->fs_mntops = vals[0];
+ j = 1;
+ }
+ else if ((f->fs_type == NULL) && (!strcmp("type", key)))
{
- global_fs.fs_vfstype = malloc(4);
- strcpy(global_fs.fs_vfstype, "nfs");
+ f->fs_type = vals[0];
+ j = 1;
+ }
+ else if (!strcmp("freq", key))
+ {
+ f->fs_freq = atoi(vals[0]);
+ }
+ else if (!strcmp("passno", key))
+ {
+ f->fs_passno = atoi(vals[0]);
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
}
- else global_fs.fs_vfstype = strdup(lu_fs->fs_vfstype);
}
- else
+
+ if (f->fs_spec == NULL) f->fs_spec = strdup("");
+ if (f->fs_file == NULL) f->fs_file = strdup("");
+ if (f->fs_vfstype == NULL) f->fs_vfstype = strdup("");
+ if (f->fs_mntops == NULL) f->fs_mntops = strdup("");
+ if (f->fs_type == NULL) f->fs_type = strdup("");
+
+ return f;
+}
+
+static struct fstab *
+copy_fstab(struct fstab *in)
+{
+ struct fstab *f;
+
+ if (in == NULL) return NULL;
+
+ f = (struct fstab *)calloc(1, sizeof(struct fstab));
+
+ f->fs_spec = LU_COPY_STRING(in->fs_spec);
+ f->fs_file = LU_COPY_STRING(in->fs_file);
+ f->fs_vfstype = LU_COPY_STRING(in->fs_vfstype);
+ f->fs_mntops = LU_COPY_STRING(in->fs_mntops);
+ f->fs_type = LU_COPY_STRING(in->fs_type);
+
+ f->fs_freq = in->fs_freq;
+ f->fs_passno = in->fs_passno;
+
+ return f;
+}
+
+static void
+recycle_fstab(struct lu_thread_info *tdata, struct fstab *in)
+{
+ struct fstab *f;
+
+ if (tdata == NULL) return;
+ f = (struct fstab *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_fstab(f);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
{
- global_fs.fs_vfstype = strdup(lu_fs->fs_vfstype);
+ tdata->lu_entry = in;
+ return;
}
- global_fs.fs_mntops = strdup(lu_fs->fs_mntops);
- global_fs.fs_type = strdup(lu_fs->fs_type);
- global_fs.fs_freq = lu_fs->fs_freq;
- global_fs.fs_passno = lu_fs->fs_passno;
+ free_fstab_data(f);
- global_free = 0;
+ f->fs_spec = in->fs_spec;
+ f->fs_file = in->fs_file;
+ f->fs_vfstype = in->fs_vfstype;
+ f->fs_mntops = in->fs_mntops;
+ f->fs_type = in->fs_type;
+ f->fs_freq = in->fs_freq;
+ f->fs_passno = in->fs_passno;
+
+ free(in);
}
static struct fstab *
-lu_getfsbyname(const char *name)
+lu_getfsspec(const char *name)
{
+ struct fstab *f;
unsigned datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
XDR inxdr;
- _lu_fsent_ptr lu_fs;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getfsbyname", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_fs = NULL;
- if (!xdr__lu_fsent_ptr(&inxdr, &lu_fs) || (lu_fs == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ f = extract_fstab(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_fs(lu_fs);
- xdr_free(xdr__lu_fsent_ptr, &lu_fs);
- return (&global_fs);
+ return f;
}
static void
lu_endfsent(void)
{
- fs_nentries = 0;
- if (fs_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)fs_data, fs_datalen);
- fs_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_fstab, free_lu_thread_info_fstab);
+ _lu_data_free_vm_xdr(tdata);\r
}
static int
lu_setfsent(void)
{
lu_endfsent();
- fs_start = 1;
- return (1);
+ return 1;
}
static struct fstab *
lu_getfsent()
{
static int proc = -1;
- _lu_fsent lu_fs;
+ struct lu_thread_info *tdata;
+ struct fstab *f;
- if (fs_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_fstab, free_lu_thread_info_fstab);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_fstab, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- fs_start = 0;
-
if (proc < 0)
{
- if (_lookup_link(_lu_port, "getfsent", &proc) !=
- KERN_SUCCESS)
+ if (_lookup_link(_lu_port, "getfsent", &proc) != KERN_SUCCESS)
{
lu_endfsent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &fs_data, &fs_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endfsent();
- return (NULL);
+ return NULL;
+ }
+
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
}
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- fs_datalen *= BYTES_PER_XDR_UNIT;
-#endif
- xdrmem_create(&fs_xdr, fs_data,
- fs_datalen, XDR_DECODE);
- if (!xdr_int(&fs_xdr, &fs_nentries))
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&fs_xdr);
lu_endfsent();
- return (NULL);
+ return NULL;
}
}
- if (fs_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&fs_xdr);
lu_endfsent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_fs, sizeof(lu_fs));
- if (!xdr__lu_fsent(&fs_xdr, &lu_fs))
+ f = extract_fstab(tdata->lu_xdr);
+ if (f == NULL)
{
- xdr_destroy(&fs_xdr);
lu_endfsent();
- return (NULL);
+ return NULL;
}
- fs_nentries--;
- convert_fs(&lu_fs);
- xdr_free(xdr__lu_fsent, &lu_fs);
- return (&global_fs);
+ tdata->lu_vm_cursor--;
+
+ return f;
}
-struct fstab *
-lu_getfsspec(const char *name)
-{
- if (name == NULL) return (struct fstab *)NULL;
- return lu_getfsbyname(name);
-}
-
-struct fstab *
+static struct fstab *
lu_getfsfile(const char *name)
{
struct fstab *fs;
return (struct fstab *)NULL;
}
+static struct fstab *
+getfs(const char *spec, const char *file, int source)
+{
+ struct fstab *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_fstab, free_lu_thread_info_fstab);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_fstab, tdata);
+ }
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case FS_GET_SPEC:
+ res = lu_getfsspec(spec);
+ break;
+ case FS_GET_FILE:
+ res = lu_getfsfile(file);
+ break;
+ case FS_GET_ENT:
+ res = lu_getfsent();
+ break;
+ default: res = NULL;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock(&_fstab_lock);
+ switch (source)
+ {
+ case FS_GET_SPEC:
+ res = copy_fstab(_old_getfsspec(spec));
+ break;
+ case FS_GET_FILE:
+ res = copy_fstab(_old_getfsfile(file));
+ break;
+ case FS_GET_ENT:
+ res = copy_fstab(_old_getfsent());
+ break;
+ default: res = NULL;
+ }
+ pthread_mutex_unlock(&_fstab_lock);
+ }
+
+ recycle_fstab(tdata, res);
+ return (struct fstab *)tdata->lu_entry;
+}
+
+
struct fstab *
getfsbyname(const char *name)
{
- if (_lu_running()) return (lu_getfsbyname(name));
- return (NULL);
+ return getfs(name, NULL, FS_GET_SPEC);
+}
+
+struct fstab *
+getfsspec(const char *name)
+{
+ return getfs(name, NULL, FS_GET_SPEC);
+}
+
+struct fstab *
+getfsfile(const char *name)
+{
+ return getfs(NULL, name, FS_GET_FILE);
}
struct fstab *
getfsent(void)
{
- if (_lu_running()) return (lu_getfsent());
- return (_old_getfsent());
+ return getfs(NULL, NULL, FS_GET_ENT);
}
int
else _old_endfsent();
}
-struct fstab *
-getfsspec(const char *name)
-{
- if (_lu_running()) return (lu_getfsspec(name));
- return (_old_getfsspec(name));
-}
-
-struct fstab *
-getfsfile(const char *name)
-{
- if (_lu_running()) return (lu_getfsfile(name));
- return (_old_getfsfile(name));
-}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
+#include <pthread.h>
#include "_lu_types.h"
#include "lookup.h"
#include "lu_utils.h"
#include "lu_overrides.h"
-#define GROUP_SENTINEL -99
+static pthread_mutex_t _group_lock = PTHREAD_MUTEX_INITIALIZER;
-static lookup_state gr_state = LOOKUP_CACHE;
-static struct group global_gr;
-static int global_free = 1;
-static char *gr_data;
-static unsigned gr_datalen = 0;
-static int gr_nentries = 0;
-static int gr_start = 1;
-static XDR gr_xdr;
+#define GR_GET_NAME 1
+#define GR_GET_GID 2
+#define GR_GET_ENT 3
static void
-freeold(void)
+free_group_data(struct group *g)
{
char **mem;
- if (global_free == 1) return;
+ if (g == NULL) return;
- free(global_gr.gr_name);
- global_gr.gr_name = NULL;
+ if (g->gr_name != NULL) free(g->gr_name);
+ if (g->gr_passwd != NULL) free(g->gr_passwd);
- free(global_gr.gr_passwd);
- global_gr.gr_passwd = NULL;
-
- mem = global_gr.gr_mem;
+ mem = g->gr_mem;
if (mem != NULL)
{
while (*mem != NULL) free(*mem++);
- free(global_gr.gr_mem);
- global_gr.gr_mem = NULL;
+ free(g->gr_mem);
}
-
- global_free = 1;
}
+static void
+free_group(struct group *g)
+{
+ if (g == NULL) return;
+ free_group_data(g);
+ free(g);
+ }
+
static void
-convert_gr(_lu_group *lu_gr)
+free_lu_thread_info_group(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_group((struct group *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct group *
+extract_group(XDR *xdr)
{
+ int i, j, nkeys, nvals, status;
+ char *key, **vals;
+ struct group *g;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ g = (struct group *)calloc(1, sizeof(struct group));
+ g->gr_gid = -2;
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_group(g);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((g->gr_name == NULL) && (!strcmp("name", key)))
+ {
+ g->gr_name = vals[0];
+ j = 1;
+ }
+ else if ((g->gr_passwd == NULL) && (!strcmp("passwd", key)))
+ {
+ g->gr_passwd = vals[0];
+ j = 1;
+ }
+ else if ((g->gr_gid == -2) && (!strcmp("gid", key)))
+ {
+ g->gr_gid = atoi(vals[0]);
+ }
+ else if ((g->gr_mem == NULL) && (!strcmp("users", key)))
+ {
+ g->gr_mem = vals;
+ j = nvals;
+ vals = NULL;
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if (g->gr_name == NULL) g->gr_name = strdup("");
+ if (g->gr_passwd == NULL) g->gr_passwd = strdup("");
+ if (g->gr_mem == NULL) g->gr_mem = (char **)calloc(1, sizeof(char *));
+
+ return g;
+}
+
+static struct group *
+copy_group(struct group *in)
+{
+ struct group *g;
int i, len;
- freeold();
+ if (in == NULL) return NULL;
+
+ g = (struct group *)calloc(1, sizeof(struct group));
- global_gr.gr_name = strdup(lu_gr->gr_name);
- global_gr.gr_passwd = strdup(lu_gr->gr_passwd);
- global_gr.gr_gid = lu_gr->gr_gid;
+ g->gr_name = LU_COPY_STRING(in->gr_name);
+ g->gr_passwd = LU_COPY_STRING(in->gr_passwd);
+ g->gr_gid = in->gr_gid;
- len = lu_gr->gr_mem.gr_mem_len;
- global_gr.gr_mem = (char **)malloc((len + 1) * sizeof(char *));
+ len = 0;
+ if (in->gr_mem != NULL)
+ {
+ for (len = 0; in->gr_mem[len] != NULL; len++);
+ }
+ g->gr_mem = (char **)calloc(len + 1, sizeof(char *));
for (i = 0; i < len; i++)
{
- global_gr.gr_mem[i] = strdup(lu_gr->gr_mem.gr_mem_val[i]);
+ g->gr_mem[i] = strdup(in->gr_mem[i]);
+ }
+
+ return g;
+}
+
+static int
+copy_group_r(struct group *in, struct group *out, char *buffer, int buflen)
+{
+ int i, len, hsize;
+ unsigned long addr;
+ char *bp, *ap;
+
+ if (in == NULL) return -1;
+ if (out == NULL) return -1;
+
+ if (buffer == NULL) buflen = 0;
+
+ /* Calculate size of input */
+ hsize = 0;
+ if (in->gr_name != NULL) hsize += strlen(in->gr_name);
+ if (in->gr_passwd != NULL) hsize += strlen(in->gr_passwd);
+
+ /* NULL pointer at end of list */
+ hsize += sizeof(char *);
+
+ len = 0;
+ if (in->gr_mem != NULL)
+ {
+ for (len = 0; in->gr_mem[len] != NULL; len++)
+ {
+ hsize += sizeof(char *);
+ hsize += strlen(in->gr_mem[len]);
+ }
+ }
+
+ /* Check buffer space */
+ if (hsize > buflen) return -1;
+
+ /* Copy result into caller's struct group, using buffer for memory */
+ bp = buffer;
+
+ out->gr_name = NULL;
+ if (in->gr_name != NULL)
+ {
+ out->gr_name = bp;
+ hsize = strlen(in->gr_name) + 1;
+ memmove(bp, in->gr_name, hsize);
+ bp += hsize;
+ }
+
+ out->gr_passwd = NULL;
+ if (in->gr_passwd != NULL)
+ {
+ out->gr_passwd = bp;
+ hsize = strlen(in->gr_passwd) + 1;
+ memmove(bp, in->gr_passwd, hsize);
+ bp += hsize;
}
- global_gr.gr_mem[len] = NULL;
+ out->gr_gid = in->gr_gid;
- global_free = 0;
+ out->gr_mem = NULL;
+ ap = bp + ((len + 1) * sizeof(char *));
+
+ if (in->gr_mem != NULL)
+ {
+ out->gr_mem = (char **)bp;
+ for (i = 0; i < len; i++)
+ {
+ addr = (unsigned long)ap;
+ memmove(bp, &addr, sizeof(unsigned long));
+ bp += sizeof(unsigned long);
+
+ hsize = strlen(in->gr_mem[i]) + 1;
+ memmove(ap, in->gr_mem[i], hsize);
+ ap += hsize;
+ }
+ }
+
+ memset(bp, 0, sizeof(unsigned long));
+ bp = ap;
+
+ return 0;
+}
+
+static void
+recycle_group(struct lu_thread_info *tdata, struct group *in)
+{
+ struct group *g;
+
+ if (tdata == NULL) return;
+ g = (struct group *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_group(g);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
+
+ free_group_data(g);
+
+ g->gr_name = in->gr_name;
+ g->gr_passwd = in->gr_passwd;
+ g->gr_gid = in->gr_gid;
+ g->gr_mem = in->gr_mem;
+
+ free(in);
}
static struct group *
lu_getgrgid(int gid)
{
- unsigned datalen;
- _lu_group_ptr lu_gr;
- XDR xdr;
+ struct group *g;
+ unsigned int datalen;
+ XDR inxdr;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ int count;
+ char *lookup_buf;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getgrgid", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
gid = htonl(gid);
- datalen = MAX_INLINE_UNITS;
+ datalen = 0;
+ lookup_buf = NULL;
- if (_lookup_one(_lu_port, proc, (unit *)&gid, 1, lookup_buf, &datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, (unit *)&gid, 1, &lookup_buf, &datalen) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- lu_gr = NULL;
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
- if (!xdr__lu_group_ptr(&xdr, &lu_gr) || lu_gr == NULL)
+ if (count == 0)
{
- xdr_destroy(&xdr);
- return (NULL);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
- xdr_destroy(&xdr);
+ g = extract_group(&inxdr);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_gr(lu_gr);
- xdr_free(xdr__lu_group_ptr, &lu_gr);
- return (&global_gr);
+ return g;
}
static struct group *
lu_getgrnam(const char *name)
{
- unsigned datalen;
+ struct group *g;
+ unsigned int datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
XDR inxdr;
- _lu_group_ptr lu_gr;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ int count;
+ char *lookup_buf;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getgrnam", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
+ datalen = 0;
+ lookup_buf = NULL;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_gr = NULL;
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
- if (!xdr__lu_group_ptr(&inxdr, &lu_gr) || (lu_gr == NULL))
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ g = extract_group(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_gr(lu_gr);
- xdr_free(xdr__lu_group_ptr, &lu_gr);
- return (&global_gr);
+ return g;
}
-
static int
lu_initgroups(const char *name, int basegid)
{
- unsigned datalen;
+ unsigned int datalen;
XDR outxdr;
XDR inxdr;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
int groups[NGROUPS];
- int ngroups = 1;
+ int ngroups;
int a_group;
- int count;
+ int i, j, count;
groups[0] = basegid;
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
return -1;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
- while (xdr_int(&inxdr, &a_group))
+ if (!xdr_int(&inxdr, &count))
{
- if (a_group == GROUP_SENTINEL) break;
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return -1;
+ }
+
+ if (count > NGROUPS) count = NGROUPS;
- for (count = 0; count < ngroups; count++)
+ ngroups = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ if (!xdr_int(&inxdr, &a_group)) break;
+
+ for (j = 0; j < ngroups; j++)
{
- if (groups[count] == a_group) break;
+ if (groups[j] == a_group) break;
}
-
- if (count >= ngroups) groups[ngroups++] = a_group;
+ if (j >= ngroups) groups[ngroups++] = a_group;
+
}
xdr_destroy(&inxdr);
-
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+
return setgroups(ngroups, groups);
}
static void
lu_endgrent(void)
{
- gr_nentries = 0;
- if (gr_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)gr_data, gr_datalen);
- gr_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_group, free_lu_thread_info_group);
+ _lu_data_free_vm_xdr(tdata);
}
static int
lu_setgrent(void)
{
lu_endgrent();
- gr_start = 1;
- return (1);
+ return 1;
}
static struct group *
lu_getgrent()
{
+ struct group *g;
static int proc = -1;
- _lu_group lu_gr;
+ struct lu_thread_info *tdata;
- if (gr_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_group, free_lu_thread_info_group);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_group, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- gr_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "getgrent", &proc) != KERN_SUCCESS)
{
lu_endgrent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &gr_data, &gr_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endgrent();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- gr_datalen *= BYTES_PER_XDR_UNIT;
-#endif
- xdrmem_create(&gr_xdr, gr_data, gr_datalen,
- XDR_DECODE);
- if (!xdr_int(&gr_xdr, &gr_nentries))
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&gr_xdr);
lu_endgrent();
- return (NULL);
+ return NULL;
}
}
- if (gr_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&gr_xdr);
lu_endgrent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_gr, sizeof(lu_gr));
- if (!xdr__lu_group(&gr_xdr, &lu_gr))
+ g = extract_group(tdata->lu_xdr);
+ if (g == NULL)
{
- xdr_destroy(&gr_xdr);
lu_endgrent();
- return (NULL);
+ return NULL;
}
- gr_nentries--;
- convert_gr(&lu_gr);
- xdr_free(xdr__lu_group, &lu_gr);
- return (&global_gr);
+ tdata->lu_vm_cursor--;
+
+ return g;
}
-struct group *
-getgrgid(gid_t gid)
+static struct group *
+getgr_internal(const char *name, gid_t gid, int source)
+{
+ struct group *res = NULL;
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case GR_GET_NAME:
+ res = lu_getgrnam(name);
+ break;
+ case GR_GET_GID:
+ res = lu_getgrgid(gid);
+ break;
+ case GR_GET_ENT:
+ res = lu_getgrent();
+ break;
+ default: res = NULL;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock(&_group_lock);
+ switch (source)
+ {
+ case GR_GET_NAME:
+ res = copy_group(_old_getgrnam(name));
+ break;
+ case GR_GET_GID:
+ res = copy_group(_old_getgrgid(gid));
+ break;
+ case GR_GET_ENT:
+ res = copy_group(_old_getgrent());
+ break;
+ default: res = NULL;
+ }
+ pthread_mutex_unlock(&_group_lock);
+ }
+
+ return res;
+}
+
+static struct group *
+getgr(const char *name, gid_t gid, int source)
{
- LOOKUP1(lu_getgrgid, _old_getgrgid, gid, struct group);
+ struct group *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_group, free_lu_thread_info_group);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_group, tdata);
+ }
+
+ res = getgr_internal(name, gid, source);
+
+ recycle_group(tdata, res);
+ return (struct group *)tdata->lu_entry;
}
-struct group *
-getgrnam(const char *name)
+static int
+getgr_r(const char *name, gid_t gid, int source, struct group *grp, char *buffer, size_t bufsize, struct group **result)
{
- LOOKUP1(lu_getgrnam, _old_getgrnam, name, struct group);
+ struct group *res = NULL;
+ int status;
+
+ *result = NULL;
+ errno = 0;
+
+ res = getgr_internal(name, gid, source);
+ if (res == NULL) return -1;
+
+ status = copy_group_r(res, grp, buffer, bufsize);
+ free_group(res);
+
+ if (status != 0)
+ {
+ errno = ERANGE;
+ return -1;
+ }
+
+ *result = grp;
+ return 0;
}
int
return (res);
}
+struct group *
+getgrnam(const char *name)
+{
+ return getgr(name, -2, GR_GET_NAME);
+}
+
+struct group *
+getgrgid(gid_t gid)
+{
+ return getgr(NULL, gid, GR_GET_GID);
+}
+
struct group *
getgrent(void)
{
- GETENT(lu_getgrent, _old_getgrent, &gr_state, struct group);
+ return getgr(NULL, -2, GR_GET_ENT);
}
int
setgrent(void)
{
- INTSETSTATEVOID(lu_setgrent, _old_setgrent, &gr_state);
+ if (_lu_running()) lu_setgrent();
+ else _old_setgrent();
+ return 1;
}
void
endgrent(void)
{
- UNSETSTATE(lu_endgrent, _old_endgrent, &gr_state);
+ if (_lu_running()) lu_endgrent();
+ else _old_endgrent();
+}
+
+int
+getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result)
+{
+ return getgr_r(name, -2, GR_GET_NAME, grp, buffer, bufsize, result);
+}
+
+int
+getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result)
+{
+ return getgr_r(NULL, gid, GR_GET_GID, grp, buffer, bufsize, result);
}
*
* @APPLE_LICENSE_HEADER_END@
*/
-/*
- * host lookup
- * Copyright (C) 1989 by NeXT, Inc.
- */
+
#include <stdlib.h>
#include <mach/mach.h>
#include <stdio.h>
#include <string.h>
-#include "lookup.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
-#include "_lu_types.h"
#include <netdb.h>
-#include "lu_utils.h"
#include <sys/socket.h>
-#import <netinet/in.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <ifaddrs.h>
+
+#include "_lu_types.h"
+#include "lookup.h"
+#include "lu_host.h"
+#include "lu_utils.h"
+
+static pthread_mutex_t _host_lock = PTHREAD_MUTEX_INITIALIZER;
extern struct hostent *_res_gethostbyaddr();
extern struct hostent *_res_gethostbyname();
extern void _old_endhostent();
extern void _old_sethostfile();
+extern mach_port_t _lu_port;
+extern int _lu_running(void);
+
extern int h_errno;
-static lookup_state h_state = LOOKUP_CACHE;
-/*
- * The static return value from get*ent functions
- */
-static struct hostent global_h;
-static int global_free = 1;
-static char *h_data = NULL;
-static unsigned h_datalen;
-static int h_nentries;
-static int h_start = 1;
-static XDR h_xdr;
+#define IPV6_ADDR_LEN 16
+#define IPV4_ADDR_LEN 4
-static void
-freeold(void)
+__private_extern__ void
+free_host_data(struct hostent *h)
{
char **aliases;
int i;
- if (global_free == 1) return;
+ if (h == NULL) return;
- free(global_h.h_name);
- aliases = global_h.h_aliases;
+ if (h->h_name != NULL) free(h->h_name);
+
+ aliases = h->h_aliases;
if (aliases != NULL)
{
while (*aliases != NULL) free(*aliases++);
- free(global_h.h_aliases);
+ free(h->h_aliases);
}
- for (i = 0; global_h.h_addr_list[i] != NULL; i++)
- free(global_h.h_addr_list[i]);
-
- free(global_h.h_addr_list);
+ if (h->h_addr_list != NULL)
+ {
+ for (i = 0; h->h_addr_list[i] != NULL; i++) free(h->h_addr_list[i]);
+ free(h->h_addr_list);
+ }
+}
- global_free = 1;
+void
+freehostent(struct hostent *h)
+{
+ if (h == NULL) return;
+ free_host_data(h);
+ free(h);
}
static void
-convert_h(_lu_hostent *lu_h)
+free_lu_thread_info_host(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ freehostent((struct hostent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+__private_extern__ struct hostent *
+extract_host(XDR *xdr, int want, int *err)
+{
+ struct hostent *h;
+ int i, j, nvals, nkeys, status, addr_len;
+ int family, addr_count, map_count;
+ struct in_addr addr;
+ struct in6_addr addr6;
+ char *key, **vals, **mapvals;
+
+ mapvals = NULL;
+ map_count = 0;
+ addr_count = 0;
+ addr_len = sizeof(u_long *);
+
+ if (xdr == NULL)
+ {
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ if (!xdr_int(xdr, &nkeys))
+ {
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ h = (struct hostent *)calloc(1, sizeof(struct hostent));
+
+ family = AF_INET;
+ h->h_length = IPV4_ADDR_LEN;
+
+ if (want > WANT_A4_ONLY)
+ {
+ family = AF_INET6;
+ h->h_length = IPV6_ADDR_LEN;
+ }
+
+ h->h_addrtype = family;
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ freehostent(h);
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((h->h_name == NULL) && (!strcmp("name", key)))
+ {
+ h->h_name = vals[0];
+ if (nvals > 1)
+ {
+ h->h_aliases = (char **)calloc(nvals, sizeof(char *));
+ for (j = 1; j < nvals; j++) h->h_aliases[j-1] = vals[j];
+ }
+ j = nvals;
+ }
+ else if ((family == AF_INET) && (h->h_addr_list == NULL) && (!strcmp("ip_address", key)))
+ {
+ addr_count = nvals;
+ h->h_addr_list = (char **)calloc(nvals + 1, addr_len);
+
+ for (j = 0; j < nvals; j++)
+ {
+ addr.s_addr = 0;
+ inet_aton(vals[j], &addr);
+ h->h_addr_list[j] = (char *)calloc(1, IPV4_ADDR_LEN);
+ memmove(h->h_addr_list[j], &(addr.s_addr), IPV4_ADDR_LEN);
+ }
+
+ h->h_addr_list[nvals] = NULL;
+ j = 0;
+ }
+ else if ((family == AF_INET6) && (h->h_addr_list == NULL) && (!strcmp("ipv6_address", key)))
+ {
+ addr_count = nvals;
+ h->h_addr_list = (char **)calloc(nvals + 1, addr_len);
+
+ for (j = 0; j < nvals; j++)
+ {
+ memset(&addr6, 0, sizeof(struct in6_addr));
+ inet_pton(family, vals[j], &addr6);
+ h->h_addr_list[j] = (char *)calloc(1, IPV6_ADDR_LEN);
+ memmove(h->h_addr_list[j], &(addr6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
+ }
+
+ h->h_addr_list[nvals] = NULL;
+ j = 0;
+ }
+ else if ((family == AF_INET6) && (mapvals == NULL) && (!strcmp("ip_address", key)))
+ {
+ map_count = nvals;
+ mapvals = vals;
+ vals = NULL;
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if ((mapvals != NULL) && (want > WANT_A6_ONLY))
+ {
+ addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
+ addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
+ addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
+
+ if (addr_count == 0)
+ {
+ h->h_addr_list = (char **)calloc(map_count + 1, addr_len);
+ }
+ else
+ {
+ h->h_addr_list = (char **)realloc(h->h_addr_list, (addr_count + map_count + 1) * addr_len);
+ }
+
+ for (i = 0; i < map_count; i++)
+ {
+ addr.s_addr = 0;
+ inet_aton(mapvals[i], &addr);
+ h->h_addr_list[addr_count] = (char *)calloc(1, IPV6_ADDR_LEN);
+ memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr.s_addr), IPV4_ADDR_LEN);
+ memcpy(h->h_addr_list[addr_count++], &(addr6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
+ }
+
+ h->h_addr_list[addr_count] = NULL;
+ }
+
+ if (mapvals != NULL)
+ {
+ for (i = 0; i < map_count; i++) free(mapvals[i]);
+ free(mapvals);
+ }
+
+ if (h->h_name == NULL) h->h_name = strdup("");
+ if (h->h_aliases == NULL) h->h_aliases = (char **)calloc(1, sizeof(char *));
+ if (h->h_addr_list == NULL) h->h_addr_list = (char **)calloc(1, sizeof(char *));
+
+ return h;
+}
+
+static struct hostent *
+copy_host(struct hostent *in)
{
int i, len, addr_len;
+ struct hostent *h;
+
+ if (in == NULL) return NULL;
- freeold();
+ h = (struct hostent *)calloc(1, sizeof(struct hostent));
- global_h.h_name = strdup(lu_h->h_names.h_names_val[0]);
+ h->h_name = LU_COPY_STRING(in->h_name);
- len = lu_h->h_names.h_names_len - 1;
- global_h.h_aliases = (char **)malloc((len + 1) * sizeof(char *));
+ len = 0;
+ if (in->h_aliases != NULL)
+ {
+ for (len = 0; in->h_aliases[len] != NULL; len++);
+ }
+ h->h_aliases = (char **)calloc(len + 1, sizeof(char *));
for (i = 0; i < len; i++)
{
- global_h.h_aliases[i] = strdup(lu_h->h_names.h_names_val[i + 1]);
+ h->h_aliases[i] = strdup(in->h_aliases[i]);
}
- global_h.h_aliases[len] = NULL;
+ h->h_addrtype = in->h_addrtype;
+ h->h_length = in->h_length;
- global_h.h_addrtype = AF_INET;
- global_h.h_length = sizeof(long);
+ len = 0;
+ if (in->h_addr_list != NULL)
+ {
+ for (len = 0; in->h_addr_list[len] != NULL; len++);
+ }
- len = lu_h->h_addrs.h_addrs_len;
addr_len = sizeof(u_long *);
+ h->h_addr_list = (char **)calloc(len + 1, addr_len);
+ for (i = 0; i < len; i++)
+ {
+ h->h_addr_list[i] = (char *)malloc(h->h_length);
+ memmove(h->h_addr_list[i], in->h_addr_list[i], h->h_length);
+ }
- global_h.h_addr_list = (char **)malloc((len + 1) * addr_len);
+ return h;
+}
- for (i = 0; i < len; i++)
+static void
+recycle_host(struct lu_thread_info *tdata, struct hostent *in)
+{
+ struct hostent *h;
+
+ if (tdata == NULL) return;
+ h = (struct hostent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ freehostent(h);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
{
- global_h.h_addr_list[i] = (char *)malloc(sizeof(long));
- bcopy((const void *)&(lu_h->h_addrs.h_addrs_val[i]),
- (void *)global_h.h_addr_list[i], sizeof(long));
+ tdata->lu_entry = in;
+ return;
}
- global_h.h_addr_list[len] = NULL;
+ free_host_data(h);
+
+ h->h_name = in->h_name;
+ h->h_aliases = in->h_aliases;
+ h->h_addrtype = in->h_addrtype;
+ h->h_length = in->h_length;
+ h->h_addr_list = in->h_addr_list;
+
+ free(in);
+}
+
+__private_extern__ struct hostent *
+fake_hostent(const char *name, struct in_addr addr)
+{
+ int addr_len;
+ struct hostent *h;
+
+ if (name == NULL) return NULL;
+
+ h = (struct hostent *)calloc(1, sizeof(struct hostent));
+
+ h->h_name = strdup(name);
+
+ h->h_aliases = (char **)calloc(1, sizeof(char *));
+
+ h->h_addrtype = AF_INET;
+ h->h_length = sizeof(long);
+
+ addr_len = sizeof(u_long *);
+ h->h_addr_list = (char **)calloc(2, addr_len);
+
+ h->h_addr_list[0] = (char *)malloc(h->h_length);
+ memmove(h->h_addr_list[0], &(addr.s_addr), h->h_length);
+
+ return h;
+}
+
+__private_extern__ struct hostent *
+fake_hostent6(const char *name, struct in6_addr addr)
+{
+ int addr_len;
+ struct hostent *h;
+
+ if (name == NULL) return NULL;
+
+ h = (struct hostent *)calloc(1, sizeof(struct hostent));
+
+ h->h_name = strdup(name);
+
+ h->h_aliases = (char **)calloc(1, sizeof(char *));
+
+ h->h_addrtype = AF_INET6;
+ h->h_length = 16;
- global_free = 0;
+ addr_len = sizeof(u_long *);
+ h->h_addr_list = (char **)calloc(2, addr_len);
+
+ h->h_addr_list[0] = (char *)malloc(h->h_length);
+ memmove(h->h_addr_list[0], &(addr.__u6_addr.__u6_addr32[0]), h->h_length);
+
+ return h;
}
static struct hostent *
-lu_gethostbyaddr(const char *addr, int len, int type)
+lu_gethostbyaddr(const char *addr, int want, int *err)
{
- unsigned datalen;
- _lu_hostent_ptr lu_h;
- XDR xdr;
- long address;
- static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
-
- if (len != sizeof(long) || (type != AF_INET))
+ struct hostent *h;
+ unsigned int datalen;
+ XDR inxdr;
+ static int proc4 = -1;
+ static int proc6 = -1;
+ char *lookup_buf, *address;
+ int proc, count, len, family;
+ struct in_addr addr4;
+ struct in6_addr addr6;
+
+ family = AF_INET;
+ len = IPV4_ADDR_LEN;
+ if (want > WANT_A4_ONLY)
{
- h_errno = HOST_NOT_FOUND;
- return (NULL);
+ family = AF_INET6;
+ len = IPV6_ADDR_LEN;
}
- if (proc < 0)
+ if ((family == AF_INET) && (proc4 < 0))
+ {
+ if (_lookup_link(_lu_port, "gethostbyaddr", &proc4) != KERN_SUCCESS)
+ {
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+ }
+ else if ((family == AF_INET6) && (proc6 < 0))
{
- if (_lookup_link(_lu_port, "gethostbyaddr", &proc) != KERN_SUCCESS)
+ if (_lookup_link(_lu_port, "getipv6nodebyaddr", &proc6) != KERN_SUCCESS)
{
- h_errno = HOST_NOT_FOUND;
- return (NULL);
+ *err = NO_RECOVERY;
+ return NULL;
}
}
- bcopy(addr, &address, sizeof(address));
- address = htonl(address);
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)&address, 1, lookup_buf, &datalen)
- != KERN_SUCCESS)
+ address = NULL;
+
+ if (family == AF_INET)
{
- h_errno = HOST_NOT_FOUND;
- return (NULL);
+ memmove(&(addr4.s_addr), addr, IPV4_ADDR_LEN);
+ addr4.s_addr = htonl(addr4.s_addr);
+ address = (char *)&(addr4.s_addr);
+ proc = proc4;
+ }
+ else
+ {
+ memmove(&(addr6.__u6_addr.__u6_addr32[0]), addr, IPV6_ADDR_LEN);
+ addr6.__u6_addr.__u6_addr32[0] = htonl(addr6.__u6_addr.__u6_addr32[0]);
+ addr6.__u6_addr.__u6_addr32[1] = htonl(addr6.__u6_addr.__u6_addr32[1]);
+ addr6.__u6_addr.__u6_addr32[2] = htonl(addr6.__u6_addr.__u6_addr32[2]);
+ addr6.__u6_addr.__u6_addr32[3] = htonl(addr6.__u6_addr.__u6_addr32[3]);
+ address = (char *)&(addr6.__u6_addr.__u6_addr32[0]);
+ proc = proc6;
+ }
+
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)address, len / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
+ {
+ *err = NO_RECOVERY;
+ return NULL;
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- lu_h = NULL;
- h_errno = HOST_NOT_FOUND;
- if (!xdr__lu_hostent_ptr(&xdr, &lu_h) ||
- !xdr_int(&xdr, &h_errno) || (lu_h == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ if (count == 0)
{
- xdr_destroy(&xdr);
- return (NULL);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ *err = HOST_NOT_FOUND;
+ return NULL;
}
- xdr_destroy(&xdr);
+ *err = 0;
+
+ h = extract_host(&inxdr, want, err);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_h(lu_h);
- xdr_free(xdr__lu_hostent_ptr, &lu_h);
- return (&global_h);
+ return h;
}
static struct hostent *
-lu_gethostbyname(const char *name)
+lu_gethostbyname(const char *name, int want, int *err)
{
- unsigned datalen;
+ struct hostent *h;
+ unsigned int datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
XDR inxdr;
- _lu_hostent_ptr lu_h;
- static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ static int proc4 = -1;
+ static int proc6 = -1;
+ char *lookup_buf;
+ int proc, count, family;
+
+ family = AF_INET;
+ if (want > WANT_A4_ONLY) family = AF_INET6;
- if (proc < 0)
+ if (((want == WANT_MAPPED_A4_ONLY) || (family == AF_INET)) && (proc4 < 0))
{
- if (_lookup_link(_lu_port, "gethostbyname", &proc) != KERN_SUCCESS)
+ if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS)
{
- h_errno = HOST_NOT_FOUND;
- return (NULL);
+ *err = NO_RECOVERY;
+ return NULL;
}
}
+ else if ((family == AF_INET6) && (proc6 < 0))
+ {
+ if (_lookup_link(_lu_port, "getipv6nodebyname", &proc6) != KERN_SUCCESS)
+ {
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+ }
+
+ proc = proc4;
+ if ((family == AF_INET6) && (want != WANT_MAPPED_A4_ONLY)) proc = proc6;
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- h_errno = HOST_NOT_FOUND;
- return (NULL);
+ *err = NO_RECOVERY;
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
- != KERN_SUCCESS)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- h_errno = HOST_NOT_FOUND;
- return (NULL);
+ *err = NO_RECOVERY;
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_h = NULL;
- h_errno = HOST_NOT_FOUND;
- if (!xdr__lu_hostent_ptr(&inxdr, &lu_h) ||
- !xdr_int(&inxdr, &h_errno) || (lu_h == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ if (count == 0)
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ *err = HOST_NOT_FOUND;
+ return NULL;
}
+ *err = 0;
+
+ h = extract_host(&inxdr, want, err);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_h(lu_h);
- xdr_free(xdr__lu_hostent_ptr, &lu_h);
- return (&global_h);
+ return h;
}
static void
lu_endhostent()
{
- h_nentries = 0;
- if (h_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)h_data, h_datalen);
- h_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
+ _lu_data_free_vm_xdr(tdata);\r
}
static void
lu_sethostent()
{
lu_endhostent();
- h_start = 1;
}
static struct hostent *
-lu_gethostent()
+lu_gethostent(int want, int *err)
{
static int proc = -1;
- _lu_hostent lu_h;
+ struct lu_thread_info *tdata;
+ struct hostent *h;
- if (h_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_host, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- h_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "gethostent", &proc) != KERN_SUCCESS)
{
lu_endhostent();
- return (NULL);
+ *err = NO_RECOVERY;
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &h_data, &h_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endhostent();
- return (NULL);
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
}
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- h_datalen *= BYTES_PER_XDR_UNIT;
-#endif
- xdrmem_create(&h_xdr, h_data, h_datalen,
- XDR_DECODE);
- if (!xdr_int(&h_xdr, &h_nentries))
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&h_xdr);
lu_endhostent();
- return (NULL);
+ *err = NO_RECOVERY;
+ return NULL;
}
}
- if (h_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&h_xdr);
lu_endhostent();
- return (NULL);
+ *err = HOST_NOT_FOUND;
+ return NULL;
}
- bzero(&lu_h, sizeof(lu_h));
- if (!xdr__lu_hostent(&h_xdr, &lu_h))
+ h = extract_host(tdata->lu_xdr, want, err);
+ if (h == NULL)
{
- xdr_destroy(&h_xdr);
lu_endhostent();
- return (NULL);
+ *err = HOST_NOT_FOUND;
+ return NULL;
}
- h_nentries--;
- convert_h(&lu_h);
- xdr_free(xdr__lu_hostent, &lu_h);
- return (&global_h);
+ *err = 0;
+ tdata->lu_vm_cursor--;
+
+ return h;
}
-struct hostent *
-gethostbyaddr(const char *addr, int len, int type)
+static struct hostent *
+gethostbyaddrerrno(const char *addr, int len, int type, int *err)
{
- struct hostent *res;
+ struct hostent *res = NULL;
+ int want;
+
+ *err = 0;
+
+ want = WANT_A4_ONLY;
+ if (type == AF_INET6) want = WANT_A6_ONLY;
if (_lu_running())
{
- res = lu_gethostbyaddr(addr, len, type);
+ res = lu_gethostbyaddr(addr, want, err);
}
else
{
- res = _res_gethostbyaddr(addr, len, type);
- if (res == NULL) res = _old_gethostbyaddr(addr, len, type);
+ pthread_mutex_lock(&_host_lock);
+ res = copy_host(_res_gethostbyaddr(addr, len, type));
+ if (res == NULL) res = copy_host(_old_gethostbyaddr(addr, len, type));
+ *err = h_errno;
+ pthread_mutex_unlock(&_host_lock);
}
- return (res);
+ return res;
}
struct hostent *
-gethostbyname(const char *name)
+gethostbyaddr(const char *addr, int len, int type)
{
- struct hostent *res;
+ struct hostent *res;
+ struct lu_thread_info *tdata;
+
+ res = gethostbyaddrerrno(addr, len, type, &h_errno);
+ if (res == NULL)
+ {
+ return NULL;
+ }
+
+ tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_host, tdata);
+ }
+
+ recycle_host(tdata, res);
+ return (struct hostent *)tdata->lu_entry;
+}
+
+struct hostent *
+gethostbynameerrno(const char *name, int *err)
+{
+ struct hostent *res = NULL;
struct in_addr addr;
+ int i, is_addr;
- if (_lu_running())
+ *err = 0;
+
+ /*
+ * If name is all dots and digits without a trailing dot,
+ * call inet_aton. If it's OK, return a fake entry.
+ * Otherwise, return an error.
+ *
+ * If name has alpha or ends with a dot, proceed as usual...
+ */
+ if (name == NULL)
+ {
+ *err = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ *err = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ is_addr = 1;
+ for (i = 0; name[i] != '\0'; i++)
{
- res = lu_gethostbyname(name);
- }
+ if (name[i] == '.') continue;
+ if ((name[i] >= '0') && (name[i] <= '9')) continue;
+ is_addr = 0;
+ break;
+ }
+
+ if ((is_addr == 1) && (name[i-1] == '.')) is_addr = 0;
+
+ if (is_addr == 1)
+ {
+ if (inet_aton(name, &addr) == 0)
+ {
+ *err = HOST_NOT_FOUND;
+ return NULL;
+ }
+ res = fake_hostent(name, addr);
+ }
+ else if (_lu_running())
+ {
+ res = lu_gethostbyname(name, WANT_A4_ONLY, err);
+ }
else
{
- res = _res_gethostbyname(name);
- if (res == NULL) res = _old_gethostbyname(name);
+ pthread_mutex_lock(&_host_lock);
+ res = copy_host(_res_gethostbyname(name));
+ if (res == NULL) res = copy_host(_old_gethostbyname(name));
+ *err = h_errno;
+ pthread_mutex_unlock(&_host_lock);
}
if (res == NULL)
{
- if (inet_aton(name, &addr) == 0) return NULL;
- return gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+ if (inet_aton(name, &addr) == 0)
+ {
+ *err = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ res = gethostbyaddrerrno((char *)&addr, sizeof(addr), AF_INET, err);
+ if (res == NULL) {
+ res = fake_hostent(name, addr);
+ }
}
- return res;
+ return res;
+}
+
+struct hostent *
+gethostbyname(const char *name)
+{
+ struct hostent *res;
+ struct lu_thread_info *tdata;
+
+ res = gethostbynameerrno(name, &h_errno);
+ if (res == NULL)
+ {
+ return NULL;
+ }
+
+ tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_host, tdata);
+ }
+
+ recycle_host(tdata, res);
+ return (struct hostent *)tdata->lu_entry;
}
struct hostent *
gethostent(void)
{
- GETENT(lu_gethostent, _old_gethostent, &h_state, struct hostent);
+ struct hostent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_host, tdata);
+ }
+
+ if (_lu_running())
+ {
+ res = lu_gethostent(WANT_A4_ONLY, &h_errno);
+ }
+ else
+ {
+ pthread_mutex_lock(&_host_lock);
+ res = copy_host(_old_gethostent());
+ pthread_mutex_unlock(&_host_lock);
+ }
+
+ recycle_host(tdata, res);
+ return (struct hostent *)tdata->lu_entry;
}
void
sethostent(int stayopen)
{
- SETSTATE(lu_sethostent, _old_sethostent, &h_state, stayopen);
+ if (_lu_running()) lu_sethostent();
+ else _old_sethostent(stayopen);
}
void
endhostent(void)
{
- UNSETSTATE(lu_endhostent, _old_endhostent, &h_state);
+ if (_lu_running()) lu_endhostent();
+ else _old_endhostent();
+}
+
+__private_extern__ int
+is_a4_mapped(const char *s)
+{
+ int i;
+ u_int8_t c;
+
+ if (s == NULL) return 0;
+
+ for (i = 0; i < 10; i++)
+ {
+ c = s[i];
+ if (c != 0x0) return 0;
+ }
+
+ for (i = 10; i < 12; i++)
+ {
+ c = s[i];
+ if (c != 0xff) return 0;
+ }
+
+ return 1;
+}
+
+__private_extern__ int
+is_a4_compat(const char *s)
+{
+ int i;
+ u_int8_t c;
+
+ if (s == NULL) return 0;
+
+ for (i = 0; i < 12; i++)
+ {
+ c = s[i];
+ if (c != 0x0) return 0;
+ }
+
+ /* Check for :: and ::1 */
+ for (i = 13; i < 15; i++)
+ {
+ /* anything non-zero in these 3 bytes means it's a V4 address */
+ c = s[i];
+ if (c != 0x0) return 1;
+ }
+
+ /* Leading 15 bytes are all zero */
+ c = s[15];
+ if (c == 0x0) return 0;
+ if (c == 0x1) return 0;
+
+ return 1;
+}
+
+struct hostent *
+getipnodebyaddr(const void *src, size_t len, int af, int *err)
+{
+ struct hostent *res;
+
+ *err = 0;
+
+ if ((af == AF_INET6) && (len == 16) && (is_a4_mapped((const char *)src) || is_a4_compat((const char *)src)))
+ {
+ src += 12;
+ len = 4;
+ af = AF_INET;
+ }
+
+ res = gethostbyaddrerrno((const char *)src, len, af, err);
+ if (res == NULL) {
+ return NULL;
+ }
+
+ if (res->h_name == NULL) {
+ freehostent(res);
+ return NULL;
+ }
+
+ return res;
+}
+
+struct hostent *
+getipnodebyname(const char *name, int af, int flags, int *err)
+{
+ int status, want, really_want, if4, if6;
+ struct hostent *res;
+ struct ifaddrs *ifa, *ifap;
+ struct in_addr addr4;
+ struct in6_addr addr6;
+
+ memset(&addr4, 0, sizeof(struct in_addr));
+ memset(&addr6, 0, sizeof(struct in6_addr));
+
+ *err = 0;
+
+ if (af == AF_INET)
+ {
+ status = inet_aton(name, &addr4);
+ if (status == 1)
+ {
+ /* return a fake hostent */
+ res = fake_hostent(name, addr4);
+ return res;
+ }
+ }
+ else if (af == AF_INET6)
+ {
+ status = inet_pton(af, name, &addr6);
+ if (status == 1)
+ {
+ /* return a fake hostent */
+ res = fake_hostent6(name, addr6);
+ return res;
+ }
+ status = inet_aton(name, &addr4);
+ if (status == 1)
+ {
+ if (!(flags & (AI_V4MAPPED|AI_V4MAPPED_CFG)))
+ {
+ *err = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
+ addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
+ addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
+ memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN);
+
+ /* return a fake hostent */
+ res = fake_hostent6(name, addr6);
+ return res;
+ }
+ }
+ else
+ {
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ /*
+ * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
+ */
+
+ if4 = 0;
+ if6 = 0;
+
+ if (flags & AI_ADDRCONFIG)
+ {
+ if (getifaddrs(&ifa) < 0)
+ {
+ *err = NO_RECOVERY;
+ return NULL;
+ }
+
+ for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
+ {
+ if (ifap->ifa_addr == NULL) continue;
+ if ((ifap->ifa_flags & IFF_UP) == 0) continue;
+ if (ifap->ifa_addr->sa_family == AF_INET) if4++;
+ else if (ifap->ifa_addr->sa_family == AF_INET6) if6++;
+ }
+
+ freeifaddrs(ifa);
+
+ /* Bail out if there are no interfaces */
+ if ((if4 == 0) && (if6 == 0))
+ {
+ *err = NO_ADDRESS;
+ return NULL;
+ }
+ }
+
+ /*
+ * Figure out what we want.
+ * If user asked for AF_INET, we only want V4 addresses.
+ */
+ want = WANT_A4_ONLY;
+ really_want = want;
+
+ if (af == AF_INET)
+ {
+ want = WANT_A4_ONLY;
+ if ((flags & AI_ADDRCONFIG) && (if4 == 0))
+ {
+ *err = NO_ADDRESS;
+ return NULL;
+ }
+ }
+ else
+ {
+ /* af == AF_INET6 */
+ want = WANT_A6_ONLY;
+ really_want = want;
+ if (flags & (AI_V4MAPPED|AI_V4MAPPED_CFG))
+ {
+ if (flags & AI_ALL)
+ {
+ want = WANT_A6_PLUS_MAPPED_A4;
+ really_want = want;
+ }
+ else
+ {
+ want = WANT_A6_ONLY;
+ really_want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
+ }
+ }
+ else
+ {
+ if ((flags & AI_ADDRCONFIG) && (if6 == 0))
+ {
+ *err = NO_ADDRESS;
+ return NULL;
+ }
+ }
+ }
+
+ res = NULL;
+
+ if (_lu_running())
+ {
+ res = lu_gethostbyname(name, want, err);
+ if ((res == NULL) &&
+ ((really_want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) ||
+ (really_want == WANT_A6_PLUS_MAPPED_A4 )))
+ {
+ res = lu_gethostbyname(name, WANT_MAPPED_A4_ONLY, err);
+ }
+ }
+ else
+ {
+ pthread_mutex_lock(&_host_lock);
+ res = copy_host(_res_gethostbyname(name));
+ if (res == NULL) res = copy_host(_old_gethostbyname(name));
+ *err = h_errno;
+ pthread_mutex_unlock(&_host_lock);
+ }
+
+ if (res == NULL)
+ {
+ *err = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ return res;
}
--- /dev/null
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * Portions Copyright (c) 2002 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.1 (the "License"). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _LU_HOST_H_
+#define _LU_HOST_H_
+
+#include <sys/cdefs.h>
+
+
+#define WANT_A4_ONLY 0
+#define WANT_A6_ONLY 1
+#define WANT_A6_PLUS_MAPPED_A4 2
+#define WANT_MAPPED_A4_ONLY 3
+
+/* ONLY TO BE USED BY getipv6nodebyaddr */
+#define WANT_A6_OR_MAPPED_A4_IF_NO_A6 -1
+
+
+__BEGIN_DECLS
+
+void free_host_data(struct hostent *h);
+struct hostent * extract_host(XDR *xdr, int want, int *err);
+struct hostent * fake_hostent(const char *name, struct in_addr addr);
+struct hostent * fake_hostent6(const char *name, struct in6_addr addr);
+int is_a4_mapped(const char *s);
+int is_a4_compat(const char *s);
+
+__END_DECLS
+
+#endif /* ! _LU_HOST_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * Portions Copyright (c) 2002 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.1 (the "License"). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <netdb.h>
+#include <netdb_async.h> /* async gethostbyXXX function prototypes */
+#include <pthread.h>
+#include <stdlib.h>
+#include <mach/mach.h>
+#include <netinfo/_lu_types.h>
+#include <netinfo/lookup.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+
+#include "lu_host.h"
+#include "lu_utils.h"
+
+extern mach_port_t _lu_port;
+extern int _lu_running(void);
+
+extern int h_errno;
+
+
+#define msgh_request_port msgh_remote_port
+#define msgh_reply_port msgh_local_port
+
+
+typedef union {
+ gethostbyaddr_async_callback hostAddr;
+ gethostbyname_async_callback hostName;
+ getipnodebyaddr_async_callback nodeAddr;
+ getipnodebyname_async_callback nodeName;
+} a_request_callout_t;
+
+typedef struct a_requests {
+ struct a_requests *next;
+ int retry;
+ struct {
+ int proc;
+ ooline_data data;
+ unsigned int dataLen;
+ int want;
+ } request;
+ mach_port_t replyPort;
+ a_request_callout_t callout;
+ void *context;
+ struct hostent *hent; /* if reply known in XXX_start() */
+} a_requests_t;
+
+static a_requests_t *a_requests = NULL;
+static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define MAX_LOOKUP_ATTEMPTS 10
+
+
+static kern_return_t
+_lookup_all_tx
+(
+ mach_port_t server,
+ int proc,
+ ooline_data indata,
+ mach_msg_type_number_t indataCnt,
+ mach_port_t *replyPort
+)
+{
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ int proc;
+ mach_msg_type_number_t indataCnt;
+ unit indata[4096];
+ } Request;
+
+ Request In;
+ register Request *InP = &In;
+ mach_msg_return_t mr;
+ unsigned int msgh_size;
+
+ if (indataCnt > 4096) {
+ return MIG_ARRAY_TOO_LARGE;
+ }
+
+ if (*replyPort == MACH_PORT_NULL) {
+ mr = mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE,
+ replyPort);
+ if (mr != KERN_SUCCESS) {
+ return mr;
+ }
+ }
+
+ msgh_size = (sizeof(Request) - 16384) + ((4 * indataCnt));
+ InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+/* InP->Head.msgh_size = msgh_size; /* msgh_size passed as argument */
+ InP->Head.msgh_request_port = server;
+ InP->Head.msgh_reply_port = *replyPort;
+ InP->Head.msgh_id = 4241776;
+ InP->NDR = NDR_record;
+ InP->proc = proc;
+ InP->indataCnt = indataCnt;
+ (void)memcpy((char *)InP->indata, (const char *)indata, 4 * indataCnt);
+
+ mr = mach_msg(&InP->Head, /* msg */
+ MACH_SEND_MSG, /* options */
+ msgh_size, /* send_size */
+ 0, /* rcv_size */
+ MACH_PORT_NULL, /* rcv_name */
+ MACH_MSG_TIMEOUT_NONE, /* timeout */
+ MACH_PORT_NULL); /* notify */
+ switch (mr) {
+ case MACH_MSG_SUCCESS :
+ mr = KERN_SUCCESS;
+ break;
+ case MACH_SEND_INVALID_REPLY :
+ (void)mach_port_destroy(mach_task_self(), *replyPort);
+ break;
+ default:
+ break;
+ }
+
+ return mr;
+}
+
+
+static kern_return_t
+_lookup_all_rx
+(
+ void *msg,
+ ooline_data *outdata,
+ mach_msg_type_number_t *outdataCnt,
+ security_token_t *token
+)
+{
+ typedef struct {
+ mach_msg_header_t Head;
+ mach_msg_body_t msgh_body;
+ mach_msg_ool_descriptor_t outdata;
+ NDR_record_t NDR;
+ mach_msg_type_number_t outdataCnt;
+ mach_msg_format_0_trailer_t trailer;
+ } Reply;
+
+ /*
+ * typedef struct {
+ * mach_msg_header_t Head;
+ * NDR_record_t NDR;
+ * kern_return_t RetCode;
+ * } mig_reply_error_t;
+ */
+
+ register Reply *OutP = msg;
+ mach_msg_format_0_trailer_t *TrailerP;
+ boolean_t msgh_simple;
+
+ if (OutP->Head.msgh_id != (4241776 + 100)) {
+ if (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
+ return MIG_SERVER_DIED;
+ else
+ return MIG_REPLY_MISMATCH;
+ }
+
+ msgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);
+
+ TrailerP = (mach_msg_format_0_trailer_t *)((vm_offset_t)OutP +
+ round_msg(OutP->Head.msgh_size));
+ if (TrailerP->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0)
+ return MIG_TRAILER_ERROR;
+
+ if (msgh_simple && ((mig_reply_error_t *)OutP)->RetCode != KERN_SUCCESS)
+ return ((mig_reply_error_t *)OutP)->RetCode;
+
+ *outdata = (ooline_data)(OutP->outdata.address);
+ *outdataCnt = OutP->outdataCnt;
+
+ *token = TrailerP->msgh_sender;
+
+ return KERN_SUCCESS;
+}
+
+
+static a_requests_t *
+request_extract(mach_port_t port)
+{
+ a_requests_t *request0, *request;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request0 = NULL;
+ request = a_requests;
+ while (request) {
+ if (port == request->replyPort) {
+ /* request found, remove from list */
+ if (request0) {
+ request0->next = request->next;
+ } else {
+ a_requests = request->next;
+ }
+ break;
+ } else {
+ /* not this request, skip to next */
+ request0 = request;
+ request = request->next;
+ }
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return request;
+}
+
+
+static void
+request_queue(a_requests_t *request)
+{
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return;
+}
+
+
+static boolean_t
+sendCannedReply(a_requests_t *request, int *error)
+{
+ /*
+ * typedef struct {
+ * mach_msg_header_t Head;
+ * NDR_record_t NDR;
+ * kern_return_t RetCode;
+ * } mig_reply_error_t;
+ */
+
+ mig_reply_error_t Out;
+ register mig_reply_error_t *OutP = &Out;
+
+ kern_return_t kr;
+ mach_msg_return_t mr;
+ unsigned int msgh_size;
+
+ /*
+ * allocate reply port
+ */
+ kr = mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE,
+ &request->replyPort);
+ if (kr != KERN_SUCCESS) {
+ *error = NO_RECOVERY;
+ return FALSE;
+ }
+
+ kr = mach_port_insert_right(mach_task_self(),
+ request->replyPort,
+ request->replyPort,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (kr != KERN_SUCCESS) {
+ (void) mach_port_destroy(mach_task_self(), request->replyPort);
+ *error = NO_RECOVERY;
+ return FALSE;
+ }
+
+ /*
+ * queue reply message
+ */
+ msgh_size = sizeof(Out);
+ OutP->Head.msgh_bits = MACH_MSGH_BITS(19, 0);
+/* OutP->Head.msgh_size = msgh_size; /* msgh_size passed as argument */
+ OutP->Head.msgh_request_port = request->replyPort;
+ OutP->Head.msgh_reply_port = MACH_PORT_NULL;
+ OutP->Head.msgh_id = 4241776 + 100;
+ OutP->RetCode = MIG_REMOTE_ERROR;
+ OutP->NDR = NDR_record;
+
+ mr = mach_msg(&OutP->Head, /* msg */
+ MACH_SEND_MSG, /* options */
+ msgh_size, /* send_size */
+ 0, /* rcv_size */
+ MACH_PORT_NULL, /* rcv_name */
+ MACH_MSG_TIMEOUT_NONE, /* timeout */
+ MACH_PORT_NULL); /* notify */
+ if (mr != MACH_MSG_SUCCESS) {
+ if (mr == MACH_SEND_INVALID_REPLY) {
+ (void)mach_port_destroy(mach_task_self(), request->replyPort);
+ }
+ *error = NO_RECOVERY;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+mach_port_t
+_gethostbyaddr_async_start(const char *addr,
+ int len,
+ int type,
+ a_request_callout_t callout,
+ void *context,
+ int *error)
+{
+ void *address;
+ int proc;
+ a_requests_t *request;
+ int want;
+
+ switch (type) {
+ case AF_INET :
+ {
+ static int proc4 = -1;
+ struct in_addr *v4addr;
+
+ if (proc4 < 0) {
+ if (_lookup_link(_lu_port, "gethostbyaddr", &proc4) != KERN_SUCCESS) {
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+ }
+
+ if (len != sizeof(struct in_addr)) {
+ *error = NO_RECOVERY;
+ return NULL;
+ }
+
+ v4addr = malloc(len);
+ memmove(v4addr, addr, len);
+ v4addr->s_addr = htonl(v4addr->s_addr);
+
+ address = (void *)v4addr;
+ proc = proc4;
+ want = WANT_A4_ONLY;
+ break;
+ }
+
+ case AF_INET6 :
+ {
+ static int proc6 = -1;
+ struct in6_addr *v6addr;
+
+ if (proc6 < 0) {
+ if (_lookup_link(_lu_port, "getipv6nodebyaddr", &proc6) != KERN_SUCCESS) {
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+ }
+
+ if (len != sizeof(struct in6_addr)) {
+ *error = NO_RECOVERY;
+ return NULL;
+ }
+
+ v6addr = malloc(len);
+ memmove(v6addr, addr, len);
+ v6addr->__u6_addr.__u6_addr32[0] = htonl(v6addr->__u6_addr.__u6_addr32[0]);
+ v6addr->__u6_addr.__u6_addr32[1] = htonl(v6addr->__u6_addr.__u6_addr32[1]);
+ v6addr->__u6_addr.__u6_addr32[2] = htonl(v6addr->__u6_addr.__u6_addr32[2]);
+ v6addr->__u6_addr.__u6_addr32[3] = htonl(v6addr->__u6_addr.__u6_addr32[3]);
+
+ address = (void *)v6addr;
+ proc = proc6;
+ want = WANT_A6_ONLY;
+ break;
+ }
+
+ default:
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ request = malloc(sizeof(a_requests_t));
+ request->next = NULL;
+ request->retry = MAX_LOOKUP_ATTEMPTS;
+ request->request.proc = proc;
+ request->request.data = (ooline_data)address;
+ request->request.dataLen = len / BYTES_PER_XDR_UNIT;
+ request->request.want = want;
+ request->replyPort = MACH_PORT_NULL;
+ request->callout = callout;
+ request->context = context;
+ request->hent = NULL;
+
+ /*
+ * allocate reply port, send query to lookupd
+ */
+ if (_lookup_all_tx(_lu_port,
+ request->request.proc,
+ request->request.data,
+ request->request.dataLen,
+ &request->replyPort) == KERN_SUCCESS) {
+ request_queue(request);
+ } else {
+ if (request->request.data) free(request->request.data);
+ free(request);
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ return request->replyPort;
+}
+
+
+boolean_t
+_gethostbyaddr_async_handleReply(void *replyMsg,
+ a_requests_t **requestP,
+ struct hostent **he,
+ int *error)
+{
+ int count;
+ ooline_data data;
+ unsigned int datalen;
+ XDR inxdr;
+ mach_msg_header_t *msg = (mach_msg_header_t *)replyMsg;
+ a_requests_t *request;
+ kern_return_t status;
+ security_token_t token;
+
+ request = request_extract(msg->msgh_local_port);
+ if (!request) {
+ /* excuse me, what happenned to the request info? */
+ return FALSE;
+ }
+
+ *requestP = request;
+ *he = NULL;
+ *error = 0;
+
+ /* unpack the reply */
+ status = _lookup_all_rx(replyMsg, &data, &datalen, &token);
+ switch (status) {
+ case KERN_SUCCESS :
+ break;
+
+ case MIG_SERVER_DIED :
+ if (--request->retry > 0) {
+ /* retry the request */
+ if (_lookup_all_tx(_lu_port,
+ request->request.proc,
+ request->request.data,
+ request->request.dataLen,
+ &request->replyPort) == KERN_SUCCESS) {
+ request_queue(request);
+ return FALSE;
+ }
+ }
+ /* fall through */
+
+ default :
+ *error = HOST_NOT_FOUND;
+ return TRUE;
+ }
+
+ datalen *= BYTES_PER_XDR_UNIT;
+
+ if (token.val[0] != 0) {
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ *error = NO_RECOVERY;
+ return TRUE;
+ }
+
+ xdrmem_create(&inxdr, data, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count)) {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ *error = NO_RECOVERY;
+ return TRUE;
+ }
+
+ if (count == 0) {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ *error = HOST_NOT_FOUND;
+ *he = NULL;
+ return TRUE;
+ }
+
+ *he = extract_host(&inxdr, request->request.want, error);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ return TRUE;
+}
+
+
+mach_port_t
+gethostbyaddr_async_start(const char *addr,
+ int len,
+ int type,
+ gethostbyaddr_async_callback callout,
+ void *context)
+{
+ a_request_callout_t cb;
+ mach_port_t mp;
+
+ if (!_lu_running()) {
+ h_errno = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ cb.hostAddr = callout;
+ mp = _gethostbyaddr_async_start(addr, len, type, cb, context, &h_errno);
+ return mp;
+}
+
+
+void
+gethostbyaddr_async_handleReply(void *replyMsg)
+{
+ int error = 0;
+ struct hostent *he = NULL;
+ a_requests_t *request = NULL;
+
+ if (_gethostbyaddr_async_handleReply(replyMsg, &request, &he, &error)) {
+ /* if we have an answer to provide */
+ h_errno = error;
+ (request->callout.hostAddr)(he, request->context);
+
+ (void)mach_port_destroy(mach_task_self(), request->replyPort);
+ if (request->request.data) free(request->request.data);
+ free(request);
+ if (he) freehostent(he);
+ }
+
+ return;
+}
+
+
+mach_port_t
+getipnodebyaddr_async_start(const void *addr,
+ size_t len,
+ int af,
+ int *error,
+ getipnodebyaddr_async_callback callout,
+ void *context)
+{
+ a_request_callout_t cb;
+ mach_port_t mp;
+
+ if (!_lu_running()) {
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ if ((af == AF_INET6) &&
+ (len == sizeof(struct in6_addr)) &&
+ (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr))) {
+ /*
+ * this is really a v4 address
+ */
+ addr += sizeof(struct in6_addr) - sizeof(struct in_addr);
+ len = sizeof(struct in_addr);
+ af = AF_INET;
+ }
+
+ cb.nodeAddr = callout;
+ mp = _gethostbyaddr_async_start(addr, len, af, cb, context, error);
+ return mp;
+}
+
+
+void
+getipnodebyaddr_async_handleReply(void *replyMsg)
+{
+ int error = 0;
+ struct hostent *he = NULL;
+ a_requests_t *request = NULL;
+
+ if (_gethostbyaddr_async_handleReply(replyMsg, &request, &he, &error)) {
+ /* if we have an answer to provide */
+ (request->callout.nodeAddr)(he, error, request->context);
+
+ (void)mach_port_destroy(mach_task_self(), request->replyPort);
+ if (request->request.data) free(request->request.data);
+ free(request);
+ /*
+ * Note: it is up to the callback function to call
+ * freehostent().
+ */
+ }
+
+ return;
+}
+
+
+mach_port_t
+_gethostbyname_async_start(const char *name,
+ int want,
+ int *error,
+ a_request_callout_t callout,
+ void *context)
+{
+ int af;
+ boolean_t is_addr = FALSE;
+ mach_port_t mp = MACH_PORT_NULL;
+ XDR outxdr;
+ static int proc;
+ a_requests_t *request;
+
+ if ((name == NULL) || (name[0] == '\0')) {
+ *error = NO_DATA;
+ return MACH_PORT_NULL;
+ }
+
+ af = (want == WANT_A4_ONLY) ? AF_INET : AF_INET6;
+
+ if ((af == AF_INET) || (want == WANT_MAPPED_A4_ONLY)) {
+ static int proc4 = -1;
+
+ if (proc4 < 0) {
+ if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS) {
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+ }
+ proc = proc4;
+ } else /* if (af == AF_INET6) */ {
+ static int proc6 = -1;
+
+ if (proc6 < 0) {
+ if (_lookup_link(_lu_port, "getipv6nodebyname", &proc6) != KERN_SUCCESS)
+ {
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+ }
+ proc = proc6;
+ }
+
+ request = malloc(sizeof(a_requests_t));
+ request->next = NULL;
+ request->retry = MAX_LOOKUP_ATTEMPTS;
+ request->request.proc = proc;
+ request->request.data = NULL;
+ request->request.dataLen = 0;
+ request->request.want = want;
+ request->replyPort = MACH_PORT_NULL;
+ request->callout = callout;
+ request->context = context;
+ request->hent = NULL;
+
+ switch (af) {
+ case AF_INET :
+ {
+ struct in_addr v4addr;
+
+ memset(&v4addr, 0, sizeof(struct in_addr));
+ if (inet_aton(name, &v4addr) == 1) {
+ /* return a fake hostent */
+ request->hent = fake_hostent(name, v4addr);
+ is_addr = TRUE;
+ }
+ break;
+ }
+
+ case AF_INET6 :
+ {
+ struct in_addr v4addr;
+ struct in6_addr v6addr;
+
+ memset(&v6addr, 0, sizeof(struct in6_addr));
+ if (inet_pton(af, name, &v6addr) == 1) {
+ /* return a fake hostent */
+ request->hent = fake_hostent6(name, v6addr);
+ is_addr = TRUE;
+ break;
+ }
+
+ memset(&v4addr, 0, sizeof(struct in_addr));
+ if (inet_aton(name, &v4addr) == 1) {
+ if (want == WANT_A4_ONLY) {
+ free(request);
+ *error = HOST_NOT_FOUND;
+ return MACH_PORT_NULL;
+ }
+
+ v6addr.__u6_addr.__u6_addr32[0] = 0x00000000;
+ v6addr.__u6_addr.__u6_addr32[1] = 0x00000000;
+ v6addr.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
+ memmove(&(v6addr.__u6_addr.__u6_addr32[3]), &(v4addr.s_addr), sizeof(struct in_addr));
+
+ /* return a fake hostent */
+ request->hent = fake_hostent6(name, v6addr);
+ is_addr = TRUE;
+ }
+ break;
+ }
+
+ default:
+ free(request);
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ if (is_addr) {
+ /*
+ * queue reply message
+ */
+ if (sendCannedReply(request, error)) {
+ request_queue(request);
+ return request->replyPort;
+ } else {
+ freehostent(request->hent);
+ free(request);
+ return MACH_PORT_NULL;
+ }
+ }
+
+ request->request.dataLen = _LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT;
+ request->request.data = malloc(request->request.dataLen);
+
+ xdrmem_create(&outxdr, request->request.data, request->request.dataLen, XDR_ENCODE);
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name)) {
+ xdr_destroy(&outxdr);
+ free(request->request.data);
+ free(request);
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ request->request.dataLen = xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT;
+
+ /*
+ * allocate reply port, send query to lookupd
+ */
+ if (_lookup_all_tx(_lu_port,
+ request->request.proc,
+ request->request.data,
+ request->request.dataLen,
+ &request->replyPort) == KERN_SUCCESS) {
+ request_queue(request);
+ mp = request->replyPort;
+ } else {
+ free(request->request.data);
+ free(request);
+ *error = NO_RECOVERY;
+ mp = NULL;
+ }
+
+ xdr_destroy(&outxdr);
+ return mp;
+}
+
+
+boolean_t
+_gethostbyname_async_handleReply(void *replyMsg,
+ a_requests_t **requestP,
+ struct hostent **he,
+ int *error)
+{
+
+ int count;
+ unsigned int datalen;
+ XDR inxdr;
+ ooline_data data;
+ mach_msg_header_t *msg = (mach_msg_header_t *)replyMsg;
+ a_requests_t *request;
+ kern_return_t status;
+ security_token_t token;
+ int want;
+
+ request = request_extract(msg->msgh_local_port);
+ if (!request) {
+ /* excuse me, what happenned to the request info? */
+ return FALSE;
+ }
+
+ *requestP = request;
+ *he = NULL;
+ *error = 0;
+
+ if (request->hent) {
+ /*
+ * if the reply was already available when the
+ * request was made
+ */
+ *he = request->hent;
+ return TRUE;
+ }
+
+ /* unpack the reply */
+ status = _lookup_all_rx(replyMsg, &data, &datalen, &token);
+ switch (status) {
+ case KERN_SUCCESS :
+ break;
+
+ case MIG_SERVER_DIED :
+ if (--request->retry > 0) {
+ /*
+ * retry the request
+ */
+ if (_lookup_all_tx(_lu_port,
+ request->request.proc,
+ request->request.data,
+ request->request.dataLen,
+ &request->replyPort) == KERN_SUCCESS) {
+ request_queue(request);
+ return FALSE;
+ }
+ }
+ /* fall through */
+
+ default :
+ *error = HOST_NOT_FOUND;
+ return TRUE;
+ }
+
+ datalen *= BYTES_PER_XDR_UNIT;
+
+ if (token.val[0] != 0) {
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ *error = NO_RECOVERY;
+ return TRUE;
+ }
+
+ xdrmem_create(&inxdr, data, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count)) {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ *error = NO_RECOVERY;
+ return TRUE;
+ }
+
+ if (count == 0) {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ *error = HOST_NOT_FOUND;
+ return TRUE;
+ }
+
+ want = request->request.want;
+ if (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) want = WANT_A6_ONLY;
+
+ *he = extract_host(&inxdr, want, error);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
+ return TRUE;
+}
+
+
+mach_port_t
+gethostbyname_async_start(const char *name,
+ gethostbyname_async_callback callout,
+ void *context)
+{
+ a_request_callout_t cb;
+ int error;
+ mach_port_t mp = MACH_PORT_NULL;
+
+ if (!_lu_running()) {
+ h_errno = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ cb.hostName = callout;
+ mp = _gethostbyname_async_start(name, WANT_A4_ONLY, &error, cb, context);
+ if (!mp) {
+ h_errno = error;
+ }
+ return mp;
+}
+
+
+void
+gethostbyname_async_handleReply(void *replyMsg)
+{
+ int error;
+ struct hostent *he;
+ a_requests_t *request;
+
+ if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error)) {
+ /* if we have an answer to provide */
+ h_errno = error;
+ (request->callout.hostAddr)(he, request->context);
+
+ (void)mach_port_destroy(mach_task_self(), request->replyPort);
+ if (request->request.data) free(request->request.data);
+ free(request);
+ if (he) freehostent(he);
+ }
+
+ return;
+}
+
+
+mach_port_t
+getipnodebyname_async_start(const char *name,
+ int af,
+ int flags,
+ int *error,
+ getipnodebyname_async_callback callout,
+ void *context)
+{
+ a_request_callout_t cb;
+ int if4 = 0;
+ int if6 = 0;
+ mach_port_t mp = MACH_PORT_NULL;
+ int want = WANT_A4_ONLY;
+
+ if (!_lu_running()) {
+ h_errno = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ /*
+ * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
+ */
+ if (flags & AI_ADDRCONFIG) {
+ struct ifaddrs *ifa, *ifap;
+
+ if (getifaddrs(&ifa) < 0) {
+ *error = NO_RECOVERY;
+ return MACH_PORT_NULL;
+ }
+
+ for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
+ if (ifap->ifa_addr == NULL)
+ continue;
+ if ((ifap->ifa_flags & IFF_UP) == 0)
+ continue;
+ if (ifap->ifa_addr->sa_family == AF_INET) {
+ if4++;
+ } else if (ifap->ifa_addr->sa_family == AF_INET6) {
+ if6++;
+ }
+ }
+
+ freeifaddrs(ifa);
+
+ /* Bail out if there are no interfaces */
+ if ((if4 == 0) && (if6 == 0)) {
+ *error = NO_ADDRESS;
+ return MACH_PORT_NULL;
+ }
+ }
+
+ /*
+ * Figure out what we want.
+ * If user asked for AF_INET, we only want V4 addresses.
+ */
+ switch (af) {
+ case AF_INET :
+ {
+ want = WANT_A4_ONLY;
+ if ((flags & AI_ADDRCONFIG) && (if4 == 0)) {
+ *error = NO_ADDRESS;
+ return MACH_PORT_NULL;
+ }
+ }
+ break;
+ case AF_INET6 :
+ {
+ want = WANT_A6_ONLY;
+ if (flags & (AI_V4MAPPED|AI_V4MAPPED_CFG)) {
+ if (flags & AI_ALL) {
+ want = WANT_A6_PLUS_MAPPED_A4;
+ } else {
+ want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
+ }
+ } else {
+ if ((flags & AI_ADDRCONFIG) && (if6 == 0)) {
+ *error = NO_ADDRESS;
+ return MACH_PORT_NULL;
+ }
+ }
+ }
+ break;
+ }
+
+ cb.nodeName = callout;
+ mp = _gethostbyname_async_start(name, want, &h_errno, cb, context);
+ return mp;
+}
+
+
+void
+getipnodebyname_async_handleReply(void *replyMsg)
+{
+ int error = 0;
+ struct hostent *he = NULL;
+ a_requests_t *request = NULL;
+
+ if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error)) {
+ /*
+ * we have an answer to provide
+ */
+ if ((he == NULL) &&
+ (error == HOST_NOT_FOUND) &&
+ ((request->request.want == WANT_A6_PLUS_MAPPED_A4) ||
+ (request->request.want == WANT_A6_OR_MAPPED_A4_IF_NO_A6))) {
+ /*
+ * no host found (yet), if requested we send a
+ * followup query to lookupd.
+ */
+ static int proc4 = -1;
+
+ if (proc4 < 0) {
+ if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS) {
+ error = NO_RECOVERY;
+ goto answer;
+ }
+ }
+
+ request->request.proc = proc4;
+ request->request.want = WANT_MAPPED_A4_ONLY;
+ if (_lookup_all_tx(_lu_port,
+ request->request.proc,
+ request->request.data,
+ request->request.dataLen,
+ &request->replyPort) == KERN_SUCCESS) {
+ request_queue(request);
+ return;
+ } else {
+ error = NO_RECOVERY;
+ }
+ }
+
+ answer :
+ (request->callout.nodeName)(he, error, request->context);
+ (void)mach_port_destroy(mach_task_self(), request->replyPort);
+ if (request->request.data) free(request->request.data);
+ free(request);
+ /*
+ * Note: it is up to the callback function to call
+ * freehostent().
+ */
+ }
+
+ return;
+}
#include "lu_utils.h"
#include "lu_overrides.h"
-#define FIX(x) ((x == NULL) ? NULL : &(x))
+#define FIX(x) ((x == NULL) ? NULL : (_lu_string *)&(x))
-static struct netgrent global_netgr;
-static int global_free = 1;
-static char *netgr_data = NULL;
-static unsigned netgr_datalen;
-static int netgr_nentries = 0;
-static int netgr_start = 1;
-static XDR netgr_xdr;
+static void
+free_netgroup_data(struct netgrent *ng)
+{
+ if (ng == NULL) return;
+
+ if (ng->ng_host != NULL) free(ng->ng_host);
+ if (ng->ng_user != NULL) free(ng->ng_user);
+ if (ng->ng_domain != NULL) free(ng->ng_domain);
+}
+
+static void
+free_netgroup(struct netgrent *ng)
+{
+ if (ng == NULL) return;
+ free_netgroup_data(ng);
+ free(ng);
+ }
static void
-freeold(void)
+free_lu_thread_info_netgroup(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_netgroup((struct netgrent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct netgrent *
+extract_netgroup(XDR *xdr)
{
- if (global_free == 1) return;
+ char *h, *u, *d;
+ struct netgrent *ng;
+
+ if (xdr == NULL) return NULL;
+
+ h = NULL;
+ u = NULL;
+ d = NULL;
+
+ if (!xdr_string(xdr, &h, LU_LONG_STRING_LENGTH))
+ {
+ return NULL;
+ }
+
+ if (!xdr_string(xdr, &u, LU_LONG_STRING_LENGTH))
+ {
+ free(h);
+ return NULL;
+ }
+
+ if (!xdr_string(xdr, &d, LU_LONG_STRING_LENGTH))
+ {
+ free(h);
+ free(u);
+ return NULL;
+ }
+
+ ng = (struct netgrent *)calloc(1, sizeof(struct netgrent));
+
+ ng->ng_host = h;
+ ng->ng_user = u;
+ ng->ng_domain = d;
+
+ return ng;
+}
+
+#ifdef NOTDEF
+static struct netgrent *
+copy_netgroup(struct netgrent *in)
+{
+ struct netgrent *ng;
+
+ if (in == NULL) return NULL;
+
+ ng = (struct group *)calloc(1, sizeof(struct netgrent));
- free(global_netgr.ng_host);
- free(global_netgr.ng_user);
- free(global_netgr.ng_domain);
+ ng->ng_host = LU_COPY_STRING(in->ng_host);
+ ng->ng_user = LU_COPY_STRING(in->ng_user);
+ ng->ng_domain = LU_COPY_STRING(in->ng_domain);
- global_free = 1;
+ return ng;
}
+#endif
static void
-convert_netgr(_lu_netgrent *lu_netgr)
+recycle_netgroup(struct lu_thread_info *tdata, struct netgrent *in)
{
- freeold();
+ struct netgrent *ng;
+
+ if (tdata == NULL) return;
+ ng = (struct netgrent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_netgroup(ng);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
- global_netgr.ng_host = strdup(lu_netgr->ng_host);
- global_netgr.ng_user = strdup(lu_netgr->ng_user);
- global_netgr.ng_domain = strdup(lu_netgr->ng_domain);
+ free_netgroup_data(ng);
- global_free = 0;
+ ng->ng_host = in->ng_host;
+ ng->ng_user = in->ng_user;
+ ng->ng_domain = in->ng_domain;
+
+ free(in);
}
int size;
int res;
_lu_innetgr_args args;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
if (proc < 0)
{
if (_lookup_link(_lu_port, "innetgr", &proc) != KERN_SUCCESS)
{
- return (0);
+ return 0;
}
}
if (!xdr__lu_innetgr_args(&xdr, &args))
{
xdr_destroy(&xdr);
- return (0);
+ return 0;
}
size = xdr_getpos(&xdr) / BYTES_PER_XDR_UNIT;
xdr_destroy(&xdr);
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf, size, lookup_buf,
- &datalen) != KERN_SUCCESS)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf, size, &lookup_buf, &datalen) != KERN_SUCCESS)
{
- return (0);
+ return 0;
}
datalen *= BYTES_PER_XDR_UNIT;
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
if (!xdr_int(&xdr, &res))
{
xdr_destroy(&xdr);
- return (0);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return 0;
}
xdr_destroy(&xdr);
- return (res);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+
+ return res;
}
static void
lu_endnetgrent(void)
{
- netgr_nentries = 0;
- if (netgr_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)netgr_data, netgr_datalen);
- netgr_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_netgroup, free_lu_thread_info_netgroup);
+ _lu_data_free_vm_xdr(tdata);
}
+
/*
* This is different than the other setXXXent routines
* since this is really more like getnetgrbyname() than
* getnetgrent().
*/
static void
-lu_setnetgrent(const char *group)
+lu_setnetgrent(const char *name)
{
unsigned datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
static int proc = -1;
+ struct lu_thread_info *tdata;
+ tdata = _lu_data_create_key(_lu_data_key_netgroup, free_lu_thread_info_netgroup);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_netgroup, tdata);
+ }
+\r
lu_endnetgrent();
if (proc < 0)
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &group))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
lu_endnetgrent();
return;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_all(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT,
- &netgr_data, &netgr_datalen) != KERN_SUCCESS)
+ datalen = xdr_getpos(&outxdr);
+ xdr_destroy(&outxdr);
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf, datalen / BYTES_PER_XDR_UNIT, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
- xdr_destroy(&outxdr);
lu_endnetgrent();
return;
}
- xdr_destroy(&outxdr);
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- netgr_datalen *= BYTES_PER_XDR_UNIT;
-#endif
-
- xdrmem_create(&netgr_xdr, netgr_data,
- netgr_datalen, XDR_DECODE);
- if (!xdr_int(&netgr_xdr, &netgr_nentries))
- {
- xdr_destroy(&netgr_xdr);
- lu_endnetgrent();
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
}
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor)) lu_endnetgrent();
}
struct netgrent *
lu_getnetgrent(void)
{
- _lu_netgrent lu_netgr;
+ struct netgrent *ng;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_netgroup, free_lu_thread_info_netgroup);
+ if (tdata == NULL) return NULL;
- if (netgr_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&netgr_xdr);
lu_endnetgrent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_netgr, sizeof(lu_netgr));
- if (!xdr__lu_netgrent(&netgr_xdr, &lu_netgr))
+ ng = extract_netgroup(tdata->lu_xdr);
+ if (ng == NULL)
{
- xdr_destroy(&netgr_xdr);
lu_endnetgrent();
- return (NULL);
+ return NULL;
}
- netgr_nentries--;
- convert_netgr(&lu_netgr);
- xdr_free(xdr__lu_netgrent, &lu_netgr);
- return (&global_netgr);
+ tdata->lu_vm_cursor--;
+
+ return ng;
}
int
const char *domain)
{
if (_lu_running()) return (lu_innetgr(group, host, user, domain));
-// return (_old_innetgr(group, host, user, domain));
- return (0);
+ return 0;
}
struct netgrent *
getnetgrent(void)
{
- if (_lu_running()) return (lu_getnetgrent());
-// return (_old_getnetgrent());
- return (NULL);
+ struct netgrent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_netgroup, free_lu_thread_info_netgroup);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_netgroup, tdata);
+ }
+
+ res = NULL;
+ if (_lu_running()) res = lu_getnetgrent();
+
+ recycle_netgroup(tdata, res);
+ return (struct netgrent *)tdata->lu_entry;
}
void
-setnetgrent(const char *group)
+setnetgrent(const char *name)
{
- if (_lu_running()) lu_setnetgrent(group);
-// else _old_setnetgrent(group);
+ if (_lu_running()) lu_setnetgrent(name);
}
void
endnetgrent(void)
{
if (_lu_running()) lu_endnetgrent();
-// else _old_endnetgrent();
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <mach/mach.h>
#include <stdio.h>
#include <string.h>
-#include "lookup.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
-#include "_lu_types.h"
#include <netdb.h>
-#include "lu_utils.h"
#include <sys/socket.h>
-#import <netinet/in.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+
+#include "_lu_types.h"
+#include "lookup.h"
+#include "lu_utils.h"
+
+static pthread_mutex_t _network_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define N_GET_NAME 1
+#define N_GET_ADDR 2
+#define N_GET_ENT 3
extern struct netent *_res_getnetbyaddr();
extern struct netent *_res_getnetbyname();
extern void _old_setnetent();
extern void _old_endnetent();
-static lookup_state n_state = LOOKUP_CACHE;
-static struct netent global_n;
-static int global_free = 1;
-static char *n_data = NULL;
-static unsigned n_datalen;
-static int n_nentries;
-static int n_start = 1;
-static XDR n_xdr;
+extern mach_port_t _lu_port;
+extern int _lu_running(void);
static void
-freeold(void)
+free_network_data(struct netent *n)
{
char **aliases;
- if (global_free == 1) return;
+ if (n == NULL) return;
- free(global_n.n_name);
+ free(n->n_name);
- aliases = global_n.n_aliases;
+ aliases = n->n_aliases;
if (aliases != NULL)
{
while (*aliases != NULL) free(*aliases++);
- free(global_n.n_aliases);
+ free(n->n_aliases);
}
+}
- global_free = 1;
+static void
+free_network(struct netent *n)
+{
+ if (n == NULL) return;
+ free_network_data(n);
+ free(n);
}
static void
-convert_n(_lu_netent *lu_n)
+free_lu_thread_info_network(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_network((struct netent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct netent *
+extract_network(XDR *xdr)
+{
+ struct netent *n;
+ int i, j, nvals, nkeys, status;
+ char *key, **vals;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ n = (struct netent *)calloc(1, sizeof(struct netent));
+
+ n->n_addrtype = AF_INET;
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_network(n);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((n->n_name == NULL) && (!strcmp("name", key)))
+ {
+ n->n_name = vals[0];
+ if (nvals > 1)
+ {
+ n->n_aliases = (char **)calloc(nvals, sizeof(char *));
+ for (j = 1; j < nvals; j++) n->n_aliases[j-1] = vals[j];
+ }
+ j = nvals;
+ }
+ else if (!strcmp("address", key))
+ {
+ n->n_net = inet_network(vals[0]);
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if (n->n_name == NULL) n->n_name = strdup("");
+ if (n->n_aliases == NULL) n->n_aliases = (char **)calloc(1, sizeof(char *));
+
+ return n;
+}
+
+static struct netent *
+copy_network(struct netent *in)
{
int i, len;
+ struct netent *n;
- freeold();
+ if (in == NULL) return NULL;
- global_n.n_name = strdup(lu_n->n_names.n_names_val[0]);
+ n = (struct netent *)calloc(1, sizeof(struct netent));
- len = lu_n->n_names.n_names_len - 1;
- global_n.n_aliases = malloc((len + 1) * sizeof(char *));
+ n->n_name = LU_COPY_STRING(in->n_name);
+ len = 0;
+ if (in->n_aliases != NULL)
+ {
+ for (len = 0; in->n_aliases[len] != NULL; len++);
+ }
+
+ n->n_aliases = (char **)calloc(len + 1, sizeof(char *));
for (i = 0; i < len; i++)
{
- global_n.n_aliases[i] = strdup(lu_n->n_names.n_names_val[i + 1]);
+ n->n_aliases[i] = strdup(in->n_aliases[i]);
+ }
+
+ n->n_addrtype = in->n_addrtype;
+ n->n_net = in->n_net;
+
+ return n;
+}
+
+static void
+recycle_network(struct lu_thread_info *tdata, struct netent *in)
+{
+ struct netent *n;
+
+ if (tdata == NULL) return;
+ n = (struct netent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_network(n);
+ tdata->lu_entry = NULL;
}
- global_n.n_aliases[len] = NULL;
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
- global_n.n_addrtype = AF_INET;
- global_n.n_net = lu_n->n_net;
+ free_network_data(n);
- global_free = 0;
+ n->n_name = in->n_name;
+ n->n_aliases = in->n_aliases;
+ n->n_addrtype = in->n_addrtype;
+ n->n_net = in->n_net;
+
+ free(in);
}
static struct netent *
lu_getnetbyaddr(long addr, int type)
{
+ struct netent *n;
unsigned datalen;
- _lu_netent_ptr lu_n;
- XDR xdr;
+ XDR inxdr;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
-
- if (type != AF_INET)
- {
- return (NULL);
- }
+ char *lookup_buf;
+ int count;
+
+ if (type != AF_INET) return NULL;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getnetbyaddr", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
addr = htonl(addr);
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)&addr, 1, lookup_buf, &datalen)
- != KERN_SUCCESS)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)&addr, 1, &lookup_buf, &datalen) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- lu_n = NULL;
- if (!xdr__lu_netent_ptr(&xdr, &lu_n) || (lu_n == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
- xdr_destroy(&xdr);
- return (NULL);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
- xdr_destroy(&xdr);
+ n = extract_network(&inxdr);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_n(lu_n);
- xdr_free(xdr__lu_netent_ptr, &lu_n);
- return (&global_n);
+ return n;
}
static struct netent *
lu_getnetbyname(const char *name)
{
+ struct netent *n;
unsigned datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
XDR inxdr;
- _lu_netent_ptr lu_n;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getnetbyname", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_n = NULL;
- if (!xdr__lu_netent_ptr(&inxdr, &lu_n) || (lu_n == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ n = extract_network(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_n(lu_n);
- xdr_free(xdr__lu_netent_ptr, &lu_n);
- return (&global_n);
+ return n;
}
static void
lu_endnetent()
{
- n_nentries = 0;
- if (n_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)n_data, n_datalen);
- n_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_network, free_lu_thread_info_network);
+ _lu_data_free_vm_xdr(tdata);\r
}
static void
lu_setnetent()
{
lu_endnetent();
- n_start = 1;
}
static struct netent *
lu_getnetent()
{
static int proc = -1;
- _lu_netent lu_n;
+ struct lu_thread_info *tdata;
+ struct netent *n;
- if (n_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_network, free_lu_thread_info_network);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_network, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- n_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "getnetent", &proc) != KERN_SUCCESS)
{
lu_endnetent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &n_data, &n_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endnetent();
- return (NULL);
+ return NULL;
+ }
+
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
}
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- n_datalen *= BYTES_PER_XDR_UNIT;
-#endif
- xdrmem_create(&n_xdr, n_data, n_datalen,
- XDR_DECODE);
- if (!xdr_int(&n_xdr, &n_nentries))
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&n_xdr);
lu_endnetent();
- return (NULL);
+ return NULL;
}
}
- if (n_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&n_xdr);
lu_endnetent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_n, sizeof(lu_n));
- if (!xdr__lu_netent(&n_xdr, &lu_n))
+ n = extract_network(tdata->lu_xdr);
+ if (n == NULL)
{
- xdr_destroy(&n_xdr);
lu_endnetent();
- return (NULL);
+ return NULL;
}
- n_nentries--;
- convert_n(&lu_n);
- xdr_free(xdr__lu_netent, &lu_n);
- return (&global_n);
+ tdata->lu_vm_cursor--;
+
+ return n;
}
-struct netent *
-getnetbyaddr(long addr, int type)
+static struct netent *
+getnet(const char *name, long addr, int type, int source)
{
- struct netent *res;
+ struct netent *res = NULL;
+ struct lu_thread_info *tdata;
- if (_lu_running())
+ tdata = _lu_data_create_key(_lu_data_key_network, free_lu_thread_info_network);
+ if (tdata == NULL)
{
- res = lu_getnetbyaddr(addr, type);
- }
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_network, tdata);
+ }
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case N_GET_NAME:
+ res = lu_getnetbyname(name);
+ break;
+ case N_GET_ADDR:
+ res = lu_getnetbyaddr(addr, type);
+ break;
+ case N_GET_ENT:
+ res = lu_getnetent();
+ break;
+ default: res = NULL;
+ }
+ }
else
{
- res = _res_getnetbyaddr(addr, type);
- if (res == NULL) res = _old_getnetbyaddr(addr, type);
- }
+ pthread_mutex_lock(&_network_lock);
+ switch (source)
+ {
+ case N_GET_NAME:
+ res = copy_network(_old_getnetbyname(name));
+ break;
+ case N_GET_ADDR:
+ res = copy_network(_old_getnetbyaddr(addr, type));
+ break;
+ case N_GET_ENT:
+ res = copy_network(_old_getnetent());
+ break;
+ default: res = NULL;
+ }
+ pthread_mutex_unlock(&_network_lock);
+ }
- return res;
+ recycle_network(tdata, res);
+ return (struct netent *)tdata->lu_entry;
}
struct netent *
-getnetbyname(const char *name)
+getnetbyaddr(long addr, int type)
{
- struct netent *res;
-
- if (_lu_running())
- {
- res = lu_getnetbyname(name);
- }
- else
- {
- res = _res_getnetbyname(name);
- if (res == NULL) res = _old_getnetbyname(name);
- }
+ return getnet(NULL, addr, type, N_GET_ADDR);
+}
- return res;
+struct netent *
+getnetbyname(const char *name)
+{
+ return getnet(name, 0, 0, N_GET_NAME);
}
struct netent *
getnetent(void)
{
- GETENT(lu_getnetent, _old_getnetent, &n_state, struct netent);
+ return getnet(NULL, 0, 0, N_GET_ENT);
}
void
setnetent(int stayopen)
{
- SETSTATE(lu_setnetent, _old_setnetent, &n_state, stayopen);
+ if (_lu_running()) lu_setnetent();
+ else _old_setnetent(stayopen);
}
void
endnetent(void)
{
- UNSETSTATE(lu_endnetent, _old_endnetent, &n_state);
+ if (_lu_running()) lu_endnetent();
+ else _old_endnetent();
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <mach/mach.h>
#include <stdio.h>
#include <string.h>
-#include "lookup.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
+#include <pthread.h>
+
#include "_lu_types.h"
+#include "lookup.h"
#include "printerdb.h"
#include "lu_utils.h"
-extern struct prdb_ent *_old_prdb_get();
-extern struct prdb_ent *_old_prdb_getbyname();
+static pthread_mutex_t _printer_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define P_GET_NAME 1
+#define P_GET_ENT 2
+
+extern prdb_ent *_old_prdb_get();
+extern prdb_ent *_old_prdb_getbyname();
extern void _old_prdb_set();
extern void _old_prdb_end();
-static lookup_state prdb_state = LOOKUP_CACHE;
-static struct prdb_ent global_prdb;
-static int global_free = 1;
-static char *prdb_data = NULL;
-static unsigned prdb_datalen = 0;
-static int prdb_nentries;
-static int prdb_start = 1;
-static XDR prdb_xdr = { 0 };
-
static void
-freeold(void)
+free_printer_data(prdb_ent *p)
{
char **names;
int i;
- if (global_free == 1) return;
+ if (p == NULL) return;
- names = global_prdb.pe_name;
+ names = p->pe_name;
if (names != NULL)
{
while (*names) free(*names++);
- free(global_prdb.pe_name);
+ free(p->pe_name);
}
- for (i = 0; i < global_prdb.pe_nprops; i++)
+ for (i = 0; i < p->pe_nprops; i++)
{
- free(global_prdb.pe_prop[i].pp_key);
- free(global_prdb.pe_prop[i].pp_value);
+ free(p->pe_prop[i].pp_key);
+ free(p->pe_prop[i].pp_value);
}
- free(global_prdb.pe_prop);
-
- global_free = 1;
+ free(p->pe_prop);
}
+static void
+free_printer(prdb_ent *p)
+{
+ if (p == NULL) return;
+ free_printer_data(p);
+ free(p);
+}
static void
-convert_prdb(_lu_prdb_ent *lu_prdb)
+free_lu_thread_info_printer(void *x)
{
- int i, len;
+ struct lu_thread_info *tdata;
- freeold();
+ if (x == NULL) return;
- len = lu_prdb->pe_names.pe_names_len;
- global_prdb.pe_name = (char **)malloc((len + 1) * sizeof(char *));
- for (i = 0; i < len; i++)
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
{
- global_prdb.pe_name[i] = strdup(lu_prdb->pe_names.pe_names_val[i]);
+ free_printer((prdb_ent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
}
- global_prdb.pe_name[len] = NULL;
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static prdb_ent *
+extract_printer(XDR *xdr)
+{
+ prdb_ent *p;
+ int i, j, nvals, nkeys, status;
+ char *key, **vals;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
- len = lu_prdb->pe_props.pe_props_len;
- global_prdb.pe_prop = (prdb_property *)malloc(len * sizeof(prdb_property));
- for (i = 0; i < len; i++)
+ p = (prdb_ent *)calloc(1, sizeof(prdb_ent));
+
+ for (i = 0; i < nkeys; i++)
{
- global_prdb.pe_prop[i].pp_key =
- strdup(lu_prdb->pe_props.pe_props_val[i].pp_key);
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_printer(p);
+ return NULL;
+ }
+
+ j = 0;
- global_prdb.pe_prop[i].pp_value =
- strdup(lu_prdb->pe_props.pe_props_val[i].pp_value);
+ if ((p->pe_name == NULL) && (!strcmp("name", key)))
+ {
+ free(key);
+ p->pe_name = vals;
+ j = nvals;
+ vals = NULL;
+ }
+ else
+ {
+ if (p->pe_nprops == 0)
+ {
+ p->pe_prop = (prdb_property *)calloc(1, sizeof(prdb_property));
+ }
+ else
+ {
+ p->pe_prop = (prdb_property *)realloc(p->pe_prop, (p->pe_nprops + 1) * sizeof(prdb_property));
+ }
+ p->pe_prop[p->pe_nprops].pp_key = key;
+ p->pe_prop[p->pe_nprops].pp_value = NULL;
+ if (nvals > 0)
+ {
+ p->pe_prop[p->pe_nprops].pp_value = vals[0];
+ j = 1;
+ }
+ else
+ {
+ p->pe_prop[p->pe_nprops].pp_value = strdup("");
+ }
+ p->pe_nprops++;
+ }
+
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
}
- global_prdb.pe_nprops = lu_prdb->pe_props.pe_props_len;
+ if (p->pe_name == NULL) p->pe_name = (char **)calloc(1, sizeof(char *));
+ if (p->pe_prop == NULL) p->pe_prop = (prdb_property *)calloc(1, sizeof(prdb_property));
- global_free = 0;
+ return p;
}
-static void
-lu_prdb_end()
+static prdb_ent *
+copy_printer(prdb_ent *in)
{
- prdb_nentries = 0;
- if (prdb_data != NULL)
+ int i;
+ prdb_ent *p;
+
+ if (in == NULL) return NULL;
+
+ p = (prdb_ent *)calloc(1, sizeof(prdb_ent));
+
+ if (in->pe_name != NULL)
+ {
+ for (i = 0; in->pe_name[i] != NULL; i++);
+ p->pe_name = (char **)calloc(i, sizeof(char *));
+ for (i = 0; p->pe_name[i] != NULL; i++) p->pe_name[i] = strdup(in->pe_name[i]);
+ }
+ else
+ {
+ p->pe_name = (char **)calloc(1, sizeof(char *));
+ }
+
+ if (in->pe_nprops > 0)
{
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)prdb_data, prdb_datalen);
- prdb_data = NULL;
+ p->pe_prop = (struct prdb_property *)calloc(in->pe_nprops, sizeof(struct prdb_property));
+
+ for (i = 0; in->pe_nprops; i++)
+ {
+ p->pe_prop[i].pp_key = strdup(in->pe_prop[i].pp_key);
+ p->pe_prop[i].pp_value = NULL;
+ if (in->pe_prop[i].pp_value != NULL) p->pe_prop[i].pp_value = strdup(in->pe_prop[i].pp_value);
+ }
}
+ else
+ {
+ p->pe_prop = (prdb_property *)calloc(1, sizeof(prdb_property));
+ }
+
+ return p;
}
static void
-lu_prdb_set()
+recycle_printer(struct lu_thread_info *tdata, struct prdb_ent *in)
{
- lu_prdb_end();
- prdb_start = 1;
+ struct prdb_ent *p;
+
+ if (tdata == NULL) return;
+ p = (struct prdb_ent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_printer(p);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
+
+ free_printer_data(p);
+
+ p->pe_name = in->pe_name;
+ p->pe_nprops = in->pe_nprops;
+ p->pe_prop = in->pe_prop;
+
+ free(in);
}
-static struct prdb_ent *
+static prdb_ent *
lu_prdb_getbyname(const char *name)
{
+ prdb_ent *p;
unsigned datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
XDR inxdr;
- _lu_prdb_ent_ptr lu_prdb;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "prdb_getbyname", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
- != KERN_SUCCESS)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_prdb = NULL;
- if (!xdr__lu_prdb_ent_ptr(&inxdr, &lu_prdb) || (lu_prdb == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ p = extract_printer(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+
+ return p;
+}
- convert_prdb(lu_prdb);
- xdr_free(xdr__lu_prdb_ent_ptr, &lu_prdb);
- return (&global_prdb);
+static void
+lu_prdb_end()
+{
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_printer, free_lu_thread_info_printer);
+ _lu_data_free_vm_xdr(tdata);
+}
+
+static void
+lu_prdb_set()
+{
+ lu_prdb_end();
}
static prdb_ent *
lu_prdb_get()
{
+ prdb_ent *p;
static int proc = -1;
- _lu_prdb_ent lu_prdb;
+ struct lu_thread_info *tdata;
- if (prdb_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_printer, free_lu_thread_info_printer);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_printer, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- prdb_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "prdb_get", &proc) != KERN_SUCCESS)
{
lu_prdb_end();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &prdb_data, &prdb_datalen)
- != KERN_SUCCESS)
+
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_prdb_end();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- prdb_datalen *= BYTES_PER_XDR_UNIT;
-#endif
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
- xdrmem_create(&prdb_xdr, prdb_data, prdb_datalen,
- XDR_DECODE);
- if (!xdr_int(&prdb_xdr, &prdb_nentries))
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&prdb_xdr);
lu_prdb_end();
- return (NULL);
+ return NULL;
}
}
- if (prdb_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&prdb_xdr);
lu_prdb_end();
- return (NULL);
+ return NULL;
}
- bzero(&lu_prdb, sizeof(lu_prdb));
- if (!xdr__lu_prdb_ent(&prdb_xdr, &lu_prdb))
+ p = extract_printer(tdata->lu_xdr);
+ if (p == NULL)
{
- xdr_destroy(&prdb_xdr);
lu_prdb_end();
- return (NULL);
+ return NULL;
+ }
+
+ tdata->lu_vm_cursor--;
+
+ return p;
+}
+
+static prdb_ent *
+getprinter(const char *name, int source)
+{
+ prdb_ent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_printer, free_lu_thread_info_printer);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_printer, tdata);
+ }
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case P_GET_NAME:
+ res = lu_prdb_getbyname(name);
+ break;
+ case P_GET_ENT:
+ res = lu_prdb_get();
+ break;
+ default: res = NULL;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock(&_printer_lock);
+ switch (source)
+ {
+ case P_GET_NAME:
+ res = copy_printer(_old_prdb_getbyname(name));
+ break;
+ case P_GET_ENT:
+ res = copy_printer(_old_prdb_get());
+ break;
+ default: res = NULL;
+ }
+ pthread_mutex_unlock(&_printer_lock);
}
- prdb_nentries--;
- convert_prdb(&lu_prdb);
- xdr_free(xdr__lu_prdb_ent, &lu_prdb);
- return (&global_prdb);
+ recycle_printer(tdata, res);
+ return (prdb_ent *)tdata->lu_entry;
}
const prdb_ent *
prdb_getbyname(const char *name)
{
- LOOKUP1(lu_prdb_getbyname, _old_prdb_getbyname, name, prdb_ent);
+ return (const prdb_ent *)getprinter(name, P_GET_NAME);
}
const prdb_ent *
prdb_get(void)
{
- GETENT(lu_prdb_get, _old_prdb_get, &prdb_state, prdb_ent);
+ return (const prdb_ent *)getprinter(NULL, P_GET_ENT);
}
void
prdb_set(const char *name)
{
- SETSTATE(lu_prdb_set, _old_prdb_set, &prdb_state, name);
+ if (_lu_running()) lu_prdb_set();
+ else _old_prdb_set();
}
void
prdb_end(void)
{
- UNSETSTATE(lu_prdb_end, _old_prdb_end, &prdb_state);
+ if (_lu_running()) lu_prdb_end();
+ else _old_prdb_end();
}
#include <mach/mach.h>
#include <stdio.h>
#include <string.h>
-#include "lookup.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
-#include "_lu_types.h"
#include <netdb.h>
+#include <netinet/in.h>
+
+#include "_lu_types.h"
+#include "lookup.h"
#include "lu_utils.h"
-#import <netinet/in.h>
extern struct protoent *_old_getprotobynumber();
extern struct protoent *_old_getprotobyname();
extern void _old_setprotoent();
extern void _old_endprotoent();
-static lookup_state p_state = LOOKUP_CACHE;
-static struct protoent global_p;
-static int global_free = 1;
-static char *p_data = NULL;
-static unsigned p_datalen;
-static int p_nentries;
-static int p_start;
-static XDR p_xdr;
+#define PROTO_GET_NAME 1
+#define PROTO_GET_NUM 2
+#define PROTO_GET_ENT 3
static void
-freeold(void)
+free_protocol_data(struct protoent *p)
{
char **aliases;
- if (global_free == 1) return;
+ if (p == NULL) return;
- free(global_p.p_name);
- aliases = global_p.p_aliases;
+ if (p->p_name != NULL) free(p->p_name);
+ aliases = p->p_aliases;
if (aliases != NULL)
{
while (*aliases != NULL) free(*aliases++);
- free(global_p.p_aliases);
+ free(p->p_aliases);
}
+}
- global_free = 1;
+static void
+free_protocol(struct protoent *p)
+{
+ if (p == NULL) return;
+ free_protocol_data(p);
+ free(p);
}
static void
-convert_p(_lu_protoent *lu_p)
+free_lu_thread_info_protocol(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_protocol((struct protoent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct protoent *
+extract_protocol(XDR *xdr)
+{
+ struct protoent *p;
+ int i, j, nvals, nkeys, status;
+ char *key, **vals;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ p = (struct protoent *)calloc(1, sizeof(struct protoent));
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_protocol(p);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((p->p_name == NULL) && (!strcmp("name", key)))
+ {
+ p->p_name = vals[0];
+ if (nvals > 1)
+ {
+ p->p_aliases = (char **)calloc(nvals, sizeof(char *));
+ for (j = 1; j < nvals; j++) p->p_aliases[j-1] = vals[j];
+ }
+ j = nvals;
+ }
+ else if (!strcmp("number", key))
+ {
+ p->p_proto = atoi(vals[0]);
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if (p->p_name == NULL) p->p_name = strdup("");
+ if (p->p_aliases == NULL) p->p_aliases = (char **)calloc(1, sizeof(char *));
+
+ return p;
+}
+
+static struct protoent *
+copy_protocol(struct protoent *in)
{
int i, len;
+ struct protoent *p;
- freeold();
+ if (in == NULL) return NULL;
- global_p.p_name = strdup(lu_p->p_names.p_names_val[0]);
+ p = (struct protoent *)calloc(1, sizeof(struct protoent));
- len = lu_p->p_names.p_names_len - 1;
- global_p.p_aliases = (char **)malloc((len + 1) * sizeof(char *));
+ p->p_proto = in->p_proto;
+ p->p_name = LU_COPY_STRING(in->p_name);
+
+ len = 0;
+ if (in->p_aliases != NULL)
+ {
+ for (len = 0; in->p_aliases[len] != NULL; len++);
+ }
+ p->p_aliases = (char **)calloc(len + 1, sizeof(char *));
for (i = 0; i < len; i++)
{
- global_p.p_aliases[i] = strdup(lu_p->p_names.p_names_val[i+1]);
+ p->p_aliases[i] = strdup(in->p_aliases[i]);
}
- global_p.p_aliases[len] = NULL;
+ return p;
+}
+
+static void
+recycle_protocol(struct lu_thread_info *tdata, struct protoent *in)
+{
+ struct protoent *p;
- global_p.p_proto = lu_p->p_proto;
+ if (tdata == NULL) return;
+ p = (struct protoent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_protocol(p);
+ tdata->lu_entry = NULL;
+ }
- global_free = 0;
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
+
+ free_protocol_data(p);
+
+ p->p_proto = in->p_proto;
+ p->p_name = in->p_name;
+ p->p_aliases = in->p_aliases;
+
+ free(in);
}
static struct protoent *
lu_getprotobynumber(long number)
{
- unsigned datalen;
- _lu_protoent_ptr lu_p;
- XDR xdr;
+ struct protoent *p;
+ unsigned int datalen;
+ XDR inxdr;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
-
+ char *lookup_buf;
+ int count;
+
if (proc < 0)
{
if (_lookup_link(_lu_port, "getprotobynumber", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
number = htonl(number);
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)&number, 1, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)&number, 1, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_p = NULL;
- if (!xdr__lu_protoent_ptr(&xdr, &lu_p) || (lu_p == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
- xdr_destroy(&xdr);
- return (NULL);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
- xdr_destroy(&xdr);
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
- convert_p(lu_p);
- xdr_free(xdr__lu_protoent_ptr, &lu_p);
- return (&global_p);
+ p = extract_protocol(&inxdr);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+
+ return p;
}
static struct protoent *
lu_getprotobyname(const char *name)
{
- unsigned datalen;
+ struct protoent *p;
+ unsigned int datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
XDR inxdr;
- _lu_protoent_ptr lu_p;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getprotobyname", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_p = NULL;
- if (!xdr__lu_protoent_ptr(&inxdr, &lu_p) || (lu_p == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ p = extract_protocol(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_p(lu_p);
- xdr_free(xdr__lu_protoent_ptr, &lu_p);
- return (&global_p);
+ return p;
}
static void
lu_endprotoent()
{
- p_nentries = 0;
- if (p_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)p_data, p_datalen);
- p_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_protocol);
+ _lu_data_free_vm_xdr(tdata);
}
static void
lu_setprotoent()
{
lu_endprotoent();
- p_start = 1;
}
+
static struct protoent *
lu_getprotoent()
{
+ struct protoent *p;
static int proc = -1;
- _lu_protoent lu_p;
+ struct lu_thread_info *tdata;
- if (p_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_protocol, free_lu_thread_info_protocol);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_protocol, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- p_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "getprotoent", &proc) != KERN_SUCCESS)
{
lu_endprotoent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &p_data, &p_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endprotoent();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- p_datalen *= BYTES_PER_XDR_UNIT;
-#endif
- xdrmem_create(&p_xdr, p_data, p_datalen,
- XDR_DECODE);
- if (!xdr_int(&p_xdr, &p_nentries))
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&p_xdr);
lu_endprotoent();
- return (NULL);
+ return NULL;
}
}
- if (p_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&p_xdr);
lu_endprotoent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_p, sizeof(lu_p));
- if (!xdr__lu_protoent(&p_xdr, &lu_p))
+ p = extract_protocol(tdata->lu_xdr);
+ if (p == NULL)
{
- xdr_destroy(&p_xdr);
lu_endprotoent();
- return (NULL);
+ return NULL;
}
- p_nentries--;
- convert_p(&lu_p);
- xdr_free(xdr__lu_protoent, &lu_p);
- return (&global_p);
+ tdata->lu_vm_cursor--;
+
+ return p;
}
-struct protoent *
-getprotobynumber(int number)
+static struct protoent *
+getproto(const char *name, int number, int source)
{
- LOOKUP1(lu_getprotobynumber, _old_getprotobynumber, number,
- struct protoent);
+ struct protoent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_protocol, free_lu_thread_info_protocol);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_protocol, tdata);
+ }
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case PROTO_GET_NAME:
+ res = lu_getprotobyname(name);
+ break;
+ case PROTO_GET_NUM:
+ res = lu_getprotobynumber(number);
+ break;
+ case PROTO_GET_ENT:
+ res = lu_getprotoent();
+ break;
+ default: res = NULL;
+ }
+ }
+ else
+ {
+ switch (source)
+ {
+ case PROTO_GET_NAME:
+ res = copy_protocol(_old_getprotobyname(name));
+ break;
+ case PROTO_GET_NUM:
+ res = copy_protocol(_old_getprotobynumber(number));
+ break;
+ case PROTO_GET_ENT:
+ res = copy_protocol(_old_getprotoent());
+ break;
+ default: res = NULL;
+ }
+ }
+
+ recycle_protocol(tdata, res);
+ return (struct protoent *)tdata->lu_entry;
}
struct protoent *
getprotobyname(const char *name)
{
- LOOKUP1(lu_getprotobyname, _old_getprotobyname, name, struct protoent);
+ return getproto(name, -2, PROTO_GET_NAME);
+}
+
+struct protoent *
+getprotobynumber(int number)
+{
+ return getproto(NULL, number, PROTO_GET_NUM);
}
struct protoent *
getprotoent(void)
{
- GETENT(lu_getprotoent, _old_getprotoent, &p_state, struct protoent);
+ return getproto(NULL, -2, PROTO_GET_ENT);
}
void
setprotoent(int stayopen)
{
- SETSTATE(lu_setprotoent, _old_setprotoent, &p_state, stayopen);
+ if (_lu_running()) lu_setprotoent();
+ else _old_setprotoent(stayopen);
}
void
endprotoent(void)
{
- UNSETSTATE(lu_endprotoent, _old_endprotoent, &p_state);
+ if (_lu_running()) lu_endprotoent();
+ else _old_endprotoent();
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
+#include <pthread.h>
#include "_lu_types.h"
#include "lookup.h"
#include "lu_utils.h"
#include "lu_overrides.h"
-static lookup_state r_state = LOOKUP_CACHE;
-static struct rpcent global_r;
-static int global_free = 1;
-static char *r_data = NULL;
-static unsigned r_datalen;
-static int r_nentries;
-static int r_start = 1;
-static XDR r_xdr;
+static pthread_mutex_t _rpc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define RPC_GET_NAME 1
+#define RPC_GET_NUM 2
+#define RPC_GET_ENT 3
static void
-freeold(void)
+free_rpc_data(struct rpcent *r)
{
char **aliases;
- if (global_free == 1) return;
+ if (r == NULL) return;
- free(global_r.r_name);
+ if (r->r_name != NULL) free(r->r_name);
- aliases = global_r.r_aliases;
+ aliases = r->r_aliases;
if (aliases != NULL)
{
while (*aliases != NULL) free(*aliases++);
- free(global_r.r_aliases);
+ free(r->r_aliases);
}
+}
- global_free = 1;
+static void
+free_rpc(struct rpcent *r)
+{
+ if (r == NULL) return;
+ free_rpc_data(r);
+ free(r);
}
static void
-convert_r(_lu_rpcent *lu_r)
+free_lu_thread_info_rpc(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_rpc((struct rpcent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct rpcent *
+extract_rpc(XDR *xdr)
+{
+ struct rpcent *r;
+ int i, j, nvals, nkeys, status;
+ char *key, **vals;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ r = (struct rpcent *)calloc(1, sizeof(struct rpcent));
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_rpc(r);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((r->r_name == NULL) && (!strcmp("name", key)))
+ {
+ r->r_name = vals[0];
+ if (nvals > 1)
+ {
+ r->r_aliases = (char **)calloc(nvals, sizeof(char *));
+ for (j = 1; j < nvals; j++) r->r_aliases[j-1] = vals[j];
+ }
+ j = nvals;
+ }
+ else if (!strcmp("number", key))
+ {
+ r->r_number= atoi(vals[0]);
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if (r->r_name == NULL) r->r_name = strdup("");
+ if (r->r_aliases == NULL) r->r_aliases = (char **)calloc(1, sizeof(char *));
+
+ return r;
+}
+
+static struct rpcent *
+copy_rpc(struct rpcent *in)
{
int i, len;
+ struct rpcent *r;
- freeold();
+ if (in == NULL) return NULL;
- global_r.r_name = strdup(lu_r->r_names.r_names_val[0]);
+ r = (struct rpcent *)calloc(1, sizeof(struct rpcent));
- len = lu_r->r_names.r_names_len - 1;
- global_r.r_aliases = (char **)malloc((len + 1) * sizeof(char *));
+ r->r_name = LU_COPY_STRING(in->r_name);
- for (i = 0; i < len; i++)
+ len = 0;
+ if (in->r_aliases != NULL)
{
- global_r.r_aliases[i] = strdup(lu_r->r_names.r_names_val[i+1]);
+ for (len = 0; in->r_aliases[len] != NULL; len++);
}
- global_r.r_aliases[len] = NULL;
+ r->r_aliases = (char **)calloc(len + 1, sizeof(char *));
+ for (i = 0; i < len; i++)
+ {
+ r->r_aliases[i] = strdup(in->r_aliases[i]);
+ }
- global_r.r_number = lu_r->r_number;
+ r->r_number = in->r_number;
- global_free = 0;
+ return r;
}
+static void
+recycle_rpc(struct lu_thread_info *tdata, struct rpcent *in)
+{
+ struct rpcent *r;
+
+ if (tdata == NULL) return;
+ r = (struct rpcent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_rpc(r);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
+ free_rpc_data(r);
+
+ r->r_name = in->r_name;
+ r->r_aliases = in->r_aliases;
+ r->r_number = in->r_number;
+
+ free(in);
+}
static struct rpcent *
lu_getrpcbynumber(long number)
{
+ struct rpcent *r;
unsigned datalen;
- _lu_rpcent_ptr lu_r;
- XDR xdr;
+ XDR inxdr;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
-
+ char *lookup_buf;
+ int count;
+
if (proc < 0)
{
if (_lookup_link(_lu_port, "getrpcbynumber", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
number = htonl(number);
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)&number, 1, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)&number, 1, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- lu_r = NULL;
- if (!xdr__lu_rpcent_ptr(&xdr, &lu_r) || lu_r == NULL)
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
- xdr_destroy(&xdr);
- return (NULL);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
- xdr_destroy(&xdr);
+ r = extract_rpc(&inxdr);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_r(lu_r);
- xdr_free(xdr__lu_rpcent_ptr, &lu_r);
- return (&global_r);
+ return r;
}
static struct rpcent *
lu_getrpcbyname(const char *name)
{
+ struct rpcent *r;
unsigned datalen;
char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
- XDR outxdr;
- XDR inxdr;
- _lu_rpcent_ptr lu_r;
+ XDR outxdr, inxdr;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ char *lookup_buf;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getrpcbyname", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_r = NULL;
- if (!xdr__lu_rpcent_ptr(&inxdr, &lu_r) || (lu_r == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ r = extract_rpc(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_r(lu_r);
- xdr_free(xdr__lu_rpcent_ptr, &lu_r);
- return (&global_r);
+ return r;
}
static void
lu_endrpcent(void)
{
- r_nentries = 0;
- if (r_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)r_data, r_datalen);
- r_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_rpc, free_lu_thread_info_rpc);
+ _lu_data_free_vm_xdr(tdata);
}
-static int
-lu_setrpcent(int stayopen)
+static void
+lu_setrpcent()
{
lu_endrpcent();
- r_start = 1;
- return (1);
}
static struct rpcent *
lu_getrpcent()
{
+ struct rpcent *r;
static int proc = -1;
- _lu_rpcent lu_r;
+ struct lu_thread_info *tdata;
- if (r_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_rpc, free_lu_thread_info_rpc);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_rpc, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- r_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "getrpcent", &proc) != KERN_SUCCESS)
{
lu_endrpcent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &r_data, &r_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endrpcent();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- r_datalen *= BYTES_PER_XDR_UNIT;
-#endif
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
- xdrmem_create(&r_xdr, r_data, r_datalen,
- XDR_DECODE);
- if (!xdr_int(&r_xdr, &r_nentries))
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&r_xdr);
lu_endrpcent();
- return (NULL);
+ return NULL;
}
}
- if (r_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&r_xdr);
lu_endrpcent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_r, sizeof(lu_r));
- if (!xdr__lu_rpcent(&r_xdr, &lu_r))
+ r = extract_rpc(tdata->lu_xdr);
+ if (r == NULL)
{
- xdr_destroy(&r_xdr);
lu_endrpcent();
- return (NULL);
+ return NULL;
}
- r_nentries--;
- convert_r(&lu_r);
- xdr_free(xdr__lu_rpcent, &lu_r);
- return (&global_r);
+ tdata->lu_vm_cursor--;
+
+ return r;
}
-struct rpcent *
-getrpcbynumber(long number)
+static struct rpcent *
+getrpc(const char *name, long number, int source)
{
- LOOKUP1(lu_getrpcbynumber, _old_getrpcbynumber, number, struct rpcent);
+ struct rpcent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_rpc, free_lu_thread_info_rpc);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_rpc, tdata);
+ }
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case RPC_GET_NAME:
+ res = lu_getrpcbyname(name);
+ break;
+ case RPC_GET_NUM:
+ res = lu_getrpcbynumber(number);
+ break;
+ case RPC_GET_ENT:
+ res = lu_getrpcent();
+ break;
+ default: res = NULL;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock(&_rpc_lock);
+ switch (source)
+ {
+ case RPC_GET_NAME:
+ res = copy_rpc(_old_getrpcbyname(name));
+ break;
+ case RPC_GET_NUM:
+ res = copy_rpc(_old_getrpcbynumber(number));
+ break;
+ case RPC_GET_ENT:
+ res = copy_rpc(_old_getrpcent());
+ break;
+ default: res = NULL;
+ }
+ pthread_mutex_unlock(&_rpc_lock);
+ }
+
+ recycle_rpc(tdata, res);
+ return (struct rpcent *)tdata->lu_entry;
}
struct rpcent *
getrpcbyname(const char *name)
{
- LOOKUP1(lu_getrpcbyname, _old_getrpcbyname, name, struct rpcent);
+ return getrpc(name, -2, RPC_GET_NAME);
+}
+
+struct rpcent *
+getrpcbynumber(long number)
+{
+ return getrpc(NULL, number, RPC_GET_NUM);
}
struct rpcent *
getrpcent(void)
{
- GETENT(lu_getrpcent, _old_getrpcent, &r_state, struct rpcent);
+ return getrpc(NULL, -2, RPC_GET_ENT);
}
void
setrpcent(int stayopen)
{
- SETSTATE(lu_setrpcent, _old_setrpcent, &r_state, stayopen);
+ if (_lu_running()) lu_setrpcent();
+ else _old_setrpcent(stayopen);
}
void
endrpcent(void)
{
- UNSETSTATE(lu_endrpcent, _old_endrpcent, &r_state);
+ if (_lu_running()) lu_endrpcent();
+ else _old_endrpcent();
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <mach/mach.h>
#include <stdio.h>
#include <string.h>
-#include "lookup.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
-#include "_lu_types.h"
#include <netdb.h>
+#include <netinet/in.h>
+#include <pthread.h>
+
+#include "_lu_types.h"
+#include "lookup.h"
#include "lu_utils.h"
-#import <netinet/in.h>
+
+static pthread_mutex_t _service_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define S_GET_NAME 1
+#define S_GET_PORT 2
+#define S_GET_ENT 3
extern struct servent *_old_getservbyport();
extern struct servent *_old_getservbyname();
extern void _old_endservent();
extern void _old_setservfile();
-static lookup_state s_state = LOOKUP_CACHE;
-static struct servent global_s;
-static int global_free = 1;
-static char *s_data = NULL;
-static unsigned s_datalen;
-static int s_nentries;
-static int s_start = 1;
-static XDR s_xdr;
-
static void
-freeold(void)
+free_service_data(struct servent *s)
{
char **aliases;
- if (global_free == 1) return;
+ if (s == NULL) return;
- if (global_s.s_name != NULL) free(global_s.s_name);
- global_s.s_name = NULL;
+ if (s->s_name != NULL) free(s->s_name);
+ if (s->s_proto != NULL) free(s->s_proto);
- if (global_s.s_proto != NULL) free(global_s.s_proto);
- global_s.s_proto = NULL;
-
- aliases = global_s.s_aliases;
+ aliases = s->s_aliases;
if (aliases != NULL)
{
while (*aliases != NULL) free(*aliases++);
- free(global_s.s_aliases);
- global_s.s_aliases = NULL;
+ free(s->s_aliases);
}
+}
- global_free = 1;
+static void
+free_service(struct servent *s)
+{
+ if (s == NULL) return;
+ free_service_data(s);
+ free(s);
}
static void
-convert_s(_lu_servent *lu_s)
+free_lu_thread_info_service(void *x)
+{
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_service((struct servent *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
+}
+
+static struct servent *
+extract_service(XDR *xdr, const char *proto)
+{
+ struct servent *s;
+ int i, j, nvals, nkeys, status;
+ char *key, **vals;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ s = (struct servent *)calloc(1, sizeof(struct servent));
+
+ for (i = 0; i < nkeys; i++)
+ {
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_service(s);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((s->s_name == NULL) && (!strcmp("name", key)))
+ {
+ s->s_name = vals[0];
+ if (nvals > 1)
+ {
+ s->s_aliases = (char **)calloc(nvals, sizeof(char *));
+ for (j = 1; j < nvals; j++) s->s_aliases[j-1] = vals[j];
+ }
+ j = nvals;
+ }
+ else if ((s->s_proto == NULL) && (!strcmp("protocol", key)))
+ {
+ if ((proto == NULL) || (proto[0] == '\0'))
+ {
+ s->s_proto = vals[0];
+ j = 1;
+ }
+ else
+ {
+ s->s_proto = strdup(proto);
+ }
+ }
+ else if ((s->s_port == 0) && (!strcmp("port", key)))
+ {
+ s->s_port = htons(atoi(vals[0]));
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
+ }
+ }
+
+ if (s->s_name == NULL) s->s_name = strdup("");
+ if (s->s_proto == NULL) s->s_proto = strdup("");
+ if (s->s_aliases == NULL) s->s_aliases = (char **)calloc(1, sizeof(char *));
+
+ return s;
+}
+
+static struct servent *
+copy_service(struct servent *in)
{
int i, len;
+ struct servent *s;
- freeold();
+ if (in == NULL) return NULL;
- global_s.s_name = strdup(lu_s->s_names.s_names_val[0]);
+ s = (struct servent *)calloc(1, sizeof(struct servent));
- len = lu_s->s_names.s_names_len - 1;
- global_s.s_aliases = (char **)malloc((len + 1) * sizeof(char *));
+ s->s_name = LU_COPY_STRING(in->s_name);
+ len = 0;
+ if (in->s_aliases != NULL)
+ {
+ for (len = 0; in->s_aliases[len] != NULL; len++);
+ }
+
+ s->s_aliases = (char **)calloc(len + 1, sizeof(char *));
for (i = 0; i < len; i++)
{
- global_s.s_aliases[i] = strdup(lu_s->s_names.s_names_val[i+1]);
+ s->s_aliases[i] = strdup(in->s_aliases[i]);
+ }
+
+ s->s_proto = LU_COPY_STRING(in->s_proto);
+ s->s_port = in->s_port;
+
+ return s;
+}
+
+static void
+recycle_service(struct lu_thread_info *tdata, struct servent *in)
+{
+ struct servent *s;
+
+ if (tdata == NULL) return;
+ s = (struct servent *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_service(s);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
}
- global_s.s_aliases[len] = NULL;
+ free_service_data(s);
- if (lu_s->s_proto != NULL) global_s.s_proto = strdup(lu_s->s_proto);
- global_s.s_port = lu_s->s_port;
+ s->s_name = in->s_name;
+ s->s_aliases = in->s_aliases;
+ s->s_proto = in->s_proto;
+ s->s_port = in->s_port;
- global_free = 0;
+ free(in);
}
static struct servent *
lu_getservbyport(int port, const char *proto)
{
- unsigned datalen;
- _lu_servent_ptr lu_s;
- XDR xdr;
+ struct servent *s;
+ unsigned int datalen;
+ XDR outxdr, inxdr;
static int proc = -1;
char output_buf[_LU_MAXLUSTRLEN + 3 * BYTES_PER_XDR_UNIT];
- unit lookup_buf[MAX_INLINE_UNITS];
- XDR outxdr;
+ char *lookup_buf;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getservbyport", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
/* Encode NULL for xmission to lookupd. */
- if (!proto) proto = "";
+ if (proto == NULL) proto = "";
xdrmem_create(&outxdr, output_buf, sizeof(output_buf), XDR_ENCODE);
- if (!xdr_int(&outxdr, &port) || !xdr__lu_string(&outxdr, &proto))
+ if (!xdr_int(&outxdr, &port) || !xdr__lu_string(&outxdr, (_lu_string *)&proto))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)output_buf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)output_buf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- lu_s = NULL;
- if (!xdr__lu_servent_ptr(&xdr, &lu_s) || (lu_s == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
{
- xdr_destroy(&xdr);
- return (NULL);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
- xdr_destroy(&xdr);
+ /*
+ * lookupd will only send back a reply for a service with the protocol specified
+ * if it finds a match. We pass the protocol name to extract_service, which
+ * copies the requested protocol name into the returned servent. This is a
+ * bit of a kludge, but since NetInfo / lookupd treat services as single entities
+ * with multiple protocols, we are forced to do some special-case handling.
+ */
+ s = extract_service(&inxdr, proto);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_s(lu_s);
- xdr_free(xdr__lu_servent_ptr, &lu_s);
- return (&global_s);
+ return s;
}
static struct servent *
lu_getservbyname(const char *name, const char *proto)
{
- unsigned datalen;
- unit lookup_buf[MAX_INLINE_UNITS];
+ struct servent *s;
+ unsigned int datalen;
+ char *lookup_buf;
char output_buf[2 * (_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT)];
- XDR outxdr;
- XDR inxdr;
- _lu_servent_ptr lu_s;
+ XDR outxdr, inxdr;
static int proc = -1;
+ int count;
if (proc < 0)
{
if (_lookup_link(_lu_port, "getservbyname", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
/* Encode NULL for xmission to lookupd. */
- if (!proto) proto = "";
+ if (proto == NULL) proto = "";
xdrmem_create(&outxdr, output_buf, sizeof(output_buf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name) || !xdr__lu_string(&outxdr, &proto))
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name) ||
+ !xdr__lu_string(&outxdr, (_lu_string *)&proto))
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)output_buf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)output_buf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_s = NULL;
- if (!xdr__lu_servent_ptr(&inxdr, &lu_s) || (lu_s == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ if (count == 0)
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ /*
+ * lookupd will only send back a reply for a service with the protocol specified
+ * if it finds a match. We pass the protocol name to extract_service, which
+ * copies the requested protocol name into the returned servent. This is a
+ * bit of a kludge, but since NetInfo / lookupd treat services as single entities
+ * with multiple protocols, we are forced to do some special-case handling.
+ */
+ s = extract_service(&inxdr, proto);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_s(lu_s);
- xdr_free(xdr__lu_servent_ptr, &lu_s);
- return (&global_s);
+ return s;
}
static void
lu_endservent()
{
- s_nentries = 0;
- if (s_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)s_data, s_datalen);
- s_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_service);
+ _lu_data_free_vm_xdr(tdata);
}
static void
lu_setservent()
{
lu_endservent();
- s_start = 1;
}
static struct servent *
lu_getservent()
{
+ struct servent *s;
static int proc = -1;
- _lu_servent lu_s;
+ struct lu_thread_info *tdata;
- if (s_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_service);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_service, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- s_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "getservent", &proc) != KERN_SUCCESS)
{
lu_endservent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &s_data, &s_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endservent();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- s_datalen *= BYTES_PER_XDR_UNIT;
-#endif
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
- xdrmem_create(&s_xdr, s_data, s_datalen,
- XDR_DECODE);
- if (!xdr_int(&s_xdr, &s_nentries))
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&s_xdr);
lu_endservent();
- return (NULL);
+ return NULL;
}
}
- if (s_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&s_xdr);
lu_endservent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_s, sizeof(lu_s));
- if (!xdr__lu_servent(&s_xdr, &lu_s))
+ s = extract_service(tdata->lu_xdr, NULL);
+ if (s == NULL)
{
- xdr_destroy(&s_xdr);
lu_endservent();
- return (NULL);
+ return NULL;
+ }
+
+ tdata->lu_vm_cursor--;
+
+ return s;
+}
+
+static struct servent *
+getserv(const char *name, const char *proto, int port, int source)
+{
+ struct servent *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_service);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_service, tdata);
+ }
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case S_GET_NAME:
+ res = lu_getservbyname(name, proto);
+ break;
+ case S_GET_PORT:
+ res = lu_getservbyport(port, proto);
+ break;
+ case S_GET_ENT:
+ res = lu_getservent();
+ break;
+ default: res = NULL;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock(&_service_lock);
+ switch (source)
+ {
+ case S_GET_NAME:
+ res = copy_service(_old_getservbyname(name, proto));
+ break;
+ case S_GET_PORT:
+ res = copy_service(_old_getservbyport(port, proto));
+ break;
+ case S_GET_ENT:
+ res = copy_service(_old_getservent());
+ break;
+ default: res = NULL;
+ }
+ pthread_mutex_unlock(&_service_lock);
}
- s_nentries--;
- convert_s(&lu_s);
- xdr_free(xdr__lu_servent, &lu_s);
- return (&global_s);
+ recycle_service(tdata, res);
+ return (struct servent *)tdata->lu_entry;
}
struct servent *
getservbyport(int port, const char *proto)
{
- LOOKUP2(lu_getservbyport, _old_getservbyport, port, proto, struct servent);
+ return getserv(NULL, proto, port, S_GET_PORT);
}
struct servent *
getservbyname(const char *name, const char *proto)
{
- LOOKUP2(lu_getservbyname, _old_getservbyname, name, proto,
- struct servent);
+ return getserv(name, proto, 0, S_GET_NAME);
}
struct servent *
getservent(void)
{
- GETENT(lu_getservent, _old_getservent, &s_state, struct servent);
+ return getserv(NULL, NULL, 0, S_GET_ENT);
}
void
setservent(int stayopen)
{
- SETSTATE(lu_setservent, _old_setservent, &s_state, stayopen);
+ if (_lu_running()) lu_setservent();
+ else _old_setservent();
}
void
endservent(void)
{
- UNSETSTATE(lu_endservent, _old_endservent, &s_state);
+ if (_lu_running()) lu_endservent();
+ else _old_endservent();
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <rpc/xdr.h>
#include <pwd.h>
#include <netinet/in.h>
+#include <pthread.h>
+#include <unistd.h>
#include "_lu_types.h"
#include "lookup.h"
#include "lu_utils.h"
#include "lu_overrides.h"
-static lookup_state pw_state = LOOKUP_CACHE;
-static struct passwd global_pw;
-static int global_free = 1;
-static char *pw_data = NULL;
-static unsigned pw_datalen;
-static int pw_nentries;
-static int pw_start = 1;
-static XDR pw_xdr;
+static pthread_mutex_t _user_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define PW_GET_NAME 1
+#define PW_GET_UID 2
+#define PW_GET_ENT 3
static void
-freeold(void)
+free_user_data(struct passwd *p)
{
- if (global_free == 1) return;
-
- free(global_pw.pw_name);
- free(global_pw.pw_passwd);
- free(global_pw.pw_class);
- free(global_pw.pw_gecos);
- free(global_pw.pw_dir);
- free(global_pw.pw_shell);
+ if (p == NULL) return;
+
+ if (p->pw_name != NULL) free(p->pw_name);
+ if (p->pw_passwd != NULL) free(p->pw_passwd);
+ if (p->pw_class != NULL) free(p->pw_class);
+ if (p->pw_gecos != NULL) free(p->pw_gecos);
+ if (p->pw_dir != NULL) free(p->pw_dir);
+ if (p->pw_shell != NULL) free(p->pw_shell);
+}
- global_free = 1;
+static void
+free_user(struct passwd *p)
+{
+ if (p == NULL) return;
+ free_user_data(p);
+ free(p);
}
static void
-convert_pw(_lu_passwd *lu_pw)
+free_lu_thread_info_user(void *x)
{
- freeold();
-
- global_pw.pw_name = strdup(lu_pw->pw_name);
- global_pw.pw_passwd = strdup(lu_pw->pw_passwd);
- global_pw.pw_uid = lu_pw->pw_uid;
- global_pw.pw_gid = lu_pw->pw_gid;
- global_pw.pw_change = lu_pw->pw_change;
- global_pw.pw_class = strdup(lu_pw->pw_class);
- global_pw.pw_gecos = strdup(lu_pw->pw_gecos);
- global_pw.pw_dir = strdup(lu_pw->pw_dir);
- global_pw.pw_shell = strdup(lu_pw->pw_shell);
- global_pw.pw_expire = lu_pw->pw_expire;
-
- global_free = 0;
+ struct lu_thread_info *tdata;
+
+ if (x == NULL) return;
+
+ tdata = (struct lu_thread_info *)x;
+
+ if (tdata->lu_entry != NULL)
+ {
+ free_user((struct passwd *)tdata->lu_entry);
+ tdata->lu_entry = NULL;
+ }
+
+ _lu_data_free_vm_xdr(tdata);
+
+ free(tdata);
}
static struct passwd *
-lu_getpwuid(int uid)
+extract_user(XDR *xdr)
{
- unsigned datalen;
- _lu_passwd_ptr lu_pw;
- XDR xdr;
- static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
-
- if (proc < 0)
+ int i, j, nvals, nkeys, status;
+ char *key, **vals;
+ struct passwd *p;
+
+ if (xdr == NULL) return NULL;
+
+ if (!xdr_int(xdr, &nkeys)) return NULL;
+
+ p = (struct passwd *)calloc(1, sizeof(struct passwd));
+
+ p->pw_uid = -2;
+ p->pw_gid = -2;
+
+ for (i = 0; i < nkeys; i++)
{
- if (_lookup_link(_lu_port, "getpwuid_A", &proc) != KERN_SUCCESS)
+ key = NULL;
+ vals = NULL;
+ nvals = 0;
+
+ status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
+ if (status < 0)
+ {
+ free_user(p);
+ return NULL;
+ }
+
+ if (nvals == 0)
+ {
+ free(key);
+ continue;
+ }
+
+ j = 0;
+
+ if ((p->pw_name == NULL) && (!strcmp("name", key)))
+ {
+ p->pw_name = vals[0];
+ j = 1;
+ }
+ else if ((p->pw_passwd == NULL) && (!strcmp("passwd", key)))
+ {
+ p->pw_passwd = vals[0];
+ j = 1;
+ }
+ else if ((p->pw_class == NULL) && (!strcmp("class", key)))
{
- return (NULL);
+ p->pw_class = vals[0];
+ j = 1;
+ }
+ else if ((p->pw_gecos == NULL) && (!strcmp("realname", key)))
+ {
+ p->pw_gecos = vals[0];
+ j = 1;
+ }
+ else if ((p->pw_dir == NULL) && (!strcmp("home", key)))
+ {
+ p->pw_dir = vals[0];
+ j = 1;
+ }
+ else if ((p->pw_shell == NULL) && (!strcmp("shell", key)))
+ {
+ p->pw_shell = vals[0];
+ j = 1;
+ }
+ else if ((p->pw_uid == -2) && (!strcmp("uid", key)))
+ {
+ p->pw_uid = atoi(vals[0]);
+ }
+ else if ((p->pw_gid == -2) && (!strcmp("gid", key)))
+ {
+ p->pw_gid = atoi(vals[0]);
+ }
+ else if (!strcmp("change", key))
+ {
+ p->pw_change = atoi(vals[0]);
+ }
+ else if (!strcmp("expire", key))
+ {
+ p->pw_expire = atoi(vals[0]);
+ }
+
+ free(key);
+ if (vals != NULL)
+ {
+ for (; j < nvals; j++) free(vals[j]);
+ free(vals);
}
}
- uid = htonl(uid);
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)&uid, 1, lookup_buf, &datalen)
- != KERN_SUCCESS)
+ if (p->pw_name == NULL) p->pw_name = strdup("");
+ if (p->pw_passwd == NULL) p->pw_passwd = strdup("");
+ if (p->pw_class == NULL) p->pw_class = strdup("");
+ if (p->pw_gecos == NULL) p->pw_gecos = strdup("");
+ if (p->pw_dir == NULL) p->pw_dir = strdup("");
+ if (p->pw_shell == NULL) p->pw_shell = strdup("");
+
+ return p;
+}
+
+static struct passwd *
+copy_user(struct passwd *in)
+{
+ struct passwd *p;
+
+ if (in == NULL) return NULL;
+
+ p = (struct passwd *)calloc(1, sizeof(struct passwd));
+
+ p->pw_name = LU_COPY_STRING(in->pw_name);
+ p->pw_passwd = LU_COPY_STRING(in->pw_passwd);
+ p->pw_uid = in->pw_uid;
+ p->pw_gid = in->pw_gid;
+ p->pw_change = in->pw_change;
+ p->pw_class = LU_COPY_STRING(in->pw_class);
+ p->pw_gecos = LU_COPY_STRING(in->pw_gecos);
+ p->pw_dir = LU_COPY_STRING(in->pw_dir);
+ p->pw_shell = LU_COPY_STRING(in->pw_shell);
+ p->pw_expire = in->pw_expire;
+
+ return p;
+}
+
+static int
+copy_user_r(struct passwd *in, struct passwd *out, char *buffer, int buflen)
+{
+ int hsize;
+ char *bp;
+
+ if (in == NULL) return -1;
+ if (out == NULL) return -1;
+
+ if (buffer == NULL) buflen = 0;
+
+ /* Calculate size of input */
+ hsize = 0;
+ if (in->pw_name != NULL) hsize += strlen(in->pw_name);
+ if (in->pw_passwd != NULL) hsize += strlen(in->pw_passwd);
+ if (in->pw_class != NULL) hsize += strlen(in->pw_class);
+ if (in->pw_gecos != NULL) hsize += strlen(in->pw_gecos);
+ if (in->pw_dir != NULL) hsize += strlen(in->pw_dir);
+ if (in->pw_shell != NULL) hsize += strlen(in->pw_shell);
+
+ /* Check buffer space */
+ if (hsize > buflen) return -1;
+
+ /* Copy result into caller's struct passwd, using buffer for memory */
+ bp = buffer;
+
+ out->pw_name = NULL;
+ if (in->pw_name != NULL)
{
- return (NULL);
+ out->pw_name = bp;
+ hsize = strlen(in->pw_name) + 1;
+ memmove(bp, in->pw_name, hsize);
+ bp += hsize;
}
- datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- lu_pw = NULL;
- if (!xdr__lu_passwd_ptr(&xdr, &lu_pw) || (lu_pw == NULL))
+ out->pw_passwd = NULL;
+ if (in->pw_passwd != NULL)
{
- xdr_destroy(&xdr);
- return (NULL);
+ out->pw_passwd = bp;
+ hsize = strlen(in->pw_passwd) + 1;
+ memmove(bp, in->pw_passwd, hsize);
+ bp += hsize;
}
- xdr_destroy(&xdr);
+ out->pw_uid = in->pw_uid;
- convert_pw(lu_pw);
- xdr_free(xdr__lu_passwd_ptr, &lu_pw);
- return (&global_pw);
+ out->pw_gid = in->pw_gid;
+
+ out->pw_change = in->pw_change;
+
+ out->pw_class = NULL;
+ if (in->pw_class != NULL)
+ {
+ out->pw_class = bp;
+ hsize = strlen(in->pw_class) + 1;
+ memmove(bp, in->pw_class, hsize);
+ bp += hsize;
+ }
+
+ out->pw_gecos = NULL;
+ if (in->pw_gecos != NULL)
+ {
+ out->pw_gecos = bp;
+ hsize = strlen(in->pw_gecos) + 1;
+ memmove(bp, in->pw_gecos, hsize);
+ bp += hsize;
+ }
+
+ out->pw_dir = NULL;
+ if (in->pw_dir != NULL)
+ {
+ out->pw_dir = bp;
+ hsize = strlen(in->pw_dir) + 1;
+ memmove(bp, in->pw_dir, hsize);
+ bp += hsize;
+ }
+
+ out->pw_shell = NULL;
+ if (in->pw_shell != NULL)
+ {
+ out->pw_shell = bp;
+ hsize = strlen(in->pw_shell) + 1;
+ memmove(bp, in->pw_shell, hsize);
+ bp += hsize;
+ }
+
+ out->pw_expire = in->pw_expire;
+
+ return 0;
+}
+
+static void
+recycle_user(struct lu_thread_info *tdata, struct passwd *in)
+{
+ struct passwd *p;
+
+ if (tdata == NULL) return;
+ p = (struct passwd *)tdata->lu_entry;
+
+ if (in == NULL)
+ {
+ free_user(p);
+ tdata->lu_entry = NULL;
+ }
+
+ if (tdata->lu_entry == NULL)
+ {
+ tdata->lu_entry = in;
+ return;
+ }
+
+ free_user_data(p);
+
+ p->pw_name = in->pw_name;
+ p->pw_passwd = in->pw_passwd;
+ p->pw_uid = in->pw_uid;
+ p->pw_gid = in->pw_gid;
+ p->pw_change = in->pw_change;
+ p->pw_class = in->pw_class;
+ p->pw_gecos = in->pw_gecos;
+ p->pw_dir = in->pw_dir;
+ p->pw_shell = in->pw_shell;
+ p->pw_expire = in->pw_expire;
+
+ free(in);
}
static struct passwd *
-lu_getpwnam(const char *name)
+lu_getpwuid(int uid)
{
- unsigned datalen;
- char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
- XDR outxdr;
+ struct passwd *p;
+ unsigned int datalen;
XDR inxdr;
- _lu_passwd_ptr lu_pw;
static int proc = -1;
- unit lookup_buf[MAX_INLINE_UNITS];
+ int count;
+ char *lookup_buf;
if (proc < 0)
{
- if (_lookup_link(_lu_port, "getpwnam_A", &proc) != KERN_SUCCESS)
+ if (_lookup_link(_lu_port, "getpwuid_A", &proc) != KERN_SUCCESS)
{
- return (NULL);
+ return NULL;
}
}
- xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &name))
- {
- xdr_destroy(&outxdr);
- return (NULL);
- }
-
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, (unit *)namebuf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ uid = htonl(uid);
+ datalen = 0;
+ lookup_buf = NULL;
+
+ if (_lookup_all(_lu_port, proc, (unit *)&uid, 1, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
- xdr_destroy(&outxdr);
- return (NULL);
+ return NULL;
}
- xdr_destroy(&outxdr);
-
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&inxdr, lookup_buf, datalen,
- XDR_DECODE);
- lu_pw = NULL;
- if (!xdr__lu_passwd_ptr(&inxdr, &lu_pw) || (lu_pw == NULL))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
xdr_destroy(&inxdr);
- return (NULL);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
+
+ p = extract_user(&inxdr);
xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
- convert_pw(lu_pw);
- xdr_free(xdr__lu_passwd_ptr, &lu_pw);
- return (&global_pw);
+ return p;
}
-#ifdef notdef
-static int
-lu_putpwpasswd(char *login, char *old_passwd, char *new_passwd)
+static struct passwd *
+lu_getpwnam(const char *name)
{
- unsigned datalen;
- int changed;
- XDR xdr;
- static int proc = -1;
- char output_buf[3 * (_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT)];
- unit lookup_buf[MAX_INLINE_UNITS];
+ struct passwd *p;
+ unsigned int datalen;
+ char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
XDR outxdr;
-
+ XDR inxdr;
+ static int proc = -1;
+ int count;
+ char *lookup_buf;
+
if (proc < 0)
{
- if (_lookup_link(_lu_port, "putpwpasswd", &proc) != KERN_SUCCESS)
+ if (_lookup_link(_lu_port, "getpwnam_A", &proc) != KERN_SUCCESS)
{
- return (0);
+ return NULL;
}
}
- xdrmem_create(&outxdr, output_buf, sizeof(output_buf), XDR_ENCODE);
- if (!xdr__lu_string(&outxdr, &login) ||
- !xdr__lu_string(&outxdr, &old_passwd) ||
- !xdr__lu_string(&outxdr, &new_passwd))
+ xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
+ if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
- return (0);
+ return NULL;
}
+
+ datalen = 0;
+ lookup_buf = NULL;
- datalen = MAX_INLINE_UNITS;
- if (_lookup_one(_lu_port, proc, output_buf,
- xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen)
+ if (_lookup_all(_lu_port, proc, (unit *)namebuf,
+ xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen)
!= KERN_SUCCESS)
{
xdr_destroy(&outxdr);
- return (0);
+ return NULL;
}
xdr_destroy(&outxdr);
datalen *= BYTES_PER_XDR_UNIT;
- xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE);
- if (!xdr_int(&xdr, &changed))
+ if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
+
+ xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
+
+ count = 0;
+ if (!xdr_int(&inxdr, &count))
{
- xdr_destroy(&xdr);
- return (0);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
}
- xdr_destroy(&xdr);
+ if (count == 0)
+ {
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+ return NULL;
+ }
- return (changed);
+ p = extract_user(&inxdr);
+ xdr_destroy(&inxdr);
+ vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
+
+
+ return p;
}
-#endif
static void
lu_endpwent(void)
{
- pw_nentries = 0;
- if (pw_data != NULL)
- {
- freeold();
- vm_deallocate(mach_task_self(), (vm_address_t)pw_data, pw_datalen);
- pw_data = NULL;
- }
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_user, free_lu_thread_info_user);
+ _lu_data_free_vm_xdr(tdata);
}
static int
lu_setpwent(void)
{
lu_endpwent();
- pw_start = 1;
- return (1);
+ return 1;
}
static struct passwd *
lu_getpwent()
{
+ struct passwd *p;
static int proc = -1;
- _lu_passwd lu_pw;
+ struct lu_thread_info *tdata;
- if (pw_start == 1)
+ tdata = _lu_data_create_key(_lu_data_key_user, free_lu_thread_info_user);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_user, tdata);
+ }
+\r
+ if (tdata->lu_vm == NULL)
{
- pw_start = 0;
-
if (proc < 0)
{
if (_lookup_link(_lu_port, "getpwent_A", &proc) != KERN_SUCCESS)
{
lu_endpwent();
- return (NULL);
+ return NULL;
}
}
- if (_lookup_all(_lu_port, proc, NULL, 0, &pw_data, &pw_datalen)
- != KERN_SUCCESS)
+ if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
{
lu_endpwent();
- return (NULL);
+ return NULL;
}
-#ifdef NOTDEF
-/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
- pw_datalen *= BYTES_PER_XDR_UNIT;
-#endif
+ /* mig stubs measure size in words (4 bytes) */
+ tdata->lu_vm_length *= 4;
- xdrmem_create(&pw_xdr, pw_data, pw_datalen,
- XDR_DECODE);
- if (!xdr_int(&pw_xdr, &pw_nentries))
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ }
+ tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
+
+ xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
+ if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
{
- xdr_destroy(&pw_xdr);
lu_endpwent();
- return (NULL);
+ return NULL;
}
}
- if (pw_nentries == 0)
+ if (tdata->lu_vm_cursor == 0)
{
- xdr_destroy(&pw_xdr);
lu_endpwent();
- return (NULL);
+ return NULL;
}
- bzero(&lu_pw, sizeof(lu_pw));
- if (!xdr__lu_passwd(&pw_xdr, &lu_pw))
+ p = extract_user(tdata->lu_xdr);
+ if (p == NULL)
{
- xdr_destroy(&pw_xdr);
lu_endpwent();
- return (NULL);
+ return NULL;
}
- pw_nentries--;
- convert_pw(&lu_pw);
- xdr_free(xdr__lu_passwd, &lu_pw);
- return (&global_pw);
+ tdata->lu_vm_cursor--;
+
+ return p;
}
-static char *loginName = NULL;
-static uid_t loginUid = -1;
+static struct passwd *
+getpw_internal(const char *name, uid_t uid, int source)
+{
+ struct passwd *res = NULL;
+ static char *loginName = NULL;
+ static struct passwd *loginEnt = NULL;
-extern char *getlogin(void);
+ if (loginName == NULL)
+ {
+ char *l = getlogin();
-struct passwd *
-getpwuid(uid_t uid)
+ pthread_mutex_lock(&_user_lock);
+ if ((loginEnt == NULL) && (l != NULL) && (*l != '\0'))
+ {
+ if (_lu_running())
+ {
+ loginEnt = lu_getpwnam(l);
+ }
+ else
+ {
+ loginEnt = copy_user(_old_getpwnam(l));
+ }
+
+ loginName = l;
+ }
+ pthread_mutex_unlock(&_user_lock);
+ }
+
+ if (loginEnt != NULL)
+ {
+ switch (source)
+ {
+ case PW_GET_NAME:
+ if (strcmp(name, loginEnt->pw_name) == 0)
+ {
+ name = loginName;
+ }
+ if (strcmp(name, loginEnt->pw_gecos) == 0)
+ {
+ name = loginName;
+ }
+ break;
+ case PW_GET_UID:
+ if (uid == loginEnt->pw_uid)
+ {
+ source = PW_GET_NAME;
+ name = loginName;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_lu_running())
+ {
+ switch (source)
+ {
+ case PW_GET_NAME:
+ res = lu_getpwnam(name);
+ break;
+ case PW_GET_UID:
+ res = lu_getpwuid(uid);
+ break;
+ case PW_GET_ENT:
+ res = lu_getpwent();
+ break;
+ default: res = NULL;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock(&_user_lock);
+ switch (source)
+ {
+ case PW_GET_NAME:
+ res = copy_user(_old_getpwnam(name));
+ break;
+ case PW_GET_UID:
+ res = copy_user(_old_getpwuid(uid));
+ break;
+ case PW_GET_ENT:
+ res = copy_user(_old_getpwent());
+ break;
+ default: res = NULL;
+ }
+ pthread_mutex_unlock(&_user_lock);
+ }
+
+ return res;
+}
+
+static struct passwd *
+getpw(const char *name, uid_t uid, int source)
{
- if (uid != 0) {
- if (loginName == NULL) {
- char *l = getlogin();
- if (l != NULL) {
- struct passwd *p = getpwnam(l);
- if (p != NULL) {
- loginUid = p->pw_uid;
- loginName = l;
- }
- }
- }
- if (uid == loginUid) {
- LOOKUP1(lu_getpwnam, _old_getpwnam, loginName, struct passwd);
- }
- }
- LOOKUP1(lu_getpwuid, _old_getpwuid, uid, struct passwd);
+ struct passwd *res = NULL;
+ struct lu_thread_info *tdata;
+
+ tdata = _lu_data_create_key(_lu_data_key_user, free_lu_thread_info_user);
+ if (tdata == NULL)
+ {
+ tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
+ _lu_data_set_key(_lu_data_key_user, tdata);
+ }
+
+ res = getpw_internal(name, uid, source);
+
+ recycle_user(tdata, res);
+
+ return (struct passwd *)tdata->lu_entry;
+}
+
+static int
+getpw_r(const char *name, uid_t uid, int source, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
+{
+ struct passwd *res = NULL;
+ int status;
+
+ *result = NULL;
+ errno = 0;
+
+ res = getpw_internal(name, uid, source);
+ if (res == NULL) return -1;
+
+ status = copy_user_r(res, pwd, buffer, bufsize);
+ free_user(res);
+
+ if (status != 0)
+ {
+ errno = ERANGE;
+ return -1;
+ }
+
+ *result = pwd;
+ return 0;
}
struct passwd *
getpwnam(const char *name)
{
- LOOKUP1(lu_getpwnam, _old_getpwnam, name, struct passwd);
+ return getpw(name, -2, PW_GET_NAME);
}
-#ifdef notdef
-/*
- * putpwpasswd() is not supported with anything other than netinfo
- * right now.
- * old_passwd is clear text.
- * new_passwd is encrypted.
- */
-#define _old_passwd(name, oldpass, newpass) 0
-int
-putpwpasswd(char *login, char *old_passwd, char *new_passwd)
+struct passwd *
+getpwuid(uid_t uid)
{
- if (_lu_running()) return (lu_putpwpasswd(login, old_passwd, new_passwd));
- return (old_passwd(login, old_passwd, new_passwd));
+ return getpw(NULL, uid, PW_GET_UID);
}
-#endif
struct passwd *
getpwent(void)
{
- GETENT(lu_getpwent, _old_getpwent, &pw_state, struct passwd);
+ return getpw(NULL, -2, PW_GET_ENT);
}
int
setpwent(void)
{
- INTSETSTATEVOID(lu_setpwent, _old_setpwent, &pw_state);
+ if (_lu_running()) lu_setpwent();
+ else _old_setpwent();
+ return 1;
}
void
endpwent(void)
{
- UNSETSTATE(lu_endpwent, _old_endpwent, &pw_state);
+ if (_lu_running()) lu_endpwent();
+ else _old_endpwent();
+}
+\rint
+getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
+{
+ return getpw_r(name, -2, PW_GET_NAME, pwd, buffer, bufsize, result);
+}
+
+int
+getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
+{
+ return getpw_r(NULL, uid, PW_GET_UID, pwd, buffer, bufsize, result);
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <stdlib.h>
#include <string.h>
#include <mach/mach.h>
-
+#include <pthread.h>
+#ifdef DEBUG
+#include <syslog.h>
+#endif
#include "_lu_types.h"
#include "lookup.h"
#include "lu_utils.h"
-#define LONG_STRING_LENGTH 8192
+#define MAX_LOOKUP_ATTEMPTS 10
+
+static pthread_key_t _info_key = NULL;
+static pthread_once_t _info_key_initialized = PTHREAD_ONCE_INIT;
+
+struct _lu_data_s
+{
+ unsigned int icount;
+ unsigned int *ikey;
+ void **idata;
+ void (**idata_destructor)(void *);
+};
+
#define _LU_MAXLUSTRLEN 256
-static ni_proplist *
-lookupd_process_dictionary(XDR *inxdr)
+ni_proplist *
+_lookupd_xdr_dictionary(XDR *inxdr)
{
int i, nkeys, j, nvals;
char *key, *val;
if (nkeys > 0)
{
i = nkeys * sizeof(ni_property);
- l->ni_proplist_val = (ni_property *)malloc(i);
- memset(l->ni_proplist_val, 0, i);
+ l->ni_proplist_val = (ni_property *)calloc(1, i);
}
for (i = 0; i < nkeys; i++)
{
key = NULL;
-
- if (!xdr_string(inxdr, &key, LONG_STRING_LENGTH))
+ if (!xdr_string(inxdr, &key, -1))
{
ni_proplist_free(l);
return NULL;
if (nvals > 0)
{
j = nvals * sizeof(ni_name);
- l->ni_proplist_val[i].nip_val.ni_namelist_val = (ni_name *)malloc(j);
- memset(l->ni_proplist_val[i].nip_val.ni_namelist_val, 0 , j);
+ l->ni_proplist_val[i].nip_val.ni_namelist_val = (ni_name *)calloc(1, j);
}
for (j = 0; j < nvals; j++)
{
val = NULL;
- if (!xdr_string(inxdr, &val, LONG_STRING_LENGTH))
+ if (!xdr_string(inxdr, &val, -1))
{
ni_proplist_free(l);
return NULL;
XDR outxdr;
XDR inxdr;
int proc;
- char *listbuf;
+ char *listbuf, *s;
char databuf[_LU_MAXLUSTRLEN * BYTES_PER_XDR_UNIT];
int n, i, j, na;
kern_return_t status;
for (i = 0; i < l->ni_proplist_len; i++)
{
p = &(l->ni_proplist_val[i]);
- if (!xdr_string(&outxdr, &(p->nip_name), _LU_MAXLUSTRLEN))
+ s = NULL;
+ if (!xdr_string(&outxdr, &s, _LU_MAXLUSTRLEN))
{
xdr_destroy(&outxdr);
return 0;
}
+ p->nip_name = s;
if (!xdr_int(&outxdr, &(p->nip_val.ni_namelist_len)))
{
for (j = 0; j < p->nip_val.ni_namelist_len; j++)
{
- if (!xdr_string(&outxdr, &(p->nip_val.ni_namelist_val[j]), _LU_MAXLUSTRLEN))
+ s = NULL;
+ if (!xdr_string(&outxdr, &s, _LU_MAXLUSTRLEN))
{
xdr_destroy(&outxdr);
return 0;
}
+ p->nip_val.ni_namelist_val[j] = s;
}
}
for (i = 0; i < n; i++)
{
- (*out)[i] = lookupd_process_dictionary(&inxdr);
+ (*out)[i] = _lookupd_xdr_dictionary(&inxdr);
}
xdr_destroy(&inxdr);
}
}
+static void
+_lu_data_free(void *x)
+{
+ struct _lu_data_s *t;
+ int i;
+
+ if (x == NULL) return;
+
+ t = (struct _lu_data_s *)x;
+
+ for (i = 0; i < t->icount; i++)
+ {
+ if ((t->idata[i] != NULL) && (t->idata_destructor[i] != NULL))
+ {
+ (*(t->idata_destructor[i]))(t->idata[i]);
+ }
+
+ t->idata[i] = NULL;
+ t->idata_destructor[i] = NULL;
+ }
+
+ if (t->ikey != NULL) free(t->ikey);
+ t->ikey = NULL;
+
+ if (t->idata != NULL) free(t->idata);
+ t->idata = NULL;
+
+ if (t->idata_destructor != NULL) free(t->idata_destructor);
+ t->idata_destructor = NULL;
+
+ free(t);
+}
+
+static void
+_lu_data_init()
+{
+ pthread_key_create(&_info_key, _lu_data_free);
+ return;
+}
+
+static struct _lu_data_s *
+_lu_data_get()
+{
+ struct _lu_data_s *libinfo_data;
+
+ /*
+ * Only one thread should create the _info_key
+ */
+ pthread_once(&_info_key_initialized, _lu_data_init);
+
+ /* Check if this thread already created libinfo_data */
+ libinfo_data = pthread_getspecific(_info_key);
+ if (libinfo_data != NULL) return libinfo_data;
+
+ libinfo_data = (struct _lu_data_s *)calloc(1, sizeof(struct _lu_data_s));
+
+ pthread_setspecific(_info_key, libinfo_data);
+ return libinfo_data;
+}
+
+void *
+_lu_data_create_key(unsigned int key, void (*destructor)(void *))
+{
+ struct _lu_data_s *libinfo_data;
+ unsigned int i, n;
+
+ libinfo_data = _lu_data_get();
+
+ for (i = 0; i < libinfo_data->icount; i++)
+ {
+ if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
+ }
+
+ i = libinfo_data->icount;
+ n = i + 1;
+
+ if (i == 0)
+ {
+ libinfo_data->ikey = (unsigned int *)malloc(sizeof(unsigned int));
+ libinfo_data->idata = (void **)malloc(sizeof(void *));
+ libinfo_data->idata_destructor = (void (**)(void *))malloc(sizeof(void (*)(void *)));
+ }
+ else
+ {
+ libinfo_data->ikey = (unsigned int *)realloc(libinfo_data->ikey, n * sizeof(unsigned int));
+ libinfo_data->idata = (void **)realloc(libinfo_data->idata, n * sizeof(void *));
+ libinfo_data->idata_destructor = (void (**)(void *))realloc(libinfo_data->idata_destructor, n * sizeof(void (*)(void *)));
+ }
+
+ libinfo_data->ikey[i] = key;
+ libinfo_data->idata[i] = NULL;
+ libinfo_data->idata_destructor[i] = destructor;
+ libinfo_data->icount++;
+
+ return NULL;
+}
+
+static unsigned int
+_lu_data_index(unsigned int key, struct _lu_data_s *libinfo_data)
+{
+ unsigned int i;
+
+ if (libinfo_data == NULL) return (unsigned int)-1;
+
+ for (i = 0; i < libinfo_data->icount; i++)
+ {
+ if (libinfo_data->ikey[i] == key) return i;
+ }
+
+ return (unsigned int)-1;
+}
+
+void
+_lu_data_set_key(unsigned int key, void *data)
+{
+ struct _lu_data_s *libinfo_data;
+ unsigned int i;
+
+ libinfo_data = _lu_data_get();
+
+ i = _lu_data_index(key, libinfo_data);
+ if (i == (unsigned int)-1) return;
+
+ libinfo_data->idata[i] = data;
+}
+
+void *
+_lu_data_get_key(unsigned int key)
+{
+ struct _lu_data_s *libinfo_data;
+ unsigned int i;
+
+ libinfo_data = _lu_data_get();
+
+ i = _lu_data_index(key, libinfo_data);
+ if (i == (unsigned int)-1) return NULL;
+
+ return libinfo_data->idata[i];
+}
+
+void
+_lu_data_free_vm_xdr(struct lu_thread_info *tdata)
+{
+ if (tdata == NULL) return;
+
+ if (tdata->lu_vm != NULL)
+ {
+ vm_deallocate(mach_task_self(), (vm_address_t)tdata->lu_vm, tdata->lu_vm_length);
+ tdata->lu_vm = NULL;
+ }
+ tdata->lu_vm_length = 0;
+ tdata->lu_vm_cursor = 0;
+
+ if (tdata->lu_xdr != NULL)
+ {
+ xdr_destroy(tdata->lu_xdr);
+ free(tdata->lu_xdr);
+ tdata->lu_xdr = NULL;
+ }
+}
+
+int
+_lu_xdr_attribute(XDR *xdr, char **key, char ***val, unsigned int *count)
+{
+ unsigned int i, j, len;
+ char **x, *s;
+
+ if (xdr == NULL) return -1;
+ if (key == NULL) return -1;
+ if (val == NULL) return -1;
+ if (count == NULL) return -1;
+
+ *key = NULL;
+ *val = NULL;
+ *count = 0;
+
+ if (!xdr_string(xdr, key, -1)) return -1;
+
+ if (!xdr_int(xdr, &len))
+ {
+ free(*key);
+ *key = NULL;
+ return -1;
+ }
+
+ if (len == 0) return 0;
+ *count = len;
+
+ x = (char **)calloc(len + 1, sizeof(char *));
+ *val = x;
+
+ for (i = 0; i < len; i++)
+ {
+ s = NULL;
+ if (!xdr_string(xdr, &s, -1))
+ {
+ for (j = 0; j < i; j++) free(x[j]);
+ free(x);
+ *val = NULL;
+ free(*key);
+ *key = NULL;
+ *count = 0;
+ return -1;
+ }
+ x[i] = s;
+ }
+
+ x[len] = NULL;
+
+ return 0;
+}
+
+kern_return_t
+_lookup_link(mach_port_t server, lookup_name name, int *procno)
+{
+ kern_return_t status;
+ security_token_t token;
+ unsigned int n;
+
+ token.val[0] = -1;
+ token.val[1] = -1;
+
+ status = MIG_SERVER_DIED;
+ for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
+ {
+ status = _lookup_link_secure(server, name, procno, &token);
+ }
+
+ if (status != KERN_SUCCESS)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_link %s status %u", getpid(), name, status);
+#endif
+ return status;
+ }
+
+ if (token.val[0] != 0)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_link %s auth failure uid=%d", getpid(), name, token.val[0]);
+#endif
+ return KERN_FAILURE;
+ }
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_link %s = %d", getpid(), name, *procno);
+#endif
+ return status;
+}
+
+kern_return_t
+_lookup_one(mach_port_t server, int proc, inline_data indata, mach_msg_type_number_t indataCnt, inline_data outdata, mach_msg_type_number_t *outdataCnt)
+{
+ kern_return_t status;
+ security_token_t token;
+ unsigned int n;
+
+ token.val[0] = -1;
+ token.val[1] = -1;
+
+ status = MIG_SERVER_DIED;
+ for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
+ {
+ status = _lookup_one_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
+ }
+
+ if (status != KERN_SUCCESS)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_one %d status %u", getpid(), proc, status);
+#endif
+ return status;
+ }
+
+ if (token.val[0] != 0)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_one %d auth failure uid=%d", getpid(), proc, token.val[0]);
+#endif
+ return KERN_FAILURE;
+ }
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_one %d", getpid(), proc);
+#endif
+ return status;
+}
+
+kern_return_t
+_lookup_all(mach_port_t server, int proc, inline_data indata, mach_msg_type_number_t indataCnt, ooline_data *outdata, mach_msg_type_number_t *outdataCnt)
+{
+ kern_return_t status;
+ security_token_t token;
+ unsigned int n;
+
+ token.val[0] = -1;
+ token.val[1] = -1;
+
+ status = MIG_SERVER_DIED;
+ for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
+ {
+ status = _lookup_all_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
+ }
+
+ if (status != KERN_SUCCESS)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_all %d status %u", getpid(), proc, status);
+#endif
+ return status;
+ }
+
+ if (token.val[0] != 0)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_all %d auth failure uid=%d", getpid(), proc, token.val[0]);
+#endif
+ return KERN_FAILURE;
+ }
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_all %d", getpid(), proc);
+#endif
+ return status;
+}
+
+kern_return_t
+_lookup_ooall(mach_port_t server, int proc, ooline_data indata, mach_msg_type_number_t indataCnt, ooline_data *outdata, mach_msg_type_number_t *outdataCnt)
+{
+ kern_return_t status;
+ security_token_t token;
+ unsigned int n;
+
+ token.val[0] = -1;
+ token.val[1] = -1;
+
+ status = MIG_SERVER_DIED;
+ for (n = 0; (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
+ {
+ status = _lookup_ooall_secure(server, proc, indata, indataCnt, outdata, outdataCnt, &token);
+ }
+
+ if (status != KERN_SUCCESS)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_ooall %d status %u", getpid(), proc, status);
+#endif
+ return status;
+ }
+
+ if (token.val[0] != 0)
+ {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_ooall %d auth failure uid=%d", getpid(), proc, token.val[0]);
+#endif
+ return KERN_FAILURE;
+ }
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "pid %u _lookup_ooall %d", getpid(), proc);
+#endif
+ return status;
+}
* Copyright (C) 1989 by NeXT, Inc.
*/
+#ifndef _LU_UTILS_H_
+#define _LU_UTILS_H_
+
#import <netinfo/lookup_types.h>
#include <netinfo/ni.h>
#include <stdarg.h>
+#define LU_COPY_STRING(x) strdup(((x) == NULL) ? "" : x)
+
+#define LU_LONG_STRING_LENGTH 8192
+
+#define _lu_data_key_alias 10010
+#define _lu_data_key_bootp 10020
+#define _lu_data_key_bootparams 10030
+#define _lu_data_key_fstab 10040
+#define _lu_data_key_group 10050
+#define _lu_data_key_host 10060
+#define _lu_data_key_netgroup 10070
+#define _lu_data_key_network 10080
+#define _lu_data_key_printer 10090
+#define _lu_data_key_protocol 10100
+#define _lu_data_key_rpc 10110
+#define _lu_data_key_service 10120
+#define _lu_data_key_user 10130
+
+struct lu_thread_info
+{
+ void *lu_entry;
+ XDR *lu_xdr;
+ char *lu_vm;
+ unsigned int lu_vm_length;
+ unsigned int lu_vm_cursor;
+};
+
extern mach_port_t _lu_port;
extern unit *_lookup_buf;
extern int _lu_running(void);
+void *_lu_data_create_key(unsigned int key, void (*destructor)(void *));
+void _lu_data_set_key(unsigned int key, void *data);
+void *_lu_data_get_key(unsigned int key);
+void _lu_data_free_vm_xdr(struct lu_thread_info *tdata);
+
+int _lu_xdr_attribute(XDR *xdr, char **key, char ***val, unsigned int *count);
+
+ni_proplist *_lookupd_xdr_dictionary(XDR *inxdr);
int lookupd_query(ni_proplist *l, ni_proplist ***out);
ni_proplist *lookupd_make_query(char *cat, char *fmt, ...);
void ni_property_merge(ni_property *a, ni_property *b);
void ni_proplist_merge(ni_proplist *a, ni_proplist *b);
-typedef enum lookup_state {
- LOOKUP_CACHE,
- LOOKUP_FILE,
-} lookup_state;
-
-#define SETSTATE(_lu_set, _old_set, state, stayopen) \
-{ \
- if (_lu_running()) { \
- _lu_set(stayopen); \
- *state = LOOKUP_CACHE; \
- } else { \
- _old_set(stayopen); \
- *state = LOOKUP_FILE; \
- } \
-}
-
-#define SETSTATEVOID(_lu_set, _old_set, state) \
-{ \
- if (_lu_running()) { \
- _lu_set(); \
- *state = LOOKUP_CACHE; \
- } else { \
- _old_set(); \
- *state = LOOKUP_FILE; \
- } \
-}
-
-#define INTSETSTATEVOID(_lu_set, _old_set, state) \
-{ \
- int result; \
- if (_lu_running()) { \
- result = _lu_set(); \
- *state = LOOKUP_CACHE; \
- } else { \
- result = _old_set(); \
- *state = LOOKUP_FILE; \
- } \
- return result; \
-}
-
-#define UNSETSTATE(_lu_unset, _old_unset, state) \
-{ \
- if (_lu_running()) { \
- _lu_unset(); \
- } else { \
- _old_unset(); \
- } \
- *state = LOOKUP_CACHE; \
-}
-
-#define GETENT(_lu_get, _old_get, state, res_type) \
-{ \
- res_type *res; \
-\
- if (_lu_running()) { \
- if (*state == LOOKUP_CACHE) { \
- res = _lu_get(); \
- } else { \
- res = _old_get(); \
- } \
- } else { \
- res = _old_get(); \
- } \
- return (res); \
-}
-
-#define LOOKUP1(_lu_lookup, _old_lookup, arg, res_type) \
-{ \
- res_type *res; \
- \
- if (_lu_running()) { \
- res = _lu_lookup(arg); \
- } else { \
- res = _old_lookup(arg); \
- } \
- return (res); \
-}
+kern_return_t _lookup_link(mach_port_t server, lookup_name name, int *procno);
+kern_return_t _lookup_one(mach_port_t server, int proc, inline_data indata, mach_msg_type_number_t indataCnt, inline_data outdata, mach_msg_type_number_t *outdataCnt);
+kern_return_t _lookup_all(mach_port_t server, int proc, inline_data indata, mach_msg_type_number_t indataCnt, ooline_data *outdata, mach_msg_type_number_t *outdataCnt);
+kern_return_t _lookup_ooall(mach_port_t server, int proc, ooline_data indata, mach_msg_type_number_t indataCnt, ooline_data *outdata, mach_msg_type_number_t *outdataCnt);
-#define LOOKUP2(_lu_lookup, _old_lookup, arg1, arg2, res_type) \
-{ \
- res_type *res; \
- \
- if (_lu_running()) { \
- res = _lu_lookup(arg1, arg2); \
- } else { \
- res = _old_lookup(arg1, arg2); \
- } \
- return (res); \
-}
+#endif /* ! _LU_UTILS_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * Portions Copyright (c) 2002 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.1 (the "License"). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _NETDB_ASYNC_H_
+#define _NETDB_ASYNC_H_
+
+#include <sys/cdefs.h>
+#include <mach/mach.h>
+#include <netdb.h>
+
+__BEGIN_DECLS
+
+/*
+ @typedef gethostbyaddr_async_callback
+ @discussion Type of the callback function used when a
+ gethostbyaddr_async_start() request is delivered.
+ @param hent The resolved host entry.
+ @param context The context provided when the request
+ was initiated.
+ */
+typedef void (*gethostbyaddr_async_callback) (
+ struct hostent *hent,
+ void *context
+ );
+
+/*!
+ @function gethostbyaddr_async_start
+ @description Asynchronously resolves an Internet address
+ @param addr The address to be resolved.
+ @param len The length, in bytes, of the address.
+ @param type
+ @param callout The function to be called when the specified
+ address has been resolved.
+ @param context A user specified context which will be passed
+ to the callout function.
+ @result A mach reply port which will be sent a message when
+ the addr resolution has completed. This message
+ should be passed to the gethostbyaddr_async_handleReply
+ function. A NULL value indicates that no address
+ was specified or some other error occurred which
+ prevented the resolution from being started.
+ */
+mach_port_t
+gethostbyaddr_async_start (
+ const char *addr,
+ int len,
+ int type,
+ gethostbyaddr_async_callback callout,
+ void *context
+ );
+
+
+/*!
+ @function gethostbyaddr_async_handleReply
+ @description This function should be called with the Mach message sent
+ to the port returned by the call to gethostbyaddr_async_start.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void
+gethostbyaddr_async_handleReply (
+ void *replyMsg
+ );
+
+
+/*
+ @typedef gethostbyname_async_callback
+ @discussion Type of the callback function used when a
+ gethostbyname_async_start() request is delivered.
+ @param hent The resolved host entry.
+ @param context The context provided when the request
+ was initiated.
+ */
+typedef void (*gethostbyname_async_callback) (
+ struct hostent *hent,
+ void *context
+ );
+
+/*!
+ @function gethostbyname_async_start
+ @description Asynchronously resolves a hostname
+ @param name The hostname to be resolved.
+ @param callout The function to be called when the specified
+ hostname has been resolved.
+ @param context A user specified context which will be passed
+ to the callout function.
+ @result A mach reply port which will be sent a message when
+ the name resolution has completed. This message
+ should be passed to the gethostbyname_async_handleReply
+ function. A NULL value indicates that no hostname
+ was specified or some other error occurred which
+ prevented the resolution from being started.
+ */
+mach_port_t
+gethostbyname_async_start (
+ const char *name,
+ gethostbyname_async_callback callout,
+ void *context
+ );
+
+
+/*!
+ @function gethostbyname_async_handleReply
+ @description This function should be called with the Mach message sent
+ to the port returned by the call to gethostbyname_async_start.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void
+gethostbyname_async_handleReply (
+ void *replyMsg
+ );
+
+
+/*
+ @typedef getipnodebyaddr_async_callback
+ @discussion Type of the callback function used when a
+ getipnodebyaddr_async_start() request is delivered.
+ @param hent The resolved host entry. If not NULL, the caller
+ must call freehostent() on the host entry.
+ @param error If error code if the resolved host entry is NULL
+ @param context The context provided when the request
+ was initiated.
+ */
+typedef void (*getipnodebyaddr_async_callback) (
+ struct hostent *hent,
+ int error,
+ void *context
+ );
+
+/*!
+ @function getipnodebyaddr_async_start
+ @description Asynchronously resolves an Internet address
+ @param addr The address to be resolved.
+ @param len The length, in bytes, of the address.
+ @param af The address family
+ @param error
+ @param callout The function to be called when the specified
+ address has been resolved.
+ @param context A user specified context which will be passed
+ to the callout function.
+ @result A mach reply port which will be sent a message when
+ the addr resolution has completed. This message
+ should be passed to the getipnodebyaddr_async_handleReply
+ function. A NULL value indicates that no address
+ was specified or some other error occurred which
+ prevented the resolution from being started.
+ */
+mach_port_t
+getipnodebyaddr_async_start (
+ const void *addr,
+ size_t len,
+ int af,
+ int *error,
+ getipnodebyaddr_async_callback callout,
+ void *context
+ );
+
+
+/*!
+ @function getipnodebyaddr_async_handleReply
+ @description This function should be called with the Mach message sent
+ to the port returned by the call to getipnodebyaddr_async_start.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void
+getipnodebyaddr_async_handleReply (
+ void *replyMsg
+ );
+
+
+/*
+ @typedef getipnodebyname_async_callback
+ @discussion Type of the callback function used when a
+ getipnodebyname_async_start() request is delivered.
+ @param hent The resolved host entry. If not NULL, the caller
+ must call freehostent() on the host entry.
+ @param error If error code if the resolved host entry is NULL
+ @param context The context provided when the request
+ was initiated.
+ */
+typedef void (*getipnodebyname_async_callback) (
+ struct hostent *hent,
+ int error,
+ void *context
+ );
+
+/*!
+ @function getipnodebyname_async_start
+ @description Asynchronously resolves a hostname
+ @param name The hostname to be resolved.
+ @param af
+ @param flags
+ @param error
+ @param callout The function to be called when the specified
+ hostname has been resolved.
+ @param context A user specified context which will be passed
+ to the callout function.
+ @result A mach reply port which will be sent a message when
+ the name resolution has completed. This message
+ should be passed to the getipnodebyname_async_handleReply
+ function. A NULL value indicates that no hostname
+ was specified or some other error occurred which
+ prevented the resolution from being started.
+ */
+mach_port_t
+getipnodebyname_async_start (
+ const char *name,
+ int af,
+ int flags,
+ int *error,
+ getipnodebyname_async_callback callout,
+ void *context
+ );
+
+
+/*!
+ @function getipnodebyname_async_handleReply
+ @description This function should be called with the Mach message sent
+ to the port returned by the call to getipnodebyname_async_start.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void
+getipnodebyname_async_handleReply (
+ void *replyMsg
+ );
+
+__END_DECLS
+
+#endif /* !_NETDB_ASYNC_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "DNSServiceDiscovery.h"
+#include "DNSServiceDiscoveryDefines.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <servers/bootstrap.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <pthread.h>
+
+#include <netinet/in.h>
+
+extern struct rpc_subsystem internal_DNSServiceDiscoveryReply_subsystem;
+
+extern boolean_t DNSServiceDiscoveryReply_server(
+ mach_msg_header_t *InHeadP,
+ mach_msg_header_t *OutHeadP);
+
+extern
+kern_return_t DNSServiceBrowserCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString regtype,
+ DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceDomainEnumerationCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ int registrationDomains
+);
+
+extern
+kern_return_t DNSServiceRegistrationCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString name,
+ DNSCString regtype,
+ DNSCString domain,
+ int port,
+ DNSCString txtRecord
+);
+
+extern
+kern_return_t DNSServiceResolverResolve_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString name,
+ DNSCString regtype,
+ DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceRegistrationAddRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ int type,
+ record_data_t data,
+ mach_msg_type_number_t record_dataCnt,
+ uint32_t ttl,
+ natural_t *reference
+);
+
+extern
+int DNSServiceRegistrationUpdateRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ natural_t reference,
+ record_data_t data,
+ mach_msg_type_number_t record_dataCnt,
+ uint32_t ttl
+);
+
+extern
+kern_return_t DNSServiceRegistrationRemoveRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ natural_t reference
+);
+
+struct a_requests {
+ struct a_requests *next;
+ mach_port_t client_port;
+ union {
+ DNSServiceBrowserReply browserCallback;
+ DNSServiceDomainEnumerationReply enumCallback;
+ DNSServiceRegistrationReply regCallback;
+ DNSServiceResolverReply resolveCallback;
+ } callout;
+ void *context;
+};
+
+static struct a_requests *a_requests = NULL;
+static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
+
+typedef struct _dns_service_discovery_t {
+ mach_port_t port;
+} dns_service_discovery_t;
+
+mach_port_t DNSServiceDiscoveryLookupServer(void)
+{
+ static mach_port_t sndPort = MACH_PORT_NULL;
+ kern_return_t result;
+
+ if (sndPort != MACH_PORT_NULL) {
+ return sndPort;
+ }
+
+ result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort);
+ if (result != KERN_SUCCESS) {
+ printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result);
+ sndPort = MACH_PORT_NULL;
+ }
+
+
+ return sndPort;
+}
+
+void _increaseQueueLengthOnPort(mach_port_t port)
+{
+ mach_port_limits_t qlimits;
+ kern_return_t result;
+
+ qlimits.mpl_qlimit = 16;
+ result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT);
+
+ if (result != KERN_SUCCESS) {
+ printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result));
+ }
+}
+
+dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.browserCallback = callBack;
+
+ result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating a browser, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+/* Service Enumeration */
+
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.enumCallback = callBack;
+
+ result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating an enumerator, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+
+/* Service Registration */
+
+dns_service_discovery_ref DNSServiceRegistrationCreate
+(const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.regCallback = callBack;
+
+ result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, port, (char *)txtRecord);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating a resolve, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+/* Resolver requests */
+
+dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.resolveCallback = callBack;
+
+ DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ natural_t reference = 0;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
+
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ }
+
+ return reference;
+}
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ return result;
+ }
+
+ return kDNSServiceDiscoveryNoError;
+}
+
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
+
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ return result;
+ }
+
+ return kDNSServiceDiscoveryNoError;
+}
+
+void DNSServiceDiscovery_handleReply(void *replyMsg)
+{
+ unsigned long result = 0xFFFFFFFF;
+ mach_msg_header_t * msgSendBufPtr;
+ mach_msg_header_t * receivedMessage;
+ unsigned msgSendBufLength;
+
+ msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
+ msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
+
+
+ receivedMessage = ( mach_msg_header_t * ) replyMsg;
+
+ // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
+ // genuine mach message. It will then cause the callback to get called.
+ result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
+ ( void ) mach_msg_send ( msgSendBufPtr );
+ free(msgSendBufPtr);
+}
+
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
+{
+ return dnsServiceDiscovery->port;
+}
+
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
+{
+ struct a_requests *request0, *request;
+ mach_port_t reply = dnsServiceDiscovery->port;
+
+ if (dnsServiceDiscovery->port) {
+ pthread_mutex_lock(&a_requests_lock);
+ request0 = NULL;
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ /* request info found, remove from list */
+ if (request0) {
+ request0->next = request->next;
+ } else {
+ a_requests = request->next;
+ }
+ break;
+ } else {
+ /* not info for this request, skip to next */
+ request0 = request;
+ request = request->next;
+ }
+
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ free(request);
+
+ mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
+
+ free(dnsServiceDiscovery);
+ }
+ return;
+}
+
+// reply functions, calls the users setup callbacks with function pointers
+
+kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
+(
+ mach_port_t reply,
+ int resultType,
+ DNSCString replyDomain,
+ DNSServiceDiscoveryReplyFlags flags
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceDomainEnumerationReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+
+ if (request != NULL) {
+ callback = (*request->callout.enumCallback);
+ requestContext = request->context;
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(resultType, replyDomain, flags, requestContext);
+ }
+
+ return KERN_SUCCESS;
+
+}
+
+kern_return_t internal_DNSServiceBrowserReply_rpc
+(
+ mach_port_t reply,
+ int resultType,
+ DNSCString replyName,
+ DNSCString replyType,
+ DNSCString replyDomain,
+ DNSServiceDiscoveryReplyFlags flags
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceBrowserReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+ if (request != NULL) {
+ callback = (*request->callout.browserCallback);
+ requestContext = request->context;
+ }
+
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
+ }
+
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceRegistrationReply_rpc
+(
+ mach_port_t reply,
+ int resultType
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceRegistrationReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+ if (request != NULL) {
+ callback = (*request->callout.regCallback);
+ requestContext = request->context;
+ }
+
+ pthread_mutex_unlock(&a_requests_lock);
+ if (request != NULL) {
+ (callback)(resultType, requestContext);
+ }
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceResolverReply_rpc
+(
+ mach_port_t reply,
+ sockaddr_t interface,
+ sockaddr_t address,
+ DNSCString txtRecord,
+ DNSServiceDiscoveryReplyFlags flags
+)
+{
+ struct sockaddr *interface_storage = NULL;
+ struct sockaddr *address_storage = NULL;
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceResolverReply callback = NULL;
+
+ if (interface) {
+ int len = ((struct sockaddr *)interface)->sa_len;
+ interface_storage = (struct sockaddr *)malloc(len);
+ bcopy(interface, interface_storage,len);
+ }
+
+ if (address) {
+ int len = ((struct sockaddr *)address)->sa_len;
+ address_storage = (struct sockaddr *)malloc(len);
+ bcopy(address, address_storage, len);
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+
+ if (request != NULL) {
+ callback = (*request->callout.resolveCallback);
+ requestContext = request->context;
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
+ }
+
+ if (interface) {
+ free(interface_storage);
+ }
+ if (address) {
+ free(address_storage);
+ }
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+* "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __DNS_SERVICE_DISCOVERY_H
+#define __DNS_SERVICE_DISCOVERY_H
+
+#include <mach/mach_types.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/cdefs.h>
+
+#include <netinet/in.h>
+
+__BEGIN_DECLS
+
+/* Opaque internal data type */
+typedef struct _dns_service_discovery_t * dns_service_discovery_ref;
+
+/* possible reply flags values */
+
+enum {
+ kDNSServiceDiscoveryNoFlags = 0,
+ kDNSServiceDiscoveryMoreRepliesImmediately = 1 << 0,
+};
+
+
+/* possible error code values */
+typedef enum
+{
+ kDNSServiceDiscoveryWaiting = 1,
+ kDNSServiceDiscoveryNoError = 0,
+ // mDNS Error codes are in the range
+ // FFFE FF00 (-65792) to FFFE FFFF (-65537)
+ kDNSServiceDiscoveryUnknownErr = -65537, // 0xFFFE FFFF
+ kDNSServiceDiscoveryNoSuchNameErr = -65538,
+ kDNSServiceDiscoveryNoMemoryErr = -65539,
+ kDNSServiceDiscoveryBadParamErr = -65540,
+ kDNSServiceDiscoveryBadReferenceErr = -65541,
+ kDNSServiceDiscoveryBadStateErr = -65542,
+ kDNSServiceDiscoveryBadFlagsErr = -65543,
+ kDNSServiceDiscoveryUnsupportedErr = -65544,
+ kDNSServiceDiscoveryNotInitializedErr = -65545,
+ kDNSServiceDiscoveryNoCache = -65546,
+ kDNSServiceDiscoveryAlreadyRegistered = -65547,
+ kDNSServiceDiscoveryNameConflict = -65548,
+ kDNSServiceDiscoveryInvalid = -65549,
+ kDNSServiceDiscoveryMemFree = -65792 // 0xFFFE FF00
+} DNSServiceRegistrationReplyErrorType;
+
+typedef uint32_t DNSRecordReference;
+
+
+/*!
+@function DNSServiceResolver_handleReply
+ @description This function should be called with the Mach message sent
+ to the port returned by the call to DNSServiceResolverResolve.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void DNSServiceDiscovery_handleReply(void *replyMsg);
+
+/* Service Registration */
+
+typedef void (*DNSServiceRegistrationReply) (
+ DNSServiceRegistrationReplyErrorType errorCode,
+ void *context
+);
+
+/*!
+@function DNSServiceRegistrationCreate
+ @description Register a named service with DNS Service Discovery
+ @param name The name of this service instance (e.g. "Steve's Printer")
+ @param regtype The service type (e.g. "_printer._tcp." -- see
+ RFC 2782 (DNS SRV) and <http://www.iana.org/assignments/port-numbers>)
+ @param domain The domain in which to register the service (e.g. "apple.com.")
+ @param port The local port on which this service is being offered (in network byte order)
+ @param txtRecord Optional protocol-specific additional information
+ @param callBack The DNSServiceRegistrationReply function to be called
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceRegistrationCreate
+(
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ uint16_t port,
+ const char *txtRecord,
+ DNSServiceRegistrationReply callBack,
+ void *context
+);
+
+/***************************************************************************/
+/* DNS Domain Enumeration */
+
+typedef enum
+{
+ DNSServiceDomainEnumerationReplyAddDomain, // Domain found
+ DNSServiceDomainEnumerationReplyAddDomainDefault, // Domain found (and should be selected by default)
+ DNSServiceDomainEnumerationReplyRemoveDomain, // Domain has been removed from network
+} DNSServiceDomainEnumerationReplyResultType;
+
+typedef enum
+{
+ DNSServiceDiscoverReplyFlagsFinished,
+ DNSServiceDiscoverReplyFlagsMoreComing,
+} DNSServiceDiscoveryReplyFlags;
+
+typedef void (*DNSServiceDomainEnumerationReply) (
+ DNSServiceDomainEnumerationReplyResultType resultType, // One of DNSServiceDomainEnumerationReplyResultType
+ const char *replyDomain,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+);
+
+/*!
+ @function DNSServiceDomainEnumerationCreate
+ @description Asynchronously create a DNS Domain Enumerator
+ @param registrationDomains A boolean indicating whether you are looking
+ for recommended registration domains
+ (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel)
+ or recommended browsing domains
+ (e.g. equivalent to the AppleTalk zone list in the Chooser).
+ @param callBack The function to be called when domains are found or removed
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate
+(
+ int registrationDomains,
+ DNSServiceDomainEnumerationReply callBack,
+ void *context
+);
+
+/***************************************************************************/
+/* DNS Service Browser */
+
+typedef enum
+{
+ DNSServiceBrowserReplyAddInstance, // Instance of service found
+ DNSServiceBrowserReplyRemoveInstance // Instance has been removed from network
+} DNSServiceBrowserReplyResultType;
+
+typedef void (*DNSServiceBrowserReply) (
+ DNSServiceBrowserReplyResultType resultType, // One of DNSServiceBrowserReplyResultType
+ const char *replyName,
+ const char *replyType,
+ const char *replyDomain,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+);
+
+/*!
+ @function DNSServiceBrowserCreate
+ @description Asynchronously create a DNS Service browser
+ @param regtype The type of service
+ @param domain The domain in which to find the service
+ @param callBack The function to be called when service instances are found or removed
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceBrowserCreate
+(
+ const char *regtype,
+ const char *domain,
+ DNSServiceBrowserReply callBack,
+ void *context
+);
+
+/***************************************************************************/
+/* Resolver requests */
+
+typedef void (*DNSServiceResolverReply) (
+ struct sockaddr *interface, // Needed for scoped addresses like link-local
+ struct sockaddr *address,
+ const char *txtRecord,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+);
+
+/*!
+@function DNSServiceResolverResolve
+ @description Resolved a named instance of a service to its address, port, and
+ (optionally) other demultiplexing information contained in the TXT record.
+ @param name The name of the service instance
+ @param regtype The type of service
+ @param domain The domain in which to find the service
+ @param callBack The DNSServiceResolverReply function to be called when the specified
+ address has been resolved.
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+
+dns_service_discovery_ref DNSServiceResolverResolve
+(
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolverReply callBack,
+ void *context
+);
+
+/***************************************************************************/
+/* Mach port accessor and deallocation */
+
+/*!
+ @function DNSServiceDiscoveryMachPort
+ @description Returns the mach port for a dns_service_discovery_ref
+ @param registration A dns_service_discovery_ref as returned from DNSServiceRegistrationCreate
+ @result A mach reply port which will be sent messages as appropriate.
+ These messages should be passed to the DNSServiceDiscovery_handleReply
+ function. A NULL value indicates that no address was
+ specified or some other error occurred which prevented the
+ resolution from being started.
+*/
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery);
+
+/*!
+ @function DNSServiceDiscoveryDeallocate
+ @description Deallocates the DNS Service Discovery type / closes the connection to the server
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a creation or enumeration call
+ @result void
+*/
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery);
+
+/***************************************************************************/
+/* Registration updating */
+
+
+/*!
+ @function DNSServiceRegistrationAddRecord
+ @description Request that the mDNS Responder add the DNS Record of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters
+ @param rdlen Length of the data
+ @param rdata Opaque binary Resource Record data, up to 64 kB.
+ @param ttl time to live for the added record.
+ @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls. If an error occurs, this value will be zero or negative
+*/
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl);
+
+/*!
+ @function DNSServiceRegistrationUpdateRecord
+ @description Request that the mDNS Responder add the DNS Record of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+ @param rdlen Length of the data
+ @param rdata Opaque binary Resource Record data, up to 64 kB.
+ @param ttl time to live for the updated record.
+ @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+*/
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl);
+
+/*!
+ @function DNSServiceRegistrationRemoveRecord
+ @description Request that the mDNS Responder remove the DNS Record(s) of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+ @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+*/
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference);
+
+
+__END_DECLS
+
+#endif /* __DNS_SERVICE_DISCOVERY_H */
--- /dev/null
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __DNS_SERVICE_DISCOVERY_DEFINES_H
+#define __DNS_SERVICE_DISCOVERY_DEFINES_H
+
+#include <mach/mach_types.h>
+
+#define DNS_SERVICE_DISCOVERY_SERVER "DNSServiceDiscoveryServer"
+
+typedef char DNSCString[1024];
+typedef char sockaddr_t[128];
+
+typedef const char * record_data_t;
+
+#endif /* __DNS_SERVICE_DISCOVERY_DEFINES_H */
+
--- /dev/null
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+subsystem
+ DNSServiceDiscoveryReply 7250;
+
+ServerPrefix internal_;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+import "DNSServiceDiscoveryDefines.h";
+
+type DNSCString = c_string[*:1024];
+type sockaddr_t = array[128] of char;
+
+simpleroutine DNSServiceDomainEnumerationReply_rpc(
+ reply: mach_port_t;
+ in resultType: int;
+ in replyDomain: DNSCString;
+ in flags: int;
+ SendTime to: natural_t);
+
+simpleroutine DNSServiceBrowserReply_rpc(
+ reply: mach_port_t;
+ in resultType: int;
+ in replyName: DNSCString;
+ in replyType: DNSCString;
+ in replyDomain: DNSCString;
+ in flags: int;
+ SendTime to: natural_t);
+
+
+simpleroutine DNSServiceRegistrationReply_rpc(
+ reply: mach_port_t;
+ in resultType: int;
+ SendTime to: natural_t);
+
+
+simpleroutine DNSServiceResolverReply_rpc(
+ reply: mach_port_t;
+ in interface: sockaddr_t;
+ in address: sockaddr_t;
+ in txtRecord: DNSCString;
+ in flags: int;
+ SendTime to: natural_t);
+
--- /dev/null
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+subsystem
+ DNSServiceDiscoveryRequest 7200;
+
+ServerPrefix provide_;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+import "DNSServiceDiscoveryDefines.h";
+
+type DNSCString = c_string[*:1024];
+type record_data = ^ array [] of MACH_MSG_TYPE_BYTE
+ ctype: record_data_t;
+
+simpleroutine DNSServiceBrowserCreate_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in regtype: DNSCString;
+ in domain: DNSCString);
+
+
+simpleroutine DNSServiceDomainEnumerationCreate_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in registrationDomains: int);
+
+simpleroutine DNSServiceRegistrationCreate_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in name: DNSCString;
+ in regtype: DNSCString;
+ in domain: DNSCString;
+ in port: int;
+ in txtRecord: DNSCString);
+
+
+simpleroutine DNSServiceResolverResolve_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in name: DNSCString;
+ in regtype: DNSCString;
+ in domain: DNSCString);
+
+routine DNSServiceRegistrationAddRecord_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in record_type: int;
+ in record_data: record_data;
+ in ttl: uint32_t;
+ out record_reference: natural_t);
+
+simpleroutine DNSServiceRegistrationUpdateRecord_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in record_reference: natural_t;
+ in record_data: record_data;
+ in ttl: uint32_t);
+
+simpleroutine DNSServiceRegistrationRemoveRecord_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in record_reference: natural_t);
+
--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = mdns
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Component
+
+HFILES = DNSServiceDiscoveryDefines.h DNSServiceDiscovery.h
+
+CFILES = DNSServiceDiscovery.c
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble\
+ DNSServiceDiscoveryReply.defs DNSServiceDiscoveryRequest.defs
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = subproj.make
+NEXTSTEP_INSTALLDIR = /usr/local/lib/system
+LIBS =
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_PUBLIC_HEADERS_DIR = /usr/include
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+###############################################################################
+# Makefile.postamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile, which is imported after all other makefiles, to
+# override attributes for a project's Makefile environment. This allows you
+# to take advantage of the environment set up by the other Makefiles.
+# You can also define custom rules at the end of this file.
+#
+###############################################################################
+#
+# These variables are exported by the standard makefiles and can be
+# used in any customizations you make. They are *outputs* of
+# the Makefiles and should be used, not set.
+#
+# PRODUCTS: products to install. All of these products will be placed in
+# the directory $(DSTROOT)$(INSTALLDIR)
+# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
+# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
+# OFILE_DIR: Directory into which .o object files are generated.
+# DERIVED_SRC_DIR: Directory used for all other derived files
+#
+# ALL_CFLAGS: flags to pass when compiling .c files
+# ALL_MFLAGS: flags to pass when compiling .m files
+# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
+# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
+# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
+# ALL_LDFLAGS: flags to pass when linking object files
+# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
+# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
+# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
+# ALL_YFLAGS: flags to pass when processing .y (yacc) files
+# ALL_LFLAGS: flags to pass when processing .l (lex) files
+#
+# NAME: name of application, bundle, subproject, palette, etc.
+# LANGUAGES: langages in which the project is written (default "English")
+# English_RESOURCES: localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES: non-localized resources of project
+#
+# SRCROOT: base directory in which to place the new source files
+# SRCPATH: relative path from SRCROOT to present subdirectory
+#
+# INSTALLDIR: Directory the product will be installed into by 'install' target
+# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+#
+# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
+#
+###############################################################################
+
+# Some compiler flags can be overridden here for certain build situations.
+#
+# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
+# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
+# to -g)
+# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
+# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
+# to -O)
+# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
+# to -pg -DPROFILE)
+# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
+# the include path (defaults to -I.)
+# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
+# passed to ld/libtool (defaults to nothing)
+
+
+# Library and Framework projects only:
+# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
+# against the framework will run against the correct version even if
+# the current version of the framework changes. You may override this
+# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
+# development cycle, but be sure to restore it before installing.
+
+
+# Ownership and permissions of files installed by 'install' target
+
+#INSTALL_AS_USER = root
+ # User/group ownership
+#INSTALL_AS_GROUP = wheel
+ # (probably want to set both of these)
+#INSTALL_PERMISSIONS =
+ # If set, 'install' chmod's executable to this
+
+
+# Options to strip. Note: -S strips debugging symbols (executables can be stripped
+# down further with -x or, if they load no bundles, with no options at all).
+
+#STRIPFLAGS = -S
+
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. Include them in
+# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
+#
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
+
+mdns_hdrs: $(DSTROOT)$(PRIVATE_HDR_INSTALLDIR)$(MDNS_HEADER_DIR_SUFFIX)
+ $(SILENT) $(FASTCP) $(MDNS_HDRS) $(DSTROOT)$(PRIVATE_HDR_INSTALLDIR)$(MDNS_HEADER_DIR_SUFFIX)
+
+$(DSTROOT)$(PRIVATE_HDR_INSTALLDIR)$(MDNS_HEADER_DIR_SUFFIX):
+ $(MKDIRS) $@
--- /dev/null
+###############################################################################
+# Makefile.preamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile for configuring the standard application makefiles
+# associated with ProjectBuilder. It is included before the main makefile.
+# In Makefile.preamble you set attributes for a project, so they are available
+# to the project's makefiles. In contrast, you typically write additional rules or
+# override built-in behavior in the Makefile.postamble.
+#
+# Each directory in a project tree (main project plus subprojects) should
+# have its own Makefile.preamble and Makefile.postamble.
+###############################################################################
+#
+# Before the main makefile is included for this project, you may set:
+#
+# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
+# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
+
+# Compiler/linker flags added to the defaults: The OTHER_* variables will be
+# inherited by all nested sub-projects, but the LOCAL_ versions of the same
+# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
+# Build Attributes inspector if at all possible. To override the default flags
+# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
+# variables below are *inputs* to the build process and distinct from the override
+# settings done (less often) in the Makefile.postamble.
+#
+# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
+# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
+# .cc, .cxx, .C, and .M files. There is no need to respecify the
+# flags in OTHER_MFLAGS, etc.
+# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
+# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
+# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
+# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
+# precompiling header files
+# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
+# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
+# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
+# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
+# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
+
+# These variables provide hooks enabling you to add behavior at almost every
+# stage of the make:
+#
+# BEFORE_PREBUILD: targets to build before installing headers for a subproject
+# AFTER_PREBUILD: targets to build after installing headers for a subproject
+# BEFORE_BUILD_RECURSION: targets to make before building subprojects
+# BEFORE_BUILD: targets to make before a build, but after subprojects
+# AFTER_BUILD: targets to make after a build
+#
+# BEFORE_INSTALL: targets to build before installing the product
+# AFTER_INSTALL: targets to build after installing the product
+# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
+# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
+#
+# BEFORE_INSTALLHDRS: targets to build before installing headers for a
+# subproject
+# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
+# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
+# AFTER_INSTALLSRC: targets to build after installing source for a subproject
+#
+# BEFORE_DEPEND: targets to build before building dependencies for a
+# subproject
+# AFTER_DEPEND: targets to build after building dependencies for a
+# subproject
+#
+# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
+# updated every time the project is built. If NO, the dependency
+# file is only built when the depend target is invoked.
+
+# Framework-related variables:
+# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the framework's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+
+# Library-related variables:
+# PUBLIC_HEADER_DIR: Determines where public exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically. For library projects you should
+# set this to something like /Developer/Headers/$(NAME). Do not set
+# this variable for framework projects unless you do not want the
+# header files included in the framework.
+# PRIVATE_HEADER_DIR: Determines where private exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically.
+# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
+# whether the libraries produced are statically linked when they
+# are used or if they are dynamically loadable. This defaults to
+# DYNAMIC.
+# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the library's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+#
+# INSTALL_AS_USER: owner of the intalled products (default root)
+# INSTALL_AS_GROUP: group of the installed products (default wheel)
+# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
+#
+# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
+# passed on the command line to recursive invocations of make. Note that
+# the values in OTHER_*FLAGS are inherited by subprojects automatically --
+# you do not have to (and shouldn't) add OTHER_*FLAGS to
+# OTHER_RECURSIVE_VARIABLES.
+
+# Additional headers to export beyond those in the PB.project:
+# OTHER_PUBLIC_HEADERS
+# OTHER_PROJECT_HEADERS
+# OTHER_PRIVATE_HEADERS
+
+# Additional files for the project's product: <<path relative to proj?>>
+# OTHER_RESOURCES: (non-localized) resources for this project
+# OTHER_OFILES: relocatables to be linked into this project
+# OTHER_LIBS: more libraries to link against
+# OTHER_PRODUCT_DEPENDS: other dependencies of this project
+# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
+# OTHER_GARBAGE: additional files to be removed by `make clean'
+
+# Set this to YES if you don't want a final libtool call for a library/framework.
+# BUILD_OFILES_LIST_ONLY
+
+# To include a version string, project source must exist in a directory named
+# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
+# OTHER_GENERATED_OFILES = $(VERS_OFILE)
+
+# This definition will suppress stripping of debug symbols when an executable
+# is installed. By default it is YES.
+# STRIP_ON_INSTALL = NO
+
+# Uncomment to suppress generation of a KeyValueCoding index when installing
+# frameworks (This index is used by WOB and IB to determine keys available
+# for an object). Set to YES by default.
+# PREINDEX_FRAMEWORK = NO
+
+# Change this definition to install projects somewhere other than the
+# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
+# and "" on other systems.
+DSTROOT = $(HOME)
+
+# Additional flags (MiG generated files)
+OTHER_OFILES = DNSServiceDiscoveryRequestUser.o DNSServiceDiscoveryReplyServer.o
+
+#private headers
+MDNS_HDRS = DNSServiceDiscoveryRequest.defs DNSServiceDiscoveryRequest.h \
+ DNSServiceDiscoveryReply.defs DNSServiceDiscoveryReply.h DNSServiceDiscoveryDefines.h
+
+BEFORE_INSTALLHDRS += $(SFILE_DIR) $(MDNS_HDRS)
+AFTER_INSTALLHDRS += mdns_hdrs
+PRIVATE_HEADER_DIR = /AppleInternal/Developer/Headers
+MDNS_HEADER_DIR_SUFFIX = /DNSServiceDiscovery
+
+# public headers
+OTHER_PUBLIC_HEADERS = DNSServiceDiscovery.h
+PUBLIC_HEADER_DIR_SUFFIX = /DNSServiceDiscovery
--- /dev/null
+{
+ DYNAMIC_CODE_GEN = YES;
+ English_RESOURCES = {};
+ FILESTABLE = {
+ H_FILES = (DNSServiceDiscoveryDefines.h, DNSServiceDiscovery.h);
+ OTHER_LINKED = (DNSServiceDiscovery.c);
+ OTHER_RESOURCES = ();
+ OTHER_SOURCES = (
+ Makefile.preamble,
+ Makefile,
+ Makefile.postamble,
+ DNSServiceDiscoveryReply.defs,
+ DNSServiceDiscoveryRequest.defs
+ );
+ PUBLIC_HEADERS = ();
+ SUBPROJECTS = ();
+ };
+ LANGUAGE = English;
+ MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
+ NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
+ NEXTSTEP_INSTALLDIR = /usr/local/lib/system;
+ NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
+ NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ NEXTSTEP_PUBLICHEADERSDIR = /usr/include;
+ PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
+ PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = mdns;
+ PROJECTTYPE = Component;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
ni_util.c sys_interfaces.c
OTHERSRCS = Makefile.preamble Makefile Makefile.postamble nibind_prot.x\
- ni_prot.x
+ ni_prot.x netinfo.3 netinfo.5
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+MAN3DIR=/usr/share/man/man3
+MAN5DIR=/usr/share/man/man5
+
+install-netinfo-man:
+ install -m 755 -o root -g wheel -d $(DSTROOT)$(MAN3DIR)
+ install -m 644 -o root -g wheel -c netinfo.3 "$(DSTROOT)$(MAN3DIR)"
+ install -m 755 -o root -g wheel -d $(DSTROOT)$(MAN5DIR)
+ install -m 644 -o root -g wheel -c netinfo.5 "$(DSTROOT)$(MAN5DIR)"
+
%_clnt.c: %.x
$(RPCGEN) $(ALL_RPCFLAGS) -l -o $(SYM_DIR)/$*_clnt.c $*.x
OTHER_OFILES = nibind_prot_clnt.o ni_prot_clnt.o nibind_prot_xdr.o ni_prot_xdr.o
NETINFO_HEADERS = nibind_prot.h ni_prot.h
AFTER_PREBUILD = $(NETINFO_HEADERS)
+AFTER_POSTINSTALL += install-netinfo-man
OTHER_PUBLIC_HEADERS = $(NETINFO_HEADERS)
BEFORE_INSTALLHEADERS += $(NETINFO_HEADERS)
PUBLIC_HEADER_DIR_SUFFIX = /netinfo
FILESTABLE = {
H_FILES = (clib.h, mm.h, ni.h, ni_util.h, sys_interfaces.h);
OTHER_LINKED = (multi_call.c, ni_error.c, ni_glue.c, ni_pwdomain.c, ni_useful.c, ni_util.c, sys_interfaces.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, nibind_prot.x, ni_prot.x);
+ OTHER_SOURCES = (
+ Makefile.preamble,
+ Makefile,
+ Makefile.postamble,
+ nibind_prot.x,
+ ni_prot.x,
+ netinfo.3,
+ netinfo.5
+ );
PUBLIC_HEADERS = (ni.h, ni_util.h);
};
LANGUAGE = English;
--- /dev/null
+.TH NETINFO 3 "August 29, 1989" "Apple Computer, Inc."
+.SH NAME
+netinfo \- library routines for NetInfo calls
+.SH SYNOPSIS
+\fB#include <netinfo/ni.h>\fR
+.SH DESCRIPTION
+These calls are the programming interface to NetInfo. Typically,
+a handle (of type "void *") is allocated through a call to
+.I ni_new,
+.I ni_open,
+or
+.I ni_connect.
+This handle opens a connection to the given NetInfo domain. Read calls
+may go to either the master or the clone servers, while writes will
+always go to the master server. If the master is unavailable,
+no writes can be performed.
+The handle is then passed to one of several NetInfo routines for database
+operations and then freed using
+.I ni_free.
+Several utility routines are also supplied which operate on NetInfo data
+structures. These routines don't require NetInfo handles.
+.LP
+.SH MACROS
+.PP
+.B NI_INDEX_NULL
+.IP
+A constant which evaluates to the highest unsigned integer. It is useful
+for indicating something which should go at the end of a list, as opposed
+to a smaller value which indicates the precise position at which the insert
+should occur.
+.PP
+\fBNI_INIT\fR(\fIptr\fR)
+.IP
+Initializes a NetInfo data structure. It effectively zeros out the structure
+referred to by
+.I ptr.
+This macro is useful for indicating an empty list or NULL value with one
+of the many NetInfo data structures.
+.SH "DATATYPES AND ASSOCIATED UTILITY ROUTINES"
+.PP
+.B ni_status
+.IP
+The result code of most NetInfo routines.
+.PP
+const char *\fBni_error\fR(ni_status \fIstatus\fR)
+.IP
+Returns the error string associated with the given NetInfo status.
+.PP
+.B ni_index
+.IP
+An index into a NetInfo list.
+.PP
+.B ni_id
+.IP
+NetInfo directories are identified through the
+.I ni_id
+data structure. It records the ID of the directory in the
+.I nii_object
+field and the instance of the directory in the
+.I nii_instance
+field. The instance indicates which version of the directory is being
+operated on and is only relevant for writes. Each time a write is
+performed, the instance is incremented to reflect the new version. If
+the instance given does not match the current instance of the directory,
+the error NI_STALE is returned, indicating a stale ID. All NetInfo
+routines which operate on directories will return the latest value of
+the instance.
+.PP
+.B ni_name
+.IP
+A NetInfo name. It is equivalent to a C string.
+.PP
+ni_name \fBni_name_dup\fR(const ni_name \fIname\fR)
+.IP
+Returns a mallocated copy of a NetInfo name.
+.PP
+void \fBni_name_free\fR(ni_name *\fInamep\fR)
+.IP
+Frees a NetInfo name. The pointer is converted to NULL. A NULL pointer
+will not be freed.
+.PP
+int \fBni_name_match\fR(const ni_name \fIname1\fR, const ni_name \fIname2\fR)
+.IP
+Compares two NetInfo names for equality. Returns non-zero for success,
+zero for failure.
+.PP
+.B ni_namelist
+.IP
+A list of NetInfo names.
+.PP
+ni_namelist \fBni_namelist_dup\fR(const ni_namelist \fInl\fR)
+.IP
+Returns a mallocated duplicate of a NetInfo namelist.
+.PP
+void \fBni_namelist_free\fR(ni_namelist *\fInl\fR)
+.IP
+Frees a NetInfo namelist. The namelist structure is zeroed. Zeroed
+namelists will not be freed.
+.PP
+void \fBni_namelist_insert\fR(ni_namelist *\fInl\fR, const ni_name \fIname\fR, ni_index \fIwhere\fR)
+.IP
+Duplicates and inserts the given name at the given location into the namelist.
+.PP
+void \fBni_namelist_delete\fR(ni_namelist *\fInl\fR, ni_index \fIwhere\fR)
+.IP
+Deletes and frees the name at the given location in the namelist.
+.PP
+ni_index \fBni_namelist_match\fR(const ni_namelist \fInl\fR, const ni_name \fIname\fR)
+.IP
+If the name is in the given namelist, the first index of its occurrence
+is returned. Otherwise, NI_INDEX_NULL is returned indicating failure.
+.PP
+.B ni_property
+.IP
+A NetInfo property. It contains a name and a namelist of associated values.
+.PP
+ni_property \fBni_prop_dup\fR(const ni_property \fIprop\fR)
+.IP
+Returns a mallocated duplicate of the given NetInfo property.
+.PP
+void \fBni_prop_free\fR(ni_property *\fIprop\fR)
+.IP
+Frees and zeros the NetInfo property. Zeroed properties will not be freed
+again.
+.PP
+.B ni_proplist
+.IP
+A list of NetInfo properties.
+.PP
+void \fBni_proplist_insert\fR(ni_proplist *\fIpl\fR, const ni_property \fIprop\fR, ni_index \fIwhere\fR)
+.IP
+Duplicates and inserts the given property at the given location into the given property
+list.
+.PP
+void \fBni_proplist_delete\fR(ni_proplist *\fIpl\fR, ni_index \fIwhere\fR)
+.IP
+Frees and deletes the property at the given location in the property list.
+.PP
+ni_index \fBni_proplist_match\fR(const ni_proplist \fIpl\fR, const ni_name \fIname\fR, const ni_name \fIval\fR)
+.IP
+Returns the location in the property list of the first property with a name
+of
+.I name
+and having value
+.I val.
+NI_INDEX_NULL is returned on failure.
+If NULL is the \fIvalue\fR argument,
+\fBni_proplist_match\fR will match on only the \fIname\fR argument.
+.PP
+ni_proplist \fBni_proplist_dup\fR(const ni_proplist \fIpl\fR)
+.IP
+Returns a mallocated duplicate property list.
+.PP
+void \fBni_proplist_free\fR(ni_proplist *\fIpl\fR)
+.IP
+Frees and zeroes the property list. A zeroed property will not be freed again.
+.PP
+.B ni_idlist
+.IP
+A list of NetInfo indices (usually directory ID's).
+.PP
+void \fBni_idlist_free\fR(ni_idlist *\fIidl\fR)
+.IP
+Frees and zeroes the given ID list. A zeroed ID list will not be freed again.
+.PP
+.B ni_entry
+.IP
+An entry in a NetInfo directory. It contains the ID of the directory and
+a list of values assocated with whatever property was requested in the
+.I ni_list
+routine. The list may be NULL, indicating that there is not associated
+property for this directory.
+.PP
+.B ni_entrylist
+.IP
+A list of NetInfo entries.
+.PP
+void \fBni_entrylist_free\fR(ni_entrylist *\fIentries\fR)
+.IP
+Frees and zeros the given entry list. A zeroed entry list will not be
+freed again.
+.LP
+.SH "ROUTINES"
+.PP
+ni_status \fBni_addrtag\fR(void *\fIhandle\fR, struct sockaddr_in *\fIaddr\fR, ni_name *\fItag\fR)
+.IP
+Returns the address and domain tag associated with the connected
+NetInfo handle.
+.PP
+ni_status \fBni_children\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_idlist *\fIidlist\fR)
+.IP
+Lists the children ID's (subdirectories) of the given directory.
+.PP
+void *\fBni_connect\fR(struct sockaddr_in *\fIaddr\fR, ni_name \fItag\fR)
+.IP
+Returns a NetInfo handle to the NetInfo domain at the given address
+and domain tag. Returns NULL on failure.
+.PP
+ni_status \fBni_create\fR(void *\fIhandle\fR, ni_id *\fIparent\fR, ni_proplist \fIprops\fR, ni_id *\fIchild\fR, ni_index \fIwhere\fR)
+.IP
+Creates a new directory at the given index initialized with the given
+properties.
+.PP
+ni_status \fBni_createname\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIprop_index\fR, ni_name \fIname\fR, ni_index \fIval_index\fR)
+.IP
+Inserts the name into the value list of the given directory at the property
+indexed by prop_index and value list location val_index.
+.PP
+ni_status \fBni_createprop\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_property \fIprop\fR, ni_index \fIwhere\fR)
+.IP
+Creates a new property at the given index in the given directory.
+.PP
+ni_status \fBni_destroy\fR(void *\fIhandle\fR, ni_id *\fIparent\fR, ni_id \fIchild\fR)
+.IP
+Destroys the directory child in the given parent directory. Both instance
+must be the latest values or the error NI_STALE is returned.
+.PP
+ni_status \fBni_destroyname\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIprop_index\fR, ni_index \fIval_index\fR)
+.IP
+Destroys a property value in the given directory at the given prop_index and
+value-list val_index.
+.PP
+ni_status \fBni_destroyprop\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIwhere\fR)
+.IP
+Destroys the property at property index
+.I where
+in the given directory.
+.PP
+ni_status \fBni_fancyopen\fR(void *\fIhandle\fR, ni_name \fIdomain\fR, void **\fIrethandle\fR, ni_fancyopenargs *\fIargs\fR)
+.PP
+.nf
+typedef struct ni_fancyopenargs {
+ int rtimeout;
+ int wtimeout;
+ int abort;
+ int needwrite;
+} ni_fancyopenargs;
+.fi
+.IP
+A fancier version of ni_open which allows one to set
+various attributes on the the returned handle. See
+.I ni_setreadtimeout(),
+.I ni_setwritetimeout(),
+.I ni_setabort()
+and
+.I ni_needwrite()
+for descriptions of the fields
+in the ni_fancyopenargs structure. A 0 in the
+rtimeout or wtimeout field indicates the
+default timeout should be used.
+.PP
+void \fBni_free\fR(void *\fIhandle\fR)
+.IP
+Frees a NetInfo handle and closes any associated connections.
+.PP
+ni_status \fBni_list\fR(void *\fIhandle\fR, ni_id *\fIdir\fR , ni_name \fIname\fR, ni_entrylist *\fIentries\fR)
+.IP
+Lists all the subdirectories of the given directory along with any associated
+values they may have for the property
+.I name.
+If a subdirectory doesn't have the property \fIname\fR,
+the entry is still returned but with a NULL property list.
+.PP
+ni_status \fBni_listprops\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_namelist *\fInl\fR)
+.IP
+Returns the list of property names associated with the given directory.
+.PP
+ni_status \fBni_lookup\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_name \fIname\fR, ni_name \fIval\fR, ni_idlist *\fIfound\fR)
+.IP
+Returns a list of subdirectories which satisfy the relation
+.I name
+equals
+.I val.
+.PP
+ni_status \fBni_lookupprop\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_name \fIname\fR, ni_namelist *\fIval\fR)
+.IP
+Returns the values associated with the property named
+.I name
+in the given directory.
+.PP
+ni_status \fBni_lookupread\fR(void *\fIhandle\fR, ni_id *\fIdirid\fR, ni_name \fIpropname\fR, ni_name \fIpropval\fR, ni_proplist *\fIprops\fR)
+.IP
+Looks up the subdirectory given the
+.I (propname, propval\)
+pair
+and returns the subdirectory's properties. This call is equivalent to
+an
+.I ni_lookup()
+followed by an
+.I ni_read().
+.PP
+void \fBni_needwrite\fR(void *\fIhandle\fR, int \fIneedwrite\fR)
+.IP
+Indicates whether subsequent calls will need to write to a
+netinfo server. By default, the flag is off and the netinfo
+library will automatically switch to a server capable of
+writing whenever a write call occurs. However, since writes
+may take some time to reach the clone server, one could read
+stale information from a clone server and then attempt to
+write the master based upon the stale information. Setting
+.I needwrite
+will lock the handle onto the master netinfo server even for
+reads to prevent this from happening.
+.PP
+ni_status \fBni_open\fR(void *\fIrelativeto\fR, ni_name \fIdomain\fR, void **\fIresult\fR)
+.IP
+Opens a connection to the NetInfo domain
+.I domain.
+The returned handle is opened relative to the domain specified in the
+.I relativeto.
+This handle may be passed as NULL, indicating relative to the local
+NetInfo domain. The path may contain "/"s to indicate a multilevel
+search and may also be "." or ".." to indicate the current domain or
+parent domain, respectively.
+.PP
+ni_status \fBni_parent\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index *\fIparent_id\fR)
+.IP
+Returns the parent ID of the given directory.
+.PP
+ni_status \fBni_pathsearch\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_name \fIpath\fR)
+.IP
+Does a multilevel lookup on a directory, relative to the given directory
+ID. The path may contain "/"s to separative directory components. "="s
+are used to specify relations and both may be escaped using "\\"s. For
+example, to find the directory associated with the superuser, you may
+specify (relative to the root directory) "/name=users/uid=0". Note that
+the equal signs are not mandatory and will default to "name=" if none
+are specified. In the previous example, "/users/uid=0" would accomplish
+the same result.
+.PP
+ni_status \fBni_read\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_proplist *\fIprops\fR)
+.IP
+Reads all of the properties of the given directory.
+.PP
+ni_status \fBni_readname\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIprop_index\fR, ni_index \fIval_index\fR, ni_name *\fIvalue\fR)
+.IP
+Reads a value from a property in the given directory. The value is indexed
+by property index
+.I prop_index
+and value index
+.I val_index.
+.PP
+ni_status \fBni_readprop\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIprop_index\fr, ni_namelist *\fInl\fR)
+.IP
+Reads the value-list associated with the given property, indexed by
+.I prop_index.
+.PP
+ni_status \fBni_renameprop\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIprop_index\fR, ni_name \fInewname\fR)
+.IP
+Renames the property indexed by
+.I prop_index
+to the new name
+.I newname.
+.PP
+ni_status \fBni_resync\fR(void *\fIhandle\fR)
+.IP
+Attempts to resynchronize the clone servers with the master copy of
+the database.
+.PP
+ni_status \fBni_root\fR(void *\fIhandle\fR, ni_id *\fIdir\fR)
+.IP
+Returns the directory ID of the root of the directory tree.
+.PP
+ni_status \fBni_self\fR(void *\fIhandle\fR, ni_id *\fIdir\fR)
+.IP
+Returns the directory ID of the given directory. Simply refreshes the
+instance field to the latest value.
+.PP
+void \fBni_setabort\fR(void *\fIhandle\fR, int \fIshouldabort\fR)
+.IP
+By default, netinfo calls will try forever until an answer
+is returned from a server.
+.I ni_setabort
+ allows one to have
+netinfo return failure upon the first timeout or other failure.
+.PP
+ni_status \fBni_setpassword\fR(void *\fIhandle\fR, ni_name \fIpassword\fR)
+.IP
+Sets the password for the session to
+.I password.
+By default, no password is sent.
+.PP
+void \fBni_setreadtimeout\fR(void *\fIhandle\fR, int \fIseconds\fR)
+.IP
+Sets the timeout associated with reads on netinfo. The timeout
+is only a hint and the effective timeout may be longer. Note
+that calls will not abort even if a timeout is set unless the
+abort flag has been set (see
+.I ni_setabort()).
+.PP
+ni_status \fBni_setuser\fr(void *\fIhandle\fR, ni_name \fIusername\fR)
+.IP
+Changes the username associated with the session. By default, the username
+is the one associated with the user-ID that was used during the UNIX login
+process.
+.PP
+void \fBni_setwritetimeout\fR(void *\fIhandle\fR, int \fIseconds\fR)
+.IP
+Sets the timeout associated with writes on netinfo. The timeout
+is only a hint and the effective timeout may be a longer. Note
+that calls will not abort even if a timeout is set unless the
+abort flag has been set (see
+.I ni_setabort()).
+.PP
+ni_status \fBni_statistics\fR(void *\fIhandle\fR, ni_proplist *\fIstatistics\fR)
+.IP
+Returns various statistics from the server.
+.PP
+ni_status \fBni_write\fR(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_proplist \fIprops\fR)
+.IP
+Writes a new property list to the directory.
+.PP
+ni_status \fBni_writename\fr(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIprop_index\fr, ni_index \fIname_index\fR, ni_name \fIval\fR)
+.IP
+Writes a new property value to the property indexed by
+.I prop_index
+and value indexed by
+.I val_index.
+.PP
+ni_status \fBni_writeprop\fr(void *\fIhandle\fR, ni_id *\fIdir\fR, ni_index \fIprop_index\fR, ni_namelist \fIvalues\fR)
+.IP
+Writes a new value list to the property indexed by
+.I prop_index.
+It is allowable to have more than one property with the same name.
+.IP
--- /dev/null
+.TH NETINFO 5 "October 8, 1990" "Apple Computer, Inc."
+.SH NAME
+netinfo \- network administrative information
+.SH DESCRIPTION
+NetInfo stores its administration information in a hierarchical database.
+The hierarchy is composed of nodes called NetInfo
+.I directories.
+Each directory may have zero or more NetInfo
+.I properties
+associated with it.
+Each property has a
+.I name
+and zero or more
+.I values.
+.PP
+This man page describes those directories and properties which have
+meaning in the system distributed by Apple. Users and 3rd-parties may
+create other directories and properties, which of course cannot be
+described here.
+.PP
+.I Search Policy
+.PP
+Virtually everything that utilizes NetInfo for lookups adheres to the
+following convention. Search the local domain first. If found, return
+the answer. Otherwise, try the next level up and so on until the top
+of the domain hierarchy is reached. For compatibility with Yellow Pages
+and BIND, see
+.I lookupd(8).
+.PP
+.I Database Format
+.PP
+At the top level, the root directory contains a single property called
+.I master.
+This properties indicates who is the master of this database, i.e., which
+server contains the master copy of the database. The singular value of master
+contains two fields, a hostname and a domain tag separated by a '/' which
+uniquely identifies the machine and process serving as master of this data.
+For example, the entry
+.I clothier/network
+says that the
+.I netinfod(8)
+process serving domain tag
+.I network
+on the machine
+.I clothier
+controls the master copy of the database.
+.PP
+For added security, a second property can be installed in the root directory
+to limit who can connect to the domain. By default, anybody can connect to
+the domain, which would allow them to read anything that is there (writes are
+protected however). If this default is undesirable, a property called
+.I trusted_networks
+should be enabled in the root directory. Its values should be the network
+(or subnet) addresses which are assumed to contain trusted machines which
+are allowed to connect to the domain. Any other clients are assumed to be
+untrustworthy. A name may be used instead of an address. If a name is given,
+then that name should be listed as a subdirectory of "/networks" within the
+same domain and resolve to the appropriate network address.
+.PP
+At the second level, the following directories exist which have the
+following names (property named "name" has these values):
+.PP
+.RS
+.I aliases
+.LP
+.I groups
+.LP
+.I machines
+.LP
+.I mounts
+.LP
+.I networks
+.LP
+.I printers
+.LP
+.I protocols
+.LP
+.I rpcs
+.LP
+.I services
+.LP
+.I users
+.RE
+.PP
+These directories contain, for the most part, only the single property
+named "name". The exception is the "machines" directory which contains
+other properties having to do with automatic host installation. These
+properties are the following:
+.PP
+.RS
+"promiscuous" - if it exists, the bootpd(8) daemon is
+promiscuous. Has no value.
+.LP
+"assignable_ipaddr" - a range of IP addresses to automatically assigned,
+specified with two values as endpoints.
+.LP
+"configuration_ipaddr" - the temporary IP address given to unknown machines in the process of booting.
+.LP
+"default_bootfile" - the default bootfile to assign to a new machine.
+.LP
+"net_passwd" - optional property. If it exists, it's the encrypted password
+for protecting automatic host installations.
+.RE
+.PP
+The directory "/aliases" contains directories which refer to individual
+mailing aliases. The relevant properties are:
+.PP
+.RS
+"name" - the name of the alias
+.LP
+"members" - a list of values, each of which is a member of this alias.
+.RE
+.PP
+The directory "/groups" contains directories which refer to individual
+system groups. The relevant properties are:
+.PP
+.RS
+"name" - the name of the system group
+.LP
+"passwd" - the associated password
+.LP
+"gid" - the associated group id
+.LP
+"users" - a list of values, each of which is a user who is a member
+of this system group.
+.RE
+.PP
+The directory "/machines" contains directories which refer to individual
+machines. The relevant properties are:
+.PP
+.RS
+"name" - the name of this machine. This property can have multiple values
+if the machine name has aliases.
+.LP
+"ip_address" - the Internet Protocol address of the machine. This property
+can have multiple values if the machine has multiple IP addresses. Note
+that the address MUST be stored in decimal-dot notation with no leading
+zeroes.
+.LP
+"en_address" - the Ethernet address of the machine. Note that the address
+MUST be stored in standard 6 field hex Ethernet notation, with no leading
+zeros. For example, "0:0:f:0:7:5a" is a valid Ethernet address,
+"00:00:0f:00:07:5a" is not.
+.LP
+"serves" - a list of values, each of which is information about which
+NetInfo domains this machine serves. Each value has the format
+.I domain-name/domain-tag.
+The domain name is the external name of the domain served by this machine as
+seen from this level of hierarchy. The domain tag is the internal
+name associated with the actual process on the machine that serves this
+information.
+.LP
+"bootfile" - the name of the kernel that this machine will use by
+default when NetBooting.
+.LP
+"bootparams" - a list of values, each of which is a Bootparams protocol
+key-value pair. For example, "root=parrish:/" has the Bootparams key
+"root" and Bootparams value "parrish:/".
+.LP
+"netgroups" - a list of values, each of which is the name of a netgroup
+of which this machine is a member.
+.RE
+.PP
+The directory "/mounts" contains directories which refer to filesystems.
+The relevant properties are:
+.PP
+.RS
+"name" - the name of the filesytem. For example, "/dev/od0a" or
+"papazian:/".
+.LP
+"dir" - the directory upon which this filesystem is mounted.
+.LP
+"type" - the filesystem type of the mount
+.LP
+"opts" - a list of values, each of which is a
+.I mount(8)
+option associated with the mounting of this filesystem.
+.LP
+"passno" - pass number on parallel
+.I fsck(8)
+.LP
+"freq" - dump frequency, in days.
+.RE
+.PP
+The directory "/networks" contains directories which refer to Internet
+networks. The relevant properties are:
+.PP
+.RS
+"name" - the name of the network. If the network has aliases, there
+may be more than one value for this property.
+.LP
+"address" - the network number of this network. The value MUST be
+in decimal-dot notation with no leading zeroes.
+.RE
+.PP
+The directory "/printers" contains directories which refer to
+printer entries. The relevant properties are:
+.PP
+.RS
+"name" - the name of the printer. If the printer has alias, this
+property will have multiple values.
+.LP
+"lp", "sd", etc. - the names of
+.I printcap(5)
+properties associated with this printer. If the value associated with
+the property name is numeric, the number has a leading "#" prepended
+to it.
+.RE
+.PP
+The directory "/protocols" contains directories which refer to
+transport protocols. The relevant properties are:
+.PP
+.RS
+"name" - the name of the protocol. If the protocol has aliases, the
+property will have multiple values.
+.LP
+"number" - the associated protocol number.
+.RE
+.PP
+The directory "/services" contains directories which refer to
+ARPA services. The relevant properties are:
+.PP
+.RS
+"name" - the name of the service. If the service has aliases, the
+property will have multiple values.
+.LP
+"protocol" - the name of the protocol upon which the service runs.
+If the service runs on multiple protocols, this property will have
+multiple values.
+.LP
+"port" - the associated port number of the service.
+.RE
+.PP
+The directory "/users" contains information which refer to users.
+The relevant properties are:
+.PP
+.RS
+"name" - the login name of the user.
+.LP
+"passwd" - the encrypted password of the user.
+.LP
+"uid" - the user id of the user.
+.LP
+"gid" - the default group id of the user.
+.LP
+"realname" - the real name of the user.
+.LP
+"home" - the home directory of the user.
+.LP
+"shell" - the login shell of the user.
+.SH "SEE ALSO"
+.I aliases(5)
+.LP
+.I bootparams(5)
+.LP
+.I bootptab(5)
+.LP
+.I fstab(5)
+.LP
+.I group(5)
+.LP
+.I hosts(5)
+.LP
+.I lookupd(8)
+.LP
+.I netinfod(8)
+.LP
+.I netgroup(5)
+.LP
+.I networks(5)
+.LP
+.I passwd(5)
+.LP
+.I printcap(5)
+.LP
+.I protocols(5)
+.LP
+.I services(5)
* Copyright (C) 1989 by NeXT, Inc.
*/
#include <libc.h>
+#include <string.h>
#include <syslog.h>
#include <netinfo/ni.h>
#include <rpc/pmap_clnt.h>
static const ni_name NAME_USERS = "users";
static const ni_name NAME_UID = "uid";
+static const ni_name NAME_DOMAIN_SERVERS = "domain_servers";
+
typedef struct getreg_stuff {
nibind_getregister_res res;
ni_private *ni;
* Somebody closed our socket. Do not close it, it could
* be owned by somebody else now.
*/
- auth_destroy(ni->tc->cl_auth);
- clnt_destroy(ni->tc);
- ni->tc = NULL;
+ if (ni->tc != NULL)
+ {
+ if (ni->tc->cl_auth != NULL) auth_destroy(ni->tc->cl_auth);
+ clnt_destroy(ni->tc);
+ ni->tc = NULL;
+ }
}
if (!needwrite && !rebind(ni) && ni->abort) {
return (0);
}
return (resp);
}
- clnt_geterr(ni->tc, &err);
- if (err.re_status != RPC_CANTRECV) {
- break;
+ if (ni->tc != NULL)
+ {
+ clnt_geterr(ni->tc, &err);
+ if (err.re_status != RPC_CANTRECV) break;
}
if (i + 1 < NI_MAXCONNTRIES) {
/*
}
+static void
+add_addr_tag(ni_private *ni, ni_name addrtag)
+{
+ struct in_addr addr;
+ ni_name tag;
+ char *slash;
+
+ slash = strchr(addrtag, '/');
+ if (slash == NULL) return;
+
+ tag = slash + 1;
+ if (tag[0] == '\0') return;
+
+ *slash = '\0';
+
+ if (inet_aton(addrtag, &addr) == 0) return;
+
+ if (ni->naddrs == 0)
+ {
+ ni->addrs = (struct in_addr *)calloc(1, sizeof(struct in_addr));
+ if (ni->addrs == NULL) return;
+
+ ni->tags = (ni_name *)calloc(1, sizeof(ni_name));
+ if (ni->tags == NULL) return;
+ }
+ else
+ {
+ ni->addrs = (struct in_addr *)realloc(ni->addrs, ((ni->naddrs + 1) * sizeof(struct in_addr)));
+ if (ni->addrs == NULL) return;
+
+ ni->tags = (ni_name *)realloc(ni->tags, ((ni->naddrs + 1) * sizeof(ni_name)));
+ if (ni->tags == NULL) return;
+ }
+
+ ni->addrs[ni->naddrs] = addr;
+ ni->tags[ni->naddrs] = ni_name_dup(tag);
+ ni->naddrs++;
+}
+
static int
-addaddr(
- void *ni,
- ni_index ido,
- ni_name tag,
- ni_private *target_ni
- )
+addaddr(void *ni, ni_index ido, ni_name tag, ni_private *target_ni)
{
ni_id id;
ni_namelist nl;
id.nii_object = ido;
NI_INIT(&nl);
- if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) {
- return (0);
- }
- if (nl.ninl_len == 0) {
- return(0);
- }
+ if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) return 0;
- if (target_ni->naddrs == 0) {
- target_ni->addrs =
- (struct in_addr *)malloc(nl.ninl_len * sizeof(struct in_addr));
- target_ni->tags =
- (ni_name *)malloc(nl.ninl_len * sizeof(ni_name));
- } else {
- target_ni->addrs =
- (struct in_addr *)realloc(target_ni->addrs,
- ((target_ni->naddrs + nl.ninl_len) * sizeof(struct in_addr)));
- target_ni->tags =
- (ni_name *)realloc(target_ni->tags,
- ((target_ni->naddrs + nl.ninl_len) * sizeof(ni_name)));
+ if (nl.ni_namelist_len == 0) return 0;
+
+ if (target_ni->naddrs == 0)
+ {
+ target_ni->addrs = (struct in_addr *)malloc(nl.ni_namelist_len * sizeof(struct in_addr));
+ target_ni->tags = (ni_name *)malloc(nl.ni_namelist_len * sizeof(ni_name));
+ }
+ else
+ {
+ target_ni->addrs = (struct in_addr *)realloc(target_ni->addrs, ((target_ni->naddrs + nl.ni_namelist_len) * sizeof(struct in_addr)));
+ target_ni->tags = (ni_name *)realloc(target_ni->tags, ((target_ni->naddrs + nl.ni_namelist_len) * sizeof(ni_name)));
}
- for (i=0; i<nl.ninl_len; i++) {
- addr.s_addr = inet_addr(nl.ninl_val[i]);
+ for (i = 0; i < nl.ni_namelist_len; i++)
+ {
+ addr.s_addr = inet_addr(nl.ni_namelist_val[i]);
target_ni->addrs[target_ni->naddrs] = addr;
target_ni->tags[target_ni->naddrs] = ni_name_dup(tag);
target_ni->naddrs++;
}
ni_namelist_free(&nl);
- return (1);
+ return 1;
}
-
static int
-get_daddr(
- ni_private *ni,
- ni_name dom,
- ni_private *target_ni
- )
+get_daddr(ni_private *ni, ni_name dom, ni_private *target_ni)
{
- ni_id id;
+ ni_id nid;
ni_idlist ids;
- ni_namelist nl;
ni_entrylist entries;
+ ni_proplist pl;
ni_index i;
ni_index j;
ni_name tag;
- if (ni_root(ni, &id) != NI_OK) {
- return(0);
+ if (dom == NULL) return 0;
+
+ if (!strcmp(dom, "."))
+ {
+ /* check for server list */
+ NI_INIT(&pl);
+ if (ni_statistics(ni, &pl) == NI_OK)
+ {
+ i = ni_proplist_match(pl, NAME_DOMAIN_SERVERS, NULL);
+ if (i != NI_INDEX_NULL)
+ {
+ if (pl.ni_proplist_val[i].nip_val.ni_namelist_len > 0)
+ {
+ for (j = 0; j < pl.ni_proplist_val[i].nip_val.ni_namelist_len; j++)
+ {
+ add_addr_tag(target_ni, pl.ni_proplist_val[i].nip_val.ni_namelist_val[j]);
+ }
+ ni_proplist_free(&pl);
+ return 1;
+ }
+ }
+ ni_proplist_free(&pl);
+ }
}
+ if (ni_root(ni, &nid) != NI_OK) return 0;
NI_INIT(&ids);
- if (ni_lookup(ni, &id, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) {
- return (0);
- }
+ if (ni_lookup(ni, &nid, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) return 0;
- id.nii_object = ids.niil_val[0];
+ nid.nii_object = ids.niil_val[0];
ni_idlist_free(&ids);
NI_INIT(&entries);
- if (ni_list(ni, &id, NAME_SERVES, &entries) != NI_OK) {
- return (0);
- }
+ if (ni_list(ni, &nid, NAME_SERVES, &entries) != NI_OK) return 0;
- for (i = 0; i < entries.niel_len; i++) {
- if (entries.niel_val[i].names != NULL) {
- nl = *entries.niel_val[i].names;
- for (j = 0; j < nl.ninl_len; j++) {
- if (match(dom, nl.ninl_val[j], &tag)) {
- if (addaddr(ni,
- entries.niel_val[i].id,
- tag,
- target_ni)) {
- ni_name_free(&tag);
- break;
- }
- ni_name_free(&tag);
- }
+ for (i = 0; i < entries.niel_len; i++)
+ {
+ if (entries.niel_val[i].names == NULL) continue;
+
+ for (j = 0; j < entries.niel_val[i].names->ni_namelist_len; j++)
+ {
+ if (match(dom, entries.niel_val[i].names->ni_namelist_val[j], &tag))
+ {
+ addaddr(ni, entries.niel_val[i].id, tag, target_ni);
+ ni_name_free(&tag);
}
}
-
}
+
ni_entrylist_free(&entries);
return (target_ni->naddrs > 0);
}
-
-#ifdef notdef
-static int
-get_haddr(
- ni_private *ni,
- ni_name hname,
- ni_name tag,
- ni_private *target_ni
- )
-{
- ni_id id;
- ni_idlist ids;
-
- if (ni_root(ni, &id) != NI_OK) {
- return(0);
- }
- NI_INIT(&ids);
- if (ni_lookup(ni, &id, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) {
- return (0);
- }
- id.nii_object = ids.niil_val[0];
- ni_idlist_free(&ids);
-
- NI_INIT(&ids);
- if (ni_lookup(ni, &id, NAME_NAME, hname, &ids) != NI_OK) {
- return (0);
- }
- id.nii_object = ids.niil_val[0];
- ni_idlist_free(&ids);
- if (!addaddr(ni, id.nii_object, tag, target_ni)) {
- return (0);
- }
- return (1);
-}
-#endif
-
-
static ni_status
getparent(ni_private *oldni, ni_private **newni)
{
ni_rparent_res *resp;
- ni_private *ni;
+ ni_private *ni = NULL;
ni_private *dupni;
- int found;
+ int found = 0;
ni_index i;
struct in_addr raddr;
int printed = 0;
int inlist = 0;
- found = 0;
- while (!found) {
+ while (found == 0)
+ {
/*
* First, find our parent, any parent
*/
- for (;;) {
+ for (;;)
+ {
resp = RCALLIT(oldni, _ni_rparent_2, NULL);
- if (resp == NULL) {
- return (NI_FAILED);
- }
- if (resp->status != NI_NORESPONSE) {
- break;
- }
- if (!printed) {
+ if (resp == NULL) return NI_FAILED;
+ if (resp->status != NI_NORESPONSE) break;
+
+ if (!printed)
+ {
syslog(LOG_ERR, "NetInfo timeout finding server for parent of %s/%s, sleeping",
inet_ntoa(oldni->addrs[0]), oldni->tags[0]);
printed++;
}
+
sleep(NI_SLEEPTIME);
}
- if (printed) {
+
+ if (printed)
+ {
raddr.s_addr = htonl(resp->ni_rparent_res_u.binding.addr);
syslog(LOG_ERR, "NetInfo %s/%s found parent %s/%s",
inet_ntoa(oldni->addrs[0]), oldni->tags[0],
inet_ntoa(raddr), resp->ni_rparent_res_u.binding.tag);
}
- if (resp->status != NI_OK) {
- return (resp->status);
- }
+
+ if (resp->status != NI_OK) return (resp->status);
+
ni = ni_alloc();
*ni = *oldni;
ni_clear(ni);
ni = ni_alloc();
*ni = *dupni;
ni_clear(ni);
- if (get_daddr(dupni, ".", ni)) {
-
+ if (get_daddr(dupni, ".", ni) == 0)
+ {
+ if (oldni->abort == 1) break;
+ }
+ else
+ {
/*
- * Now make sure returned parent is head of
- * list
+ * Make sure returned parent is head of list
*/
- for (i = 0; i < ni->naddrs; i++) {
- if (ni->addrs[i].s_addr ==
- dupni->addrs[0].s_addr) {
+ for (i = 0; i < ni->naddrs; i++)
+ {
+ if (ni->addrs[i].s_addr == dupni->addrs[0].s_addr)
+ {
ni_switch(ni, i);
inlist++;
break;
dupni->tsock = -1;
dupni->tport = -1;
dupni->tc = NULL;
- found++;
+ found = 1;
/*
* If returned parent wasn't in list, it's a rogue.
* Log an error and drop the connection.
*/
- if (inlist == 0) {
+ if (inlist == 0)
+ {
syslog(LOG_ERR, "Rogue NetInfo server detected: %s/%s",
inet_ntoa(dupni->addrs[0]), dupni->tags[0]);
reinit(ni);
}
ni_free(dupni);
}
- if (found) {
+
+ if (found)
+ {
*newni = ni;
- return (NI_OK);
- } else {
- ni_free(ni);
- return (NI_FAILED);
+ return NI_OK;
}
+
+ if (ni != NULL) ni_free(ni);
+ return NI_FAILED;
}
void *d, *p;
ni_id n;
ni_status status;
+ struct sockaddr_in addr;
*dom = NULL;
nid->nii_object = NI_INDEX_NULL;
nid->nii_instance = NI_INDEX_NULL;
- status = ni_open(NULL, ".", &d);
- if (status != NI_OK) return status;
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- if (timeout > 0)
- {
- ni_setreadtimeout(d, timeout);
- ni_setabort(d, 1);
- }
+ d = ni_connect(&addr, "local");
+ if (d == NULL) return NI_FAILED;
while (d != NULL)
{
+ if (timeout > 0)
+ {
+ ni_setreadtimeout(d, timeout);
+ ni_setabort(d, 1);
+ }
+
status = ni_pathsearch(d, &n, dirname);
if (status == NI_OK)
{
ni_namelist *nl;
ni_status status;
- /* get subdirectory list */
- NI_INIT(&el);
- status = ni_list(handle, dir, name, &el);
- if (status != NI_OK) return status;
-
+ /* compile the regular expression */
cexp = (regex_t *)malloc(sizeof(regex_t));
memset(cexp, 0, sizeof(regex_t));
i = regcomp(cexp, expr, flags);
return NI_FAILED;
}
+ /* get subdirectory list */
+ NI_INIT(&el);
+ status = ni_list(handle, dir, name, &el);
+ if (status != NI_OK)
+ {
+ regfree(cexp);
+ free(cexp);
+ return status;
+ }
+
for (i = 0; i < el.ni_entrylist_len; i++)
{
if (el.ni_entrylist_val[i].names == NULL) continue;
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <ifaddrs.h>
#include "sys_interfaces.h"
__private_extern__ interface_list_t *
sys_interfaces(void)
{
- struct ifconf ifc;
- struct ifreq *ifr;
- char buf[1024]; /* XXX */
- int offset, addrlen, extra, delta;
- int sock;
+ interface_list_t *my_interfaces = NULL;
interface_t *iface;
- interface_list_t *my_interfaces;
+ struct ifaddrs *ifa, *p;
- sock = socket(AF_INET, SOCK_DGRAM, 0);
-
- if (sock < 0) return NULL;
-
- ifc.ifc_len = sizeof(buf);
- ifc.ifc_buf = buf;
-
- if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
- {
- close(sock);
- return NULL;
- }
+ if (getifaddrs(&ifa) < 0) return NULL;
my_interfaces = (interface_list_t *)malloc(sizeof(interface_list_t));
my_interfaces->count = 0;
my_interfaces->interface = NULL;
- delta = sizeof(struct ifreq);
- addrlen = delta - IFNAMSIZ;
- extra = 0;
-
- offset = 0;
-
- while (offset <= ifc.ifc_len)
+ for (p = ifa; p != NULL; p = p->ifa_next)
{
- ifr = (struct ifreq *)(ifc.ifc_buf + offset);
-
-#ifndef _NO_SOCKADDR_LENGTH_
- extra = ifr->ifr_addr.sa_len - addrlen;
- if (extra < 0) extra = 0;
-#endif
-
- offset = offset + delta + extra;
-
- if (ifr->ifr_addr.sa_family != AF_INET) continue;
- if (ioctl(sock, SIOCGIFFLAGS, (char *)ifr) < 0) continue;
+ if (p->ifa_addr == NULL) continue;
+ if ((p->ifa_flags & IFF_UP) == 0) continue;
+ if (p->ifa_addr->sa_family != AF_INET) continue;
my_interfaces->count++;
if (my_interfaces->count == 1)
iface = &(my_interfaces->interface[my_interfaces->count - 1]);
memset(iface, 0, sizeof(interface_t));
-
- memmove(iface->name, ifr->ifr_name, IFNAMSIZ);
- iface->flags = ifr->ifr_ifru.ifru_flags;
- iface->addr.s_addr = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
- ioctl(sock, SIOCGIFNETMASK, (char *)ifr);
- iface->mask.s_addr = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
+ iface->name = strdup(p->ifa_name);
+ iface->flags = p->ifa_flags;
+ iface->addr.s_addr = ((struct sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr;
+ iface->mask.s_addr = ((struct sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr;
iface->netaddr.s_addr = iface->addr.s_addr & iface->mask.s_addr;
iface->bcast.s_addr = iface->netaddr.s_addr | (~iface->mask.s_addr);
}
- close(sock);
+ freeifaddrs(ifa);
+
return my_interfaces;
}
__private_extern__ void
sys_interfaces_release(interface_list_t *l)
{
+ int i;
+
if (l == NULL) return;
- if (l->interface != NULL) free(l->interface);
+ for (i = 0; i < l->count; i++)
+ {
+ if (l->interface[i].name != NULL) free(l->interface[i].name);
+ }
+
+ free(l->interface);
free(l);
}
#define __SYS_INTERFACES__
#include <sys/types.h>
+#include <netinet/in.h>
#include <sys/socket.h>
-#include <sys/ioctl.h>
#include <net/if.h>
-#include <netinet/in.h>
typedef struct
{
- char name[IFNAMSIZ];
+ char *name;
short flags;
struct in_addr addr;
struct in_addr mask;
interface_t *interface;
} interface_list_t;
-interface_list_t * sys_interfaces(void);
+interface_list_t *sys_interfaces(void);
void sys_interfaces_release(interface_list_t *l);
int sys_is_my_address(interface_list_t *l, struct in_addr *a);
int sys_is_my_network(interface_list_t *l, struct in_addr *a);
yp_all.c yp_bind.c yp_first.c yp_get_default_domain.c\
yp_maplist.c yp_master.c yp_order.c
-OTHERSRCS = Makefile.preamble Makefile
+OTHERSRCS = Makefile.preamble Makefile yp_all.3 yp_bind.3 yp_first.3\
+ yp_get_default_domain.3 yp_master.3 yp_match.3 yp_next.3\
+ yp_order.3 yp_unbind.3 ypclnt.3 yperr_string.3 ypprot_err.3\
+ ypserv.acl.5
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+AFTER_POSTINSTALL += install-nis-man
PUBLIC_HEADER_DIR_SUFFIX = /rpcsvc
yp_master.c,
yp_order.c
);
- OTHER_SOURCES = (Makefile.preamble, Makefile);
+ OTHER_SOURCES = (
+ Makefile.preamble,
+ Makefile,
+ yp_all.3,
+ yp_bind.3,
+ yp_first.3,
+ yp_get_default_domain.3,
+ yp_master.3,
+ yp_match.3,
+ yp_next.3,
+ yp_order.3,
+ yp_unbind.3,
+ ypclnt.3,
+ yperr_string.3,
+ ypprot_err.3,
+ ypserv.acl.5
+ );
PUBLIC_HEADERS = (ypclnt.h, yp_prot.h);
};
LANGUAGE = English;
register char *name;
register char *domain;
{
- while (*key++ = *name++)
+ while ((*key++ = *name++))
;
*(key-1) = '.';
- while (*key++ = *domain++)
+ while ((*key++ = *domain++))
;
}
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.\" $OpenBSD: ypclnt.3,v 1.5 1996/12/28 09:06:29 downsj Exp $
+.\"
+.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd October 26, 1994
+.Dt YPCLNT 3
+.Os
+.Sh NAME
+.Nm yp_all ,
+.Nm yp_bind ,
+.Nm yp_first ,
+.Nm yp_get_default_domain ,
+.Nm yp_master ,
+.Nm yp_match ,
+.Nm yp_next ,
+.Nm yp_order ,
+.Nm yp_unbind ,
+.Nm yperr_string ,
+.Nm ypprot_err
+.Nd Interface to the YP subsystem
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <rpcsvc/ypclnt.h>
+.Fd #include <rpcsvc/yp_prot.h>
+.Ft int
+.Fn yp_all "char *indomain" "char *inmap" "struct ypall_callback *incallback"
+.Ft int
+.Fn yp_bind "char *dom"
+.Ft int
+.Fn yp_first "char *indomain" "char *inmap" "char **outkey" "int *outkeylen" "char **outval" "int *outvallen"
+.Ft int
+.Fn yp_get_default_domain "char **domp"
+.Ft int
+.Fn yp_master "char *indomain" "char *inmap" "char **outname"
+.Ft int
+.Fn yp_match "char *indomain" "char *inmap" "const char *inkey" "int inkeylen" "char **outval" "int *outvallen"
+.Ft int
+.Fn yp_next "char *indomain" "char *inmap" "char *inkey" "int inkeylen" "char **outkey" "int *outkeylen" "char **outval" "int *outvallen"
+.Ft int
+.Fn yp_order "char *indomain" "char *inmap" "char *outorder"
+.Ft void
+.Fn yp_unbind "char *dom"
+.Ft char *
+.Fn yperr_string "int incode"
+.Ft int
+.Fn ypprot_err "unsigned int incode"
+.Sh DESCRIPTION
+The
+.Nm ypclnt
+suite provides an interface to the YP subsystem. For a general description
+of the YP subsystem, see
+.Xr yp 8 .
+.Pp
+For all functions, input values begin with
+.Pa in
+and output values begin with
+.Pa out .
+Any output values of type
+.Em char **
+should be the addresses of uninitialized character pointers. Memory will be
+allocated by the YP client routines using
+.Fn malloc .
+This memory can later be freed by the user if there is no additional need for
+the data stored there. For
+.Pa outkey
+and
+.Pa outval ,
+two extra bytes of memory are allocated for a
+.Ql \en
+and
+.Ql \e0 ,
+which are not
+reflected in the values of
+.Pa outkeylen
+or
+.Pa outvallen .
+All occurrences of
+.Pa indomain
+and
+.Pa inmap
+must be non-null, null-terminated strings. All input strings which also have
+a corresponding length parameter cannot be null unless the corresponding
+length value is zero. Such strings need not be null-terminated.
+.Pp
+All YP lookup calls (the functions
+.Fn yp_all ,
+.Fn yp_first ,
+.Fn yp_master ,
+.Fn yp_match ,
+.Fn yp_next ,
+.Fn yp_order )
+require a YP domain name and a YP map name. The default domain name may be
+obtained by calling
+.Fn yp_get_default_domain ,
+and should thus be used before all other YP calls in a client program.
+The value it places
+.Pa outdomain
+is suitable for use as the
+.Pa indomain
+parameter to all subsequent YP calls.
+.Pp
+In order for YP lookup calls to succeed, the client process must be bound
+to a YP server process. The client process need not explicitly bind to
+the server, as it happens automatically whenever a lookup occurs.
+The function
+.Fn yp_bind
+is provided for a backup strategy, e.g. a local file, when a YP server process
+is not available. Each binding uses one socket descriptor on the client
+process, which may be explicitly freed using
+.Fn yp_unbind ,
+which frees all per-process and per-node resources to bind the domain and
+marks the domain unbound.
+.Pp
+If, during a YP lookup, an RPC failure occurs, the domain used in the lookup
+is automatically marked unbound and the
+.Nm ypclnt
+layer retries the lookup as long as
+.Xr ypbind 8
+is running and either the client process cannot bind to a server for the domain
+specified in the lookup, or RPC requests to the YP server process fail.
+If an error is not RPC-related, one of the YP error codes described below
+is returned and control given back to the user code.
+.Pp
+The
+.Nm ypclnt
+suite provides the following functionality:
+.Bl -tag -width Fn yp_match
+.It Fn yp_match
+Provides the value associated with the given key.
+.It Fn yp_first
+Provides the first key-value pair from the given map in the named domain.
+.It Fn yp_next
+Provides the next key-value pair in the given map. To obtain the second pair,
+the
+.Pa inkey
+value should be the
+.Pa outkey
+value provided by the initial call to
+.Fn yp_first .
+In the general case, the next key-value pair may be obtained by using the
+.Pa outkey
+value from the previous call to
+.Fn yp_next
+as the value for
+.Pa inkey .
+.Pp
+Of course, the notions of ``first'' and ``next'' are particular to the
+type of YP map being accessed, and thus there is no guarantee of lexical
+order. The only guarantees provided with
+.Fn yp_first
+and
+.Fn yp_next ,
+providing that the same map on the same server is polled repeatedly
+until
+.Fn yp_next
+returns YPERR_NOMORE, are that all key-value pairs in that map will be accessed
+exactly once, and if the entire procedure is repeated, the order will be
+the same.
+.Pp
+If the server is heaviliy loaded or the server fails for some reason, the
+domain being used may become unbound. If this happens, and the client process
+re-binds, the retrieval rules will break: some entries may be seen twice, and
+others not at all. For this reason, the function
+.Fn yp_all
+provides a better solution for reading all of the entries in a particular
+map.
+.It Fn yp_all
+This function provides a way to transfer an entire map from
+the server to the client process with a single request. This transfer
+uses TCP, unlike all other functions in the
+.Nm ypclnt
+suite, which use UDP. The entire transaction occurs in a single RPC
+request-response. The third argument to this function provides a way
+to supply the name of a function to process each key-value pair in the
+map.
+.Fn Yp_all
+returns after the entire transaction is complete, or the
+.Pa foreach
+function decides that it does not want any more key-value pairs. The third
+argument to
+.Fn yp_all
+is:
+.Bd -literal -offset indent
+struct ypall_callback *incallback {
+ int (*foreach)();
+ char *data;
+};
+.Ed
+.Pp
+The
+.Em char *data
+argument is an opaque pointer for use by the callback function. The
+.Pa foreach
+function should return non-zero when it no longer wishes to process
+key-value pairs, at which time
+.Fn yp_all
+returns a value of 0, and is called with the following arguments:
+.Pp
+.Bd -literal -offset indent
+int foreach (
+ int instatus,
+ char *inkey,
+ int inkeylen,
+ char *inval,
+ int invallen,
+ char *indata
+);
+.Ed
+.Pp
+Where:
+.Bl -tag -width "inkey, inval"
+.It Fa instatus
+Holds one of the return status values described in
+.Nm <rpcsvc/yp_prot.h> :
+see
+.Fn ypprot_err
+below for a function that will translate YP protocol errors into a
+.Nm ypclnt
+layer error code as described in
+.Nm <rpcsvc/ypclnt.h> .
+.It Fa inkey, inval
+The key and value arguments are somewhat different here than described
+above. In this case, the memory pointed to by
+.Fa inkey
+and
+.Fa inval
+is private to
+.Fn yp_all ,
+and is overwritten with each subsequent key-value pair, thus the
+.Pa foreach
+function should do something useful with the contents of that memory during
+each iteration. If the key-value pairs are not terminated with either
+.Ql \en
+or
+.Ql \e0
+in the map, then they will not be terminated as such when given to the
+.Pa foreach
+function, either.
+.It Fa indata
+This is the contents of the
+.Pa incallback->data
+element of the callback structure. It is provided as a means to share
+state between the
+.Pa foreach
+function and the user code. Its use is completely optional: cast it to
+something useful or simply ignore it.
+.El
+.It Fn yp_order
+Returns the order number for a map.
+.It Fn yp_master
+Returns the hostname for the machine on which the master YP server process for
+a map is running.
+.It Fn yperr_string
+Returns a pointer to a null-terminated error string that does not contain a
+.Ql \&.
+or
+.Ql \en .
+.It Fn ypprot_err
+Converts a YP protocol error code to a
+.Nm ypclnt
+error code suitable for
+.Fn yperr_string .
+.El
+.Sh RETURN VALUES
+All functions in the
+.Nm ypclnt
+suite which are of type
+.Em int
+return 0 upon success or one of the following error codes upon failure:
+.Bl -tag -width "YPERR_BADARGS "
+.It Bq Er YPERR_BADARGS
+The passed arguments to the function are invalid
+.It Bq Er YPERR_BADDB
+The YP map that was polled is defective.
+.It Bq Er YPERR_DOMAIN
+Client process cannot bind to server on this YP domain.
+.It Bq Er YPERR_KEY
+The key passed does not exist.
+.It Bq Er YPERR_MAP
+There is no such map in the server's domain.
+.It Bq Er YPERR_DOM
+The local YP domain is not set.
+.It Bq Er YPERR_NOMORE
+There are no more records in the queried map.
+.It Bq Er YPERR_PMAP
+Cannot communicate with portmap.
+.It Bq Er YPERR_RESRC
+A resource allocation failure occurred.
+.It Bq Er YPERR_RPC
+An RPC failure has occurred. The domain has been marked unbound.
+.It Bq Er YPERR_VERS
+Client/server version mismatch. If the server is running version 1
+of the YP protocol,
+.Fn yp_all
+functionality does not exist.
+.It Bq Er YPERR_BIND
+Cannot communicate with
+.Xr ypbind 8 .
+.It Bq Er YPERR_YPERR
+An internal server or client error has occurred.
+.It Bq Er YPERR_YPSERV
+The client cannot communicate with the YP server process.
+.El
+.Sh SEE ALSO
+.Xr malloc 3 ,
+.Xr yp 8 ,
+.Xr ypbind 8 ,
+.Xr ypserv 8
+.Sh AUTHOR
+Theo De Raadt
--- /dev/null
+.so man3/ypclnt.3
* SUCH DAMAGE.
*/
-#ifndef LINT
+#if defined(LIBC_SCCS) && !defined(lint)
static char rcsid[] = "$OpenBSD: yppasswdd_xdr.c,v 1.4 1997/08/19 07:00:52 niklas Exp $";
#endif
--- /dev/null
+.so man3/ypclnt.3
--- /dev/null
+.\" $OpenBSD: ypserv.acl.5,v 1.5 1996/07/04 21:17:15 deraadt Exp $
+.\" Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Mats O Jansson
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd July 2, 1994
+.Dt YPSERV.ACL 5
+.Os
+.Sh NAME
+.Nm ypserv.acl
+.Nd
+.Xr ypserv 8
+configuration file
+.Sh DESCRIPTION
+The
+.Nm ypserv.acl
+file controls which hosts can connect to the
+.Nm YP
+server.
+.Pp
+The format is more complex than the format for
+.Xr securenet 5 .
+The first two verbs on each line controls if the line will
+.Nm allow
+or
+.Nm deny
+access for a
+.Nm host ,
+network
+.Nm (net)
+or
+.Nm all
+hosts.
+.Pp
+The
+.Nm YP
+server reads the configuration file and build a list in memory. This list
+is processed from the beginning for every incomming request. As soon a
+match is found in the list the search terminates and it returns success
+or failure depending on
+.Nm allow
+or
+.Nm deny .
+If no match was found in the list success is returned.
+.Pp
+If access is denied every call will cause a
+.Nm no such domain
+error for the caller.
+.Pp
+There is no default name for this file. Start
+.Nm ypserv
+with a
+.Ar -a filename
+to read a file with this format.
+.Pp
+The following different syntax can be used:
+.Pp
+<
+.Nm allow|deny
+>
+.Nm host
+<
+.Nm hostname|ip-address
+>
+.Pp
+If
+.Nm hostname
+has more than one ip address then all will be added to the list.
+.Pp
+<
+.Nm allow|deny
+>
+.Nm net
+<
+.Nm netname|netnumber
+>
+.Op Nm netmask <netname|netnumber>
+.Pp
+If
+.Nm netmask
+part of the command isn't given then the netmask will be assumed to be a
+class A, B or C net depending on the net number.
+.Pp
+<
+.Nm allow|deny
+>
+.Nm all
+.Pp
+A line containing one of these commands will always match any host.
+.Sh EXAMPLES
+.Pp
+A configuration file might appear as follows:
+.Bd -literal
+# This is an example of an access control file to be used by ypserv.
+#
+# This file is parsed line by line. First match will terminate the check
+# of the caller.
+#
+
+###########################################################################
+# This is the commands that will match a single host
+#
+# allow host <hostname|ip-address>
+# deny host <hostname|ip-address>
+#
+# To process hostname gethostbyname is called. If the hostname has
+# multiple ip-addresses all will be added (I hope). ip-address
+# processed by inet_aton.
+deny host jodie
+
+###########################################################################
+# This is the commands that will match a network
+#
+# allow net <netname|netnumber> [netmask <netname|netnumber>]
+# deny net <netname|netnumber> [netmask <netname|netnumber>]
+#
+# To process netname getnetbyname is called, and inet_aton is used for
+# netnumber. inet_aton both access numbers as 255.255.255.0 and 0xffffff00.
+#
+# If netmask isn't given the parser will assume netmask from the first bits
+# of the network number. So if the network is subneted the you have to add
+# the netmask. In my case I've got the network 139.58.253.0 at home so too
+# allow any of my computers to talk with the server I need the following
+# line
+#
+allow net mojathome netmask 255.255.255.0
+
+###########################################################################
+# At last we have a command that will match any caller:
+#
+# allow all
+# deny all
+#
+
+# reject all connections
+deny all
+
+.Ed
+.Sh FILES
+.Bl -tag -width /var/yp/ypserv.acl -compact
+.It Pa /var/yp/ypserv.acl
+A
+.Xr ypserv 8
+configuration file.
+.El
+.Sh SEE ALSO
+.Xr yp 8 ,
+.Xr ypserv 8 ,
+.Xr securenet 5
+.Sh AUTHOR
+Mats O Jansson <moj@stacken.kth.se>
+
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: auth_none.c,v 1.2 1999/10/14 21:56:52 wsanchez Exp $";
+static char *rcsid = "$Id: auth_none.c,v 1.3 2002/02/19 20:36:22 epeyton Exp $";
#endif
/*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#define MAX_MARSHEL_SIZE 20
+extern bool_t xdr_opaque_auth();
+
/*
* Authenticator operations routines
*/
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: auth_unix.c,v 1.3 2001/01/17 19:05:42 majka Exp $";
+static char *rcsid = "$Id: auth_unix.c,v 1.4 2002/02/19 20:36:22 epeyton Exp $";
#endif
/*
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/auth_unix.h>
+extern bool_t xdr_opaque_auth();
+
/*
* Unix authenticator operations vector
*/
};
#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
-static bool_t marshal_new_auth();
+static void marshal_new_auth();
/*
* the maximum size of the group list that will be sent.
*/
-static maxgrplist = NGROUPS;
+static int maxgrplist = NGROUPS;
+void
set_rpc_maxgrouplist(num)
int num;
{
* Marshals (pre-serializes) an auth struct.
* sets private data, au_marshed and au_mpos
*/
-static bool_t
+static void
marshal_new_auth(auth)
register AUTH *auth;
{
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: authunix_prot.c,v 1.3 2001/01/17 19:05:42 majka Exp $";
+static char *rcsid = "$Id: authunix_prot.c,v 1.4 2002/02/19 20:36:22 epeyton Exp $";
#endif
/*
*/
+#include <sys/types.h>
+#include <netinet/in.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)bindresvport.c 1.8 88/02/08 SMI";*/
/*static char *sccsid = "from: @(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: bindresvport.c,v 1.2 1999/10/14 21:56:52 wsanchez Exp $";
+/*from: OpenBSD: bindresvport.c,v 1.7 1996/07/30 16:25:47 downsj Exp */
+static char *rcsid = "$FreeBSD: src/lib/libc/rpc/bindresvport.c,v 1.12 2000/01/26 09:02:42 shin Exp $";
#endif
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
+ *
+ * Portions Copyright(C) 1996, Jason Downs. All rights reserved.
*/
+#include <string.h>
+#include <unistd.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/socket.h>
/*
* Bind a socket to a privileged IP port
*/
+int
bindresvport(sd, sin)
int sd;
struct sockaddr_in *sin;
{
- int res;
- static short port;
- struct sockaddr_in myaddr;
- extern int errno;
- int i;
-
-#define STARTPORT 600
-#define ENDPORT (IPPORT_RESERVED - 1)
-#define NPORTS (ENDPORT - STARTPORT + 1)
-
- if (sin == (struct sockaddr_in *)0) {
- sin = &myaddr;
- bzero(sin, sizeof (*sin));
- sin->sin_family = AF_INET;
- } else if (sin->sin_family != AF_INET) {
+ return bindresvport_sa(sd, (struct sockaddr *)sin);
+}
+
+/*
+ * Bind a socket to a privileged port for whatever protocol.
+ */
+int
+bindresvport_sa(sd, sa)
+ int sd;
+ struct sockaddr *sa;
+{
+ int old, error, af;
+ struct sockaddr_storage myaddr;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int proto, portrange, portlow;
+ u_int16_t port;
+ int salen;
+
+ if (sa == NULL) {
+ salen = sizeof(myaddr);
+ sa = (struct sockaddr *)&myaddr;
+
+ if (getsockname(sd, sa, &salen) == -1)
+ return -1; /* errno is correctly set */
+
+ af = sa->sa_family;
+ memset(&myaddr, 0, salen);
+ } else
+ af = sa->sa_family;
+
+ if (af == AF_INET) {
+ proto = IPPROTO_IP;
+ portrange = IP_PORTRANGE;
+ portlow = IP_PORTRANGE_LOW;
+ sin = (struct sockaddr_in *)sa;
+ salen = sizeof(struct sockaddr_in);
+ port = sin->sin_port;
+ } else if (af == AF_INET6) {
+ proto = IPPROTO_IPV6;
+ portrange = IPV6_PORTRANGE;
+ portlow = IPV6_PORTRANGE_LOW;
+ sin6 = (struct sockaddr_in6 *)sa;
+ salen = sizeof(struct sockaddr_in6);
+ port = sin6->sin6_port;
+ } else {
errno = EPFNOSUPPORT;
return (-1);
}
+ sa->sa_family = af;
+ sa->sa_len = salen;
+
if (port == 0) {
- port = (getpid() % NPORTS) + STARTPORT;
+ int oldlen = sizeof(old);
+
+ error = getsockopt(sd, proto, portrange, &old, &oldlen);
+ if (error < 0)
+ return (error);
+
+ error = setsockopt(sd, proto, portrange, &portlow,
+ sizeof(portlow));
+ if (error < 0)
+ return (error);
}
- res = -1;
- errno = EADDRINUSE;
- for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) {
- sin->sin_port = htons(port++);
- if (port > ENDPORT) {
- port = STARTPORT;
+
+ error = bind(sd, sa, salen);
+
+ if (port == 0) {
+ int saved_errno = errno;
+
+ if (error) {
+ if (setsockopt(sd, proto, portrange, &old,
+ sizeof(old)) < 0)
+ errno = saved_errno;
+ return (error);
+ }
+
+ if (sa != (struct sockaddr *)&myaddr) {
+ /* Hmm, what did the kernel assign... */
+ if (getsockname(sd, sa, &salen) < 0)
+ errno = saved_errno;
+ return (error);
}
- res = bind(sd,
- (struct sockaddr *)sin, sizeof(struct sockaddr_in));
}
- return (res);
+ return (error);
}
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";*/
/*static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: clnt_generic.c,v 1.2 1999/10/14 21:56:52 wsanchez Exp $";
+static char *rcsid = "$Id: clnt_generic.c,v 1.3 2002/02/19 20:36:22 epeyton Exp $";
#endif
/*
* Copyright (C) 1987, Sun Microsystems, Inc.
*/
+#include <string.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
#include <sys/errno.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: clnt_perror.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: clnt_perror.c,v 1.3 2002/02/19 20:36:22 epeyton Exp $";
#endif
/*
*
*/
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <rpc/rpc.h>
#include <rpc/types.h>
clnt_spcreateerror(s)
char *s;
{
- extern int sys_nerr;
char *str = _buf();
if (str == 0)
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: clnt_raw.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: clnt_raw.c,v 1.3 2002/02/19 20:36:22 epeyton Exp $";
#endif
/*
* any interference from the kernal.
*/
+#include <stdio.h>
+#include <stdlib.h>
#include <rpc/rpc.h>
+extern bool_t xdr_opaque_auth();
+
#define MCALL_MSG_SIZE 24
/*
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)clnt_simple.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: clnt_simple.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: clnt_simple.c,v 1.3 2002/02/19 20:36:23 epeyton Exp $";
#endif
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
#include <netdb.h>
char *oldhost;
} *callrpc_private;
+int
callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
char *host;
xdrproc_t inproc, outproc;
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: clnt_tcp.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: clnt_tcp.c,v 1.4 2002/03/15 22:07:48 majka Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
+#include <sys/fcntl.h>
#include <netdb.h>
#include <errno.h>
#include <rpc/pmap_clnt.h>
extern int errno;
+extern int bindresvport();
+extern bool_t xdr_opaque_auth();
+
static int readtcp();
static int writetcp();
u_int recvsz;
{
CLIENT *h;
- register struct ct_data *ct;
+ register struct ct_data *ct = NULL;
struct timeval now;
struct rpc_msg call_msg;
+ int rfd;
h = (CLIENT *)mem_alloc(sizeof(*h));
if (h == NULL) {
/*
* Initialize call message
*/
- (void)gettimeofday(&now, (struct timezone *)0);
- call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+ rfd = open("/dev/random", O_RDONLY, 0);
+ if ((rfd < 0) || (read(rfd, &call_msg.rm_xid, sizeof(call_msg.rm_xid)) != sizeof(call_msg.rm_xid)))
+ {
+ gettimeofday(&now, (struct timezone *)0);
+ call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+ }
+ if (rfd > 0) close(rfd);
+
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
call_msg.rm_call.cb_prog = prog;
FD_SET(ct->ct_sock, &mask);
while (TRUE) {
readfds = mask;
- switch (select(ct->ct_sock+1, &readfds, (int*)NULL, (int*)NULL,
+ switch (select(ct->ct_sock+1, &readfds, NULL, NULL,
&(ct->ct_wait))) {
case 0:
ct->ct_error.re_status = RPC_TIMEDOUT;
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: clnt_udp.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: clnt_udp.c,v 1.4 2002/03/15 22:07:49 majka Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
+#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <errno.h>
#include <rpc/pmap_clnt.h>
+extern int bindresvport();
+extern bool_t xdr_opaque_auth();
+
extern int errno;
/*
u_int recvsz;
{
CLIENT *cl;
- register struct cu_data *cu;
+ register struct cu_data *cu = NULL;
struct timeval now;
struct rpc_msg call_msg;
+ int rfd;
cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
if (cl == NULL) {
}
cu->cu_outbuf = &cu->cu_inbuf[recvsz];
- (void)gettimeofday(&now, (struct timezone *)0);
if (raddr->sin_port == 0) {
u_short port;
if ((port =
cu->cu_total.tv_usec = -1;
cu->cu_sendsz = sendsz;
cu->cu_recvsz = recvsz;
- call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+
+ rfd = open("/dev/random", O_RDONLY, 0);
+ if ((rfd < 0) || (read(rfd, &call_msg.rm_xid, sizeof(call_msg.rm_xid)) != sizeof(call_msg.rm_xid)))
+ {
+ gettimeofday(&now, (struct timezone *)0);
+ call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+ }
+ if (rfd > 0) close(rfd);
+
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
call_msg.rm_call.cb_prog = program;
FD_SET(cu->cu_sock, &mask);
for (;;) {
readfds = mask;
- switch (select(cu->cu_sock+1, &readfds, (int *)NULL,
- (int *)NULL, &(cu->cu_wait))) {
+ switch (select(cu->cu_sock+1, &readfds, NULL,
+ NULL, &(cu->cu_wait))) {
case 0:
time_waited.tv_sec += cu->cu_wait.tv_sec;
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: get_myaddress.c,v 1.3 2000/08/03 20:25:14 ajn Exp $";
+static char *rcsid = "$Id: get_myaddress.c,v 1.4 2002/02/19 20:36:23 epeyton Exp $";
#endif
/*
#include <rpc/pmap_prot.h>
#include <sys/socket.h>
#include <stdio.h>
+#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";*/
-static char *rcsid = "$Id: getrpcent.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: getrpcent.c,v 1.3 2002/02/19 20:36:23 epeyton Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <rpc/rpc.h>
if (d == 0)
return (0);
setrpcent(0);
- while (p = getrpcent()) {
+ while ((p = getrpcent())) {
if (p->r_number == number)
break;
}
char **rp;
setrpcent(0);
- while (rpc = getrpcent()) {
+ while ((rpc = getrpcent())) {
if (strcmp(rpc->r_name, name) == 0)
return (rpc);
for (rp = rpc->r_aliases; *rp != NULL; rp++) {
struct rpcent *
getrpcent()
{
- struct rpcent *hp;
- int reason;
register struct rpcdata *d = _rpcdata();
if (d == 0)
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)getrpcport.c 1.3 87/08/11 SMI";*/
/*static char *sccsid = "from: @(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: getrpcport.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: getrpcport.c,v 1.3 2002/02/19 20:36:23 epeyton Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <string.h>
#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
#include <netdb.h>
#include <sys/socket.h>
+int
getrpcport(host, prognum, versnum, proto)
char *host;
{
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)pmap_clnt.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: pmap_clnt.c,v 1.3 2000/08/03 20:25:14 ajn Exp $";
+static char *rcsid = "$Id: pmap_clnt.c,v 1.4 2002/02/19 20:36:23 epeyton Exp $";
#endif
/*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
+#include <string.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: pmap_getmaps.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: pmap_getmaps.c,v 1.3 2002/02/19 20:36:24 epeyton Exp $";
#endif
/*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
+#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: pmap_getport.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: pmap_getport.c,v 1.3 2002/02/19 20:36:24 epeyton Exp $";
#endif
/*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
+#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: pmap_prot2.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: pmap_prot2.c,v 1.3 2002/02/19 20:36:24 epeyton Exp $";
#endif
/*
*/
bool_t more_elements;
register int freeing = (xdrs->x_op == XDR_FREE);
- register struct pmaplist **next;
+ register struct pmaplist **next = NULL;
while (TRUE) {
more_elements = (bool_t)(*rp != NULL);
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: pmap_rmt.c,v 1.2 1999/10/14 21:56:53 wsanchez Exp $";
+static char *rcsid = "$Id: pmap_rmt.c,v 1.4 2002/03/15 22:07:50 majka Exp $";
#endif
/*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
+#include <string.h>
+#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_rmt.h>
#include <sys/socket.h>
+#include <sys/fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <net/if.h>
struct ifreq ifreq, *ifr;
struct sockaddr_in *sin;
char *cp, *cplim;
- int n, i = 0;
+ int i = 0;
ifc.ifc_len = UDPMSGSIZE;
ifc.ifc_buf = buf;
struct rpc_msg msg;
struct timeval t;
char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
+ int rfd;
/*
* initialization: create a socket, a broadcast address, and
baddr.sin_port = htons(PMAPPORT);
baddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
- (void)gettimeofday(&t, (struct timezone *)0);
- msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
+
+ rfd = open("/dev/random", O_RDONLY, 0);
+ if ((rfd < 0) || (read(rfd, &msg.rm_xid, sizeof(msg.rm_xid)) != sizeof(msg.rm_xid)))
+ {
+ gettimeofday(&t, (struct timezone *)0);
+ msg.rm_xid = getpid() ^ t.tv_sec ^ t.tv_usec;
+ }
+ if (rfd > 0) close(rfd);
+
t.tv_usec = 0;
msg.rm_direction = CALL;
msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
msg.acpted_rply.ar_results.where = (caddr_t)&r;
msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
readfds = mask;
- switch (select(sock+1, &readfds, (int *)NULL,
- (int *)NULL, &t)) {
+ switch (select(sock+1, &readfds, NULL, NULL, &t)) {
case 0: /* timed out */
stat = RPC_TIMEDOUT;
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: rpc_callmsg.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: rpc_callmsg.c,v 1.3 2002/02/19 20:36:24 epeyton Exp $";
#endif
/*
*
*/
+#include <stdlib.h>
+#include <string.h>
#include <sys/param.h>
#include <rpc/rpc.h>
+extern bool_t xdr_opaque_auth();
+
/*
* XDR a call message
*/
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: rpc_commondata.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: rpc_commondata.c,v 1.3 2002/02/19 20:36:24 epeyton Exp $";
#endif
#include <rpc/rpc.h>
*/
#if defined(__APPLE__)
struct opaque_auth _null_auth = {0};
-fd_set svc_fdset = {0};
+fd_set svc_fdset = {{0}};
int svc_maxfd = -1;
struct rpc_createerr rpc_createerr = {0};
#else
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro";*/
/*static char *sccsid = "from: @(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: rpc_dtablesize.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: rpc_dtablesize.c,v 1.3 2002/02/19 20:36:24 epeyton Exp $";
#endif
+#include <unistd.h>
#include <sys/types.h>
/*
* Cache the result of getdtablesize(), so we don't have to do an
* expensive system call every time.
*/
+int
_rpc_dtablesize()
{
static int size;
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc.c 2.4 88/08/11 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc.c,v 1.3 2001/08/23 01:25:01 ajn Exp $";
+static char *rcsid = "$Id: svc.c,v 1.4 2002/02/19 20:36:24 epeyton Exp $";
#endif
/*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
+#include <stdlib.h>
+#include <string.h>
#include <sys/errno.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
maskp = (u_long *)readfds->fds_bits;
for (sock = 0; sock <= svc_maxfd; sock += NFDBITS) {
- for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) {
+ for (mask = *maskp++; (bit = ffs(mask)); mask ^= (1 << (bit - 1))) {
if ((sock + bit) > (svc_maxfd + 1))
/* if we're past our sockets */
return;
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc_auth.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc_auth.c 2.1 88/08/07 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc_auth.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: svc_auth.c,v 1.3 2002/02/19 20:36:25 epeyton Exp $";
#endif
/*
static struct {
enum auth_stat (*authenticator)();
} svcauthsw[] = {
- _svcauth_null, /* AUTH_NULL */
- _svcauth_unix, /* AUTH_UNIX */
- _svcauth_short, /* AUTH_SHORT */
+ { _svcauth_null }, /* AUTH_NULL */
+ { _svcauth_unix }, /* AUTH_UNIX */
+ { _svcauth_short }, /* AUTH_SHORT */
};
#define AUTH_MAX 2 /* HIGHEST AUTH NUMBER */
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc_auth_unix.c,v 1.3 2001/01/17 19:05:42 majka Exp $";
+static char *rcsid = "$Id: svc_auth_unix.c,v 1.4 2002/02/19 20:36:25 epeyton Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <string.h>
#include <sys/param.h>
#include <rpc/rpc.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc_raw.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc_raw.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: svc_raw.c,v 1.3 2002/02/19 20:36:25 epeyton Exp $";
#endif
/*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
+#include <stdlib.h>
#include <rpc/rpc.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc_run.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: svc_run.c,v 1.3 2002/02/19 20:36:25 epeyton Exp $";
#endif
/*
* This is the rpc server side idle loop
* Wait for input, call server program.
*/
+#include <stdio.h>
+#include <unistd.h>
#include <rpc/rpc.h>
#include <sys/errno.h>
for (;;) {
readfds = svc_fdset;
- switch (select(svc_maxfd+1, &readfds, (int *)0, (int *)0,
+ switch (select(svc_maxfd+1, &readfds, NULL, NULL,
(struct timeval *)0)) {
case -1:
if (errno == EINTR) {
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc_simple.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc_simple.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: svc_simple.c,v 1.3 2002/02/19 20:36:25 epeyton Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
#include <sys/socket.h>
#include <netdb.h>
static SVCXPRT *transp;
struct proglst *pl;
+int
registerrpc(prognum, versnum, procnum, progname, inproc, outproc)
char *(*progname)();
xdrproc_t inproc, outproc;
if (procnum == NULLPROC) {
(void) fprintf(stderr,
- "can't reassign procedure number %d\n", NULLPROC);
+ "can't reassign procedure number %ld\n", NULLPROC);
return (-1);
}
if (transp == 0) {
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc_tcp.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: svc_tcp.c,v 1.3 2002/02/19 20:36:25 epeyton Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
#include <errno.h>
-extern bool_t abort();
-extern errno;
+
+extern int bindresvport();
/*
* Ops vector for TCP/IP based rpc service handle
/*
* Ops vector for TCP/IP rendezvous handler
*/
+static bool_t rendezvous_abort();
static bool_t rendezvous_request();
static enum xprt_stat rendezvous_stat();
static struct xp_ops svctcp_rendezvous_op = {
rendezvous_request,
rendezvous_stat,
- abort,
- abort,
- abort,
+ rendezvous_abort,
+ rendezvous_abort,
+ rendezvous_abort,
svctcp_destroy
};
return (xprt);
}
+static bool_t
+rendezvous_abort()
+{
+ abort();
+ return (FALSE);
+}
+
static bool_t
rendezvous_request(xprt)
register SVCXPRT *xprt;
FD_SET(sock, &mask);
do {
readfds = mask;
- if (select(sock+1, &readfds, (int*)NULL, (int*)NULL,
+ if (select(sock+1, &readfds, NULL, NULL,
&wait_per_try) <= 0) {
if (errno == EINTR) {
continue;
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: svc_udp.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: svc_udp.c,v 1.3 2002/02/19 20:36:25 epeyton Exp $";
#endif
/*
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
#include <errno.h>
+extern int bindresvport();
#define rpc_buffer(xprt) ((xprt)->xp_p1)
-#define MAX(a, b) ((a > b) ? a : b)
static bool_t svcudp_recv();
static bool_t svcudp_reply();
* Enable use of the cache.
* Note: there is no disable.
*/
+int
svcudp_enablecache(transp, size)
SVCXPRT *transp;
u_long size;
* Try to get an entry from the cache
* return 1 if found, 0 if not found
*/
-static
+static int
cache_get(xprt, msg, replyp, replylenp)
SVCXPRT *xprt;
struct rpc_msg *msg;
*
* from: @(#)types.h 1.18 87/07/24 SMI
* from: @(#)types.h 2.3 88/08/15 4.0 RPCSRC
- * $Id: types.h,v 1.2 1999/10/14 21:56:54 wsanchez Exp $
+ * $Id: types.h,v 1.3 2002/07/27 18:24:28 majka Exp $
*/
/*
# define NULL 0
#endif
-#define mem_alloc(bsize) malloc(bsize)
+#define mem_alloc(bsize) calloc(1, bsize)
#define mem_free(ptr, bsize) free(ptr)
#ifndef makedev /* ie, we haven't already included it */
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)xdr.c 1.35 87/08/12";*/
/*static char *sccsid = "from: @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: xdr.c,v 1.2 1999/10/14 21:56:54 wsanchez Exp $";
+static char *rcsid = "$Id: xdr.c,v 1.3 2002/02/19 20:36:26 epeyton Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
register u_int cnt;
{
register u_int rndup;
- static crud[BYTES_PER_XDR_UNIT];
+ static char crud[BYTES_PER_XDR_UNIT];
/*
* if no data we are done
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: xdr_array.c,v 1.2 1999/10/14 21:56:55 wsanchez Exp $";
+static char *rcsid = "$Id: xdr_array.c,v 1.3 2002/02/19 20:36:26 epeyton Exp $";
#endif
/*
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: xdr_mem.c,v 1.2 1999/10/14 21:56:55 wsanchez Exp $";
+static char *rcsid = "$Id: xdr_mem.c,v 1.3 2002/02/19 20:36:26 epeyton Exp $";
#endif
/*
*/
+#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <netinet/in.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/
/*static char *sccsid = "from: @(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC";*/
-static char *rcsid = "$Id: xdr_rec.c,v 1.2 1999/10/14 21:56:55 wsanchez Exp $";
+static char *rcsid = "$Id: xdr_rec.c,v 1.3 2002/02/19 20:36:26 epeyton Exp $";
#endif
/*
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <netinet/in.h>
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)xdr_reference.c 1.11 87/08/11 SMI";*/
/*static char *sccsid = "from: @(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC";*/
-static char *rcsid = "$Id: xdr_reference.c,v 1.2 1999/10/14 21:56:55 wsanchez Exp $";
+static char *rcsid = "$Id: xdr_reference.c,v 1.3 2002/02/19 20:36:26 epeyton Exp $";
#endif
/*
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
CFILES = getgrouplist.c glob.c hton.c putpwpasswd.c pwcache.c rcmd.c\
rcmdsh.c
-OTHERSRCS = Makefile
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble rcmd.3
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
--- /dev/null
+###############################################################################
+# NeXT Makefile.postamble Template
+# Copyright 1993, NeXT Computer, Inc.
+#
+# This Makefile is used for configuring the standard app makefiles associated
+# with ProjectBuilder.
+#
+# Use this template to set attributes for a project, sub-project, bundle, or
+# palette. Each node in the project's tree of sub-projects and bundles
+# should have it's own Makefile.preamble and Makefile.postamble. Additional
+# rules (e.g., after_install) that are defined by the developer should be
+# defined in this file.
+#
+###############################################################################
+#
+# Here are the variables exported by the common "app" makefiles that can be
+# used in any customizations you make to the template below:
+#
+# PRODUCT_ROOT - Name of the directory to which resources are copied.
+# OFILE_DIR - Directory into which .o object files are generated.
+# (Note that this name is calculated based on the target
+# architectures specified in Project Builder).
+# DERIVED_SRC_DIR - Directory used for all other derived files
+# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations
+#
+# NAME - name of application, bundle, subproject, palette, etc.
+# LANGUAGE - langage in which the project is written (default "English")
+# ENGLISH - boolean flag set iff $(LANGUAGE) = "English"
+# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese"
+# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES - non-localized resources of project
+# PROJECTVERSION - version of ProjectBuilder that output Makefile
+# APPICON - application icon file
+# DOCICONS - dock icon files
+# ICONSECTIONS - Specifies icon sections when linking executable
+#
+# CLASSES - Class implementation files in project.
+# HFILES - Header files in project.
+# MFILES - Other Objective-C source files in project.
+# CFILES - Other C source files in project.
+# PSWFILES - .psw files in the project
+# PSWMFILES - .pswm files in the project
+# SUBPROJECTS - Subprojects of this project
+# BUNDLES - Bundle subprojects of this project
+# OTHERSRCS - Other miscellaneous sources of this project
+# OTHERLINKED - Source files not matching a standard source extention
+#
+# LIBS - Libraries to link with when making app target
+# DEBUG_LIBS - Libraries to link with when making debug target
+# PROF_LIBS - Libraries to link with when making profile target
+# OTHERLINKEDOFILES - Other relocatable files to (always) link in.
+#
+# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles
+# MAKEFILEDIR - Directory in which to find $(MAKEFILE)
+# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make)
+# INSTALLDIR - Directory app will be installed into by 'install' target
+#
+###############################################################################
+
+
+# Change defaults assumed by the standard makefiles here. Edit the
+# following default values as appropriate. (Note that if no Makefile.postamble
+# exists, these values will have defaults set in common.make).
+
+# Versioning of frameworks, libraries, bundles, and palettes:
+#CURRENTLY_ACTIVE_VERSION = YES # Set to "NO" to produce a compatibility binary
+#DEPLOY_WITH_VERSION_NAME = A
+#COMPATIBILITY_PROJECT_VERSION = 1
+
+# Some compiler flags can be easily overridden here, but onlytake effect at
+# the top-level:
+#OPTIMIZATION_CFLAG = -O
+#DEBUG_SYMBOLS_CFLAG = -g
+#WARNING_CFLAGS = -Wall
+#DEBUG_BUILD_CFLAGS = -DDEBUG
+#PROFILE_BUILD_CFLAGS = -pg -DPROFILE
+
+# Flags passed to yacc
+#YFLAGS = -d
+
+# Library and Framework projects only:
+# 1. If you want something other than the default .dylib name, override it here
+#DYLIB_INSTALL_NAME = lib$(NAME).dylib
+
+# 2. If you want to change the -install_name flag from the absolute path to the development area, change it here. One good choice is the installation directory. Another one might be none at all.
+#DYLIB_INSTALL_DIR = $(INSTALLDIR)
+
+# Ownership and permissions of files installed by 'install' target
+#INSTALL_AS_USER = root # User/group ownership
+#INSTALL_AS_GROUP = wheel # (probably want to set both of these)
+#INSTALL_PERMISSIONS = # If set, 'install' chmod's executable to this
+
+# Options to strip for various project types. Note: -S strips debugging symbols
+# (executables can be stripped down further with -x or, if they load no bundles, with no
+# options at all).
+#APP_STRIP_OPTS = -S
+#TOOL_STRIP_OPTS = -S
+#LIBRARY_STRIP_OPTS = -S # for .a archives
+#DYNAMIC_STRIP_OPTS = -S # for bundles and shared libraries
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. "Official"
+# user-defined rules are:
+# * before_install
+# * after_install
+# * after_installhdrs
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
+install-man-page:
+ mkdir -p "$(DSTROOT)/usr/share/man/man3"
+ install -c -m 644 rcmd.3 "$(DSTROOT)/usr/share/man/man3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/rcmd.3" "$(DSTROOT)/usr/share/man/man3/iruserok.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/rcmd.3" "$(DSTROOT)/usr/share/man/man3/iruserok_sa.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/rcmd.3" "$(DSTROOT)/usr/share/man/man3/rcmd_af.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/rcmd.3" "$(DSTROOT)/usr/share/man/man3/rresvport.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/rcmd.3" "$(DSTROOT)/usr/share/man/man3/rresvport_af.3"
+ $(LN) -f "$(DSTROOT)/usr/share/man/man3/rcmd.3" "$(DSTROOT)/usr/share/man/man3/ruserok.3"
--- /dev/null
+AFTER_POSTINSTALL += install-man-page
+OTHER_CFLAGS = \
+ -DINET6=1 \
DYNAMIC_CODE_GEN = YES;
FILESTABLE = {
OTHER_LINKED = (getgrouplist.c, glob.c, hton.c, putpwpasswd.c, pwcache.c, rcmd.c, rcmdsh.c);
- OTHER_SOURCES = (Makefile);
+ OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, rcmd.3);
};
LANGUAGE = English;
MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
int *grpcnt;
{
register struct group *grp;
- register struct passwd *pw;
register int i, ngroups;
int ret, maxgroups;
* Scan the group file to find additional groups.
*/
setgrent();
- while (grp = getgrent()) {
+ while ((grp = getgrent())) {
if (grp->gr_gid == agroup)
continue;
for (i = 0; grp->gr_mem[i]; i++) {
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
+#include <string.h>
#include <utmp.h>
#define NCACHE 64 /* power of 2 */
-#define MASK NCACHE - 1 /* bits to store with */
+#define MASK (NCACHE - 1) /* bits to store with */
char *
user_from_uid(uid, nouser)
static struct ncache {
uid_t uid;
char name[UT_NAMESIZE + 1];
- } c_uid[NCACHE];
+ } *c_uid[NCACHE];
static int pwopen;
static char nbuf[15]; /* 32 bits == 10 digits */
register struct passwd *pw;
- register struct ncache *cp;
+ register struct ncache **cp;
- cp = c_uid + (uid & MASK);
- if (cp->uid != uid || !*cp->name) {
+ cp = &c_uid[uid & MASK];
+ if (*cp == NULL || (*cp)->uid != uid || !*(*cp)->name) {
if (pwopen == 0) {
setpassent(1);
pwopen = 1;
}
if ((pw = getpwuid(uid)) == NULL) {
+err:
if (nouser)
return (NULL);
(void)snprintf(nbuf, sizeof(nbuf), "%u", uid);
return (nbuf);
}
- cp->uid = uid;
- (void)strncpy(cp->name, pw->pw_name, UT_NAMESIZE);
- cp->name[UT_NAMESIZE] = '\0';
+ if (*cp == NULL) {
+ *cp = malloc(sizeof(struct ncache));
+ if (*cp == NULL)
+ goto err;
+ }
+ (*cp)->uid = uid;
+ (void)strncpy((*cp)->name, pw->pw_name, UT_NAMESIZE);
+ (*cp)->name[UT_NAMESIZE] = '\0';
}
- return (cp->name);
+ return ((*cp)->name);
}
char *
static struct ncache {
gid_t gid;
char name[UT_NAMESIZE + 1];
- } c_gid[NCACHE];
+ } *c_gid[NCACHE];
static int gropen;
static char nbuf[15]; /* 32 bits == 10 digits */
struct group *gr;
- struct ncache *cp;
+ struct ncache **cp = NULL;
- cp = c_gid + (gid & MASK);
- if (cp->gid != gid || !*cp->name) {
+ cp = &c_gid[gid & MASK];
+ if (*cp == NULL || (*cp)->gid != gid || !*(*cp)->name) {
if (gropen == 0) {
setgroupent(1);
gropen = 1;
}
if ((gr = getgrgid(gid)) == NULL) {
+err:
if (nogroup)
return (NULL);
(void)snprintf(nbuf, sizeof(nbuf), "%u", gid);
return (nbuf);
}
- cp->gid = gid;
- (void)strncpy(cp->name, gr->gr_name, UT_NAMESIZE);
- cp->name[UT_NAMESIZE] = '\0';
+ if (*cp == NULL) {
+ *cp = malloc(sizeof(struct ncache));
+ if (*cp == NULL)
+ goto err;
+ }
+ (*cp)->gid = gid;
+ (void)strncpy((*cp)->name, gr->gr_name, UT_NAMESIZE);
+ (*cp)->name[UT_NAMESIZE] = '\0';
}
- return (cp->name);
+ return ((*cp)->name);
}
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)rcmd.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/lib/libc/net/rcmd.3,v 1.12.2.7 2001/08/17 15:42:38 ru Exp $
+.\"
+.Dd March 3, 2000
+.Dt RCMD 3
+.Os
+.Sh NAME
+.Nm rcmd ,
+.Nm rresvport ,
+.Nm iruserok ,
+.Nm ruserok ,
+.Nm rcmd_af ,
+.Nm rresvport_af ,
+.Nm iruserok_sa
+.Nd routines for returning a stream to a remote command
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <unistd.h>
+.Ft int
+.Fn rcmd "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p"
+.Ft int
+.Fn rresvport "int *port"
+.Ft int
+.Fn iruserok "u_long raddr" "int superuser" "const char *ruser" "const char *luser"
+.Ft int
+.Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser"
+.Ft int
+.Fn rcmd_af "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" "int af"
+.Ft int
+.Fn rresvport_af "int *port" "int af"
+.Ft int
+.Fn iruserok_sa "const void *addr" "int addrlen" "int superuser" "const char *ruser" "const char *luser"
+.Sh DESCRIPTION
+The
+.Fn rcmd
+function
+is used by the super-user to execute a command on
+a remote machine using an authentication scheme based
+on reserved port numbers.
+The
+.Fn rresvport
+function
+returns a descriptor to a socket
+with an address in the privileged port space.
+The
+.Fn ruserok
+function
+is used by servers
+to authenticate clients requesting service with
+.Fn rcmd .
+All three functions are present in the same file and are used
+by the
+.Xr rshd 8
+server (among others).
+.Pp
+The
+.Fn rcmd
+function
+looks up the host
+.Fa *ahost
+using
+.Xr gethostbyname 3 ,
+returning -1 if the host does not exist.
+Otherwise
+.Fa *ahost
+is set to the standard name of the host
+and a connection is established to a server
+residing at the well-known Internet port
+.Fa inport .
+.Pp
+If the connection succeeds,
+a socket in the Internet domain of type
+.Dv SOCK_STREAM
+is returned to the caller, and given to the remote
+command as
+.Em stdin
+and
+.Em stdout .
+If
+.Fa fd2p
+is non-zero, then an auxiliary channel to a control
+process will be set up, and a descriptor for it will be placed
+in
+.Fa *fd2p .
+The control process will return diagnostic
+output from the command (unit 2) on this channel, and will also
+accept bytes on this channel as being
+.Tn UNIX
+signal numbers, to be
+forwarded to the process group of the command.
+If
+.Fa fd2p
+is 0, then the
+.Em stderr
+(unit 2 of the remote
+command) will be made the same as the
+.Em stdout
+and no
+provision is made for sending arbitrary signals to the remote process,
+although you may be able to get its attention by using out-of-band data.
+.Pp
+The protocol is described in detail in
+.Xr rshd 8 .
+.Pp
+The
+.Fn rresvport
+function is used to obtain a socket to which an address with a Privileged
+Internet port is bound.
+This socket is suitable for use by
+.Fn rcmd
+and several other functions.
+Privileged Internet ports are those in the range 0 to 1023.
+Only the super-user is allowed to bind an address of this sort
+to a socket.
+.Pp
+The
+.Fn iruserok
+and
+.Fn ruserok
+functions take a remote host's IP address or name, as returned by the
+.Xr gethostbyname 3
+routines, two user names and a flag indicating whether the local user's
+name is that of the super-user.
+Then, if the user is
+.Em NOT
+the super-user, it checks the
+.Pa /etc/hosts.equiv
+file.
+If that lookup is not done, or is unsuccessful, the
+.Pa .rhosts
+in the local user's home directory is checked to see if the request for
+service is allowed.
+.Pp
+If this file does not exist, is not a regular file, is owned by anyone
+other than the user or the super-user, or is writable by anyone other
+than the owner, the check automatically fails.
+Zero is returned if the machine name is listed in the
+.Dq Pa hosts.equiv
+file, or the host and remote user name are found in the
+.Dq Pa .rhosts
+file; otherwise
+.Fn iruserok
+and
+.Fn ruserok
+return -1.
+If the local domain (as obtained from
+.Xr gethostname 3 )
+is the same as the remote domain, only the machine name need be specified.
+.Pp
+The
+.Fn iruserok
+function is strongly preferred for security reasons.
+It requires trusting the local DNS at most, while the
+.Fn ruserok
+function requires trusting the entire DNS, which can be spoofed.
+.Pp
+The functions with an
+.Dq Li _af
+or
+.Dq Li _sa
+suffix, i.e.,
+.Fn rcmd_af ,
+.Fn rresvport_af
+and
+.Fn iruserok_sa ,
+work the same as the corresponding functions without a
+suffix, except that they are capable of handling both IPv6 and IPv4 ports.
+.Pp
+The
+.Dq Li _af
+suffix means that the function has an additional
+.Fa af
+argument which is used to specify the address family,
+(see below).
+The
+.Fa af
+argument extension is implemented for functions
+that have no binary address argument.
+Instead, the
+.Fa af
+argument specifies which address family is desired.
+.Pp
+The
+.Dq Li _sa
+suffix means that the function has general socket address and
+length arguments.
+As the socket address is a protocol independent data structure,
+IPv4 and IPv6 socket address can be passed as desired.
+The
+.Fa sa
+argument extension is implemented for functions
+that pass a protocol dependent binary address argument.
+The argument needs to be replaced with a more general address structure
+to support multiple address families in a general way.
+.Pp
+The functions with neither an
+.Dq Li _af
+suffix nor an
+.Dq Li _sa
+suffix work for IPv4 only, except for
+.Fn ruserok
+which can handle both IPv6 and IPv4.
+To switch the address family, the
+.Fa af
+argument must be filled with
+.Dv AF_INET ,
+or
+.Dv AF_INET6 .
+For
+.Fn rcmd_af ,
+.Dv PF_UNSPEC
+is also allowed.
+.Sh DIAGNOSTICS
+The
+.Fn rcmd
+function
+returns a valid socket descriptor on success.
+It returns -1 on error and prints a diagnostic message
+on the standard error.
+.Pp
+The
+.Fn rresvport
+function
+returns a valid, bound socket descriptor on success.
+It returns -1 on error with the global value
+.Va errno
+set according to the reason for failure.
+The error code
+.Er EAGAIN
+is overloaded to mean ``All network ports in use.''
+.Sh SEE ALSO
+.Xr rlogin 1 ,
+.Xr rsh 1 ,
+.Xr intro 2 ,
+.Xr rexec 3 ,
+.Xr rexecd 8 ,
+.Xr rlogind 8 ,
+.Xr rshd 8
+.Pp
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%T "Advanced Socket API for IPv6"
+.%O RFC2292
+.Re
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%T "Advanced Socket API for IPv6"
+.%O draft-ietf-ipngwg-rfc2292bis-01.txt
+.Re
+.Sh HISTORY
+Most of these
+functions appeared in
+.Bx 4.2 .
+.Fn rresvport_af
+appeared in RFC2292, and was implemented by the WIDE project
+for the Hydrangea IPv6 protocol stack kit.
+.Fn rcmd_af
+appeared in draft-ietf-ipngwg-rfc2292bis-01.txt,
+and was implemented in the WIDE/KAME IPv6 protocol stack kit.
+.Fn iruserok_sa
+appeared in discussion on the IETF ipngwg mailing list,
+and was implemented in
+.Fx 4.0 .
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/net/rcmd.c,v 1.23.2.5 2001/03/05 10:47:11 obrien Exp $
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: rcmd.c,v 1.30 1998/02/12 02:21:19 deraadt Exp $";
+static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
-#include <syslog.h>
-#include <stdlib.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <arpa/nameser.h>
+
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
+#ifndef socklen_t
+#define socklen_t int
+#endif
-typedef u_int32_t in_addr_t; /* base type for internet address */
-typedef u_int16_t in_port_t; /* IP port type */
+extern int innetgr __P(( const char *, const char *, const char *, const char * ));
-extern int bindresvport(int sd, struct sockaddr_in *sin);
-extern int getdomainname(char *val, size_t len);
-extern int rcmdsh(char **ahost, int rport, const char *locuser, const char *remuser, const char *cmd, char *rshprog);
+#define max(a, b) ((a > b) ? a : b)
+
+int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
+int __ivaliduser_af __P((FILE *,const void *, const char *, const char *,
+ int, int));
+int __ivaliduser_sa __P((FILE *, const struct sockaddr *, socklen_t,
+ const char *,const char *));
+static int __icheckhost __P((const struct sockaddr *, socklen_t,
+ const char *));
-int __ivaliduser __P((FILE *, in_addr_t, const char *, const char *));
-static int __icheckhost __P((u_int32_t, const char *));
-static char *__gethostloop __P((u_int32_t));
int
rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
const char *locuser, *remuser, *cmd;
int *fd2p;
{
- struct hostent *hp;
- struct sockaddr_in sin, from;
- fd_set *readsp = NULL;
- int oldmask;
- pid_t pid;
- int s, lport, timo;
- char c, *p;
-
- /* call rcmdsh() with specified remote shell if appropriate. */
- if ((getuid() == geteuid()) && (p = getenv("RSH"))) {
- struct servent *sp = getservbyname("shell", "tcp");
-
- if (sp && sp->s_port == rport)
- return (rcmdsh(ahost, rport, locuser, remuser,
- cmd, p));
- }
-
- /* use rsh(1) if non-root and remote port is shell. */
- if (geteuid()) {
- struct servent *sp = getservbyname("shell", "tcp");
+ return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
+}
- if (sp && sp->s_port == rport)
- return (rcmdsh(ahost, rport, locuser, remuser,
- cmd, NULL));
- }
+int
+rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
+ char **ahost;
+ u_short rport;
+ const char *locuser, *remuser, *cmd;
+ int *fd2p;
+ int af;
+{
+ struct addrinfo hints, *res, *ai;
+ struct sockaddr_storage from;
+ fd_set reads;
+ long oldmask;
+ pid_t pid;
+ int s, aport, lport, timo, error;
+ char c;
+ int refused, nres;
+ char num[8], paddr[NI_MAXHOST];
+ static char canonnamebuf[MAXDNAME]; /* is it proper here? */
pid = getpid();
- hp = gethostbyname(*ahost);
- if (hp == NULL) {
- herror(*ahost);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
+ error = getaddrinfo(*ahost, num, &hints, &res);
+ if (error) {
+ fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+ gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+ strerror(errno));
return (-1);
}
- *ahost = hp->h_name;
+ if (res->ai_canonname
+ && strlen(res->ai_canonname) + 1 < sizeof(canonnamebuf)) {
+ strncpy(canonnamebuf, res->ai_canonname, sizeof(canonnamebuf));
+ *ahost = canonnamebuf;
+ }
+ nres = 0;
+ for (ai = res; ai; ai = ai->ai_next)
+ nres++;
+ ai = res;
+ refused = 0;
oldmask = sigblock(sigmask(SIGURG));
for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
- s = rresvport(&lport);
+ s = rresvport_af(&lport, ai->ai_family);
if (s < 0) {
+ if (errno != EAGAIN && ai->ai_next) {
+ ai = ai->ai_next;
+ continue;
+ }
if (errno == EAGAIN)
(void)fprintf(stderr,
"rcmd: socket: All ports in use\n");
else
(void)fprintf(stderr, "rcmd: socket: %s\n",
strerror(errno));
+ freeaddrinfo(res);
sigsetmask(oldmask);
return (-1);
}
fcntl(s, F_SETOWN, pid);
- bzero(&sin, sizeof sin);
- sin.sin_len = sizeof(struct sockaddr_in);
- sin.sin_family = hp->h_addrtype;
- sin.sin_port = rport;
- bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
break;
(void)close(s);
if (errno == EADDRINUSE) {
lport--;
continue;
}
- if (errno == ECONNREFUSED && timo <= 16) {
- (void)sleep(timo);
- timo *= 2;
- continue;
+ if (errno == ECONNREFUSED)
+ refused = 1;
+ if (ai->ai_next == NULL && (!refused || timo > 16)) {
+ (void)fprintf(stderr, "%s: %s\n",
+ *ahost, strerror(errno));
+ freeaddrinfo(res);
+ sigsetmask(oldmask);
+ return (-1);
}
- if (hp->h_addr_list[1] != NULL) {
+ if (nres > 1) {
int oerrno = errno;
+ getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ paddr, sizeof(paddr),
+ NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
(void)fprintf(stderr, "connect to address %s: ",
- inet_ntoa(sin.sin_addr));
+ paddr);
errno = oerrno;
perror(0);
- hp->h_addr_list++;
- bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
- (void)fprintf(stderr, "Trying %s...\n",
- inet_ntoa(sin.sin_addr));
- continue;
}
- (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
- sigsetmask(oldmask);
- return (-1);
+ if ((ai = ai->ai_next) == NULL) {
+ /* refused && timo <= 16 */
+ struct timespec time_to_sleep, time_remaining;
+
+ time_to_sleep.tv_sec = timo;
+ time_to_sleep.tv_nsec = 0;
+ (void)nanosleep(&time_to_sleep, &time_remaining);
+ timo *= 2;
+ ai = res;
+ refused = 0;
+ }
+ if (nres > 1) {
+ getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ paddr, sizeof(paddr),
+ NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ fprintf(stderr, "Trying %s...\n", paddr);
+ }
}
#if 0
/*
lport = 0;
} else {
char num[8];
- int s2 = rresvport(&lport), s3;
- int len = sizeof(from);
- int fdssize = howmany(MAX(s, s2)+1, NFDBITS) * sizeof(fd_mask);
+ int s2 = rresvport_af(&lport, ai->ai_family), s3;
+ int len = ai->ai_addrlen;
+ int nfds;
if (s2 < 0)
goto bad;
- readsp = (fd_set *)malloc(fdssize);
- if (readsp == NULL)
- goto bad;
listen(s2, 1);
(void)snprintf(num, sizeof(num), "%d", lport);
if (write(s, num, strlen(num)+1) != strlen(num)+1) {
(void)close(s2);
goto bad;
}
+ nfds = max(s, s2)+1;
+ if(nfds > FD_SETSIZE) {
+ fprintf(stderr, "rcmd: too many files\n");
+ (void)close(s2);
+ goto bad;
+ }
again:
- bzero(readsp, fdssize);
- FD_SET(s, readsp);
- FD_SET(s2, readsp);
+ FD_ZERO(&reads);
+ FD_SET(s, &reads);
+ FD_SET(s2, &reads);
errno = 0;
- if (select(MAX(s, s2) + 1, readsp, 0, 0, 0) < 1 ||
- !FD_ISSET(s2, readsp)) {
+ if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){
if (errno != 0)
(void)fprintf(stderr,
"rcmd: select (setting up stderr): %s\n",
goto bad;
}
s3 = accept(s2, (struct sockaddr *)&from, &len);
+ switch (from.ss_family) {
+ case AF_INET:
+ aport = ntohs(((struct sockaddr_in *)&from)->sin_port);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
+ break;
+#endif
+ default:
+ aport = 0; /* error */
+ break;
+ }
/*
* XXX careful for ftp bounce attacks. If discovered, shut them
* down and check for the real auxiliary channel to connect.
*/
- if (from.sin_family == AF_INET && from.sin_port == htons(20)) {
+ if (aport == 20) {
close(s3);
goto again;
}
goto bad;
}
*fd2p = s3;
- from.sin_port = ntohs(from.sin_port);
- if (from.sin_family != AF_INET ||
- from.sin_port >= IPPORT_RESERVED ||
- from.sin_port < IPPORT_RESERVED / 2) {
+ if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) {
(void)fprintf(stderr,
"socket: protocol failure in circuit setup.\n");
goto bad2;
goto bad2;
}
sigsetmask(oldmask);
- free(readsp);
+ freeaddrinfo(res);
return (s);
bad2:
if (lport)
(void)close(*fd2p);
bad:
- if (readsp)
- free(readsp);
(void)close(s);
sigsetmask(oldmask);
+ freeaddrinfo(res);
return (-1);
}
int
-rresvport(alport)
- int *alport;
+rresvport(port)
+ int *port;
+{
+ return rresvport_af(port, AF_INET);
+}
+
+int
+rresvport_af(alport, family)
+ int *alport, family;
{
- struct sockaddr_in sin;
int s;
+ struct sockaddr_storage ss;
+ u_short *sport;
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family;
+ switch (family) {
+ case AF_INET:
+ ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in);
+ sport = &((struct sockaddr_in *)&ss)->sin_port;
+ ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6);
+ sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
+ ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
- bzero(&sin, sizeof sin);
- sin.sin_len = sizeof(struct sockaddr_in);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- s = socket(AF_INET, SOCK_STREAM, 0);
+ s = socket(ss.ss_family, SOCK_STREAM, 0);
if (s < 0)
return (-1);
- sin.sin_port = htons((in_port_t)*alport);
- if (*alport < IPPORT_RESERVED - 1) {
- if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
- return (s);
- if (errno != EADDRINUSE) {
- (void)close(s);
- return (-1);
- }
+#if 0 /* compat_exact_traditional_rresvport_semantics */
+ sin.sin_port = htons((u_short)*alport);
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ return (s);
+ if (errno != EADDRINUSE) {
+ (void)close(s);
+ return (-1);
}
- sin.sin_port = 0;
- if (bindresvport(s, &sin) == -1) {
+#endif
+ *sport = 0;
+ if (bindresvport_sa(s, (struct sockaddr *)&ss) == -1) {
(void)close(s);
return (-1);
}
- *alport = (int)ntohs(sin.sin_port);
+ *alport = (int)ntohs(*sport);
return (s);
}
const char *rhost, *ruser, *luser;
int superuser;
{
- struct hostent *hp;
- char **ap;
- int i;
-#define MAXADDRS 35
- u_int32_t addrs[MAXADDRS + 1];
-
- if ((hp = gethostbyname(rhost)) == NULL)
+ struct addrinfo hints, *res, *r;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ error = getaddrinfo(rhost, "0", &hints, &res);
+ if (error)
return (-1);
- for (i = 0, ap = hp->h_addr_list; *ap && i < MAXADDRS; ++ap, ++i)
- bcopy(*ap, &addrs[i], sizeof(addrs[i]));
- addrs[i] = 0;
- for (i = 0; i < MAXADDRS && addrs[i]; i++)
- if (iruserok((in_addr_t)addrs[i], superuser, ruser, luser) == 0)
+ for (r = res; r; r = r->ai_next) {
+ if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser,
+ luser) == 0) {
+ freeaddrinfo(res);
return (0);
+ }
+ }
+ freeaddrinfo(res);
return (-1);
}
unsigned long raddr;
int superuser;
const char *ruser, *luser;
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
+ return iruserok_sa((struct sockaddr *)&sin, sin.sin_len, superuser,
+ ruser, luser);
+}
+
+/*
+ * AF independent extension of iruserok.
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+int
+iruserok_sa(ra, rlen, superuser, ruser, luser)
+ const void *ra;
+ int rlen;
+ int superuser;
+ const char *ruser, *luser;
{
register char *cp;
struct stat sbuf;
uid_t uid;
int first;
char pbuf[MAXPATHLEN];
+ const struct sockaddr *raddr;
+ struct sockaddr_storage ss;
+
+ /* avoid alignment issue */
+ if (rlen > sizeof(ss))
+ return(-1);
+ memcpy(&ss, ra, rlen);
+ raddr = (struct sockaddr *)&ss;
first = 1;
hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
again:
if (hostf) {
- if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
+ if (__ivaliduser_sa(hostf, raddr, rlen, luser, ruser) == 0) {
(void)fclose(hostf);
return (0);
}
* Returns 0 if ok, -1 if not ok.
*/
int
-__ivaliduser(hostf, raddrl, luser, ruser)
+__ivaliduser(hostf, raddr, luser, ruser)
FILE *hostf;
- in_addr_t raddrl;
+ u_int32_t raddr;
const char *luser, *ruser;
{
- register char *user, *p;
- char *buf;
- const char *auser, *ahost;
- int hostok, userok;
- char *rhost = (char *)-1;
- char domain[MAXHOSTNAMELEN];
- u_int32_t raddr = (u_int32_t)raddrl;
- size_t buflen;
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
+ return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, sin.sin_len,
+ luser, ruser);
+}
+
+/*
+ * Returns 0 if ok, -1 if not ok.
+ *
+ * XXX obsolete API.
+ */
+int
+__ivaliduser_af(hostf, raddr, luser, ruser, af, len)
+ FILE *hostf;
+ const void *raddr;
+ const char *luser, *ruser;
+ int af, len;
+{
+ struct sockaddr *sa = NULL;
+ struct sockaddr_in *sin = NULL;
+#ifdef INET6
+ struct sockaddr_in6 *sin6 = NULL;
+#endif
+ struct sockaddr_storage ss;
+
+ memset(&ss, 0, sizeof(ss));
+ switch (af) {
+ case AF_INET:
+ if (len != sizeof(sin->sin_addr))
+ return -1;
+ sin = (struct sockaddr_in *)&ss;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin->sin_addr, raddr, sizeof(sin->sin_addr));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (len != sizeof(sin6->sin6_addr))
+ return -1;
+ /* you will lose scope info */
+ sin6 = (struct sockaddr_in6 *)&ss;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&sin6->sin6_addr, raddr, sizeof(sin6->sin6_addr));
+ break;
+#endif
+ default:
+ return -1;
+ }
- getdomainname(domain, sizeof(domain));
+ sa = (struct sockaddr *)&ss;
+ return __ivaliduser_sa(hostf, sa, sa->sa_len, luser, ruser);
+}
+
+/*
+ * Returns 0 if ok, -1 if not ok.
+ */
+int
+__ivaliduser_sa(hostf, raddr, salen, luser, ruser)
+ FILE *hostf;
+ const struct sockaddr *raddr;
+ socklen_t salen;
+ const char *luser, *ruser;
+{
+ register char *user, *p;
+ int ch;
+ char buf[MAXHOSTNAMELEN + 128]; /* host + login */
+ char hname[MAXHOSTNAMELEN];
+ /* Presumed guilty until proven innocent. */
+ int userok = 0, hostok = 0;
+#ifdef YP
+ char *ypdomain;
+
+ if (yp_get_default_domain(&ypdomain))
+ ypdomain = NULL;
+#else
+#define ypdomain NULL
+#endif
+ /* We need to get the damn hostname back for netgroup matching. */
+ if (getnameinfo(raddr, salen, hname, sizeof(hname), NULL, 0,
+ NI_NAMEREQD) != 0)
+ return (-1);
- while ((buf = fgetln(hostf, &buflen))) {
+ while (fgets(buf, sizeof(buf), hostf)) {
p = buf;
- if (*p == '#')
+ /* Skip lines that are too long. */
+ if (strchr(p, '\n') == NULL) {
+ while ((ch = getc(hostf)) != '\n' && ch != EOF);
continue;
- while (*p != '\n' && *p != ' ' && *p != '\t' && p < buf + buflen) {
- if (!isprint(*p))
- goto bail;
- *p = isupper(*p) ? tolower(*p) : *p;
- p++;
}
- if (p >= buf + buflen)
+ if (*p == '\n' || *p == '#') {
+ /* comment... */
continue;
+ }
+ while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
+ *p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p;
+ p++;
+ }
if (*p == ' ' || *p == '\t') {
*p++ = '\0';
- while (*p == ' ' || *p == '\t' && p < buf + buflen)
+ while (*p == ' ' || *p == '\t')
p++;
- if (p >= buf + buflen)
- continue;
user = p;
while (*p != '\n' && *p != ' ' &&
- *p != '\t' && p < buf + buflen) {
- if (!isprint(*p))
- goto bail;
+ *p != '\t' && *p != '\0')
p++;
- }
} else
user = p;
*p = '\0';
-
- if (p == buf)
- continue;
-
- auser = *user ? user : luser;
- ahost = buf;
-
- if (strlen(ahost) >= MAXHOSTNAMELEN)
- continue;
-
/*
- * innetgr() must lookup a hostname (we do not attempt
- * to change the semantics so that netgroups may have
- * #.#.#.# addresses in the list.)
+ * Do +/- and +@/-@ checking. This looks really nasty,
+ * but it matches SunOS's behavior so far as I can tell.
*/
- if (ahost[0] == '+')
- switch (ahost[1]) {
- case '\0':
+ switch(buf[0]) {
+ case '+':
+ if (!buf[1]) { /* '+' matches all hosts */
hostok = 1;
break;
- case '@':
- if (rhost == (char *)-1)
- rhost = __gethostloop(raddr);
- hostok = 0;
- if (rhost)
- hostok = innetgr(&ahost[2], rhost,
- NULL, domain);
- break;
- default:
- hostok = __icheckhost(raddr, &ahost[1]);
- break;
}
- else if (ahost[0] == '-')
- switch (ahost[1]) {
- case '\0':
- hostok = -1;
- break;
- case '@':
- if (rhost == (char *)-1)
- rhost = __gethostloop(raddr);
- hostok = 0;
- if (rhost)
- hostok = -innetgr(&ahost[2], rhost,
- NULL, domain);
- break;
- default:
- hostok = -__icheckhost(raddr, &ahost[1]);
- break;
+ if (buf[1] == '@') /* match a host by netgroup */
+ hostok = innetgr((char *)&buf[2],
+ (char *)&hname, NULL, ypdomain);
+ else /* match a host by addr */
+ hostok = __icheckhost(raddr, salen,
+ (char *)&buf[1]);
+ break;
+ case '-': /* reject '-' hosts and all their users */
+ if (buf[1] == '@') {
+ if (innetgr((char *)&buf[2],
+ (char *)&hname, NULL, ypdomain))
+ return(-1);
+ } else {
+ if (__icheckhost(raddr, salen,
+ (char *)&buf[1]))
+ return(-1);
}
- else
- hostok = __icheckhost(raddr, ahost);
-
-
- if (auser[0] == '+')
- switch (auser[1]) {
- case '\0':
+ break;
+ default: /* if no '+' or '-', do a simple match */
+ hostok = __icheckhost(raddr, salen, buf);
+ break;
+ }
+ switch(*user) {
+ case '+':
+ if (!*(user+1)) { /* '+' matches all users */
userok = 1;
break;
- case '@':
- userok = innetgr(&auser[2], NULL, ruser,
- domain);
- break;
- default:
- userok = strcmp(ruser, &auser[1]) ? 0 : 1;
- break;
}
- else if (auser[0] == '-')
- switch (auser[1]) {
- case '\0':
- userok = -1;
- break;
- case '@':
- userok = -innetgr(&auser[2], NULL, ruser,
- domain);
- break;
- default:
- userok = strcmp(ruser, &auser[1]) ? 0 : -1;
- break;
+ if (*(user+1) == '@') /* match a user by netgroup */
+ userok = innetgr(user+2, NULL, ruser, ypdomain);
+ else /* match a user by direct specification */
+ userok = !(strcmp(ruser, user+1));
+ break;
+ case '-': /* if we matched a hostname, */
+ if (hostok) { /* check for user field rejections */
+ if (!*(user+1))
+ return(-1);
+ if (*(user+1) == '@') {
+ if (innetgr(user+2, NULL,
+ ruser, ypdomain))
+ return(-1);
+ } else {
+ if (!strcmp(ruser, user+1))
+ return(-1);
+ }
}
- else
- userok = strcmp(ruser, auser) ? 0 : 1;
-
- /* Check if one component did not match */
- if (hostok == 0 || userok == 0)
- continue;
-
- /* Check if we got a forbidden pair */
- if (userok <= -1 || hostok <= -1)
- return (-1);
-
- /* Check if we got a valid pair */
- if (hostok >= 1 && userok >= 1)
- return (0);
+ break;
+ default: /* no rejections: try to match the user */
+ if (hostok)
+ userok = !(strcmp(ruser,*user ? user : luser));
+ break;
+ }
+ if (hostok && userok)
+ return(0);
}
-bail:
return (-1);
}
/*
- * Returns "true" if match, 0 if no match. If we do not find any
- * semblance of an A->PTR->A loop, allow a simple #.#.#.# match to work.
+ * Returns "true" if match, 0 if no match.
+ *
+ * NI_WITHSCOPEID is useful for comparing sin6_scope_id portion
+ * if af == AF_INET6.
*/
static int
-__icheckhost(raddr, lhost)
- u_int32_t raddr;
- const char *lhost;
+__icheckhost(raddr, salen, lhost)
+ const struct sockaddr *raddr;
+ socklen_t salen;
+ const char *lhost;
{
- register struct hostent *hp;
- register char **pp;
- struct in_addr in;
-
- hp = gethostbyname(lhost);
- if (hp != NULL) {
- /* Spin through ip addresses. */
- for (pp = hp->h_addr_list; *pp; ++pp)
- if (!bcmp(&raddr, *pp, sizeof(raddr)))
- return (1);
+ struct sockaddr_in sin;
+ struct sockaddr_in6 *sin6;
+ struct addrinfo hints, *res, *r;
+ int error;
+ char h1[NI_MAXHOST], h2[NI_MAXHOST];
+
+ if (raddr->sa_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)raddr;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
+ sizeof(sin.sin_addr));
+ raddr = (struct sockaddr *)&sin;
+ salen = sin.sin_len;
+ }
}
- in.s_addr = raddr;
- if (strcmp(lhost, inet_ntoa(in)) == 0)
- return (1);
- return (0);
-}
-
-/*
- * Return the hostname associated with the supplied address.
- * Do a reverse lookup as well for security. If a loop cannot
- * be found, pack the result of inet_ntoa() into the string.
- */
-static char *
-__gethostloop(raddr)
- u_int32_t raddr;
-{
- static char remotehost[MAXHOSTNAMELEN];
- struct hostent *hp;
- struct in_addr in;
-
- hp = gethostbyaddr((char *) &raddr, sizeof(raddr), AF_INET);
- if (hp == NULL)
- return (NULL);
-
- /*
- * Look up the name and check that the supplied
- * address is in the list
- */
- strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
- remotehost[sizeof(remotehost) - 1] = '\0';
- hp = gethostbyname(remotehost);
- if (hp == NULL)
- return (NULL);
-
- for (; hp->h_addr_list[0] != NULL; hp->h_addr_list++)
- if (!bcmp(hp->h_addr_list[0], (caddr_t)&raddr, sizeof(raddr)))
- return (remotehost);
+ h1[0] = '\0';
+ if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0,
+ NI_NUMERICHOST | NI_WITHSCOPEID) != 0)
+ return (0);
+
+ /* Resolve laddr into sockaddr */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = raddr->sa_family;
+ hints.ai_socktype = SOCK_DGRAM; /*XXX dummy*/
+ res = NULL;
+ error = getaddrinfo(lhost, "0", &hints, &res);
+ if (error)
+ return (0);
+
+ for (r = res; r ; r = r->ai_next) {
+ h2[0] = '\0';
+ if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
+ NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) != 0)
+ continue;
+ if (strcmp(h1, h2) == 0) {
+ freeaddrinfo(res);
+ return (1);
+ }
+ }
- /*
- * either the DNS adminstrator has made a configuration
- * mistake, or someone has attempted to spoof us
- */
- in.s_addr = raddr;
- syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s",
- inet_ntoa(in), hp->h_name);
- return (NULL);
+ /* No match. */
+ freeaddrinfo(res);
+ return (0);
}
(void) close(sp[1]);
/* Reap child. */
(void) wait(NULL);
- return(sp[0]);
}
- /* NOTREACHED */
+ return(sp[0]);
}